def cache_instrument_models(self): """ Queries Smoothie for the model and ID strings of attached pipettes, and saves them so they can be reported without querying Smoothie again (as this could interrupt a command if done during a run or other movement). Shape of return dict should be: ``` { "left": { "model": "<model_string>" or None, "id": "<pipette_id_string>" or None }, "right": { "model": "<model_string>" or None, "id": "<pipette_id_string>" or None } } ``` :return: a dict with pipette data (shape described above) """ log.debug("Updating instrument model cache") for mount in self.model_by_mount.keys(): model_value = self._driver.read_pipette_model(mount) if model_value: name_value = pipette_config.name_for_model(model_value) else: name_value = None plunger_axis = 'B' if mount == 'left' else 'C' mount_axis = 'Z' if mount == 'left' else 'A' if model_value: cfg = pipette_config.load(model_value) home_pos = cfg.home_position max_travel = cfg.max_travel steps_mm = cfg.steps_per_mm else: home_pos = self.config.default_pipette_configs['homePosition'] max_travel = self.config.default_pipette_configs['maxTravel'] steps_mm = self.config.default_pipette_configs['stepsPerMM'] self._driver.update_steps_per_mm({plunger_axis: steps_mm}) self._driver.update_pipette_config(mount_axis, {'home': home_pos}) self._driver.update_pipette_config(plunger_axis, {'max_travel': max_travel}) if model_value: id_response = self._driver.read_pipette_id(mount) else: id_response = None self.model_by_mount[mount] = { 'model': model_value, 'id': id_response, 'name': name_value } log.debug("{}: {} [{}]".format(mount, self.model_by_mount[mount]['model'], self.model_by_mount[mount]['id']))
def test_load_instrument(loop): ctx = papi.ProtocolContext(loop=loop) for model in config_models: loaded = ctx.load_instrument(model, Mount.LEFT, replace=True) assert loaded.model == model instr_name = name_for_model(model) loaded = ctx.load_instrument(instr_name, Mount.RIGHT, replace=True) assert loaded.name == instr_name
def __init__(self, model: str, inst_offset_config: Dict[str, Tuple[float, float, float]], pipette_id: str = None) -> None: self._config = pipette_config.load(model, pipette_id) self._name = pipette_config.name_for_model(model) self._model = model self._model_offset = self._config.model_offset self._current_volume = 0.0 self._working_volume = self._config.max_volume self._current_tip_length = 0.0 self._fallback_tip_length = self._config.tip_length self._has_tip = False self._pipette_id = pipette_id pip_type = 'multi' if self._config.channels > 1 else 'single' self._instrument_offset = Point(*inst_offset_config[pip_type]) self._log = mod_log.getChild( self._pipette_id if self._pipette_id else '<unknown>') self._log.info("loaded: {}, instr offset {}".format( model, self._instrument_offset)) self.ready_to_aspirate = False
async def test_get_cached_pipettes(async_server, async_client, monkeypatch): test_model = 'p300_multi_v1' test_name = 'p300_multi' test_id = '123abc' hw = async_server['com.opentrons.hardware'] hw._backend._attached_instruments = { types.Mount.RIGHT: { 'model': test_model, 'id': test_id }, types.Mount.LEFT: { 'model': test_model, 'id': test_id } } await hw.reset() model = pipette_config.load(test_model) expected = { 'left': { 'model': test_model, 'name': test_name, 'tip_length': model.tip_length, 'mount_axis': 'z', 'plunger_axis': 'b', 'id': test_id }, 'right': { 'model': test_model, 'name': test_name, 'tip_length': model.tip_length, 'mount_axis': 'a', 'plunger_axis': 'c', 'id': test_id } } resp = await async_client.get('/pipettes') text = await resp.text() assert resp.status == 200 assert json.loads(text) == expected model1 = 'p10_single_v1.3' config1 = pipette_config.load(model1) id1 = 'fgh876' hw._backend._attached_instruments = { types.Mount.RIGHT: { 'model': model1, 'id': id1 }, types.Mount.LEFT: { 'model': model1, 'id': id1 } } resp1 = await async_client.get('/pipettes') text1 = await resp1.text() assert resp1.status == 200 assert json.loads(text1) == expected expected2 = { 'left': { 'model': model1, 'name': pipette_config.name_for_model(model1), 'tip_length': config1.tip_length, 'mount_axis': 'z', 'plunger_axis': 'b', 'id': id1 }, 'right': { 'model': model1, 'name': pipette_config.name_for_model(model1), 'tip_length': config1.tip_length, 'mount_axis': 'a', 'plunger_axis': 'c', 'id': id1 } } resp2 = await async_client.get('/pipettes?refresh=true') text2 = await resp2.text() assert resp2.status == 200 assert json.loads(text2) == expected2
def cache_instrument_models(self): """ Queries Smoothie for the model and ID strings of attached pipettes, and saves them so they can be reported without querying Smoothie again (as this could interrupt a command if done during a run or other movement). Shape of return dict should be: ``` { "left": { "model": "<model_string>" or None, "id": "<pipette_id_string>" or None }, "right": { "model": "<model_string>" or None, "id": "<pipette_id_string>" or None } } ``` :return: a dict with pipette data (shape described above) """ log.debug("Updating instrument model cache") for mount in self.model_by_mount.keys(): plunger_axis = 'B' if mount == 'left' else 'C' mount_axis = 'Z' if mount == 'left' else 'A' model_value = self._driver.read_pipette_model(mount) splits = {plunger_axis: None} if model_value: name_value = pipette_config.name_for_model(model_value) pc = pipette_config.load(model_value) home_current = pc.plunger_current if 'needsUnstick' in pc.quirks: splits[plunger_axis] = MoveSplit(split_distance=1, split_current=1.5, split_speed=1, after_time=1800, fullstep=True) else: name_value = None home_current = self.config.high_current[plunger_axis] if model_value: cfg = pipette_config.load(model_value) home_pos = cfg.home_position max_travel = cfg.max_travel steps_mm = cfg.steps_per_mm idle_current = cfg.idle_current else: home_pos = self.config.default_pipette_configs['homePosition'] max_travel = self.config.default_pipette_configs['maxTravel'] steps_mm = self.config.default_pipette_configs['stepsPerMM'] idle_current = self.config.low_current[plunger_axis] self._driver.update_steps_per_mm({plunger_axis: steps_mm}) self._driver.update_pipette_config(mount_axis, {'home': home_pos}) self._driver.update_pipette_config(plunger_axis, {'max_travel': max_travel}) self._driver.set_dwelling_current({plunger_axis: idle_current}) self._driver.configure_splits_for(splits) if model_value: id_response = self._driver.read_pipette_id(mount) else: id_response = None self.model_by_mount[mount] = { 'model': model_value, 'id': id_response, 'name': name_value, 'home_current': home_current } log.debug("{}: {} [{}]".format(mount, self.model_by_mount[mount]['model'], self.model_by_mount[mount]['id']))