2014-03-15 19:57:14 +00:00
#!/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 <http://www.gnu.org/licenses/>.
#
# 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
2014-03-16 10:35:23 +00:00
from datetime import datetime
2014-03-15 19:57:14 +00:00
import threading
import Queue
2014-03-13 03:22:06 +00:00
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
2014-03-11 17:35:45 +00:00
import select
2014-03-13 03:22:06 +00:00
import re
2014-03-11 17:35:45 +00:00
from collections import deque
2014-03-13 03:22:06 +00:00
from PyQt4 . QtCore import QBuffer , QByteArray , QIODevice
from PyQt4 import QtGui
import pyqtgraph as pg
2014-03-11 17:35:45 +00:00
2014-03-13 03:22:06 +00:00
from pyqtgraph . widgets . PlotWidget import PlotWidget
2014-03-15 19:57:14 +00:00
from chaosc . argparser_groups import *
2014-03-16 10:35:23 +00:00
try :
from chaosc . c_osc_lib import *
except ImportError :
from chaosc . osc_lib import *
QtGui . QApplication . setGraphicsSystem ( ' opengl ' )
2014-03-15 19:57:14 +00:00
2014-03-13 03:22:06 +00:00
try :
from chaosc . c_osc_lib import decode_osc
except ImportError as e :
print ( e )
from chaosc . osc_lib import decode_osc
2014-03-15 19:57:14 +00:00
QAPP = QtGui . QApplication ( [ ] )
2014-03-13 03:22:06 +00:00
class PlotWindow ( PlotWidget ) :
def __init__ ( self , title = None , * * kargs ) :
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 )
2014-03-15 19:57:14 +00:00
class OSCThread ( threading . Thread ) :
def __init__ ( self , args ) :
super ( OSCThread , self ) . __init__ ( )
2014-03-16 10:35:23 +00:00
self . args = args
2014-03-15 19:57:14 +00:00
self . running = True
2014-03-16 10:35:23 +00:00
self . own_address = socket . getaddrinfo ( args . own_host , args . own_port , socket . AF_INET6 , socket . SOCK_DGRAM , 0 , socket . AI_V4MAPPED | socket . AI_ALL | socket . AI_CANONNAME ) [ - 1 ] [ 4 ] [ : 2 ]
self . chaosc_address = chaosc_host , chaosc_port = socket . getaddrinfo ( args . chaosc_host , args . chaosc_port , socket . AF_INET6 , socket . SOCK_DGRAM , 0 , socket . AI_V4MAPPED | socket . AI_ALL | socket . AI_CANONNAME ) [ - 1 ] [ 4 ] [ : 2 ]
2014-03-15 19:57:14 +00:00
self . osc_sock = socket . socket ( 2 , 2 , 17 )
2014-03-16 10:35:23 +00:00
self . osc_sock . bind ( self . own_address )
2014-03-15 19:57:14 +00:00
self . osc_sock . setblocking ( 0 )
2014-03-16 10:35:23 +00:00
print " %s : starting up osc receiver on ' %s : %d ' " % (
datetime . now ( ) . strftime ( " %x %X " ) , self . own_address [ 0 ] , self . own_address [ 1 ] )
self . subscribe_me ( )
def subscribe_me ( self ) :
""" Use this procedure for a quick ' n dirty subscription to your chaosc instance.
: param chaosc_address : ( chaosc_host , chaosc_port )
: type chaosc_address : tuple
: param receiver_address : ( host , port )
: type receiver_address : tuple
: param token : token to get authorized for subscription
: type token : str
"""
print " %s : subscribing to ' %s : %d ' with label %r " % ( datetime . now ( ) . strftime ( " %x %X " ) , self . chaosc_address [ 0 ] , self . chaosc_address [ 1 ] , self . args . subscriber_label )
msg = OSCMessage ( " /subscribe " )
msg . appendTypedArg ( self . own_address [ 0 ] , " s " )
msg . appendTypedArg ( self . own_address [ 1 ] , " i " )
msg . appendTypedArg ( self . args . authenticate , " s " )
if self . args . subscriber_label is not None :
msg . appendTypedArg ( self . args . subscriber_label , " s " )
self . osc_sock . sendto ( msg . encode_osc ( ) , self . chaosc_address )
def unsubscribe_me ( self ) :
if self . args . keep_subscribed :
return
print " %s : unsubscribing from ' %s : %d ' " % ( datetime . now ( ) . strftime ( " %x %X " ) , self . chaosc_address [ 0 ] , self . chaosc_address [ 1 ] )
msg = OSCMessage ( " /unsubscribe " )
msg . appendTypedArg ( self . own_address [ 0 ] , " s " )
msg . appendTypedArg ( self . own_address [ 1 ] , " i " )
msg . appendTypedArg ( self . args . authenticate , " s " )
self . osc_sock . sendto ( msg . encode_osc ( ) , self . chaosc_address )
2014-03-15 19:57:14 +00:00
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 ] ) )
2014-03-16 10:35:23 +00:00
self . unsubscribe_me ( )
2014-03-15 19:57:14 +00:00
print " OSCThread is going down "
queue = Queue . Queue ( )
2014-03-13 03:22:06 +00:00
class MyHandler ( BaseHTTPRequestHandler ) :
2014-03-15 19:57:14 +00:00
2014-03-20 23:19:09 +00:00
def __del__ ( self ) :
self . thread . running = False
self . thread . join ( )
2014-03-13 03:22:06 +00:00
def do_GET ( self ) :
2014-03-16 10:35:23 +00:00
print " get "
2014-03-15 19:57:14 +00:00
2014-03-16 10:35:23 +00:00
self . thread = thread = OSCThread ( self . server . args )
2014-03-15 19:57:14 +00:00
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 ]
2014-03-20 23:19:09 +00:00
2014-03-20 03:05:01 +00:00
def set_point ( plotPoint , pos , value , ix , max_items ) :
scale = 254 / max_items * ix
2014-03-20 23:19:09 +00:00
y = 6 * ix + value / max_items + scale
plotPoint . setData ( x = [ pos ] , y = [ y ] )
2014-03-20 03:05:01 +00:00
2014-03-20 23:19:09 +00:00
def find_max_value ( item_data ) :
max_index = - 1
for ix , i in enumerate ( item_data ) :
if i > 250 :
return ix , i
return None , None
2014-03-20 03:05:01 +00:00
2014-03-20 23:19:09 +00:00
def rearrange ( item_data , actual_pos , max_items ) :
max_value_index , max_value = find_max_value ( item_data )
if max_value_index is None :
return actual_pos
2014-03-20 03:05:01 +00:00
mean = int ( max_items / 2. )
2014-03-20 23:19:09 +00:00
start = mean - max_value_index
if start != 0 :
item_data . rotate ( start )
pos = ( actual_pos + start ) % max_items
else :
pos = actual_pos
print " rearrange " , mean , start , actual_pos , pos , item_data
2014-03-20 03:05:01 +00:00
return pos
2014-03-20 23:19:09 +00:00
def set_value ( item_data , pos , max_pos , value ) :
print " setValue before " , pos , None , max_pos , value , item_data , len ( item_data )
item_data [ pos ] = value
new_pos = ( pos + 1 ) % max_pos
print " setValue after " , pos , new_pos , max_pos , value , item_data , len ( item_data )
return new_pos
def resize ( item_data , max_length , new_max_length , pos ) :
print " resize " , max_length , new_max_length
if new_max_length < 15 :
return max_length , pos
if new_max_length > max_length :
pad = ( new_max_length - max_length )
print " pad " , pad
for i in range ( pad ) :
if i % 2 == 0 :
item_data . append ( 0 )
else :
item_data . appendleft ( 0 )
pos + = 1
return new_max_length , pos
elif new_max_length < max_length :
pad = ( max_length - new_max_length )
for i in range ( pad ) :
if i % 2 == 0 :
item_data . pop ( )
if pos > = new_max_length :
pos = 0
else :
item_data . popleft ( )
if pos > 0 :
pos - = 1
return new_max_length , pos
return max_length , pos
2014-03-20 03:05:01 +00:00
2014-03-13 03:22:06 +00:00
try :
self . path = re . sub ( ' [^.a-zA-Z0-9] ' , " " , str ( self . path ) )
if self . path == " " or self . path == None or self . path [ : 1 ] == " . " :
return
2014-03-15 19:57:14 +00:00
2014-03-13 03:22:06 +00:00
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 ( )
2014-03-15 19:57:14 +00:00
elif self . path . endswith ( " .mjpeg " ) :
2014-03-20 03:05:01 +00:00
data_points = 21
2014-03-13 03:22:06 +00:00
2014-03-15 19:57:14 +00:00
self . send_response ( 200 )
2014-03-20 03:05:01 +00:00
pos1 = 0
pos2 = 0
pos3 = 0
2014-03-20 23:19:09 +00:00
lengths1 = [ 0 ]
2014-03-20 03:05:01 +00:00
data1_max_value = 0
data2_max_value = 0
data3_max_value = 0
data1_distance = data_points
data2_distance = data_points
data3_distance = data_points
plot_data1 = deque ( [ 0 ] * data_points )
plot_data2 = deque ( [ 0 ] * data_points )
plot_data3 = deque ( [ 0 ] * data_points )
2014-03-20 23:19:09 +00:00
plt = PlotWidget ( title = " <h1>EKG</h1> " )
2014-03-15 19:57:14 +00:00
plt . hide ( )
2014-03-20 03:05:01 +00:00
plotItem1 = pg . PlotCurveItem ( pen = pg . mkPen ( ' r ' , width = 2 ) , width = 2 , name = " bjoern " )
plotItem2 = pg . PlotCurveItem ( pen = pg . mkPen ( ' g ' , width = 2 ) , width = 2 , name = " merle " )
plotItem3 = pg . PlotCurveItem ( pen = pg . mkPen ( ' b ' , width = 2 ) , width = 2 , name = " uwe " )
shadowPen = pg . mkPen ( " w " , width = 10 )
plotItem1 . setShadowPen ( pen = shadowPen , width = 6 , cosmetic = True )
plotItem2 . setShadowPen ( pen = shadowPen , width = 6 , cosmetic = True )
plotItem3 . setShadowPen ( pen = shadowPen , width = 6 , cosmetic = True )
pen = pg . mkPen ( " w " , size = 1 )
brush = pg . mkBrush ( " w " )
plotPoint1 = pg . ScatterPlotItem ( pen = pen , brush = brush , size = 10 )
plotPoint2 = pg . ScatterPlotItem ( pen = pen , brush = brush , size = 10 )
plotPoint3 = pg . ScatterPlotItem ( pen = pen , brush = brush , size = 10 )
2014-03-15 19:57:14 +00:00
actors . append ( plotItem1 )
actors . append ( plotItem2 )
actors . append ( plotItem3 )
2014-03-13 03:22:06 +00:00
plotItem1 . setPos ( 0 , 0 * 6 )
plotItem2 . setPos ( 0 , 1 * 6 )
plotItem3 . setPos ( 0 , 2 * 6 )
plt . addItem ( plotItem1 )
plt . addItem ( plotItem2 )
plt . addItem ( plotItem3 )
2014-03-20 03:05:01 +00:00
plt . addItem ( plotPoint1 )
plt . addItem ( plotPoint2 )
plt . addItem ( plotPoint3 )
2014-03-13 03:22:06 +00:00
2014-03-15 19:57:14 +00:00
plt . setLabel ( ' left ' , " <h2>Amplitude</h2> " )
2014-03-20 23:19:09 +00:00
plt . setLabel ( ' bottom ' , " <h2><sup>Time</sup></h2> " )
2014-03-13 03:22:06 +00:00
plt . showGrid ( True , True )
ba = plt . getAxis ( " bottom " )
bl = plt . getAxis ( " left " )
ba . setTicks ( [ ] )
bl . setTicks ( [ ] )
2014-03-20 23:19:09 +00:00
ba . setWidth ( 0 )
ba . setHeight ( 0 )
bl . setWidth ( 0 )
bl . setHeight ( 0 )
2014-03-13 03:22:06 +00:00
plt . setYRange ( 0 , 254 )
2014-03-15 19:57:14 +00:00
2014-03-13 03:22:06 +00:00
self . wfile . write ( " Content-Type: multipart/x-mixed-replace; boundary=--aaboundary " )
self . wfile . write ( " \r \n \r \n " )
2014-03-15 19:57:14 +00:00
plt . resize ( 1280 , 720 )
2014-03-13 03:22:06 +00:00
while 1 :
2014-03-15 19:57:14 +00:00
while 1 :
try :
osc_address , args = queue . get_nowait ( )
except Queue . Empty :
break
2014-03-20 03:05:01 +00:00
max_items = len ( actors )
2014-03-15 19:57:14 +00:00
value = args [ 0 ]
2014-03-20 03:05:01 +00:00
2014-03-15 19:57:14 +00:00
if osc_address == " /bjoern/ekg " :
2014-03-20 23:19:09 +00:00
if value > 250 :
data_points , pos1 = resize ( plot_data1 , len ( plot_data1 ) , lengths1 [ - 1 ] , pos1 )
foo , pos2 = resize ( plot_data2 , len ( plot_data2 ) , lengths1 [ - 1 ] , pos2 )
foo , pos3 = resize ( plot_data3 , len ( plot_data3 ) , lengths1 [ - 1 ] , pos3 )
print " length1 " , lengths1
lengths1 . append ( 0 )
else :
lengths1 [ - 1 ] + = 1
2014-03-20 03:05:01 +00:00
ix = actors . index ( plotItem1 )
2014-03-20 23:19:09 +00:00
2014-03-20 03:05:01 +00:00
pos1 = rearrange ( plot_data1 , pos1 , data_points )
2014-03-20 23:19:09 +00:00
set_point ( plotPoint1 , pos1 , value , ix , max_items )
pos1 = set_value ( plot_data1 , pos1 , data_points , value )
2014-03-15 19:57:14 +00:00
try :
2014-03-20 03:05:01 +00:00
plotItem1 . setData ( y = np . array ( scale_data ( plot_data1 , ix , max_items ) ) , clear = True )
2014-03-15 19:57:14 +00:00
except ValueError :
pass
2014-03-20 23:19:09 +00:00
2014-03-15 19:57:14 +00:00
elif osc_address == " /merle/ekg " :
2014-03-20 03:05:01 +00:00
ix = actors . index ( plotItem2 )
2014-03-20 23:19:09 +00:00
2014-03-20 03:05:01 +00:00
pos2 = rearrange ( plot_data2 , pos2 , data_points )
2014-03-20 23:19:09 +00:00
set_point ( plotPoint2 , pos2 , value , ix , max_items )
pos2 = set_value ( plot_data2 , pos2 , data_points , value )
2014-03-15 19:57:14 +00:00
try :
2014-03-20 03:05:01 +00:00
plotItem2 . setData ( y = np . array ( scale_data ( plot_data2 , ix , max_items ) ) , clear = True )
2014-03-15 19:57:14 +00:00
except ValueError :
pass
elif osc_address == " /uwe/ekg " :
2014-03-20 03:05:01 +00:00
ix = actors . index ( plotItem3 )
pos3 = rearrange ( plot_data3 , pos3 , data_points )
2014-03-20 23:19:09 +00:00
set_point ( plotPoint3 , pos3 , value , ix , max_items )
pos3 = set_value ( plot_data3 , pos3 , data_points , value )
2014-03-15 19:57:14 +00:00
try :
2014-03-20 03:05:01 +00:00
plotItem3 . setData ( y = np . array ( scale_data ( plot_data3 , ix , max_items ) ) , clear = True )
2014-03-15 19:57:14 +00:00
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 ( )
2014-03-13 03:22:06 +00:00
exporter = pg . exporters . ImageExporter . ImageExporter ( plt . plotItem )
2014-03-15 19:57:14 +00:00
img = exporter . export ( " tmpfile " , True )
2014-03-13 03:22:06 +00:00
buffer = QBuffer ( )
2014-03-15 19:57:14 +00:00
buffer . open ( QIODevice . WriteOnly )
2014-03-13 03:22:06 +00:00
img . save ( buffer , " JPG " , 100 )
JpegData = buffer . data ( )
2014-03-15 19:57:14 +00:00
del buffer
self . wfile . write ( " --aaboundary \r \n Content-Type: image/jpeg \r \n Content-length: %d \r \n \r \n %s \r \n \r \n \r \n " % ( len ( JpegData ) , JpegData ) )
elif self . path . endswith ( " .jpeg " ) :
2014-03-13 03:22:06 +00:00
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
2014-03-15 19:57:14 +00:00
except ( KeyboardInterrupt , SystemError ) :
thread . running = False
thread . join ( )
2014-03-13 03:22:06 +00:00
except IOError :
self . send_error ( 404 , ' File Not Found: %s ' % self . path )
2014-03-15 19:57:14 +00:00
class JustAHTTPServer ( HTTPServer ) :
pass
2014-03-13 03:22:06 +00:00
2014-03-11 17:35:45 +00:00
def main ( ) :
2014-03-15 19:57:14 +00:00
a = create_arg_parser ( " ekgplotter " )
2014-03-16 10:35:23 +00:00
own_group = add_main_group ( a )
2014-03-20 03:05:01 +00:00
own_group . add_argument ( ' -x ' , " --http_host " , default = " 0.0.0.0 " ,
2014-03-16 10:35:23 +00:00
help = ' my host, defaults to " socket.gethostname() " ' )
own_group . add_argument ( ' -X ' , " --http_port " , default = 9000 ,
type = int , help = ' my port, defaults to 9000 ' )
2014-03-15 19:57:14 +00:00
add_chaosc_group ( a )
add_subscriber_group ( a , " ekgplotter " )
args = finalize_arg_parser ( a )
2014-03-13 03:22:06 +00:00
try :
2014-03-16 10:35:23 +00:00
host , port = socket . getaddrinfo ( args . http_host , args . http_port , socket . AF_INET6 , socket . SOCK_DGRAM , 0 , socket . AI_V4MAPPED | socket . AI_ALL | socket . AI_CANONNAME ) [ - 1 ] [ 4 ] [ : 2 ]
server = JustAHTTPServer ( ( " 0.0.0.0 " , 9000 ) , MyHandler )
server . args = args
print " %s : starting up http server on ' %s : %d ' " % (
datetime . now ( ) . strftime ( " %x %X " ) , host , port )
2014-03-13 03:22:06 +00:00
server . serve_forever ( )
except KeyboardInterrupt :
print ' ^C received, shutting down server '
server . socket . close ( )
2014-03-15 19:57:14 +00:00
2014-03-13 03:22:06 +00:00
if __name__ == ' __main__ ' :
main ( )
2014-03-15 19:57:14 +00:00