diff --git a/openflexure_microscope/api/__init__.py b/openflexure_microscope/api/__init__.py
new file mode 100644
index 00000000..08fef38a
--- /dev/null
+++ b/openflexure_microscope/api/__init__.py
@@ -0,0 +1 @@
+from . import utilities
diff --git a/openflexure_microscope/api/templates/index.html b/openflexure_microscope/api/templates/index_v0.html
similarity index 100%
rename from openflexure_microscope/api/templates/index.html
rename to openflexure_microscope/api/templates/index_v0.html
diff --git a/openflexure_microscope/api/templates/index_v1.html b/openflexure_microscope/api/templates/index_v1.html
new file mode 100644
index 00000000..d1f67f86
--- /dev/null
+++ b/openflexure_microscope/api/templates/index_v1.html
@@ -0,0 +1,9 @@
+
+
+ Video Streaming Demonstration
+
+
+ Video Streaming Demonstration
+
+
+
diff --git a/openflexure_microscope/api/utilities.py b/openflexure_microscope/api/utilities.py
new file mode 100644
index 00000000..40dd6c69
--- /dev/null
+++ b/openflexure_microscope/api/utilities.py
@@ -0,0 +1,15 @@
+def parse_payload(request):
+ """Convert request to JSON. Will eventually handle error-checking."""
+ # TODO: Handle invalid JSON payloads
+ state = request.get_json()
+ return state
+
+
+def gen(camera):
+ """Video streaming generator function."""
+ while True:
+ # the obtained frame is a jpeg
+ frame = camera.get_frame()
+
+ yield (b'--frame\r\n'
+ b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
diff --git a/openflexure_microscope/api/app.py b/openflexure_microscope/api/v0.py
similarity index 89%
rename from openflexure_microscope/api/app.py
rename to openflexure_microscope/api/v0.py
index 4a109823..5987a9c0 100644
--- a/openflexure_microscope/api/app.py
+++ b/openflexure_microscope/api/v0.py
@@ -11,34 +11,19 @@ from flask import (
import numpy as np
+from openflexure_microscope.api.utilities import parse_payload, gen
from openflexure_microscope.camera.pi import StreamingCamera
app = Flask(__name__)
cam = StreamingCamera()
-def parse_payload(request):
- """Convert request to JSON. Will eventually handle error-checking."""
- # TODO: Handle invalid JSON payloads
- state = request.get_json()
- return state
-
-
-def gen(camera):
- """Video streaming generator function."""
- while True:
- # the obtained frame is a jpeg
- frame = camera.get_frame()
-
- yield (b'--frame\r\n'
- b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
-
@app.route('/')
def index():
"""Video streaming home page."""
cam.start_worker() # Start the stream
- return render_template('index.html')
+ return render_template('index_v0.html')
@app.route('/stream')
diff --git a/openflexure_microscope/api/v1.py b/openflexure_microscope/api/v1.py
new file mode 100644
index 00000000..1b4ae096
--- /dev/null
+++ b/openflexure_microscope/api/v1.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+"""
+TODO: Implement stage control methods
+TODO: Reimplement capture methods
+TODO: Implement API route to cleanly shut down server
+TODO: Implement microscope function API routes (autofocus etc)
+"""
+
+from pprint import pprint
+from importlib import import_module
+import time
+import datetime
+
+from flask import (
+ Flask, render_template, Response,
+ redirect, request, jsonify, send_file)
+
+import numpy as np
+
+from openflexure_microscope.api.utilities import parse_payload, gen
+
+from openflexure_microscope import Microscope
+from openflexure_microscope.camera.pi import StreamingCamera
+from openflexure_stage import OpenFlexureStage
+
+import logging, sys
+logging.basicConfig(stream=sys.stderr, level=logging.INFO)
+
+
+# Create the microscope object globally (common to all spawned server threads)
+microscope = Microscope(
+ StreamingCamera(),
+ OpenFlexureStage("/dev/ttyUSB0")
+)
+
+# Create flask app
+app = Flask(__name__)
+
+# Some useful functions
+def uri(suffix, base='/api/v1'):
+ return base + suffix
+
+# Define front-end routes
+
+@app.route('/')
+def index():
+ """Video streaming home page."""
+ return render_template(
+ 'index_v1.html'
+ )
+
+# Define API routes
+
+# Basic routes
+
+@app.route(uri('/stream'))
+def stream():
+ """Video streaming route. Put this in the src attribute of an img tag."""
+ global microscope
+
+ return Response(
+ gen(microscope.camera),
+ mimetype='multipart/x-mixed-replace; boundary=frame')
+
+@app.route(uri('/state'))
+def state():
+ """Return JSONified microscope state"""
+ global microscope
+
+ return jsonify(microscope.state)
+
+# Positioning routes
+
+@app.route(uri('/position'), methods=['GET', 'POST', 'PUT'])
+def position():
+ """Return JSONified microscope state"""
+ global microscope
+
+ if request.method == 'POST' or request.method == 'PUT':
+ logging.debug("TODO: Move stage.")
+
+ return jsonify(microscope.state['position'])
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0', threaded=True, debug=True, use_reloader=False)
diff --git a/openflexure_microscope/microscope.py b/openflexure_microscope/microscope.py
index 7762a821..cb9e7418 100644
--- a/openflexure_microscope/microscope.py
+++ b/openflexure_microscope/microscope.py
@@ -24,3 +24,22 @@ class Microscope(object):
"""Shut down the microscope hardware."""
self.camera.close()
self.stage.close()
+
+ # Create unified state
+ @property
+ def state(self):
+ state = {}
+
+ # Add stage position
+ position = self.stage.position
+ state['position'] = {
+ 'absolute': True,
+ 'x': position[0],
+ 'y': position[1],
+ 'z': position[2],
+ }
+
+ # Add camera state
+ state.update(self.camera.state)
+
+ return state
diff --git a/start_interface b/start_interface
index b4ccb02b..13b267f7 100644
--- a/start_interface
+++ b/start_interface
@@ -1 +1 @@
-gunicorn --threads 5 --workers 1 --bind 0.0.0.0:5000 openflexure_microscope.api.app:app
\ No newline at end of file
+gunicorn --threads 5 --workers 1 --bind 0.0.0.0:5000 openflexure_microscope.api.v1:app
\ No newline at end of file