Skip to content

Commit

Permalink
feat(api): publish module commands and make module data endpoint (#2053)
Browse files Browse the repository at this point in the history
Include Module method calls in the message broker, which allows for run log entries in the run-app.
Create a new endpoint that requests the live data from a module with a given serial number. Point
the TempdeckStatusCard's IntervalWrapper at this new endpoint.

Closes #1653
  • Loading branch information
b-cooper authored Aug 14, 2018
1 parent dbafde9 commit c25c081
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 197 deletions.
3 changes: 0 additions & 3 deletions api/opentrons/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,6 @@ def P1000_Single(
aspirate_flow_rate=aspirate_flow_rate,
dispense_flow_rate=dispense_flow_rate)

def Magbead(self, *args, **kwargs):
return inst.Magbead(self.robot, *args, **kwargs)

def _create_pipette_from_config(
self,
config,
Expand Down
55 changes: 32 additions & 23 deletions api/opentrons/commands/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,25 +250,43 @@ def drop_tip(instrument, location):
)


def engage(motor):
text = "Engaging Magbead at mosfet #{motor}"
def magdeck_engage():
text = "Engaging magnetic deck module"
return make_command(
name=types.MAGBEAD_ENGAGE,
payload={
'motor': motor,
'text': text
}
name=types.MAGDECK_ENGAGE,
payload={'text': text}
)


def disengage(motor):
text = "Disengaging Magbead at mosfet #{motor}"
def magdeck_disengage():
text = "Disengaging magnetic deck module"
return make_command(
name=types.MAGBEAD_ENGAGE,
payload={
'motor': motor,
'text': text
}
name=types.MAGDECK_DISENGAGE,
payload={'text': text}
)


def magdeck_calibrate():
text = "Calibrating magnetic deck module"
return make_command(
name=types.MAGDECK_CALIBRATE,
payload={'text': text}
)


def tempdeck_set_temp():
text = "Setting temperature deck module temperature"
return make_command(
name=types.TEMPDECK_SET_TEMP,
payload={'text': text}
)


def tempdeck_deactivate():
text = "Deactivating temperature deck module"
return make_command(
name=types.TEMPDECK_DEACTIVATE,
payload={'text': text}
)


Expand Down Expand Up @@ -302,15 +320,6 @@ def resume():
)


def magbead():
pass


magbead.engage = engage
magbead.disengage = disengage
magbead.delay = delay


def publish(before, after, command, meta=None):
publish_command = functools.partial(
broker.publish,
Expand Down
28 changes: 21 additions & 7 deletions api/opentrons/commands/types.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
COMMAND = 'command'


# Robot #
# helpers #

def makeRobotCommandName(name):
return '{}.{}'.format(COMMAND, name)


# Robot #

DELAY = makeRobotCommandName('DELAY')
HOME = makeRobotCommandName('HOME')
PAUSE = makeRobotCommandName('PAUSE')
RESUME = makeRobotCommandName('RESUME')
COMMENT = makeRobotCommandName('COMMENT')

# Pipette #

ASPIRATE = makeRobotCommandName('ASPIRATE')
DISPENSE = makeRobotCommandName('DISPENSE')
MIX = makeRobotCommandName('MIX')
Expand All @@ -14,13 +25,16 @@ def makeRobotCommandName(name):
TRANSFER = makeRobotCommandName('TRANSFER')
PICK_UP_TIP = makeRobotCommandName('PICK_UP_TIP')
DROP_TIP = makeRobotCommandName('DROP_TIP')
COMMENT = makeRobotCommandName('COMMENT')
MAGBEAD_ENGAGE = makeRobotCommandName('MAGBEAD_ENGAGE')
DELAY = makeRobotCommandName('DELAY')
BLOW_OUT = makeRobotCommandName('BLOW_OUT')
AIR_GAP = makeRobotCommandName('AIR_GAP')
TOUCH_TIP = makeRobotCommandName('TOUCH_TIP')
RETURN_TIP = makeRobotCommandName('RETURN_TIP')
HOME = makeRobotCommandName('HOME')
PAUSE = makeRobotCommandName('PAUSE')
RESUME = makeRobotCommandName('RESUME')

# Modules #

MAGDECK_CALIBRATE = makeRobotCommandName('MAGDECK_CALIBRATE')
MAGDECK_DISENGAGE = makeRobotCommandName('MAGDECK_DISENGAGE')
MAGDECK_ENGAGE = makeRobotCommandName('MAGDECK_ENGAGE')

TEMPDECK_DEACTIVATE = makeRobotCommandName('TEMPDECK_DEACTIVATE')
TEMPDECK_SET_TEMP = makeRobotCommandName('TEMPDECK_SET_TEMP')
2 changes: 0 additions & 2 deletions api/opentrons/instruments/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from opentrons.instruments.magbead import Magbead
from opentrons.instruments.pipette import Pipette


__all__ = [
Magbead,
Pipette
]

Expand Down
2 changes: 1 addition & 1 deletion api/opentrons/instruments/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
class Instrument(object):
"""
This class represents instrument attached to the :any:`Robot`:
:Pipette:, :Magbead:.
:Pipette:.
It gives the instruments ability to CRUD their calibration data,
and gives access to some common methods across instruments
Expand Down
89 changes: 0 additions & 89 deletions api/opentrons/instruments/magbead.py

This file was deleted.

2 changes: 1 addition & 1 deletion api/opentrons/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def load(name, slot):
# that type that is on the robot, in the future we should add
# support for multiple instances of one module type this
# accessor would then load the correct disambiguated module
# instance (via nickname?)
# instance via the module's serial
matching_modules = [
module for module in robot.modules if isinstance(
module, SUPPORTED_MODULES.get(name)
Expand Down
7 changes: 6 additions & 1 deletion api/opentrons/modules/magdeck.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from opentrons.drivers.mag_deck import MagDeck as MagDeckDriver
from opentrons import commands


class MissingDevicePortError(Exception):
Expand All @@ -19,6 +20,7 @@ def __init__(self, lw=None, port=None):
self._driver = None
self._device_info = None

@commands.publish.both(command=commands.magdeck_calibrate)
def calibrate(self):
'''
Calibration involves probing for top plate to get the plate height
Expand All @@ -28,6 +30,7 @@ def calibrate(self):
# return if successful or not?
self._engaged = False

@commands.publish.both(command=commands.magdeck_engage)
def engage(self):
'''
Move the magnet to plate top - 1 mm
Expand All @@ -36,6 +39,7 @@ def engage(self):
self._driver.move(self._driver.plate_height - 1.0)
self._engaged = True

@commands.publish.both(command=commands.magdeck_disengage)
def disengage(self):
'''
Home the magnet
Expand All @@ -54,7 +58,8 @@ def to_dict(self):
'model': self.device_info and self.device_info.get('model'),
'fwVersion': self.device_info and self.device_info.get('version'),
'displayName': 'Magnetic Deck',
'status': self.status
'status': self.status,
'data': {'engaged': self._engaged}
}

@property
Expand Down
14 changes: 13 additions & 1 deletion api/opentrons/modules/tempdeck.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from opentrons.drivers.temp_deck import TempDeck as TempDeckDriver
from opentrons import commands


class MissingDevicePortError(Exception):
Expand All @@ -18,6 +19,7 @@ def __init__(self, lw=None, port=None):
self._driver = None
self._device_info = None

@commands.publish.both(command=commands.tempdeck_set_temp)
def set_temperature(self, celsius):
"""
Set temperature in degree Celsius
Expand All @@ -28,6 +30,7 @@ def set_temperature(self, celsius):
if self._driver and self._driver.is_connected():
self._driver.set_temperature(celsius)

@commands.publish.both(command=commands.tempdeck_deactivate)
def deactivate(self):
""" Stop heating/cooling and turn off the fan """
if self._driver and self._driver.is_connected():
Expand All @@ -51,7 +54,16 @@ def to_dict(self):
'model': self.device_info and self.device_info.get('model'),
'fwVersion': self.device_info and self.device_info.get('version'),
'displayName': 'Temperature Deck',
'status': self.status
**self.live_data()
}

def live_data(self):
return {
'status': self.status,
'data': {
'currentTemp': self.temperature,
'targetTemp': self.target
}
}

@property
Expand Down
17 changes: 17 additions & 0 deletions api/opentrons/server/endpoints/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@ async def get_attached_modules(request):
return web.json_response(data, status=200)


async def get_module_data(request):
"""
Query a module (by its serial number) for its live data
"""
requested_serial = request.match_info['serial']
res = None

for module in robot.modules:
if module.device_info.get('serial') == requested_serial:
res = module.live_data() if module.live_data() else None

if res:
return web.json_response(res, status=200)
else:
return web.json_response({"message": "Module not found"}, status=404)


async def get_engaged_axes(request):
"""
Query driver for engaged state by axis. Response keys will be axes XYZABC
Expand Down
2 changes: 2 additions & 0 deletions api/opentrons/server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ def init(loop=None):
'/identify', control.identify)
server.app.router.add_get(
'/modules', control.get_attached_modules)
server.app.router.add_get(
'/modules/{serial}/data', control.get_module_data)
server.app.router.add_post(
'/camera/picture', control.take_picture)
server.app.router.add_post(
Expand Down
Loading

0 comments on commit c25c081

Please sign in to comment.