def __init__(self, agent, ip=IP_DEFAULT, port=17123): ''' Parameters ---------- ip : string IP address port : int Port number ''' self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.take_data = False self._dev = dS378(ip=ip, port=port) self.initialized = False agg_params = {'frame_length': 60} self.agent.register_feed('relay', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, ip_addr, port, mode=None, samp=2): self.ip_addr = ip_addr self.port = port self.xy_stage = None self.initialized = False self.take_data = False self.is_moving = False self.agent = agent self.log = agent.log self.lock = TimeoutLock() if mode == 'acq': self.auto_acq = True else: self.auto_acq = False self.sampling_frequency = float(samp) ### register the position feeds agg_params = { 'frame_length': 10 * 60, #[sec] } self.agent.register_feed('positions', record=True, agg_params=agg_params, buffer_time=0)
def __init__(self, agent, port, ip_address, f_sample=2.5, fake_errors=False): self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.ip_address = ip_address self.fake_errors = fake_errors self.port = port self.module: Optional[Module] = None self.f_sample = f_sample self.initialized = False self.take_data = False # Registers data feeds agg_params = { 'frame_length': 60, } self.agent.register_feed('ptc_status', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, sn, ip, f_sample=0.1, threshold=0.1, window=900): self.agent = agent self.sn = sn self.ip = ip self.f_sample = f_sample self.t_sample = 1/self.f_sample - 0.01 assert self.t_sample < 7200, \ "acq sampling freq must be such that t_sample is less than 2 hours" self._lock = TimeoutLock() self.log = agent.log self.initialized = False self.take_data = False self.module = None # for stability checking self.threshold = threshold self.window = window self._recent_temps = None self._static_setpoint = None agg_params = {'frame_length': 10*60} # sec # combined feed for thermometry and control data self.agent.register_feed( 'temperatures', record=True, agg_params=agg_params, buffer_time=1 )
def __init__(self, agent, num_channels=2, fake_data=False, port="/dev/ttyUSB0"): print(num_channels) self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.fake_data = fake_data self.module = None self.port = port self.thermometers = [ 'Channel {}'.format(i + 1) for i in range(num_channels) ] self.log = agent.log self.initialized = False self.take_data = False # Registers Temperature and Voltage feeds agg_params = { 'frame_length': 60, } self.agent.register_feed('temperatures', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, name, ip, fake_data=False, dwell_time_delay=0): # self._acq_proc_lock is held for the duration of the acq Process. # Tasks that require acq to not be running, at all, should use # this lock. self._acq_proc_lock = TimeoutLock() # self._lock is held by the acq Process only when accessing # the hardware but released occasionally so that (short) Tasks # may run. Use a YieldingLock to guarantee that a waiting # Task gets activated preferentially, even if the acq thread # immediately tries to reacquire. self._lock = YieldingLock(default_timeout=5) self.name = name self.ip = ip self.fake_data = fake_data self.dwell_time_delay = dwell_time_delay self.module = None self.thermometers = [] self.log = agent.log self.initialized = False self.take_data = False self.agent = agent # Registers temperature feeds agg_params = { 'frame_length': 10 * 60 #[sec] } self.agent.register_feed('temperatures', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, ip_address, active_channels, function_file, sampling_frequency): self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.ip_address = ip_address self.module = None self.ljf = LabJackFunctions() self.sampling_frequency = sampling_frequency # Labjack channels to read if active_channels[0] == 'T7-all': self.chs = ['AIN{}'.format(i) for i in range(14)] elif active_channels[0] == 'T4-all': self.chs = ['AIN{}'.format(i) for i in range(12)] else: self.chs = active_channels # Load dictionary of unit conversion functions from yaml file. Assumes # the file is in the $OCS_CONFIG_DIR directory if function_file == 'None': self.functions = {} else: function_file_path = os.path.join(os.environ['OCS_CONFIG_DIR'], function_file) with open(function_file_path, 'r') as stream: self.functions = yaml.safe_load(stream) if self.functions is None: self.functions = {} self.log.info( f"Applying conversion functions: {self.functions}") self.initialized = False self.take_data = False # Register main feed. Exclude influx due to potentially high scan rate agg_params = {'frame_length': 60, 'exclude_influx': True} self.agent.register_feed('sensors', record=True, agg_params=agg_params, buffer_time=1) # Register downsampled feed for influx. agg_params_downsampled = {'frame_length': 60} self.agent.register_feed('sensors_downsampled', record=True, agg_params=agg_params_downsampled, buffer_time=1) self.agent.register_feed('registers', record=True, agg_params={'frame_length': 10 * 60}, buffer_time=1.)
def __init__(self, agent, ip_address, username, password): """ Initializes the class variables Args: ip_address(str): IP Address for the agent. username(str): username credential to login to strip password(str): password credential to login to strip """ self.agent = agent self.lock = TimeoutLock() self.ip_address = ip_address self.user = username self.passw = password
def __init__(self, agent, args): self.agent: ocs_agent.OCSAgent = agent self.log = agent.log self.prot = None self.protocol_lock = TimeoutLock() self.current_session = None if args.monitor_id is not None: self.agent.subscribe_on_start( self._on_session_data, 'observatory.{}.feeds.pysmurf_session_data'.format( args.monitor_id), )
def __init__(self, agent, ip_address, gpib_slot): self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.job = None self.ip_address = ip_address self.gpib_slot = gpib_slot self.monitor = False self.awg = None # Registers data feeds agg_params = { 'frame_length': 60, } self.agent.register_feed('AWG', record=True, agg_params=agg_params)
def __init__(self, agent, ip_address, port, f_sample=2.5): self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.f_sample = f_sample self.take_data = False self.gauge = Pfeiffer(ip_address, int(port)) agg_params = { 'frame_length': 60, } self.agent.register_feed('pressures', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, port='/dev/ttyACM0'): self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.port = port self.take_data = False self.arduino = HWPSimulator(port=self.port) self.initialized = False agg_params = {'frame_length': 60} self.agent.register_feed('amplitudes', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent_obj, port=8080): self.active = True self.agent = agent_obj self.log = agent_obj.log self.lock = TimeoutLock() self.port = port self.take_data = False self.initialized = False # For clock count to time conversion self.rising_edge_count = 0 self.irig_time = 0 agg_params = {'frame_length': 60} self.agent.register_feed('HWPEncoder', record=True, agg_params=agg_params) agg_params = {'frame_length': 60, 'exclude_influx': True} self.agent.register_feed('HWPEncoder_full', record=True, agg_params=agg_params) self.parser = EncoderParser(beaglebone_port=self.port)
def __init__(self, agent, kikusui_ip, kikusui_port, pid_ip, pid_port, pid_verbosity): self.agent = agent self.log = agent.log self.lock = TimeoutLock() self._initialized = False self.take_data = False self.kikusui_ip = kikusui_ip self.kikusui_port = int(kikusui_port) self.pid_ip = pid_ip self.pid_port = pid_port self._pid_verbosity = pid_verbosity > 0 self.cmd = None # Command object for PSU commanding self.pid = None # PID object for pid controller commanding agg_params = {'frame_length': 60} self.agent.register_feed('hwprotation', record=True, agg_params=agg_params)
def __init__(self, agent, ip_address, gpib_slot): self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.job = None self.ip_address = ip_address self.gpib_slot = gpib_slot self.monitor = False self.psu = None # Registers Temperature and Voltage feeds agg_params = { 'frame_length': 10 * 60, } self.agent.register_feed('psu_output', record=True, agg_params=agg_params, buffer_time=0)
def __init__(self, agent, ip_address, num_channels): self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.ip_address = ip_address self.module = None self.sensors = ['Channel {}'.format(i+1) for i in range(num_channels)] self.initialized = False self.take_data = False # Register feed agg_params = { 'frame_length': 60, } self.agent.register_feed('Sensors', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, port, f_sample=1.): self.agent: ocs_agent.OCSAgent = agent self.log = agent.log self.lock = TimeoutLock() self.port = port self.dev = None self.f_sample = f_sample self.initialized = False self.take_data = False # Registers Temperature and Voltage feeds agg_params = {'frame_length': 60} self.agent.register_feed('mag_field', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, ipaddr=IPADDR_DEFAULT): ''' Parameters ---------- ipaddr : str IP address of AC supply ''' self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.take_data = False self.initialized = False self._pcr = PCR500MA(ipaddr) agg_params = {'frame_length': 60} self.agent.register_feed('acsupply', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, port="/dev/ttyUSB0", f_sample=2.5): self.agent: ocs_agent.OCSAgent = agent self.log = agent.log self.lock = TimeoutLock() self.port = port self.module: Optional[Module] = None self.f_sample = f_sample self.initialized = False self.take_data = False # Registers Temperature and Voltage feeds agg_params = { 'frame_length': 60, } self.agent.register_feed('temperatures', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, port=PORT_DEFAULT): ''' Parameters ---------- port : string Port to connect ''' self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.take_data = False self._ble2 = BLE2(port=port) self.initialized = False agg_params = {'frame_length': 60} self.agent.register_feed('motor', record=True, agg_params=agg_params, buffer_time=1)
def __init__(self, agent, config_file): self.agent = agent self.lock = TimeoutLock() self.meas_cap = meas_cap_builder(config_file) agg_params = { 'frame_length': 60, } for meas, capdists in self.meas_cap.items(): self.agent.register_feed("Cap{}".format(meas.num), record=True, agg_params=agg_params) for n, capdist in enumerate(capdists): for i in range(len(capdist.avgs) + 1): self.agent.register_feed("Dist{}_Cal{}_Intvl{}".format(meas.num, n, i), record=True, agg_params=agg_params) self.initialized = False self.take_data = False self.f_poll = POLL_FREQUENCY self.send_interval = self.f_poll/SEND_FREQUENCY
def __init__(self, agent, port="/dev/ttyUSB0", sample_freq=0.5): self.active = True self.agent: ocs_agent.OCSAgent = agent self.log = agent.log self.lock = TimeoutLock() self.port = port self.module: Optional[VantagePro2] = None if sample_freq > 0.5: self.log.warn("Sample frequency too fast! Setting to 0.5Hz") sample_freq = 0.5 self.sample_freq = sample_freq self.initialized = False self.take_data = False # Registers weather data feed agg_params = { 'frame_length': 60, } self.agent.register_feed('weather_data', record=True, agg_params=agg_params)
class stmACAgent: ''' OCS agent class for stimulator AC source ''' def __init__(self, agent, ipaddr=IPADDR_DEFAULT): ''' Parameters ---------- ipaddr : str IP address of AC supply ''' self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.take_data = False self.initialized = False self._pcr = PCR500MA(ipaddr) agg_params = {'frame_length': 60} self.agent.register_feed('acsupply', record=True, agg_params=agg_params, buffer_time=1) def init_pcr500(self, session, params=None): '''Initialization of pcr500 AC supply ''' if self.initialized: return True, "Already initialized." with self.lock.acquire_timeout(timeout=0, job='init') as acquired: if not acquired: self.log.warn( "Could not start init because {} is already running". format(self.lock.job)) return False, "Could not acquire lock." try: self._pcr.checkID() except ValueError: pass print("AC supply PCR500 initialized.") self.initialized = True return True, "AC supply PCR500 initialized." def start_acq(self, session, params): '''Starts acquiring data. ''' f_sample = params.get('sampling frequency', 0.1) sleep_time = 1 / f_sample - 0.1 if not self.initialized: self.init_pcr500(session) #with self.lock.acquire_timeout(timeout=0, job='acq') as acquired: # if not acquired: # self.log.warn("Could not start acq because {} is already running".format(self.lock.job)) # return False, "Could not acquire lock." session.set_status('running') self.take_data = True session.data = {"fields": {}} while self.take_data: with self.lock.acquire_timeout(timeout=1, job='acq') as acquired: if not acquired: print( f"Lock could not be acquired because it is held by {self.lock.job}" ) return False current_time = time.time() data = { 'timestamp': current_time, 'block_name': 'acsupply', 'data': {} } voltage = self._pcr.getVoltage() current = self._pcr.getCurrent() power = self._pcr.getPower() if not self.lock.release_and_acquire(timeout=10): print( f"Could not re-acquire lock now held by {self.lock.job}." ) return False data['data']['voltage'] = voltage data['data']['current'] = current data['data']['power'] = power field_dict = { f'acsupply': { 'voltage': voltage, 'current': current, 'power': power } } session.data['fields'].update(field_dict) time.sleep(sleep_time) self.agent.publish_to_feed('acsupply', data) self.agent.feeds['acsupply'].flush_buffer() return True, 'Acquisition exited cleanly.' def stop_acq(self, session, params=None): """ Stops the data acquisiton. """ if self.take_data: self.take_data = False return True, 'requested to stop taking data.' return False, 'acq is not currently running.' def set_values(self, session, params=None): '''A task to set sensor parameters for AC supply volt : float operate AC voltage ''' if params is None: params = {} with self.lock.acquire_timeout(3, job='set_values') as acquired: if not acquired: self.log.warn('Could not start set_values because ' f'{self.lock.job} is already running') return False, 'Could not acquire lock.' volt = params.get('volt') if not volt is None: self.voltsetting = volt # self._ble2.set_speed(speed) def get_values(self, session, params=None): '''A task to provide configuration information ''' pass def switchPower(self, session, params=None, state=0): '''A task to turn switch, state 0 = off, 1 = on ''' pass def get_settings(self, session, params=None): ''' Get relay states''' if params is None: params = {} with self.lock.acquire_timeout(3, job='get_settings') as acquired: if not acquired: self.log.warn('Could not start get_setting because ' f'{self.lock.job} is already running') return False, 'Could not acquire lock.' setV = self.Voltage session.data = {'volt': setV} return True, f'Got AC status' def getACstatus(self, session, params=None): with self.lock.acquire_timeout(3, job='get_settings') as acquired: if not acquired: self.log.warn('Could not start get_setting because ' f'{self.lock.job} is already running') return False, 'Could not acquire lock.' #print(self, session, params) volt = self._pcr._a('MEAS:VOLT:AC?') curr = self._pcr._a('MEAS:CURR:AC?') freq = self._pcr._a('MEAS:FREQ?') power = self._pcr._a('MEAS:POW:AC?') preac = self._pcr._a('MEAS:POW:AC:REAC?') print(volt, curr, freq, power, preac) return True, f'AC {volt}, {curr}, {freq}, {power}, {preac}' def rampVoltage(self, session, params=None): # normal temperature control print(params) voltgoal = params.get('volt', 0) print(voltgoal) if (voltgoal < 0): print("Voltage cannot be negative!") return False, 'Voltage cannot be negative' while (abs(voltgoal - self._pcr.Voltage) > VoltStep): if (self._pcr.Voltage < voltgoal): self._pcr.Voltage = self._pcr.Voltage + VoltStep elif (self._pcr.Voltage > voltgoal): self._pcr.Voltage = self._pcr.Voltage - VoltStep with self.lock.acquire_timeout(timeout=3, job='set_voltage') as acquired: print("Set ", self._pcr.Voltage) self._pcr.setVoltage(self._pcr.Voltage) time.sleep(0.5) print(self._pcr.getCurrent()) time.sleep(WaitTimeStep - 0.5) with self.lock.acquire_timeout(timeout=3, job='set_voltage') as acquired: print("last step to", voltgoal) self._pcr.Voltage = voltgoal print(self, self._pcr.getCurrent()) self._pcr.setVoltage(self._pcr.Voltage) time.sleep(0.5) print(self._pcr.getCurrent()) return True, f'Reached to voltage {voltgoal}' def forceZero(self, session, params=None): #for site work while (self._pcr.Voltage > VoltStep): with self.lock.acquire_timeout(timeout=3, job='set_voltage') as acquired: self._pcr.Voltage = self._pcr.Voltage - VoltStep print("go down to ", self._pcr.Voltage) self._pcr.setVoltage(self._pcr.Voltage) time.sleep(WaitTimeForce) print("set to 0 Volt") with self.lock.acquire_timeout(timeout=3, job='set_voltage') as acquired: self._pcr.Voltage = 0.0 self._pcr.setVoltage(0.0) return True, f'Ramped down to 0 volt.'
class LS372_Agent: """Agent to connect to a single Lakeshore 372 device. Args: name (ApplicationSession): ApplicationSession for the Agent. ip (str): IP Address for the 372 device. fake_data (bool, optional): generates random numbers without connecting to LS if True. dwell_time_delay (int, optional): Amount of time, in seconds, to delay data collection after switching channels. Note this time should not include the change pause time, which is automatically accounted for. Will automatically be reduced to dwell_time - 1 second if it is set longer than a channel's dwell time. This ensures at least one second of data collection at the end of a scan. """ def __init__(self, agent, name, ip, fake_data=False, dwell_time_delay=0): # self._acq_proc_lock is held for the duration of the acq Process. # Tasks that require acq to not be running, at all, should use # this lock. self._acq_proc_lock = TimeoutLock() # self._lock is held by the acq Process only when accessing # the hardware but released occasionally so that (short) Tasks # may run. Use a YieldingLock to guarantee that a waiting # Task gets activated preferentially, even if the acq thread # immediately tries to reacquire. self._lock = YieldingLock(default_timeout=5) self.name = name self.ip = ip self.fake_data = fake_data self.dwell_time_delay = dwell_time_delay self.module = None self.thermometers = [] self.log = agent.log self.initialized = False self.take_data = False self.agent = agent # Registers temperature feeds agg_params = { 'frame_length': 10 * 60 #[sec] } self.agent.register_feed('temperatures', record=True, agg_params=agg_params, buffer_time=1) def init_lakeshore_task(self, session, params=None): """init_lakeshore_task(params=None) Perform first time setup of the Lakeshore 372 communication. Args: params (dict): Parameters dictionary for passing parameters to task. Parameters: auto_acquire (bool, optional): Default is False. Starts data acquisition after initialization if True. """ if params is None: params = {} if self.initialized and not params.get('force', False): self.log.info("Lakeshore already initialized. Returning...") return True, "Already initialized" with self._lock.acquire_timeout(job='init') as acquired1, \ self._acq_proc_lock.acquire_timeout(timeout=0., job='init') \ as acquired2: if not acquired1: self.log.warn(f"Could not start init because " f"{self._lock.job} is already running") return False, "Could not acquire lock" if not acquired2: self.log.warn(f"Could not start init because " f"{self._acq_proc_lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') if self.fake_data: self.res = random.randrange(1, 1000) session.add_message("No initialization since faking data") self.thermometers = ["thermA", "thermB"] else: self.module = LS372(self.ip) print("Initialized Lakeshore module: {!s}".format(self.module)) session.add_message("Lakeshore initilized with ID: %s" % self.module.id) self.thermometers = [ channel.name for channel in self.module.channels ] self.initialized = True # Start data acquisition if requested if params.get('auto_acquire', False): self.agent.start('acq') return True, 'Lakeshore module initialized.' def start_acq(self, session, params=None): """acq(params=None) Method to start data acquisition process. The most recent data collected is stored in session.data in the structure:: >>> session.data {"fields": {"Channel_05": {"T": 293.644, "R": 33.752, "timestamp": 1601924482.722671}, "Channel_06": {"T": 0, "R": 1022.44, "timestamp": 1601924499.5258765}, "Channel_08": {"T": 0, "R": 1026.98, "timestamp": 1601924494.8172355}, "Channel_01": {"T": 293.41, "R": 108.093, "timestamp": 1601924450.9315426}, "Channel_02": {"T": 293.701, "R": 30.7398, "timestamp": 1601924466.6130798} } } """ with self._acq_proc_lock.acquire_timeout(timeout=0, job='acq') \ as acq_acquired, \ self._lock.acquire_timeout(job='acq') as acquired: if not acq_acquired: self.log.warn(f"Could not start Process because " f"{self._acq_proc_lock.job} is already running") return False, "Could not acquire lock" if not acquired: self.log.warn(f"Could not start Process because " f"{self._lock.job} is holding the lock") return False, "Could not acquire lock" session.set_status('running') self.log.info("Starting data acquisition for {}".format( self.agent.agent_address)) previous_channel = None last_release = time.time() session.data = {"fields": {}} self.take_data = True while self.take_data: # Relinquish sampling lock occasionally. if time.time() - last_release > 1.: last_release = time.time() if not self._lock.release_and_acquire(timeout=10): self.log.warn(f"Failed to re-acquire sampling lock, " f"currently held by {self._lock.job}.") continue if self.fake_data: data = { 'timestamp': time.time(), 'block_name': 'fake-data', 'data': {} } for therm in self.thermometers: reading = np.random.normal(self.res, 20) data['data'][therm] = reading time.sleep(.1) else: active_channel = self.module.get_active_channel() # The 372 reports the last updated measurement repeatedly # during the "pause change time", this results in several # stale datapoints being recorded. To get around this we # query the pause time and skip data collection during it # if the channel has changed (as it would if autoscan is # enabled.) if previous_channel != active_channel: if previous_channel is not None: pause_time = active_channel.get_pause() self.log.debug("Pause time for {c}: {p}", c=active_channel.channel_num, p=pause_time) dwell_time = active_channel.get_dwell() self.log.debug("User set dwell_time_delay: {p}", p=self.dwell_time_delay) # Check user set dwell time isn't too long if self.dwell_time_delay > dwell_time: self.log.warn("WARNING: User set dwell_time_delay of " + \ "{delay} s is larger than channel " + \ "dwell time of {chan_time} s. If " + \ "you are autoscanning this will " + \ "cause no data to be collected. " + \ "Reducing dwell time delay to {s} s.", delay=self.dwell_time_delay, chan_time=dwell_time, s=dwell_time - 1) total_time = pause_time + dwell_time - 1 else: total_time = pause_time + self.dwell_time_delay for i in range(total_time): self.log.debug( "Sleeping for {t} more seconds...", t=total_time - i) time.sleep(1) # Track the last channel we measured previous_channel = self.module.get_active_channel() current_time = time.time() data = { 'timestamp': current_time, 'block_name': active_channel.name, 'data': {} } # Collect both temperature and resistance values from each Channel channel_str = active_channel.name.replace(' ', '_') temp_reading = self.module.get_temp( unit='kelvin', chan=active_channel.channel_num) res_reading = self.module.get_temp( unit='ohms', chan=active_channel.channel_num) # For data feed data['data'][channel_str + '_T'] = temp_reading data['data'][channel_str + '_R'] = res_reading # For session.data field_dict = { channel_str: { "T": temp_reading, "R": res_reading, "timestamp": current_time } } session.data['fields'].update(field_dict) session.app.publish_to_feed('temperatures', data) self.log.debug("{data}", data=session.data) return True, 'Acquisition exited cleanly.' def stop_acq(self, session, params=None): """ Stops acq process. """ if self.take_data: self.take_data = False return True, 'requested to stop taking data.' else: return False, 'acq is not currently running' def set_heater_range(self, session, params): """ Adjust the heater range for servoing cryostat. Wait for a specified amount of time after the change. :param params: dict with 'range', 'wait' keys :type params: dict range - the heater range value to change to wait - time in seconds after changing the heater value to wait, allows the servo to adjust to the new heater range, typical value of ~600 seconds """ with self._lock.acquire_timeout(job='set_heater_range') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') heater_string = params.get('heater', 'sample') if heater_string.lower() == 'sample': heater = self.module.sample_heater elif heater_string.lower() == 'still': heater = self.module.still_heater current_range = heater.get_heater_range() if params['range'] == current_range: print( "Current heater range matches commanded value. Proceeding unchanged." ) else: heater.set_heater_range(params['range']) time.sleep(params['wait']) return True, f'Set {heater_string} heater range to {params["range"]}' def set_excitation_mode(self, session, params): """ Set the excitation mode of a specified channel. :param params: dict with "channel" and "mode" keys for Channel.set_excitation_mode() :type params: dict """ with self._lock.acquire_timeout(job='set_excitation_mode') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') self.module.channels[params['channel']].set_excitation_mode( params['mode']) session.add_message( f'post message in agent for Set channel {params["channel"]} excitation mode to {params["mode"]}' ) print( f'print statement in agent for Set channel {params["channel"]} excitation mode to {params["mode"]}' ) return True, f'return text for Set channel {params["channel"]} excitation mode to {params["mode"]}' def set_excitation(self, session, params): """ Set the excitation voltage/current value of a specified channel. :param params: dict with "channel" and "value" keys for Channel.set_excitation() :type params: dict """ with self._lock.acquire_timeout(job='set_excitation') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') current_excitation = self.module.channels[ params['channel']].get_excitation() if params['value'] == current_excitation: print( f'Channel {params["channel"]} excitation already set to {params["value"]}' ) else: self.module.channels[params['channel']].set_excitation( params['value']) session.add_message( f'Set channel {params["channel"]} excitation to {params["value"]}' ) print( f'Set channel {params["channel"]} excitation to {params["value"]}' ) return True, f'Set channel {params["channel"]} excitation to {params["value"]}' def set_pid(self, session, params): """ Set the PID parameters for servo control of fridge. :param params: dict with "P", "I", and "D" keys for Heater.set_pid() :type params: dict """ with self._lock.acquire_timeout(job='set_pid') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') self.module.sample_heater.set_pid(params["P"], params["I"], params["D"]) session.add_message( f'post message text for Set PID to {params["P"]}, {params["I"]}, {params["D"]}' ) print( f'print text for Set PID to {params["P"]}, {params["I"]}, {params["D"]}' ) return True, f'return text for Set PID to {params["P"]}, {params["I"]}, {params["D"]}' def set_active_channel(self, session, params): """ Set the active channel on the LS372. :param params: dict with "channel" number :type params: dict """ with self._lock.acquire_timeout(job='set_active_channel') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') self.module.set_active_channel(params["channel"]) session.add_message( f'post message text for set channel to {params["channel"]}') print(f'print text for set channel to {params["channel"]}') return True, f'return text for set channel to {params["channel"]}' def set_autoscan(self, session, params): """ Sets autoscan on the LS372. :param params: dict with "autoscan" value """ with self._lock.acquire_timeout(job='set_autoscan') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') if params['autoscan']: self.module.enable_autoscan() self.log.info('enabled autoscan') else: self.module.disable_autoscan() self.log.info('disabled autoscan') return True, 'Set autoscan to {}'.format(params['autoscan']) def servo_to_temperature(self, session, params): """Servo to temperature passed into params. :param params: dict with "temperature" Heater.set_setpoint() in unites of K :type params: dict """ with self._lock.acquire_timeout( job='servo_to_temperature') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') # Check we're in correct control mode for servo. if self.module.sample_heater.mode != 'Closed Loop': session.add_message( f'Changing control to Closed Loop mode for servo.') self.module.sample_heater.set_mode("Closed Loop") # Check we aren't autoscanning. if self.module.get_autoscan() is True: session.add_message( f'Autoscan is enabled, disabling for PID control on dedicated channel.' ) self.module.disable_autoscan() # Check we're scanning same channel expected by heater for control. if self.module.get_active_channel().channel_num != int( self.module.sample_heater.input): session.add_message( f'Changing active channel to expected heater control input' ) self.module.set_active_channel( int(self.module.sample_heater.input)) # Check we're setup to take correct units. if self.module.get_active_channel().units != 'kelvin': session.add_message( f'Setting preferred units to Kelvin on heater control input.' ) self.module.get_active_channel().set_units('kelvin') # Make sure we aren't servoing too high in temperature. if params["temperature"] > 1: return False, f'Servo temperature is set above 1K. Aborting.' self.module.sample_heater.set_setpoint(params["temperature"]) return True, f'Setpoint now set to {params["temperature"]} K' def check_temperature_stability(self, session, params): """Check servo temperature stability is within threshold. :param params: dict with "measurements" and "threshold" parameters :type params: dict measurements - number of measurements to average for stability check threshold - amount within which the average needs to be to the setpoint for stability """ with self._lock.acquire_timeout( job='check_temp_stability') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') setpoint = float(self.module.sample_heater.get_setpoint()) if params is None: params = {'measurements': 10, 'threshold': 0.5e-3} test_temps = [] for i in range(params['measurements']): test_temps.append(self.module.get_temp()) time.sleep( .1 ) # sampling rate is 10 readings/sec, so wait 0.1 s for a new reading mean = np.mean(test_temps) session.add_message( f'Average of {params["measurements"]} measurements is {mean} K.' ) print( f'Average of {params["measurements"]} measurements is {mean} K.' ) if np.abs(mean - setpoint) < params['threshold']: print("passed threshold") session.add_message(f'Setpoint Difference: ' + str(mean - setpoint)) session.add_message( f'Average is within {params["threshold"]} K threshold. Proceeding with calibration.' ) return True, f"Servo temperature is stable within {params['threshold']} K" else: print("we're in the else") #adjust_heater(t,rest) return False, f"Temperature not stable within {params['threshold']}." def set_output_mode(self, session, params=None): """ Set output mode of the heater. :param params: dict with "heater" and "mode" parameters :type params: dict heater - Specifies which heater to control. Either 'sample' or 'still' mode - Specifies mode of heater. Can be "Off", "Monitor Out", "Open Loop", "Zone", "Still", "Closed Loop", or "Warm up" """ with self._lock.acquire_timeout(job='set_output_mode') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" session.set_status('running') if params['heater'].lower() == 'still': self.module.still_heater.set_mode(params['mode']) if params['heater'].lower() == 'sample': self.module.sample_heater.set_mode(params['mode']) self.log.info("Set {} output mode to {}".format( params['heater'], params['mode'])) return True, "Set {} output mode to {}".format(params['heater'], params['mode']) def set_heater_output(self, session, params=None): """ Set display type and output of the heater. :param params: dict with "heater", "display", and "output" parameters :type params: dict heater - Specifies which heater to control. Either 'sample' or 'still' output - Specifies heater output value. If display is set to "Current" or heater is "still", can be any number between 0 and 100. If display is set to "Power", can be any number between 0 and the maximum allowed power. Note that for the still heater this sets the still heater manual output, NOT the still heater still output. Use set_still_output() instead to set the still output. display (opt)- Specifies heater display type. Can be "Current" or "Power". If None, heater display is not reset before setting output. """ with self._lock.acquire_timeout(job='set_heater_output') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" heater = params['heater'].lower() output = params['output'] display = params.get('display', None) if heater == 'still': self.module.still_heater.set_heater_output( output, display_type=display) if heater.lower() == 'sample': self.log.info("display: {}\toutput: {}".format( display, output)) self.module.sample_heater.set_heater_output( output, display_type=display) self.log.info("Set {} heater display to {}, output to {}".format( heater, display, output)) session.set_status('running') data = { 'timestamp': time.time(), 'block_name': '{}_heater_out'.format(heater), 'data': { '{}_heater_out'.format(heater): output } } session.app.publish_to_feed('temperatures', data) return True, "Set {} display to {}, output to {}".format( heater, display, output) def set_still_output(self, session, params=None): """ Set the still output on the still heater. This is different than the manual output on the still heater. Use set_heater_output() for that. :param params: dict with "output" parameter :type params: dict output - Specifies still heater output value. Can be any number between 0 and 100. """ with self._lock.acquire_timeout(job='set_still_output') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" output = params['output'] self.module.still_heater.set_still_output(output) self.log.info("Set still output to {}".format(output)) session.set_status('running') data = { 'timestamp': time.time(), 'block_name': 'still_heater_still_out', 'data': { 'still_heater_still_out': output } } session.app.publish_to_feed('temperatures', data) return True, "Set still output to {}".format(output) def get_still_output(self, session, params=None): """ Gets the current still output on the still heater. This task has no useful parameters. The still heater output is stored in the session.data object in the format:: {"still_heater_still_out": 9.628} """ with self._lock.acquire_timeout(job='get_still_output') as acquired: if not acquired: self.log.warn(f"Could not start Task because " f"{self._lock.job} is already running") return False, "Could not acquire lock" still_output = self.module.still_heater.get_still_output() self.log.info("Current still output is {}".format(still_output)) session.set_status('running') session.data = {"still_heater_still_out": still_output} return True, "Current still output is {}".format(still_output)
class VantagePro2Agent: """Agent to connect to single VantagePro2 Weather Monitor Device. Args: sample_freq (double): frequency (Hz) at which the weather monitor samples data. Can not be faster than 0.5 Hz. This value is converted to period (sec) for time.wait(seconds) port (string): usb port that the weather monitor is connected to. The monitor will communicate via this port. """ # change port argument when I figure out how to generalize it! def __init__(self, agent, port="/dev/ttyUSB0", sample_freq=0.5): self.active = True self.agent: ocs_agent.OCSAgent = agent self.log = agent.log self.lock = TimeoutLock() self.port = port self.module: Optional[VantagePro2] = None if sample_freq > 0.5: self.log.warn("Sample frequency too fast! Setting to 0.5Hz") sample_freq = 0.5 self.sample_freq = sample_freq self.initialized = False self.take_data = False # Registers weather data feed agg_params = { 'frame_length': 60, } self.agent.register_feed('weather_data', record=True, agg_params=agg_params) # Task functions. def init_VantagePro2_task(self, session, params=None): """ Perform first time setup of the Weather Monitor Module. Args: params (dict): Parameters dictionary for passing parameters to task. """ if params is None: params = {} auto_acquire = params.get('auto_acquire', False) if self.initialized: return True, "Already Initialized Module" with self.lock.acquire_timeout(0, job='init') as acquired: if not acquired: self.log.warn("Could not start init because " "{} is already running".format(self.lock.job)) return False, "Could not acquire lock." session.set_status('starting') self.module = VantagePro2(self.port) print("Initialized Vantage Pro2 module: {!s}".format( self.module)) self.initialized = True # Start data acquisition if requested if auto_acquire: self.agent.start('acq') time.sleep(2) return True, 'Vantage Pro2 module initialized.' def start_acq(self, session, params=None): """ Method to start data acquisition process. Args: sample_freq (double): Frequency at which weather data is sampled. Defaults to 0.5 Hz. """ if params is None: params = {} sample_freq = params.get('sample_freq') # If loops is None, use value passed to Agent init if sample_freq is None: sample_freq = self.sample_freq wait_time = 1/sample_freq with self.lock.acquire_timeout(0, job='acq') as acquired: if not acquired: self.log.warn("""Could not start acq because {} is already running""" .format(self.lock.job)) return False, "Could not acquire lock." session.set_status('running') # use pacemaker class to take data at regular intervals if sample_freq % 1 == 0: pm = Pacemaker(sample_freq, True) else: pm = Pacemaker(sample_freq) self.take_data = True while self.take_data: pm.sleep() data = { 'timestamp': time.time(), 'block_name': 'weather', 'data': {} } data['data'] = self.module.weather_daq() self.agent.publish_to_feed('weather_data', data) time.sleep(wait_time) self.agent.feeds['weather_data'].flush_buffer() return True, 'Acquisition exited cleanly.' def stop_acq(self, session, params=None): """ Stops acq process. """ if self.take_data: self.take_data = False print('requested to stop taking data.') return True, 'data taking succesfully halted' else: return False, 'acq is not currently running'
class LS240_Agent: def __init__(self, agent, num_channels=2, fake_data=False, port="/dev/ttyUSB0"): print(num_channels) self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.fake_data = fake_data self.module = None self.port = port self.thermometers = [ 'Channel {}'.format(i + 1) for i in range(num_channels) ] self.log = agent.log self.initialized = False self.take_data = False # Registers Temperature and Voltage feeds agg_params = { 'frame_length': 60, } self.agent.register_feed('temperatures', record=True, agg_params=agg_params, buffer_time=1) # Task functions. def init_lakeshore_task(self, session, params=None): """ Task to initialize Lakeshore 240 Module. """ if self.initialized: return True, "Already Initialized Module" with self.lock.acquire_timeout(0, job='init') as acquired: if not acquired: self.log.warn("Could not start init because " "{} is already running".format(self.lock.job)) return False, "Could not acquire lock." session.set_status('starting') if self.fake_data: session.add_message("No initialization since faking data") # self.thermometers = ["chan_1", "chan_2"] else: self.module = Module(port=self.port) print("Initialized Lakeshore module: {!s}".format(self.module)) session.add_message("Lakeshore initialized with ID: %s" % self.module.inst_sn) self.initialized = True return True, 'Lakeshore module initialized.' def set_values(self, session, params=None): """ A task to set sensor parameters for a Lakeshore240 Channel Args: channel (int, 1 -- 2 or 8): Channel number to set. Optional Args: sensor (int, 1, 2, or 3): 1 = Diode, 2 = PlatRTC, 3 = NTC RTD auto_range (int, 0 or 1): Must be 0 or 1. Specifies if channel should use autorange. range (int 0-8): Specifies range if autorange is false. Only settable for NTC RTD. 0 = 10 Ohms (1 mA) 1 = 30 Ohms (300 uA) 2 = 100 Ohms (100 uA) 3 = 300 Ohms (30 uA) 4 = 1 kOhm (10 uA) 5 = 3 kOhms (3 uA) 6 = 10 kOhms (1 uA) 7 = 30 kOhms (300 nA) 8 = 100 kOhms (100 nA) current_reversal (int, 0 or 1): Specifies if input current reversal is on or off. Always 0 if input is a diode. units (int, 1-4): Specifies preferred units parameter, and sets the units for alarm settings. 1 = Kelvin 2 = Celsius 3 = Sensor 4 = Fahrenheit enabled (int, 0 or 1): sets if channel is enabled name (str): sets name of channel """ if params is None: params = {} with self.lock.acquire_timeout(0, job='set_values') as acquired: if not acquired: self.log.warn("Could not start set_values because " "{} is already running".format(self.lock.job)) return False, "Could not acquire lock." if not self.fake_data: self.module.channels[params['channel'] - 1].set_values( sensor=params.get('sensor'), auto_range=params.get('auto_range'), range=params.get('range'), current_reversal=params.get('current_reversal'), unit=params.get('unit'), enabled=params.get('enabled'), name=params.get('name'), ) return True, 'Set values for channel {}'.format(params['channel']) def upload_cal_curve(self, session, params=None): """ Task to upload a calibration curve to a channel. Args: channel (int, 1 -- 2 or 8): Channel number filename (str): filename for cal curve """ channel = params['channel'] filename = params['filename'] with self.lock.acquire_timeout(0, job='upload_cal_curve') as acquired: if not acquired: self.log.warn("Could not start set_values because " "{} is already running".format(self.lock.job)) return False, "Could not acquire lock." if not self.fake_data: channel = self.module.channels[channel - 1] self.log.info( "Starting upload to channel {}...".format(channel)) channel.load_curve(filename) self.log.info("Finished uploading.") return True, "Uploaded curve to channel {}".format(channel) def start_acq(self, session, params=None): """ Task to start data acquisition. Args: sampling_frequency (float): Sampling frequency for data collection. Defaults to 2.5 Hz """ if params is None: params = {} f_sample = params.get('sampling_frequency', 2.5) sleep_time = 1 / f_sample - 0.01 with self.lock.acquire_timeout(0, job='acq') as acquired: if not acquired: self.log.warn( "Could not start acq because {} is already running".format( self.lock.job)) return False, "Could not acquire lock." session.set_status('running') self.take_data = True while self.take_data: data = { 'timestamp': time.time(), 'block_name': 'temps', 'data': {} } if self.fake_data: for therm in self.thermometers: data['data'][therm + ' T'] = random.randrange(250, 350) data['data'][therm + ' V'] = random.randrange(250, 350) time.sleep(.2) else: for i, therm in enumerate(self.thermometers): data['data'][ therm + ' T'] = self.module.channels[i].get_reading( unit='K') data['data'][ therm + ' V'] = self.module.channels[i].get_reading( unit='S') time.sleep(sleep_time) self.agent.publish_to_feed('temperatures', data) self.agent.feeds['temperatures'].flush_buffer() return True, 'Acquisition exited cleanly.' def stop_acq(self, session, params=None): """ Stops acq process. """ if self.take_data: self.take_data = False return True, 'requested to stop taking data.' else: return False, 'acq is not currently running'
class LS336_Agent: """Agent to connect to a single Lakeshore 336 device. Supports channels 'A','B','C', and 'D' for Lakeshore 336s that do not have the extra Lakeshore 3062 scanner installed. Also has channels 'D2','D3','D4', and 'D5' for 336s that have the extra scanner. Currently only supports heaters '1' and '2'. Parameters ---------- sn: str Serial number of the LS336 ip: str IP Address for the 336 device f_sample: float, optional (default 0.1) The frequency of sampling for acquiring data (in Hz) threshold: float, optional (default 0.1) The max difference (in K) between the setpoint and current temperature that will be considered stable window: int, optional (default 900) The amount of time (in s) over which the difference between the setpoint and the current temperature must not exceed threshold while checking for temperature stability. Attributes ---------- sn: str Serial number of the LS336 ip: str IP Address for the 336 device module: LS336 object Driver object module.channels: dict The available channels in the LS336 object module.heaters: dict The available heaters in the LS336 object f_sample: float The frequency of sampling for acquiring data (in Hz) t_sample: float The time between each sample (inverse of f_sample - 0.01) threshold: float The max difference (in K) between the setpoint and current temperature that will be considered stable window: int The amount of time (in s) over which the difference between the setpoint and the current temperature must not exceed threshold while checking for temperature stability. _recent_temps: numpy array, protected Array of recent temperatures for checking temperature stability _static_setpoint: float, protected The final setpoint value to avoid issues when the setpoint is ramping to a new value. Used in checking temperature stability """ def __init__(self, agent, sn, ip, f_sample=0.1, threshold=0.1, window=900): self.agent = agent self.sn = sn self.ip = ip self.f_sample = f_sample self.t_sample = 1/self.f_sample - 0.01 assert self.t_sample < 7200, \ "acq sampling freq must be such that t_sample is less than 2 hours" self._lock = TimeoutLock() self.log = agent.log self.initialized = False self.take_data = False self.module = None # for stability checking self.threshold = threshold self.window = window self._recent_temps = None self._static_setpoint = None agg_params = {'frame_length': 10*60} # sec # combined feed for thermometry and control data self.agent.register_feed( 'temperatures', record=True, agg_params=agg_params, buffer_time=1 ) @ocs_agent.param('auto_acquire', default=False, type=bool) def init_lakeshore(self, session, params=None): """init_lakeshore(auto_acquire=False) **Task** - Perform first time setup of the Lakeshore 336 communication Parameters: auto_acquire (bool, optional): Default is False. Starts data acquisition after initialization if True. """ if params is None: params = {} # test if this agent is already running if self.initialized: self.log.info('Lakeshore already initialized, returning...') return True, 'Already initialized' # initialize lakeshore with self._lock.acquire_timeout(job='init', timeout=0) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get lakeshore self.module = LS336(self.ip) session.add_message( f'Lakeshore initialized with ID: {self.module.id}') self.initialized = True # start data acq if passed if params.get('auto_acquire', False): self.agent.start('acq') return True, 'Lakeshore module initialized' @ocs_agent.param('f_sample', default=0.1, type=float) def acq(self, session, params=None): """acq(f_sample=0.1) **Process** - Begins recording data from thermometers and heaters. Parameters: f_sample (float, optional): Default is 0.1. Sets the sampling rate in Hz. Notes: The most recent data collected is stored in session.data in the structure: >>> response.session['data'] {"ls336_fields": {"timestamp": 1921920543, "block_name": "temperatures" "data": {"Channel_A_T": (some value) "Channel_A_V": (some value) "Channel_B_T": (some value) "Channel_B_V": (some value) "Channel_C_T": (some value) "Channel_C_V": (some value) "Channel_D_T": (some value) "Channel_D_V": (some value) } } } """ if params is None: params = {} # get sampling frequency f_sample = params.get('f_sample') if f_sample is None: t_sample = self.t_sample else: t_sample = 1/f_sample - 0.01 self.t_sample = t_sample # acquire lock and start Process with self._lock.acquire_timeout(job='acq', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # initialize recent temps array # shape is N_points x N_channels # N_points is 2 hour / t_sample rounded up # N_channels is 8 if the extra scanner is installed, 4 otherwise # t_sample can't be more than 2 hours N_channels = len(self.module.channels) self._recent_temps = np.full( (int(np.ceil(7200 / self.t_sample)), N_channels), -1.0) print(self._recent_temps.size) # acquire data from Lakeshore self.take_data = True while self.take_data: # get thermometry data current_time = time.time() temperatures_message = { 'timestamp': current_time, 'block_name': 'temperatures', 'data': {} } temps = self.module.get_kelvin('0') # array of 4 (or 8) floats voltages = self.module.get_sensor('0') # array of 4/8 floats for i, channel in enumerate(self.module.channels.values()): channel_str = channel.input_name.replace(' ', '_') temperatures_message['data'][channel_str + '_T'] = temps[i] temperatures_message['data'][channel_str + '_V'] = voltages[i] # append to recent temps array for temp stability check self._recent_temps = np.roll(self._recent_temps, 1, axis=0) self._recent_temps[0] = temps # publish to feed self.agent.publish_to_feed( 'temperatures', temperatures_message) # For session.data - named to avoid conflicting with LS372 # if in use at same time. session.data['ls336_fields'] = temperatures_message # get heater data heaters_message = { 'timestamp': current_time, 'block_name': 'heaters', 'data': {} } for i, heater in enumerate(self.module.heaters.values()): heater_str = heater.output_name.replace(' ', '_') heaters_message['data'][ heater_str + '_Percent'] = heater.get_heater_percent() heaters_message['data'][ heater_str + '_Range'] = heater.get_heater_range() heaters_message['data'][ heater_str + '_Max_Current'] = heater.get_max_current() heaters_message['data'][ heater_str + '_Setpoint'] = heater.get_setpoint() # publish to feed self.agent.publish_to_feed('temperatures', heaters_message) # finish sample self.log.debug( f'Sleeping for {np.round(self.t_sample)} seconds...') # release and reacquire lock between data acquisition self._lock.release() time.sleep(t_sample) if not self._lock.acquire(timeout=10, job='acq'): print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not re-acquire lock' return True, 'Acquisition exited cleanly' @ocs_agent.param('_') def stop_acq(self, session, params=None): """stop_acq() **Task** - Stops acq process. """ if params is None: params = {} if self.take_data: self.take_data = False return True, 'Requested to stop taking data' else: return False, 'acq is not currently running' @ocs_agent.param('range', type=str, choices=['off', 'low', 'medium', 'high']) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def set_heater_range(self, session, params): """set_heater_range(range=None,heater='2') **Task** - Adjusts the heater range for servoing the load. Parameters: range (str): Sets the range of the chosen heater. Must be one of 'off', 'low', 'medium', and 'high'. heater (str, optional): default '2'. Chooses which heater's range to change. Must be '1' or '2'. Notes: The range setting has no effect if an output is in the Off mode, and it does not apply to an output in Monitor Out mode. An output in Monitor Out mode is always on. """ with self._lock.acquire_timeout(job='set_heater_range', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # set range current_range = heater.get_heater_range() if params['range'] == current_range: print( 'Current heater range matches commanded value. ' 'Proceeding unchanged') else: heater.set_heater_range(params['range']) session.add_message( f"Set {heater.output_name} range to {params['range']}") return True, f"Set {heater.output_name} range to {params['range']}" @ocs_agent.param('P', type=float, check=lambda x: 0.1 <= x <= 1000) @ocs_agent.param('I', type=float, check=lambda x: 0.1 <= x <= 1000) @ocs_agent.param('D', type=float, check=lambda x: 0 <= x <= 200) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def set_pid(self, session, params): """set_pid(P=None,I=None,D=None,heater='2') **Task** - Set the PID parameters for servoing the load. Parameters: P (float): Proportional term for PID loop (must be between 0.1 and 1000) I (float): Integral term for PID loop (must be between 0.1 and 1000) D (float): Derivative term for PID loop (must be between 0 and 200) heater (str, optional): Selects the heater on which to change the PID settings. Must be '1' or '2'. """ with self._lock.acquire_timeout(job='set_pid', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # set pid current_p, current_i, current_d = heater.get_pid() if (params['P'] == current_p and params['I'] == current_i and params['D'] == current_d): print('Current heater PID matches commanded value. ' 'Proceeding unchanged') else: heater.set_pid(params['P'], params['I'], params['D']) session.add_message( f"Set {heater.output_name} PID to {params['P']}, " f"{params['I']}, {params['D']}") return True, (f"Set {heater.output_name} PID to {params['P']}, " f" {params['I']}, {params['D']}") @ocs_agent.param('mode', type=str, choices=['off', 'closed loop', 'zone', 'open loop']) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def set_mode(self, session, params): """set_mode(mode=None,heater='2') **Task** - Sets the output mode of the heater. Parameters: mode (str): Selects the output mode for the heater. Accepts four options: 'off', 'closed loop', 'zone', and 'open loop'. for restrictions based on the selected heater. heater (str, optional): Default '2'. Selects the heater on which to change the mode. Must be '1' or '2'. Notes: Does not support the options 'monitor out' and 'warm up', which only work for the unsupported analog outputs (heaters 3 and 4). """ with self._lock.acquire_timeout(job='set_mode', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # set mode current_mode = heater.get_mode() if params['mode'] == current_mode: print( 'Current heater mode matches commanded value. ' 'Proceeding unchanged') else: heater.set_mode(params['mode']) session.add_message( f"Set {heater.output_name} mode to {params['mode']}") return True, f"Set {heater.output_name} mode to {params['mode']}" @ocs_agent.param('resistance', type=float) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def set_heater_resistance(self, session, params): """set_heater_resistance(resistance=None,heater='2') **Task** - Sets the heater resistance and resistance setting of the heater. The associated 'get' function in the Heater class is get_heater_resistance_setting(). Parameters: resistance (float): The actual resistance of the load heater (str, optional): Default '2'. Selects the heater on which to set the resistance. Must be '1' or '2'. """ with self._lock.acquire_timeout(job='set_heater_resistance', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # set heater resistance _ = heater.get_heater_resistance_setting() if params['resistance'] == heater.resistance: print( 'Current heater resistance matches commanded value. ' 'Proceeding unchanged') else: heater.set_heater_resistance(params['resistance']) session.add_message( f"Set {heater.output_name} resistance to " f"{params['resistance']}") return True, (f"Set {heater.output_name} resistance to " f"{params['resistance']}") @ocs_agent.param('current', type=float, check=lambda x: 0.0 <= x <= 2.0) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def set_max_current(self, session, params): """set_max_current(current=None,heater='2') **Task** - Sets the maximum current that can pass through a heater. Parameters: current (float): The desired max current. Must be between 0 and 2 A. heater (str, optional): Default '2'. Selects the heater on which to set the max current. Must be '1' or '2'. """ with self._lock.acquire_timeout(job='set_max_current', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # set max current current_max_current = heater.get_max_current() if params['current'] == current_max_current: print( 'Current max current matches commanded value. ' 'Proceeding unchanged') else: heater.set_max_current(params['current']) session.add_message( f"Set {heater.output_name} max current to {params['current']}") return True, (f"Set {heater.output_name} max current to " f"{params['current']}") @ocs_agent.param('percent', type=float) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def set_manual_out(self, session, params): """set_manual_out(percent=None,heater='2') **Task** - Sets the manual output of the heater as a percentage of the full current or power depending on which display the heater is set to use. Parameters: percent (float): Percent of full current or power to set on the heater. Must have 2 or fewer decimal places. heater (str, optional): Default '2'. Selects the heater on which to set the manual output. Must be '1' or '2'. """ with self._lock.acquire_timeout(job='set_manual_out', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # set manual out current_manual_out = heater.get_manual_out() if params['percent'] == current_manual_out: print('Current manual out matches commanded value. ' 'Proceeding unchanged') else: heater.set_manual_out(params['percent']) session.add_message( f"Set {heater.output_name} manual out to {params['percent']}") return True, (f"Set {heater.output_name} manual out to " f"{params['percent']}") @ocs_agent.param('input', type=str, choices=['A', 'B', 'C', 'D', 'D1', 'D2', 'D3', 'D4', 'D5']) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def set_input_channel(self, session, params): """set_input_channel(input=None,heater='2') **Task** - Sets the input channel of the heater control loop. Parameters: input (str): The name of the heater to use as the input channel. Must be one of 'none','A','B','C', or 'D'. Can also be 'D2','D3','D4', or 'D5' if the extra Lakeshore 3062 Scanner is installed in your LS336. heater (str, optional): Default '2'. Selects the heater for which to set the input channel. Must be '1' or '2'. """ with self._lock.acquire_timeout(job='set_input_channel', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # D1 is the same as D if params['input'] == 'D1': params['input'] = 'D' # set input channel current_input_channel = heater.get_input_channel() if params['input'] == current_input_channel: print( 'Current input channel matches commanded value. ' 'Proceeding unchanged') else: heater.set_input_channel(params['input']) session.add_message( f"Set {heater.output_name} input channel to {params['input']}") return True, (f"Set {heater.output_name} input channel to " f"{params['input']}") @ocs_agent.param('setpoint', type=float) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def set_setpoint(self, session, params): """set_setpoint(setpoint=None,heater='2') **Task** - Sets the setpoint of the heater control loop, after first turning ramp off. May be a limit to how high the setpoint can go based on your system parameters. Parameters: setpoint (float): The setpoint for the control loop. Units depend on the preferred sensor units (Kelvin, Celsius, or Sensor). heater (str, optional): Default '2'. Selects the heater for which to set the input channel. Must be '1' or '2'. """ with self._lock.acquire_timeout(job='set_setpoint', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # set setpoint current_setpoint = heater.get_setpoint() if params['setpoint'] == current_setpoint: print('Current setpoint matches commanded value. ' 'Proceeding unchanged') else: heater.set_ramp_on_off('off') heater.set_setpoint(params['setpoint']) # static setpoint used in temp stability check # to avoid ramping bug self._static_setpoint = params['setpoint'] session.add_message( f"Turned ramp off and set {heater.output_name} setpoint to " f"{params['setpoint']}") return True, (f"Turned ramp off and set {heater.output_name} " f"setpoint to {params['setpoint']}") @ocs_agent.param('T_limit', type=int) @ocs_agent.param('channel', type=str, default='A', choices=['A', 'B', 'C', 'D', 'D2', 'D3', 'D4', 'D5']) def set_T_limit(self, session, params): """set_T_limit(T_limit=None,channel='A') **Task** - Sets the temperature limit above which the control output assigned to the selected channel shut off. Parameters: T_limit (int): The temperature limit in Kelvin. Note that a limit of 0 K turns off this feature for the given channel. channel (str, optional): Default 'A'. Selects which channel to use for controlling the temperature. Options are 'A','B','C', and 'D'. Can also be 'D2','D3','D4', or 'D5' if the extra Lakeshore 3062 Scanner is installed in your LS336. """ with self._lock.acquire_timeout(job='set_T_limit', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get channel channel_key = params.get('channel', 'A') # default to input A channel = self.module.channels[channel_key] # set T limit current_limit = channel.get_T_limit() if params['T_limit'] == current_limit: print('Current T limit matches commanded value. ' 'Proceeding unchanged') else: channel.set_T_limit(params['T_limit']) session.add_message( f"Set {channel.input_name} T limit to {params['T_limit']}") return True, f"Set {channel.input_name} T limit to {params['T_limit']}" @ocs_agent.param('temperature', type=float) @ocs_agent.param('ramp', default=0.1, type=float) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) @ocs_agent.param('transport', default=False, type=bool) @ocs_agent.param('transport_offset', default=0, type=float, check=lambda x: x >= 0.0) def servo_to_temperature(self, session, params): """servo_to_temperature(temperature=None,ramp=0.1,heater='2',\ transport=False,transport_offset=0) **Task** - A wrapper for setting the heater setpoint. Performs sanity checks on heater configuration before publishing setpoint: 1. checks control mode of heater (closed loop) 2. checks units of input channel (kelvin) 3. resets setpoint to current temperature with ramp off 4. sets ramp on to specified rate 5. checks setpoint does not exceed input channel T_limit 6. sets setpoint to commanded value Note that this function does NOT turn on the heater if it is off. You must use set_heater_range() to pick a range first. Parameters: temperature (float): The new setpoint in Kelvin. Make sure there is is a control input set to the heater and its units are Kelvin. ramp (float, optional): Default 0.1. The rate for how quickly the setpoint ramps to new value. Units of K/min. heater (str, optional): Default '2'. The heater to use for servoing. Must be '1' or '2'. transport (bool, optional): Default False. See Notes for description. transport_offset (float, optional): Default 0. In Kelvin. See Notes. Notes: If param 'transport' is provided and True, the control loop restarts when the setpoint is first reached. This is useful for loads with long cooling times or time constant to help minimize over/undershoot. If param 'transport' is provided and True, and 'transport_offset' is provided and positive, and the setpoint is higher than the current temperature, then the control loop will restart when the setpoint - transport_offset is first reached. This is useful to avoid a "false positive" temperature stability check too shortly after transport completes. """ # get sampling frequency t_sample = self.t_sample with self._lock.acquire_timeout(job='servo_to_temperature', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # get current setpoint current_setpoint = heater.get_setpoint() # check in correct control mode if heater.get_mode() != 'closed loop': session.add_message( 'Changing control to closed loop mode for servo.') heater.set_mode("closed loop") # check in correct units channel = heater.get_input_channel() if channel == 'none': return False, (f'{heater.output_name} does not have an ' f'input channel assigned') if self.module.channels[channel].get_units() != 'kelvin': session.add_message( 'Setting preferred units to kelvin on ' 'heater control input.') self.module.channels[channel].set_units('kelvin') # restart setpoint at current temperature current_temp = np.round(float(self.module.get_kelvin(channel)), 4) session.add_message( f'Turning ramp off and setting setpoint to current ' f'temperature {current_temp}') heater.set_ramp_on_off('off') heater.set_setpoint(current_temp) # reset ramp settings ramp = params.get('ramp', 0.1) session.add_message( f'Turning ramp on and setting rate to {ramp}K/min') heater.set_ramp_on_off('on') heater.set_ramp_rate(ramp) # make sure not exceeding channel T limit T_limit = self.module.channels[channel].get_T_limit() if T_limit <= params['temperature']: return False, (f"{heater.output_name} control channel " f"{channel} T limit of {T_limit}K is lower " f"than setpoint of {params['temperature']}") # set setpoint if params['temperature'] == current_setpoint: print('Current setpoint matches commanded value. ' 'Proceeding unchanged') else: session.add_message( f"Setting {heater.output_name} setpoint to " f"{params['temperature']}") heater.set_setpoint(params['temperature']) # static setpoint used in temp stability check # to avoid pulling the ramping setpoint self._static_setpoint = params['temperature'] # if transport, restart control loop when setpoint # first crossed if params.get('transport', False): current_range = heater.get_heater_range() starting_sign = np.sign( params['temperature'] - current_temp) transporting = True # if we are raising temp, allow possibility of # stopping transport at a cooler temp T_offset = 0 if starting_sign > 0: T_offset = params.get('transport_offset', 0) if T_offset < 0: return False, ('Transport offset temperature ' 'cannot be negative') while transporting: current_temp = np.round( self.module.get_kelvin(channel), 4) # check when this flips current_sign = np.sign( params['temperature'] - T_offset - current_temp) # release and reacquire lock between data acquisition self._lock.release() time.sleep(t_sample) if not self._lock.acquire(timeout=10, job='servo_to_temperature'): print( f"Lock could not be acquired because it is " f"held by {self._lock.job}") return False, 'Could not re-acquire lock' if current_sign != starting_sign: transporting = False # update flag # cycle control loop session.add_message( 'Transport complete, restarting control ' 'loop at provided setpoint') heater.set_heater_range('off') # necessary 1 s for prev command to register # in ls336 firmware for some reason time.sleep(1) heater.set_heater_range(current_range) return True, (f"Set {heater.output_name} setpoint to " f"{params['temperature']}") @ocs_agent.param('threshold', default=0.1, type=float) @ocs_agent.param('window', default=900, type=int) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def check_temperature_stability(self, session, params): """check_temperature_stability(threshold=0.1,window=900,heater='2') **Task** - Assesses whether the load is stable around the setpoint to within some threshold. Parameters: threshold (float, optional): Default 0.1. See notes. window (int, optional): Default 900. See notes. heater (str, optional): Default '2'. Selects the heater for which to set the input channel. Must be '1' or '2'. Notes ----- Param 'threshold' sets the upper bound on the absolute temperature difference between the setpoint and any temperature from the input channel in the last 'window' seconds. Param 'window' sets the lookback time into the most recent temperature data, in seconds. Note that this function grabs the most recent data in one window-length of time; it does not take new data. If you want to use the result of this task for making logical decisions in a client (e.g. waiting longer before starting a process if the temperature is not yet stable), use the session['success'] key. It will be True if the temperature is stable and False if not. Example: >>> response = ls336.check_temperature_stability() >>> response.session['success'] True """ # get threshold threshold = params.get('threshold') if threshold is None: threshold = self.threshold # get window window = params.get('window') if window is None: window = self.window num_idxs = int(np.ceil(window / self.t_sample)) with self._lock.acquire_timeout(job='check_temperature_stability', timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # get channel channel = heater.get_input_channel() channel_num = self.module.channels[channel].num # get current temp current_temp = np.round(self.module.get_kelvin(channel), 4) # check if recent temps and current temps are within threshold _recent_temps = self._recent_temps[:num_idxs, channel_num-1] _recent_temps = np.concatenate( (np.array([current_temp]), _recent_temps)) # get static setpoint if None if self._static_setpoint is None: self._static_setpoint = heater.get_setpoint() # avoids checking against the ramping setpoint, # i.e. want to compare to commanded setpoint not mid-ramp setpoint setpoint = self._static_setpoint session.add_message( f'Maximum absolute difference in recent temps is ' f'{np.max(np.abs(_recent_temps - setpoint))}K') if np.all(np.abs(_recent_temps - setpoint) < threshold): session.add_message( f'Recent temps are within {threshold}K of setpoint') return True, (f'Servo temperature is stable within ' f'{threshold}K of setpoint') return False, (f'Servo temperature is not stable within ' f'{threshold}K of setpoint') @ocs_agent.param('attribute', type=str) @ocs_agent.param('channel', type=str, default='A', choices=['A', 'B', 'C', 'D', 'D1', 'D2', 'D3', 'D4', 'D5']) def get_channel_attribute(self, session, params): """get_channel_attribute(attribute=None,channel='A') **Task** - Gets an arbitrary channel attribute and stores it in the session.data dict. Attribute must be the name of a method in the namespace of the Lakeshore336 Channel class, with a leading "get\_" removed (see example). Parameters: attribute (str): The name of the channel attribute to get. See the Lakeshore 336 Channel class API for all options. channel (str, optional): Default 'A'. Selects which channel for which to get the attribute. Options are 'A','B','C', and 'D'. Can also be 'D2','D3','D4', or 'D5' if the extra Lakeshore 3062 Scanner is installed in your LS336. Example: >>> ls.get_channel_attribute(attribute = 'T_limit').session['data'] {'T_limit': 30.0} """ with self._lock.acquire_timeout(job=f"get_{params['attribute']}", timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get channel channel_key = params.get('channel', 'A') # default to input A channel = self.module.channels[channel_key] # check that attribute is a valid channel method if getattr(channel, f"get_{params['attribute']}", False) is not False: query = getattr(channel, f"get_{params['attribute']}") # get attribute resp = query() session.data[params['attribute']] = resp return True, (f"Retrieved {channel.input_name} {params['attribute']}, value is {resp}") @ocs_agent.param('attribute', type=str) @ocs_agent.param('heater', default='2', type=str, choices=['1', '2']) def get_heater_attribute(self, session, params): """get_heater_attribute(attribute=None,heater='2') **Task** - Gets an arbitrary heater attribute and stores it in the session.data dict. Attribute must be the name of a method in the namespace of the Lakeshore336 Heater class, with a leading "get\_" removed (see example). Parameters: attribute (str): The name of the channel attribute to get. See the Lakeshore 336 Heater class API for all options. heater (str, optional): Default '2'. Selects the heater for which to get the heater attribute. Must be '1' or '2'. Examples -------- >>> ls.get_heater_attribute(attribute = 'heater_range').session['data'] {'heater_range': 'off'} """ with self._lock.acquire_timeout(job=f"get_{params['attribute']}", timeout=3) as acquired: if not acquired: print( f"Lock could not be acquired because it is held by " f"{self._lock.job}") return False, 'Could not acquire lock' session.set_status('running') # get heater heater_key = params.get('heater', '2') # default to 50W output heater = self.module.heaters[heater_key] # check that attribute is a valid heater method if getattr(heater, f"get_{params['attribute']}", False) is not False: query = getattr(heater, f"get_{params['attribute']}") # get attribute resp = query() session.data[params['attribute']] = resp return True, f"Retrieved {heater.output_name} {params['attribute']}, value is {resp}"
class Keithley2230GAgent: def __init__(self, agent, ip_address, gpib_slot): self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.job = None self.ip_address = ip_address self.gpib_slot = gpib_slot self.monitor = False self.psu = None # Registers Temperature and Voltage feeds agg_params = { 'frame_length': 10 * 60, } self.agent.register_feed('psu_output', record=True, agg_params=agg_params, buffer_time=0) def init_psu(self, session, params=None): """ Task to connect to Keithley power supply """ with self.lock.acquire_timeout(0) as acquired: if not acquired: return False, "Could not acquire lock" try: self.psu = psuInterface(self.ip_address, self.gpib_slot) self.idn = self.psu.identify() except socket.timeout as e: self.log.error("PSU timed out during connect") return False, "Timeout" self.log.info("Connected to psu: {}".format(self.idn)) return True, 'Initialized PSU.' def monitor_output(self, session, params=None): """ Process to continuously monitor PSU output current and voltage and send info to aggregator. Args: wait (float, optional): time to wait between measurements [seconds]. """ if params is None: params = {} wait_time = params.get('wait', 1) self.monitor = True while self.monitor: with self.lock.acquire_timeout(1) as acquired: if acquired: data = { 'timestamp': time.time(), 'block_name': 'output', 'data': {} } for chan in [1, 2, 3]: data['data']["Voltage_{}".format( chan)] = self.psu.getVolt(chan) data['data']["Current_{}".format( chan)] = self.psu.getCurr(chan) # self.log.info(str(data)) # print(data) self.agent.publish_to_feed('psu_output', data) else: self.log.warn("Could not acquire in monitor_current") time.sleep(wait_time) return True, "Finished monitoring current" def stop_monitoring(self, session, params=None): self.monitor = False return True, "Stopping current monitor" def set_voltage(self, session, params=None): """ Sets voltage of power supply: Args: channel (int): Channel number (1, 2, or 3) volts (float): Voltage to set. Must be between 0 and 30. """ with self.lock.acquire_timeout(1) as acquired: if acquired: self.psu.setVolt(params['channel'], params['volts']) else: return False, "Could not acquire lock" return True, 'Set channel {} voltage to {}'.format( params['channel'], params['volts']) def set_current(self, session, params=None): """ Sets current of power supply: Args: channel (int): Channel number (1, 2, or 3) "current" (float): Curent to set. Must be between x and y. """ with self.lock.acquire_timeout(1) as acquired: if acquired: self.psu.setCurr(params['channel'], params['current']) else: return False, "Could not acquire lock" return True, 'Set channel {} current to {}'.format( params['channel'], params['current']) def set_output(self, session, params=None): """ Task to turn channel on or off. Args: channel (int): Channel number (1, 2, or 3) state (bool): True for on, False for off """ with self.lock.acquire_timeout(1) as acquired: if acquired: self.psu.setOutput(params['channel'], params['state']) else: return False, "Could not acquire lock" return True, 'Initialized PSU.'
class PfeifferAgent: def __init__(self, agent, ip_address, port, f_sample=2.5): self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.f_sample = f_sample self.take_data = False self.gauge = Pfeiffer(ip_address, int(port)) agg_params = { 'frame_length': 60, } self.agent.register_feed('pressures', record=True, agg_params=agg_params, buffer_time=1) def start_acq(self, session, params=None): """ Get pressures from the Pfeiffer gauges, publishes them to the feed Args: sampling_frequency- defaults to 2.5 Hz """ if params is None: params = {} f_sample = params.get('sampling_frequency') if f_sample is None: f_sample = self.f_sample sleep_time = 1. / f_sample - 0.01 with self.lock.acquire_timeout(timeout=0, job='init') as acquired: # Locking mechanism stops code from proceeding if no lock acquired if not acquired: self.log.warn( "Could not start init because {} is already running". format(self.lock.job)) return False, "Could not acquire lock." session.set_status('running') self.take_data = True while self.take_data: data = { 'timestamp': time.time(), 'block_name': 'pressures', 'data': {} } pressure_array = self.gauge.read_pressure_all() # Loop through all the channels on the device for channel in range(len(pressure_array)): data['data']["pressure_ch" + str(channel + 1)] = pressure_array[channel] self.agent.publish_to_feed('pressures', data) time.sleep(sleep_time) self.agents.feeds['pressures'].flush_buffer() return True, 'Acquistion exited cleanly' def stop_acq(self, session, params=None): """ End pressure data acquisition """ if self.take_data: self.take_data = False self.gauge.close() return True, 'requested to stop taking data.' else: return False, 'acq is not currently running'
class HWPSimulatorAgent: def __init__(self, agent, port='/dev/ttyACM0'): self.active = True self.agent = agent self.log = agent.log self.lock = TimeoutLock() self.port = port self.take_data = False self.arduino = HWPSimulator(port=self.port) self.initialized = False agg_params = {'frame_length': 60} self.agent.register_feed('amplitudes', record=True, agg_params=agg_params, buffer_time=1) def init_arduino(self): """ Initializes the Arduino connection. """ if self.initialized: return True, "Already initialized." with self.lock.acquire_timeout(timeout=0, job='init') as acquired: if not acquired: self.log.warn( "Could not start init because {} is already running". format(self.lock.job)) return False, "Could not acquire lock." try: self.arduino.read() except ValueError: pass print("Arduino HWP Simulator initialized.") self.initialized = True return True, 'Arduino HWP Simulator initialized.' def start_acq(self, session, params): """Starts acquiring data. Args: sampling_frequency (float): Sampling frequency for data collection. Defaults to 2.5 Hz """ f_sample = params.get('sampling_frequency', 2.5) sleep_time = 1 / f_sample - 0.1 if not self.initialized: self.init_arduino() with self.lock.acquire_timeout(timeout=0, job='acq') as acquired: if not acquired: self.log.warn( "Could not start acq because {} is already running".format( self.lock.job)) return False, "Could not acquire lock." session.set_status('running') self.take_data = True while self.take_data: data = { 'timestamp': time.time(), 'block_name': 'amps', 'data': {} } data['data']['amplitude'] = self.arduino.read() time.sleep(sleep_time) self.agent.publish_to_feed('amplitudes', data) self.agent.feeds['amplitudes'].flush_buffer() return True, 'Acquisition exited cleanly.' def stop_acq(self, session, params=None): """ Stops the data acquisiton. """ if self.take_data: self.take_data = False return True, 'requested to stop taking data.' else: return False, 'acq is not currently running.'