IPyClient¶
Typically you would import the class IPyClient, and overide its rxevent(event) method, which is an awaitable coroutine.
rxevent(event) is automatically called whenever data is received, and the event will be of a type which can be tested, and attributes read to handle the data received.
As devices and vectors are learnt from the received data, the IPyClient object becomes a mapping of devicename to device objects, which in turn are mappings to vectors and values. It also has a send_newVector coroutine method which can be used by your own code to send data to the remote instrument.
The IPyClient object has an asyncrun() coroutine method which needs to be awaited, typically gathered with your own tasks, to run your script or client.
IPyClient has a ‘hardware’ coroutine method which is started with the IPyClient.asyncrun method, but as default does nothing. It is available to be overidden if required, for example, if data is to be sent to the remote instrument every ten seconds:
async def hardware(self):
while not self._stop:
await asyncio.sleep(10)
datavalue = my_function() # your own function which obtains data
await self.send_newVector("devicename", "vectorname", members={"membername":datavalue})
Note that attribute self._stop becomes True when the method shutdown() is called, requesting any coroutines to stop.
- class IPyClient(indihost='localhost', indiport=7624, **clientdata)¶
This class can be used to create your own scripts or client, and provides a connection to an INDI service, with parsing of the XML protocol. You should create your own class, inheriting from this, and overriding the rxevent method. The argument clientdata provides any named arguments you may wish to pass into the object when instantiating it. The IPyClient object is also a mapping of devicename to device object, which is populated as devices and their vectors are learned from the INDI protocol.
- property BLOBfolder¶
Setting the BLOBfolder to a folder will automatically transmit an enableBLOB for all devices set to Also, and will save incoming BLOBs to that folder. Setting it to None will transmit an enableBLOB for all devices set to the enableBLOBdefault value
- async asyncrun()¶
Await this method to run the client.
- property connected¶
property showing connected status, True or False
- create_itemid(devicename='', vectorname='', membername='', **kwargs)¶
This is called as each device, vector and member is learnt, and returns an integer. This integer is set as an itemid attribute into the device/vector/member. As default this method just increments a counter (self._itemid) whenever it is called, and returns the integer ensuring the itemid attributes are unique. The devicename,vectorname and membername arguments are given, but not used and the itemid attributes are not used any further, other than being copied to snapshots. Their only purpose is to be available as itemid attributes which may be useful to client software. If you wish, this method may be overwritten to provide an id scheme of your own choosing, the kwargs argument being available for your convenience.
- debug_verbosity(verbose)¶
Set how verbose the debug xml logs will be when created.
0 no xml logs will be generated1 for transmitted/received vector tags only,2 for transmitted/received vectors, members and contents (apart from BLOBs)3 for all transmitted/received data including BLOBs.
- enabledlen()¶
Returns the number of enabled devices
- get_user_string(devicename, vectorname, membername)¶
Each device, vector and member has a user_string attribute. If devicename, vectorname and membername are given this method returns the user string of the member. If membername is None, the user_string of the vector is returned, if vectorname is None as well, the user_string of the device is returned. If no object can be found, and no initial string has been set with the set_user_string method, None will be returned.
- get_vector_state(devicename, vectorname)¶
Gets the state string of the given vectorname, if this vector does not exist returns None - this could be because the vector is not yet learnt. The vector state attribute will still be returned, even if vector.enable is False
- async hardware()¶
This is started when asyncrun is called. As default does nothing so stops immediately. It is available to be overriden if required.
- async report(message)¶
The given string message will be logged at level INFO, and if self.enable_reports is True will be injected into the received data, which will be picked up by the rxevent method. It is a way to set a message on to your client display, in the same way messages come from the INDI service.
- async resend_enableBLOB(devicename, vectorname=None)¶
Internal method used by the framework, which sends an enableBLOB instruction, repeating the last value sent. Used as an automatic reply to a def packet received, if no last value sent the default is the enableBLOBdefault value.
- async rxevent(event)¶
Override this. On receiving data, this is called, and should handle any necessary actions. event is an object with attributes according to the data received.
- async send(xmldata)¶
Transmits xmldata, this is an internal method, not normally called by a user. xmldata is an xml.etree.ElementTree object
- async send_enableBLOB(value, devicename, vectorname=None)¶
Sends an enableBLOB instruction. The value should be one of “Never”, “Also”, “Only”.
- async send_getProperties(devicename=None, vectorname=None)¶
Sends a getProperties request. On startup the IPyClient object will automatically send getProperties, so typically you will not have to use this method.
- async send_newVector(devicename, vectorname, timestamp=None, members={})¶
Send a Vector with updated member values, members is a membername to value dictionary.
Note, if this vector is a BLOB Vector, the members dictionary should be {membername:(value, blobsize, blobformat)} where value could be a bytes object, a pathlib.Path, or a string filepath. If blobsize of zero is used, the size value sent will be set to the number of bytes in the BLOB. The INDI standard specifies the size should be that of the BLOB before any compression, therefore if you are sending a compressed file, you should set the blobsize prior to compression. blobformat should be a file extension, such as ‘.png’. If it is an empty string and value is a filename, the extension will be taken from the filename.
- set_user_string(devicename, vectorname, membername, user_string='')¶
Each device, vector and member has a user_string attribute, initially set to empty strings, and can be changed to any string you may require. These strings may be used for any purpose, such as setting associated id values for a database perhaps. It is suggested they should be limited to strings, so if JSON snapshots are taken, they are easily converted to JSON values. This method can be called before asyncrun is called, and before the devices are learnt, which would only be useful for those scripts which know in advance what devices they are connecting to. As soon as the device, vector or member becomes learnt it will then be set with the user string. If membername is None, the user_string is applied to the vector, if vectorname is None it applies to the device.
- set_vector_timeouts(timeout_enable=None, timeout_min=None, timeout_max=None)¶
The INDI protocol allows the server to suggest a timeout for each vector. This method allows you to set minimum and maximum timeouts which restricts the suggested values.
These should be given as integer seconds. If any parameter is not provided (left at None) then that value will not be changed.
If timeout_enable is set to False, no VectorTimeOut events will occur.
As default, timeouts are enabled, minimum is set to 2 seconds, maximum 10 seconds.
- shutdown()¶
Shuts down the client, sets the flag self._stop to True
- snapshot()¶
Take a snapshot of the client and returns an object which is a restricted copy of the current state of devices and vectors. Vector methods for sending data will not be available. These copies will not be updated by events. This is provided so that you can handle the client data, without fear of their values changing.
- property stop¶
returns self._stop, being the instruction to stop the client
- async warning(message)¶
The given string message will be logged at level WARNING, and will be injected into the received data, which will be picked up by the rxevent method. It is a way to set a message on to your client display, in the same way messages come from the INDI service.
Attributes
Attributes of the IPyClient object are:
self.indihost
The host as given in the class argument.
self.indiport
The port as given in the class argument.
self.clientdata
Dictionary of any named arguments.
self.BLOBfolder
If set to a directory, enableBLOB instructions will be sent automatically (with value Also) allowing the server to send BLOBs, which this client will receive and save to files in this directory.
self.enableBLOBdefault
If set to a string; one of “Never”, “Also”, “Only” then this value will be the default used by the client.
self.enable_reports
If True, then messages set into the report method will be injected into the client as a received message, and hence will be shown on the terminal messages window. As default this is True.
self.connected
True if a connection has been made.
self.user_string
This is initially an empty string, but can be set by your code to any string you like.
self.stopped
This is an asyncio.Event object, which is set when asyncrun is finished. awaiting self.stopped.wait() will wait until the client has shutdown. This could be used to clear up after a client has closed.
self.messages
This is a collections.deque of item tuples (Timestamp, message).
Where the messages are ‘system’ messages received from the INDI server, or by the report() or warning() coroutine methods. They are not associated with a device which has its own messages attribute. The deque has a maxlen=8 value set, and so only the last eight messages will be available.
Note, messages are added with ‘appendleft’ so the newest message is messages[0] and the oldest message is messages[-1] or can be obtained with .pop()
user_string¶
The client, and each device, vector and member all have ‘user_string’ attributes. These are not received from the server, or sent to the server, but are available for any string data you may want to associate with the object. These may be useful to provide additional data to your client display code.
Strings are specified rather than general Python Objects, so that the snapshot, together with its JSON methods can safely include these strings.
Client Snapshot¶
The snapshot() method of IPyClient returns a Snap object which is a copy of the state of the client, devices etc.. This could be used if you wish to pass this state to your own routines, perhaps to record values in another thread without danger of them being updated.
A subclass of IPyClient is available, see Threaded synchronous Client, which uses queues to pass snapshots to your threaded code.
The snapshot is a mapping of devicename to snapshot copies of devices and vectors, without any coroutine methods, so cannot be used to send vector updates. You would never instantiate this class yourself, but would ceate it by calling the snapshot method of IPyClient.
- class Snap(indihost, indiport, connected, messages, user_string)¶
An instance of this object is returned when a snapshot is taken of the client. It is a mapping of device name to device snapshots, which are in turn mappings of vectorname to vector snapshots. These snapshots record values and attributes, at the moment of the snapshot. Unlike IPyClient this has no send_newVector method, and the snap vectors do not have the send methods.
- dictdump(inc_blob=False, inc_user_string=False, inc_itemid=False)¶
Returns a dictionary of this client information and is used to generate the JSON output. If any BLOB vectors are included and inc_blob is False, the BLOB values will be given as None in the dictionary, set inc_blob to True to also include the BLOB in the dictionary. If inc_user_string and inc_itemid are set to True, then these values will be included, otherwise not,
- dump(fp, indent=None, separators=None, inc_blob=False, inc_user_string=False, inc_itemid=False)¶
Serialize the snapshot as a JSON formatted stream to fp, a file-like object. This uses the Python json module which always produces str objects, not bytes objects. Therefore, fp.write() must support str input. If any BLOB vectors are included and inc_blob is False, the BLOB values will be given as Null in the file, set inc_blob to True to also include the BLOB.
- dumps(indent=None, separators=None, inc_blob=False, inc_user_string=False, inc_itemid=False)¶
Returns a JSON string of the snapshot. If any BLOB vectors are included and inc_blob is False, the BLOB values will be given as Null in the string, set inc_blob to True to also include the BLOB.
- enabledlen()¶
Returns the number of enabled devices
- get_vector_state(devicename, vectorname)¶
Gets the state string of the given vectorname, if this vector does not exist returns None
The dumps and dump methods can be used to create JSON records of the client state.
The Snap object has attributes, which are copies of the IPyClient attributes.
self.indihost
self.indiport
self.user_string
self.connected
This is the connected value, True or False, at the point the snapshot is taken, it does not update.
self.messages
The messages attribute is cast as a list rather than a collections.deque. It is the messages at the point the snapshot is taken, it does not update.