# Starting/creating/deleting devices

## Multiple device classes (Python and C++) in a server

Within the same python interpreter, it is possible to mix several Tango classes. Let’s say two of your colleagues programmed two separate Tango classes in two separated python files: A `PLC` class in a `PLC.py`:

     1# PLC.py
     2
     3from tango.server import Device
     4
     5class PLC(Device):
     6
     7    # bla, bla my PLC code
     8
     9if __name__ == "__main__":
    10    PLC.run_server()

… and a `IRMirror` in a `IRMirror.py`:

     1# IRMirror.py
     2
     3from tango.server import Device
     4
     5class IRMirror(Device):
     6
     7    # bla, bla my IRMirror code
     8
     9if __name__ == "__main__":
    10    IRMirror.run_server()

You want to create a Tango server called `PLCMirror` that is able to contain devices from both PLC and IRMirror classes. All you have to do is write a `PLCMirror.py` containing the code:

    1# PLCMirror.py
    2
    3from tango.server import run
    4from PLC import PLC
    5from IRMirror import IRMirror
    6
    7run([PLC, IRMirror])

It is also possible to add C++ Tango class in a Python device server as soon as:

  1. The Tango class is in a shared library

  2. It exist a C function to create the Tango class

  3. The C++ Tango class is linked against the same `libtango.so` object as PyTango (i.e., cannot be used with binary wheels from PyPI, but can with conda-forge or a custom build).

For a Tango class called MyTgClass, the shared library has to be called MyTgClass.so and has to be in a directory listed in the LD_LIBRARY_PATH environment variable. The C function creating the Tango class has to be called _create_MyTgClass_class() and has to take one parameter of type “char *” which is the Tango class name. Here is an example of the main function of the same device server than before but with one C++ Tango class called SerialLine:

     1import tango
     2import sys
     3
     4if __name__ == '__main__':
     5    util = tango.Util(sys.argv)
     6    util.add_class('SerialLine', 'SerialLine', language="c++")
     7    util.add_class(PLCClass, PLC, 'PLC')
     8    util.add_class(IRMirrorClass, IRMirror, 'IRMirror')
     9
    10    U = tango.Util.instance()
    11    U.server_init()
    12    U.server_run()

Line 6:

  The C++ class is registered in the device server

Line 7 and 8:

  The two Python classes are registered in the device server

## Create/Delete devices dynamically

This feature is only possible since PyTango 7.1.2

Starting from PyTango 7.1.2 it is possible to create devices in a device server “en caliente”. This means that you can create a command in your “management device” of a device server that creates devices of (possibly) several other tango classes. There are two ways to create a new device which are described below.

Tango imposes a limitation: the tango class(es) of the device(s) that is(are) to be created must have been registered before the server starts. If you use the high level API, the tango class(es) must be listed in the call to `run()`. If you use the lower level server API, it must be done using individual calls to `add_class()`.

### Dynamic device from a known tango class name

If you know the tango class name but you don’t have access to the `tango.DeviceClass` (or you are too lazy to search how to get it ;-) the way to do it is call `create_device()` / `delete_device()`. Here is an example of implementing a tango command on one of your devices that creates a device of some arbitrary class (the example assumes the tango commands ‘CreateDevice’ and ‘DeleteDevice’ receive a parameter of type DevVarStringArray with two strings. No error processing was done on the code for simplicity sake):

     1from tango import Util
     2from tango.server import Device, command
     3
     4class MyDevice(Device):
     5
     6    @command(dtype_in=[str])
     7    def CreateDevice(self, pars):
     8        klass_name, dev_name = pars
     9        util = Util.instance()
    10        util.create_device(klass_name, dev_name, alias=None, cb=None)
    11
    12    @command(dtype_in=[str])
    13    def DeleteDevice(self, pars):
    14        klass_name, dev_name = pars
    15        util = Util.instance()
    16        util.delete_device(klass_name, dev_name)

An optional callback can be registered that will be executed after the device is registed in the tango database but before the actual device object is created and its init_device method is called. It can be used, for example, to initialize some device properties.

### Dynamic device from a known tango class

If you already have access to the `DeviceClass` object that corresponds to the tango class of the device to be created you can call directly the `create_device()` / `delete_device()`. For example, if you wish to create a clone of your device, you can create a tango command called Clone:

     1class MyDevice(tango.Device):
     2
     3    def fill_new_device_properties(self, dev_name):
     4        prop_names = db.get_device_property_list(self.get_name(), "*")
     5        prop_values = db.get_device_property(self.get_name(), prop_names.value_string)
     6        db.put_device_property(dev_name, prop_values)
     7
     8        # do the same for attributes...
     9        ...
    10
    11    def Clone(self, dev_name):
    12        klass = self.get_device_class()
    13        klass.create_device(dev_name, alias=None, cb=self.fill_new_device_properties)
    14
    15    def DeleteSibling(self, dev_name):
    16        klass = self.get_device_class()
    17        klass.delete_device(dev_name)

Note that the cb parameter is optional. In the example it is given for demonstration purposes only.