commit 24d33b33c0b8f90bbeadff9eca87d603272c9d25 Author: Daniele Tricoli Date: Thu Feb 9 23:56:22 2023 +0100 Initial import diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9da4340 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +.pytest_cache +.envrc +dist/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..80f0a27 --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2023 Daniele Tricoli +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..358cbca --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# freakble + +A simple tool to send messages into [FreakWAN](https://github.com/antirez/sx1276-micropython-driver/) +over Bluetooth low energy. diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..42976d9 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,279 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + +[[package]] +name = "async-timeout" +version = "4.0.2" +description = "Timeout context manager for asyncio programs" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] + +[[package]] +name = "ble-serial" +version = "2.7.0" +description = "A package to connect BLE serial adapters" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ble-serial-2.7.0.tar.gz", hash = "sha256:8f16fbf07cef0ea36f6e79d6f035982e17ec9e8c3690de9ac06702eaf7cccb78"}, + {file = "ble_serial-2.7.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:cc106ac2e7afe3ca4a8adbb32d795bb6d13556de29dac24dc243ff7a2e6b1e6b"}, +] + +[package.dependencies] +bleak = ">=0.18.0" +coloredlogs = ">=15.0" +pyserial = {version = ">=3.4.0", markers = "platform_system == \"Windows\""} + +[[package]] +name = "bleak" +version = "0.19.5" +description = "Bluetooth Low Energy platform Agnostic Klient" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "bleak-0.19.5-py3-none-any.whl", hash = "sha256:31e92e6754379bb394b8544457c77ce09a8a7dbc5f9adf3119b34576c901ef1e"}, + {file = "bleak-0.19.5.tar.gz", hash = "sha256:87845a96453c58c19031c735444a7b3156800534bcd3f23ba74e119e9ae3cd88"}, +] + +[package.dependencies] +async-timeout = ">=3.0.0,<5" +bleak-winrt = {version = ">=1.2.0,<2.0.0", markers = "platform_system == \"Windows\""} +dbus-fast = {version = ">=1.22.0,<2.0.0", markers = "platform_system == \"Linux\""} +pyobjc-core = {version = ">=8.5.1,<9.0.0", markers = "platform_system == \"Darwin\""} +pyobjc-framework-CoreBluetooth = {version = ">=8.5.1,<9.0.0", markers = "platform_system == \"Darwin\""} +pyobjc-framework-libdispatch = {version = ">=8.5.1,<9.0.0", markers = "platform_system == \"Darwin\""} + +[[package]] +name = "bleak-winrt" +version = "1.2.0" +description = "Python WinRT bindings for Bleak" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "bleak-winrt-1.2.0.tar.gz", hash = "sha256:0577d070251b9354fc6c45ffac57e39341ebb08ead014b1bdbd43e211d2ce1d6"}, + {file = "bleak_winrt-1.2.0-cp310-cp310-win32.whl", hash = "sha256:a2ae3054d6843ae0cfd3b94c83293a1dfd5804393977dd69bde91cb5099fc47c"}, + {file = "bleak_winrt-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:677df51dc825c6657b3ae94f00bd09b8ab88422b40d6a7bdbf7972a63bc44e9a"}, + {file = "bleak_winrt-1.2.0-cp311-cp311-win32.whl", hash = "sha256:9449cdb942f22c9892bc1ada99e2ccce9bea8a8af1493e81fefb6de2cb3a7b80"}, + {file = "bleak_winrt-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:98c1b5a6a6c431ac7f76aa4285b752fe14a1c626bd8a1dfa56f66173ff120bee"}, + {file = "bleak_winrt-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:623ac511696e1f58d83cb9c431e32f613395f2199b3db7f125a3d872cab968a4"}, + {file = "bleak_winrt-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:13ab06dec55469cf51a2c187be7b630a7a2922e1ea9ac1998135974a7239b1e3"}, + {file = "bleak_winrt-1.2.0-cp38-cp38-win32.whl", hash = "sha256:5a36ff8cd53068c01a795a75d2c13054ddc5f99ce6de62c1a97cd343fc4d0727"}, + {file = "bleak_winrt-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:810c00726653a962256b7acd8edf81ab9e4a3c66e936a342ce4aec7dbd3a7263"}, + {file = "bleak_winrt-1.2.0-cp39-cp39-win32.whl", hash = "sha256:dd740047a08925bde54bec357391fcee595d7b8ca0c74c87170a5cbc3f97aa0a"}, + {file = "bleak_winrt-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:63130c11acfe75c504a79c01f9919e87f009f5e742bfc7b7a5c2a9c72bf591a7"}, +] + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coloredlogs" +version = "15.0.1" +description = "Colored terminal output for Python's logging module" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, + {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, +] + +[package.dependencies] +humanfriendly = ">=9.1" + +[package.extras] +cron = ["capturer (>=2.4)"] + +[[package]] +name = "dbus-fast" +version = "1.84.0" +description = "A faster version of dbus-next" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dbus_fast-1.84.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:4c067d48a3c6cd974ee908022b6a375244a388009d42f0216520626a90d972a8"}, + {file = "dbus_fast-1.84.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:918a83c66ff252a793dc079126d8508761ff23b68595f8de93e0b621b7472ee5"}, + {file = "dbus_fast-1.84.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b3b22db8108fb917f12c847ab5c3899f990e202ad6d8c9c08aeade4ad993e08"}, + {file = "dbus_fast-1.84.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2745a491022d29d80aa605e888fd807a4f93dd03dae797d00d753e8a92eb37e8"}, + {file = "dbus_fast-1.84.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:156c44ba4c0fa7ee5f8a59f66ba1c6fce75992d477de34cd6ed0350e8a496450"}, + {file = "dbus_fast-1.84.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fc03d61d1f85353bcc29d954c6c0d0c3c62f418714c667204fd301ab26b1b7e"}, + {file = "dbus_fast-1.84.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f3d0d5e58782b8ccbf422b48257b32439c3938fc99776f90f11834c8b0e6be04"}, + {file = "dbus_fast-1.84.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ac5f4ee0cba5f5c326c1f24b5ffae21138384dfec156f32e0105e78349b7f558"}, + {file = "dbus_fast-1.84.0-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:883cdb93a44586e3eaf9e5623eaec6af2ba80789c2b2665c83f2f97683971f0c"}, + {file = "dbus_fast-1.84.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb96aaea2f043b201add04db3616eb716557ecc87274389b6f366a9486355f74"}, + {file = "dbus_fast-1.84.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b7b26edec3635c69d2f84ac8cd68d4b2208d45675409bdaaf03d05255c469088"}, + {file = "dbus_fast-1.84.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f7524af1b8158e2fa315297a1254221b6d0f56ace9ba919553841f338209f02a"}, + {file = "dbus_fast-1.84.0-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:e84cfc5b257e632d277d34d049137cae8baf734cc959a99507976920c42d1462"}, + {file = "dbus_fast-1.84.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c620bb0210586f1ea06a5c755bb12b8ccc5a2fc7e192f4edcca570f18f4ce284"}, + {file = "dbus_fast-1.84.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1613af6d4cf8e046bec30b8955163cb2cb8e6143aac4eff033c43f83f88d2c59"}, + {file = "dbus_fast-1.84.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fbd85e487143248bb296f089feaf9b4ac859aa821839f35c85298d334ad12af3"}, + {file = "dbus_fast-1.84.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:54cdf4223e6698e9e2264fbcafac7a6f6bab5831b8dd6e722542f0fbb5faf132"}, + {file = "dbus_fast-1.84.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b7f59e2d70465ac9295f90e3ee5e731d0524f3f683c7c3e11eb7cb7a6d05b4"}, + {file = "dbus_fast-1.84.0-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:09fb7c0ee3454f0c696d89a3a567ad184cbe8fbea0db35c1b30876e93b08abec"}, + {file = "dbus_fast-1.84.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4f58f544beea53044dd0233ea867a256a8be76bfd6252128eb2a7b6dda77298e"}, + {file = "dbus_fast-1.84.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:571083ad74447618b173472fef95289eb915c2a6f69355b97dbad660ef51637f"}, + {file = "dbus_fast-1.84.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:7a624cc2b40152ac18e6e38a9f0e65c4573ba76da4e5cc368cde3b4fd46f5ba1"}, + {file = "dbus_fast-1.84.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:747b61d1b3b5a32702ac2ba5b8544775cdb1503f6c922950d19e8aa1ddb577c1"}, + {file = "dbus_fast-1.84.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:7c2033552309b9929f7f109e176a1786c30b532af63ab14c32711ee39ec5a78f"}, + {file = "dbus_fast-1.84.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:543f15d25abab42d4ebe39e7f955ea8d457f9cc8b0b8bf4a3dbe0f648aee029d"}, + {file = "dbus_fast-1.84.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:d7cb4a7b8a3e60f7aa1959d487c6423e4d6387762cc1f08ab2a8ad1203719c8e"}, + {file = "dbus_fast-1.84.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16d60d00ed31522e0a663845c69173d815d501b4272b8fdf685b3a376a49c20d"}, + {file = "dbus_fast-1.84.0.tar.gz", hash = "sha256:d64f1b68c1c81268e846471caeb9264a9306a6c6ad356c30d5cdf7d1ecc251a1"}, +] + +[[package]] +name = "humanfriendly" +version = "10.0" +description = "Human friendly output for text interfaces using Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, + {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, +] + +[package.dependencies] +pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""} + +[[package]] +name = "pyobjc-core" +version = "8.5.1" +description = "Python<->ObjC Interoperability Module" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyobjc-core-8.5.1.tar.gz", hash = "sha256:f8592a12de076c27006700c4a46164478564fa33d7da41e7cbdd0a3bf9ddbccf"}, + {file = "pyobjc_core-8.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b62dcf987cc511188fc2aa5b4d3b9fd895361ea4984380463497ce4b0752ddf4"}, + {file = "pyobjc_core-8.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0accc653501a655f66c13f149a1d3d30e6cb65824edf852f7960a00c4f930d5b"}, + {file = "pyobjc_core-8.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f82b32affc898e9e5af041c1cecde2c99f2ce160b87df77f678c99f1550a4655"}, + {file = "pyobjc_core-8.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f7b2f6b6f3caeb882c658fe0c7098be2e8b79893d84daa8e636cb3e58a07df00"}, + {file = "pyobjc_core-8.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:872c0202c911a5a2f1269261c168e36569f6ddac17e5d854ac19e581726570cc"}, + {file = "pyobjc_core-8.5.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:21f92e231a4bae7f2d160d065f5afbf5e859a1e37f29d34ac12592205fc8c108"}, + {file = "pyobjc_core-8.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:315334dd09781129af6a39641248891c4caa57043901750b0139c6614ce84ec0"}, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "8.5.1" +description = "Wrappers for the Cocoa frameworks on macOS" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyobjc-framework-Cocoa-8.5.1.tar.gz", hash = "sha256:9a3de5cdb4644e85daf53f2ed912ef6c16ea5804a9e65552eafe62c2e139eb8c"}, + {file = "pyobjc_framework_Cocoa-8.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa572acc2628488a47be8d19f4701fc96fce7377cc4da18316e1e08c3918521a"}, + {file = "pyobjc_framework_Cocoa-8.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cb3ae21c8d81b7f02a891088c623cef61bca89bd671eff58c632d2f926b649f3"}, + {file = "pyobjc_framework_Cocoa-8.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:88f08f5bd94c66d373d8413c1d08218aff4cff0b586e0cc4249b2284023e7577"}, + {file = "pyobjc_framework_Cocoa-8.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:063683b57e4bd88cb0f9631ae65d25ec4eecf427d2fe8d0c578f88da9c896f3f"}, + {file = "pyobjc_framework_Cocoa-8.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f8806ddfac40620fb27f185d0f8937e69e330617319ecc2eccf6b9c8451bdd1"}, + {file = "pyobjc_framework_Cocoa-8.5.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7733a9a201df9e0cc2a0cf7bf54d76bd7981cba9b599353b243e3e0c9eefec10"}, + {file = "pyobjc_framework_Cocoa-8.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f0ab227f99d3e25dd3db73f8cde0999914a5f0dd6a08600349d25f95eaa0da63"}, +] + +[package.dependencies] +pyobjc-core = ">=8.5.1" + +[[package]] +name = "pyobjc-framework-corebluetooth" +version = "8.5.1" +description = "Wrappers for the framework CoreBluetooth on macOS" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyobjc-framework-CoreBluetooth-8.5.1.tar.gz", hash = "sha256:b4f621fc3b5bf289db58e64fd746773b18297f87a0ffc5502de74f69133301c1"}, + {file = "pyobjc_framework_CoreBluetooth-8.5.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:bc720f2987a4d28dc73b13146e7c104d717100deb75c244da68f1d0849096661"}, + {file = "pyobjc_framework_CoreBluetooth-8.5.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2167f22886beb5b3ae69e475e055403f28eab065c49a25e2b98b050b483be799"}, + {file = "pyobjc_framework_CoreBluetooth-8.5.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:aa9587a36eca143701731e8bb6c369148f8cc48c28168d41e7323828e5117f2d"}, +] + +[package.dependencies] +pyobjc-core = ">=8.5.1" +pyobjc-framework-Cocoa = ">=8.5.1" + +[[package]] +name = "pyobjc-framework-libdispatch" +version = "8.5.1" +description = "Wrappers for libdispatch on macOS" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyobjc-framework-libdispatch-8.5.1.tar.gz", hash = "sha256:066fb34fceb326307559104d45532ec2c7b55426f9910b70dbefd5d1b8fd530f"}, + {file = "pyobjc_framework_libdispatch-8.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a316646ab30ba2a97bc828f8e27e7bb79efdf993d218a9c5118396b4f81dc762"}, + {file = "pyobjc_framework_libdispatch-8.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7730a29e4d9c7d8c2e8d9ffb60af0ab6699b2186296d2bff0a2dd54527578bc3"}, + {file = "pyobjc_framework_libdispatch-8.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:76208d9d2b0071df2950800495ac0300360bb5f25cbe9ab880b65cb809764979"}, + {file = "pyobjc_framework_libdispatch-8.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1ad9aa4773ff1d89bf4385c081824c4f8708b50e3ac2fe0a9d590153242c0f67"}, + {file = "pyobjc_framework_libdispatch-8.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81e1833bd26f15930faba678f9efdffafc79ec04e2ea8b6d1b88cafc0883af97"}, + {file = "pyobjc_framework_libdispatch-8.5.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:73226e224436eb6383e7a8a811c90ed597995adb155b4f46d727881a383ac550"}, + {file = "pyobjc_framework_libdispatch-8.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d115355ce446fc073c75cedfd7ab0a13958adda8e3a3b1e421e1f1e5f65640da"}, +] + +[package.dependencies] +pyobjc-core = ">=8.5.1" + +[[package]] +name = "pyreadline3" +version = "3.4.1" +description = "A python implementation of GNU readline." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, + {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, +] + +[[package]] +name = "pyserial" +version = "3.5" +description = "Python Serial Port Extension" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0"}, + {file = "pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb"}, +] + +[package.extras] +cp2110 = ["hidapi"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.11" +content-hash = "36a7b82cddcd68682fd20572833866f9ae2caf700ddaa71c0f564e6baa9c0004" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1847992 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,20 @@ +[tool.poetry] +name = "freakble" +version = "0.1.0" +description = "" +authors = ["Daniele Tricoli "] +readme = "README.md" +packages = [{include = "freakble", from = "src"}] + +[tool.poetry.dependencies] +python = "^3.11" +ble-serial = "^2.7.0" +click = "^8.1.3" + +[tool.poetry.scripts] +freakble = "freakble.main:run" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/src/freakble/__init__.py b/src/freakble/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/freakble/main.py b/src/freakble/main.py new file mode 100644 index 0000000..a56f082 --- /dev/null +++ b/src/freakble/main.py @@ -0,0 +1,85 @@ +import asyncio +import logging +from functools import wraps + +import click +from ble_serial.bluetooth.ble_interface import BLE_interface + + +def coro(f): + @wraps(f) + def wrapper(*args, **kwargs): + return asyncio.run(f(*args, **kwargs)) + + return wrapper + + +async def send_conditionally(ble: BLE_interface, data: bytes, loop: bool): + """Send specified data. + + Raise asyncio.CancelledError if loop == True after data is sent once. + """ + ble.queue_send(data) + # TODO: Make the user able to specify sleep duration. + await asyncio.sleep(0.1) + if not loop: + raise asyncio.CancelledError + + +async def send_forever(ble: BLE_interface, data: bytes, loop: bool): + """Send data forever.""" + while True: + await send_conditionally(ble, data, loop) + + +def _receive_callback(data: bytes): + logging.debug("Received:", data) + + +@click.group() +@click.option("--adapter", default="hci0", type=str, help="ble adapter [default: hci0]") +@click.option("--device", required=True, type=str, help="ble device address") +@click.pass_context +def cli(ctx, adapter, device): + """A simple tool to send messages into FreakWAN.""" + ctx.ensure_object(dict) + ctx.obj["ADAPTER"] = adapter + ctx.obj["DEVICE"] = device + ctx.obj["BLE"] = BLE_interface(ctx.obj["ADAPTER"], None) + + +@cli.command() +@click.pass_context +@click.option("--loop", is_flag=True, default=False, help="send forever the messages") +@click.argument("messages", type=str, nargs=-1) +@coro +async def send(ctx, messages, loop): + """Send one or more messages over BLE to a specific device.""" + msg = " ".join(messages) + ble = ctx.obj["BLE"] + device = ctx.obj["DEVICE"] + ble.set_receiver(_receive_callback) + try: + logging.info(f"Connecting to {device}...") + await ble.connect(device, "public", 10.0) + # TODO: Handle WRITE_UUID and READ_UUID. + await ble.setup_chars(None, None, "rw") + + await asyncio.gather( + ble.send_loop(), + send_forever(ble, bytes(msg, "utf-8"), loop), + ) + except asyncio.CancelledError: + pass + finally: + await ble.disconnect() + + +def run(): + """CLI entrypoint.""" + # ble-serial fire a warning on disconnect, but our main use case is to just + # send a message and disconnect, so we disable logging here. + # TODO: Make configurable by the user. + logging.disable() + + asyncio.run(cli()) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29