Adding a Process
So far we have an Agent with a single Task. Tasks are meant to be short operations that end in finite time. Often we want to collect data from a housekeeping device indefinitely, for that we use a Process. We will add a Process to the Barebones Agent that simply counts up from zero. To do so we add two more class methods:
def count(self, session, params):
"""count()
**Process** - Count up from 0.
The count will restart if the process is stopped and restarted.
Notes:
The most recent value is stored in the session data object in the
format::
>>> response.session['data']
{"value": 0,
"timestamp": 1600448753.9288929}
"""
# Initialize the counter
self._count=True
counter = 0
print("Starting the count!")
# Main process loop
while self._count:
counter += 1
print(f"{counter}! Ah! Ah! Ah!")
session.data = {"value": counter,
"timestamp": time.time()}
time.sleep(1)
return True, 'Acquisition exited cleanly.'
def _stop_count(self, session, params):
"""Stop monitoring the turbo output."""
if self._count:
self._count = False
return True, 'requested to stop taking data.'
else:
return False, 'count is not currently running'
Additionally, we have to register the Process, like we did with the Task:
agent.register_process(
'count',
barebone.count,
barebone._stop_count)
The ‘count’ Process looks much like a Task, however it contains a while loop
(with self._count
initialized to False in the class’ __init__()
method.)
The Process loop will continue to run until stopped via a .stop()
call.
When registering the Process we must provide a name, the main method for running the Process, as well as a stop method. Since the stop method is separate, but to an OCS Client it is apart of the Process as a whole we mark the stop method as private with a leading underscore, this prevents it from showing the Agent API, which Client developers will use when writing control programs that interact with the Agent.
Agent Code
Our Agent in full now looks like this:
import time
from ocs import ocs_agent, site_config
class BarebonesAgent:
"""Barebone Agent demonstrating writing an Agent from scratch.
This Agent is meant to be an example for Agent development, and provides a
clean starting point when developing a new Agent.
Parameters:
agent (OCSAgent): OCSAgent object from :func:`ocs.ocs_agent.init_site_agent`.
Attributes:
agent (OCSAgent): OCSAgent object from :func:`ocs.ocs_agent.init_site_agent`.
_count (bool): Internal tracking of whether the Agent should be
counting or not. This is used to exit the Process loop by changing
it to False via the count.stop() command. Your Agent won't use this
exact attribute, but might have a similar one.
"""
def __init__(self, agent):
self.agent = agent
self._count = False
def count(self, session, params):
"""count()
**Process** - Count up from 0.
The count will restart if the process is stopped and restarted.
Notes:
The most recent value is stored in the session data object in the
format::
>>> response.session['data']
{"value": 0,
"timestamp": 1600448753.9288929}
"""
# Initialize the counter
self._count=True
counter = 0
print("Starting the count!")
# Main process loop
while self._count:
counter += 1
print(f"{counter}! Ah! Ah! Ah!")
session.data = {"value": counter,
"timestamp": time.time()}
time.sleep(1)
return True, 'Acquisition exited cleanly.'
def _stop_count(self, session, params):
"""Stop monitoring the turbo output."""
if self._count:
self._count = False
return True, 'requested to stop taking data.'
else:
return False, 'count is not currently running'
@ocs_agent.param('text', default='hello world', type=str)
def print(self, session, params):
"""print(text='hello world')
**Task** - Print some text passed to a Task.
Args:
text (str): Text to print out. Defaults to 'hello world'.
Notes:
The session data will be updated with the text::
>>> response.session['data']
{'text': 'hello world',
'last_updated': 1660249321.8729222}
"""
# Print the text provided to the Agent logs
print(f"{params['text']}")
# Store the text provided in session.data
session.data = {'text': params['text'],
'last_updated': time.time()}
# bool, 'descriptive text message'
# True if task succeeds, False if not
return True, 'Printed text to logs'
def main(args=None):
args = site_config.parse_args(agent_class='BarebonesAgent', args=args)
agent, runner = ocs_agent.init_site_agent(args)
barebone = BarebonesAgent(agent)
agent.register_process(
'count',
barebone.count,
barebone._stop_count)
agent.register_task('print', barebone.print)
runner.run(agent, auto_reconnect=True)
if __name__ == '__main__':
main()
Running the Agent
Run the Agent like we did previously, then we can use a Client to start the count Process:
>>> from ocs.ocs_client import OCSClient
>>> client = OCSClient('barebones1')
>>> client.count.start()
OCSReply: OK : Started process "count".
count[session=0]; status=starting for 0.008996 s
messages (1 of 1):
1658512144.473 Status is now "starting".
other keys in .session: op_code, data
>>> client.count.status()
OCSReply: OK : Session active.
count[session=0]; status=running for 7.5 s
messages (2 of 2):
1658512144.473 Status is now "starting".
1658512144.476 Status is now "running".
other keys in .session: op_code, data
>>> client.count.status().session['data']
{'value': 13, 'timestamp': 1658512156.49813}
>>> client.count.stop()
OCSReply: OK : Requested stop on process "count".
count[session=0]; status=running for 22.4 s
messages (2 of 2):
1658512144.473 Status is now "starting".
1658512144.476 Status is now "running".
other keys in .session: op_code, data
In the Agent logs you should see (truncating several counts):
2022-07-22T13:49:04-0400 start called for count
2022-07-22T13:49:04-0400 count:0 Status is now "starting".
2022-07-22T13:49:04-0400 count:0 Status is now "running".
2022-07-22T13:49:04-0400 Starting the count!
2022-07-22T13:49:04-0400 1! Ah! Ah! Ah!
2022-07-22T13:49:05-0400 2! Ah! Ah! Ah!
2022-07-22T13:49:06-0400 3! Ah! Ah! Ah!
2022-07-22T13:49:07-0400 4! Ah! Ah! Ah!
2022-07-22T13:49:08-0400 5! Ah! Ah! Ah!
2022-07-22T13:49:09-0400 6! Ah! Ah! Ah!
2022-07-22T13:49:27-0400 count:0 Acquisition exited cleanly.
2022-07-22T13:49:27-0400 count:0 Status is now "done".
Next, we will replace the print statements here with use of the OCS logger.