2.3. Device Manager¶
[1]:
from device_manager import DeviceManager
device_manager = DeviceManager()
device_manager
[1]:
<device_manager.manager.DeviceManager at 0x1ca0c011d30>
The DeviceManager
combines the functionality of some classes:
To search for connected devices, it contains a
DeviceScanner
To store devices in the
DeviceManager
, it can be used just like a standard python dictionaryTo store the devices persistantly, the
DeviceManager
can be serialized in a JSON-file
2.3.1. Searching for devices¶
To search a device, you can use the functions find_by_address
or find_by_device
, that are working as their names say.
Additionally, the DeviceManager
has a scanner
-property that is an instance of DeviceScanner
:
[2]:
device_manager.scanner
[2]:
<device_manager.scanner.DeviceScanner at 0x1ca0c0115b0>
This DeviceScanner
can be used to search for devices by their unique identifiers and it can provide a list of all connected devices. The DeviceScanner
is splitted into an USBDeviceScanner
and a LANDeviceScanner
. When the device_manager.scanner
is used, it automatically uses both types of scanners to search for devices. But by using the __getitem__
operator, you can specify the device type you are seraching for.
[3]:
device_manager.scanner["lan"]
[3]:
<device_manager.scanner._win32.Win32LANDeviceScanner at 0x1ca0c199820>
[4]:
device_manager.scanner["usb"].list_devices()
[4]:
(USBDevice('USB\\VID_413C&PID_5534\\4&3FFD8F2A&0&21'),
USBDevice('USB\\VID_413C&PID_2513\\6&1FFE1F1B&1&2'),
USBDevice('USB\\VID_0B15&PID_3401\\0123456789ABCD'),
USBDevice('USB\\VID_413C&PID_2134\\ABC1234'),
USBDevice('USB\\VID_1130&PID_1620\\XYZWVUT975310'),
USBDevice('USB\\VID_0781&PID_5581\\01171114'),
USBDevice('USB\\VID_1BCF&PID_2B8D\\4C5DDB4'))
[5]:
device_manager.scanner["usb"].find_devices(serial="0123456789ABCD")
[5]:
(USBDevice('USB\\VID_0B15&PID_3401\\0123456789ABCD'),)
2.3.2. Using the DeviceManager as a dictionary¶
Standard dictionary functionality¶
The DeviceManager
-class can be used as a standard python dictionary. For this purpose, the DeviceManager
supports the functions set
, get
and remove
, as well as the magic functions __getitem__
, __setitem__
and __delitem__
, for getting, setting and deleting items from the dictionary.
Storing devices into the DeviceManager¶
Using the set
function or the __setitem__
operator, you can easily add devices to the device manager. To do this, you can define a name, which will be used to identify the device.
[6]:
from device_manager import USBDevice, LANDevice
test_usb_device = USBDevice()
test_usb_device.address = "path/to/my/new/usb/device"
# Add the device by using the add function
device_manager.set("my-usb-device", test_usb_device)
test_lan_device = LANDevice()
test_lan_device.address = "my.lan-device.com"
# Add the device by using the __setitem__ operator
device_manager["my-lan-device"] = test_lan_device
Now, both added keys can be found in device_manager
:
[7]:
device_manager.keys()
[7]:
('my-usb-device', 'my-lan-device')
Beside keys
, you can also use the functions values
or items
to get all stored devices or key-value-pairs of the DeviceManager
– just as knwon from the standard python dictionary.
Getting a device stored in the DeviceManager¶
Getting a device from the DeviceManager
works analogously to setting a device. So, getting an item is done with the get
function or the __getitem__
operator.
[8]:
# Gets the device, which was stored as "my-lan-device", by using the get function
device_manager.get("my-lan-device")
[8]:
LANDevice('my.lan-device.com')
[9]:
# Gets the device, which was stored as "my-usb-device", by using the __getitem__ operator
device_manager["my-usb-device"]
[9]:
USBDevice('path/to/my/new/usb/device')
Checking the DeviceManager’s available keys¶
Before accessing a key of the DeviceManager
-object, you can check if the key is known to the DeviceManager
.
[10]:
# Check the length (number of keys) of device_manager
len(device_manager)
[10]:
2
[11]:
# Check if a device-name is already in device_manager
"my-usb-device" in device_manager
[11]:
True
Removing devices from the DeviceManager¶
To remove a device from the DeviceManager
, you can use the __delitem__
operator or the remove
function.
[12]:
# Deletes the device which was stored at "my-usb-device", by using the __delitem__ operator
del device_manager["my-usb-device"]
[13]:
# Deletes the device which was stored at "my-usb-device", by using the remove function
device_manager.remove("my-lan-device")
Now, after the previously added keys were removed, device_manager
is empty again:
[14]:
device_manager.keys()
[14]:
()
To remove all items from the DeviceManager
, you can also use the clear function:
[15]:
device_manager.clear()
Extended dictionary functionalities¶
Additionaly to the standard dictionary functionality, there are several functions that do not work with a standard python dictionary.
Multiple devices with the same key¶
The DeviceManager
allows you to store multiple devices with the same key, but only if the devices have different types. This is very useful, if you need to store a device which supports different connection types.
The following examples shows a device that can be connected with ethernet (LAN) or USB:
[16]:
device_manager["multi-interface-device"] = test_usb_device
device_manager["multi-interface-device"] = test_lan_device
device_manager["multi-interface-device"]
[16]:
{<DeviceType.USB: 'usb'>: USBDevice('path/to/my/new/usb/device'),
<DeviceType.LAN: 'lan'>: LANDevice('my.lan-device.com')}
Doing this, shows how the devices are actually stored inside the DeviceManager
, because the DeviceManager
uses two keys for storing a device:
user-defined name
type of the device
If the DeviceManager
has multiple devices for a key, it will return a dictionary when requesting that devices. But if the DeviceManager
only knwos a single device for the provided key, it returns only this device - not a dictionary. So, if you do not use this functionality, you will not notice it.
Accessing a specific device type¶
Due to the fact, that it is possible to store more than a single device for the same key, there is a possibility to access only the device you need. By using a tuple-key you can provide the required device-type to the second key:
[17]:
from device_manager import DeviceType
device_manager["multi-interface-device", DeviceType.USB]
[17]:
USBDevice('path/to/my/new/usb/device')
The second key does not need to be a DeviceType
-object, you can also use a string or the device’s type or even a Device
-object:
[18]:
device_manager["multi-interface-device", "usb"]
[18]:
USBDevice('path/to/my/new/usb/device')
[19]:
device_manager["multi-interface-device", USBDevice]
[19]:
USBDevice('path/to/my/new/usb/device')
[20]:
device_manager["multi-interface-device", test_usb_device]
[20]:
USBDevice('path/to/my/new/usb/device')
Deleting items works analogously to this:
[21]:
del device_manager["multi-interface-device", "usb"]
[22]:
# The ethernet device is still there
device_manager["multi-interface-device", "lan"]
[22]:
LANDevice('my.lan-device.com')
Now it is not required anymore to specify the DeviceType
, because only the ethernet device is left for key “multi-interface-device”:
[23]:
# The ethernet device is the only device that is left
device_manager["multi-interface-device"]
[23]:
LANDevice('my.lan-device.com')
Automatical search for a device¶
If you want to add a device, but you do not have a Device
-object, you can just pass the device’s address as string into the device_manager.
[24]:
device_manager["added-by-address", "usb"] = "USB\\VID_0B15&PID_3401\\0123456789ABCD"
print(device_manager["added-by-address"])
print("vendor id: ", device_manager["added-by-address"].vendor_id)
print("product id:", device_manager["added-by-address"].product_id)
print("serial: ", device_manager["added-by-address"].serial)
USBDevice('USB\\VID_0B15&PID_3401\\0123456789ABCD')
vendor id: 2837
product id: 13313
serial: 0123456789ABCD
As you can see, the Device
-object was automatically filled with its information. To add the device you can also leave out the type-specification. This results in a search for all available device types (currently usb and lan), which takes more time than the targeted search for one device type.
2.3.3. Serialization¶
Storing the device manager in a file¶
To persistantly save your devices, you can use the save
function of the DeviceManager
:
[25]:
with open("mydevices.json", "w") as file:
device_manager.save(file, pretty=True)
# Show file contents
with open("mydevices.json", "r") as file:
print(file.read())
{
"multi-interface-device": {
"lan": {
"type": "lan",
"address": "my.lan-device.com",
"address_aliases": []
}
},
"added-by-address": {
"usb": {
"type": "usb",
"address": "USB\\VID_0B15&PID_3401\\0123456789ABCD",
"address_aliases": [
"USB\\VID_0B15&PID_3401&REV_0100",
"USB\\VID_0B15&PID_3401",
],
"vendor_id": 2837,
"product_id": 13313,
"revision_id": 256,
"serial": "0123456789ABCD"
}
}
}
Loading the device manager from a file¶
To load data from the file, either use the load
function or the context manager function load_device_manager
, if you do not have a DeviceManager
-object yet:
[26]:
from device_manager import load_device_manager
with load_device_manager("mydevices.json") as manager:
devices = manager.items()
# This is doing the same:
manager = DeviceManager()
with open("mydevices.json", "r") as file:
devices = manager.load(file)
devices
[26]:
(('multi-interface-device', {<DeviceType.LAN: 'lan'>: LANDevice(None)}),
('added-by-address',
{<DeviceType.USB: 'usb'>: USBDevice('USB\\VID_0B15&PID_3401\\0123456789ABCD')}))
After loading data from a file, the DeviceManager
automatically checks the addresses of the devices. That causes the LANDevice
at “multi-interface-device” to have None
as address.