{ "info": { "author": "Daniel Stock", "author_email": "daniel.stock@ipa.fraunhofer.de", "bugtrack_url": null, "classifiers": [], "description": "\n

\n \n \"VFK\n \n

\n\n# MSB websocket client library for Python\n\n[![Build Status](https://travis-ci.org/research-virtualfortknox/msb-client-websocket-python.svg?branch=master)](https://travis-ci.org/research-virtualfortknox/msb-client-websocket-python)\n[![PyPI version](https://badge.fury.io/py/msb-client-websocket-python.svg)](https://badge.fury.io/py/msb-client-websocket-python)\n\n**Compatibility Matrix**\n\nClient version compatibility to MSB versions:\n\n| | **1.5.x-RELEASE** |\n|---|:---:|\n| 1.0.x | x |\n\n## Welcome\n\nIf you want to contribute, please read the [Contribution Guidelines](.github/CONTRIBUTING.md).\n\nIf you want to test this client by using its sources and a sample app, read the [App Sample](doc/app_sample.md).\n\nIf you want to know how to use this client in your own project, read below.\n\n## What is VFK MSB\n\nTODO: Link to general documentation about VFK MSB\n\nYou can use this client to connect a python app to VFK MSB.\n\n## Prerequisites\n\n* Setup [Python](https://www.python.org/downloads/) **version 3.6.x**\n* MSB client installed using PyPi\n* Optional: Use pipenv to run your python app in a virtual environment to avoid dependency isssues with other apps\n\nInstall MSB client from PyPi\n\n```sh\npip install msb-client-websocket-python\n```\n\nImport to your applicaton\n\n```python\nfrom msb_client.ComplexDataFormat import ComplexDataFormat\nfrom msb_client.DataType import DataType\nfrom msb_client.Event import Event\nfrom msb_client.Function import Function\nfrom msb_client.MsbClient import MsbClient\n```\n\n## Create self-description\n\nThe figure below shows a minimal required `self-description model` of a smart object / application.\nEvery smart object / application requires (must have) a uuid and a token.\nThe uuid is competent for identification\nand the token is used to verify the smart object / application for its owner on the MSB side.\n\n![Self Description](doc/images/self-description.png)\n\nTODO: Here you can find more information about\nthe `self-description structure` and `supported data formats`.\n\n### Alternative 1 - By application.properties\n\nAdd the main description by adding an `application.poperties` file to the root of your project:\n\nGenerate the uuid e.g. by a tool like https://www.uuidgenerator.net/\n\n```sh\nmsb.uuid=76499d88-34cf-4836-8cc1-7e0d9c54dacx\nmsb.name=YourSmartObjectName\nmsb.description=YourSmartObjectDesc\nmsb.token=5e0d9c54dacx\nmsb.type=SmartObject\n```\n\nWhen initializing your msb client instance, the `application.properties` file will be loaded.\n\n```python\nmyMsbClient = MsbClient()\n```\n\nYou can also set a custom path to the `application.properties` file.\n\n```python\nmyMsbClient = MsbClient(applicationPropertiesCustomPath=\"./your/path/to/application.properties\")\n```\n\n### Alternative 2 - By constructor\n\nIf you do not provide an application.properties file, use the constructor\nto define the basic self description.\n\n```python\nSERVICE_TYPE = \"SmartObject\"\nSO_UUID = str(uuid.uuid1()) # you can type in an own uuid here instead of generating it\nSO_NAME = \"YourSmartObjectName\"\nSO_DESCRIPTION = \"YourSmartObjectDesc\" \nSO_TOKEN = SO_UUID[-6:]\nmyMsbClient = MsbClient(\n SERVICE_TYPE,\n SO_UUID,\n SO_NAME,\n SO_DESCRIPTION,\n SO_TOKEN,\n)\n```\n\n## Add Events\n\nAdd `events` to your smart object / application which can be send to MSB.\n\n### Alternative 1: Simple event creation sample (using method params):\n\n```python\nevent_id = \"E1\"\nevent_name = \"EVENT \" + event_id\nevent_description = \"EVENT Description \" + event_id\nevent_dataformat = DataType.STRING\nevent_priority = 1 # 0 (LOW), 1 (MEDIUM), 2 (HIGH)\nisArray = False # just one value or array of it?\n\n# add the event\nmyMsbClient.addEvent(\n event_id,\n event_name,\n event_description,\n event_dataformat,\n event_priority,\n isArray,\n)\n```\n\n### Alternative 2: Complex event creation sample (using object):\n\n```python\nevent_id = \"E2\"\nevent_name = \"EVENT \" + event_id\nevent_description = \"EVENT Description \" + event_id\nevent_priority = 1 # 0 (LOW), 1 (MEDIUM), 2 (HIGH)\nisArray = False # just one value or array of it?\n\n# define a complex data format to be used in an event\n# init the complex data format\nmyDevice = ComplexDataFormat(\"MyDevice\")\nmyModule = ComplexDataFormat(\"MyModule\")\n\n# add the properties to the complex objects\n# (property_name, property_datatype, isArray)\nmyModule.addProperty(\"moduleName\", DataType.STRING, False)\nmyDevice.addProperty(\"deviceName\", DataType.STRING, False)\nmyDevice.addProperty(\"deviceWeight\", DataType.FLOAT, False)\nmyDevice.addProperty(\"submodules\", myModule, True)\n\n# add the event (with the root of the nested complex object)\nmyMsbClient.addEvent(\n event_id,\n event_name,\n event_description,\n myDevice,\n event_priority,\n isArray,\n)\n```\n\n### Alternative 3: Complex event creation sample (using json object):\n\n```python\nevent_id = \"E3\"\nevent_name = \"EVENT \" + event_id\nevent_description = \"EVENT Description \" + event_id\nevent_priority = 1 # 0 (LOW), 1 (MEDIUM), 2 (HIGH)\nisArray = False # just one value or array of it?\n\n# add the event (with the MSB-ready json object)\nmyMsbClient.addEvent(\n event_id,\n event_name,\n event_description,\n {\n \"Team\" : {\n \"type\" : \"object\",\n \"properties\" : {\n \"staff\" : {\n \"type\" : \"array\",\n \"items\" : {\n \"$ref\" : \"#/definitions/Member\"\n }\n }\n }\n },\n \"Member\" : {\n \"type\" : \"object\",\n \"properties\" : {\n \"name\" : {\n \"type\" : \"string\"\n },\n \"status\" : {\n \"enum\" : [ \"present\", \"absent\" ],\n \"type\" : \"string\"\n }\n }\n },\n \"dataObject\" : {\n \"$ref\" : \"#/definitions/Team\"\n }\n },\n event_priority,\n isArray,\n)\n```\n\nSee `app_sample.py` for more event creation examples.\n\n## Add Functions\n\nAdd `functions` and their implementations your smart object / application is able to handle.\n\n### Alternative 1: Simple function creation sample (using method params):\n\n```python\nfunction_id = \"F1\"\nfunction_name = \"FUNC \" + function_id\nfunction_description = \"FUNC Description \" + function_id\nfunction_dataformat = DataType.STRING\nisArray = False # handle array of values or just one value?\nresponseEvents = None # you can link to response events here by a list of event is e.g. [\"E1\"]\n\n# define the function which will be passed to the function description\n# this function implementation will be called\ndef printMsg(msg):\n print(str(msg[\"dataObject\"]))\n\n# add the function\nmyMsbClient.addFunction(\n function_id,\n function_name,\n function_description,\n function_dataformat,\n printMsg,\n isArray,\n responseEvents,\n)\n```\n\n### Alternative 2: Complex function creation sample (using object):\n\n```python\nfunction_id = \"F2\"\nfunction_name = \"FUNC \" + function_id\nfunction_description = \"FUNC Description \" + function_id\nisArray = False # handle array of values or just one value?\nresponseEvents = None # you can link to response events here by a list of event is e.g. [\"E1\"]\n\n# define a complex data format to be used in an event\n# init the complex data format\nmyCar = ComplexDataFormat(\"MyCar\")\n\n# add the properties to the complex objects\n# (property_name, property_datatype, isArray)\nmyCar.addProperty(\"carColor\", DataType.STRING, False)\nmyCar.addProperty(\"carNrOfSeats\", DataType.INT32, False)\nmyCar.addProperty(\"carWeight\", DataType.FLOAT, False)\n\n# define the function which will be passed to the function description\n# this function implementation will be called\ndef printMsg(msg):\n print(str(msg[\"dataObject\"]))\n\n# add the function\nmyMsbClient.addFunction(\n function_id,\n function_name,\n function_description,\n myCar,\n printMsg,\n isArray,\n responseEvents,\n)\n```\n\n### Alternative 3: Complex function creation sample (using json object):\n\n```python\nfunction_id = \"F3\"\nfunction_name = \"FUNC \" + function_id\nfunction_description = \"FUNC Description \" + function_id\nisArray = False # handle array of values or just one value?\nresponseEvents = None # you can link to response events here by a list of event is e.g. [\"E1\"]\n\n# define the function which will be passed to the function description\n# this function implementation will be called\ndef printMsg(msg):\n print(str(msg[\"dataObject\"]))\n\n# add the function\nmyMsbClient.addFunction(\n function_id,\n function_name,\n function_description,\n {\n \"MyCar\" : {\n \"type\" : \"object\",\n \"properties\" : {\n \"carColor\" : {\n \"type\" : \"string\"\n },\n \"carNrOfSeats\" : {\n \"format\": \"int32\",\n \"type\": \"integer\"\n },\n \"carWeight\" : {\n \"format\": \"float\",\n \"type\": \"number\"\n },\n \"wheels\" : {\n \"type\" : \"array\",\n \"items\" : {\n \"$ref\" : \"#/definitions/MyWheel\"\n }\n }\n }\n },\n \"MyWheel\" : {\n \"type\" : \"object\",\n \"properties\" : {\n \"position\" : {\n \"enum\" : [ \"br\", \"bl\", \"fr\", \"fl\" ],\n \"type\" : \"string\"\n }\n }\n },\n \"dataObject\" : {\n \"$ref\" : \"#/definitions/MyCar\"\n }\n },\n printMsg,\n isArray,\n responseEvents,\n)\n```\n\nSee `app_sample.py` of the application template for more (and complex) examples.\n\n## Connect and Register Client\n\n```python\nmsb_url = 'ws://127.0.0.1:8085'\nmyMsbClient.connect(msb_url)\nmyMsbClient.register()\n```\n\nYou will get an `IO_CONNECTED` and `IO_REGISTERED` event from MSB, if successful.\n\n## Event publishing\n\nFor publishing an event to a websocket broker interface,\nonly the `eventId` and `data` are required of the already specified event (see above).\n\n```python\nevent_id = \"E1\"\nevent_value = 'Hello World!'\n\nmyMsbClient.publish(\n event_id, \n event_value\n)\n```\n\nThe MSB responds with an `IO_PUBLISHED` event, if successful.\n\nBy default events are published with a low priority.\n\nIt is also possible to `set the priority` of an event.\n\nThere are three possible priorities for events like it is shown at the following table.\n\n| `Constant` | `Value` |\n|:---:|:---:|\n| LOW | 0 |\n| MEDIUM| 1 |\n| HIGH| 2 |\n\n```python\nevent_id = \"E1\"\nevent_value = 'Hello World!'\nevent_priority = 2\n\nmyMsbClient.publish(\n event_id, \n event_value,\n event_priority\n)\n```\n\nAnother option is to publish an event as `cached event` by setting the cache parameter to true.\nAnd you can add a `post date`.\n\nThis means that the event is not deleted if the connection is broken.\n\n```python\nevent_id = \"E1\"\nevent_value = 'Hello World!'\nevent_priority = 2\nevent_isCached = True\nevent_postDate = datetime.datetime.utcnow().isoformat()[:-3] + \"Z\"\n\nmyMsbClient.publish(\n event_id, \n event_value,\n event_priority,\n event_isCached,\n event_postDate\n)\n```\n\nYou cann also handle `correlation ids` to identify an event among flows.\n\n```python\nevent_id = \"E1\"\nevent_value = 'Hello World!'\nevent_priority = 2\nevent_isCached = True\nevent_postDate = datetime.datetime.utcnow().isoformat()[:-3] + \"Z\"\nevent_correlationId = \"72047f33-a9ae-4aa5-b7ae-c1c4a2797cac\"\n\nmyMsbClient.publish(\n event_id, \n event_value,\n event_priority,\n event_isCached,\n event_postDate,\n event_correlationId\n)\n```\n\nFor values based on complex data formats it will look like this:\n\n```python\nevent_id = \"E2\"\nevent_priority = 2\nevent_isCached = True\nevent_postDate = datetime.datetime.utcnow().isoformat()[:-3] + \"Z\"\nevent_correlationId = \"72047f33-a9ae-4aa5-b7ae-c1c4a2797cac\"\n\n# pepare the complex ovbject based on a complex data format\n# use it as event value\nmyModuleObj = {}\nmyModuleObj['moduleName'] = 'Module 1'\nmyDeviceObj = {}\nmyDeviceObj['deviceName'] = 'Device 1'\nmyDeviceObj['deviceWeight'] = 1.3\nmyDeviceObj['submodules'] = [myModuleObj]\n\nmyMsbClient.publish(\n event_id, \n myDeviceObj,\n event_priority,\n event_isCached,\n event_postDate,\n event_correlationId\n)\n```\n\n## Function call handling\n\nAs shown above the addFunction method includes a `function pointer`\nto point to the function implementation.\n\n## Configuration parameters\n\nConfiguration parameters are a simple list of key value pairs for the smart object / application.\nIt is displayed and can be customized in the MSB UI to change your apps behaviour during runtime.\n\n`Add` condifuration parameters:\n\n```python\nparam_name_1 = \"testParam1\"\nparam_value_1 = True\nparam_datatype_1 = DataType.BOOLEAN\nmyMsbClient.addConfigParameter(param_name_1, param_value_1, param_datatype_1)\n\nparam_name_2 = \"testParam2\"\nparam_value_2 = \"StringValue\"\nparam_datatype_2 = DataType.STRING\nmyMsbClient.addConfigParameter(param_name_2, param_value_2, param_datatype_2)\n\nparam_name_3 = \"testParam3\"\nparam_value_3 = 1000\nparam_datatype_3 = DataType.INT32\nmyMsbClient.addConfigParameter(param_name_3, param_value_3, param_datatype_3)\n```\n\n`Get` configuration parameter (after changed in MSB UI) to change your app behaviour:\n\n```python\n# get by getConfigParameter using name as key\nparameterValueFound_1 = myMsbClient.getConfigParameter(param_name_1)\nparameterValueFound_2 = myMsbClient.getConfigParameter(param_name_2)\nparameterValueFound_3 = myMsbClient.getConfigParameter(param_name_3)\n```\n\n## SSL/TLS connection configuration\n\nTo enable `SSL/TLS`, you need to specify wss:// or https:// in the URL instead of ws:// or http://.\n\nFurthermore, it is necessary to specify a trust store in the client,\nwhich contains the public certificate of the MSB interface, so that it is considered trustworthy.\n\n```python\nmsb_url = 'wss://:'\nmyMsbClient.connect(msb_url)\nmyMsbClient.register()\n```\n\nIf you use an IP instead of a public url during development,\nit will be necessary to disable the hostname verification to connect via web socket secure.\n\n```python\nmyMsbClient.disableHostnameVerification(True) \n```\n\n## Connection recovery\n\nIf connection to the common websocket interface is broken the client performs a reconnect.\n\nAfter a reconnect the registration at the MSB will be redone automatically by the client.\n\nYou can change this interval by setting an integer value in `ms` for the reconnect interval.\n\n```python\nmyMsbClient.setReconnectInterval(10000)\n```\n\nOr you can disable the automatic reconnect.\n\n```python\nmyMsbClient.disableAutoReconnect(True)\n```\n\n## Event caching\n\nIf the client loses the connection, the published events are cached in a queue.\n\nAfter a successfull reconnection, the queued events are published to MSB (FIFO principle).\nThe default size of the queue is 1000 entries. The size can be changed:\n\n```python\nmyMsbClient.setEventCacheSize(1000)\n```\n\nIf no event caching is needed, you can disable it.\n\n```python\nmyMsbClient.disableEventCache(True)\n```\n\n## Debug mode\n\nTo debug your clients communication with MSB, you can enable the debug mode\n\n```python\nmyMsbClient.enableDebug(True)\n```\n\nTo enable the trace of the websocket communication use also\n\n```python\nmyMsbClient.enableTrace(True)\n```\n\nIt mgiht be also helpful to enable data format validation, to check if an event value is valid\n\n```python\nmyMsbClient.enableDataFormatValidation(True)\n```\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://research.virtualfortknox.de/", "keywords": "", "license": "Apache-2.0", "maintainer": "", "maintainer_email": "", "name": "msb-client-websocket-python", "package_url": "https://pypi.org/project/msb-client-websocket-python/", "platform": "", "project_url": "https://pypi.org/project/msb-client-websocket-python/", "project_urls": { "Bug Tracker": "https://github.com/research-virtualfortknox/msb-client-websocket-python/issues", "Homepage": "https://research.virtualfortknox.de/", "Source Code": "https://github.com/research-virtualfortknox/msb-client-websocket-python.git" }, "release_url": "https://pypi.org/project/msb-client-websocket-python/1.0.7/", "requires_dist": [ "websocket-client (>=0.56.0)", "jsonschema (>=3.0.1)", "jsonpickle (>=0.9.6)", "enum34 (>=1.1.6)" ], "requires_python": "", "summary": "The Python client library to connect to the Websocket Interface of the VFK MSB", "version": "1.0.7" }, "last_serial": 5884485, "releases": { "1.0.1": [ { "comment_text": "", "digests": { "md5": "c9771c24836051eb1c902a84af6ed15a", "sha256": "f42944eb2ec390b53abe6f7fa03d191fbe735b3e5418dde40c2b306c89c4b4bf" }, "downloads": -1, "filename": "msb_client_websocket_python-1.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "c9771c24836051eb1c902a84af6ed15a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24794, "upload_time": "2019-06-07T10:05:20", "url": "https://files.pythonhosted.org/packages/41/b1/57ba822717e1a7e9b062cc6c6948b636a30ce3c4f8d76bce0101963a40e7/msb_client_websocket_python-1.0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "bdfad6138f04a773fbe140c2e5255414", "sha256": "b0dfc7e771810557673b7b7cef86ecdee385c308700204dc6d7e453872dae436" }, "downloads": -1, "filename": "msb-client-websocket-python-1.0.1.tar.gz", "has_sig": false, "md5_digest": "bdfad6138f04a773fbe140c2e5255414", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31970, "upload_time": "2019-06-07T10:05:22", "url": "https://files.pythonhosted.org/packages/fd/42/2dc516ae78179a395e96cd4319c5cf0c00d3b885ff627da87d6be2b274c1/msb-client-websocket-python-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "02f26f77c485ff22a1defdaa60a13a68", "sha256": "441897726974120edae6c650c862c738f41ac7c809a4ffd98146a9eba857f1e4" }, "downloads": -1, "filename": "msb_client_websocket_python-1.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "02f26f77c485ff22a1defdaa60a13a68", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25436, "upload_time": "2019-06-18T10:25:39", "url": "https://files.pythonhosted.org/packages/67/8a/51ac65f8c9d7a6ec090b675ef202909e7d22a06ac5bdc506fca5055b2094/msb_client_websocket_python-1.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ed2ec967d168890e7b91ac580e2696bb", "sha256": "b8b5f4ed46cd50ff706038551ed9687555629831deaf77b1f912e7c7e92023ce" }, "downloads": -1, "filename": "msb-client-websocket-python-1.0.2.tar.gz", "has_sig": false, "md5_digest": "ed2ec967d168890e7b91ac580e2696bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33647, "upload_time": "2019-06-18T10:25:41", "url": "https://files.pythonhosted.org/packages/6e/c5/2422161a71294c674452a230b4afdc6e8104b71fdff8a7486f5f98c91730/msb-client-websocket-python-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "01d903cb8e4306ccc5afc5cd2eb7e445", "sha256": "0187828afc89b2b801199b876a9c37c2b00b2a7362345776eda01f72ca69e019" }, "downloads": -1, "filename": "msb_client_websocket_python-1.0.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "01d903cb8e4306ccc5afc5cd2eb7e445", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25444, "upload_time": "2019-07-24T14:44:57", "url": "https://files.pythonhosted.org/packages/02/a1/8a2d53fd849cfd894d029d97cb48a4057349b0a845f0034b09f2caa65411/msb_client_websocket_python-1.0.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b64850541ea0a5cbecc0847e7635c558", "sha256": "08bf36c627e6a100932f1955ae03afa111ff28bf6986ee2f42518c2f1fd9dfb1" }, "downloads": -1, "filename": "msb-client-websocket-python-1.0.3.tar.gz", "has_sig": false, "md5_digest": "b64850541ea0a5cbecc0847e7635c558", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33812, "upload_time": "2019-07-24T14:44:58", "url": "https://files.pythonhosted.org/packages/d7/fa/321eb4d43257fbce2b56c156113e9eddf2e5d0760bd3646b15f020ee8068/msb-client-websocket-python-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "3b6a1a8f0613f4ae54b04a3207764e4d", "sha256": "26002c648b520fda9f1315d37f1b15684b371041daee69f06a4358413e1a659e" }, "downloads": -1, "filename": "msb_client_websocket_python-1.0.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "3b6a1a8f0613f4ae54b04a3207764e4d", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25482, "upload_time": "2019-07-25T07:59:17", "url": "https://files.pythonhosted.org/packages/3c/4e/de3b6d37ab3e5c51d7dbacc4a54d5fba4d8835a5b11dea4ee0bf73c222b0/msb_client_websocket_python-1.0.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "899926720fa4a505df0f7aeaa9d72a36", "sha256": "89964a56a8587c57a6c9c2ed7275762150101ecc644024135ac9f2a152ce136a" }, "downloads": -1, "filename": "msb-client-websocket-python-1.0.4.tar.gz", "has_sig": false, "md5_digest": "899926720fa4a505df0f7aeaa9d72a36", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33902, "upload_time": "2019-07-25T07:59:19", "url": "https://files.pythonhosted.org/packages/21/25/e74af604868d3ba25e8afe48e2e5907412d1fc4d42083d27e999e9c5050c/msb-client-websocket-python-1.0.4.tar.gz" } ], "1.0.5": [ { "comment_text": "", "digests": { "md5": "802b178d3ae67c1ba11bc8830f3feeba", "sha256": "d7d78398f74d26b4b321dde0c9417e636db6a63312230b86be6e87206752533d" }, "downloads": -1, "filename": "msb_client_websocket_python-1.0.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "802b178d3ae67c1ba11bc8830f3feeba", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25576, "upload_time": "2019-08-02T13:08:39", "url": "https://files.pythonhosted.org/packages/94/86/60e278de7713e7b415fa4ba08ba5c0197feec473c38a2cdc0d06d3971716/msb_client_websocket_python-1.0.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a633e641912bc1892d6c8b51256a5b98", "sha256": "65c73eea8d3ecec442a7432a6f0f36513b485ac2c57282e8c7daeae60b412d3e" }, "downloads": -1, "filename": "msb-client-websocket-python-1.0.5.tar.gz", "has_sig": false, "md5_digest": "a633e641912bc1892d6c8b51256a5b98", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34030, "upload_time": "2019-08-02T13:08:41", "url": "https://files.pythonhosted.org/packages/2a/3c/2ecc4ca930a57b359df245fc1aff59e5d6f806541f153cfb78294193d10c/msb-client-websocket-python-1.0.5.tar.gz" } ], "1.0.6": [ { "comment_text": "", "digests": { "md5": "33dc3eec811fb960e61b769cae6a8afc", "sha256": "81b43619ee897ea91eef7ad9355fd5e928368aeb0277eaf74fd7d9f2dc5c0e13" }, "downloads": -1, "filename": "msb_client_websocket_python-1.0.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "33dc3eec811fb960e61b769cae6a8afc", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25649, "upload_time": "2019-09-04T06:36:31", "url": "https://files.pythonhosted.org/packages/c5/b4/29e9a4ff17b7a2b7bff926a80c7c5cba8f0252ab6a6d60d63e91a84bdbe5/msb_client_websocket_python-1.0.6-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b05504c728de73368e8e6ea1c268d66f", "sha256": "73c8d361dda588d8f4eddb48dbbffa5ccfe1f3c0c00ea43c97b61dd725e9d977" }, "downloads": -1, "filename": "msb-client-websocket-python-1.0.6.tar.gz", "has_sig": false, "md5_digest": "b05504c728de73368e8e6ea1c268d66f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34107, "upload_time": "2019-09-04T06:36:33", "url": "https://files.pythonhosted.org/packages/49/fc/101207e88bb147d652d74b539d9543199d6502228616c83a066952170fd1/msb-client-websocket-python-1.0.6.tar.gz" } ], "1.0.7": [ { "comment_text": "", "digests": { "md5": "437f937baeb36afef739b6f6bb83f42b", "sha256": "be575f50510e35cff73ad6c9f12dd0f0ed9b37013118b9d06d22c3fa9e726947" }, "downloads": -1, "filename": "msb_client_websocket_python-1.0.7-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "437f937baeb36afef739b6f6bb83f42b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25683, "upload_time": "2019-09-25T10:30:08", "url": "https://files.pythonhosted.org/packages/02/0c/e5f52b040c870746bd688ae6006f15c72e1a6c66a807b77b15ab2e07fb15/msb_client_websocket_python-1.0.7-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "feace42abc7263e3cdc3ddfb4ffe8dd2", "sha256": "7888de2733098254a4b2a968d0d228c527a9088a7199fd448dcb0e9565aef1d8" }, "downloads": -1, "filename": "msb-client-websocket-python-1.0.7.tar.gz", "has_sig": false, "md5_digest": "feace42abc7263e3cdc3ddfb4ffe8dd2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34160, "upload_time": "2019-09-25T10:30:10", "url": "https://files.pythonhosted.org/packages/5f/59/a47d5620a40e42132323bcb1a9002c8c9a9cf88f2897af17f2dfb8fbdf59/msb-client-websocket-python-1.0.7.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "437f937baeb36afef739b6f6bb83f42b", "sha256": "be575f50510e35cff73ad6c9f12dd0f0ed9b37013118b9d06d22c3fa9e726947" }, "downloads": -1, "filename": "msb_client_websocket_python-1.0.7-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "437f937baeb36afef739b6f6bb83f42b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25683, "upload_time": "2019-09-25T10:30:08", "url": "https://files.pythonhosted.org/packages/02/0c/e5f52b040c870746bd688ae6006f15c72e1a6c66a807b77b15ab2e07fb15/msb_client_websocket_python-1.0.7-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "feace42abc7263e3cdc3ddfb4ffe8dd2", "sha256": "7888de2733098254a4b2a968d0d228c527a9088a7199fd448dcb0e9565aef1d8" }, "downloads": -1, "filename": "msb-client-websocket-python-1.0.7.tar.gz", "has_sig": false, "md5_digest": "feace42abc7263e3cdc3ddfb4ffe8dd2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34160, "upload_time": "2019-09-25T10:30:10", "url": "https://files.pythonhosted.org/packages/5f/59/a47d5620a40e42132323bcb1a9002c8c9a9cf88f2897af17f2dfb8fbdf59/msb-client-websocket-python-1.0.7.tar.gz" } ] }