diff --git a/ekgplotter/ekgplotter/ekg_plotter_unused.py b/ekgplotter/ekgplotter/ekg_plotter_unused.py new file mode 100644 index 0000000..1cd2542 --- /dev/null +++ b/ekgplotter/ekgplotter/ekg_plotter_unused.py @@ -0,0 +1,169 @@ +import numpy as np +import string,cgi,time, random, socket +from os import curdir, sep +from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer +from SocketServer import ThreadingMixIn, ForkingMixIn +import select +import re + +from collections import deque + +from PyQt4.QtCore import QBuffer, QByteArray, QIODevice +from PyQt4 import QtGui +import pyqtgraph as pg + +from pyqtgraph.widgets.PlotWidget import PlotWidget + + +try: + from chaosc.c_osc_lib import decode_osc +except ImportError as e: + print(e) + from chaosc.osc_lib import decode_osc + +QAPP = None + +def mkQApp(): + if QtGui.QApplication.instance() is None: + global QAPP + QAPP = QtGui.QApplication([]) + + +class PlotWindow(PlotWidget): + def __init__(self, title=None, **kargs): + mkQApp() + self.win = QtGui.QMainWindow() + PlotWidget.__init__(self, **kargs) + self.win.setCentralWidget(self) + for m in ['resize']: + setattr(self, m, getattr(self.win, m)) + if title is not None: + self.win.setWindowTitle(title) + + +class MyHandler(BaseHTTPRequestHandler): + def do_GET(self): + print "get" + global plotValues + try: + self.path=re.sub('[^.a-zA-Z0-9]', "",str(self.path)) + if self.path=="" or self.path==None or self.path[:1]==".": + return + if self.path.endswith(".html"): + f = open(curdir + sep + self.path) + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.end_headers() + self.wfile.write(f.read()) + f.close() + return + if self.path.endswith(".mjpeg"): + self.send_response(200) + + plot_data1 = deque([0] * 100) + plot_data2 = deque([254/3] * 100) + plot_data3 = deque([254/3*2] * 100) + plt = PlotWindow(title="EKG", name="Merle") + plt.addLegend() + #plt = pg.plot(pen=(0, 3*1.3)) + plt.resize(1280, 720) + plotItem1 = pg.PlotCurveItem(pen=(0, 3*1.3), name="bjoern") + plotItem2 = pg.PlotCurveItem(pen=(1, 3*1.3), name="merle") + plotItem3 = pg.PlotCurveItem(pen=(2, 3*1.3), name="uwe") + plotItem1.setPos(0, 0*6) + plotItem2.setPos(0, 1*6) + plotItem3.setPos(0, 2*6) + plt.addItem(plotItem1) + plt.addItem(plotItem2) + plt.addItem(plotItem3) + + plt.setLabel('left', "EKG") + plt.setLabel('bottom', "Time") + plt.showGrid(True, True) + ba = plt.getAxis("bottom") + bl = plt.getAxis("left") + ba.setTicks([]) + bl.setTicks([]) + plt.setYRange(0, 254) + print type(plt) + self.wfile.write("Content-Type: multipart/x-mixed-replace; boundary=--aaboundary") + self.wfile.write("\r\n\r\n") + osc_sock = socket.socket(2, 2, 17) + osc_sock.bind(("", 10000)) + osc_sock.setblocking(0) + last = time.time() + now = last + + while 1: + for i in xrange(3): + reads, writes, errs = select.select([osc_sock], [], [], 0.01) + #print reads, writes, errs + if reads: + osc_input = reads[0].recv(4096) + osc_address, typetags, args = decode_osc(osc_input, 0, len(osc_input)) + #print "osc", osc_address, typetags, args + if osc_address.startswith("/bjoern"): + plot_data1.appendleft(args[0] / 3) + plot_data1.pop() + elif osc_address.startswith("/merle"): + plot_data2.appendleft(args[0] / 3 + 254/3) + plot_data2.pop() + elif osc_address.startswith("/uwe"): + plot_data3.appendleft(args[0] / 3 + 254/3*2) + plot_data3.pop() + + plotItem1.setData(y=np.array(plot_data1), clear=True) + plotItem2.setData(y=np.array(plot_data2), clear=True) + plotItem3.setData(y=np.array(plot_data3), clear=True) + #item = plt.plot(plot_data1, pen=(0, 3*1.3), clear=True) + + exporter = pg.exporters.ImageExporter.ImageExporter(plt.plotItem) + exporter.parameters()['width'] = 1280 + #exporter.parameters()['height'] = 720 + name = 'tmpfile' + img = exporter.export(name, True) + buffer = QBuffer() + buffer.open(QIODevice.ReadWrite) + img.save(buffer, "JPG", 100) + JpegData = buffer.data() + self.wfile.write("--aaboundary\r\n") + self.wfile.write("Content-Type: image/jpeg\r\n") + self.wfile.write("Content-length: %d\r\n\r\n" % len(JpegData)) + self.wfile.write(JpegData) + self.wfile.write("\r\n\r\n\r\n") + now = time.time() + dur = now - last + print dur + wait = 0.04 - dur + if wait > 0: + time.sleep(wait) + last = now + return + if self.path.endswith(".jpeg"): + f = open(curdir + sep + self.path) + self.send_response(200) + self.send_header('Content-type','image/jpeg') + self.end_headers() + self.wfile.write(f.read()) + f.close() + return + return + except IOError: + self.send_error(404,'File Not Found: %s' % self.path) + + +#class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): +class ThreadedHTTPServer(HTTPServer, ForkingMixIn): + """Handle requests in a separate thread.""" + +def main(): + try: + server = ThreadedHTTPServer(('0.0.0.0', 9000), MyHandler) + print 'started httpserver...' + server.serve_forever() + except KeyboardInterrupt: + print '^C received, shutting down server' + server.socket.close() + +if __name__ == '__main__': + main() diff --git a/ekgplotter/ekgplotter/index.html b/ekgplotter/ekgplotter/index.html new file mode 100644 index 0000000..3f46bbb --- /dev/null +++ b/ekgplotter/ekgplotter/index.html @@ -0,0 +1,7 @@ + + + +Smiley face + + + diff --git a/ekgplotter/ekgplotter/main.py b/ekgplotter/ekgplotter/main.py index 1cd2542..3679c6b 100644 --- a/ekgplotter/ekgplotter/main.py +++ b/ekgplotter/ekgplotter/main.py @@ -1,3 +1,31 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# This file is part of sensors2osc package +# +# sensors2osc is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# sensors2osc is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with sensors2osc. If not, see . +# +# found the mjpeg part here, thanks for the nice code :) +# http://hardsoftlucid.wordpress.com/2013/04/11/mjpeg-server-for-webcam-in-python-with-opencv/ +# the osc integration stuff is implemented by me +# +# Copyright (C) 2014 Stefan Kögl + +from __future__ import absolute_import + +import threading +import Queue import numpy as np import string,cgi,time, random, socket from os import curdir, sep @@ -14,6 +42,10 @@ import pyqtgraph as pg from pyqtgraph.widgets.PlotWidget import PlotWidget +from chaosc.argparser_groups import * + +QtGui.QApplication.setGraphicsSystem('raster') + try: from chaosc.c_osc_lib import decode_osc @@ -21,17 +53,11 @@ except ImportError as e: print(e) from chaosc.osc_lib import decode_osc -QAPP = None - -def mkQApp(): - if QtGui.QApplication.instance() is None: - global QAPP - QAPP = QtGui.QApplication([]) +QAPP = QtGui.QApplication([]) class PlotWindow(PlotWidget): def __init__(self, title=None, **kargs): - mkQApp() self.win = QtGui.QMainWindow() PlotWidget.__init__(self, **kargs) self.win.setCentralWidget(self) @@ -41,14 +67,61 @@ class PlotWindow(PlotWidget): self.win.setWindowTitle(title) +class OSCThread(threading.Thread): + def __init__(self, args): + super(OSCThread, self).__init__() + self.running = True + self.osc_sock = socket.socket(2, 2, 17) + self.osc_sock.bind((args.own_host, args.own_port)) + self.osc_sock.setblocking(0) + + def run(self): + + while self.running: + reads, writes, errs = select.select([self.osc_sock], [], [], 0.05) + if reads: + osc_input = reads[0].recv(4096) + osc_address, typetags, messages = decode_osc(osc_input, 0, len(osc_input)) + if osc_address.find("ekg") > -1 or osc_address.find("plot") != -1: + queue.put_nowait((osc_address, messages)) + else: + queue.put_nowait(("/bjoern/ekg", [0])) + queue.put_nowait(("/merle/ekg", [0])) + queue.put_nowait(("/uwe/ekg", [0])) + print "OSCThread is going down" + + +queue = Queue.Queue() + class MyHandler(BaseHTTPRequestHandler): + def do_GET(self): - print "get" - global plotValues + + self.thread = thread = OSCThread() + thread.daemon = True + thread.start() + + actors = list() + is_item1 = True + is_item2 = True + is_item3 = True + + def setPositions(): + for ix, item in enumerate(actors): + item.setPos(0, ix*6) + + + def scale_data(data, ix, max_items): + scale = 254 / max_items * ix + return [value / max_items + scale for value in data] + + try: + self.path=re.sub('[^.a-zA-Z0-9]', "",str(self.path)) if self.path=="" or self.path==None or self.path[:1]==".": return + if self.path.endswith(".html"): f = open(curdir + sep + self.path) self.send_response(200) @@ -56,20 +129,26 @@ class MyHandler(BaseHTTPRequestHandler): self.end_headers() self.wfile.write(f.read()) f.close() - return - if self.path.endswith(".mjpeg"): - self.send_response(200) + elif self.path.endswith(".mjpeg"): + data_points = 1000 - plot_data1 = deque([0] * 100) - plot_data2 = deque([254/3] * 100) - plot_data3 = deque([254/3*2] * 100) - plt = PlotWindow(title="EKG", name="Merle") - plt.addLegend() - #plt = pg.plot(pen=(0, 3*1.3)) - plt.resize(1280, 720) - plotItem1 = pg.PlotCurveItem(pen=(0, 3*1.3), name="bjoern") - plotItem2 = pg.PlotCurveItem(pen=(1, 3*1.3), name="merle") - plotItem3 = pg.PlotCurveItem(pen=(2, 3*1.3), name="uwe") + self.send_response(200) + plot_data1 = data = deque([0] * data_points) + plot_data2 = data = deque([0] * data_points) + plot_data3 = data = deque([0] * data_points) + plt = PlotWidget(title="

EKG

", name="Merle") + plt.hide() + plotItem1 = pg.PlotCurveItem(pen=pg.mkPen('r', width=2), name="bjoern") + plotItem2 = pg.PlotCurveItem(pen=pg.mkPen('g', width=2), name="merle") + plotItem3 = pg.PlotCurveItem(pen=pg.mkPen('b', width=2), name="uwe") + print type(plotItem1) + pen = pg.mkPen(254, 254, 254) + plotItem1.setShadowPen(pen=pen, width=6, cosmetic=True) + plotItem2.setShadowPen(pen=pen, width=6, cosmetic=True) + plotItem3.setShadowPen(pen=pen, width=6, cosmetic=True) + actors.append(plotItem1) + actors.append(plotItem2) + actors.append(plotItem3) plotItem1.setPos(0, 0*6) plotItem2.setPos(0, 1*6) plotItem3.setPos(0, 2*6) @@ -77,93 +156,138 @@ class MyHandler(BaseHTTPRequestHandler): plt.addItem(plotItem2) plt.addItem(plotItem3) - plt.setLabel('left', "EKG") - plt.setLabel('bottom', "Time") + plt.setLabel('left', "

Amplitude

") + plt.setLabel('bottom', "

Time

") plt.showGrid(True, True) ba = plt.getAxis("bottom") bl = plt.getAxis("left") ba.setTicks([]) bl.setTicks([]) plt.setYRange(0, 254) - print type(plt) + self.wfile.write("Content-Type: multipart/x-mixed-replace; boundary=--aaboundary") self.wfile.write("\r\n\r\n") - osc_sock = socket.socket(2, 2, 17) - osc_sock.bind(("", 10000)) - osc_sock.setblocking(0) - last = time.time() - now = last + + + plt.resize(1280, 720) while 1: - for i in xrange(3): - reads, writes, errs = select.select([osc_sock], [], [], 0.01) - #print reads, writes, errs - if reads: - osc_input = reads[0].recv(4096) - osc_address, typetags, args = decode_osc(osc_input, 0, len(osc_input)) - #print "osc", osc_address, typetags, args - if osc_address.startswith("/bjoern"): - plot_data1.appendleft(args[0] / 3) - plot_data1.pop() - elif osc_address.startswith("/merle"): - plot_data2.appendleft(args[0] / 3 + 254/3) - plot_data2.pop() - elif osc_address.startswith("/uwe"): - plot_data3.appendleft(args[0] / 3 + 254/3*2) - plot_data3.pop() + while 1: + try: + osc_address, args = queue.get_nowait() + except Queue.Empty: + break - plotItem1.setData(y=np.array(plot_data1), clear=True) - plotItem2.setData(y=np.array(plot_data2), clear=True) - plotItem3.setData(y=np.array(plot_data3), clear=True) - #item = plt.plot(plot_data1, pen=(0, 3*1.3), clear=True) + value = args[0] + if osc_address == "/bjoern/ekg": + plot_data1.append(value) + plot_data1.popleft() + try: + plotItem1.setData(y=np.array(scale_data(plot_data1, actors.index(plotItem1), len(actors))), clear=True) + except ValueError: + pass + elif osc_address == "/merle/ekg": + plot_data2.append(value) + plot_data2.popleft() + try: + plotItem2.setData(y=np.array(scale_data(plot_data2, actors.index(plotItem2), len(actors))), clear=True) + except ValueError: + pass + elif osc_address == "/uwe/ekg": + plot_data3.append(value) + plot_data3.popleft() + try: + plotItem3.setData(y=np.array(scale_data(plot_data3, actors.index(plotItem3), len(actors))), clear=True) + except ValueError: + pass + elif osc_address == "/plot/uwe": + if value == 1 and is_item3 == False: + print "uwe on" + plt.addItem(plotItem3) + is_item3 = True + actors.append(plotItem3) + setPositions() + elif value == 0 and is_item3 == True: + print "uwe off" + plt.removeItem(plotItem3) + is_item3 = False + actors.remove(plotItem3) + setPositions() + elif osc_address == "/plot/merle": + if value == 1 and is_item2 == False: + print "merle on" + plt.addItem(plotItem2) + is_item2 = True + actors.append(plotItem2) + setPositions() + elif value == 0 and is_item2 == True: + print "merle off" + plt.removeItem(plotItem2) + is_item2 = False + actors.remove(plotItem2) + setPositions() + elif osc_address == "/plot/bjoern": + if value == 1 and is_item1 == False: + print "bjoern on" + plt.addItem(plotItem1) + is_item1 = True + actors.append(plotItem1) + setPositions() + elif value == 0 and is_item1 == True: + print "bjoern off" + plt.removeItem(plotItem1) + is_item1 = False + actors.remove(plotItem1) + setPositions() exporter = pg.exporters.ImageExporter.ImageExporter(plt.plotItem) - exporter.parameters()['width'] = 1280 - #exporter.parameters()['height'] = 720 - name = 'tmpfile' - img = exporter.export(name, True) + img = exporter.export("tmpfile", True) buffer = QBuffer() - buffer.open(QIODevice.ReadWrite) + buffer.open(QIODevice.WriteOnly) img.save(buffer, "JPG", 100) JpegData = buffer.data() - self.wfile.write("--aaboundary\r\n") - self.wfile.write("Content-Type: image/jpeg\r\n") - self.wfile.write("Content-length: %d\r\n\r\n" % len(JpegData)) - self.wfile.write(JpegData) - self.wfile.write("\r\n\r\n\r\n") - now = time.time() - dur = now - last - print dur - wait = 0.04 - dur - if wait > 0: - time.sleep(wait) - last = now - return - if self.path.endswith(".jpeg"): + del buffer + self.wfile.write("--aaboundary\r\nContent-Type: image/jpeg\r\nContent-length: %d\r\n\r\n%s\r\n\r\n\r\n" % (len(JpegData), JpegData)) + + elif self.path.endswith(".jpeg"): f = open(curdir + sep + self.path) self.send_response(200) self.send_header('Content-type','image/jpeg') self.end_headers() self.wfile.write(f.read()) f.close() - return return + except (KeyboardInterrupt, SystemError): + thread.running = False + thread.join() except IOError: self.send_error(404,'File Not Found: %s' % self.path) + def __del__(self): + self.thread.running = False + self.thread.join() + + +class JustAHTTPServer(HTTPServer): + pass -#class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): -class ThreadedHTTPServer(HTTPServer, ForkingMixIn): - """Handle requests in a separate thread.""" def main(): + a = create_arg_parser("ekgplotter") + add_main_group(a) + add_chaosc_group(a) + add_subscriber_group(a, "ekgplotter") + args = finalize_arg_parser(a) + try: - server = ThreadedHTTPServer(('0.0.0.0', 9000), MyHandler) + server = JustAHTTPServer(('0.0.0.0', 9000), MyHandler) print 'started httpserver...' server.serve_forever() except KeyboardInterrupt: print '^C received, shutting down server' server.socket.close() + if __name__ == '__main__': main() + diff --git a/ekgplotter/setup.py b/ekgplotter/setup.py index 2d45c49..3cb5b9a 100644 --- a/ekgplotter/setup.py +++ b/ekgplotter/setup.py @@ -22,7 +22,7 @@ setup( exclude_package_data = {'': ['.gitignore']}, - install_requires=[], + install_requires=["pyqtgraph"], # installing unzipped zip_safe = False,