diff --git a/Dockerfile b/Dockerfile index ee766ef..4ba5c95 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,10 +10,17 @@ RUN apt-get update && apt-get install -y \ apache2 \ iptables \ nodejs \ + python-virtualenv \ python-imaging \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +# Install pip +# RUN easy_install pip + +# Install Flask +RUN pip install Flask + # Apache site configuration ADD chute/000-default.conf /etc/apache2/sites-available/ @@ -30,6 +37,6 @@ ADD chute/run.sh /usr/local/bin/run.sh # Set the work dir for nodejs photo server WORKDIR "/var/www/html" -EXPOSE 80 81 8010 +EXPOSE 80 81 8010 8011 CMD ["/bin/bash", "/usr/local/bin/run.sh"] diff --git a/chute/hello.py b/chute/hello.py new file mode 100644 index 0000000..5240d45 --- /dev/null +++ b/chute/hello.py @@ -0,0 +1,19 @@ +from flask import Flask +from flask import request +app = Flask(__name__) + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'GET': + return ('get message') + else: + return ("error") + +@app.route('/') +def hello_world(): + return 'Hello, World!' + +app.run(host = '0.0.0.0', port = 5001) + +#if(__name__ == "__main__"): +# print("In Main") diff --git a/chute/run.sh b/chute/run.sh index 43b1a43..1f2b7db 100644 --- a/chute/run.sh +++ b/chute/run.sh @@ -5,7 +5,15 @@ mkdir -p /var/www/html/motionLog chmod a+rw /var/www/html/motionLog # Execute the file, one pic every 2 seconds -python /usr/local/bin/seccam.py -m_sec 2.0 > seccam.log 2> seccam.err & +python /usr/local/bin/seccam.py -m_sec 5.0 > seccam.log 2> seccam.err & +#python /usr/local/bin/seccam.py -m_sec 2.0 > seccam.log & + + +#export FLASK_APP = seccam.py +#flask run > flask.log & + +# Execute the file, one pic every 2 seconds +# python /usr/local/bin/snapshot.py -m_sec 2.0 > snapshot.log 2> snapshot.err & # Add the symlink ln -s --relative /var/www/html/motionLog /var/www/html/app-dist/ diff --git a/chute/seccam.py b/chute/seccam.py index b986109..28771b4 100644 --- a/chute/seccam.py +++ b/chute/seccam.py @@ -4,6 +4,9 @@ import httplib import base64 import StringIO +import thread +from flask import Flask +from flask import request try: import PIL @@ -18,6 +21,63 @@ THRESH_1 = 40.0 THRESH_2 = 60.0 +#''' + +def create_app(ip, m_save): + app = Flask(__name__) + + @app.route('/login', methods=['GET', 'POST']) + def login(): + if request.method == 'GET': + return ('get message') + else: + return ("error") + + @app.route('/') + def hello_world(): + return 'Hello, World!' + + @app.route('/snap') + def takeSnapShot(): + print("In snap shot") + jpg = None + fileName = "" + print(ip, m_save) + while(jpg is None): + try: + print("try to get image") + img = getImage(ip) + # Did we get an image? + if(img is None): + print("** SnapShot Failed, retrying") + time.sleep(2.0) + continue + else: + try: + jpg = PIL.Image.open(img) + fileName = "%s%d.jpg" % (m_save, time.time()) + print('jpg: %s' % str(fileName)) + jpg.save(fileName) + except Exception as e: + time.sleep(2.0) + jpg = None + except KeyboardInterrupt: + break + except Exception as e: + print('!! error: %s' % str(e)) + jpg = None + time.sleep(2.0) + return fileName + + return app + +#''' +def run_app(ip, m_save): + print("\nListen!!!\n") + app = create_app(ip, m_save) + app.run(host = '0.0.0.0', port = 8011) +#''' + def setupArgParse(): p = argparse.ArgumentParser(description='SecCam security suite') p.add_argument('-calibrate', help='Temporary mode to help calibrate the thresholds', action='store_true') @@ -31,9 +91,9 @@ def getImage(ip): # Here is a portion of the URL ####################################################################### # TODO1 : Send a HTTP GET Request to the WebCam - # (with Username:'admin' and Password:''). - # We recommend using the httplib package - h = httplib.HTTP(ip, 80) + # (with Username:'admin' and Password:''). + # We recommend using the httplib package + h = httplib.HTTP(ip, 80) h.putrequest('GET', '/image.jpg') h.putheader('Host', ip) h.putheader('User-agent', 'python-httplib') @@ -91,6 +151,8 @@ def detectMotion(img1, jpg2): if(__name__ == "__main__"): + print("In main\n") + p = setupArgParse() args = p.parse_args() @@ -99,6 +161,8 @@ def detectMotion(img1, jpg2): sens = args.m_sensitivity m_save = '/var/www/html/motionLog/motion-' + print("After global vars\n") + if(m_sec < 1.0): print('** For the workshop, please do not use lower than 1.0 for m_sec') exit() @@ -126,6 +190,7 @@ def detectMotion(img1, jpg2): subnet = "" ip = "" while(ip == ""): + print("Try to connect from router to WebCam") try: # Get the subnet if haven't yet @@ -172,6 +237,15 @@ def detectMotion(img1, jpg2): print("Found IP %s" % ip) + + try: + thread.start_new_thread( run_app, (ip, m_save,) ) + except: + print "Error: unable to start thread" + + #while(True): + # pass + # Setup while loop requesting images from webcam while(True): try: @@ -193,7 +267,7 @@ def detectMotion(img1, jpg2): ####################################################################### # TODO2 : Check the RMS difference and store the image to the proper # location, for our webserver to read these files they should go - # under the location /srv/www/motionlog/* + # under the location /srv/www/motionlog/* if(diff > thresh): print("** Motion! %.3f" % diff) fileName = "%s%d.jpg" % (m_save, time.time()) diff --git a/chute/snapshot.py b/chute/snapshot.py new file mode 100644 index 0000000..0ffb325 --- /dev/null +++ b/chute/snapshot.py @@ -0,0 +1,203 @@ +#!/usr/bin/python + +import sys, math, os, string, time, argparse, json, subprocess +import httplib +import base64 +import StringIO + +try: + import PIL + from PIL import Image, ImageChops +except Exception as e: + print('No PIL, please install "python-imaging-library" if on OpenWrt') + sys.exit(1) + +timeflt = lambda: time.time() + +THRESH_0 = 20.0 +THRESH_1 = 40.0 +THRESH_2 = 60.0 + +def setupArgParse(): + p = argparse.ArgumentParser(description='SecCam security suite') + p.add_argument('-calibrate', help='Temporary mode to help calibrate the thresholds', action='store_true') + p.add_argument('-m_sec', help='How much time to wait between motion images', type=float, default=2.0) + p.add_argument('-m_sensitivity', help='How sensitive the motion capture should be, 0=very, 1=somewhat, 2=not very', type=int, default=0) + return p + +def getImage(ip): + """Gets the file from the specified host, port and location/query""" + try: + # Here is a portion of the URL + ####################################################################### + # TODO1 : Send a HTTP GET Request to the WebCam + # (with Username:'admin' and Password:''). + # We recommend using the httplib package + h = httplib.HTTP(ip, 80) + h.putrequest('GET', '/image.jpg') + h.putheader('Host', ip) + h.putheader('User-agent', 'python-httplib') + h.putheader('Content-type', 'image/jpeg') + h.putheader('Authorization', 'Basic {0}'.format(base64.b64encode("{0}:".format('admin')))) + h.endheaders() + + (returncode, returnmsg, headers) = h.getreply() + print "return code:",returncode + print "return message:",returnmsg + print "headers:",headers + if returncode != 200: + print returncode, returnmsg + sys.exit() + + f = h.getfile() + return StringIO.StringIO(f.read()) + + except Exception as e: + print('!! Failed to connect to webcam: %s' % str(e)) + return None + +def detectMotion(img1, jpg2): + """ + Detects motion using a simple difference algorithm. + Arguments: + img1 : the image data from the getImage() function + jpg2 : the last jpg object (you save outside of this function) + Returns: + None if no img data provided + (None, JPG) if jpg2 is None, we convert img1 into a JPG object and return that + (RMS, JPG) if img difference successful + """ + if(not img1): + return None + + #Convert to Image so we can compare them using PIL + try: + jpg1 = PIL.Image.open(img1) + except Exception as e: + print('jpg1: %s' % str(e)) + return None + + if(not jpg2): + return (None, jpg1) + + # Now compute the difference + diff = PIL.ImageChops.difference(jpg1, jpg2) + h = diff.histogram() + sq = (value*((idx%256)**2) for idx, value in enumerate(h)) + sum_sqs = sum(sq) + rms = math.sqrt(sum_sqs / float(jpg1.size[0] * jpg1.size[1])) + return (rms,jpg1) + +def takeSnapShot(ip, m_save): + jpg = None + while(jpg is None): + try: + img = getImage(ip) + # Did we get an image? + if(img is None): + print("** SnapShot Failed, retrying") + time.sleep(1.0) + continue + else: + try: + jpg = PIL.Image.open(img) + fileName = "%s%d.jpg" % (m_save, time.time()) + print('jpg: %s' % str(fileName)) + jpg.save(fileName) + return jpg; + except Exception as e: + time.sleep(1.0) + jpg = None + except KeyboardInterrupt: + break + except Exception as e: + print('!! error: %s' % str(e)) + jpg = None + time.sleep(1.0) + +if(__name__ == "__main__"): + p = setupArgParse() + args = p.parse_args() + + calib = args.calibrate + m_sec = args.m_sec + sens = args.m_sensitivity + m_save = '/var/www/html/motionLog/motion-' + + if(m_sec < 1.0): + print('** For the workshop, please do not use lower than 1.0 for m_sec') + exit() + + #Setup threshold for motion + #very sensitive + if(sens == 0): + thresh = THRESH_0 + #kind of sensitive + elif(sens == 1): + thresh = THRESH_1 + #not very sensitive + elif(sens == 2): + thresh = THRESH_2 + else: + raise Exception('InvalidParam', 'm_sensitivity') + + # Need to store the old image + oldjpg = None + + ## Determine IP address + ####################################################################### + # make sure apr table contains all devices + # Get the subnet of paradrop + subnet = "" + ip = "" + while(ip == ""): + try: + + # Get the subnet if haven't yet + if (subnet == ""): + cmd = "ifconfig -a | grep 'inet addr:192.168' | awk '{print $2}' | egrep -o '([0-9]+\.){2}[0-9]+'" + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output, errors = p.communicate() + if (output != ""): + subnet = output.rstrip() + + # Add a . after 192.168.xxx + subnet = subnet + '.' + print "subnet: " + subnet + + # Prevent race condition by running this in the loop to put the device on the arp table + cmd = "echo $(seq 100 200) | xargs -P255 -I% -d' ' ping -W 1 -c 1 " + subnet + "% | grep -E '[0-1].*?:'" + p2 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output2, errors2 = p2.communicate() + + # Search arp for leading mac address bits + cmd="arp -a | grep -e '28:10:7b' -e 'b0:c5:54' -e '01:b0:c5' | awk '{print $2}' | egrep -o '([0-9]+\.){3}[0-9]+'" + p3 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output3, errors3 = p3.communicate() + + if (output3 != ""): + print "output3: '" + output3 + "'" + ip = output3.rstrip() + + # Set iptables for wan port access + cmd="iptables -t nat -A PREROUTING -p tcp --dport 81 -j DNAT --to-destination " + ip + ":80" + print "cmd: " + cmd + p4 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output4, errors4 = p4.communicate() + cmd="iptables -t nat -A POSTROUTING -p tcp -d " + ip + " --dport 81 -j MASQUERADE" + print "cmd: " + cmd + p5 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output5, errors5 = p5.communicate() + + except KeyboardInterrupt: + break + except Exception as e: + print('!! error: %s' % str(e)) + time.sleep(m_sec) + + print("Found IP %s" % ip) + + # Setup while loop requesting images from webcam + while(True): + jpg = takeSnapShot(ip, m_save) + time.sleep(5.0) diff --git a/chute/web/app-dist/index.html b/chute/web/app-dist/index.html index 563c393..f3bde9d 100644 --- a/chute/web/app-dist/index.html +++ b/chute/web/app-dist/index.html @@ -1,9 +1,53 @@ -