{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Device Manager\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from device_manager import DeviceManager\n", "\n", "device_manager = DeviceManager()\n", "device_manager" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `DeviceManager` combines the functionality of some classes:\n", "\n", "1. To search for connected devices, it contains a `DeviceScanner`\n", "2. To store devices in the `DeviceManager`, it can be used just like a standard python dictionary\n", "3. To store the devices persistantly, the `DeviceManager` can be serialized in a JSON-file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Searching for devices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To search a device, you can use the functions `find_by_address` or `find_by_device`, that are working as their names say.\n", "\n", "Additionally, the `DeviceManager` has a `scanner`-property that is an instance of `DeviceScanner`:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager.scanner" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager.scanner[\"lan\"]" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(USBDevice('USB\\\\VID_413C&PID_5534\\\\4&3FFD8F2A&0&21'),\n", " USBDevice('USB\\\\VID_413C&PID_2513\\\\6&1FFE1F1B&1&2'),\n", " USBDevice('USB\\\\VID_0B15&PID_3401\\\\0123456789ABCD'),\n", " USBDevice('USB\\\\VID_413C&PID_2134\\\\ABC1234'),\n", " USBDevice('USB\\\\VID_1130&PID_1620\\\\XYZWVUT975310'),\n", " USBDevice('USB\\\\VID_0781&PID_5581\\\\01171114'),\n", " USBDevice('USB\\\\VID_1BCF&PID_2B8D\\\\4C5DDB4'))" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager.scanner[\"usb\"].list_devices()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(USBDevice('USB\\\\VID_0B15&PID_3401\\\\0123456789ABCD'),)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager.scanner[\"usb\"].find_devices(serial=\"0123456789ABCD\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using the DeviceManager as a dictionary" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Standard dictionary functionality\n", "\n", "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Storing devices into the DeviceManager\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from device_manager import USBDevice, LANDevice\n", "\n", "test_usb_device = USBDevice()\n", "test_usb_device.address = \"path/to/my/new/usb/device\"\n", "\n", "# Add the device by using the add function\n", "device_manager.set(\"my-usb-device\", test_usb_device)\n", "\n", "test_lan_device = LANDevice()\n", "test_lan_device.address = \"my.lan-device.com\"\n", "\n", "# Add the device by using the __setitem__ operator\n", "device_manager[\"my-lan-device\"] = test_lan_device" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, both added keys can be found in `device_manager`:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('my-usb-device', 'my-lan-device')" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager.keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Getting a device stored in the DeviceManager\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "LANDevice('my.lan-device.com')" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets the device, which was stored as \"my-lan-device\", by using the get function\n", "device_manager.get(\"my-lan-device\")" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "USBDevice('path/to/my/new/usb/device')" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets the device, which was stored as \"my-usb-device\", by using the __getitem__ operator\n", "device_manager[\"my-usb-device\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Checking the DeviceManager's available keys\n", "\n", "Before accessing a key of the `DeviceManager`-object, you can check if the key is known to the `DeviceManager`." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Check the length (number of keys) of device_manager\n", "len(device_manager)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Check if a device-name is already in device_manager\n", "\"my-usb-device\" in device_manager" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Removing devices from the DeviceManager\n", "\n", "To remove a device from the `DeviceManager`, you can use the `__delitem__` operator or the `remove` function." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# Deletes the device which was stored at \"my-usb-device\", by using the __delitem__ operator\n", "del device_manager[\"my-usb-device\"]" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "# Deletes the device which was stored at \"my-usb-device\", by using the remove function\n", "device_manager.remove(\"my-lan-device\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, after the previously added keys were removed, `device_manager` is empty again:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "()" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager.keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To remove all items from the `DeviceManager`, you can also use the clear function:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "device_manager.clear()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Extended dictionary functionalities\n", "\n", "Additionaly to the standard dictionary functionality, there are several functions that do not work with a standard python dictionary." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Multiple devices with the same key\n", "\n", "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.\n", "\n", "The following examples shows a device that can be connected with ethernet (LAN) or USB:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{: USBDevice('path/to/my/new/usb/device'),\n", " : LANDevice('my.lan-device.com')}" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager[\"multi-interface-device\"] = test_usb_device\n", "device_manager[\"multi-interface-device\"] = test_lan_device\n", "\n", "device_manager[\"multi-interface-device\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Doing this, shows how the devices are actually stored inside the `DeviceManager`, because the `DeviceManager` uses two keys for storing a device:\n", "\n", "1. user-defined name\n", "2. type of the device\n", "\n", "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Accessing a specific device type\n", "\n", "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:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "USBDevice('path/to/my/new/usb/device')" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from device_manager import DeviceType\n", "\n", "device_manager[\"multi-interface-device\", DeviceType.USB]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "USBDevice('path/to/my/new/usb/device')" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager[\"multi-interface-device\", \"usb\"]" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "USBDevice('path/to/my/new/usb/device')" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager[\"multi-interface-device\", USBDevice]" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "USBDevice('path/to/my/new/usb/device')" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "device_manager[\"multi-interface-device\", test_usb_device]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Deleting items works analogously to this:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "del device_manager[\"multi-interface-device\", \"usb\"]" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "LANDevice('my.lan-device.com')" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The ethernet device is still there\n", "device_manager[\"multi-interface-device\", \"lan\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now it is not required anymore to specify the `DeviceType`, because only the ethernet device is left for key \"multi-interface-device\":" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "LANDevice('my.lan-device.com')" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The ethernet device is the only device that is left\n", "device_manager[\"multi-interface-device\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Automatical search for a device\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "USBDevice('USB\\\\VID_0B15&PID_3401\\\\0123456789ABCD')\n", "vendor id: 2837\n", "product id: 13313\n", "serial: 0123456789ABCD\n" ] } ], "source": [ "device_manager[\"added-by-address\", \"usb\"] = \"USB\\\\VID_0B15&PID_3401\\\\0123456789ABCD\"\n", "\n", "print(device_manager[\"added-by-address\"])\n", "print(\"vendor id: \", device_manager[\"added-by-address\"].vendor_id)\n", "print(\"product id:\", device_manager[\"added-by-address\"].product_id)\n", "print(\"serial: \", device_manager[\"added-by-address\"].serial)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Serialization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Storing the device manager in a file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To persistantly save your devices, you can use the `save` function of the `DeviceManager`:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"multi-interface-device\": {\n", " \"lan\": {\n", " \"type\": \"lan\",\n", " \"address\": \"my.lan-device.com\",\n", " \"address_aliases\": []\n", " }\n", " },\n", " \"added-by-address\": {\n", " \"usb\": {\n", " \"type\": \"usb\",\n", " \"address\": \"USB\\\\VID_0B15&PID_3401\\\\0123456789ABCD\",\n", " \"address_aliases\": [\n", " \"USB\\\\VID_0B15&PID_3401&REV_0100\",\n", " \"USB\\\\VID_0B15&PID_3401\",\n", " ],\n", " \"vendor_id\": 2837,\n", " \"product_id\": 13313,\n", " \"revision_id\": 256,\n", " \"serial\": \"0123456789ABCD\"\n", " }\n", " }\n", "}\n" ] } ], "source": [ "with open(\"mydevices.json\", \"w\") as file:\n", " device_manager.save(file, pretty=True)\n", "\n", "# Show file contents\n", "with open(\"mydevices.json\", \"r\") as file:\n", " print(file.read())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Loading the device manager from a file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(('multi-interface-device', {: LANDevice(None)}),\n", " ('added-by-address',\n", " {: USBDevice('USB\\\\VID_0B15&PID_3401\\\\0123456789ABCD')}))" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from device_manager import load_device_manager\n", "\n", "with load_device_manager(\"mydevices.json\") as manager:\n", " devices = manager.items()\n", "\n", "# This is doing the same:\n", "manager = DeviceManager()\n", "with open(\"mydevices.json\", \"r\") as file:\n", " devices = manager.load(file)\n", "\n", "devices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.1" }, "nbsphinx": { "execute": "never" } }, "nbformat": 4, "nbformat_minor": 4 }