Commit 42c26d44 by John Donnal

added new modules and project structure

parent 674f1495
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
.message{
background: #c2daf3;
margin: 4px;
padding: 8px;
border-radius: 0.4rem;
border-color: #007bff;
border-style: solid;
border-width: 2px;
margin-left: 10px;
font-weight: bold;
}
This diff could not be displayed because it is too large.
$(function () {
setInterval(loadData, 2000);
$("#update-interval").val(loadData);
});
function loadData(){
$.get("data.json", function (data) {
$("#data").text(data['random_value']);
});
}
function change_bkgd(){
let color = parseInt(Math.random()*0xFFFFFF).toString(16);
$(".jumbotron").css("background", "#"+color);
}
\ 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.
{% extends "layout.jinja2" %}
{% block title %} Bootstrap Interface {% endblock %}
{% block css %}
<link rel="stylesheet" href="assets/css/index.css">
{% endblock %}
{% block js %}
<script src="assets/js/index.js"></script>
{% endblock %}
{% block content %}
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">Bootstrap Interface</h1>
<p class="lead">
This module uses CSS and Javascript to create an interactive UI
</p>
<hr class="my-4">
<ul class="list-group">
<!-- example of jinja2 data -->
<li class="list-group-item">Static value injected with jinja2:
<span class="message">{{ message }}</span>
</li>
<!-- example of AJAX data -->
<li class="list-group-item">Dynamic data loaded with AJAX:
<!-- see assets/index.js for AJAX code -->
<span id="data" class="message">&mdash;</span>
</li>
</ul>
<p class="lead mt-4">
<button class="btn btn-primary btn-lg" onclick="change_bkgd()">
Change Background
</button>
</p>
</div>
</div>
{% endblock %}
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<!-- load the page specif CSS -->
{% block css %}{% endblock %}
<title>{% block title %} Default Title {% endblock %}</title>
</head>
<body>
<div class="container-fluid">
<!-- page specific content here -->
{% block content %}
Default Content
{% endblock %}
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="assets/js/jquery-3.3.1.min.js"></script>
<script src="assets/js/popper.min.js"></script>
<script src="assets/js/bootstrap.bundle.min.js" ></script>
<!-- load the page specific js -->
{% block js %}{% endblock %}
</body>
</html>
\ No newline at end of file
#!/usr/bin/env python3
import asyncio import asyncio
from aiohttp import web from aiohttp import web
from joule.client.reader_module import ReaderModule
import aiohttp_jinja2 import aiohttp_jinja2
import jinja2 import jinja2
import os import os
from random import randint
from joule.client.reader_module import ReaderModule
CSS_DIR = os.path.join(os.path.dirname(__file__), 'assets', 'css') CSS_DIR = os.path.join(os.path.dirname(__file__), 'assets', 'css')
JS_DIR = os.path.join(os.path.dirname(__file__), 'assets', 'js') JS_DIR = os.path.join(os.path.dirname(__file__), 'assets', 'js')
...@@ -31,14 +35,18 @@ class BootstrapInterface(ReaderModule): ...@@ -31,14 +35,18 @@ class BootstrapInterface(ReaderModule):
@aiohttp_jinja2.template('index.jinja2') @aiohttp_jinja2.template('index.jinja2')
async def index(self, request): async def index(self, request):
return {'name': "Data Visualizer", return {'message': "hello world"}
'version': 1.0}
# json end point for AJAX requests # json end point for AJAX requests
async def data(self, request): async def data(self, request):
# return summary statistics, etc. # return summary statistics, etc.
return web.json_response(data=[1,2,8]) return web.json_response(data={'random_value': randint(0, 10)})
if __name__ == "__main__":
r = ComplexInterface() def main():
r = BootstrapInterface()
r.start() r.start()
if __name__ == "__main__":
main()
...@@ -6,21 +6,22 @@ from joule import CompositeModule, LocalNumpyPipe ...@@ -6,21 +6,22 @@ from joule import CompositeModule, LocalNumpyPipe
from high_bandwidth_reader import HighBandwidthReader from high_bandwidth_reader import HighBandwidthReader
from example_filter import ExampleFilter from example_filter import ExampleFilter
class ExampleComposite(CompositeModule): class ExampleComposite(CompositeModule):
""" Merge reader and filter into a single module: """ Merge reader and filter into a single module:
[reader -> filter]-> [reader -> filter]->
""" """
async def setup(self, parsed_args, async def setup(self, parsed_args,
inputs, outputs): inputs, outputs):
# 1.) create nested modules
#1.) create nested modules
my_reader = HighBandwidthReader() my_reader = HighBandwidthReader()
my_filter = ExampleFilter() my_filter = ExampleFilter()
#2.) create local pipes for interior streams # 2.) create local pipes for interior streams
pipe = LocalNumpyPipe(name="raw", layout="float32_1") pipe = LocalNumpyPipe(name="raw", layout="float32_1")
#3.) convert modules into tasks # 3.) convert modules into tasks
# output is an interior stream (write-end) # output is an interior stream (write-end)
parsed_args = argparse.Namespace(rate=100) parsed_args = argparse.Namespace(rate=100)
task1 = my_reader.run(parsed_args, pipe) task1 = my_reader.run(parsed_args, pipe)
...@@ -31,9 +32,14 @@ class ExampleComposite(CompositeModule): ...@@ -31,9 +32,14 @@ class ExampleComposite(CompositeModule):
{"raw": pipe}, {"raw": pipe},
{"filtered": outputs["filtered"]}) {"filtered": outputs["filtered"]})
#4.) tasks are executed in the main event loop # 4.) tasks are executed in the main event loop
return [task1, task2] return [task1, task2]
if __name__ == "__main__":
def main():
r = ExampleComposite() r = ExampleComposite()
r.start() r.start()
if __name__ == "__main__":
main()
#!/usr/bin/python3 #!/usr/bin/env python3
from joule import FilterModule, EmptyPipe from joule import FilterModule, EmptyPipe
from scipy.signal import medfilt from scipy.signal import medfilt
...@@ -33,6 +33,10 @@ class ExampleFilter(FilterModule): ...@@ -33,6 +33,10 @@ class ExampleFilter(FilterModule):
await asyncio.sleep(1) await asyncio.sleep(1)
if __name__ == "__main__": def main():
r = ExampleFilter() r = ExampleFilter()
r.start() r.start()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
import asyncio import asyncio
from aiohttp import web from aiohttp import web
from joule.client.reader_module import ReaderModule from joule import ReaderModule
class ExampleInterface(ReaderModule): class ExampleInterface(ReaderModule):
...@@ -17,6 +19,10 @@ class ExampleInterface(ReaderModule): ...@@ -17,6 +19,10 @@ class ExampleInterface(ReaderModule):
return web.Response(text="hello world!") return web.Response(text="hello world!")
if __name__ == "__main__": def main():
r = ExampleVisualizer() r = ExampleInterface()
r.start() r.start()
if __name__ == "__main__":
main()
#!/usr/bin/python3 #!/usr/bin/env python3
from joule import ReaderModule from joule import ReaderModule
from joule.utilities import time_now from joule.utilities import time_now
...@@ -10,11 +10,16 @@ class ExampleReader(ReaderModule): ...@@ -10,11 +10,16 @@ class ExampleReader(ReaderModule):
"Example reader: generates random values" "Example reader: generates random values"
async def run(self, parsed_args, output): async def run(self, parsed_args, output):
while(1): while True:
value = np.random.rand() # data from sensor value = np.random.rand() # data from sensor
await output.write(np.array([[time_now(), value]])) await output.write(np.array([[time_now(), value]]))
await asyncio.sleep(1) await asyncio.sleep(1)
if __name__ == "__main__":
def main():
r = ExampleReader() r = ExampleReader()
r.start() r.start()
if __name__ == "__main__":
main()
#!/usr/bin/python3 #!/usr/bin/env python3
from joule import ReaderModule from joule import ReaderModule
from joule.utilities import time_now from joule.utilities import time_now
...@@ -7,7 +7,7 @@ import numpy as np ...@@ -7,7 +7,7 @@ import numpy as np
class HighBandwidthReader(ReaderModule): class HighBandwidthReader(ReaderModule):
#Produce sawtooth waveform at specified sample rate" """ Produce a 1Hz ramp sampled at [rate] Hz """
def custom_args(self, parser): def custom_args(self, parser):
grp = parser.add_argument_group("module", grp = parser.add_argument_group("module",
...@@ -15,21 +15,26 @@ class HighBandwidthReader(ReaderModule): ...@@ -15,21 +15,26 @@ class HighBandwidthReader(ReaderModule):
grp.add_argument("--rate", type=float, grp.add_argument("--rate", type=float,
required=True, required=True,
help="sample rate in Hz") help="sample rate in Hz")
async def run(self, parsed_args, output): async def run(self, parsed_args, output):
start_ts = time_now() start_ts = time_now()
#run 5 times per second # run 5 times per second
period=1 period = 1
samples_per_period=np.round(parsed_args.rate*period) samples_per_period = np.round(parsed_args.rate * period)
while(1): while True:
end_ts = start_ts+period*1e6 end_ts = start_ts + period * 1e6
ts = np.linspace(start_ts,end_ts, ts = np.linspace(start_ts, end_ts,
samples_per_period,endpoint=False) samples_per_period, endpoint=False)
vals=np.linspace(0,33,samples_per_period) vals = np.linspace(0, 33, samples_per_period)
start_ts = end_ts start_ts = end_ts
chunk = np.hstack((ts[:,None], vals[:,None])) chunk = np.hstack((ts[:, None], vals[:, None]))
await output.write(chunk) await output.write(chunk)
await asyncio.sleep(period) await asyncio.sleep(period)
if __name__ == "__main__":
def main():
r = HighBandwidthReader() r = HighBandwidthReader()
r.start() r.start()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
from joule import ReaderModule
from joule.utilities import time_now
import asyncio
import numpy as np
import logging
ERROR_PROBABILITY = 0.25
class IntermittentReader(ReaderModule):
""" Like HighBandwidth reader with random data interruptions """
def custom_args(self, parser):
grp = parser.add_argument_group("module",
"module specific arguments")
grp.add_argument("--rate", type=float,
required=True,
help="sample rate in Hz")
async def run(self, parsed_args, output):
start_ts = time_now()
period = 1
samples_per_period = np.round(parsed_args.rate * period)
while True:
try:
end_ts = start_ts + period * 1e6
ts = np.linspace(start_ts, end_ts,
samples_per_period, endpoint=False)
vals = np.linspace(0, 33, samples_per_period)
start_ts = end_ts
chunk = np.hstack((ts[:, None], vals[:, None]))
# simulate an error
if np.random.rand() < ERROR_PROBABILITY:
raise ValueError
await output.write(chunk)
except ValueError:
logging.error("simulated data interruption")
await output.close_interval()
await asyncio.sleep(period)
def main():
r = IntermittentReader()
r.start()
if __name__ == "__main__":
main()
#!/usr/bin/python3 #!/usr/bin/env python3
from joule import FilterModule, EmptyPipe from joule import FilterModule, EmptyPipe
...@@ -24,6 +24,10 @@ class OffsetFilter(FilterModule): ...@@ -24,6 +24,10 @@ class OffsetFilter(FilterModule):
except EmptyPipe: except EmptyPipe:
break break
if __name__ == "__main__":
def main():
r = OffsetFilter() r = OffsetFilter()
r.start() r.start()
if __name__ == "__main__":
main()
...@@ -27,3 +27,4 @@ urllib3==1.23 ...@@ -27,3 +27,4 @@ urllib3==1.23
yarl==1.2.6 yarl==1.2.6
Jinja2==2.10 Jinja2==2.10
aiohttp-jinja2==1.0.0 aiohttp-jinja2==1.0.0
joule
\ No newline at end of file
#!/usr/bin/env python #!/usr/bin/env python3
from setuptools import setup from setuptools import setup
import versioneer import versioneer
...@@ -44,7 +44,8 @@ setup( ...@@ -44,7 +44,8 @@ setup(
'tabulate', 'tabulate',
'sqlalchemy', 'sqlalchemy',
'aiohttp-jinja2', 'aiohttp-jinja2',
'jinja2'], 'jinja2',
'joule'],
namespace_packages=[], namespace_packages=[],
packages=['jouleexamples'], packages=['jouleexamples'],
include_package_data=True, include_package_data=True,
......
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