示例#1
0
def restart():
    """Restart the Crossbar WAMP router and Python backend.

    By default, does not change networking configuration.
    """
    if debug == True: FileIO.log('script_keeper.restart called')
    subprocess.call([os.path.join(dir_path,'../../otone_scripts/start.sh'), 'NOCHANGE'])
示例#2
0
def share_inet():
    """Triggers ethernet interface (eth0) to try to obtain ip address via dhcp by taking it down, and then 
    bringing it up
    """
    if debug == True: FileIO.log('script_keeper.share_inet called')
    cmd = os.path.join(dir_path,'../../otone_scripts/share_inet.sh')

    create_share = asyncio.create_subprocess_exec(cmd,stdout=asyncio.subprocess.PIPE)

    criterion = True
    while criterion == True:
        proc_share = yield from create_share
        stdout_, stderr_ = yield from proc_share.communicate()

        if stdout_ is not None:
            stdout_str = stdout_.decode("utf-8")
            if debug == True and verbose == True: FileIO.log('share_inet.stdout... '+stdout_str)
            read_progress(stdout_str)
        else:
            if debug == True and verbose == True: FileIO.log('share_inet.stdout... None')
        if stderr_ is not None:
            if debug == True and verbose == True: FileIO.log('share_inet.stderr...'+stderr_.decode("utf-8"))
        else:
            if debug == True and verbose == True: FileIO.log('share_inet.stderr... None')
        if proc_share.returncode is not None:
            criterion = False
    return
示例#3
0
 def erase_job(self, data):
     """Call :meth:`clear`... redundant, consider removing, and why does it have unused data parameter???
     """
     if debug == True: FileIO.log('the_queue.erase_job called')
     #doesn't map to smoothieAPI
     #function eraseJob(){
     self.clear() 
示例#4
0
def write_led(num, val):
    """Turn an LED on or off.

    Not currently implemented. This is in anticipation of having LED indicators
    """
    if debug == True: FileIO.log('script_keeper.write_led called')
    subprocess.call([os.path.join(dir_path,'../../otone_scripts/write_led.sh'),str(num),str(val)])
示例#5
0
 def delay_state(self):
     """Sets theState object's delaying value to 0, and then calls :meth:`on_state_change`.
     Used by :meth:`delay` for timing end of a delay
     """
     if debug == True: FileIO.log('smoothie_ser2net.delay_state called')
     self.theState['delaying'] = 0
     self.on_state_change(self.theState)
示例#6
0
    def on_connect(self, theState):
        """Callback when connection made

        currently does zilch
        """
        if debug == True:
            FileIO.log('smoothie_ser2net.on_connect called')
示例#7
0
    def create_deck(self, new_deck):
        """Create a dictionary of new container names to be stored in each pipette given a deck list

        Calls :meth:`head.save_pipette_values` right before returning dictionary

        :returns: container data for each axis
        :rtype: dictionary
        
        """
        if debug == True: 
            FileIO.log('head.create_deck called')
            if verbose == True:
                FileIO.log('\tnewDeck:\n\n', new_deck,'\n')
        
        #doesn't map to smoothieAPI
        nameArray = []  

        for containerName in new_deck :
            nameArray.append(containerName) 
        
        response = {}  
        
        for n in self.PIPETTES:
            response[n] = self.PIPETTES[n].create_deck(nameArray)  

        self.save_pipette_values() 
        return response         
示例#8
0
 def connect(self):
     """Make a connection to Smoothieboard using :class:`CB_Factory`
     """
     if debug == True: FileIO.log('smoothie_ser2net.connect called')
     self.my_loop = asyncio.get_event_loop()
     callbacker = self.CB_Factory(self)
     asyncio.async(self.my_loop.create_connection(lambda: callbacker, host='0.0.0.0', port=3333))
示例#9
0
 def calibrate_container(self, pipette, container):   
     """Set the location of a container
     """
     if debug == True: FileIO.log('head.calibrate_container called')
     if pipette and self.PIPETTES[pipette]:     
         state = self.smoothieAPI.get_state()
         self.PIPETTES[pipette].calibrate_container(container,state)
示例#10
0
    def save_pipette_values(self):
        """Save pipette values to otone_data/pipette_values.json
        """
        if debug == True: FileIO.log('head.save_pipette_values called')
        pipette_values = {}

        for axis in self.PIPETTES:
            pipette_values[axis] = {}
            for k, v in self.PIPETTES[axis].__dict__.items():
                pipette_values[axis][k] = v

            # should include:
            #  'top'
            #  'bottom'
            #  'blowout'
            #  'droptip'
            #  'volume'
            #  'theContainers'

        filetext = json.dumps(pipette_values,sort_keys=True,indent=4,separators=(',',': '))
        if debug == True: FileIO.log('filetext: ', filetext)
        
        filename = os.path.join(self.dir_par_par_path,'otone_data/pipette_calibrations.json')

        # save the pipette's values to a local file, to be loaded when the server restarts
        FileIO.writeFile(filename,filetext,lambda: FileIO.onError('\t\tError saving the file:\r\r'))      
示例#11
0
 def get_state(self):
     """Get state information from Smoothieboard
     """
     if debug == True: FileIO.log('head.get_state called')
     #maps to smoothieAPI.get_state()
     #function get_state ()
     return self.smoothieAPI.get_state()
示例#12
0
 def reset(self):
     """Reset the Smoothieboard and clear theQueue object (:class:`the_queue`)
     """
     if debug == True: FileIO.log('head.reset called')
     #maps to smoothieAPI.reset() with extra code
     self.smoothieAPI.reset()
     self.theQueue.clear();
示例#13
0
 def raw(self, string):
     """Send a raw command to the Smoothieboard
     """
     if debug == True: FileIO.log('head.raw called')
     #maps to smoothieAPI.raw()
     #function raw(string)
     self.smoothieAPI.raw(string)
示例#14
0
    def __init__(self, tools, publisher):
        """Initialize Head object
        
        tools = dictionary of the tools on the head
        
        """
        if debug == True: FileIO.log('head.__init__ called')
        self.smoothieAPI = openSmoothie.Smoothie(self)
        self.PIPETTES = {'a':Pipette('a'),'b':Pipette('b')}    #need to create this dict in head setup
        self.tools = tools
        self.pubber = publisher
        self.smoothieAPI.set_raw_callback(self.pubber.on_raw_data)
        self.smoothieAPI.set_position_callback(self.pubber.on_position_data)
        self.smoothieAPI.set_limit_hit_callback(self.pubber.on_limit_hit)
        self.smoothieAPI.set_move_callback(self.pubber.on_start)
        self.smoothieAPI.set_delay_callback(self.pubber.show_delay)
        self.theQueue = TheQueue(self, publisher)
        
        #connect with the smoothie board
        self.smoothieAPI.connect()
        self.path = os.path.abspath(__file__)
        self.dir_path = os.path.dirname(self.path)  
        self.dir_par_path = os.path.dirname(self.dir_path)
        self.dir_par_par_path = os.path.dirname(self.dir_par_path)      

        self.load_pipette_values()
示例#15
0
    def on_state_change(self, state):
        """Check the given state (from Smoothieboard) and engage :obj:`theQueue` (:class:`the_queue`) accordingly

        If the state is 1 or the state.delaying is 1 then :obj:`theQueue` is_busy,

        else if the state is 0 and the state.delaying is 0, :obj:`theQueue` is not busy, 
        clear the currentCommand for the next one, and if not paused, tell :obj:`theQueue` 
        to step. Then update :obj:`theState`.

        :todo:
        :obj:`theState` should be updated BEFORE the actions taken from given state
        """
        if debug == True: FileIO.log('head.on_state_change called')
        
        if state['stat'] == 1 or state['delaying'] == 1:
            self.theQueue.is_busy = True

        elif state['stat'] == 0 and state['delaying'] == 0:
            self.theQueue.is_busy = False
            self.theQueue.currentCommand = None
            if self.theQueue.paused==False:
                self.theQueue.step(False)
    
        self.theState = state
        if debug == True and verbose == True: FileIO.log('\n\n\tHead state:\n\n',self.theState,'\n')
示例#16
0
    def end_sequence(self):
        """Returns the end pipetting sequence when running pipette command - currently an empty dictionary
        """
        if debug == True: FileIO.log('pipette.end_sequence called')
        oneCommand = {}

        return [oneCommand]
示例#17
0
 def publish_calibrations(self):
     """Publish calibrations data
     """
     if debug == True: FileIO.log('head.publish_calibrations called')
     self.pubber.send_message('containerLocations',self.get_deck())
     self.pubber.send_message('pipetteValues',self.get_pipettes())
     
示例#18
0
 def try_add(self, cmd):
     """Add a command to the smoothieQueue
     """
     FileIO.log('smoothie_ser2net.try_add called')
     self.smoothieQueue.append(cmd)
     #if len(self.smoothieQueue) == 1:
     self.try_step()
示例#19
0
 def resume_job(self):
     """Call :meth:`resume`... redundant, consider removing
     """
     if debug == True: FileIO.log('the_queue.resume_job called')
     #doesn't map to smoothieAPI
     #function resumeJob()
     self.resume()
示例#20
0
 def reset(self):
     """Reset robot
     """
     if debug == True: FileIO.log('smoothie_ser2net.reset called')
     if self.my_transport is not None:
         resetString = _dict['reset']
         self.send(self, resetString)
示例#21
0
    def __init__(self, axis):
        """Initialize Pipette

        toolname = the name of the tool (string)
        tooltype = the type of tool e.g. 1ch pipette, 8ch pipette, etc.(string)
        axis = position of tool on head & associated 
                motor (A, B, C, etc) (string)
        offset = the offset in space from the A tool which is defined to
            have offset = (0,0,0)
        """
        if debug == True: FileIO.log('pipette.__init__ called')
        toolname = axis + '_pipette'
        super().__init__(toolname, 'pipette', axis)

        #default parameters to start with
        self.resting = 0  #rest position of plunger when not engaged
        self.top = 0   #just touching the plunger (saved)
        self.bottom = 1  #calculated by pipette object (saved)
        self.blowout = 2  #value saved 2-5 mm before droptip (saved)
        self.droptip = 4  #complete max position of plunger (saved)

        #the calibrated plate offsets for this pipette

        self.volume = 200  #max volume pipette can hold calculated during calibration (saved in pipette_calibrations.json)
        self.bottom_distance = 2 #distance between blowout and botton

        self.theContainers = {} #(saved)
        self.tip_racks = []
        self.trash_container = []
        self.tip_rack_origin = ""
示例#22
0
 def erase_job(self):
     """Erase the ProtocolRunner job
     """
     if debug == True: FileIO.log('instruction_queue.erase_job called')
     self.head.erase_job()
     self.isRunning = False;
     self.instructionArray = []
示例#23
0
 def run_program(self,progName,ctrl=None,lid=None,vesselType=None,vesselVol=None):
     """run a named program in the cycler's files
     Name must be in quotes
     specify control method BLOCK, PROBE, or CALC. CALC by default
     specify heated lid on or off. On by default
     specify vessel type ('"Tubes"' or '"Plate"') and volume (10-100)
     Returns True if successful, False if not
     """
     # first check if program exists and exit program if not
     if not self.find_program(progName):
         print("Program does not exist")
         return False
     # cancel other programs
     if self.check_busy():
         self.cancel()
     # make sure lid is closed
     self.close_lid()
     # control method is CALC by default, lid ON by default
     ctrl = ctrl or self.ctrl
     lid = lid or self.lid
     # set temp calc algorithm parameters
     self.set_calc(vesselType,vesselVol)
     # send run command to cycler
     sendStr = self.format_input(['RUN '+progName,ctrl,lid],',')
     if debug == True: FileIO.log('cycler.py sending {0}'.format(sendStr))
     self.send(sendStr)
     return True
示例#24
0
 def home(self, data):
     """Intermediate step to start a homing sequence
     """
     if debug == True: FileIO.log('subscriber.home called')
     self.runner.insQueue.infinity_data = None
     self.runner.insQueue.erase_job()
     self.head.home(data)
示例#25
0
 def start_infinity_job(self, infinity_instructions):
     """Start a job and save instructions to a variable (infinity_data) so they can be perpetually run with :meth:`start_job`
     """
     if debug == True: FileIO.log('instruction_queue.start_infinity_job called')
     if infinity_instructions and len(infinity_instructions):
         self.infinity_data = json.dumps(infinity_instructions,sort_keys=True,indent=4,separators=(',',': '))
         self.start_job(infinity_instructions, True)
示例#26
0
 def move_plunger(self, data):
     """Tell the :class:`head` to move a :class:`pipette` to given location(s)
     """
     if debug == True:
         FileIO.log('subscriber.move_plunger called')
         if verbose == True: FileIO.log('\ndata:\n\t',data,'\n')
     self.head.move_plunger(data['axis'], data['locations'])
示例#27
0
 def move_pipette(self, data):
     """Tell the :class:`head` to move a :class:`pipette` 
     """
     if debug == True: FileIO.log('subscriber.move_pipette called')
     axis = data['axis']
     property_ = data['property']
     self.head.move_pipette(axis, property_)
示例#28
0
    def onJoin(self, details):
        """Callback fired when WAMP session has been established.

        May return a Deferred/Future.

        Starts instatiation of robot objects by calling :meth:`otone_client.instantiate_objects`.
        """
        if debug == True: FileIO.log('otone_client : WampComponent.onJoin called')
        if not self.factory._myAppSession:
            self.factory._myAppSession = self
        
        crossbar_status = True    
        instantiate_objects()
        
        
        def set_client_status(status):
            if debug == True: FileIO.log('otone_client : WampComponent.set_client_status called')
            global client_status
            client_status = status
            self.publish('com.opentrons.robot_ready',True)
        
        FileIO.log('about to publish com.opentrons.robot_ready TRUE')
        self.publish('com.opentrons.robot_ready',True)
        yield from self.subscribe(set_client_status, 'com.opentrons.browser_ready')
        yield from self.subscribe(subscriber.dispatch_message, 'com.opentrons.browser_to_robot')
示例#29
0
 def instructions(self, data):
     """Intermediate step to have :class:`prtocol_runner` and :class:`the_queue` start running a protocol
     """
     if debug == True:
         FileIO.log('subscriber.instructions called')
         if verbose == True: FileIO.log('\targs: ', data,'\n')
     if data and len(data):
         self.runner.insQueue.start_job (data, True)
示例#30
0
 def set_slot(self, slot):
     """Set a new slot of a DeckModule on the deck
     
     slot = an integer between 1 and 15 to indicate the position
     of this deckModule
     """
     if debug == True: FileIO.log('deck_module.set_slot called')
     self.slot = slot