{ "info": { "author": "Raphael Apfeldorfer", "author_email": "raphael.apfeldorfer@actility.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# pyThingPark\n\nPython implementation of LoRaWAN standard and ThingPark Wireless tunnel API\n\n## Installation\nPyThingPark doesn't support Python2 in order to keep maintenance to the minimum. \nTo install Python3, refer to [https://www.python.org/downloads](https://www.python.org/downloads/)\n\nTo implement LoRaWAN MIC calculation and encryption, pyThingPark make use of Python standard cryptographic library `cryptography`.\n\npyThingPark is packaged and distributed on pip\n```\npip3 install pyThingPark\n```\n\nTo compile a .whl built distribution file + tar.gz source, and upload on PyPi, please refer to [Python Package instructions](https://packaging.python.org/tutorials/packaging-projects/#generating-distribution-archives)\n\n## Functionalities\nThis package is implemented as a library and contains no executable file. This is meant to help the analysis of LoRaWAN messages as well as the implementation of Application Server integrating with ThingPark Wireless via the tunnel interface.\n\n### lorawan.py: Python loRaWAN implementation\n***lorawan.py*** implements all LoRaWAN message types: JoinRequest, JoinAccept, UlUnconfFrame, DlUnconfFrame, UlConfFrame, DlConfFrame as objects.\n\nMessages can be create with the `__init__` method by providing all sub-fields, or by importing directly the Physical Payload displayed in Actility LRC logs.\nFor example,\n\n 17:33:32.472 [DET] (lrc-lora-0) [LoRa.c:927] LoRaMAC_UpLink '0001000171ac293df0bd2d6e6645d32301e2e2f98f810f'\n 17:33:32.472 [DET] (lrc-lora-0) [join.c:3651] Join Request AppEUI: 90dffb0000000000 DevEUI:90dffbbd5813c019 DevNonce:2d2c\ncan be imported as a JoinRequest message for analysis with the following command:\n\n >>> from lorawan import JoinRequest\n >>> jr = JoinRequest.fromPayload(\"0001000171ac293df0bd2d6e6645d32301e2e2f98f810f\")\n >>> jr\n {'MessageType': 'JoinReq', 'MACVersion': '1.0', 'PHYPayload': '0001000171ac293df0bd2d6e6645d32301e2e2f98f810f', 'JoinEUI': 'f03d29ac71010001', 'DevEUI': '0123d345666e2dbd', 'DevNonce': 'e2e2', 'MIC': 'f98f810f'}\nand MIC can be verified by providing AppKey as an input:\n\n >>> jr.computeMIC(AppKey=\"28125FFD247F3D933834B4A2862CE05D\")\n 'f98f810f'\nJoinAccept is automatically decrypted if provided in encrypted form via `fromPayload` method (and AppKey is mandatory in this case)\n\n >>> from lorawan import JoinAccept\n >>> JoinAccept.fromPayload(\"2051b239de5da07db5a8844c4714488cf116815975a04e70bf86282ed11eaa5289\", \"28125FFD247F3D933834B4A2862CE05D\")\n {'MessageType': 'JoinAns', 'MACVersion': '1.0', 'PHYPayload': '20096095020000d07e94052301184f84e85684b85e84886684586e8400a782a999', 'JoinNonce': '956009', 'NetId': '000002', 'DevAddr': '05947ed0', 'DLSettings': '23', 'RxDelay': '01', 'CFList': '00846e58846688845eb88456e8844f18', 'MIC': 'a782a999'}\n\n### device.py: Python LoRaWAN key derivation implementation\n***device.py*** implements LW1.0 key derivation functions, making it simple to check session keys are computed correctly on the device after receiving the JoinAccept.\n\nExample code:\n\n >>> d = Device(\"FFFFFFAA00AC7000\",\"FFFFFFBB00000000\",\"037407b0a2eb121d99b2ad03b605af3a\",None,None)\n >>> jr = lorawan.JoinRequest.fromPayload(\"0x0000000000bbffffff0070ac00aaffffffc3f5d6de8f3e\")\n >>> ja = lorawan.JoinAccept.fromPayload(\"202573C61502E510C4802CEE5C076A6D9C1329A8F89689BA77BFE13F5A7CD15809\",d.AppKey)\n >>> print(d.deriveKeys(ja.JoinNonce, ja.NetId, jr.DevNonce))\n ('6f10ae090fd5f6ecf0a8e37638abb2da', 'a172e9f886f3835f3f7ebaa51a658b19')\n\n### uplinkTunnel.py: Python ThingParkWireless tunnel implementation\nThis part of the library aims at providing a reference to integrate AS with TP Wireless with security options enabled.\n\n`DevEUI_uplink`decodes TPW document as XML or JSON form, and provide ability to decrypt payload in case it is sent encrypted by TPW (SSM or HSM mode):\n\n >>> uplink = DevEUI_uplink(\"0123D345666E2DBD1121afac18845bbe3771708042dcdcc1f500000127-65.00000012.5000009G1LC31C000146F043.6407817.017418C000146F0-65.00000012.500000-65.237602100118249{'alr':{'pro':'LORA/Generic','ver':'1'}}0439d42627c5afe3d4d536340646621a202019-08-05T17:33:51.362+02:0070.0000000.00000005947ED0006000716.0000001\")\n >>> ASTK = \"dbfb0939c448ff1fbf84e84d6ac8ce98\"\n >>> uplink.decryptPayload(ASTK)\n\n`UplinkTunnel` take HTTP query params as an extra input, and can compute or verify the UL security token (taking Transport Interface Application Key TIAK as input)\n\n >>> query_params = 'AS_ID=sink&LrnFPort=1&Time=2019-04-29T18:21:17.290+02:00&Token=d306f33c239a9c45d160e0cd6e4071e22a4f4b426f892a0651cf622e81369f3d&LrnDevEui=0024AEB3C02BE1C4&LrnInfos=TWA_100122002.8962.AS-1-4458785'\n >>> TIAK = 'bec499c69e9c939e413b663961636c61'\n >>> tunnel = UplinkTunnel(uplink, query_params,TIAK)\n >>> expectedToken = tunnel.token()\n\n### dxMaker.py: Python DX maker wrapper\n***dxMaker.py*** is a Python wrapper using [DX API](https://dx-api.thingpark.com/maker/latest/api/).\nIt can be used to simply provision devices in ThingPark Activation on TP labs instance.\n\nIn order to use DX, you must first get a bearer token for authentication.\nThis can be done using `DxAdmin` class with necessary credentials:\n\n >>> dx = DxAdmin(\"my-account@acme.fr\", \"a_clever_password\", platform=\"js-labs-api\")\n >>> bearerToken = dx.getBearerToken()\n\nOnce a bearer token is available (it can of course also be generated directly on [DX Admin](https://dx-api.thingpark.com/admin/latest/swagger-ui/index.html?shortUrl=tpdx-admin-api-contract.json)), you can use it to create a `DxMaker`instance and create FactoryDevice on TP Labs via DX:\n\n >>> bearerToken = \"bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJTVUJTQ1JJQkVSOjEwMDAwMDA4NSJdLCJleHAiOjE1Njk4MzM4NTMsImp0aSI6ImM4ZGI4Y2RmLTcxNGYtNGE3OS1hNGZiLTI0OWYxNWVhMGIxYiIsImNsaWV94FDpZCI6ImpzLWxhYnMtYXBpL3JhcGhhZWwuYXBmZWxkb3JmZXItanMtbGFicy1zdWJAYWN0aWxpdHkuY29tIn0.KQaDUlrp6lcPJU9Gz5Re25WlHzMvIW75aef1oECCBGMOcIw9u_I7SyyZOMp1K9-AuJOY60DyfXLnVMIm_3CWaw\"\n >>> dx = dxMaker.DxMaker(bearerToken)\n >>> device = dxMaker.FactoryDevice(DevEUI=my.devEUI, JoinEUI=my.joinEUI, TkmInfo=my.tkmInfo)\n >>> dx.postFactoryDevice(device)\n >>> dx.deleteFactoryDevice(device.deviceJson[\"deviceEUI\"])\n\nA simple `FactoryDevice` class is provided to store device information necessary for the Join Server, and only Microchip ECC608 provisioning is supported for now. Only pre-commissioning of the Join Server is supported in this version, so no ASTK handling is implemented in the wrapper.\n\n## Extending the package\nFuture development may include\n* Complete implementation of remaining LoRaWAN messages\n* Decoding of MAC commands\n* LoRaWAN1.0.4 / Class B\n* LoRaWAN1.1\n* Downlink messages\n\nThis package is implemented as a library, Each function implementation is validated in the `main` part as a set of `assert` so we can easily test non-regressions.\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/actility/pyThingPark", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "pyThingPark", "package_url": "https://pypi.org/project/pyThingPark/", "platform": "", "project_url": "https://pypi.org/project/pyThingPark/", "project_urls": { "Homepage": "https://github.com/actility/pyThingPark" }, "release_url": "https://pypi.org/project/pyThingPark/0.0.4/", "requires_dist": [ "cryptography" ], "requires_python": ">=3.6", "summary": "Python tools for ThingPark", "version": "0.0.4", "yanked": false, "yanked_reason": null }, "last_serial": 6014024, "releases": { "0.0.2": [ { "comment_text": "", "digests": { "md5": "89ce3c712ea5d1e78f6eb99331018d95", "sha256": "c406ca71d64800a689e7fbdcf119f513f554186a42f208fa4a4b4c3f011b37dd" }, "downloads": -1, "filename": "pyThingPark-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "89ce3c712ea5d1e78f6eb99331018d95", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 17792, "upload_time": "2019-10-07T09:14:12", "upload_time_iso_8601": "2019-10-07T09:14:12.112960Z", "url": "https://files.pythonhosted.org/packages/c0/0c/91d59c52dd94ad6277297278dc61b91082d91ee06e0689b24a78b89e0737/pyThingPark-0.0.2-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "adacb743e226377781c44825e048e487", "sha256": "e453a8930960f06493ffa810590283fdc9a85a38d980b75a5e19a8d29a6570f9" }, "downloads": -1, "filename": "pyThingPark-0.0.2.tar.gz", "has_sig": false, "md5_digest": "adacb743e226377781c44825e048e487", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17075, "upload_time": "2019-10-07T09:14:14", "upload_time_iso_8601": "2019-10-07T09:14:14.918216Z", "url": "https://files.pythonhosted.org/packages/88/7e/1a05573b39f558717817bde6baf717abfe4114f68cc1abe3058610684dc4/pyThingPark-0.0.2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "d24bf4c1d09f7c487703481507c094b2", "sha256": "6ed02d666246d221dc7b5b4eebb995a109163b5d959c2f50d961dd234d7ce07c" }, "downloads": -1, "filename": "pyThingPark-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "d24bf4c1d09f7c487703481507c094b2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 17841, "upload_time": "2019-10-08T10:19:47", "upload_time_iso_8601": "2019-10-08T10:19:47.525383Z", "url": "https://files.pythonhosted.org/packages/30/1a/e57e59665103d8c2d53322bb33aaa6df0da425c88ac653418e191e168a7f/pyThingPark-0.0.3-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "f1a8cf194e0073902ec9f112bc33bbf5", "sha256": "57acfeb6b83c615883570be2e0076f944c871c23b4d085a220e948b6943a8908" }, "downloads": -1, "filename": "pyThingPark-0.0.3.tar.gz", "has_sig": false, "md5_digest": "f1a8cf194e0073902ec9f112bc33bbf5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17148, "upload_time": "2019-10-08T10:19:49", "upload_time_iso_8601": "2019-10-08T10:19:49.674665Z", "url": "https://files.pythonhosted.org/packages/16/90/a8f38131691ee36201f5dcf0ad368c0b78aee77fb202fdfac897017487d6/pyThingPark-0.0.3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "5e3297fef888c83a52bf4d4341be1e88", "sha256": "be550c82f290e8e311634e28d04af8b60bb9d799f3556db5588bbbb728b54282" }, "downloads": -1, "filename": "pyThingPark-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "5e3297fef888c83a52bf4d4341be1e88", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 17913, "upload_time": "2019-10-22T16:51:17", "upload_time_iso_8601": "2019-10-22T16:51:17.982812Z", "url": "https://files.pythonhosted.org/packages/2d/b6/0a9d074549d437d100e18372c24abe93badc3febb56308d6d054512ae344/pyThingPark-0.0.4-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "cf54e6b3da75cf5d6b9774f70382b96b", "sha256": "9f741be670bbcda456bc1d46953aaea1945587c12f7967ea2fc53ca12f84005c" }, "downloads": -1, "filename": "pyThingPark-0.0.4.tar.gz", "has_sig": false, "md5_digest": "cf54e6b3da75cf5d6b9774f70382b96b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17206, "upload_time": "2019-10-22T16:51:20", "upload_time_iso_8601": "2019-10-22T16:51:20.203816Z", "url": "https://files.pythonhosted.org/packages/6b/0f/f71914578ac29b543a1002f15934fbc686284ba9cea93ce44804c855339a/pyThingPark-0.0.4.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "5e3297fef888c83a52bf4d4341be1e88", "sha256": "be550c82f290e8e311634e28d04af8b60bb9d799f3556db5588bbbb728b54282" }, "downloads": -1, "filename": "pyThingPark-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "5e3297fef888c83a52bf4d4341be1e88", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 17913, "upload_time": "2019-10-22T16:51:17", "upload_time_iso_8601": "2019-10-22T16:51:17.982812Z", "url": "https://files.pythonhosted.org/packages/2d/b6/0a9d074549d437d100e18372c24abe93badc3febb56308d6d054512ae344/pyThingPark-0.0.4-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "cf54e6b3da75cf5d6b9774f70382b96b", "sha256": "9f741be670bbcda456bc1d46953aaea1945587c12f7967ea2fc53ca12f84005c" }, "downloads": -1, "filename": "pyThingPark-0.0.4.tar.gz", "has_sig": false, "md5_digest": "cf54e6b3da75cf5d6b9774f70382b96b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17206, "upload_time": "2019-10-22T16:51:20", "upload_time_iso_8601": "2019-10-22T16:51:20.203816Z", "url": "https://files.pythonhosted.org/packages/6b/0f/f71914578ac29b543a1002f15934fbc686284ba9cea93ce44804c855339a/pyThingPark-0.0.4.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }