MBLogic for an open world in automation
This section describes the "generic client framework". This is a library which is used to help create custom generic clients. The generic client framework handles communications between the generic client and the main system. It also operates the "scan" cycle which calls the user protocol code on a regular schedule.
Generic clients are experimental at this stage, and the interface is subject to change. If you intend to make use of this feature at this stage in its development, be prepared to make minor modifications to your custom generic clients in future versions.
The generic framework library is located in a file called "GenClientLib.py". This file contains the following classes:
GenClientController handles communications with the generic interface server, and scheduling of the user protocol code scan.
# Initialise the generic client handler. gencontrol = GenClientLib.GenClientController(port, clientname, UserClient)
The initialisation parameters are:
StatCodes formats command status messages. It expects the following parameters:
It returns a tuple containing a command status message in the format expected by the status reporting system on the server.
GetOptions reads and analyses the command line parameters which are set by the system when it starts a client. These parameters are:
The class contains one method ("GetStartParams") which returns the port, client name, and delay.
# Get the command line parameter options. CmdOpts = GenClientLib.GetOptions() port, clientname, startdelay = CmdOpts.GetStartParams()
"GetStartParams" is a convenience class and is not an essential part of the generic client framework. Alternate implementations may be used if a generic client requires more command line parameters.
The generic client framework expects a class which implements the actual client communications. This class must include the following methods:
Writing user protocol classes is discussed in another section.
If you wish to be able to shut down the user client gracefully using a keyboard interrupt, you will need to include signal handlers.
# Signal handler. def SigHandler(signum, frame): print('\nOperator terminated generic client %s at %s' % (clientname, time.ctime())) gencontrol.StopClient() def SigTermHandler(signum, frame): print('\Received terminate signal for generic client %s at %s' % (clientname, time.ctime())) gencontrol.StopClient() # Initialise the signal handler. signal.signal(signal.SIGINT, SigHandler) signal.signal(signal.SIGTERM, SigTermHandler)
The following shows a simple example with the actual protocol implementation left out.
#!/usr/bin/python """ This file should contain the user routines used to help implement the protocol specific generic client functions. """ # These are some example imports, which may not be required in another implementation. import time import urllib2 import signal import json # This import handles the generic client framework. import GenClientLib ############################################################ class UserClient: """ """ ######################################################## def __init__(self): """The initialisation code goes here. """ # This formats the command status messages self._StatusMsgs = GenClientLib.StatCodes() ######################################################## def GetClientMsgs(self): """Return the list of client messages. """ return self._ClientMsgs ######################################################## def GetStatus(self): """Return the current status. """ return self._ConnectStatus, cmdstat ######################################################## def SetParams(self, hostconfig, clientconfig, cmdlist): """Accept the configuration parameters and validate them. """ # Do soemthing with these parameters ... pass ######################################################## def NextCommand(self, readtable, servercmd): """This should execute the next command, whatever it is. This is called regularly by GenClient. """ data = {} # First check if we've got a good parameter set. if self._ConfigOK: # Various details go here... # Set the connection status. self._ConnectStatus = 'running' nextpoll = 0.3 else: # Set the connection status. self._ConnectStatus = 'stopped' nextpoll = 1.0 return data, nextpoll ############################################################ ############################################################ # Signal handler. def SigHandler(signum, frame): print('\nOperator terminated generic client %s at %s' % (clientname, time.ctime())) gencontrol.StopClient() def SigTermHandler(signum, frame): print('\Received terminate signal for generic client %s at %s' % (clientname, time.ctime())) gencontrol.StopClient() # Initialise the signal handler. signal.signal(signal.SIGINT, SigHandler) signal.signal(signal.SIGTERM, SigTermHandler) ############################################################ # Get the command line parameter options. CmdOpts = GenClientLib.GetOptions() port, clientname, startdelay = CmdOpts.GetStartParams() # Initialise the generic client handler. gencontrol = GenClientLib.GenClientController(port, clientname, UserClient) print('\n\nStarting generic client %s at %s' % (clientname, time.ctime())) # Delay the specified number of seconds. This will allow the main # program to start up before trying to contact it. time.sleep(startdelay) # Start the generic client. gencontrol.StartClient() # This doesn't get executed until the client halts. print('\n\nGeneric client %s halted at %s' % (clientname, time.ctime()))