IPyDriver¶
Typically you would create a subclass of IPyDriver.
The driver has methods which can be overwritten.
async def rxevent(self, event)
This is called whenever data is received from the client, typically to set an instrument parameter. The event object describes the received data, and you provide the code which then controls your instrument, event objects are described at RxEvents.
async def hardware(self)
This could be a contuously running coroutine which you can use to operate your instruments, and if required send updates to the client.
async def snoopevent(self, event)
This is used if the device is monitoring the data sent by other devices, these event objects are described at SnoopEvents.
IPyDriver is a mapping of devicename:deviceobject, so your code in these methods could access a specific device using self[‘devicename’].
As well as the methods documented below, dict methods are available such as get() and iteration through keys(), values() and items().
Similarly a Device object is a mapping to a vector, so to access a vector you could use self[‘devicename’][‘vectorname’].
- class IPyDriver(*devices, **driverdata)¶
A subclass of this should be created with methods written to control your device.
devices are Device objects this driver handles.
You may optionally include named arguments of any instrumentation objects that may be useful to you, these will be available in the dictionary self.driverdata.
This object is also a mapping, of devicename:deviceobject
- async asyncrun()¶
await this to operate the driver, which will then communicate by stdin and stdout.
Do not await this if the driver is being set into IPyServer, in that situation the IPyServer will control communications.
- devices()¶
Returns a list of device objects
- async hardware()¶
Override this to operate device hardware, and transmit updates
For example: call your own code to operate hardware then update the appropriate vectors, and send updated values to the client using await vector.send_setVector()
- static indi_number_to_float(value)¶
The INDI spec allows a number of different number formats, given any number string, this returns a float. If an error occurs while parsing the number, a TypeError exception is raised.
- async rxevent(event)¶
Override this. On receiving data, this is called, and should handle any necessary actions. event is an object describing the event, with attributes devicename, vectorname, vector, root where vector is the properties vector the event refers to, and root is an xml.etree.ElementTree object of the received xml
- async rxgetproperties(event)¶
This is an internal method called whenever a getProperties event is received from the client. It replies with a send_defVector to send a property vector definition back to the client. It would normally never be called by users own code. If the auto_send_def attribute is False, this does not send anything, and the getProperties event needs to be handled by rxevent.
- async send(xmldata)¶
Transmits xmldata, this is an internal method, not normally called by a user.
- async send_getProperties(devicename=None, vectorname=None)¶
Sends a getProperties request - which is used to snoop data from other devices on the network, if devicename given, it must not be a device of this driver as the point of this is to snoop on remote devices.
- async send_message(message='', timestamp=None)¶
Send system wide message - without device name
- shutdown()¶
Shuts down the driver, sets the flag self.stop to True
- snoop(devicename, vectorname, timeout=30)¶
Call this to snoop on a given devicename, vectorname. This will cause a getProperties to be sent, and will also send further getProperties every timeout seconds if no snooping data is being received from the specified vector. This avoids a possible problem where intermediate servers may be temporarily turned off, and will lose their instruction to broadcast snooping traffic. This method is only applicable when snooping on a specific device vector. timeout must be an integer equal or greater than 5 seconds.
- async snoopevent(event)¶
Override this if this driver is snooping on other devices. On receiving snoop data, this is called, and should handle any necessary actions. event is an object with attributes according to the data received.
- property stop¶
returns self._stop, being the instruction to stop the driver
The ipydriver object has attributes:
driverdata - The dictionary of named arguments you have optionally set in the constructor.
This is particularly useful to pass in any object which controls your instrument, and which is then accessable in your rxevent and hardware methods.
auto_send_def - As default this is set to True.
With auto_send_def set to True, whenever a getProperties event is received from a client, a vector send_defVector() method will be called, automatically replying with the vector definition. If set to False, the driver developer will need to test for a getProperties event in the rxevent method, and implement a send_defVector() . Possibly one reason you may want to do this is to send a message with every vector definition.
stop - Normally False, but set to True when the driver shutdown() method is called.
stopped - An asyncio.Event() object, await driver.stopped.wait() will block until the driver stops.
debug_enable - As default this is set to False.
With debug_enable set to False, then xml traffic will not be logged at the driver level, but will still be logged at the server level which logs all traffic between server and attached clients. See the logging section of this documentation for further details.
There are two ways a driver can be run, assuming ‘driver’ is an instance of this class.
This coroutine outputs the xml data on stdout, and reads it on stdin:
await driver.asyncrun()
This could be awaited together with any other co-routines needed to run your instrument. Making your script executable, and using the above method should allow your driver to work with other parties INDI server software that expect stdin and stdout streams from drivers.
Alternatively, use indipydriver.IPyServer, this listens on the given host and port, to which a client can connect. Multiple drivers can be served, and multiple client connections can be made:
server = IPyServer(*drivers, host="localhost", port=7624, maxconnections=5)
await server.asyncrun()
You would use then use indipyterm, or other INDI client, to connect to this port, however note that if your client is running remotely, and you are connecting over a network, then in the above command “localhost” would need to be changed to the IP address of the servers listening port, or to “0.0.0.0” to listen on all ports.