diff --git a/api/opentrons/hardware_control/__init__.py b/api/opentrons/hardware_control/__init__.py index f3520e227e7..31fef414733 100644 --- a/api/opentrons/hardware_control/__init__.py +++ b/api/opentrons/hardware_control/__init__.py @@ -83,6 +83,9 @@ def __init__(self, # {'X': 0.0, 'Y': 0.0, 'Z': 0.0, 'A': 0.0, 'B': 0.0, 'C': 0.0} self._current_position: dict = None + self._attached_instruments = {types.Mount.LEFT: None, + types.Mount.RIGHT: None} + @classmethod def build_hardware_controller( cls, config: dict = None, @@ -101,14 +104,16 @@ def build_hardware_controller( @classmethod def build_hardware_simulator( - cls, config: dict = None, + cls, + attached_instruments, + config: dict = None, loop: asyncio.AbstractEventLoop = None) -> 'API': """ Build a simulating hardware controller. This method may be used both on a real robot and on dev machines. Multiple simulating hardware controllers may be active at one time. """ - return cls(simulator.Simulator(config, loop), + return cls(simulator.Simulator(attached_instruments, config, loop), config=config, loop=loop) # Query API @@ -141,7 +146,10 @@ async def identify(self, seconds): @_log_call async def cache_instrument_models(self): - pass + self._log.info("Updating instrument model cache") + for mount in types.Mount: + self._attached_instruments[mount] = \ + self._backend.get_attached_instruments(mount) @_log_call async def update_smoothie_firmware(self, firmware_file): @@ -203,7 +211,7 @@ async def _move(self, target_position: Dict[str, float]): try: self._backend.move(target_position) except Exception: - mod_log.exception('Move failed') + self._log.exception('Move failed') self._current_position.clear() raise diff --git a/api/opentrons/hardware_control/controller.py b/api/opentrons/hardware_control/controller.py index 4bc2cf90ee0..2556f1b8a16 100644 --- a/api/opentrons/hardware_control/controller.py +++ b/api/opentrons/hardware_control/controller.py @@ -72,3 +72,6 @@ def move(self, target_position: Dict[str, float], home_flagged_axes=True): def home(self): return self._smoothie_driver.home() + + def get_attached_instruments(self, mount): + return self._smoothie_driver.read_pipette_model(mount.name.lower()) diff --git a/api/opentrons/hardware_control/simulator.py b/api/opentrons/hardware_control/simulator.py index 10cb09dd63d..52af00d86a6 100644 --- a/api/opentrons/hardware_control/simulator.py +++ b/api/opentrons/hardware_control/simulator.py @@ -7,9 +7,10 @@ class Simulator: a robot with no smoothie connected. """ - def __init__(self, config, loop): + def __init__(self, attached_instruments, config, loop): self._config = config self._loop = loop + self._attached_instruments = attached_instruments def move(self, target_position: Dict[str, float]): pass @@ -17,3 +18,6 @@ def move(self, target_position: Dict[str, float]): def home(self): # driver_3_0-> HOMED_POSITION return {'X': 418, 'Y': 353, 'Z': 218, 'A': 218, 'B': 19, 'C': 19} + + def get_attached_instruments(self, mount): + return self._attached_instruments[mount] diff --git a/api/tests/opentrons/hardware_control/test_instruments.py b/api/tests/opentrons/hardware_control/test_instruments.py new file mode 100644 index 00000000000..d3070f104f0 --- /dev/null +++ b/api/tests/opentrons/hardware_control/test_instruments.py @@ -0,0 +1,30 @@ +import pytest +from opentrons import types +from opentrons import hardware_control as hc + + +async def test_cache_instruments(loop): + dummy_instruments_attached = {types.Mount.LEFT: 'model_abc', + types.Mount.RIGHT: None} + hw_api = hc.API.build_hardware_simulator( + attached_instruments=dummy_instruments_attached, loop=loop) + await hw_api.cache_instrument_models() + assert hw_api._attached_instruments == dummy_instruments_attached + + +@pytest.mark.skipif(not hc.controller, + reason='hardware controller not available ' + '(probably windows)') +async def test_cache_instruments_hc(monkeypatch, hardware_controller_lockfile, + running_on_pi, loop): + dummy_instruments_attached = {types.Mount.LEFT: 'model_abc', + types.Mount.RIGHT: None} + hw_api_cntrlr = hc.API.build_hardware_controller(loop=loop) + + def mock_driver_method(mount): + attached_pipette = {'left': 'model_abc', 'right': None} + return attached_pipette[mount] + monkeypatch.setattr(hw_api_cntrlr._backend._smoothie_driver, + 'read_pipette_model', mock_driver_method) + await hw_api_cntrlr.cache_instrument_models() + assert hw_api_cntrlr._attached_instruments == dummy_instruments_attached diff --git a/api/tests/opentrons/hardware_control/test_moves.py b/api/tests/opentrons/hardware_control/test_moves.py index 4784ecc235d..10925b6767b 100644 --- a/api/tests/opentrons/hardware_control/test_moves.py +++ b/api/tests/opentrons/hardware_control/test_moves.py @@ -2,23 +2,22 @@ from opentrons import types from opentrons import hardware_control as hc -if not hc.controller: - pytest.skip('hardware controller not available (probably windows)', - allow_module_level=True) - @pytest.fixture def hardware_api(monkeypatch, loop): def mock_move(position): pass - - hw_api = hc.API.build_hardware_simulator(loop=loop) + attached_pipettes = {types.Mount.LEFT: None, types.Mount.RIGHT: None} + hw_api = hc.API.build_hardware_simulator( + attached_instruments=attached_pipettes, loop=loop) monkeypatch.setattr(hw_api._backend, 'move', mock_move) return hw_api async def test_controller_home(loop): - c = hc.API.build_hardware_simulator(loop=loop) + attached_pipettes = {types.Mount.LEFT: None, types.Mount.RIGHT: None} + c = hc.API.build_hardware_simulator( + attached_instruments=attached_pipettes, loop=loop) await c.home() assert c._current_position == {'X': 418, 'Y': 353, 'Z': 218, 'A': 218, 'B': 19, 'C': 19}