Commit 4334e46e by John Donnal

auto doc rebuild

parent dac169bf
Showing with 0 additions and 3440 deletions
.. Wattsworth documentation master file, created by
sphinx-quickstart on Tue Aug 1 11:55:55 2017.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
The Wattsworth Project
======================
Installing the Software
-----------------------
All of the software repositories are available at
https://git.wattsworth.net/wattsworth. The software has been tested on
64 bit Ubuntu Linux. While it is possible to run on Arm-based Single
Board Computers (eg Raspberry Pi), the software works best on x86 systems
such as the Intel NUC.
Use the Puppet repository to install the complete Wattsworth stack
.. code-block:: bash
$> sudo apt-get update
$> sudo apt-get install puppet
$> git clone https://git.wattsworth.net/wattsworth/puppet.git
$> cd puppet
$> sudo puppet apply --modulepath=./modules --verbose site.pp
.. toctree::
:maxdepth: 2
:caption: Contents:
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
/* This file intentionally left blank. */
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
};
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this);
});
}
}
return this.each(function() {
highlight(this);
});
};
/*
* backward compatibility for jQuery.browser
* This will be supported until firefox bug is fixed.
*/
if (!jQuery.browser) {
jQuery.uaMatch = function(ua) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated == 'undefined')
return string;
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
* see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
if (!body.length) {
body = $('body');
}
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
},
initOnKeyListeners: function() {
$(document).keyup(function(event) {
var activeElementType = document.activeElement.tagName;
// don't navigate when in search box or textarea
if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
switch (event.keyCode) {
case 37: // left
var prevHref = $('link[rel="prev"]').prop('href');
if (prevHref) {
window.location.href = prevHref;
return false;
}
case 39: // right
var nextHref = $('link[rel="next"]').prop('href');
if (nextHref) {
window.location.href = nextHref;
return false;
}
}
}
});
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});
\ No newline at end of file
This diff could not be displayed because it is too large.
.highlight .hll { background-color: #ffffcc }
.highlight { background: #eeffcc; }
.highlight .c { color: #408090; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #333333 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #208050 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #208050 } /* Literal.Number.Bin */
.highlight .mf { color: #208050 } /* Literal.Number.Float */
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
.highlight .sa { color: #4070a0 } /* Literal.String.Affix */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #06287e } /* Name.Function.Magic */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Index &#8212; Wattsworth 1.0 documentation</title>
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="index" title="Index" href="#" />
<link rel="search" title="Search" href="search.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head>
<body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1 id="index">Index</h1>
<div class="genindex-jumpbox">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<div><input type="text" name="q" /></div>
<div><input type="submit" value="Go" /></div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2017, John Donnal, James Paris.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 1.6.2</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.10</a>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The Wattsworth Project &#8212; Wattsworth 1.0 documentation</title>
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head>
<body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="the-wattsworth-project">
<h1>The Wattsworth Project<a class="headerlink" href="#the-wattsworth-project" title="Permalink to this headline"></a></h1>
<div class="section" id="installing-the-software">
<h2>Installing the Software<a class="headerlink" href="#installing-the-software" title="Permalink to this headline"></a></h2>
<p>All of the software repositories are available at
<a class="reference external" href="https://git.wattsworth.net/wattsworth">https://git.wattsworth.net/wattsworth</a>. The software has been tested on
64 bit Ubuntu Linux. While it is possible to run on Arm-based Single
Board Computers (eg Raspberry Pi), the software works best on x86 systems
such as the Intel NUC.</p>
<p>Use the Puppet repository to install the complete Wattsworth stack</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$&gt; sudo apt-get update
$&gt; sudo apt-get install puppet
$&gt; git clone https://git.wattsworth.net/wattsworth/puppet.git
$&gt; <span class="nb">cd</span> puppet
$&gt; sudo puppet apply --modulepath<span class="o">=</span>./modules --verbose site.pp
</pre></div>
</div>
<div class="toctree-wrapper compound">
</div>
</div>
</div>
<div class="section" id="indices-and-tables">
<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><a class="reference internal" href="genindex.html"><span class="std std-ref">Index</span></a></li>
<li><a class="reference internal" href="py-modindex.html"><span class="std std-ref">Module Index</span></a></li>
<li><a class="reference internal" href="search.html"><span class="std std-ref">Search Page</span></a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h3><a href="#">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">The Wattsworth Project</a><ul>
<li><a class="reference internal" href="#installing-the-software">Installing the Software</a></li>
</ul>
</li>
<li><a class="reference internal" href="#indices-and-tables">Indices and tables</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="#">Documentation overview</a><ul>
</ul></li>
</ul>
</div>
<div role="note" aria-label="source link">
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/index.rst.txt"
rel="nofollow">Show Source</a></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<div><input type="text" name="q" /></div>
<div><input type="submit" value="Go" /></div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2017, John Donnal, James Paris.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 1.6.2</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.10</a>
|
<a href="_sources/index.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>
\ No newline at end of file
.. _joule-concepts:
==============
Joule Concepts
==============
.. _streams:
Streams
"""""""
Streams are timestamped data flows that connect modules together.
Streams can represent primary measurements such as readings from a current
sensor or derived measurements such as harmonic content. A stream has
one or more elements and can be viewed as a database table:
========= ======== ======== === ========
timestamp element1 element2 ... elementN
========= ======== ======== === ========
1003421 0.0 10.5 ... 2.3
1003423 1.0 -8.0 ... 2.3
1003429 8.0 12.5 ... 2.3
1003485 4.0 83.5 ... 2.3
========= ======== ======== === ========
.. _modules:
Modules
"""""""
Modules process streams. A module may receive zero, one or more
input streams and may produce zero, one, or more output streams. While
Joule does not enforce any structure on modules, we suggest
structuring your data pipeline with two types of modules: Readers, and
Filters. Readers take no inputs. They directly manage a sensor (eg a
TTY USB device) and generate an output data stream with sensor
values. Filters take these streams as inputs and produce new outputs.
Filters can be chained to produce complex behavior from simple,
reusable building blocks.
Example
"""""""
Using a light sensor and temperature sensor to detect occupancy in a room:
.. image:: /images/joule_system.png
Pipes
"""""
Pipes connect streams to modules. Pipe read and writes are asynchronous
coroutines which allows modules to effeciently manage many pipe connections
at once. The animation below shows a producer module using a pipe to communicate
with a consume module. See reference section for details on the pipe API.
.. image:: /_static/joule_pipe.gif
.. _getting-started:
===============
Getting Started
===============
Before reading this section :ref:`install Joule <installing-joule>`
and make sure you are familiar with concepts of :ref:`streams
<streams>` and :ref:`modules <modules>`. Configurations shown here use
the system defaults which expect a NilmDB repository to be avaiable at
**\http://localhost/nilmdb**. If your setup is different see
:ref:`main.conf` for the full set configuration options.
A Reader Module
---------------
In this example we will create a simple data capture pipeline that
sends two random values to a stream. We will use the builtin **joule
reader** module to generate the values. See :ref:`writing_modules` for
details on building custom modules.
We start by creating a stream configuration file for the data. Copy
the following into a new file at
**/etc/joule/stream_configs/demo_random.conf**
.. code-block:: ini
[Main]
name = Random Data
path = /demo/random
datatype = float32
keep = 1w
[Element1]
name = rand1
[Element2]
name = rand2
This will allocate a new stream in NilmDB named **/demo/random** that
holds two **float32** elements. We name the first element **rand1**
and the second element **rand2**. **Note:** *If your database has an
existing stream with this name and a different layout (datatype
and/or number of elements) you must remove it before continuing.*
Next we will set up a module to write data to this stream. **joule
reader** is a multipurpose reader module provided with Joule. It can
read values from file objects, serial ports, and more. In this
demonstration we will use it to simply generate random values. When **joule
reader** is called from the command line it prints values to stdout:
.. code-block:: bash
$> joule reader
# ... list of reader modules
$> joule reader help random
# ... help with the random module
$> joule reader random 2 10
Starting random stream: 2 elements @ 10.0Hz
1485188853650944 0.32359053067687582 0.70028608966895545
1485188853750944 0.72139550945715136 0.39218791387411422
1485188853850944 0.40728044378612194 0.26446072057019654
1485188853950944 0.61021957330250398 0.27359526775709841
# ... more output ...
Copy the following into a file at **/etc/joule/module_configs/demo_reader.conf**
.. code-block:: ini
[Main]
exec_cmd = joule reader random 2 10
name = Demo Reader
[Source]
# a reader has no inputs
[Destination]
output = /demo/random
This will create a reader module that runs **joule reader random** and pipes
the output to **/demo/random**. That's all you need to do to set up
the capture pipeline. Restart joule and check that the new module is
running:
.. code-block:: bash
$> sudo systemctl restart joule.service
# check status using joule commands
$> joule modules
+-------------+---------+--------------+---------+-----+-------------+
| Module | Sources | Destinations | Status | CPU | mem |
+-------------+---------+--------------+---------+-----+-------------+
| Demo Reader | | /demo/random | running | 0% | 33 MB (42%) |
+-------------+---------+--------------+---------+-----+-------------+
$> joule logs "Demo Reader"
[27 Jan 2017 18:05:41] ---starting module---
[27 Jan 2017 18:05:41] Starting random stream: 2 elements @ 10.0Hz
# confirm data is entering NilmDB
$> nilmtool list -E /demo/random
/demo/random
interval extents: Fri, 27 Jan 2017 # ...
total data: 1559 rows, 155.700002 seconds
A Filter Module
---------------
In this example we will connect the reader we set up above to a filter module. We will
use the builtin **joule filter** to compute the moving average of our data.
See :ref:`writing_modules` for details on building custom modules.
Start by creating a stream configuration file for the data. Copy the
following into a new file at
**/etc/joule/stream_configs/demo_filtered.conf**
.. code-block:: ini
[Main]
name = Filtered Data
path = /demo/filtered
datatype = float32
keep = 1w
[Element1]
name = filtered1
[Element2]
name = filtered2
This will allocate a new stream at **/demo/filtered** that holds two
**float32** elements. We name the first element **filtered1** and the
second element **filtered2**
Next we will set up a module that computes the moving average of **/demo/random**
and stores the output in **/demo/filtered**. **joule filter**
is a multipurpose module that can compute several different types
of filters including median, moving average, and more. When called from the command line
it will display a description of the operations it will perform on the data
.. code-block:: bash
$> joule filter
# ... list of filter modules
$> joule filter help mean
# ... help with the mean module
$> joule filter mean 9
per-element moving average with a window size of 9
To add this filter to our pipeline copy the following into a file at
**/etc/joule/module_configs/demo_filter.conf**
.. code-block:: ini
[Main]
exec_cmd = joule filter mean 9
name = Demo Filter
[Source]
input = /demo/random
[Destination]
output = /demo/filtered
This will create a filter module that runs **joule filter** using
input from **/demo/random** and storing output in
**/demo/filtered**. Now our pipeline consists of two modules: a reader
and a filter. Restart joule and check that both modules are running:
.. code-block:: bash
$> sudo systemctl restart joule.service
# check status using joule commands
$> joule modules
+-------------+--------------+----------------+---------+-----+-------------+
| Module | Sources | Destinations | Status | CPU | mem |
+-------------+--------------+----------------+---------+-----+-------------+
| Demo Reader | | /demo/random | running | 0% | 33 MB (42%) |
| Demo Filter | /demo/random | /demo/filtered | running | 0% | 53 MB (68%) |
+-------------+--------------+----------------+---------+-----+-------------+
$> joule logs "Demo Reader"
[27 Jan 2017 18:22:48] ---starting module---
[27 Jan 2017 18:22:48] Starting random stream: 2 elements @ 10.0Hz
$> joule logs "Demo Filter"
[27 Jan 2017 18:22:48] ---starting module---
[27 Jan 2017 18:22:48] Starting moving average filter with window size 9
# confirm data is entering NilmDB
$> nilmtool list -E -n /demo/*
/demo/filtered
interval extents: Fri, 27 Jan 2017 # ...
total data: 132 rows, 13.100001 seconds
/demo/random
interval extents: Fri, 27 Jan 2017 # ...
total data: 147 rows, 14.600001 seconds
.. Joule documentation master file, created by
sphinx-quickstart on Fri Jan 6 17:16:21 2017.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Joule: Modular Data Processing
=================================
Joule is a data capture and signal processing engine. It allows you to
turn a single board computer like the Raspberry Pi into a robust
sensor platform. Joule uses modules to build complex acquisition and
signal processing workflows from simple building blocks. Modules are
user defined processes that are connected together by data streams.
Joule acts as a process manager, ensuring that modules start at system
boot and are restarted if they fail. Joule also collects runtime
statistics and logs for each module making it easy to detect
bugs and find bottlenecks in processing pipelines.
.. toctree::
:maxdepth: 2
concepts
install
getting_started
writing_modules
testing_modules
nilm
reference
Contributing & Running Tests
----------------------------
Contribution is always welcome. Please include tests with your pull request.
Unittests can be run using nose2, see **joule/htmlcov** for code coverage.
.. code-block:: bash
$> cd joule
$> nose2 # run all unittests
End to end tests are run from the **tests/e2e** directory and require
docker-compose and the NilmDB container. See
https://docs.docker.com/compose/install/ for details on installing
docker-compose. The NilmDB container is available by request on `Docker Hub`_.
.. code-block:: bash
$> cd test/e2e
$> ./runner.sh # run end-to-end tests
.. _Docker Hub: https://hub.docker.com/
.. _installing-joule:
============
Installation
============
Joule requires NilmDb for stream storage [#f1]_. The other dependency is Python 3.5. On distros
that do not ship with Python 3.5 such as Raspbian it must be built from source.
Install NilmDb
--------------------
NilmDb is accessible from the Wattsworth git repository. Contact
donnal@usna.edu to request access. From the terminal, run the
following commands to install and configure NilmDb.
Install dependencies
.. code-block:: bash
$> sudo apt-get update
$> sudo apt-get install cython git build-essential \
python2.7 python2.7-dev python-setuptools python-pip \
python-cherrypy3 python-decorator python-requests \
python-dateutil python-tz python-progressbar python-psutil \
python-simplejson apache2 libapache2-mod-wsgi -y
Install NilmDb
.. code-block:: bash
$> git clone https://git.wattsworth.net/wattsworth/nilmdb.git
$> cd nilmdb
$> sudo make install
*Configure WSGI Scripts*
Create a directory for NilmDB (eg **/opt/nilmdb**), in this directory
create a file **nilmdb.wsgi** as shown below:
.. code-block:: python
import nilmdb.server
application = nilmdb.server.wsgi_application("/opt/nilmdb/db","/nilmdb")
This will create a virtual host at **http://localhost/nilmdb** with data stored
in the directory **/opt/nilmdb/db**. Now create a user to run Nilmdb and give them
permissions on the directory:
.. code-block:: bash
$> adduser nilmdb
$> sudo chown -R nilmdb:nilmdb /opt/nilmdb
*Configure Apache*
Edit the default virtual host configuration at
**/etc/apache2/site-available/000-default** to add the following lines
within the ``<VirtualHost>`` directive:
.. code-block:: apache
<VirtualHost *:80>
# Add these 6 lines
WSGIScriptAlias /nilmdb /opt/nilmdb/nilmdb.wsgi
WSGIDaemonProcess nilmdb-procgroup threads=32 user=nilmdb group=nilmdb
<Location /nilmdb>
WSGIProcessGroup nilmdb-procgroup
WSGIApplicationGroup nilmdb-appgroup
Require all granted
</Location>
# (other existing configuration here)
</VirtualHost>
Note these values assume you followed the user creation and file
naming guidelines above.
*Test the Installation*
Restart Apache to start the NilmDB server, then check the database is
available using the **nilmtool** command.
.. code-block:: bash
$> sudo apache2ctl restart
$> nilmtool info
Client version: 1.10.3
#...more information
Docker
^^^^^^
NilmDb is also available as a container through
Docker Hub. E-mail donnal@usna.edu for access. See the `docker homepage
<https://www.docker.com/>`_ for
more information on containers.
.. code-block:: bash
$> docker pull jdonnal/nilmdb
Install Python 3.5
------------------
Joule requires Python 3.5 or greater. As of this writing many distros including
Raspbian ship with earlier versions. Check your version by running
the following command:
.. code-block:: bash
$> sudo apt-get install python3 python3-pip -y
$> python3 -V
Python 3.5.2 #<--- this version is ok
If your version is 3.5.2 or greater, skip ahead to installing Joule, otherwise you
must build Python 3.5 from source by following the instructions below:
Install Dependencies
.. code-block:: bash
$> sudo apt-get install build-essential tk-dev libssl-dev libblas-dev \
liblapack-dev libbz2-dev gfortran libsqlite3-dev
Download and Install Source
.. code-block:: bash
$> wget https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tgz
$> tar -xvf Python-3.5.2.tgz
$> cd Python-3.5.2
$> ./configure
$> make
$> sudo make install
This will install python3.5 into **/usr/local/bin**
VirtualEnv
^^^^^^^^^^
You may optionally install Joule into a virtual environment, this is
recommended if you expect Joule to conflict with other Python tools
you already have installed. The easiest way to work with virtual
environments is with *virtualenvwrapper*
.. code-block:: bash
$> pip2 install virtualenv virtualenvwrapper
$> export WORKON_HOME=~/Envs
$> source /usr/local/bin/virtualenvwrapper.sh
(`Full virtualenvwrapper install
instructions. <https://virtualenvwrapper.readthedocs.io/en/latest/install.html>`_)
Create a new virtual environment using Python 3.5
.. code-block:: bash
$> mkvirtualenv joule -p /usr/local/bin/python3.5 #<-- path to 3.5 installation
$> workon joule
Install Joule
-------------
Joule is accessible form the Wattsworth git repository. Contact
donnal@usna.edu to request access. From the terminal, run the
following commands to install and configure Joule.
.. code-block:: bash
# install dependencies
# if python3.5 was installed from source you must specify the correct pip
# (ie /usr/local/bin/pip3.5 instead of pip3)
$> pip3 install --upgrade pip # make sure pip is up to date
$> pip3 install python-datetime-tz
$> apt-get install python3-numpy python3-scipy python3-yaml -y
.. code-block:: bash
# install Joule
$> git clone https://git.wattsworth.net/wattsworth/joule.git
$> cd joule
$> python3 setup.py install
*Configure Joule*
By default joule looks for configuration files at **/etc/joule**. Run
the following commands to create the basic directory structure
.. code-block:: bash
$> sudo mkdir -p /etc/joule/module_configs
$> sudo mkdir -p /etc/joule/stream_configs
$> sudo touch /etc/joule/main.conf
*Create Startup Scripts*
To configure Joule to run automatically you must add a configuration script to systemd. Copy the following into **/etc/systemd/system/joule.service**
.. code-block:: ini
[Unit]
Description = "Joule Management Daemon"
After = syslog.target
[Service]
Type = simple
# **note: path will be different if joule is in a virtualenv**
ExecStart = /usr/local/bin/jouled
StandardOutput = journal
StandardError = journal
Restart = always
[Install]
WantedBy = multi-user.target
To enable and start the joule service run
.. code-block:: bash
$> sudo systemctl enable joule.service
$> sudo systemctl start joule.service
Verify Installation
-------------------
Check that joule is running:
.. code-block:: bash
$> sudo systemctl status joule.service
● joule.service - "Joule Management Daemon"
Loaded: loaded (/etc/systemd/system/joule.service; enabled)
Active: active (running) since Tue 2017-01-17 09:53:21 EST; 7s ago
Main PID: 2296 (jouled)
CGroup: /system.slice/joule.service
└─2296 /usr/local/bin/python3 /usr/local/bin/jouled
Joule is managed from the terminal using the **joule** command, on a fresh
installation there is nothing for Joule to do so these commands will not return
data. Check that they are available by printing the help output.
.. code-block:: bash
$> joule modules -h
# ... some help text
$> joule logs -h
# ... some help text
Your Joule installation should be ready to go, read
:ref:`getting-started` to configure your first module and start
capturing data.
.. [#f1] A local installation of NilmDb is not strictly necessary as all
communication between Joule and NilmDb occurs over HTTP but sending
all stream data over a network connection to a remote NilmDb instance
may impact performance.
.. [#f2] These commands assume **python3** points to a Python
3.5 or later instance. If your system **python3** is earlier than 3.5
work in a virtual environment or adjust your environment to reference
the python3.5 binaries in **/usr/local/bin/**
============
NILM Modules
============
NILM modules provides a suite of reader and filter modules for
non-intrusive power monitors. The system is designed to be run using
a YAML configuration file located at **/opt/configs/meters.yml** although
the modules can be configured to run independently.
Installation
------------
NILM Modules is accessible from the Wattsworth git repository. Contact
donnal@usna.edu to request access. From the terminal, run the
following commands to install and configure NILM Modules
.. code-block:: bash
$> git clone https://git.wattsworth.net/wattsworth/nilm.git
$> cd nilm
$> sudo python3 setup.py install
Configuration
-------------
Set up a **meters.yml** file according to the guidelines at wattsworth.net for a `contact meter`_
or a `noncontact meter`_. Then run the following from the command line
.. code-block:: bash
$> nilm configure
This will install stream and module configurations into **/etc/joule/**. Each NILM meter
will have four streams located in **/meter#**
.. code-block:: none
/meter#/sensor
float32 stream of raw ADC sensor values
/meter#/iv
current and voltage at the sample rate of the sensor
/meter#/sinefit
zero crossings of the voltage waveform (freq, amplitude, offset)
/meter#/prep-a
/meter#/prep-b
/meter#/prep-c
harmonic envelopes of real and reactive power for each phase
Each NILM has a reader module **meter#_capture** and a filter module
**meter#_process**. The modules read configuration values from the
**meters.yml** file.
Verify Operation
----------------
To begin using the newly installed modules restart the **jouled** service by
running the following command:
.. code-block:: bash
$> sudo systemctl restart joule.service
Verify that the modules are running using the **joule modules** command.
.. code-block:: bash
$> joule modules
+--------------------------------+----------------+-----------------+---------+-----+--------------+
| Module | Sources | Destinations | Status | CPU | mem |
+--------------------------------+----------------+-----------------+---------+-----+--------------+
| meter4 process: | /meter4/sensor | /meter4/prep-a | running | 39% | 30 MB (355%) |
| reconstruct -> sinefit -> prep | | /meter4/prep-b | | | |
| | | /meter4/prep-c | | | |
| | | /meter4/iv | | | |
| | | /meter4/sinefit | | | |
| meter4 capture: | | /meter4/sensor | running | 8% | 28 MB (336%) |
| serial data capture | | | | | |
+--------------------------------+----------------+-----------------+---------+-----+--------------+
Any errors will be reported in the log files for each module. Use the
**joule logs** command to print recent log entries. The logs are
automatically rotated: see the ProcDB:MaxLogLines parameter in :ref:`main.conf`
.. code-block:: bash
$> joule logs "meter4 capture"
[23 Jan 2017 16:14:56] ---starting module---
$> joule logs "meter4 process"
[23 Jan 2017 16:14:56] ---starting module---
Check that the data is entering NilmDB using the **nilmtool** command. Joule inserts data periodically, see NilmDB:InsertionPeriod in :ref:`main.conf`
.. code-block:: bash
$> nilmtool list -En /meter4/prep*
/meter4/prep-a
interval extents: Mon, 23 Jan 2017 16:11:01.833447 -0500 -> Mon, 23 Jan 2017 16:16:29.322283 -0500
total data: 18054 rows, 300.878769 seconds
/meter4/prep-b
interval extents: Mon, 23 Jan 2017 16:11:01.833447 -0500 -> Mon, 23 Jan 2017 16:16:29.322283 -0500
total data: 18054 rows, 300.878769 seconds
/meter4/prep-c /meter4/prep-a
interval extents: Mon, 23 Jan 2017 16:11:01.833447 -0500 -> Mon, 23 Jan 2017 16:16:29.322283 -0500
total data: 18054 rows, 300.878769 seconds
.. _contact meter: https://www.wattsworth.net/help/software#config-contact
.. _noncontact meter: https://www.wattsworth.net/help/software#config-noncontact
Reference
===============
.. contents:: :local:
Command Line Utilities
----------------------
joule
'''''
jouled
''''''
nilmtool
''''''''
Configuration Files
-------------------
.. _main.conf:
main.conf
'''''''''
Joule uses a set of default configurations that should work for most
cases. These defaults can be customized by editing
**/etc/joule/main.conf**. Start joule with the **--config** flag to use a configuration file at
an alternate location. The example **main.conf** below shows the
full set of options and their default settings:
.. code-block:: ini
[NilmDB]
url = http://localhost/nilmdb
InsertionPeriod = 5
[ProcDB]
DbPath = /tmp/joule-proc-db.sqlite
MaxLogLines = 100
[Jouled]
ModuleDirectory = /etc/joule/module_configs
StreamDirectory = /etc/joule/stream_configs
See the list below for information on each setting.
``NilmDB``
* ``url``: address of NilmDB server
* ``InsertionPeriod``: how often to send stream data to NilmDB (in seconds)
``ProcDB``
* ``DbPath``: path to sqlite database used internally by joule
* ``MaxLogLines``: max number of lines to keep in a module log file (automatically rolls)
``Jouled``
* ``ModuleDirectory``: folder with module configuration files (absolute path)
* ``StreamDirectory``: folder with stream configuration files (absolute path)
stream configs
''''''''''''''
.. code-block:: ini
[Main]
#required settings (examples)
path = /nilmdb/path/name
datatype = float32
keep = 1w
#optional settings (defaults)
decimate = yes
[Element1...ElementN]
#required settings (examples)
name = Element Name
#optional settings (defaults)
plottable = yes
discrete = no
offset = 0.0
scale_factor = 1.0
default_max = null
default_min = null
module configs
''''''''''''''
.. code-block:: ini
[Main]
#required
name = module name
exec_cmd = /path/to/executable --args
#optional
description = a short description
[Source]
path1 = /nilmdb/input/stream1
path2 = /nilmdb/input/stream2
# additional sources...
[Destination]
path1 = /nilmdb/output/stream1
path2 = /nilmdb/output/stream2
# additional destinations...
.. _numpy_pipes:
Numpy Pipes
-----------
Concepts
''''''''
Methods
'''''''
E2E Utilities
-------------
joule
'''''
nilmtool
''''''''
.. _writing_modules:
===============
Writing Modules
===============
Modules are standalone processes managed by Joule. They are
connected to eachother and to the backing NilmDB datastore by
streams. Modules can have zero or more input streams and one or more
output streams. Joule does not impose any additional constraints on
modules but we recommend structuring modules using the reader
and filter patterns. See :ref:`joule-concepts` for more details.
The sections below show you how to write a custom reader or
filter by extending the **ReaderModule** and **FilterModule**
built-ins. This is recommended for most use cases. Before continuing,
clone the starter repository:
.. code-block:: bash
$> git clone https://git.wattsworth.net/wattsworth/example_modules.git
$> cd example_modules
# install nose2 and asynctest module to run tests
$> sudo pip3 install nose2 asynctest
This repository contains an example reader and filter as well as unit
testing and end to end testing infrastructure. Proper testing is
critical to designing complex modules, especially filters.
Custom Readers
--------------
This section explains how to use the **ReaderModule** class to develop
a custom reader module. The code snippets in this section refer to the
**ReaderDemo** module defined in **reader.py** from the example_modules
repository.
A reader module should extend from the base class **ReaderModule**, and
provide custom functionality by overriding the parent methods:
.. code-block:: python
from joule.client import ReaderModule
class ReaderDemo(ReaderModule):
"Example reader: generates incrementing values at user specified rate"
#...your code here...
The module should provide a custom ``__init__`` function which calls
the parent, and may define two special properties: **description** and
**help**. The description property should be a short one line summary of the module
eg "reads data from serial port", and the help property should be a longer, multiline
string explaining what the module does and how to use it, preferably with a usage example.
These properties are used by the **joule reader** help system.
You may also add any additional initialization code your module requires.
.. code-block:: python
def __init__(self):
super(ReaderDemo, self).__init__("Demo Reader")
self.description = "one line: demo reader"
self.help = "a paragraph: this reader does x,y,z etc..."
#...your custom initialization...
The module must also provide an implementation of
``custom_args``. This function receives a parser object and may add
custom arguments to it. See the `argparse documentation
<https://docs.python.org/3/library/argparse.html>`_ for details on
adding arguments to the parser. These arguments will be available to
the ``run`` function.
.. code-block:: python
def custom_args(self, parser):
parser.add_argument("rate", type=float, help="period in seconds")
#...additional arguments as required...
# ... or, if your module does not require arguments
def custom_args(self, parser):
pass
Finally, the module must implement ``run``. This function performs the
actual work in the module. It is an asynchronous coroutine but you
can generally treat it as a normal function. See the `asyncio documenation
<https://docs.python.org/3/library/asyncio.html>`_ for details on
coroutines.
.. code-block:: python
async def run(self, parsed_args, output): #<-- this is a coroutine
count = 0
while(1):
await output.write(np.array([[time_now(), count]])) #<--note await syntax
await asyncio.sleep(parsed_args.rate) #can also use time.sleep()
count += 1
This function takes two parameters, **parsed_args** and
**output**. The parsed_args is a namespace object with values for the
arguments specified in **custom_args**. **output** is a NumpyPipe that
connects the module to the joule system (see :ref:`numpy_pipes`). The
pipe has a single function, **write** which accepts a numpy array.
The array should be a matrix of timestamps and values, if you are
inserting a single sample, enclose the matrix in double braces to
provide the correct dimension. Also note that the **write** method is
a coroutine and must be called with the **await** keyword.
.. code-block:: python
data = np.array([[ts, val, val, val, ...],
[ts, val, val, val, ...],
....])
await output.write(data)
If you run the filter from the command line it will print values to stdout. This can help
debug your code. Additionally it is best practice to provide unittests for your custom reader
modules. An example is provided in **test_reader.py**. See :ref:`unit_testing` for more details.
Custom Filters
--------------
This section explains how to use the **FilterModule** class to develop
a custom filter module. The code snippets in this section refer to the
**FilterDemo** module defined in **filter.py** from the example_modules
repository.
A filter module should extend from the base class **FilterModule**, and
provide custom functionality by overriding the parent methods:
.. code-block:: python
from joule.client import FilterModule
class FilterDemo(FilterModule):
" Example filter: applies a dc offset "
#...your code here...
The module should provide a custom ``__init__`` function which calls
the parent, and may define two special properties: **description** and
**help**. The description property should be a short one line summary of the module
eg "computes a moving average", and the help property should be a longer, multiline
string explaining what the module does and how to use it, preferably with a usage example.
These properties are used by the **joule filter** help system.
You may also add any additional initialization code your module requires.
.. code-block:: python
def __init__(self):
super(ReaderDemo, self).__init__("Demo Reader")
self.description = "one line: demo reader"
self.help = "a paragraph: this reader does x,y,z etc..."
#...your custom initialization...
The module must also provide an implementation of
``custom_args``. This function receives a parser object and may add
custom arguments to it. See the `argparse documentation
<https://docs.python.org/3/library/argparse.html>`_ for details on
adding arguments to the parser. These arguments will be available to
the ``run`` function.
.. code-block:: python
def custom_args(self, parser):
parser.add_argument("offset", type=float, default=0,
help="apply an offset")
#...additional arguments as required...
# ... or, if your module does not require arguments
def custom_args(self, parser):
pass
Finally, the module must implement ``run``. This function performs the
actual work in the module. It is an asynchronous coroutine but for the most part you
can treat it as a normal function. See the `asyncio documenation
<https://docs.python.org/3/library/asyncio.html>`_ for details on
coroutines.
.. code-block:: python
async def run(self, parsed_args, inputs, outputs): #<-- this is a coroutine
stream_in = inputs["input"] #<--access pipes by name
stream_out = outputs["output"]
while(1):
sarray = await stream_in.read() #<--note await syntax
sarray["data"] += parsed_args.offset
await stream_out.write(sarray) #<--note await syntax
stream_in.consume(len(sarray)) #<--indicates
This function takes three parameters, **parsed_args**, **inputs**, and
**outputs**. The parsed_args is a namespace object with values for the
arguments specified in **custom_args**. **inputs** and **outputs** are
dictionaries of NumpyPipes indexed the names specified in the module
configuration file. These pipes connect the module to the joule system.
.. code-block:: ini
[Main]
exec_cmd = python3 filter.py
name = Demo Filter
[Source]
input = /demo/raw #<--name used in inputs dictionary
[Destination]
output = /demo/filtered #<--name used in outputs dictionary
The input pipes have two functions, **read** and **consume**. Access
data in the pipe using the read function which is a coroutine. This
returns a structured Numpy array by default, if you would like a
flattened array, set the optional parameter flatten.
.. code-block:: python
values = await stream_in.read()
# returns a structured array
# values['timestamp'] = [ts, ts, ts, ..., ts]
# values['data'] = [[val1, val2, val3, ..., valN],
# [val1, val2, val3, ..., valN],...]
values = await stream_in.read(flatten=True)
# returns a flat array
# values = [[ts, val1, val2, val3, ..., valN],
[ts, val1, val2, val3, ..., valN],...]
Every call to **read** should followed by **consume** to indicate how
much of the data your module has used. The next call to **read** will
prepend any unconsumed data from the previous read. This allows you to
design filters which operate on only a portion of the input data such
as linear filters. See the built-in **mean** and **median** filters
for an example of using a portion of the input data.
The **ouput** pipes have a single function **write** which accepts
a Numpy array. See the ReaderModule section for more details on output pipes.
Unlike ReaderModules, modules derived from FilterModule cannot be run
from the command line because filters require an input stream provided
by the joule environment.You should always verify your modules using
unittests. The testing framework provides mock input streams to test
modules in isolation. An example is provided in **test_filter.py**. See
:ref:`unit_testing` for more details.
/* This file intentionally left blank. */
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
};
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this);
});
}
}
return this.each(function() {
highlight(this);
});
};
/*
* backward compatibility for jQuery.browser
* This will be supported until firefox bug is fixed.
*/
if (!jQuery.browser) {
jQuery.uaMatch = function(ua) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated == 'undefined')
return string;
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
* see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
if (!body.length) {
body = $('body');
}
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
},
initOnKeyListeners: function() {
$(document).keyup(function(event) {
var activeElementType = document.activeElement.tagName;
// don't navigate when in search box or textarea
if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
switch (event.keyCode) {
case 37: // left
var prevHref = $('link[rel="prev"]').prop('href');
if (prevHref) {
window.location.href = prevHref;
return false;
}
case 39: // right
var nextHref = $('link[rel="next"]').prop('href');
if (nextHref) {
window.location.href = nextHref;
return false;
}
}
}
});
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});
\ No newline at end of file
This diff could not be displayed because it is too large.
.highlight .hll { background-color: #ffffcc }
.highlight { background: #eeffcc; }
.highlight .c { color: #408090; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #333333 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #208050 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #208050 } /* Literal.Number.Bin */
.highlight .mf { color: #208050 } /* Literal.Number.Float */
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Joule Concepts &#8212; Joule 1.0.0 documentation</title>
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Installation" href="install.html" />
<link rel="prev" title="Joule: Modular Data Processing" href="index.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head>
<body role="document">
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="joule-concepts">
<span id="id1"></span><h1>Joule Concepts<a class="headerlink" href="#joule-concepts" title="Permalink to this headline"></a></h1>
<div class="section" id="streams">
<span id="id2"></span><h2>Streams<a class="headerlink" href="#streams" title="Permalink to this headline"></a></h2>
<p>Streams are timestamped data flows that connect modules together.
Streams can represent primary measurements such as readings from a current
sensor or derived measurements such as harmonic content. A stream has
one or more elements and can be viewed as a database table:</p>
<blockquote>
<div><table border="1" class="docutils">
<colgroup>
<col width="25%" />
<col width="22%" />
<col width="22%" />
<col width="8%" />
<col width="22%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">timestamp</th>
<th class="head">element1</th>
<th class="head">element2</th>
<th class="head">...</th>
<th class="head">elementN</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>1003421</td>
<td>0.0</td>
<td>10.5</td>
<td>...</td>
<td>2.3</td>
</tr>
<tr class="row-odd"><td>1003423</td>
<td>1.0</td>
<td>-8.0</td>
<td>...</td>
<td>2.3</td>
</tr>
<tr class="row-even"><td>1003429</td>
<td>8.0</td>
<td>12.5</td>
<td>...</td>
<td>2.3</td>
</tr>
<tr class="row-odd"><td>1003485</td>
<td>4.0</td>
<td>83.5</td>
<td>...</td>
<td>2.3</td>
</tr>
</tbody>
</table>
</div></blockquote>
</div>
<div class="section" id="modules">
<span id="id3"></span><h2>Modules<a class="headerlink" href="#modules" title="Permalink to this headline"></a></h2>
<p>Modules process streams. A module may receive zero, one or more
input streams and may produce zero, one, or more output streams. While
Joule does not enforce any structure on modules, we suggest
structuring your data pipeline with two types of modules: Readers, and
Filters. Readers take no inputs. They directly manage a sensor (eg a
TTY USB device) and generate an output data stream with sensor
values. Filters take these streams as inputs and produce new outputs.
Filters can be chained to produce complex behavior from simple,
reusable building blocks.</p>
</div>
<div class="section" id="example">
<h2>Example<a class="headerlink" href="#example" title="Permalink to this headline"></a></h2>
<p>Using a light sensor and temperature sensor to detect occupancy in a room:</p>
<img alt="_images/joule_system.png" src="_images/joule_system.png" />
</div>
<div class="section" id="pipes">
<h2>Pipes<a class="headerlink" href="#pipes" title="Permalink to this headline"></a></h2>
<p>Pipes connect streams to modules. Pipe read and writes are asynchronous
coroutines which allows modules to effeciently manage many pipe connections
at once. The animation below shows a producer module using a pipe to communicate
with a consume module. See reference section for details on the pipe API.</p>
<img alt="_images/joule_pipe.gif" src="_images/joule_pipe.gif" />
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo">
<a href="index.html">
<img class="logo" src="_static/logo.png" alt="Logo"/>
</a>
</p>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">Joule Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#streams">Streams</a></li>
<li class="toctree-l2"><a class="reference internal" href="#modules">Modules</a></li>
<li class="toctree-l2"><a class="reference internal" href="#example">Example</a></li>
<li class="toctree-l2"><a class="reference internal" href="#pipes">Pipes</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="install.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="writing_modules.html">Writing Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="testing_modules.html">Testing Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="nilm.html">NILM Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="reference.html">Reference</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
<li>Previous: <a href="index.html" title="previous chapter">Joule: Modular Data Processing</a></li>
<li>Next: <a href="install.html" title="next chapter">Installation</a></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<div><input type="text" name="q" /></div>
<div><input type="submit" value="Go" /></div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2017, John Donnal.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 1.5.1</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.9</a>
|
<a href="_sources/concepts.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Index &#8212; Joule 1.0.0 documentation</title>
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="index" title="Index" href="#" />
<link rel="search" title="Search" href="search.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head>
<body role="document">
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1 id="index">Index</h1>
<div class="genindex-jumpbox">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo">
<a href="index.html">
<img class="logo" src="_static/logo.png" alt="Logo"/>
</a>
</p>
<h3>Navigation</h3>
<ul>
<li class="toctree-l1"><a class="reference internal" href="concepts.html">Joule Concepts</a></li>
<li class="toctree-l1"><a class="reference internal" href="install.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="writing_modules.html">Writing Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="testing_modules.html">Testing Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="nilm.html">NILM Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="reference.html">Reference</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<div><input type="text" name="q" /></div>
<div><input type="submit" value="Go" /></div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2017, John Donnal.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 1.5.1</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.9</a>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Joule: Modular Data Processing &#8212; Joule 1.0.0 documentation</title>
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Joule Concepts" href="concepts.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head>
<body role="document">
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="joule-modular-data-processing">
<h1>Joule: Modular Data Processing<a class="headerlink" href="#joule-modular-data-processing" title="Permalink to this headline"></a></h1>
<p>Joule is a data capture and signal processing engine. It allows you to
turn a single board computer like the Raspberry Pi into a robust
sensor platform. Joule uses modules to build complex acquisition and
signal processing workflows from simple building blocks. Modules are
user defined processes that are connected together by data streams.</p>
<p>Joule acts as a process manager, ensuring that modules start at system
boot and are restarted if they fail. Joule also collects runtime
statistics and logs for each module making it easy to detect
bugs and find bottlenecks in processing pipelines.</p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="concepts.html">Joule Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="concepts.html#streams">Streams</a></li>
<li class="toctree-l2"><a class="reference internal" href="concepts.html#modules">Modules</a></li>
<li class="toctree-l2"><a class="reference internal" href="concepts.html#example">Example</a></li>
<li class="toctree-l2"><a class="reference internal" href="concepts.html#pipes">Pipes</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="install.html">Installation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="install.html#install-nilmdb">Install NilmDb</a></li>
<li class="toctree-l2"><a class="reference internal" href="install.html#install-python-3-5">Install Python 3.5</a></li>
<li class="toctree-l2"><a class="reference internal" href="install.html#install-joule">Install Joule</a></li>
<li class="toctree-l2"><a class="reference internal" href="install.html#verify-installation">Verify Installation</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getting_started.html#a-reader-module">A Reader Module</a></li>
<li class="toctree-l2"><a class="reference internal" href="getting_started.html#a-filter-module">A Filter Module</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="writing_modules.html">Writing Modules</a><ul>
<li class="toctree-l2"><a class="reference internal" href="writing_modules.html#custom-readers">Custom Readers</a></li>
<li class="toctree-l2"><a class="reference internal" href="writing_modules.html#custom-filters">Custom Filters</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="testing_modules.html">Testing Modules</a><ul>
<li class="toctree-l2"><a class="reference internal" href="testing_modules.html#unit-testing">Unit Testing</a></li>
<li class="toctree-l2"><a class="reference internal" href="testing_modules.html#end-to-end-testing">End-to-End Testing</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="nilm.html">NILM Modules</a><ul>
<li class="toctree-l2"><a class="reference internal" href="nilm.html#installation">Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="nilm.html#configuration">Configuration</a></li>
<li class="toctree-l2"><a class="reference internal" href="nilm.html#verify-operation">Verify Operation</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="reference.html">Reference</a><ul>
<li class="toctree-l2"><a class="reference internal" href="reference.html#command-line-utilities">Command Line Utilities</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#configuration-files">Configuration Files</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#numpy-pipes">Numpy Pipes</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#e2e-utilities">E2E Utilities</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="contributing-running-tests">
<h2>Contributing &amp; Running Tests<a class="headerlink" href="#contributing-running-tests" title="Permalink to this headline"></a></h2>
<p>Contribution is always welcome. Please include tests with your pull request.
Unittests can be run using nose2, see <strong>joule/htmlcov</strong> for code coverage.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$&gt; <span class="nb">cd</span> joule
$&gt; nose2 <span class="c1"># run all unittests</span>
</pre></div>
</div>
<p>End to end tests are run from the <strong>tests/e2e</strong> directory and require
docker-compose and the NilmDB container. See
<a class="reference external" href="https://docs.docker.com/compose/install/">https://docs.docker.com/compose/install/</a> for details on installing
docker-compose. The NilmDB container is available by request on <a class="reference external" href="https://hub.docker.com/">Docker Hub</a>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$&gt; <span class="nb">cd</span> test/e2e
$&gt; ./runner.sh <span class="c1"># run end-to-end tests</span>
</pre></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo">
<a href="#">
<img class="logo" src="_static/logo.png" alt="Logo"/>
</a>
</p>
<h3>Navigation</h3>
<ul>
<li class="toctree-l1"><a class="reference internal" href="concepts.html">Joule Concepts</a></li>
<li class="toctree-l1"><a class="reference internal" href="install.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="writing_modules.html">Writing Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="testing_modules.html">Testing Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="nilm.html">NILM Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="reference.html">Reference</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="#">Documentation overview</a><ul>
<li>Next: <a href="concepts.html" title="next chapter">Joule Concepts</a></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<div><input type="text" name="q" /></div>
<div><input type="submit" value="Go" /></div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2017, John Donnal.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 1.5.1</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.9</a>
|
<a href="_sources/index.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>
\ No newline at end of file
No preview for this file type
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &#8212; Joule 1.0.0 documentation</title>
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="#" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
<script type="text/javascript" id="searchindexloader"></script>
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head>
<body role="document">
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1 id="search-documentation">Search</h1>
<div id="fallback" class="admonition warning">
<script type="text/javascript">$('#fallback').hide();</script>
<p>
Please activate JavaScript to enable the search
functionality.
</p>
</div>
<p>
From here you can search these documents. Enter your search
words into the box below and click "search". Note that the search
function will automatically search for all of the words. Pages
containing fewer words won't appear in the result list.
</p>
<form action="" method="get">
<input type="text" name="q" value="" />
<input type="submit" value="search" />
<span id="search-progress" style="padding-left: 10px"></span>
</form>
<div id="search-results">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo">
<a href="index.html">
<img class="logo" src="_static/logo.png" alt="Logo"/>
</a>
</p>
<h3>Navigation</h3>
<ul>
<li class="toctree-l1"><a class="reference internal" href="concepts.html">Joule Concepts</a></li>
<li class="toctree-l1"><a class="reference internal" href="install.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="writing_modules.html">Writing Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="testing_modules.html">Testing Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="nilm.html">NILM Modules</a></li>
<li class="toctree-l1"><a class="reference internal" href="reference.html">Reference</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
</ul></li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2017, John Donnal.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 1.5.1</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.9</a>
</div>
</body>
</html>
\ No newline at end of file
Search.setIndex({docnames:["getting_started","index","install","nilm","writing_modules"],envversion:51,filenames:["getting_started.rst","index.rst","install.rst","nilm.rst","writing_modules.rst"],objects:{},objnames:{},objtypes:{},terms:{"0hz":0,"1e6":[],"case":4,"class":4,"default":[0,2,4],"export":2,"final":4,"float":4,"function":4,"import":[2,4],"new":[0,2],"null":[],"return":[2,4],"short":4,"super":4,"true":4,"try":[],"while":4,E2E:1,Not:[],That:0,The:[1,2,3,4],Then:3,There:[],These:[2,4],Use:3,Using:[],__init__:4,__main__:[],__name__:[],_captur:3,_process:3,about:[],abov:[0,2],absolut:[],accept:4,access:[2,3,4],accord:3,acquisit:1,act:1,activ:2,actual:4,adc:3,add:[0,2,4],add_argu:4,added:[],adding:4,addit:4,addition:4,address:[],addus:2,adjust:2,after:2,ago:2,ahead:2,all:[0,1,2],alloc:0,allow:[1,4],alreadi:2,also:[1,2,4],altern:[],although:3,alwai:[1,2,4],amplitud:3,ani:[3,4],anim:[],apach:2,apache2:2,apache2ctl:2,apart:[],api:[],appgroup:2,appli:4,applic:2,appropri:[],apt:2,arang:[],arg:[],argpars:4,argument:4,arithmet:[],arrai:4,assembl:[],assert:[],assert_array_almost_equ:[],assert_array_equ:[],associ:[],assum:2,assur:[],async:4,asynchron:4,asyncio:4,asynctest:4,attach:[],automat:[2,3],avaiabl:0,avail:[1,2,4],averag:[0,4],await:4,back:4,base:4,basic:2,becaus:4,befor:[0,4],begin:3,behavior:[],below:[2,4],best:4,between:2,bin:2,binari:2,block:1,board:1,boilerpl:[],boot:1,bootstrap:[],both:0,bottleneck:1,brace:4,bug:1,build:[0,1,2],built:[2,4],builtin:0,call:[0,4],call_lat:[],can:[0,1,3,4],cancel:[],cancellederror:[],cannot:4,captur:[0,1,2,3],cgroup:2,chain:[],check:[0,2,3],check_data:[],check_log:[],check_modul:[],cherrypy3:2,chown:2,clean:[],cleanli:[],client:[2,4],clone:[2,3,4],close:[],code:[1,4],collect:1,column:[],com:1,combin:[],command:[0,1,2,3,4],common:[],commun:2,compar:[],complet:[],complex:[1,4],compos:1,comput:[0,1,4],concept:[0,1,4],conf:[0,2,3],confid:[],config:3,configur:[0,1,2,4],confirm:0,conflict:2,connect:[0,1,2,4],consist:0,constraint:4,consum:4,contact:[2,3],contain:[1,2,4],content:[],continu:[0,4],copi:[0,2],coroutin:4,correct:[2,4],correctli:[],count:4,counter:[],coverag:1,cpu:[0,3],creat:[0,2],creation:2,credenti:[],critic:4,cross:3,current:3,custom:[0,1],custom_arg:4,cython:2,daemon:2,data:[0,2,3,4],databas:[0,2],dataset:[],datastor:4,datatyp:0,date:2,datetim:2,dateutil:2,dbpath:[],debug:4,decim:[],decor:2,def:4,default_max:[],default_min:[],defin:[1,4],degre:[],demo:[0,4],demo_filt:0,demo_random:0,demo_read:0,demonstr:0,depend:2,deploi:[],deriv:4,describ:[],descript:[0,2,4],design:[3,4],desir:[],destin:[0,3,4],detail:[0,1,4],detect:1,dev:2,develop:4,devic:[],dictionari:4,diff:[],differ:[0,2],dimens:4,direct:2,directli:[],directori:[1,2],disabl:[],discret:[],displai:0,distro:2,doc:1,docker:1,docstr:[],documen:4,document:4,doe:4,donnal:[2,3],doubl:4,down:[],download:2,e2e:1,e2e_joule_1:[],e2eutil:[],each:[1,3],eachoth:4,earlier:2,easi:1,easiest:2,ect:[],edit:2,edu:[2,3],effeci:[],element1:0,element2:0,element:0,elementn:[],enabl:2,enclos:4,end:[1,4],enforc:[],engin:1,ensur:1,ensure_futur:[],enter:[0,3],entri:3,env:2,envelop:3,environ:[2,4],error:3,especi:4,essenti:2,est:2,etc:[0,2,3,4],everi:4,exactli:[],exampl:[0,1,4],example_modul:4,except:[],exec:[],exec_cmd:[0,4],execstart:2,execut:[],exist:[0,2],exit:[],expect:[0,2],explain:4,extend:4,extent:[0,3],fail:1,fake:[],familiar:0,few:[],field:[],file:[0,1,2,3,4],filter:[1,3],filterdemo:4,filtered1:0,filtered2:0,filtermodul:4,find:1,first:[0,2],flag:[],flat:4,flatten:4,float32:[0,3],float32_1:[],flow:[],folder:[],follow:[0,2,3,4],form:2,four:3,framework:4,freq:3,fresh:2,fri:0,from:[0,1,2,3,4],ftp:2,full:[0,2],gener:[0,4],get:[1,2],get_event_loop:[],gfortran:2,git:[2,3,4],give:2,given:[],global:[],good:[],grant:2,greater:2,greatli:[],group:2,guid:[],guidelin:[2,3],harmon:3,has:[0,3,4],have:[2,3,4],help:[0,2,4],here:[0,2,4],high:[],hold:0,homepag:2,host:2,how:4,hstack:[],htmlcov:1,http:[0,1,2,3,4],hub:[1,2],ignor:[],impact:2,implement:4,impos:4,improv:[],includ:[0,1,2],increas:[],increment:4,independ:3,index:4,indic:4,inexact:[],info:2,inform:2,infrastructur:4,initi:4,inner:[],input:[0,4],ins:4,insert:[3,4],insertionperiod:3,instal:[0,1,4],instanc:2,instead:2,instruct:2,int32:[],intern:[],interpret:[],interrog:[],interv:[0,3],intrus:3,isol:4,jan:[0,3],jdonnal:2,joul:[0,3,4],journal:2,just:[],keep:0,keyword:4,larg:[],later:2,layout:0,len:4,libapache2:2,libbla:2,libbz2:2,liblapack:2,librari:[],libsqlite3:2,libssl:2,light:[],like:[1,4],line:[0,1,2,3,4],linear:4,list:[0,3],live:[],load:2,local:2,localhost:[0,2],localnumpypip:[],locat:[2,3],log:[0,1,2,3],logic:[],longer:4,look:2,mai:[2,4],mail:2,main:[0,2,3,4],make:[0,1,2],manag:[1,2,4],mani:2,manual:[],match:[],matrix:4,max:[],maxloglin:3,mean:[0,4],measur:[],median:[0,4],mem:[0,3],meter4:3,meter:3,method:4,mimic:[],mkdir:2,mkvirtualenv:2,mock:4,mod:2,modul:[1,2],module_config:[0,2],moduledirectori:[],mon:3,monitor:3,more:[0,2,4],most:4,move:[0,4],much:4,multi:2,multilin:4,multipurpos:0,must:[0,2,4],my_filt:[],my_read:[],my_task:[],name:[0,2,4],namespac:4,necessari:2,need:0,net:[2,3,4],network:2,newli:3,next:[0,4],nilm:1,nilmdb:[0,1,3,4],nilmtool:[0,2,3],non:3,noncontact:3,none:[],normal:4,nose2:[1,4],note:[0,2,4],noth:2,now:[0,2],number:0,numpi:[1,2,4],numpypip:4,object:[0,4],occup:[],occur:2,offset:[3,4],often:[],omit:[],onc:[],one:4,ones:[],onli:4,oper:[0,1,4],opt:[2,3],option:[0,2,4],order:[],org:2,other:2,otherwis:2,ouput:4,our:0,output:[0,2,4],over:2,overrid:4,own:[],paragraph:4,paramet:[3,4],parent:4,parsed_arg:4,parser:4,part:4,pass:4,path1:[],path2:[],path:[0,2],pattern:4,per:0,perform:[0,2,4],period:[3,4],permiss:2,phase:3,pid:2,pip2:2,pip3:[2,4],pip:2,pipe:[0,1,4],pipe_in:[],pipe_out:[],pipelin:[0,1],platform:1,pleas:1,plottabl:[],point:2,port:[0,4],portion:4,possibl:[],power:3,practic:4,prefer:4,prep:3,prepend:4,prescript:[],prevent:[],previou:4,primari:[],print:[0,2,3,4],proc:[],procdb:3,process:[3,4],procgroup:2,produc:[],product:[],progressbar:2,project:[],prompt:[],proper:4,properli:[],properti:4,provid:[0,3,4],psutil:2,pull:[1,2],python2:2,python3:[2,3,4],python:1,rand1:0,rand2:0,random:0,rang:[],raspberri:1,raspbian:2,rate:[3,4],rather:[],raw:[3,4],reactiv:3,read:[0,2,3,4],read_nowait:[],reader:[1,3],readerdemo:4,readermodul:4,readi:2,real:3,receiv:4,recent:3,recogn:[],recommend:[2,4],reconstruct:3,reduc:[],refactor:[],refer:[1,2,4],regress:[],remot:2,remov:0,report:3,repositori:[0,2,3,4],repres:[],request:[1,2,3],requir:[1,2,4],rest:[],restart:[0,1,2,3],resul:[],retriev:[],reusabl:[],robust:1,roll:[],room:[],rotat:3,routin:[],row:[0,3],run:[0,2,3,4],run_until_complet:[],runner:1,runtim:1,safe:[],same:[],sampl:[3,4],sarrai:4,scale_factor:[],schedul:[],scipi:2,script:2,second:[0,3,4],section:[0,4],see:[0,1,2,3,4],seed:[],seem:[],self:4,send:[0,2],sensor:[1,3],sequenc:[],serial:[0,3,4],serv:[],server:2,servic:[0,2,3],set:[0,3,4],setup:[0,2,3],setuptool:2,sever:0,ship:2,should:[2,4],show:4,shown:[0,2],signal:1,similar:[],simpl:[0,1,2],simplejson:2,simpli:0,sinc:2,sinefit:3,singl:[1,4],site:2,size:0,skip:2,sleep:4,slice:2,slower:[],snippet:4,some:2,sourc:[0,2,3,4],special:4,specifi:[2,4],spuriou:[],sqlite:[],standalon:4,standard:[],standarderror:2,standardoutput:2,start:[1,2,3],starter:4,startup:2,statist:1,statu:[0,2,3],stdout:[0,4],step:[],stop:[],storag:2,store:[0,2],stream1:[],stream2:[],stream:[0,1,2,3,4],stream_config:[0,2],stream_in:4,stream_out:4,streamdirectori:[],strictli:2,string:4,structur:[2,4],subdirectori:[],sudo:[0,2,3,4],suggest:[],suit:3,summari:4,sure:[0,2],synchron:[],syntax:4,syslog:2,system:[0,1,2,3,4],systemctl:[0,2,3],systemd:2,tabl:[],take:4,tar:2,target:2,task:[],tear:[],tediou:[],temperatur:[],termin:[2,3],test:[2,4],test_:[],test_filt:4,test_input:[],test_read:4,testcas:[],testfilt:[],testread:[],text:2,tgz:2,than:2,thei:[1,2,4],them:2,therefor:[],thi:[0,2,3,4],thing:[],though:[],thread:2,three:4,through:2,time:4,time_now:4,timestamp:4,tmp:[],togeth:1,tool:2,top:[],total:[0,3],touch:2,treat:4,tty:[],tue:2,turn:1,two:[0,4],type:[0,2,4],unconsum:4,understand:[],unit:[1,2,4],unittest:[1,4],unlik:4,unset:[],until:[],updat:2,upgrad:2,url:[],usag:4,usb:[],use:[0,4],used:4,user:[1,2,4],uses:1,using:[0,1,2,3,4],usna:[2,3],usr:2,util:1,val1:4,val2:4,val3:4,val:4,valn:4,valu:[0,2,3,4],vari:[],verifi:[1,4],version:2,view:[],virtual:2,virtualenvwrapp:2,virtualhost:2,voltag:3,wai:2,wait:[],want:[],wantedbi:2,wattsworth:[2,3,4],waveform:3,welcom:1,well:4,wget:2,what:4,when:0,which:[0,4],window:0,within:2,work:[2,4],workflow:1,workon:2,workon_hom:2,would:4,write:[0,1,2],write_nowait:[],written:[],wsgi:2,wsgi_appl:2,wsgiapplicationgroup:2,wsgidaemonprocess:2,wsgiprocessgroup:2,wsgiscriptalia:2,www:2,xvf:2,yaml:[2,3],yes:[],yml:3,you:[0,1,2,4],your:[0,1,2,4],zero:[3,4]},titles:["Getting Started","Joule: Modular Data Processing","Installation","NILM Modules","Writing Modules"],titleterms:{E2E:[],build:[],check:[],command:[],concept:[],conf:[],config:[],configur:3,contribut:1,custom:4,data:1,docker:2,end:[],event:[],exampl:[],file:[],filter:[0,4],filtermodul:[],get:0,instal:[2,3],joul:[1,2],line:[],loop:[],main:[],method:[],modul:[0,3,4],modular:1,nilm:3,nilmdb:2,nilmtool:[],numpi:[],object:[],oper:3,pipe:[],process:1,python:2,reader:[0,4],readermodul:[],refer:[],result:[],run:1,start:0,stream:[],test:1,unit:[],util:[],verifi:[2,3],virtualenv:2,write:4}})
\ No newline at end of file
No preview for this file type
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &#8212; Wattsworth 1.0 documentation</title>
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="#" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
<script type="text/javascript" id="searchindexloader"></script>
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head>
<body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1 id="search-documentation">Search</h1>
<div id="fallback" class="admonition warning">
<script type="text/javascript">$('#fallback').hide();</script>
<p>
Please activate JavaScript to enable the search
functionality.
</p>
</div>
<p>
From here you can search these documents. Enter your search
words into the box below and click "search". Note that the search
function will automatically search for all of the words. Pages
containing fewer words won't appear in the result list.
</p>
<form action="" method="get">
<input type="text" name="q" value="" />
<input type="submit" value="search" />
<span id="search-progress" style="padding-left: 10px"></span>
</form>
<div id="search-results">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper"><div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
</ul></li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2017, John Donnal, James Paris.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 1.6.2</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.10</a>
</div>
</body>
</html>
\ No newline at end of file
Search.setIndex({docnames:["index"],envversion:52,filenames:["index.rst"],objects:{},objnames:{},objtypes:{},terms:{"while":0,Use:0,all:0,appli:0,apt:0,arm:0,avail:0,base:0,bash:[],been:0,best:0,bit:0,block:[],board:0,clone:0,code:[],complet:0,comput:0,get:0,git:0,has:0,http:0,index:0,intel:0,linux:0,modul:0,modulepath:0,modules_path:[],net:0,nuc:0,page:0,possibl:0,puppet:0,raspberri:0,repositori:0,run:0,search:0,singl:0,site:0,stack:0,sudo:0,system:0,test:0,ubuntu:0,updat:0,verbos:0,work:0,x86:0},titles:["The Wattsworth Project"],titleterms:{The:0,document:[],indic:0,instal:0,project:0,softwar:0,tabl:0,wattsworth:0,welcom:[]}})
\ No newline at end of file
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
No preview for this file type
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment