diff --git a/openflexure_microscope/api/v1.py b/openflexure_microscope/api/v1.py index 486f1f67..447110cf 100644 --- a/openflexure_microscope/api/v1.py +++ b/openflexure_microscope/api/v1.py @@ -11,6 +11,7 @@ import numpy as np from importlib import import_module import time import datetime +import os from flask import ( Flask, render_template, Response, @@ -29,11 +30,6 @@ import logging, sys logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) -# Create the microscope object globally (common to all spawned server threads) -api_microscope = Microscope( - StreamingCamera(), - OpenFlexureStage("/dev/ttyUSB0") -) # Create flask app app = Flask(__name__) @@ -45,9 +41,29 @@ def not_found(error): # Some useful functions # TODO: Maybe auto-generate API URI base from module name -def uri(suffix, base='/api/v1'): - return base + suffix +def uri(suffix, base=None): + if not base: + api_ver = os.path.splitext(os.path.basename(__file__))[0] + base = "/api/{}".format(api_ver) + uri = base + suffix + logging.debug("Created app route: {}".format(uri)) + return uri +# Create a dummy microscope object, with no hardware attachments +api_microscope = Microscope(None, None) +logging.debug("Created an empty microscope in global.") + +# After app starts, but before first request, attach hardware to global microscope +@app.before_first_request +def attach_microscope(): + # Create the microscope object globally (common to all spawned server threads) + global api_microscope + logging.debug("First request made. Populating microscope with hardware...") + api_microscope.attach( + StreamingCamera(), + OpenFlexureStage("/dev/ttyUSB0") + ) + logging.debug("Microscope successfully attached!") ##### WEBAPP ROUTES ###### diff --git a/openflexure_microscope/microscope.py b/openflexure_microscope/microscope.py index 1758df3b..75449b07 100644 --- a/openflexure_microscope/microscope.py +++ b/openflexure_microscope/microscope.py @@ -2,7 +2,7 @@ """ Defines a microscope object, binding a camera and stage with basic functionality. """ - +import logging import numpy as np from openflexure_stage import OpenFlexureStage @@ -20,11 +20,7 @@ class Microscope(object): microscope (:py:class:`openflexure_stage.stage.OpenFlexureStage`): stage object """ def __init__(self, camera: StreamingCamera, stage: OpenFlexureStage): - print("Assigning camera") - self.camera = camera #: :py:class:`openflexure_microscope.camera.pi.StreamingCamera`: Picamera object - print("Assigning stage") - self.stage = stage #: :py:class:`openflexure_stage.stage.OpenFlexureStage`: OpenFlexure stage object - self.stage.backlash = np.zeros(3, dtype=np.int) + self.attach(camera, stage) def __enter__(self): """Create microscope on context enter.""" @@ -38,6 +34,27 @@ class Microscope(object): """Shut down the microscope hardware.""" self.camera.close() self.stage.close() + + def attach(self, camera: StreamingCamera, stage: OpenFlexureStage): + """ + Retroactively attaches a camera and stage to the microscope object. + + Allows the microscope to be created as a "dummy", with hardware communications + opened at a later time. + + Args: + camera (:py:class:`openflexure_microscope.camera.pi.StreamingCamera`): camera object + microscope (:py:class:`openflexure_stage.stage.OpenFlexureStage`): stage object + """ + + self.camera = camera #: :py:class:`openflexure_microscope.camera.pi.StreamingCamera`: Picamera object + if isinstance(camera, StreamingCamera): + logging.info("Attached camera {}".format(camera)) + + self.stage = stage #: :py:class:`openflexure_stage.stage.OpenFlexureStage`: OpenFlexure stage object + if isinstance(self.stage, OpenFlexureStage): # If a stage object has been attached + logging.info("Attached stage {}".format(stage)) + self.stage.backlash = np.zeros(3, dtype=np.int) # Create unified state @property