Created API V1
This commit is contained in:
parent
d04943c944
commit
973ccf67ab
8 changed files with 132 additions and 18 deletions
1
openflexure_microscope/api/__init__.py
Normal file
1
openflexure_microscope/api/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from . import utilities
|
||||||
9
openflexure_microscope/api/templates/index_v1.html
Normal file
9
openflexure_microscope/api/templates/index_v1.html
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Video Streaming Demonstration</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Video Streaming Demonstration</h1>
|
||||||
|
<img src="{{ url_for('stream') }}">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
15
openflexure_microscope/api/utilities.py
Normal file
15
openflexure_microscope/api/utilities.py
Normal file
|
|
@ -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')
|
||||||
|
|
@ -11,34 +11,19 @@ from flask import (
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
from openflexure_microscope.api.utilities import parse_payload, gen
|
||||||
from openflexure_microscope.camera.pi import StreamingCamera
|
from openflexure_microscope.camera.pi import StreamingCamera
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
cam = StreamingCamera()
|
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('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
"""Video streaming home page."""
|
"""Video streaming home page."""
|
||||||
cam.start_worker() # Start the stream
|
cam.start_worker() # Start the stream
|
||||||
return render_template('index.html')
|
return render_template('index_v0.html')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/stream')
|
@app.route('/stream')
|
||||||
85
openflexure_microscope/api/v1.py
Normal file
85
openflexure_microscope/api/v1.py
Normal file
|
|
@ -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)
|
||||||
|
|
@ -24,3 +24,22 @@ class Microscope(object):
|
||||||
"""Shut down the microscope hardware."""
|
"""Shut down the microscope hardware."""
|
||||||
self.camera.close()
|
self.camera.close()
|
||||||
self.stage.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
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
gunicorn --threads 5 --workers 1 --bind 0.0.0.0:5000 openflexure_microscope.api.app:app
|
gunicorn --threads 5 --workers 1 --bind 0.0.0.0:5000 openflexure_microscope.api.v1:app
|
||||||
Loading…
Add table
Add a link
Reference in a new issue