├── .gitignore ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── README.rus.md ├── gen_crt.sh ├── img ├── postman_addr.png ├── postman_conn.png ├── postman_new_ws.png ├── running.png ├── wifi.png └── work.png ├── pics ├── client.png ├── connect.png ├── esp_echo.png ├── hard_reset.png ├── server_echo.png └── sync_project.png ├── requirements.txt ├── server.py └── src ├── boot.py ├── config.json ├── main.py ├── main_f ├── __init__.py └── func.py └── pymakr.conf /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | tls/ 132 | 133 | ESP*.bin 134 | src/*.der 135 | src/*.pem 136 | src/*.crt 137 | src/*.key 138 | server.ext -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | micropy-cli = "*" 8 | esptool = "*" 9 | websockets = "*" 10 | mpremote = "*" 11 | 12 | [dev-packages] 13 | 14 | [requires] 15 | python_version = "3.10" 16 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "879aecbaac7fa16fdcb277639eb3be2c1ceed263087941deca9f2f8df2fbb4df" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.10" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "argcomplete": { 20 | "hashes": [ 21 | "sha256:65b3133a29ad53fb42c48cf5114752c7ab66c1c38544fdf6460f450c09b42591", 22 | "sha256:d0519b1bc867f5f4f4713c41ad0aba73a4a5f007449716b16f385f2166dc6adf" 23 | ], 24 | "markers": "sys_platform != 'win32'", 25 | "version": "==3.6.2" 26 | }, 27 | "async-timeout": { 28 | "hashes": [ 29 | "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", 30 | "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" 31 | ], 32 | "markers": "python_version < '3.11'", 33 | "version": "==4.0.3" 34 | }, 35 | "attrs": { 36 | "hashes": [ 37 | "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", 38 | "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015" 39 | ], 40 | "markers": "python_version >= '3.7'", 41 | "version": "==23.1.0" 42 | }, 43 | "autoflake": { 44 | "hashes": [ 45 | "sha256:3ae7495db9084b7b32818b4140e6dc4fc280b712fb414f5b8fe57b0a8e85a840", 46 | "sha256:c98b75dc5b0a86459c4f01a1d32ac7eb4338ec4317a4469515ff1e687ecd909e" 47 | ], 48 | "markers": "python_version >= '3.8'", 49 | "version": "==2.3.1" 50 | }, 51 | "beautifulsoup4": { 52 | "hashes": [ 53 | "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", 54 | "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195" 55 | ], 56 | "markers": "python_full_version >= '3.7.0'", 57 | "version": "==4.13.4" 58 | }, 59 | "bitarray": { 60 | "hashes": [ 61 | "sha256:01482b80f618987de4e250274e054c905af59201ee49a74ac5145d8572dca9e1", 62 | "sha256:03c39938b375d4728cd6c14d425eb34867c35babfd45732dbcc60a549a8d637b", 63 | "sha256:051fe461440eaeb303b04f2e35373cfb7db644c488c3852a9ee9129bf07c9dcf", 64 | "sha256:05a4529d4cf17493b33cfea0d8923cba640e048962e9ea10ba0a4d312fedc6b8", 65 | "sha256:07f8a786eb1e36afd9826c7e559d1698a4469f06eb0bda5379fab495bee5a269", 66 | "sha256:0811939f0bfbe09d2db2011e95f711caca0bbb7c8e50f67d5797a82c45383307", 67 | "sha256:0a8a8380d06c79b1c5e22c2db16bf057a2189d192ae93f04ef8f9ccd7dc01481", 68 | "sha256:0aad91dcfbf8bea3ad97b337672fd465972461772548950a426249f550e66921", 69 | "sha256:0d9621b6969acbd60ea92632774fe50453984aadcc9369fc72927c8a9fe428f3", 70 | "sha256:1231eb0b49ad745f775ea63fae84271c5d4f0791d80bdd9e2404a526590aea16", 71 | "sha256:133fbab2968ddb2089222d16128aea86087f2eda49d77929bcbb84c529903a3d", 72 | "sha256:18cdc11f306df9181d1b4c6518dfc7069d755b033b685c7a472d8cf8d6aedd62", 73 | "sha256:1c6f3718d37e1e3e2a524cdb8d5fa5fe8cdf04f0ed71691e4bb0a244323e3700", 74 | "sha256:1fef2337b74c83713e46e7060a7f9d4a1799bde33509bbde8eac5bd4f8e6d848", 75 | "sha256:2107b87318e7c965fc9ea2d516fe9d8c10c8c157a0c7eec5c6d16b9ac3e0ccd5", 76 | "sha256:21fcb013cb9b1d4d46072a2ec6c380c7999b3cecd401ccf4aac2fef3ab398caf", 77 | "sha256:22036b501e5f91e9ab336dbf5edabab9e10c0f7ad51416191069d231ffcafb96", 78 | "sha256:27d429d9279ef729692dd5e808188778f1a973a487f5351730728aa0f8456a60", 79 | "sha256:2916a52ce97a80926f7bbc6170ac5b8a15f61fa560be5083fe12e0feb2c66ae1", 80 | "sha256:29aeabffa38aae43f714312c5af887ac430c15f0f6da1c14492d11e96a1b4c98", 81 | "sha256:2b0817dc6954d716468d30db82546285b3a89774698d518db581d886bf8cbf65", 82 | "sha256:2d8a134cd28693c309b2622f0b63f86038347dc8c4c34d590f76b188b17866af", 83 | "sha256:2dafea29a7c53be59cb7b64f5d1c2f6a56ba418fff541e8b8b19a88fed998ca1", 84 | "sha256:2e1cf5c3326b2a1ba455fd438e5a8dcf408fcd69814a8ba00eaf7861b566ebe8", 85 | "sha256:33169e078512e2ab0306e92b499c1ccfe9c37548c1aee75e1695fc4141e23357", 86 | "sha256:336bd5cba10dfa440d2a3e65fc916b766a9d2cf221840567370a0a59f8801e06", 87 | "sha256:33de53df262517bf7dc7adb4c84bd0387edfe0bcc237235a780bf21400627abf", 88 | "sha256:36525e897c2fef06947c91dd153b8b8c147eabb96ace927fd806039f65e4833a", 89 | "sha256:37bb92e74067316a62a8b5de360c7f2991858986549714da8d88587f49a427ec", 90 | "sha256:3bc21c1cc3c7b08e06107839433b0b7f85b410c0866a5c1327f19353602716b6", 91 | "sha256:3dce6fdc46840124ca7ba8aa86eb0f2fd0964c21d5abbebd47e63252fd7bd6e5", 92 | "sha256:3e32ebd79190d55cf7d177dc4f349ba5457ab2d12b2e4937de4f2b6e9147e4ca", 93 | "sha256:425d7f947f328d5638e029d3da27892c7018e534aaeeef15c07c7cdc59a7bf77", 94 | "sha256:42a1de62751d115fa1a8bb7e410eb072a3e339a2e61fb65230b76da3586362c5", 95 | "sha256:42fa967c295007833a52a88ff6d41877aeed2d9a90f30e0998c684261432c55c", 96 | "sha256:46e60a4fb5ce262032d4a01e68ccc4a07bfb82434fba3743d29a658e44cddeae", 97 | "sha256:473510778a6d94488685425db363beae885d74d383cb61a05cc9c566ac9a5470", 98 | "sha256:47eee592d135ca78b831cabb5967e3a6b614ad1e44e78e789395008c24347ea3", 99 | "sha256:4acedcc2ff904a9798d34659053d7158f0d74b230b7d417783362a6ef33e891f", 100 | "sha256:4b9ec350463367fe8bc24a896cea9b221e21e5e91220659d46d083e6f6e67ace", 101 | "sha256:5037843b68d79279b3b3ac1e35014fe050d66e36f0771a75bfe89d9164638b7f", 102 | "sha256:51426d9b59e0e8a83fcba0cbb841e2a9e5a568f1ac08fa8b296d58746b395999", 103 | "sha256:537ff43f156c7f89445fc0249a7e75629087ca7ad2da2de22d8ba8c227bc8caa", 104 | "sha256:57d61ab68631fab95777772a40c1a315dc018e84acc8b5043c588aaff07b1b9f", 105 | "sha256:57fad2cbc851c209798a6b3b8c78e95e9475da7c3666ee592863d24f0ddc38e2", 106 | "sha256:59e34652ea8b69b6d927fd183c24bde3130cf999342fcf891e86b987b5c399e9", 107 | "sha256:5d35a57c6656475d5fbac60103af41b336018cf5e69ff7b8dcbd7c203ca62db8", 108 | "sha256:5d8c489da9208119d5e164e9605ff5937c5fb00aa5d90a28925571cb88b24db9", 109 | "sha256:5e4d425eb6a203f6e13ffc9af653d200da8d4400ac840a4ac5526eab7ba9531b", 110 | "sha256:5ecc01600beff9cec9711da18e15a783d96a0f0fccf66f131b231ed0d9c0c556", 111 | "sha256:5fd2aad6341d8900299e3af500a6c4f92e3cd9262ab41f19bd280b4ae74450c6", 112 | "sha256:61aed5ce5ab6019b3b3edb7e184b7e9a51a39ca966379ed5325bf9b0e825f549", 113 | "sha256:63971b6a68bf313f0091dba13ff65d037279a5c4cbb63382e4b0f6d3c8550368", 114 | "sha256:6407849448baeead1adef13d1e4449223d7d08558c40918d7e4f07e53aa138cd", 115 | "sha256:652e115afd311a3ffdc9603e39a99fd7fbd32c1ae816c9834ffad5363c2574fa", 116 | "sha256:65c9fb683b1df351d16b00d0d0b6f0dda84c1c05d22d62c63bb13dc59c124170", 117 | "sha256:676d22dd740ac84d9a92717f2607039aa1f4315cb55a967c45c70f354b98cf0d", 118 | "sha256:6801402e5dc0acf5d0f541d2cefa3dcf26559d5707d600b0d6a8bfbd765ac033", 119 | "sha256:6897992cacebe06954672a6fd3211ce018fbf3ac5df46606eab72604b30afb73", 120 | "sha256:6c55ecb81880658bcdec83168429cebb0457c6cf95f3ab04d3f70b9fb0456aeb", 121 | "sha256:6c7c82c6e7bec0e5be7340dce51607f8658aca5cae8b7a98afb5abac1c565301", 122 | "sha256:6cdb841c6bdab7cefbef32d98be845e2366d12b86e547d44ef3409f2993019a0", 123 | "sha256:6d60fbaed377021083d3617cd70d164ec676dd8d76adc1c15e6e21ae39244811", 124 | "sha256:6e4681317279b3bfbe22344e65558b894f15480c629b0490aae98654df84b06e", 125 | "sha256:6f6de79345f98f85bf0bd41e0f2946c7f37fd6212791f2f7f24c3ae74e31fee7", 126 | "sha256:6f9a74f5e8422cee4a180a5603c0d43d56b68b963cb6ccc286d917060a65695c", 127 | "sha256:70e9228830b3fcfffb18719aa78e0b8f3d724db300fb9009fc24b6f66969823e", 128 | "sha256:70ea3cff990ff9087c95c306d4ec51c7113a3ab02899ea3dc1ee46be62fabcbb", 129 | "sha256:74b7b306c93520b50252fa1b4e2d93de5455f6be1b3d2a4b0aec0ecd3eb8b009", 130 | "sha256:7a8e66e4ea7413edee3953139cb8a92c2a028a56532364bf05dcafc311a0de54", 131 | "sha256:7da29e6056d5b4575399f6e378e6a37751d7dd7eaa2566a2775b703ec2663978", 132 | "sha256:7e1508f85c857fa62dd881b1657faefc62eefb9baba8e5f0f2feca7f72a7580e", 133 | "sha256:8013109b3f798b872c30d700710bdc98a1be964d801d050dc95f3e2cd1ecd65c", 134 | "sha256:802cde1b3619a3981e440c5dc98f4feb7e843f7fbb1f2fa679585c531a0348c5", 135 | "sha256:8117acd7e1d2a0c094ac4c054c7c0bb786a67208978ccec451a487485295fc88", 136 | "sha256:8225e99433efddccea1e4384430bb56583a2972443c789544be962b2a682c335", 137 | "sha256:84a3e3d9f0ce1ba23152d170cc0c60c13c11f9868fe967055427f8b9c35a743e", 138 | "sha256:8553bfa6c2f940d7ded09acd3e4b84f333ab9fc36154cb624488878fc9ec713d", 139 | "sha256:88136ae424ce92052bc6774001fc455b9d76a509c7a44bb933004b23b02ceecf", 140 | "sha256:8a361f348a277c3769ff3f4e4a10b7743cacc35e1a8a26f4c5fc3025b42a9874", 141 | "sha256:8e4f6f272a1a30b8f4a3bfb5af6264f3d0baaf2c508157c9efabf4553a390c42", 142 | "sha256:9004c94170d1193fcac217829cd969318b723b7ad8befc84f30bd8396716f662", 143 | "sha256:900faf30692c2ec8f4d5c44d3c5bc074b6ec85a20fb670a9f0959edb0bdc1cfe", 144 | "sha256:91e24383bfc4d0c6c9d993424c5c99a85e8c40b567449573b90decd43d488888", 145 | "sha256:938559bb457966f9bae5b7ff64a5ee9d0450c0cdce0b63ff9b7e8ca50131c514", 146 | "sha256:95e9ee9cc9bde08a25b89cf5b9c8fa1abb90ceba737c3f397cfc89e5ea49a441", 147 | "sha256:9c514698cf295c105721889102e2433e0162c7cf7b89c1d9b4154a28b06352f4", 148 | "sha256:a5fe86ca5918944d267b1f09d81dd77cd7b450ff06ba9f2c006e51d340e33979", 149 | "sha256:a67b33a39ba2859568068a1cc51da879c7d858d87748636ccb30f656a33031b7", 150 | "sha256:a78e17a0b6e9085002e94ba1f881aae9ce75c2d0e900928eb287a44ac3e47226", 151 | "sha256:a955e61d29fed54861d747fa5d66226b499310d5f9a9a91e4bbc5a5ca3f82481", 152 | "sha256:b0139e8c8e5ac269308ebaf55c67d1f32226815c90905c890fafbd1ce70925cc", 153 | "sha256:b120d9258db731483bafa0c38bb0b5c3f2aeab505d6e83d42d4fcd6f22a32622", 154 | "sha256:b80224aac62267461e9cd06a7db4fd6a283cd257ca5cd19f9db830b63cebd289", 155 | "sha256:b8b253d8c7779c7ab33fce8a401fee06aa378244ca235f110deaa09679a16535", 156 | "sha256:b8c149bd5a3b239cc0cf4989bfa297e1e1bb89bea0736050a01a7eb9db014a6d", 157 | "sha256:b8fdc8c53543ddabb989d984f84c43c5c12f323c519d748cf55032e9435d73ee", 158 | "sha256:bac783ce6238ef439280b4818f6ac7024d8783f8f198587383401a660365c588", 159 | "sha256:bda0b77877f8ee47776c1358217ebe9c196a0028f8903218d55e673f2d1606f1", 160 | "sha256:be54d2786f74217e9774cdcf79a5444727fcb73801ce44a87f3956970632a639", 161 | "sha256:c30333686e54dbea97d2425710eafff4e24c5b432e192cb33c66235487c6ac3d", 162 | "sha256:c63efd2f7bba854feeef7562f6ba6e7b8f48c9a4800c4ee4455d75d9ca02613f", 163 | "sha256:c8c5a195b3a9707bde47bf2a2f8a20af01293ffe475cd3fd53b63f0f5ae5bae5", 164 | "sha256:cc51292edc2fd90f059d83fba29551fc7de999029c6306bfc6965df6dd97c35c", 165 | "sha256:d0f97332151cf24876db2a301812643c2b047cde8d2393cea36f96684967beb4", 166 | "sha256:d21b8a74b765435588688d0514776402acc17032827056bea9995f43d9150ea2", 167 | "sha256:d401eaa20bbd4a102c7bbe31fe555f6702403a3ee768b97cd4c44d35f01df17c", 168 | "sha256:d52d6841bf564cd7624e0216b0efb27b57a15a8587b5b53ad71eee186e2ac769", 169 | "sha256:d5ad3049a928a29e01c415dec260d36f55795b2203f26d02cc47844748d86279", 170 | "sha256:d5f8ea6460051ce8923cabbae42f9af1837e10ae795c2febb5e79e2ffca6fa1b", 171 | "sha256:d91ef222a9f2072641b58682bed68a20a09ce955b39932da4cd06d96b40da735", 172 | "sha256:da9e87a91600fbc2442c869fb66a4d57d8dc248825af3c2ec4844a92aa3ffaca", 173 | "sha256:db08b35662a28ead0c8f75e330c7e2043ed255b1f9412201769ff63f24db48f7", 174 | "sha256:dbd1f60c4685dba1ab521f24864683288b8975abc6d0d12764399d1ec6744594", 175 | "sha256:ddb68688be910188e62ee888391557f74e11c6b19c91f24844c6ec7c633fe427", 176 | "sha256:df566fa4ac42001d3158cc1b7842ff092249641c14edd673fb7ce7188a10ee6b", 177 | "sha256:e6cac01fa6f458777f8daf556ff78b8f058ed2c00c7d4fdc18e4bbab7fe9c6cd", 178 | "sha256:e6d9780f1e62aba1d024dfcf2248abb585f401fade8f447ce4b735b1b78cdd52", 179 | "sha256:e91ddcdf4075de26234ae74b60cdd39e170e3e4fafa1c593ecc28749e9b165e2", 180 | "sha256:eb8d9c7a17609cee20dca8e44af182edcbdaad2a753ff3d5a2e9a1407028a2a7", 181 | "sha256:ec9e5e3c3ff3ff15b8cd5c1d2592d12a4b721d333e6ec5d6af3c141769887a6f", 182 | "sha256:ecac62be9653729df4d37a3556160297452801c87efbc0698004e03f0d28cbdb", 183 | "sha256:edc0e8f49bd094cbd1d19be22e24869b9183948a5b8f47e63e0269b8edcfa96c", 184 | "sha256:f0b90482f03e26a763922adc2a11ec87841832c305bb76eb2b6ea8c8e731431a", 185 | "sha256:f0cf0501df82a767df00a073b28fbbde44048aab80d71c5e6e21745bf830422c", 186 | "sha256:f1846ff7c71e7c0bbc0c054b64110652c7aea8753ceb32902d58dc08d3c9574c", 187 | "sha256:f1cb4c1ce2cd7f7fde3d84c83b3892429bc953ad23d539919dbae798bfebb134", 188 | "sha256:f26ca11c44274cd9e7cec01b37c17d80335fb4f7f9111f57685881f0b7eb4702", 189 | "sha256:f35f915aa9079bf488c518c6379a4ba1304c24d845ad735c20df73cc116b478d", 190 | "sha256:f73bc95ac3afebc5e1c6236a8c20b31089860f55ef633fd4e28ca85e21938827", 191 | "sha256:f7b3d0d9022d782978a3a630f4aadc57d999c0bd60238131ddf31f27ceac8a2c", 192 | "sha256:f9a65c63884bf32814860d23591068bfaa04c9c3dfd5d44d0c3e07cc166dd767", 193 | "sha256:fc51920d0961ced44fc3937286e9057f8a0d10cbb274fb6dd342cb58ab61b60b", 194 | "sha256:fefebc0f40dec700f3b1d4172336ac109061cd7340a6f21bd091042077c23346" 195 | ], 196 | "version": "==3.3.2" 197 | }, 198 | "bitstring": { 199 | "hashes": [ 200 | "sha256:69d1587f0ac18dc7d93fc7e80d5f447161a33e57027e726dc18a0a8bacf1711a", 201 | "sha256:a08bc09d3857216d4c0f412a1611056f1cc2b64fd254fb1e8a0afba7cfa1a95a" 202 | ], 203 | "markers": "python_version >= '3.8'", 204 | "version": "==4.3.1" 205 | }, 206 | "black": { 207 | "hashes": [ 208 | "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320", 209 | "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351", 210 | "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350", 211 | "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f", 212 | "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf", 213 | "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148", 214 | "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4", 215 | "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d", 216 | "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc", 217 | "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d", 218 | "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2", 219 | "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f" 220 | ], 221 | "markers": "python_version >= '3.7'", 222 | "version": "==22.12.0" 223 | }, 224 | "bleak": { 225 | "hashes": [ 226 | "sha256:6c92a47abe34e6dea8ffc5cea9457cbff6e1be966854839dbc25cddb36b79ee4", 227 | "sha256:ce3106b7258212d92bb77be06f9301774f51f5bbc9f7cd50976ad794e9514dba" 228 | ], 229 | "markers": "python_version >= '3.7' and python_version < '4.0'", 230 | "version": "==0.20.2" 231 | }, 232 | "bleak-sigspec": { 233 | "hashes": [ 234 | "sha256:0a7b68909773a05429ceaaeaf10964a24d2df53dd40f17c35a0f96071ac927c7", 235 | "sha256:4e5e9372aa135756bbf52c5a4982aaa6e62ef21e00aeb87f4752ef05288a05f4" 236 | ], 237 | "version": "==0.0.4" 238 | }, 239 | "boltons": { 240 | "hashes": [ 241 | "sha256:8c50a71829525835ca3c849c7ed2511610c972b4dddfcd41a4a5447222beb4b0", 242 | "sha256:f716a1b57698a5b19062f3146cb5ce3549904028a2f267c2c0cf584eea3ad75b" 243 | ], 244 | "version": "==23.0.0" 245 | }, 246 | "cachetools": { 247 | "hashes": [ 248 | "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", 249 | "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a" 250 | ], 251 | "markers": "python_version >= '3.7'", 252 | "version": "==5.5.2" 253 | }, 254 | "cachier": { 255 | "hashes": [ 256 | "sha256:383564e514b5fcf6aa1a714afb73cf6cca71552d442f2c699246ca97a7aef343", 257 | "sha256:b24eb049d8871a191fe3096cacc9ec7aa4d5aac7fe16fd6c41cff4ad7d1e2d32" 258 | ], 259 | "version": "==2.0.0" 260 | }, 261 | "certifi": { 262 | "hashes": [ 263 | "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", 264 | "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3" 265 | ], 266 | "markers": "python_version >= '3.6'", 267 | "version": "==2025.4.26" 268 | }, 269 | "cffi": { 270 | "hashes": [ 271 | "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", 272 | "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", 273 | "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", 274 | "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", 275 | "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", 276 | "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", 277 | "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", 278 | "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", 279 | "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", 280 | "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", 281 | "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", 282 | "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", 283 | "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", 284 | "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", 285 | "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", 286 | "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", 287 | "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", 288 | "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", 289 | "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", 290 | "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", 291 | "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", 292 | "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", 293 | "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", 294 | "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", 295 | "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", 296 | "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", 297 | "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", 298 | "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", 299 | "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", 300 | "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", 301 | "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", 302 | "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", 303 | "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", 304 | "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", 305 | "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", 306 | "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", 307 | "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", 308 | "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", 309 | "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", 310 | "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", 311 | "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", 312 | "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", 313 | "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", 314 | "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", 315 | "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", 316 | "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", 317 | "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", 318 | "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", 319 | "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", 320 | "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", 321 | "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", 322 | "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", 323 | "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", 324 | "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", 325 | "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", 326 | "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", 327 | "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", 328 | "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", 329 | "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", 330 | "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", 331 | "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", 332 | "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", 333 | "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", 334 | "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", 335 | "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", 336 | "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", 337 | "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" 338 | ], 339 | "markers": "platform_python_implementation != 'PyPy'", 340 | "version": "==1.17.1" 341 | }, 342 | "charset-normalizer": { 343 | "hashes": [ 344 | "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4", 345 | "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45", 346 | "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", 347 | "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", 348 | "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", 349 | "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", 350 | "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d", 351 | "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", 352 | "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184", 353 | "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", 354 | "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b", 355 | "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64", 356 | "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", 357 | "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", 358 | "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", 359 | "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344", 360 | "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58", 361 | "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", 362 | "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471", 363 | "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", 364 | "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", 365 | "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836", 366 | "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", 367 | "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", 368 | "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", 369 | "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1", 370 | "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01", 371 | "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", 372 | "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58", 373 | "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", 374 | "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", 375 | "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2", 376 | "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a", 377 | "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597", 378 | "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", 379 | "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5", 380 | "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb", 381 | "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f", 382 | "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", 383 | "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", 384 | "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", 385 | "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", 386 | "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7", 387 | "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7", 388 | "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455", 389 | "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", 390 | "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4", 391 | "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", 392 | "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3", 393 | "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", 394 | "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", 395 | "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", 396 | "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", 397 | "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", 398 | "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", 399 | "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", 400 | "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12", 401 | "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa", 402 | "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", 403 | "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", 404 | "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f", 405 | "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", 406 | "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", 407 | "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5", 408 | "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02", 409 | "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", 410 | "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", 411 | "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e", 412 | "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", 413 | "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", 414 | "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", 415 | "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", 416 | "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681", 417 | "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba", 418 | "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", 419 | "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a", 420 | "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", 421 | "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", 422 | "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", 423 | "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", 424 | "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027", 425 | "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7", 426 | "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518", 427 | "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", 428 | "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", 429 | "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", 430 | "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", 431 | "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da", 432 | "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", 433 | "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f", 434 | "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", 435 | "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f" 436 | ], 437 | "markers": "python_version >= '3.7'", 438 | "version": "==3.4.2" 439 | }, 440 | "click": { 441 | "hashes": [ 442 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", 443 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" 444 | ], 445 | "markers": "python_version >= '3.7'", 446 | "version": "==8.1.3" 447 | }, 448 | "colorama": { 449 | "hashes": [ 450 | "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", 451 | "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" 452 | ], 453 | "version": "==0.4.6" 454 | }, 455 | "cryptography": { 456 | "hashes": [ 457 | "sha256:02f55fb4f8b79c1221b0961488eaae21015b69b210e18c386b69de182ebb1259", 458 | "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43", 459 | "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645", 460 | "sha256:21a83f6f35b9cc656d71b5de8d519f566df01e660ac2578805ab245ffd8523f8", 461 | "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44", 462 | "sha256:3883076d5c4cc56dbef0b898a74eb6992fdac29a7b9013870b34efe4ddb39a0d", 463 | "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f", 464 | "sha256:3be3f649d91cb182c3a6bd336de8b61a0a71965bd13d1a04a0e15b39c3d5809d", 465 | "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54", 466 | "sha256:479d92908277bed6e1a1c69b277734a7771c2b78633c224445b5c60a9f4bc1d9", 467 | "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137", 468 | "sha256:5639c2b16764c6f76eedf722dbad9a0914960d3489c0cc38694ddf9464f1bb2f", 469 | "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c", 470 | "sha256:5d186f32e52e66994dce4f766884bcb9c68b8da62d61d9d215bfe5fb56d21334", 471 | "sha256:5d20cc348cca3a8aa7312f42ab953a56e15323800ca3ab0706b8cd452a3a056c", 472 | "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b", 473 | "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2", 474 | "sha256:896530bc9107b226f265effa7ef3f21270f18a2026bc09fed1ebd7b66ddf6375", 475 | "sha256:962bc30480a08d133e631e8dfd4783ab71cc9e33d5d7c1e192f0b7c06397bb88", 476 | "sha256:978631ec51a6bbc0b7e58f23b68a8ce9e5f09721940933e9c217068388789fe5", 477 | "sha256:9b4d4a5dbee05a2c390bf212e78b99434efec37b17a4bff42f50285c5c8c9647", 478 | "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c", 479 | "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359", 480 | "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5", 481 | "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d", 482 | "sha256:c138abae3a12a94c75c10499f1cbae81294a6f983b3af066390adee73f433028", 483 | "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01", 484 | "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904", 485 | "sha256:cad399780053fb383dc067475135e41c9fe7d901a97dd5d9c5dfb5611afc0d7d", 486 | "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93", 487 | "sha256:dad80b45c22e05b259e33ddd458e9e2ba099c86ccf4e88db7bbab4b747b18d06", 488 | "sha256:dd3db61b8fe5be220eee484a17233287d0be6932d056cf5738225b9c05ef4fff", 489 | "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76", 490 | "sha256:e909df4053064a97f1e6565153ff8bb389af12c5c8d29c343308760890560aff", 491 | "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759", 492 | "sha256:fc3c9babc1e1faefd62704bb46a69f359a9819eb0292e40df3fb6e3574715cd4", 493 | "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053" 494 | ], 495 | "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", 496 | "version": "==44.0.3" 497 | }, 498 | "dbus-fast": { 499 | "hashes": [ 500 | "sha256:05d53e0db08de6b3ba43eb110e01b9e6264e7143849ea9772af45b15575c21b2", 501 | "sha256:08ca9968dd46b854e5c7b00be32cb273edaf17ddc9647811ff63ae3b9dca822d", 502 | "sha256:17d743d13dbde0691adb98f1a6c87f0cf5617a4c9169b4820972dc8869095c6b", 503 | "sha256:26045c50bbd8c1674814759332333799b073216b2b2cac9e1cfebf757c7f926d", 504 | "sha256:3277944b418063ad051e8e49144151962691188b972f1fbca7af39fdef4f8a47", 505 | "sha256:331c4a26e010fd8ad3168b9680f39a7d0765507d3aadcbe5f250da0474877f14", 506 | "sha256:33cee333a15241e516ee84aaabdd952dbb1a63f9e986028574451475e97a113f", 507 | "sha256:3dd64c5cd362ceead6cc02603b6b4cbda58b2cbb6ec816a2f21b1901dfc3cb61", 508 | "sha256:3ffcd1c999599da7806d7887d5ce1e9f0d814aa35af92daecab542c9b70794c1", 509 | "sha256:43093d8e42342841c7ac69e236370c31949c35b659032888dae8b3af1fa35e9e", 510 | "sha256:4e73b7dcbac5f418bd4b334ad112e40e8b3bc05c53a3fc451926450ce3bb805e", 511 | "sha256:4f4b26849254fafb11656fc8c10f8bce67deab683694e0fc7b56edd891d4e118", 512 | "sha256:5c5d344e3fe3c4b16593fad70448c66ca3130c8c692c74a921c15f18650581a7", 513 | "sha256:5f653085d9f96ed2e48434ba951cf4bf0229cc273a87b9799e7cf3a9a6612a56", 514 | "sha256:69f19fb94ac714b917c51fcc329b51695f085f779841edd6e429170f1f073f47", 515 | "sha256:6dfd99cf624f769cf838e62d75ceb737b2866b1783a4f11a928cf38e4c906a5f", 516 | "sha256:76fb9d11bd6ebe1f832350ec57ada352f096f24b5731e38bcbad86ab9b27190b", 517 | "sha256:7aee30619c79334980a25a1e94299a751b3f276644ec0a69c76bfe57be184e7a", 518 | "sha256:85739b90e6f983494c3c7187d4daaa50f4f4369aa1e87e876066de97ca1bcd58", 519 | "sha256:9180d4d39d8688b9d8d43f427f0f2883354fa9df18a1f46d14f1762b82249d1f", 520 | "sha256:9706e10a6c24d4c03d28b1631e3882009964d5207a86cae2b42466635d7546be", 521 | "sha256:99902ca6c10368492fdf5a28321d86c7e92e50fd742f0163599602c442232d29", 522 | "sha256:aefa695088405d313c703790ac503ad0b2ac1e4807393f1f02e410b6984aedd0", 523 | "sha256:b842e94140e39a196d4d83e02eddcbc461b906871ba02f1c5374055f2d628c47", 524 | "sha256:bd68b5e7d7c6cd10d804d072062100a4893ad0c19bdac03b53b1809c51a4e3c7", 525 | "sha256:c3241252a744b0960e7eb9dcad2892af2bc695b4f47636bab2f17f6012d914ce", 526 | "sha256:c71e84a7ce3b050745dfb2bcd32ade891ecf6f4b06d3baa4dfe30ad09720a0be", 527 | "sha256:cab158bcf86c4b2e03c2f3453738a61de83c82cbed11f23331ccc9a9aba6d5b1", 528 | "sha256:e19173e65967581186666a47cd0af06111c7e957fb529198e532b35a47171460", 529 | "sha256:e2c107caefa186919169e07a852edea3d931dfb6112584fa2c6e5653d91c0d2d", 530 | "sha256:ea2692efe0d6d6d58fb427cd0ed53ab44ced0c2ada642b0c15fd139c60a706d6", 531 | "sha256:f52ef5edef41a0ed29645d7c6e1ee89b5e8f5e5c1ba9901699dcec9cfaf8d961", 532 | "sha256:fae11a8ed320013decd2bf6a982f010fff011bf935c4f32141e804ba7963719b", 533 | "sha256:ffd3665a6fbe318aadac998ae117b19214e0782397c86ab47792a120979783a6" 534 | ], 535 | "markers": "platform_system == 'Linux'", 536 | "version": "==1.95.2" 537 | }, 538 | "deprecated": { 539 | "hashes": [ 540 | "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", 541 | "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec" 542 | ], 543 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 544 | "version": "==1.2.18" 545 | }, 546 | "dill": { 547 | "hashes": [ 548 | "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", 549 | "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049" 550 | ], 551 | "markers": "python_version >= '3.8'", 552 | "version": "==0.4.0" 553 | }, 554 | "distlib": { 555 | "hashes": [ 556 | "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46", 557 | "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e" 558 | ], 559 | "version": "==0.3.6" 560 | }, 561 | "dpath": { 562 | "hashes": [ 563 | "sha256:496615b4ea84236d18e0d286122de74869a60e0f87e2c7ec6787ff286c48361b" 564 | ], 565 | "version": "==1.5.0" 566 | }, 567 | "ecdsa": { 568 | "hashes": [ 569 | "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3", 570 | "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61" 571 | ], 572 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 573 | "version": "==0.19.1" 574 | }, 575 | "esptool": { 576 | "hashes": [ 577 | "sha256:dc4ef26b659e1a8dcb019147c0ea6d94980b34de99fbe09121c7941c8b254531" 578 | ], 579 | "index": "pypi", 580 | "markers": "python_version >= '3.7'", 581 | "version": "==4.8.1" 582 | }, 583 | "gitdb": { 584 | "hashes": [ 585 | "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", 586 | "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf" 587 | ], 588 | "markers": "python_version >= '3.7'", 589 | "version": "==4.0.12" 590 | }, 591 | "gitpython": { 592 | "hashes": [ 593 | "sha256:8ce3bcf69adfdf7c7d503e78fd3b1c492af782d58893b650adb2ac8912ddd573", 594 | "sha256:f04893614f6aa713a60cbbe1e6a97403ef633103cdd0ef5eb6efe0deb98dbe8d" 595 | ], 596 | "markers": "python_version >= '3.7'", 597 | "version": "==3.1.31" 598 | }, 599 | "idna": { 600 | "hashes": [ 601 | "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", 602 | "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" 603 | ], 604 | "markers": "python_version >= '3.6'", 605 | "version": "==3.10" 606 | }, 607 | "intelhex": { 608 | "hashes": [ 609 | "sha256:87cc5225657524ec6361354be928adfd56bcf2a3dcc646c40f8f094c39c07db4", 610 | "sha256:892b7361a719f4945237da8ccf754e9513db32f5628852785aea108dcd250093" 611 | ], 612 | "version": "==2.3.0" 613 | }, 614 | "jinja2": { 615 | "hashes": [ 616 | "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", 617 | "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" 618 | ], 619 | "markers": "python_version >= '3.7'", 620 | "version": "==3.1.2" 621 | }, 622 | "jsonschema": { 623 | "hashes": [ 624 | "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163", 625 | "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a" 626 | ], 627 | "version": "==3.2.0" 628 | }, 629 | "libcst": { 630 | "hashes": [ 631 | "sha256:1069b808a711db5cd47538f27eb2c73206317aa0d8b5a3500b23aab24f86eb2e", 632 | "sha256:1312e293b864ef3cb4b09534ed5f104c2dc45b680233c68bf76237295041c781", 633 | "sha256:158478e8f45578fb26621b3dc0fe275f9e004297e9afdcf08936ecda05681174", 634 | "sha256:24582506da24e31f2644f862f11413a6b80fbad68d15194bfcc3f7dfebf2ec5e", 635 | "sha256:349f2b4ee4b982fe254c65c78d941fc96299f3c422b79f95ef8c7bba2b7f0f90", 636 | "sha256:3cb3b7821eac00713844cda079583230c546a589b22ed5f03f2ddc4f985c384b", 637 | "sha256:50be085346a35812535c7f876319689e15a7bfd1bd8efae8fd70589281d944b6", 638 | "sha256:5648aeae8c90a2abab1f7b1bf205769a0179ed2cfe1ea7f681f6885e87b8b193", 639 | "sha256:58fe90458a26a55358207f74abf8a05dff51d662069f070b4bd308a000a80c09", 640 | "sha256:5ed101fee1af7abea3684fcff7fab5b170ceea4040756f54c15c870539daec66", 641 | "sha256:72dff8783ac79cd10f2bd2fde0b28f262e9a22718ae26990948ba6131b85ca8b", 642 | "sha256:76884b1afe475e8e68e704bf26eb9f9a2867029643e58f2f26a0286e3b6e998e", 643 | "sha256:76adc53660ef094ff83f77a2550a7e00d1cab8e5e63336e071c17c09b5a89fe2", 644 | "sha256:7cfa4d4beb84d0d63247aca27f1a15c63984512274c5b23040f8b4ba511036d7", 645 | "sha256:7e1b4cbaf7b1cdad5fa3eababe42d5b46c0d52afe13c5ba4eac2495fc57630ea", 646 | "sha256:83ee7e7be4efac4c140a97d772e1f6b3553f98fa5f46ad78df5dfe51e5a4aa4d", 647 | "sha256:8cdf2d0157438d3d52d310b0b6be31ff99bed19de489b2ebd3e2a4cd9946da45", 648 | "sha256:8fa0ec646ed7bce984d0ee9dbf514af278050bdb16a4fb986e916ace534eebc6", 649 | "sha256:999fbbe467f61cbce9e6e054f86cd1c5ffa3740fd3dc8ebdd600db379f699256", 650 | "sha256:a10adc2e8ea2dda2b70eabec631ead2fc4a7a7ab633d6c2b690823c698b8431a", 651 | "sha256:a144f20aff4643b00374facf8409d30c7935db8176e5b2a07e1fd44004db2c1f", 652 | "sha256:a677103d2f1ab0e50bc3a7cc6c96c7d64bcbac826d785e4cbf5ee9aaa9fcfa25", 653 | "sha256:a8fdfd4a7d301adb785aa4b98e4a7cca45c5ff8cfb460b485d081efcfaaeeab7", 654 | "sha256:b1569d87536bed4e9c11dd5c94a137dc0bce2a2b05961489c6016bf4521bb7cf", 655 | "sha256:b98a829d96e8b209fb761b00cd1bacc27c70eae77d00e57976e5ae2c718c3f81", 656 | "sha256:bb9f10e5763e361e8bd8ff765fc0f1bcf744f242ff8b6d3e50ffec4dda3972ac", 657 | "sha256:bcbd07cec3d7a7be6f0299b0c246e085e3d6cc8af367e2c96059183b97c2e2fe", 658 | "sha256:cfeeabb528b5df7b4be1817b584ce79e9a1a66687bd72f6de9c22272462812f1", 659 | "sha256:e7acfa747112ae40b032739661abd7c81aff37191294f7c2dab8bbd72372e78f", 660 | "sha256:f3e9d9fdd9a9b9b8991936ff1c07527ce7ef396c8233280ba9a7137e72c2e48e" 661 | ], 662 | "markers": "python_version >= '3.7'", 663 | "version": "==0.4.10" 664 | }, 665 | "loguru": { 666 | "hashes": [ 667 | "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c", 668 | "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3" 669 | ], 670 | "markers": "python_version >= '3.5'", 671 | "version": "==0.6.0" 672 | }, 673 | "mailbits": { 674 | "hashes": [ 675 | "sha256:72cd08926b3d0276607a4441ed5a059c4526409d8db2d57e0a6b23996a000bf8", 676 | "sha256:9ddbfc65d7d7fc0a09b82a123cb480f21aa38b3f7ae58bf71a81b4399b3217d5" 677 | ], 678 | "markers": "python_version >= '3.8'", 679 | "version": "==0.2.2" 680 | }, 681 | "markdown-it-py": { 682 | "hashes": [ 683 | "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", 684 | "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" 685 | ], 686 | "markers": "python_version >= '3.8'", 687 | "version": "==3.0.0" 688 | }, 689 | "markupsafe": { 690 | "hashes": [ 691 | "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", 692 | "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", 693 | "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", 694 | "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", 695 | "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", 696 | "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", 697 | "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", 698 | "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", 699 | "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", 700 | "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", 701 | "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", 702 | "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", 703 | "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", 704 | "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", 705 | "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", 706 | "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", 707 | "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", 708 | "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", 709 | "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", 710 | "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", 711 | "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", 712 | "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", 713 | "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", 714 | "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", 715 | "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", 716 | "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", 717 | "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", 718 | "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", 719 | "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", 720 | "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", 721 | "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", 722 | "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", 723 | "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", 724 | "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", 725 | "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", 726 | "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", 727 | "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", 728 | "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", 729 | "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", 730 | "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", 731 | "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", 732 | "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", 733 | "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", 734 | "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", 735 | "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", 736 | "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", 737 | "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", 738 | "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", 739 | "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", 740 | "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", 741 | "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", 742 | "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", 743 | "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", 744 | "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", 745 | "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", 746 | "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", 747 | "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", 748 | "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", 749 | "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", 750 | "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" 751 | ], 752 | "markers": "python_version >= '3.7'", 753 | "version": "==2.1.3" 754 | }, 755 | "mdurl": { 756 | "hashes": [ 757 | "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", 758 | "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" 759 | ], 760 | "markers": "python_version >= '3.7'", 761 | "version": "==0.1.2" 762 | }, 763 | "micropy-cli": { 764 | "hashes": [ 765 | "sha256:0745af6bd260988357d5822fdbfce8a62fc7e090eff2d324a8d8e17143332818", 766 | "sha256:409fb0acb0414c804815c6592dc7481f2f22b4ee05833388390d0c866c4d05a5" 767 | ], 768 | "index": "pypi", 769 | "markers": "python_version < '3.12' and python_version >= '3.8'", 770 | "version": "==4.2.2" 771 | }, 772 | "micropython-stubber": { 773 | "hashes": [ 774 | "sha256:2a5a25b4d97fc3e6c0f048672efd72386c2c59a9c79515d8a6a309c9d822c3f0", 775 | "sha256:8fd66a045664f3419abc9cb68dc9308b88ca10db31750ff1ce86f9493869ba17" 776 | ], 777 | "markers": "python_version < '3.12' and python_version >= '3.8'", 778 | "version": "==1.13.7" 779 | }, 780 | "mpremote": { 781 | "hashes": [ 782 | "sha256:42691ff8f7ea4b5f2fc1b51de99609995d383671a4b4d4daad8cbd486d26aa23", 783 | "sha256:d0dcd8ab364d87270e1766308882e536e541052efd64aadaac83bc7ebbea2815" 784 | ], 785 | "index": "pypi", 786 | "markers": "python_version >= '3.4'", 787 | "version": "==1.25.0" 788 | }, 789 | "mypy": { 790 | "hashes": [ 791 | "sha256:023fe9e618182ca6317ae89833ba422c411469156b690fde6a315ad10695a521", 792 | "sha256:031fc69c9a7e12bcc5660b74122ed84b3f1c505e762cc4296884096c6d8ee140", 793 | "sha256:2de7babe398cb7a85ac7f1fd5c42f396c215ab3eff731b4d761d68d0f6a80f48", 794 | "sha256:2e93a8a553e0394b26c4ca683923b85a69f7ccdc0139e6acd1354cc884fe0128", 795 | "sha256:390bc685ec209ada4e9d35068ac6988c60160b2b703072d2850457b62499e336", 796 | "sha256:3a2d219775a120581a0ae8ca392b31f238d452729adbcb6892fa89688cb8306a", 797 | "sha256:3efde4af6f2d3ccf58ae825495dbb8d74abd6d176ee686ce2ab19bd025273f41", 798 | "sha256:4a99fe1768925e4a139aace8f3fb66db3576ee1c30b9c0f70f744ead7e329c9f", 799 | "sha256:4b41412df69ec06ab141808d12e0bf2823717b1c363bd77b4c0820feaa37249e", 800 | "sha256:4c8d8c6b80aa4a1689f2a179d31d86ae1367ea4a12855cc13aa3ba24bb36b2d8", 801 | "sha256:4d19f1a239d59f10fdc31263d48b7937c585810288376671eaf75380b074f238", 802 | "sha256:4e4a682b3f2489d218751981639cffc4e281d548f9d517addfd5a2917ac78119", 803 | "sha256:695c45cea7e8abb6f088a34a6034b1d273122e5530aeebb9c09626cea6dca4cb", 804 | "sha256:701189408b460a2ff42b984e6bd45c3f41f0ac9f5f58b8873bbedc511900086d", 805 | "sha256:70894c5345bea98321a2fe84df35f43ee7bb0feec117a71420c60459fc3e1eed", 806 | "sha256:8293a216e902ac12779eb7a08f2bc39ec6c878d7c6025aa59464e0c4c16f7eb9", 807 | "sha256:8d26b513225ffd3eacece727f4387bdce6469192ef029ca9dd469940158bc89e", 808 | "sha256:a197ad3a774f8e74f21e428f0de7f60ad26a8d23437b69638aac2764d1e06a6a", 809 | "sha256:bea55fc25b96c53affab852ad94bf111a3083bc1d8b0c76a61dd101d8a388cf5", 810 | "sha256:c9a084bce1061e55cdc0493a2ad890375af359c766b8ac311ac8120d3a472950", 811 | "sha256:d0e9464a0af6715852267bf29c9553e4555b61f5904a4fc538547a4d67617937", 812 | "sha256:d8e9187bfcd5ffedbe87403195e1fc340189a68463903c39e2b63307c9fa0394", 813 | "sha256:eaeaa0888b7f3ccb7bcd40b50497ca30923dba14f385bde4af78fac713d6d6f6", 814 | "sha256:f46af8d162f3d470d8ffc997aaf7a269996d205f9d746124a179d3abe05ac602", 815 | "sha256:f70a40410d774ae23fcb4afbbeca652905a04de7948eaf0b1789c8d1426b72d1", 816 | "sha256:fe91be1c51c90e2afe6827601ca14353bbf3953f343c2129fa1e247d55fd95ba" 817 | ], 818 | "markers": "python_version >= '3.7'", 819 | "version": "==1.2.0" 820 | }, 821 | "mypy-extensions": { 822 | "hashes": [ 823 | "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", 824 | "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558" 825 | ], 826 | "markers": "python_version >= '3.8'", 827 | "version": "==1.1.0" 828 | }, 829 | "netifaces": { 830 | "hashes": [ 831 | "sha256:043a79146eb2907edf439899f262b3dfe41717d34124298ed281139a8b93ca32", 832 | "sha256:08e3f102a59f9eaef70948340aeb6c89bd09734e0dca0f3b82720305729f63ea", 833 | "sha256:0f6133ac02521270d9f7c490f0c8c60638ff4aec8338efeff10a1b51506abe85", 834 | "sha256:18917fbbdcb2d4f897153c5ddbb56b31fa6dd7c3fa9608b7e3c3a663df8206b5", 835 | "sha256:2479bb4bb50968089a7c045f24d120f37026d7e802ec134c4490eae994c729b5", 836 | "sha256:2650beee182fed66617e18474b943e72e52f10a24dc8cac1db36c41ee9c041b7", 837 | "sha256:28f4bf3a1361ab3ed93c5ef360c8b7d4a4ae060176a3529e72e5e4ffc4afd8b0", 838 | "sha256:3ecb3f37c31d5d51d2a4d935cfa81c9bc956687c6f5237021b36d6fdc2815b2c", 839 | "sha256:469fc61034f3daf095e02f9f1bbac07927b826c76b745207287bc594884cfd05", 840 | "sha256:48324183af7f1bc44f5f197f3dad54a809ad1ef0c78baee2c88f16a5de02c4c9", 841 | "sha256:50721858c935a76b83dd0dd1ab472cad0a3ef540a1408057624604002fcfb45b", 842 | "sha256:54ff6624eb95b8a07e79aa8817288659af174e954cca24cdb0daeeddfc03c4ff", 843 | "sha256:5be83986100ed1fdfa78f11ccff9e4757297735ac17391b95e17e74335c2047d", 844 | "sha256:5f9ca13babe4d845e400921973f6165a4c2f9f3379c7abfc7478160e25d196a4", 845 | "sha256:73ff21559675150d31deea8f1f8d7e9a9a7e4688732a94d71327082f517fc6b4", 846 | "sha256:7dbb71ea26d304e78ccccf6faccef71bb27ea35e259fb883cfd7fd7b4f17ecb1", 847 | "sha256:815eafdf8b8f2e61370afc6add6194bd5a7252ae44c667e96c4c1ecf418811e4", 848 | "sha256:841aa21110a20dc1621e3dd9f922c64ca64dd1eb213c47267a2c324d823f6c8f", 849 | "sha256:84e4d2e6973eccc52778735befc01638498781ce0e39aa2044ccfd2385c03246", 850 | "sha256:8f7da24eab0d4184715d96208b38d373fd15c37b0dafb74756c638bd619ba150", 851 | "sha256:96c0fe9696398253f93482c84814f0e7290eee0bfec11563bd07d80d701280c3", 852 | "sha256:aab1dbfdc55086c789f0eb37affccf47b895b98d490738b81f3b2360100426be", 853 | "sha256:c03fb2d4ef4e393f2e6ffc6376410a22a3544f164b336b3a355226653e5efd89", 854 | "sha256:c37a1ca83825bc6f54dddf5277e9c65dec2f1b4d0ba44b8fd42bc30c91aa6ea1", 855 | "sha256:c92ff9ac7c2282009fe0dcb67ee3cd17978cffbe0c8f4b471c00fe4325c9b4d4", 856 | "sha256:c9a3a47cd3aaeb71e93e681d9816c56406ed755b9442e981b07e3618fb71d2ac", 857 | "sha256:cb925e1ca024d6f9b4f9b01d83215fd00fe69d095d0255ff3f64bffda74025c8", 858 | "sha256:d07b01c51b0b6ceb0f09fc48ec58debd99d2c8430b09e56651addeaf5de48048", 859 | "sha256:e76c7f351e0444721e85f975ae92718e21c1f361bda946d60a214061de1f00a1", 860 | "sha256:eb4813b77d5df99903af4757ce980a98c4d702bbcb81f32a0b305a1537bdf0b1" 861 | ], 862 | "version": "==0.11.0" 863 | }, 864 | "nodeenv": { 865 | "hashes": [ 866 | "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", 867 | "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9" 868 | ], 869 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", 870 | "version": "==1.9.1" 871 | }, 872 | "packaging": { 873 | "hashes": [ 874 | "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", 875 | "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" 876 | ], 877 | "markers": "python_version >= '3.6'", 878 | "version": "==21.3" 879 | }, 880 | "pathspec": { 881 | "hashes": [ 882 | "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", 883 | "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" 884 | ], 885 | "markers": "python_version >= '3.8'", 886 | "version": "==0.12.1" 887 | }, 888 | "pathtools": { 889 | "hashes": [ 890 | "sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0" 891 | ], 892 | "version": "==0.1.2" 893 | }, 894 | "pipx": { 895 | "hashes": [ 896 | "sha256:3933c43bb344e649cb28e10d357e0967ce8572f1c19caf90cf39ae95c2a0afaf", 897 | "sha256:762de134e16a462be92645166d225ecef446afaef534917f5f70008d63584360" 898 | ], 899 | "markers": "python_version >= '3.8'", 900 | "version": "==1.7.1" 901 | }, 902 | "platformdirs": { 903 | "hashes": [ 904 | "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94", 905 | "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351" 906 | ], 907 | "markers": "python_version >= '3.9'", 908 | "version": "==4.3.7" 909 | }, 910 | "portalocker": { 911 | "hashes": [ 912 | "sha256:80e984e24de292ff258a5bea0e4f3f778fff84c0ae1275dbaebc4658de4aacb3", 913 | "sha256:ec20f6dda2ad9ce89fa399a5f31f4f1495f515958f0cb7ca6543cef7bb5a749e" 914 | ], 915 | "markers": "python_version >= '3.9'", 916 | "version": "==3.1.1" 917 | }, 918 | "prompt-toolkit": { 919 | "hashes": [ 920 | "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", 921 | "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed" 922 | ], 923 | "markers": "python_version >= '3.8'", 924 | "version": "==3.0.51" 925 | }, 926 | "pycparser": { 927 | "hashes": [ 928 | "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", 929 | "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" 930 | ], 931 | "markers": "python_version >= '3.8'", 932 | "version": "==2.22" 933 | }, 934 | "pydantic": { 935 | "hashes": [ 936 | "sha256:07293ab08e7b4d3c9d7de4949a0ea571f11e4557d19ea24dd3ae0c524c0c334d", 937 | "sha256:0a2aabdc73c2a5960e87c3ffebca6ccde88665616d1fd6d3db3178ef427b267a", 938 | "sha256:0da48717dc9495d3a8f215e0d012599db6b8092db02acac5e0d58a65248ec5bc", 939 | "sha256:128d9453d92e6e81e881dd7e2484e08d8b164da5507f62d06ceecf84bf2e21d3", 940 | "sha256:2196c06484da2b3fded1ab6dbe182bdabeb09f6318b7fdc412609ee2b564c49a", 941 | "sha256:2e9aec8627a1a6823fc62fb96480abe3eb10168fd0d859ee3d3b395105ae19a7", 942 | "sha256:3283b574b01e8dbc982080d8287c968489d25329a463b29a90d4157de4f2baaf", 943 | "sha256:3c52eb595db83e189419bf337b59154bdcca642ee4b2a09e5d7797e41ace783f", 944 | "sha256:4b466a23009ff5cdd7076eb56aca537c745ca491293cc38e72bf1e0e00de5b91", 945 | "sha256:517a681919bf880ce1dac7e5bc0c3af1e58ba118fd774da2ffcd93c5f96eaece", 946 | "sha256:5f8bbaf4013b9a50e8100333cc4e3fa2f81214033e05ac5aa44fa24a98670a29", 947 | "sha256:6257bb45ad78abacda13f15bde5886efd6bf549dd71085e64b8dcf9919c38b60", 948 | "sha256:67195274fd27780f15c4c372f4ba9a5c02dad6d50647b917b6a92bf00b3d301a", 949 | "sha256:6cafde02f6699ce4ff643417d1a9223716ec25e228ddc3b436fe7e2d25a1f305", 950 | "sha256:73ef93e5e1d3c8e83f1ff2e7fdd026d9e063c7e089394869a6e2985696693766", 951 | "sha256:7845b31959468bc5b78d7b95ec52fe5be32b55d0d09983a877cca6aedc51068f", 952 | "sha256:7847ca62e581e6088d9000f3c497267868ca2fa89432714e21a4fb33a04d52e8", 953 | "sha256:7e1d5290044f620f80cf1c969c542a5468f3656de47b41aa78100c5baa2b8276", 954 | "sha256:7ee829b86ce984261d99ff2fd6e88f2230068d96c2a582f29583ed602ef3fc2c", 955 | "sha256:83fcff3c7df7adff880622a98022626f4f6dbce6639a88a15a3ce0f96466cb60", 956 | "sha256:939328fd539b8d0edf244327398a667b6b140afd3bf7e347cf9813c736211896", 957 | "sha256:95c70da2cd3b6ddf3b9645ecaa8d98f3d80c606624b6d245558d202cd23ea3be", 958 | "sha256:963671eda0b6ba6926d8fc759e3e10335e1dc1b71ff2a43ed2efd6996634dafb", 959 | "sha256:970b1bdc6243ef663ba5c7e36ac9ab1f2bfecb8ad297c9824b542d41a750b298", 960 | "sha256:9863b9420d99dfa9c064042304868e8ba08e89081428a1c471858aa2af6f57c4", 961 | "sha256:ad428e92ab68798d9326bb3e5515bc927444a3d71a93b4a2ca02a8a5d795c572", 962 | "sha256:b48d3d634bca23b172f47f2335c617d3fcb4b3ba18481c96b7943a4c634f5c8d", 963 | "sha256:b9cd67fb763248cbe38f0593cd8611bfe4b8ad82acb3bdf2b0898c23415a1f82", 964 | "sha256:d111a21bbbfd85c17248130deac02bbd9b5e20b303338e0dbe0faa78330e37e0", 965 | "sha256:e1aa5c2410769ca28aa9a7841b80d9d9a1c5f223928ca8bec7e7c9a34d26b1d4", 966 | "sha256:e692dec4a40bfb40ca530e07805b1208c1de071a18d26af4a2a0d79015b352ca", 967 | "sha256:e7c9900b43ac14110efa977be3da28931ffc74c27e96ee89fbcaaf0b0fe338e1", 968 | "sha256:eec39224b2b2e861259d6f3c8b6290d4e0fbdce147adb797484a42278a1a486f", 969 | "sha256:f0b7628fb8efe60fe66fd4adadd7ad2304014770cdc1f4934db41fe46cc8825f", 970 | "sha256:f50e1764ce9353be67267e7fd0da08349397c7db17a562ad036aa7c8f4adfdb6", 971 | "sha256:fab81a92f42d6d525dd47ced310b0c3e10c416bbfae5d59523e63ea22f82b31e" 972 | ], 973 | "markers": "python_version >= '3.7'", 974 | "version": "==1.10.9" 975 | }, 976 | "pyflakes": { 977 | "hashes": [ 978 | "sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a", 979 | "sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b" 980 | ], 981 | "markers": "python_version >= '3.9'", 982 | "version": "==3.3.2" 983 | }, 984 | "pygithub": { 985 | "hashes": [ 986 | "sha256:3d87a822e6c868142f0c2c4bf16cce4696b5a7a4d142a7bd160e1bdf75bc54a9", 987 | "sha256:c44e3a121c15bf9d3a5cc98d94c9a047a5132a9b01d22264627f58ade9ddc217" 988 | ], 989 | "markers": "python_version >= '3.7'", 990 | "version": "==1.59.1" 991 | }, 992 | "pygments": { 993 | "hashes": [ 994 | "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", 995 | "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c" 996 | ], 997 | "markers": "python_version >= '3.8'", 998 | "version": "==2.19.1" 999 | }, 1000 | "pyjwt": { 1001 | "extras": [ 1002 | "crypto" 1003 | ], 1004 | "hashes": [ 1005 | "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", 1006 | "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb" 1007 | ], 1008 | "markers": "python_version >= '3.9'", 1009 | "version": "==2.10.1" 1010 | }, 1011 | "pynacl": { 1012 | "hashes": [ 1013 | "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858", 1014 | "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d", 1015 | "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93", 1016 | "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1", 1017 | "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92", 1018 | "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff", 1019 | "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba", 1020 | "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394", 1021 | "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b", 1022 | "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543" 1023 | ], 1024 | "markers": "python_version >= '3.6'", 1025 | "version": "==1.5.0" 1026 | }, 1027 | "pyparsing": { 1028 | "hashes": [ 1029 | "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", 1030 | "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be" 1031 | ], 1032 | "markers": "python_version >= '3.9'", 1033 | "version": "==3.2.3" 1034 | }, 1035 | "pypi-simple": { 1036 | "hashes": [ 1037 | "sha256:d393c23b841637e34038723291b4bcfd19e342ef47205e9eaa5fe4642ccd4763", 1038 | "sha256:f50bdf61b914ffa48c5cf2c3998552fad1ce285a71ae898f56342b338d4bf771" 1039 | ], 1040 | "markers": "python_version >= '3.7'", 1041 | "version": "==1.1.0" 1042 | }, 1043 | "pyright": { 1044 | "hashes": [ 1045 | "sha256:b8a3ba40481aa47ba08ffb3228e821d22f7d391f83609211335858bf05686bdb", 1046 | "sha256:c80d04f98b5a4358ad3a35e241dbf2a408eee33a40779df365644f8054d2517e" 1047 | ], 1048 | "markers": "python_version >= '3.7'", 1049 | "version": "==1.1.400" 1050 | }, 1051 | "pyrsistent": { 1052 | "hashes": [ 1053 | "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f", 1054 | "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e", 1055 | "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958", 1056 | "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34", 1057 | "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca", 1058 | "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d", 1059 | "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d", 1060 | "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4", 1061 | "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714", 1062 | "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf", 1063 | "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee", 1064 | "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8", 1065 | "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224", 1066 | "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d", 1067 | "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054", 1068 | "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656", 1069 | "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7", 1070 | "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423", 1071 | "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce", 1072 | "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e", 1073 | "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3", 1074 | "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0", 1075 | "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f", 1076 | "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b", 1077 | "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce", 1078 | "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a", 1079 | "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174", 1080 | "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86", 1081 | "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f", 1082 | "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b", 1083 | "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98", 1084 | "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022" 1085 | ], 1086 | "markers": "python_version >= '3.8'", 1087 | "version": "==0.20.0" 1088 | }, 1089 | "pyserial": { 1090 | "hashes": [ 1091 | "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", 1092 | "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0" 1093 | ], 1094 | "version": "==3.5" 1095 | }, 1096 | "pysondb-v2": { 1097 | "hashes": [ 1098 | "sha256:1f5d2d864e5f5d1334d639681199255526ab0c8aa0b4b324462e78aae0e08d10", 1099 | "sha256:3226ee94b7550e602f7061f68ae64b5d02812153d799b57aa74343f20ed0cd9b" 1100 | ], 1101 | "markers": "python_full_version >= '3.7.0'", 1102 | "version": "==2.2.0" 1103 | }, 1104 | "python-minifier": { 1105 | "hashes": [ 1106 | "sha256:36681584ada9b12a3c7ec8cb9c716603685d7ef3dac981d4197996c0b7221948", 1107 | "sha256:ba8697b507b6ff059b4b43db2e08d8f9a6bd048d80ae3b955cd286092be2ffb2" 1108 | ], 1109 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' and python_version < '3.12'", 1110 | "version": "==2.9.0" 1111 | }, 1112 | "python-nmap": { 1113 | "hashes": [ 1114 | "sha256:f75af6b91dd8e3b0c31f869db32163f62ada686945e5b7c25f84bc0f7fad3b64" 1115 | ], 1116 | "version": "==0.7.1" 1117 | }, 1118 | "pyudev": { 1119 | "hashes": [ 1120 | "sha256:2e945427a21674893bb97632401db62139d91cea1ee96137cc7b07ad22198fc7", 1121 | "sha256:e8246f0a014fe370119ba2bc781bfbe62c0298d0d6b39c94e83102a8a3f56960" 1122 | ], 1123 | "markers": "python_version >= '3.7'", 1124 | "version": "==0.24.3" 1125 | }, 1126 | "pyyaml": { 1127 | "hashes": [ 1128 | "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", 1129 | "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", 1130 | "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", 1131 | "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", 1132 | "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", 1133 | "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", 1134 | "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", 1135 | "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", 1136 | "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", 1137 | "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", 1138 | "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", 1139 | "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", 1140 | "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", 1141 | "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", 1142 | "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", 1143 | "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", 1144 | "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", 1145 | "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", 1146 | "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", 1147 | "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", 1148 | "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", 1149 | "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", 1150 | "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", 1151 | "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", 1152 | "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", 1153 | "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", 1154 | "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", 1155 | "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", 1156 | "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", 1157 | "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", 1158 | "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", 1159 | "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", 1160 | "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", 1161 | "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", 1162 | "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", 1163 | "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", 1164 | "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", 1165 | "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", 1166 | "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", 1167 | "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", 1168 | "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", 1169 | "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", 1170 | "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", 1171 | "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", 1172 | "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", 1173 | "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", 1174 | "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", 1175 | "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", 1176 | "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", 1177 | "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", 1178 | "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", 1179 | "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", 1180 | "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" 1181 | ], 1182 | "markers": "python_version >= '3.8'", 1183 | "version": "==6.0.2" 1184 | }, 1185 | "questionary": { 1186 | "hashes": [ 1187 | "sha256:600d3aefecce26d48d97eee936fdb66e4bc27f934c3ab6dd1e292c4f43946d90", 1188 | "sha256:fecfcc8cca110fda9d561cb83f1e97ecbb93c613ff857f655818839dac74ce90" 1189 | ], 1190 | "markers": "python_version >= '3.6' and python_version < '4.0'", 1191 | "version": "==1.10.0" 1192 | }, 1193 | "reedsolo": { 1194 | "hashes": [ 1195 | "sha256:2b6a3e402a1ee3e1eea3f932f81e6c0b7bbc615588074dca1dbbcdeb055002bd", 1196 | "sha256:c1359f02742751afe0f1c0de9f0772cc113835aa2855d2db420ea24393c87732" 1197 | ], 1198 | "version": "==1.7.0" 1199 | }, 1200 | "requests": { 1201 | "hashes": [ 1202 | "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", 1203 | "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" 1204 | ], 1205 | "markers": "python_version >= '3.7'", 1206 | "version": "==2.31.0" 1207 | }, 1208 | "requirements-parser": { 1209 | "hashes": [ 1210 | "sha256:5963ee895c2d05ae9f58d3fc641082fb38021618979d6a152b6b1398bd7d4ed4", 1211 | "sha256:76650b4a9d98fc65edf008a7920c076bb2a76c08eaae230ce4cfc6f51ea6a773" 1212 | ], 1213 | "version": "==0.2.0" 1214 | }, 1215 | "rich": { 1216 | "hashes": [ 1217 | "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", 1218 | "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" 1219 | ], 1220 | "version": "==13.9.4" 1221 | }, 1222 | "rshell": { 1223 | "hashes": [ 1224 | "sha256:7942b758a9ae5c6ff46516b0317f437dfce9f0721f3a3b635ebd501c9cd38fb9" 1225 | ], 1226 | "markers": "sys_platform != 'win32'", 1227 | "version": "==0.0.31" 1228 | }, 1229 | "setuptools": { 1230 | "hashes": [ 1231 | "sha256:31e2c58dbb67c99c289f51c16d899afedae292b978f8051efaf6262d8212f927", 1232 | "sha256:ea8e00d7992054c4c592aeb892f6ad51fe1b4d90cc6947cc45c45717c40ec537" 1233 | ], 1234 | "markers": "python_version >= '3.9'", 1235 | "version": "==80.3.1" 1236 | }, 1237 | "shellingham": { 1238 | "hashes": [ 1239 | "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", 1240 | "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" 1241 | ], 1242 | "version": "==1.5.4" 1243 | }, 1244 | "six": { 1245 | "hashes": [ 1246 | "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", 1247 | "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" 1248 | ], 1249 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 1250 | "version": "==1.17.0" 1251 | }, 1252 | "smmap": { 1253 | "hashes": [ 1254 | "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", 1255 | "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e" 1256 | ], 1257 | "markers": "python_version >= '3.7'", 1258 | "version": "==5.0.2" 1259 | }, 1260 | "soupsieve": { 1261 | "hashes": [ 1262 | "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", 1263 | "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a" 1264 | ], 1265 | "markers": "python_version >= '3.8'", 1266 | "version": "==2.7" 1267 | }, 1268 | "tabulate": { 1269 | "hashes": [ 1270 | "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", 1271 | "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f" 1272 | ], 1273 | "markers": "python_version >= '3.7'", 1274 | "version": "==0.9.0" 1275 | }, 1276 | "tenacity": { 1277 | "hashes": [ 1278 | "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", 1279 | "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687" 1280 | ], 1281 | "markers": "python_version >= '3.8'", 1282 | "version": "==8.5.0" 1283 | }, 1284 | "tomli": { 1285 | "hashes": [ 1286 | "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", 1287 | "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", 1288 | "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", 1289 | "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", 1290 | "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", 1291 | "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", 1292 | "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", 1293 | "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", 1294 | "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", 1295 | "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", 1296 | "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", 1297 | "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", 1298 | "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", 1299 | "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", 1300 | "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", 1301 | "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", 1302 | "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", 1303 | "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", 1304 | "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", 1305 | "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", 1306 | "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", 1307 | "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", 1308 | "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", 1309 | "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", 1310 | "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", 1311 | "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", 1312 | "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", 1313 | "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", 1314 | "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", 1315 | "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", 1316 | "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", 1317 | "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" 1318 | ], 1319 | "markers": "python_version < '3.11'", 1320 | "version": "==2.2.1" 1321 | }, 1322 | "tomli-w": { 1323 | "hashes": [ 1324 | "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", 1325 | "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021" 1326 | ], 1327 | "markers": "python_version >= '3.9'", 1328 | "version": "==1.2.0" 1329 | }, 1330 | "tqdm": { 1331 | "hashes": [ 1332 | "sha256:1871fb68a86b8fb3b59ca4cdd3dcccbc7e6d613eeed31f4c332531977b89beb5", 1333 | "sha256:c4f53a17fe37e132815abceec022631be8ffe1b9381c2e6e30aa70edc99e9671" 1334 | ], 1335 | "markers": "python_version >= '3.7'", 1336 | "version": "==4.65.0" 1337 | }, 1338 | "typed-config": { 1339 | "hashes": [ 1340 | "sha256:20f1e4feda489394bad5ea3bb5333fb6e9a3f6d42efc6e459b4ddbc6e16d99db", 1341 | "sha256:ed5adb4a210def671c2b6a45bd3e614bca4a31e21af1fa962c06fd669689edd3" 1342 | ], 1343 | "markers": "python_full_version >= '3.6.0'", 1344 | "version": "==1.5.0" 1345 | }, 1346 | "typer": { 1347 | "extras": [ 1348 | "all" 1349 | ], 1350 | "hashes": [ 1351 | "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2", 1352 | "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee" 1353 | ], 1354 | "markers": "python_version >= '3.6'", 1355 | "version": "==0.9.0" 1356 | }, 1357 | "typing-extensions": { 1358 | "hashes": [ 1359 | "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26", 1360 | "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5" 1361 | ], 1362 | "markers": "python_version >= '3.7'", 1363 | "version": "==4.6.3" 1364 | }, 1365 | "typing-inspect": { 1366 | "hashes": [ 1367 | "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", 1368 | "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78" 1369 | ], 1370 | "version": "==0.9.0" 1371 | }, 1372 | "unsync": { 1373 | "hashes": [ 1374 | "sha256:a29e0f8952ffb0b3a0453ce436819a5a1ba2febbb5caa707c319f6f98d35f3c5" 1375 | ], 1376 | "version": "==1.4.0" 1377 | }, 1378 | "upydevice": { 1379 | "hashes": [ 1380 | "sha256:7fa4f89aeb7d828bdcbac6839d9fdb1078e799a6b79bfb051e65bf6884b6ec2b", 1381 | "sha256:9e95cc105319833e710639b86ae108d2d5e4fac9019ed0d0d0dbbccd7a1cdb21" 1382 | ], 1383 | "version": "==0.3.8" 1384 | }, 1385 | "urllib3": { 1386 | "hashes": [ 1387 | "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", 1388 | "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813" 1389 | ], 1390 | "markers": "python_version >= '3.9'", 1391 | "version": "==2.4.0" 1392 | }, 1393 | "userpath": { 1394 | "hashes": [ 1395 | "sha256:2cbf01a23d655a1ff8fc166dfb78da1b641d1ceabf0fe5f970767d380b14e89d", 1396 | "sha256:6c52288dab069257cc831846d15d48133522455d4677ee69a9781f11dbefd815" 1397 | ], 1398 | "markers": "python_version >= '3.7'", 1399 | "version": "==1.9.2" 1400 | }, 1401 | "watchdog": { 1402 | "hashes": [ 1403 | "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", 1404 | "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", 1405 | "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", 1406 | "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", 1407 | "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", 1408 | "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", 1409 | "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", 1410 | "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", 1411 | "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", 1412 | "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", 1413 | "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", 1414 | "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", 1415 | "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", 1416 | "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", 1417 | "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", 1418 | "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", 1419 | "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", 1420 | "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", 1421 | "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", 1422 | "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", 1423 | "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", 1424 | "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", 1425 | "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", 1426 | "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", 1427 | "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", 1428 | "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", 1429 | "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", 1430 | "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", 1431 | "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", 1432 | "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2" 1433 | ], 1434 | "markers": "python_version >= '3.9'", 1435 | "version": "==6.0.0" 1436 | }, 1437 | "wcwidth": { 1438 | "hashes": [ 1439 | "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", 1440 | "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5" 1441 | ], 1442 | "version": "==0.2.13" 1443 | }, 1444 | "websockets": { 1445 | "hashes": [ 1446 | "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", 1447 | "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", 1448 | "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", 1449 | "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", 1450 | "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", 1451 | "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", 1452 | "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", 1453 | "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", 1454 | "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", 1455 | "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880", 1456 | "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123", 1457 | "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", 1458 | "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", 1459 | "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed", 1460 | "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", 1461 | "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411", 1462 | "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", 1463 | "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", 1464 | "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", 1465 | "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", 1466 | "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb", 1467 | "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e", 1468 | "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee", 1469 | "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f", 1470 | "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", 1471 | "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", 1472 | "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", 1473 | "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", 1474 | "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", 1475 | "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", 1476 | "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", 1477 | "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", 1478 | "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", 1479 | "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5", 1480 | "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", 1481 | "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", 1482 | "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", 1483 | "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9", 1484 | "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", 1485 | "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", 1486 | "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", 1487 | "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", 1488 | "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940", 1489 | "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", 1490 | "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", 1491 | "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", 1492 | "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", 1493 | "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b", 1494 | "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a", 1495 | "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054", 1496 | "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", 1497 | "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", 1498 | "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", 1499 | "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4", 1500 | "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", 1501 | "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", 1502 | "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", 1503 | "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b", 1504 | "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", 1505 | "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770", 1506 | "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", 1507 | "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", 1508 | "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", 1509 | "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", 1510 | "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", 1511 | "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", 1512 | "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", 1513 | "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", 1514 | "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7" 1515 | ], 1516 | "index": "pypi", 1517 | "markers": "python_version >= '3.9'", 1518 | "version": "==15.0.1" 1519 | }, 1520 | "wrapt": { 1521 | "hashes": [ 1522 | "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f", 1523 | "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c", 1524 | "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a", 1525 | "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b", 1526 | "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555", 1527 | "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c", 1528 | "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b", 1529 | "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6", 1530 | "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8", 1531 | "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662", 1532 | "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061", 1533 | "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998", 1534 | "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb", 1535 | "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62", 1536 | "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984", 1537 | "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", 1538 | "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2", 1539 | "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306", 1540 | "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7", 1541 | "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", 1542 | "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", 1543 | "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6", 1544 | "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192", 1545 | "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317", 1546 | "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f", 1547 | "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda", 1548 | "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563", 1549 | "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a", 1550 | "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f", 1551 | "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", 1552 | "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9", 1553 | "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8", 1554 | "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82", 1555 | "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9", 1556 | "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845", 1557 | "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", 1558 | "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125", 1559 | "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504", 1560 | "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b", 1561 | "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7", 1562 | "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc", 1563 | "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6", 1564 | "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", 1565 | "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a", 1566 | "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3", 1567 | "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a", 1568 | "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72", 1569 | "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681", 1570 | "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438", 1571 | "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", 1572 | "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2", 1573 | "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb", 1574 | "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5", 1575 | "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a", 1576 | "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3", 1577 | "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", 1578 | "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2", 1579 | "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22", 1580 | "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72", 1581 | "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061", 1582 | "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f", 1583 | "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9", 1584 | "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04", 1585 | "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", 1586 | "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9", 1587 | "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f", 1588 | "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", 1589 | "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", 1590 | "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6", 1591 | "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0", 1592 | "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", 1593 | "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c", 1594 | "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", 1595 | "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6", 1596 | "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000", 1597 | "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb", 1598 | "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119", 1599 | "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b", 1600 | "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58" 1601 | ], 1602 | "markers": "python_version >= '3.8'", 1603 | "version": "==1.17.2" 1604 | } 1605 | }, 1606 | "develop": {} 1607 | } 1608 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Rus](README.rus.md) 2 | # example_async_websocket 3 | This project is designed to test the functionality of the [micropython-async-websocket-client](https://pypi.org/project/micropython-async-websocket-client/) package. 4 | 5 | The project demonstrates the operation of an [ESP32S controller](https://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:ESP32_Espressif_ESP-WROOM-32_Dev_Board.jpg) and its clones 6 | running [micropython](https://micropython.org). 7 | 8 | Key objectives of the micropython-async-websocket-client package: 9 | 10 | 1. Establish and maintain a stable WebSocket connection with a server. 11 | 2. Ensure that connection failures do not disrupt the controller’s main workflow. 12 | 3. Enable bidirectional communication—sending data to the server and receiving control signals from it. 13 | 14 | # Requirements 15 | - ESP32 controller 16 | - USB cable with data wire 17 | - Ubuntu 24.04 18 | - Python 3.10 19 | - VSCode + PyMakr plugin 20 | 21 | > [!CAUTION] 22 | > 1. Use only the deb installation of VSCode! 23 | > The snap version does not support the PyMakr plugin! 24 | > 2. The project https://github.com/Vovaman/start_ESP32_with_micropython 25 | > explains how to work with ESP32 in VSCode. 26 | > This includes PyMakr setup, file transfer to the controller, project synchronization, etc. 27 | > 3. All further steps assume that pipenv and pyenv are installed as described in the above project. 28 | > 4. All commands must be executed in the project’s root directory within the pipenv virtual environment. 29 | 30 | - WiFi network 31 | 32 | > [!CAUTION] 33 | > This guide assumes the ESP32 operates in a local Wi-Fi network. 34 | > Examples with TLS use self-signed certificates. 35 | 36 | # Running Examples 37 | Before running any examples: 38 | 39 | - Obtain the Wi-Fi network name () 40 | and password () used by both the computer and the controller. 41 | - Determine the computer’s IP address () in the Wi-Fi network. 42 | - Synchronize the project with the controller: 43 | 44 | ![sync project](pics/sync_project.png) 45 | - install the [async_websocket_client package](https://github.com/Vovaman/micropython_async_websocket_client?tab=readme-ov-file#installation). 46 | 47 | If the connection between the server and controller is successful, the controller’s terminal will display: 48 | 49 | ![ESP echo](pics/esp_echo.png) 50 | 51 | ...and the server’s console output will show: 52 | 53 | ![Server echo](pics/server_echo.png) 54 | 55 | ## WS. No Encryption 56 | The simplest case: unencrypted communication. 57 | 58 | 1. ``src/config.json``: 59 | ```json 60 | { 61 | "wifi": { 62 | "SSID": "", 63 | "password": "", 64 | "attempts": 3, 65 | "delay_in_msec": 200 66 | }, 67 | "server": "ws://:8000/", 68 | "socket_delay_ms": 5 69 | } 70 | ``` 71 | 2. Update project on the controller: 72 | ```bash 73 | $ mpremote fs cp src/* :/ 74 | ``` 75 | 3. Reboot the controller. 76 | 4. Start the server: 77 | ```bash 78 | $ python server.py 79 | ``` 80 | 81 | ## WSS. 82 | ### No Certificate Verification (Client or Server) 83 | 84 | > [!CAUTION] 85 | > TLS encrypts the channel even without certificates, but this is still insecure! 86 | 87 | 1. src/config.json: 88 | ```json 89 | { 90 | "wifi": { 91 | "SSID": "", 92 | "password": "", 93 | "attempts": 3, 94 | "delay_in_msec": 200 95 | }, 96 | "server": "wss://:8443/", 97 | "ssl": { 98 | "cert_reqs": 0 99 | }, 100 | "socket_delay_ms": 5 101 | } 102 | ``` 103 | 2. Even though certificate checks are disabled, 104 | the server must still use a certificate and key. 105 | 106 | Generate certificates: 107 | ```bash 108 | $ ./gen_crt.sh --srv= 109 | ``` 110 | 111 | > [!NOTE] 112 | > The gen_crt.sh script will prompt for a key password. Use the same password throughout. 113 | 114 | The script copies required files to the project directory. Since the controller does not need certificates here, delete unnecessary files: 115 | ```bash 116 | $ rm src/*.crt src/*.key src/ca.der 117 | ``` 118 | 3. Update the project on the controller: 119 | ```bash 120 | $ mpremote fs cp src/* :/ 121 | ``` 122 | 4. Reboot the controller. 123 | 5. Start the server: 124 | ```bash 125 | $ python server.py --ssl --ssl-keyfile=tls//.key --ssl-certfile=tls//.crt --port=8443 126 | ``` 127 | 128 | > [!CAUTION] 129 | > The server does not require a CA certificate in this mode. 130 | 131 | ### Server Certificate Verified by Controller, No Client Certificate Required 132 | > [!CAUTION] 133 | > Higher security: the controller verifies the server’s certificate, 134 | > but the server allows any client. 135 | > 136 | > Still insecure. 137 | 138 | 1. ``src/config.json``: 139 | ```json 140 | { 141 | "wifi": { 142 | "SSID": "", 143 | "password": "", 144 | "attempts": 3, 145 | "delay_in_msec": 200 146 | }, 147 | "server": "wss://:8443/", 148 | "ssl": { 149 | "cert_reqs": 2, 150 | "ca": "ca.der" 151 | }, 152 | "socket_delay_ms": 5 153 | } 154 | ``` 155 | 156 | 2. Generate certificates: 157 | ```bash 158 | $ ./gen_crt.sh --srv= 159 | ``` 160 | 161 | Remove unnecessary files: 162 | ```bash 163 | $ rm src/*.crt src/*.key 164 | ``` 165 | 3. The controller lacks a real-time clock (RTC) and defaults to January 1, 2000. 166 | If the system time is incorrect, certificate validation will fail with 167 | ``The certificate validity starts in the future``. 168 | 169 | Set the controller’s time via its console: 170 | 171 | ```python 172 | >>> from machine import RTC 173 | >>> rtc = RTC() 174 | >>> rtc.datetime((2025,5,7,1,13,0,0,0)) # replace with current time 175 | ``` 176 | 4. Update the project on the controller: 177 | ```bash 178 | $ mpremote fs cp src/* :/ 179 | ``` 180 | 5. Reboot the controller. 181 | > [!CAUTION] 182 | > Time may reset after reboot. 183 | > If this occurs frequently, 184 | > add time-setting commands to the project code. 185 | 6. Start the server: 186 | ```bash 187 | $ python server.py --ssl --ssl-keyfile=tls//.key --ssl-certfile=tls//.crt --port=8443 188 | ``` 189 | ### Certificates is optional 190 | This mode is realized too, but we will not check it. 191 | 192 | ### Mutual Certificate Verification (Server and Controller) 193 | Most secure mode: enables client authentication via certificates. 194 | 195 | 1. Generate certificates with a client name: 196 | ```bash 197 | $ ./gen_crt.sh --srv= --cn="ESP Client 1" 198 | ``` 199 | 2. ``src/config.json``: 200 | ```json 201 | { 202 | "wifi": { 203 | "SSID": "", 204 | "password": "", 205 | "attempts": 3, 206 | "delay_in_msec": 200 207 | }, 208 | "server": "wss://:8443/", 209 | "ssl": { 210 | "key": "ESP Client 1.key", 211 | "cert": "ESP Client 1.crt", 212 | "ca": "ca.der", 213 | "cert_reqs": 2 214 | }, 215 | "socket_delay_ms": 5 216 | } 217 | ``` 218 | 3. Set the controller’s time (as described earlier). 219 | 4. Update the project on the controller. 220 | 5. Reboot the controller. 221 | 6. Start the server: 222 | ```bash 223 | $ python server.py --ssl --ssl-keyfile=tls//.key --ssl-certfile=tls//.crt --ssl-ca-cert=tls/ca/ca.crt --ssl-certs-reqs=2 --port=8443 224 | ``` 225 | 226 | The server extracts the client’s name from the certificate: 227 | 228 | ![Client](pics/client.png) 229 | 230 | This allows certificate-based client authorization on the server. 231 | 232 | # Test project componenets 233 | ## Test server 234 | The WebSocket server is implemented in ``server.py``. 235 | It accepts connections, echoes received messages. 236 | ## Project for ESP32 237 | The ``src`` folder contains files for the ESP32 project. Key functionalities: 238 | - Main loop: Blinks the onboard blue LED (if available) and sends ``SOS!`` to the server. 239 | - Data loop: Receives server messages. 240 | 241 | > [!NOTE] 242 | > Tested with [firmware v1.25.0](https://micropython.org/resources/firmware/ESP32_GENERIC-20250415-v1.25.0.bin). 243 | 244 | # Configuration parameters 245 | ## src/config 246 | ``` 247 | { 248 | "wifi": { 249 | "SSID": "SSID", # network name 250 | "password": "***********", # network password 251 | "attempts": 3, # connection attempts per cycle 252 | "delay_in_msec": 200 # post-connection delay (ms) 253 | }, 254 | "server": "ws://192.168.1.100:8000/", # server address 255 | "socket_delay_ms": 5 # Read/write delay (increase for slow networks) 256 | "ssl": { 257 | "ca": "", # CA certificate (DER format) 258 | "key": "", # client private key 259 | "cert": "", # client certificate 260 | "cert_reqs": 2 # certificate check mode: 0 - CERT_NONE, 1 - CERT_OPTIONAL, 2 - CERT_REQUIRED 261 | } 262 | } 263 | ``` 264 | 265 | # Conclusion 266 | All components function correctly. 267 | The ESP32 maintains communication with the server, and the server echoes messages to clients. 268 | 269 | Test scenarios: 270 | - Power cycle the controller. 271 | - Stop/restart the server. 272 | - Send rapid bursts of messages. 273 | - Adjust ``socket_delay_ms`` in ``src/config.json``. 274 | - Experiment with TLS settings. 275 | - ... -------------------------------------------------------------------------------- /README.rus.md: -------------------------------------------------------------------------------- 1 | [Eng](README.md) 2 | # example_async_websocket 3 | Этот проект создан для тестирования работы пакета 4 | [micropython-async-websocket-client](https://pypi.org/project/micropython-async-websocket-client/). 5 | 6 | В проекте рассматривается работа контроллера 7 | [ESP32S controller](https://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:ESP32_Espressif_ESP-WROOM-32_Dev_Board.jpg) 8 | и клонов под управлением [micropython](https://micropython.org). 9 | 10 | Задачи, решаемые пакетом `micropython-async-websocket-client`: 11 | 1. Создать и поддерживать в рабочем режиме websocket-канал для связи с сервером. 12 | 2. Разрыв связи с сервером не должен влиять на основной рабочий цикл контроллера. 13 | 3. Данные не только посылаются на сервер, но появляется также возможность принимать управляющие сигналы с сервера. 14 | 15 | # Требования 16 | - ESP32 контроллер 17 | - USB кабель с проводом для передачи данных 18 | - Ubuntu 24.04 19 | - Python 3.10 20 | - VSCode + PyMakr plugin 21 | 22 | > [!CAUTION] 23 | > 1. Используйте только deb-установку VSCode! 24 | > В версии для `snap` не работает расширение `PyMakr`! 25 | > 2. Проект https://github.com/Vovaman/start_ESP32_with_micropython объясняет, 26 | > как работать с ESP32 из VSCode. 27 | > 28 | > Установка плагина PyMakr, копирование файлов на контроллер, 29 | > синхронизация проекта и т.д. - все операции описаны в указанном проекте. 30 | > 3. Все дальнейшие действия предполагают, что установлены ``pipenv`` и ``pyenv``, 31 | > как описано в проекте https://github.com/Vovaman/start_ESP32_with_micropython. 32 | > 33 | > Все действия выполняются в корневой папке проекта, внутри виртуальной среды ``pipenv``. 34 | 35 | - сеть WiFi 36 | 37 | > [!CAUTION] 38 | > Исходим из того, что работаем с ESP32 в локальной wi-fi сети. 39 | > 40 | > Примеры с TLS используют самоподписанные сертификаты. 41 | 42 | # Запуск примеров 43 | Перед выполнением всех описанных ниже примеров: 44 | - Выясним имя (````) и пароль ```` wifi-сети, 45 | посредством которой связаны компьютер, на котором мы работаем и контроллер; 46 | - Определим IP-адрес компьютера (````), на котором мы работаем, в указанной wifi-сети. 47 | - Выполним синхронизацию проекта с контроллером; 48 | ![Синхронизация проекта](pics/sync_project.png) 49 | - [установим](https://github.com/Vovaman/micropython_async_websocket_client?tab=readme-ov-file#installation) пакет ``async_websocket_client`` 50 | 51 | В случае успешного установления связи между сервером и контроллером вывод в терминале контроллера будет иметь вид: 52 | 53 | ![ESP echo](pics/esp_echo.png) 54 | 55 | ...вывод сервера в консоли: 56 | 57 | ![Server echo](pics/server_echo.png) 58 | 59 | ## WS. Безопасность отсутствует. 60 | Самый простой случай: канал связи не шифруется. 61 | 62 | 1. ``src/config.json``: 63 | ```json 64 | { 65 | "wifi": { 66 | "SSID": "", 67 | "password": "", 68 | "attempts": 3, 69 | "delay_in_msec": 200 70 | }, 71 | "server": "ws://:8000/", 72 | "socket_delay_ms": 5 73 | } 74 | ``` 75 | 2. Обновляем проект на контроллере: 76 | ```bash 77 | $ mpremote fs cp src/* :/ 78 | ``` 79 | 3. Перезапускаем контроллер. 80 | 4. Запуск сервера: 81 | ```bash 82 | $ python server.py 83 | ``` 84 | ## WSS 85 | ### Сертификаты не проверяются ни клиентом, ни сервером 86 | > [!CAUTION] 87 | > TLS предполагает, что канал связи шифруется в любом случае, даже без сертификатов, 88 | > но, тем не менее, это небезопасный способ связи! 89 | 90 | 1. ``src/config.json``: 91 | ```json 92 | { 93 | "wifi": { 94 | "SSID": "", 95 | "password": "", 96 | "attempts": 3, 97 | "delay_in_msec": 200 98 | }, 99 | "server": "wss://:8443/", 100 | "ssl":{ 101 | "cert_reqs": 0 102 | } 103 | "socket_delay_ms": 5 104 | } 105 | ``` 106 | 107 | 2. Не смотря на то, что проверка сертификатов не требуется, 108 | сервер всё равно должен запускаться с серверными сертификатом и ключом. 109 | 110 | Генерируем сертификаты: 111 | ```bash 112 | $ ./gen_crt.sh --srv= 113 | ``` 114 | 115 | > [!NOTE] 116 | > Скрипт ``gen_crt.sh`` запрашивает пароль для ключа. 117 | > В процессе выполнения этого скрипта вводите один и тот же пароль. 118 | 119 | Скрипт автоматически копирует нужные файлы в каталог, предназначенный для синхронизации с контроллером, но в этом примере контроллеру не нужны никакие сертификаты, поэтому удаляем ненужные файлы: 120 | ```bash 121 | $ rm src/*.crt src/*.key src/ca.der 122 | ``` 123 | 3. Обновляем проект на контроллере: 124 | ```bash 125 | $ mpremote fs cp src/* :/ 126 | ``` 127 | 4. Перезапускаем контроллер. 128 | 5. Запускаем сервер: 129 | ```bash 130 | $ python server.py --ssl --ssl-keyfile=tls//.key --ssl-certfile=tls//.crt --port=8443 131 | ``` 132 | 133 | > [!CAUTION] 134 | > Обратите внимание, что в таком режиме работы серверу не требуется сертификат центра авторизации. 135 | 136 | ### Сертификат сервера проверяется контроллером, сервер не требует наличия сертификата у клиента 137 | > [!CAUTION] 138 | > Это более высокий уровень безопасности: контроллер проверяет корректность сертификата сервера, 139 | > но сервер допускает соединение с любым клиентом. 140 | > 141 | > Это также небезопасный способ связи. 142 | 143 | 1. ``src/config.json``: 144 | ```json 145 | { 146 | "wifi": { 147 | "SSID": "", 148 | "password": "", 149 | "attempts": 3, 150 | "delay_in_msec": 200 151 | }, 152 | "server": "wss://:8443/", 153 | "ssl":{ 154 | "cert_reqs": 2, 155 | "ca": "ca.der" 156 | } 157 | "socket_delay_ms": 5 158 | } 159 | ``` 160 | 161 | 2. Генерируем сертификаты: 162 | ```bash 163 | $ ./gen_crt.sh --srv= 164 | ``` 165 | 166 | > [!NOTE] 167 | > Скрипт ``gen_crt.sh`` запрашивает пароль для ключа. 168 | > В процессе выполнения этого скрипта вводите один и тот же пароль. 169 | 170 | Скрипт автоматически копирует нужные файлы в каталог, предназначенный для синхронизации с контроллером, но в этом примере контроллеру нужен только сертификат центра сертификации, поэтому удаляем ненужные файлы: 171 | ```bash 172 | $ rm src/*.crt src/*.key 173 | ``` 174 | 3. Сертификат действителен в течение определённого периода времени, начиная с момента выдачи. 175 | 176 | Контроллер не имеет энергонезависимых часов и установленное на нём по умолчанию время - начало суток 1 января 2000 года. 177 | 178 | Если не установить правильную дату, то при проверке сертификата сервера контроллер будет выдавать ошибку: 179 | ``The certificate validity starts in the future``. 180 | 181 | Установим дату и время на контроллере, выполнив в его консоли команды: 182 | 183 | ```python 184 | >>> from machine import RTC 185 | >>> rtc = RTC() 186 | >>> rtc.datetime((2025,5,7,1,13,0,0,0)) # впишите корректные числа, соответствующие текущей метке времени 187 | ``` 188 | 4. Обновляем проект на контроллере: 189 | ```bash 190 | $ mpremote fs cp src/* :/ 191 | ``` 192 | 5. Перезапускаем контроллер. 193 | > [!CAUTION] 194 | > При перезапуске контроллера время может сброситься к первоначальному значению. 195 | > Если с вашим контроллером такое происходит регулярно, то команды установления метки времени необходимо вписать 196 | > в код проекта. 197 | 6. Запускаем сервер: 198 | ```bash 199 | $ python server.py --ssl --ssl-keyfile=tls//.key --ssl-certfile=tls//.crt --port=8443 200 | ``` 201 | ### Опциональная проверка сертификатов 202 | Режим опциональной проверки сертификатов сервера реализован и в модуле ``async_websocket_client``, и на тестовом сервере, но рассматривать его мы не будем. 203 | 204 | ### Проверка сертификатов сервером и контроллером 205 | Самый безопасный режим работы. 206 | 207 | Позволяет реализовать аутентификацию и авторизацию клиента на базе данных из сертификата. 208 | 1. Генерируем сертификаты. Кроме IP сервера укажем имя клиента: 209 | ```bash 210 | $ ./gen_crt.sh --srv= --cn="ESP Client 1" 211 | ``` 212 | > [!NOTE] 213 | > Скрипт ``gen_crt.sh`` запрашивает пароль для ключа. 214 | > В процессе выполнения этого скрипта вводите один и тот же пароль. 215 | 216 | Скрипт скопирует все нужные файлы в каталог для проекта на контроллере. 217 | 218 | 2. ``src/config.json``: 219 | ```json 220 | { 221 | "wifi": { 222 | "SSID": "", 223 | "password": "", 224 | "attempts": 3, 225 | "delay_in_msec": 200 226 | }, 227 | "server": "wss://:8443/", 228 | "ssl": { 229 | "key": "ESP Client 1.key", 230 | "cert": "ESP Client 1.crt", 231 | "ca": "ca.der", 232 | "cert_reqs": 2 233 | }, 234 | "socket_delay_ms": 5 235 | } 236 | ``` 237 | 3. Аналогично предыдущему примеру, устанавливаем на контроллере корректное время. 238 | 4. Обновляем проект на контроллере: 239 | ```bash 240 | $ mpremote fs cp src/* :/ 241 | ``` 242 | 5. Перезапускаем контроллер. 243 | 6. Запускаем сервер: 244 | ```bash 245 | $ python server.py --ssl --ssl-keyfile=tls//.key --ssl-certfile=tls//.crt --ssl-ca-cert=tls/ca/ca.crt --ssl-certs-reqs=2 --port=8443 246 | ``` 247 | 248 | Сервер получает имя клиента из сертификата: 249 | 250 | ![Client](pics/client.png) 251 | 252 | Таким образом, на сервере можно организовать авторизацию пользователей с помощью сертификатов. 253 | 254 | # Компоненты тестового проекта 255 | ## Тестовый сервер 256 | Тестовый websocket-сервер реализован в файле `server.py`. 257 | Сервер поддерживает подключение по websocket, получает от клиентов сообщения и посылает их обратно. 258 | ## Проект для ESP32 259 | Папка `src` содержит файлы для тестового ESP32 проекта. 260 | Функциональность проекта состоит из двух задач: 261 | - основной рабочий цикл контроллера моргает голубым диодом (при его наличии на контроллере) и посылает на сервер сообщение `SOS!`; 262 | - цикл чтения данных получает данные с сервера. 263 | 264 | > [!NOTE] 265 | > Проект тестировался [на прошивке версии 1.25.0](https://micropython.org/resources/firmware/ESP32_GENERIC-20250415-v1.25.0.bin). 266 | 267 | # Параметры 268 | ## src/config 269 | ``` 270 | { 271 | "wifi": { 272 | "SSID": "SSID", # имя сети 273 | "password": "***********", # пароль для подключения к сети 274 | "attempts": 3, # количество попыток подключения к сети в течение одного цикла работы 275 | "delay_in_msec": 200 # задержка после команды `wifi.connect()` 276 | }, 277 | "server": "ws://192.168.1.100:8000/", # адрес подключения к тестовому серверу 278 | "socket_delay_ms": 5 # задержка для операций чтения/записи данных тестового сервера. 279 | # если у вас медленная сеть, 280 | # попробуйте увеличить эту задержку 281 | "ssl": { 282 | "ca": "", # сертификат удостоверяющего центра в DER формате 283 | "key": "", # файл с секретным ключом клиента 284 | "cert": "", # файл сертификата клиента 285 | "cert_reqs": 2 # код режима проверки сертификатов: 0 - CERT_NONE, 1 - CERT_OPTIONAL, 2 - CERT_REQUIRED 286 | }, 287 | } 288 | ``` 289 | 290 | # Заключение 291 | Все компоненты работают. ESP32 выполняет свою работу и поддерживает канал связи с сервером, сервер принимает сообщения и рассылает их всем клиентам. 292 | 293 | Попробуйте потестировать работу компонентов: 294 | - включайте/выключайте контроллер, 295 | - останавливайте сервер, 296 | - быстро посылайте много сообщений из контроллера, 297 | - меняйте параметры задержек в файле конфигурации `src/config.json, 298 | - ... 299 | -------------------------------------------------------------------------------- /gen_crt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # coding: utf-8 3 | # 4 | # $ ./gen_crt.sh --srv="IP or host name" --kl= --cn="client CN" 5 | # 6 | # --srv - default value is current hostname 7 | # --kl - default value is 4096 8 | # --cn - default value is result of command 'uuidgen' 9 | # 10 | # script generates certific ates, arranging them in directory structure: 11 | # tls 12 | # - ca 13 | # - ca.crt # root certificate for certificates authority center 14 | # - ca.der # root certificate for certificates authority center in DER format 15 | # - ca.key # private key for root certificate 16 | # - server 17 | # - .crt # server's certificate 18 | # - .key # private key for server's certificate 19 | # - .pem # .crt + .key 20 | # - client 21 | # - .crt # client's certificate 22 | # - .key # private key for client's certificate 23 | # 24 | 25 | # Server Name 26 | SRV_NAME=$HOSTNAME 27 | 28 | # Certificate validity period (10 years) 29 | DAYS=3654 30 | 31 | # common folder 32 | TLS_DIR="./tls" 33 | 34 | # Store for center authority (CA) root certificate 35 | ROOT_DIR="./tls/ca" 36 | 37 | # Path to server's certificate 38 | SRV_DIR="./tls/" 39 | 40 | # Path to clients directory 41 | CLIENTS_DIR="./tls/clients" 42 | 43 | # Client name 44 | CLIENT_NAME=$(uuidgen) 45 | # Path to client certificate 46 | CLIENT_DIR="${CLIENTS_DIR}/${CLIENT_NAME}" 47 | 48 | # CA root key name 49 | ROOT_CA_KEY="${ROOT_DIR}/ca.key" 50 | 51 | # CA root certificate name 52 | ROOT_CA_CRT="${ROOT_DIR}/ca.der" 53 | ROOT_CA_CRT_PEM="${ROOT_DIR}/ca.crt" 54 | 55 | # key long 56 | KEY_LENGTH=4096 57 | 58 | regex='^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' 59 | 60 | while [[ "$1" != "" ]]; do 61 | PARAM=`echo $1 | awk -F= '{print $1}'` 62 | VALUE=`echo $1 | awk -F= '{print $2}'` 63 | case ${PARAM} in 64 | --srv) 65 | SRV_NAME=${VALUE} 66 | SRV_DIR=${SRV_DIR}${SRV_NAME} 67 | ;; 68 | --kl) 69 | KEY_LENGTH=${VALUE} 70 | ;; 71 | --cn) 72 | CLIENT_NAME=${VALUE} 73 | CLIENT_DIR=${CLIENTS_DIR}/${CLIENT_NAME} 74 | ;; 75 | *) 76 | echo "ERROR: unknown parameter \"${PARAM}\"" 77 | exit 1 78 | ;; 79 | esac 80 | shift 81 | done 82 | 83 | # create tls folder 84 | if [[ ! -d ${TLS_DIR} ]] 85 | then 86 | mkdir ${TLS_DIR} 87 | fi 88 | 89 | # create tls/root 90 | if [[ ! -d ${ROOT_DIR} ]] 91 | then 92 | mkdir ${ROOT_DIR} 93 | fi 94 | 95 | # create tls/server 96 | if [[ ! -d ${SRV_DIR} ]] 97 | then 98 | mkdir ${SRV_DIR} 99 | fi 100 | 101 | # create tls/clients 102 | if [[ ! -d ${CLIENTS_DIR} ]] 103 | then 104 | mkdir ${CLIENTS_DIR} 105 | fi 106 | 107 | if [[ ! -f ${ROOT_CA_KEY} ]] 108 | then 109 | echo "Create root certificate and key..." 110 | # DER certificate is for using in controller, 111 | # current version of firmware (1.25.0) use only DER format 112 | openssl req -new -newkey rsa:${KEY_LENGTH} -keyout ${ROOT_CA_KEY} \ 113 | -x509 -days ${DAYS} -outform DER -out ${ROOT_CA_CRT} \ 114 | -subj "/CN=root_ca_center" 115 | 116 | # ...for server convert it to PEM 117 | openssl x509 -inform der -in ${ROOT_CA_CRT} -out ${ROOT_CA_CRT_PEM} 118 | fi 119 | 120 | SRV_KEY=${SRV_DIR}/${SRV_NAME}.key 121 | SRV_CERT=${SRV_DIR}/${SRV_NAME}.crt 122 | SRV_CSR=${SRV_DIR}/${SRV_NAME}.csr 123 | SRV_BUNDLE=${SRV_DIR}/${SRV_NAME}.pem 124 | 125 | echo "Create private key for server certificate..." 126 | openssl genrsa -out ${SRV_KEY} ${KEY_LENGTH} 127 | 128 | echo "Create request" 129 | openssl req -sha256 -new -key ${SRV_KEY} -out ${SRV_CSR} \ 130 | -subj "/CN=${SRV_NAME}" 131 | 132 | echo "Sign the CSR by own root CA certificate" 133 | if [[ ${SRV_NAME} =~ $regex ]]; then 134 | # srv_name is ip4 135 | echo -e "authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nsubjectAltName=IP:${SRV_NAME}" > server.ext 136 | openssl x509 -req -in ${SRV_CSR} -CA ${ROOT_CA_CRT} -CAkey ${ROOT_CA_KEY} \ 137 | -CAcreateserial -out ${SRV_CERT} -days ${DAYS} -extfile server.ext 138 | else 139 | openssl x509 -req -in ${SRV_CSR} -CA ${ROOT_CA_CRT} -CAkey ${ROOT_CA_KEY} \ 140 | -CAcreateserial -out ${SRV_CERT} -days ${DAYS} 141 | fi 142 | 143 | echo "Create bundle: server_cert + server_key" 144 | cat ${SRV_CERT} ${SRV_KEY} > ${SRV_BUNDLE} 145 | 146 | # create tls/client 147 | if [[ ! -d ${CLIENT_DIR} ]] 148 | then 149 | mkdir "${CLIENT_DIR}" 150 | fi 151 | 152 | echo "Create client private key" 153 | openssl genrsa -out "${CLIENT_DIR}/${CLIENT_NAME}.key" ${KEY_LENGTH} 154 | 155 | echo "Create CSR for client. Attention: name of client is '${CLIENT_NAME}'" 156 | openssl req -new -key "${CLIENT_DIR}/${CLIENT_NAME}.key" -out "${CLIENT_DIR}/${CLIENT_NAME}.csr" \ 157 | -subj "/CN=${CLIENT_NAME}" 158 | 159 | echo "Create client certificate" 160 | openssl x509 -req -in "${CLIENT_DIR}/${CLIENT_NAME}.csr" \ 161 | -CA ${ROOT_CA_CRT} -CAkey ${ROOT_CA_KEY} -CAcreateserial \ 162 | -out "${CLIENT_DIR}/${CLIENT_NAME}.crt" -days ${DAYS} 163 | 164 | echo "Copy certificates to project catalog" 165 | cp "${CLIENT_DIR}/${CLIENT_NAME}.key" src/ 166 | cp "${CLIENT_DIR}/${CLIENT_NAME}.crt" src/ 167 | cp "${ROOT_CA_CRT}" src/ 168 | -------------------------------------------------------------------------------- /img/postman_addr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/img/postman_addr.png -------------------------------------------------------------------------------- /img/postman_conn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/img/postman_conn.png -------------------------------------------------------------------------------- /img/postman_new_ws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/img/postman_new_ws.png -------------------------------------------------------------------------------- /img/running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/img/running.png -------------------------------------------------------------------------------- /img/wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/img/wifi.png -------------------------------------------------------------------------------- /img/work.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/img/work.png -------------------------------------------------------------------------------- /pics/client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/pics/client.png -------------------------------------------------------------------------------- /pics/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/pics/connect.png -------------------------------------------------------------------------------- /pics/esp_echo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/pics/esp_echo.png -------------------------------------------------------------------------------- /pics/hard_reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/pics/hard_reset.png -------------------------------------------------------------------------------- /pics/server_echo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/pics/server_echo.png -------------------------------------------------------------------------------- /pics/sync_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vovaman/example_async_websocket/f83d586cdb8a3b613dde4203319bae480de2052d/pics/sync_project.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -i https://pypi.org/simple 2 | fastapi 3 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import ssl 3 | from websockets.asyncio.server import serve 4 | import argparse 5 | from datetime import datetime 6 | 7 | async def handler(websocket): 8 | ssl_object = websocket.transport.get_extra_info('ssl_object') 9 | 10 | if ssl_object: 11 | client_cert = ssl_object.getpeercert() 12 | 13 | # Extract Common Name (CN) from certificate 14 | common_name = None 15 | if client_cert: 16 | # Parse subject 17 | subject = client_cert.get('subject', []) 18 | for item in subject: 19 | for attr in item: 20 | if attr[0].lower() == 'commonname': 21 | common_name = attr[1] 22 | break 23 | if common_name: 24 | break 25 | 26 | print(f"New client: {common_name}") 27 | else: 28 | print("New anonymous client.") 29 | 30 | try: 31 | async for message in websocket: 32 | print(f"{datetime.now()}: {message}") 33 | await websocket.send(f"Echo: {message}") 34 | except Exception as ex: 35 | print("Connection is closed.") 36 | 37 | async def main(): 38 | parser = argparse.ArgumentParser(description="Args like --key=value") 39 | parser.add_argument('--ssl', action="store_true", help="Switch TLS on.") 40 | parser.add_argument('--ssl-keyfile', type=str, help="Server's secret key file.") 41 | parser.add_argument('--ssl-certfile', type=str, help="Server's certificate file.") 42 | parser.add_argument('--ssl-password', default=None, type=str, help="Pass phrase.") 43 | parser.add_argument('--ssl-ca-cert', type=str, help="CA's certificate.") 44 | parser.add_argument('--ssl-certs-reqs', type=int, default=0, help="Flag for certificate requires.") 45 | parser.add_argument('--port', type=int, default=8000, help='Port number') 46 | 47 | args = parser.parse_args() 48 | 49 | ssl_context = None 50 | if args.ssl: 51 | ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) 52 | ssl_context.verify_mode = args.ssl_certs_reqs 53 | ssl_context.load_cert_chain(certfile=args.ssl_certfile, keyfile=args.ssl_keyfile, password=args.ssl_password) 54 | if args.ssl_certs_reqs: 55 | ssl_context.load_verify_locations(cafile=args.ssl_ca_cert) 56 | 57 | async with serve(handler, "0.0.0.0", args.port, ssl=ssl_context) as server: 58 | print(f"Server started on 0.0.0.0:{args.port}") 59 | await server.serve_forever() 60 | 61 | asyncio.run(main()) -------------------------------------------------------------------------------- /src/boot.py: -------------------------------------------------------------------------------- 1 | # boot.py -- run on boot-up 2 | -------------------------------------------------------------------------------- /src/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "wifi": { 3 | "SSID": "", 4 | "password": "", 5 | "attempts": 3, 6 | "delay_in_msec": 200 7 | }, 8 | "server": "", 9 | "ssl": { 10 | "ca": "", 11 | "key": "", 12 | "cert": "", 13 | "cert_reqs": 2 14 | }, 15 | "socket_delay_ms": 5 16 | } 17 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | import asyncio as a 2 | from main_f import read_loop, blink_loop 3 | 4 | async def main(): 5 | 6 | tasks = [read_loop(), blink_loop()] 7 | await a.gather(*tasks) 8 | 9 | a.run(main()) 10 | -------------------------------------------------------------------------------- /src/main_f/__init__.py: -------------------------------------------------------------------------------- 1 | from .func import read_loop, blink_loop 2 | -------------------------------------------------------------------------------- /src/main_f/func.py: -------------------------------------------------------------------------------- 1 | import network as net 2 | import asyncio as a 3 | import json 4 | from machine import Pin 5 | import gc 6 | 7 | from ws import AsyncWebsocketClient 8 | 9 | # trying to read config -------------------------------------------------------- 10 | # if config file format is wrong, exception is raised and program will stop 11 | print("Trying to load config...") 12 | 13 | f = open("../config.json") 14 | text = f.read() 15 | f.close() 16 | config = json.loads(text) 17 | del text 18 | # ------------------------------------------------------------------------------ 19 | 20 | print("Create WS instance...") 21 | # create instance of websocket 22 | ws = AsyncWebsocketClient(config['socket_delay_ms']) 23 | 24 | print("Created.") 25 | 26 | # this lock will be used for data interchange between loops -------------------- 27 | # better choice is to use uasynio.queue, but it is not documented yet 28 | lock = a.Lock() 29 | # this array stores messages from server 30 | data_from_ws = [] 31 | # ------------------------------------------------------------------------------ 32 | 33 | # SSID - network name 34 | # pwd - password 35 | # attempts - how many time will we try to connect to WiFi in one cycle 36 | # delay_in_msec - delay duration between attempts 37 | async def wifi_connect(SSID: str, pwd: str, attempts: int = 3, delay_in_msec: int = 200) -> network.WLAN: 38 | wifi = net.WLAN(net.STA_IF) 39 | 40 | wifi.active(1) 41 | count = 1 42 | 43 | while not wifi.isconnected() and count <= attempts: 44 | print("WiFi connecting. Attempt {}.".format(count)) 45 | if wifi.status() != net.STAT_CONNECTING: 46 | wifi.connect(SSID, pwd) 47 | await a.sleep_ms(delay_in_msec) 48 | count += 1 49 | 50 | if wifi.isconnected(): 51 | print("ifconfig: {}".format(wifi.ifconfig())) 52 | else: 53 | print("Wifi not connected.") 54 | 55 | return wifi 56 | 57 | # Function for main control loop. 58 | # It makes sense for ESP32 with integrated LED on Pin2. 59 | # Write another function for main loop for other controller types. 60 | p2 = Pin(2, Pin.OUT) 61 | async def blink_sos(): 62 | global p2 63 | 64 | async def blink(on_ms: int, off_ms: int): 65 | p2.on() 66 | await a.sleep_ms(on_ms) 67 | p2.off() 68 | await a.sleep_ms(off_ms) 69 | 70 | await blink(200, 50) 71 | await blink(200, 50) 72 | await blink(200, 50) 73 | await blink(400, 50) 74 | await blink(400, 50) 75 | await blink(400, 50) 76 | await blink(200, 50) 77 | await blink(200, 50) 78 | await blink(200, 50) 79 | 80 | # ------------------------------------------------------ 81 | # Main loop function: blink and send data to server. 82 | # This code emulates main control cycle for controller. 83 | async def blink_loop(): 84 | global lock 85 | global data_from_ws 86 | global ws 87 | 88 | # Main "work" cycle. It should be awaitable as possible. 89 | while True: 90 | await blink_sos() 91 | if ws is not None: 92 | if await ws.open(): 93 | await ws.send('SOS!') 94 | print("SOS!", end=' ') 95 | 96 | # lock data archive 97 | await lock.acquire() 98 | if data_from_ws: 99 | for item in data_from_ws: 100 | print("\nData from ws: {}".format(item)) 101 | data_from_ws = [] 102 | lock.release() 103 | gc.collect() 104 | 105 | await a.sleep_ms(400) 106 | # ------------------------------------------------------ 107 | 108 | 109 | # ------------------------------------------------------ 110 | # Task for read loop 111 | async def read_loop(): 112 | global config 113 | global lock 114 | global data_from_ws 115 | 116 | # may be, it 117 | wifi = await wifi_connect(config["wifi"]["SSID"], config["wifi"]["password"]) 118 | while True: 119 | gc.collect() 120 | if not wifi.isconnected(): 121 | wifi = await wifi_connect(config["wifi"]["SSID"], config["wifi"]["password"]) 122 | if not wifi.isconnected(): 123 | await a.sleep_ms(config["wifi"]["delay_in_msec"]) 124 | continue 125 | print("Handshaking...") 126 | # connect to test socket server 127 | # if protocol is wss, get certificate from config 128 | kw = {} 129 | if config["server"].startswith("wss"): 130 | ssl = config.get("ssl", {}) 131 | kw["keyfile"] = ssl.get("key") 132 | kw["certfile"] = ssl.get("cert") 133 | kw["cafile"] = ssl.get("ca") 134 | kw["cert_reqs"] = ssl.get("cert_reqs") 135 | 136 | handshaked = False 137 | while not handshaked: 138 | try: 139 | print("...handshaking...") 140 | if await ws.handshake(config["server"], **kw): 141 | handshaked = True 142 | print("handshaked!") 143 | except OSError as ex: 144 | print("Exception: ", ex) 145 | gc.collect() 146 | a.sleep_ms(1000) 147 | 148 | try: 149 | while await ws.open(): 150 | data = await ws.recv() 151 | 152 | if data is not None: 153 | await lock.acquire() 154 | data_from_ws.append(data) 155 | lock.release() 156 | 157 | await a.sleep_ms(50) 158 | except Exception as ex: 159 | print("Exception: {}".format(ex)) 160 | await a.sleep(1) 161 | # ------------------------------------------------------ 162 | -------------------------------------------------------------------------------- /src/pymakr.conf: -------------------------------------------------------------------------------- 1 | { 2 | "py_ignore": [ 3 | ".vscode", 4 | ".gitignore", 5 | ".git", 6 | "env", 7 | "venv" 8 | ], 9 | "name": "src" 10 | } --------------------------------------------------------------------------------