{ "info": { "author": "WolkAbout", "author_email": "info@wolkabout.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only", "Topic :: Communications", "Topic :: Internet", "Topic :: Software Development :: Embedded Systems" ], "description": "# WolkGatewayModule-SDK-Python\n\nPython 3 package for connecting devices to WolkAbout IoT Platform through [WolkGateway](https://github.com/Wolkabout/WolkGateway).\n\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) [![Documentation Status](https://readthedocs.org/projects/wolkgatewaymodule-sdk-python/badge/?version=latest)](https://wolkgatewaymodule-sdk-python.readthedocs.io/en/latest/?badge=latest) [![PyPI version](https://badge.fury.io/py/wolk-gateway-module.svg)](https://badge.fury.io/py/wolk-gateway-module) ![GitHub](https://img.shields.io/github/license/Wolkabout/WolkGatewayModule-SDK-Python.svg?style=flat-square) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/wolk-gateway-module.svg?style=flat-square)\n\n----\nThis package is meant to be used for developing WolkGateway modules that enable devices without IP connectivity to send their data to WolkAbout IoT Platform.\n\n![WolkGateway Architecture](https://github.com/Wolkabout/WolkGatewayModule-SDK-Python/blob/master/docs/source/wolkabout_gateway_module.gif)\n\nThe user is responsible for providing the custom implementation that usually contains the device\u2019s network communication protocol, as well as for providing the business logic and everything related to the used hardware and the specifics of their particular use case.\n\nHowever, all the communication that is directed towards the gateway through WolkConnect - BUS Handler is already provided with this package, an open source implementation written in Python 3.7 that uses the MQTT protocol over TCP/IP to communicate with [WolkGateway](https://github.com/Wolkabout/WolkGateway).\n\n## Requirements\n\n* Python 3.7\n\nAll requirements for this project can be installed on Debian based systems by invoking:\n```console\nsudo apt-get install python3.7 python3-pip && python3 -m pip install pip && python3.7 -m pip install pip\n```\n\n## Installation\n\nThe project can be installed using Python's package manager pip:\n```console\nsudo python3.7 -m pip install wolk-gateway-module\n```\n\nor installed from source by cloning the repository and running:\n\n```console\nsudo python3.7 -m pip install -r requirements.txt\npython3.7 setup.py install\n```\n\n\n## Example Usage\n\n### Creating devices\n\n```python\nimport wolk_gateway_module as wolk\n\n# Create device sensors\n\n# Use data_type parameter where reading type & unit symbol are not important\ngeneric_sensor = wolk.SensorTemplate(\n name=\"Generic sensor\",\n reference=\"G\", # References must be unique per device\n data_type=wolk.DataType.NUMERIC,\n description=\"Optional description\",\n minimum=0, # Optional minimum value\n maximum=100, # Optional maximum value\n)\ntemperature_sensor = wolk.SensorTemplate(\n name=\"Temperature\",\n reference=\"T\",\n reading_type_name=wolk.ReadingTypeName.TEMPERATURE,\n unit=wolk.ReadingTypeMeasurementUnit.CELSIUS,\n minimum=-20,\n maximum=85,\n description=\"Temperature sensor with range -20 to 85 Celsius\",\n)\n# Create a device template used to register the device\ndevice_template = wolk.DeviceTemplate(\n sensors=[generic_sensor, temperature_sensor]\n)\n# Create a device\ndevice = wolk.Device(\n name=\"Device\",\n key=\"DEVICE_KEY\", # Unique device key\n template=device_template\n)\n```\n\n### Establishing connection with WolkGateway\n\n```python\n# Implement a device status provider\n\n\ndef get_device_status(device_key: str) -> wolk.DeviceStatus:\n \"\"\"Return current device status.\"\"\"\n if device_key == \"DEVICE_KEY\":\n # Handle getting current device status here\n return wolk.DeviceStatus.CONNECTED\n\n\nwolk_module = wolk.Wolk(\n host=\"localhost\", # Host address of WolkGateway\n port=1883, # TCP/IP port used for WolkGateway's MQTT broker\n module_name=\"Python module\", # Used for connection authentication\n device_status_provider=get_device_status,\n)\n\nwolk_module.connect()\n```\n\n### Disconnecting from WolkGateway\n\n```python\nwolk_module.disconnect()\n```\n\n### Adding devices\n\nDevices need to be registered on the Platform before their data is considered valid.\nThis is achieved by calling:\n```python\nwolk_module.add_device(device)\n```\nTo stop listening for commands for a specific device use:\n```python\nwolk_module.remove_device(device)\n```\nThis will only stop acknowledging inbound commands, to delete the device completely use WolkGateway or the web application, depending on who has control over devices.\n\n### Publishing device status\nDevice status is obtained by calling provided `device_status_provider` function\n```python\nwolk_module.publish_device_status(\"DEVICE_KEY\")\n```\n\n### Adding sensor readings\n\n```python\nwolk_module.add_sensor_reading(\"DEVICE_KEY\", \"REFERENCE\", \"value\")\n# For reading with data size > 1, like location or acceleration use tuples\nwolk_module.add_sensor_reading(\"DEVICE_KEY\", \"LOC\", (24.534, -34.325))\n# Add timestamps to store when reading occurred to preserve history, otherwise\n# Platform will assign timestamp when it receives the reading\nwolk_module.add_sensor_reading(\"KEY\", \"R\", 12, int(round(time.time() * 1000)))\n```\n\nThis method will put serialized messages in storage.\n\n### Publishing stored messages\n\n```python\nwolk_module.publish() # Publish all stored messages\nwolk_module.publish(\"DEVICE_KEY\") # Publish all stored messages for device\n```\n\n### Alarms\n```python\nhumidity_alarm = wolk.AlarmTemplate(\n name=\"High Humidity\",\n reference=\"HH\",\n description=\"High humidity has been detected\"\n)\ndevice_template = wolk.DeviceTemplate(alarms=[humidity_alarm])\n\n# Create device, Wolk instance, add device, connect...\n\n# Will place alarm message into storage, use publish method to send\nwolk_module.add_alarm(\"DEVICE_KEY\", \"HH\", active=True, timestamp=None)\n```\n\n### Actuators\n\nIn order to control device actuators, provide an `actuation_handler` and `actuator_status_provider`.\n\n```python\nswitch_actuator = wolk.ActuatorTemplate(\n name=\"Switch\",\n reference=\"SW\",\n data_type=wolk.DataType.BOOLEAN,\n description=\"Light switch\",\n)\nslider_actuator = wolk.ActuatorTemplate(\n name=\"Slider\",\n reference=\"SL\",\n data_type=wolk.DataType.NUMERIC,\n minimum=0,\n maximum=100,\n description=\"Light dimmer\",\n)\ndevice_template = wolk.DeviceTemplate(\n actuators=[switch_actuator, slider_actuator]\n)\ndevice = wolk.Device(\"Device\", \"DEVICE_KEY\", device_template)\n\n\ndef handle_actuation(\n device_key: str, reference: str, value: Union[bool, int, float, str]\n) -> None:\n \"\"\"\n Set device actuator identified by reference to value.\n\n Must be implemented as non blocking.\n Must be implemented as thread safe.\n \"\"\"\n if device_key == \"DEVICE_KEY\":\n if reference == \"SW\":\n # Handle setting the value here\n switch.value = value\n\n elif reference == \"SL\":\n slider.value = value\n\n\ndef get_actuator_status(\n device_key: str, reference: str\n) -> Tuple[wolk.ActuatorState, Union[bool, int, float, str]]:\n \"\"\"\n Get current actuator status identified by device key and reference.\n\n Reads the status of actuator from the device\n and returns it as a tuple containing the actuator state and current value.\n\n Must be implemented as non blocking.\n Must be implemented as thread safe.\n \"\"\"\n if device_key == \"DEVICE_KEY\":\n if reference == \"SW\":\n # Handle getting current actuator value here\n return wolk.ActuatorState.READY, switch.value\n\n elif reference == \"SL\":\n return wolk.ActuatorState.READY, slider.value\n\n\n# Pass functions to Wolk instance\nwolk_module = wolk.Wolk(\n host=\"localhost\",\n port=1883,\n module_name=\"Python module\",\n device_status_provider=get_device_status,\n actuation_handler=handle_actuation,\n actuator_status_provider=get_actuator_status,\n)\n\nwolk_module.add_device(device)\n\nwolk_module.connect()\n\n# This method will call the provided actuator_status_provider function\n# and publish the state immediately or store message if unable to publish\nwolk_module.publish_actuator_status(\"DEVICE_KEY\", \"SW\")\nwolk_module.publish_actuator_status(\"DEVICE_KEY\", \"SL\")\n```\n\n### Configurations\n\nSimilar to actuators, using device configuration options requires providing a `configuration_handler` and a `configuration_provider` to the `Wolk` instance.\n\n```python\nlogging_level_configuration = wolk.ConfigurationTemplate(\n name=\"Logging level\",\n reference=\"LL\",\n data_type=wolk.DataType.STRING,\n default_value=\"INFO\",\n description=\"eg. Set device logging level\",\n)\nlogging_interval_configuration = wolk.ConfigurationTemplate(\n name=\"Logging interval\",\n reference=\"LI\",\n data_type=wolk.DataType.NUMERIC,\n size=3,\n labels=[\"seconds\", \"minutes\", \"hours\"],\n description=\"eg. Set logging intervals\",\n)\ndevice_template = wolk.DeviceTemplate(\n configurations=[logging_level_configuration, logging_level_configuration]\n)\ndevice = wolk.Device(\"Device\", \"DEVICE_KEY\", device_template)\n\n\ndef get_configuration(\n device_key: str\n) -> Dict[\n str,\n Union[\n int,\n float,\n bool,\n str,\n Tuple[int, int],\n Tuple[int, int, int],\n Tuple[float, float],\n Tuple[float, float, float],\n Tuple[str, str],\n Tuple[str, str, str],\n ],\n]:\n \"\"\"\n Get current configuration options.\n\n Reads device configuration and returns it as a dictionary\n with device configuration reference as key,\n and device configuration value as value.\n Must be implemented as non blocking.\n Must be implemented as thread safe.\n \"\"\"\n if device_key == \"DEVICE_KEY\":\n # Handle getting configuration values here\n return {\n \"LL\": get_log_level(),\n \"LI\": get_log_inteval(),\n }\n\n\ndef handle_configuration(\n device_key: str,\n configuration: Dict[\n str,\n Union[\n int,\n float,\n bool,\n str,\n Tuple[int, int],\n Tuple[int, int, int],\n Tuple[float, float],\n Tuple[float, float, float],\n Tuple[str, str],\n Tuple[str, str, str],\n ],\n ],\n) -> None:\n \"\"\"\n Change device's configuration options.\n\n Must be implemented as non blocking.\n Must be implemented as thread safe.\n \"\"\"\n if device_key == \"DEVICE_KEY\":\n for reference, value in configuration.items():\n # Handle setting configuration values here\n if reference == \"LL\":\n set_log_level(value)\n elif reference == \"LI\":\n set_log_interval(value)\n\n\n# Pass functions to Wolk instance\nwolk_module = wolk.Wolk(\n host=\"localhost\",\n port=1883,\n module_name=\"Python module\",\n device_status_provider=get_device_status,\n configuration_provider=get_configuration,\n configuration_handler=handle_configuration,\n)\n\nwolk_module.add_device(device)\n\nwolk_module.connect()\n\n# This method will call the provided configuration_provider function\n# and publish the state immediately or store message if unable to publish\nwolk_module.publish_configuration(\"DEVICE_KEY\")\n```\n\n### Firmware update\nIn order to enable firmware update for devices, provide an implementation of `FirmwareHandler` and pass to `Wolk` instance.\n\n```python\n\ndevice_template = wolk.DeviceTemplate(supports_firmware_update=True)\ndevice = wolk.Device(\"Device\", \"DEVICE_KEY\", device_template)\n\n\nclass FirmwareHandlerImplementation(wolk.FirmwareHandler):\n \"\"\"Handle firmware installation and abort commands, and report version.\n\n Once an object of this class is passed to a Wolk object,\n it will set callback methods `on_install_success` and\n `on_install_fail` used for reporting the result of\n the firmware update process. Use these callbacks in `install_firmware`\n and `abort_installation` methods.\"\"\"\n\n def install_firmware(\n self, device_key: str, firmware_file_path: str\n ) -> None:\n \"\"\"\n Handle the installation of the firmware file.\n\n Call `self.on_install_success(device_key)` to report success.\n Reporting success will also get new firmware version.\n\n If installation fails, call `self.on_install_fail(device_key, status)`\n where:\n `status = FirmwareUpdateStatus(\n FirmwareUpdateState.ERROR,\n FirmwareUpdateErrorCode.INSTALLATION_FAILED\n )`\n or use other values from `FirmwareUpdateErrorCode` if they fit better.\n \"\"\"\n if device_key == \"DEVICE_KEY\":\n print(\n f\"Installing firmware: '{firmware_file_path}' \"\n f\"on device '{device_key}'\"\n )\n # Handle the actual installation here\n if install_success:\n self.on_install_success(device_key)\n else:\n status = wolk.FirmwareUpdateStatus(\n wolk.FirmwareUpdateState.ERROR,\n wolk.FirmwareUpdateErrorCode.INSTALLATION_FAILED,\n )\n self.on_install_fail(device_key, status)\n\n def abort_installation(self, device_key: str) -> None:\n \"\"\"\n Attempt to abort the firmware installation process for device.\n\n Call `self.on_install_fail(device_key, status)` to report if\n the installation process was able to be aborted with\n `status = FirmwareUpdateStatus(FirmwareUpdateState.ABORTED)`\n If unable to stop the installation process, no action is required.\n \"\"\"\n if device_key == \"DEVICE_KEY\":\n # Manage to stop firmware installation\n status = wolk.FirmwareUpdateStatus(\n wolk.FirmwareUpdateState.ABORTED\n )\n self.on_install_fail(device_key, status)\n\n def get_firmware_version(self, device_key: str) -> str:\n \"\"\"Return device's current firmware version.\"\"\"\n if device_key == \"DEVICE_KEY\":\n # Handle getting the current firmware version here\n return version\n\n\nwolk_module = wolk.Wolk(\n host=\"localhost\",\n port=1883,\n module_name=\"Python module\",\n device_status_provider=get_device_status,\n firmware_handler=FirmwareHandlerImplementation(),\n)\n\nwolk_module.add_device(device)\n\nwolk_module.connect()\n```\n\n### Debugging\n\nEnable debug logging with:\n```python\nwolk.logging_config(\"debug\", log_file=None)\n```\n\n### Data persistence\n\nData persistence mechanism used **by default** stored messages in-memory.\nIn cases when provided in-memory persistence is suboptimal, it it possible to use custom persistence by implementing `OutboundMessageQueue` and passing it in the following manner:\n```python\nwolk_module = wolk.Wolk(\n host=\"localhost\",\n port=1883,\n module_name=\"Python module\",\n device_status_provider=get_device_status,\n outbound_message_queue=CustomPersistence()\n)\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://github.com/Wolkabout/WolkGatewayModule-SDK-Python", "keywords": "IoT,WolkAbout,Internet of Things", "license": "Apache License 2.0", "maintainer": "", "maintainer_email": "", "name": "wolk-gateway-module", "package_url": "https://pypi.org/project/wolk-gateway-module/", "platform": "", "project_url": "https://pypi.org/project/wolk-gateway-module/", "project_urls": { "Homepage": "https://github.com/Wolkabout/WolkGatewayModule-SDK-Python" }, "release_url": "https://pypi.org/project/wolk-gateway-module/1.0.4/", "requires_dist": [ "paho-mqtt (==1.4.0)" ], "requires_python": "", "summary": "SDK for gateway communication modules that connect to WolkAbout IoT Platform", "version": "1.0.4" }, "last_serial": 5540692, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "7721b6db8e84b91e6576a48af7cac45a", "sha256": "3b360c4eaa03873189a9eeb7d47462b99f8c3ad2b1504d0fcefd92b5c9db0712" }, "downloads": -1, "filename": "wolk_gateway_module-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "7721b6db8e84b91e6576a48af7cac45a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 71934, "upload_time": "2019-05-24T12:37:46", "url": "https://files.pythonhosted.org/packages/58/b1/ea851c2085f0ec932bb6c301f7d6c788bb3f99bb9eed4696ad9ebc23af39/wolk_gateway_module-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b67d7961c50c23e6101b7977d9d8e72f", "sha256": "adea55e518295e291714e3f316929602e2ed2ed28a2e89416768f72f73b39a01" }, "downloads": -1, "filename": "wolk-gateway-module-1.0.0.tar.gz", "has_sig": false, "md5_digest": "b67d7961c50c23e6101b7977d9d8e72f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44736, "upload_time": "2019-05-24T12:37:49", "url": "https://files.pythonhosted.org/packages/b9/32/6974cef4b6b883c43f12cdedaec3354f9c65e03f8fa620cc1470f5228a7a/wolk-gateway-module-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "12403485206d710c24630d976cfadaad", "sha256": "1c46cc71a6293afb09f66d06967c611115bf2d623681bcccd8323d5936b6a5ee" }, "downloads": -1, "filename": "wolk_gateway_module-1.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "12403485206d710c24630d976cfadaad", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 72109, "upload_time": "2019-05-30T14:25:31", "url": "https://files.pythonhosted.org/packages/de/6d/269804b5bba14afee6f1d3cb4885afd64adf5a3f8fe93511eacb99bcb47e/wolk_gateway_module-1.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1718c4f9a60e2fb4579334e5e2dbb785", "sha256": "1f9d14f416775542f9f5e1ca9c822016ac50529f1277380d7fdf6bcbf99d2ea0" }, "downloads": -1, "filename": "wolk-gateway-module-1.0.1.tar.gz", "has_sig": false, "md5_digest": "1718c4f9a60e2fb4579334e5e2dbb785", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45104, "upload_time": "2019-05-30T14:25:33", "url": "https://files.pythonhosted.org/packages/02/d7/1280ca1741fb215671a4e766acb48cdb6033995a5fcd652cbc84a46f2c59/wolk-gateway-module-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "672f6720d6a8d307e8e27fde89f2f404", "sha256": "b6ef52766ca0476d4b580136d8fb4c723c540ad86596a5936a651f52eb944344" }, "downloads": -1, "filename": "wolk_gateway_module-1.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "672f6720d6a8d307e8e27fde89f2f404", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 72219, "upload_time": "2019-06-03T11:57:09", "url": "https://files.pythonhosted.org/packages/e2/0c/159831990f46a79e73323ab2a2eb25a196df0ddedaa85fd7ddeb4f2661f1/wolk_gateway_module-1.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ca2bb72bb31ef5c1ccaa60f6734ab0e2", "sha256": "c59342565c0db381bdc5d9ff27a3488f909bda9b0588c5d065afa533e627a2b8" }, "downloads": -1, "filename": "wolk-gateway-module-1.0.2.tar.gz", "has_sig": false, "md5_digest": "ca2bb72bb31ef5c1ccaa60f6734ab0e2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45346, "upload_time": "2019-06-03T11:57:12", "url": "https://files.pythonhosted.org/packages/1e/4a/5ebb22fb0d8c99301edd506a7e18dd15318179b5783f7a68f4167abbc986/wolk-gateway-module-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "adb9245d90b9a07d039c95576a4e407b", "sha256": "006039ed29975f9202956060870378d93921daaf27b199de7559eb56412f9b00" }, "downloads": -1, "filename": "wolk_gateway_module-1.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "adb9245d90b9a07d039c95576a4e407b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 72731, "upload_time": "2019-06-04T13:02:25", "url": "https://files.pythonhosted.org/packages/41/a1/9cb2f5cf082e15298db3ed417ea4861000bc9223753bed5454de233c22c7/wolk_gateway_module-1.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1bfe9614689cbffd5d1bd75a14aba505", "sha256": "08f0a2c1465c6d82ce37dbe578554a57fb6465d2405552e1f46c6923ab6345bc" }, "downloads": -1, "filename": "wolk-gateway-module-1.0.3.tar.gz", "has_sig": false, "md5_digest": "1bfe9614689cbffd5d1bd75a14aba505", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46214, "upload_time": "2019-06-04T13:02:28", "url": "https://files.pythonhosted.org/packages/b5/38/26573f181189de4f9abddc47d605b71a236204c45335616d53bbd7033820/wolk-gateway-module-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "938614d069cbd216e49a27024ffead7a", "sha256": "2ccc227babc2de6711efe6a6489f0d4509f15776e567004cfe1e4a0814eccfc0" }, "downloads": -1, "filename": "wolk_gateway_module-1.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "938614d069cbd216e49a27024ffead7a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 72725, "upload_time": "2019-07-16T13:54:18", "url": "https://files.pythonhosted.org/packages/96/23/9ba59eb5d03533342970a1cb487fef16fdb62abb8736063b3d428e0b00d4/wolk_gateway_module-1.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "90b2a17f5a93a3b56dcdab59b5e9e887", "sha256": "35d8a531f0b9d3a896c97f70f9b96057c6b460227fe8cd7eac4e065596ea00c7" }, "downloads": -1, "filename": "wolk-gateway-module-1.0.4.tar.gz", "has_sig": false, "md5_digest": "90b2a17f5a93a3b56dcdab59b5e9e887", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46220, "upload_time": "2019-07-16T13:54:20", "url": "https://files.pythonhosted.org/packages/9e/90/0111d95acffac1eac7d4e08df73e443f6e177c48013f13bc50059ba032d5/wolk-gateway-module-1.0.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "938614d069cbd216e49a27024ffead7a", "sha256": "2ccc227babc2de6711efe6a6489f0d4509f15776e567004cfe1e4a0814eccfc0" }, "downloads": -1, "filename": "wolk_gateway_module-1.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "938614d069cbd216e49a27024ffead7a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 72725, "upload_time": "2019-07-16T13:54:18", "url": "https://files.pythonhosted.org/packages/96/23/9ba59eb5d03533342970a1cb487fef16fdb62abb8736063b3d428e0b00d4/wolk_gateway_module-1.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "90b2a17f5a93a3b56dcdab59b5e9e887", "sha256": "35d8a531f0b9d3a896c97f70f9b96057c6b460227fe8cd7eac4e065596ea00c7" }, "downloads": -1, "filename": "wolk-gateway-module-1.0.4.tar.gz", "has_sig": false, "md5_digest": "90b2a17f5a93a3b56dcdab59b5e9e887", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46220, "upload_time": "2019-07-16T13:54:20", "url": "https://files.pythonhosted.org/packages/9e/90/0111d95acffac1eac7d4e08df73e443f6e177c48013f13bc50059ba032d5/wolk-gateway-module-1.0.4.tar.gz" } ] }