From c66f0fb6caeafbe89c6a7a03124c3ce651bf4150 Mon Sep 17 00:00:00 2001 From: jr4 Date: Wed, 11 Dec 2024 22:17:07 -0600 Subject: [PATCH 1/3] feat: basic support for hello fairy --- .github/workflows/ci.yml | 3 +- .github/workflows/labels.yml | 2 +- examples/run.py | 19 ++- poetry.lock | 241 ++++++++++++++--------------------- pyproject.toml | 2 +- src/led_ble/const.py | 9 +- src/led_ble/led_ble.py | 99 ++++++++++---- src/led_ble/model_db.py | 9 ++ src/led_ble/protocol.py | 119 +++++++++++++++++ 9 files changed, 330 insertions(+), 173 deletions(-) create mode 100644 src/led_ble/protocol.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55aac95..d87c6a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v3 with: - python-version: "3.9" + python-version: "3.10" - uses: pre-commit/action@v2.0.3 # Make sure commit messages follow the conventional commits convention: @@ -36,7 +36,6 @@ jobs: fail-fast: false matrix: python-version: - - "3.9" - "3.10" - "3.11" - "3.11" diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index 638716e..008ea11 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -15,7 +15,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.8 + python-version: 3.10 - name: Install labels run: pip install labels - name: Sync config with Github diff --git a/examples/run.py b/examples/run.py index 273ec77..43ad8c0 100644 --- a/examples/run.py +++ b/examples/run.py @@ -9,8 +9,7 @@ _LOGGER = logging.getLogger(__name__) -ADDRESS = "D0291B39-3A1B-7FF2-787B-4E743FED5B25" -ADDRESS = "D0291B39-3A1B-7FF2-787B-4E743FED5B25" +ADDRESS = "BE:27:E1:00:10:63" # Hello Fairy-1063PPPP async def run() -> None: @@ -34,20 +33,36 @@ def on_state_changed(state: LEDBLEState) -> None: device = await future led = LEDBLE(device) cancel_callback = led.register_callback(on_state_changed) + _LOGGER.info("update...") await led.update() + _LOGGER.info("turn_on...") await led.turn_on() + _LOGGER.info("set_rgb(red)...") await led.set_rgb((255, 0, 0), 255) await asyncio.sleep(1) + _LOGGER.info("set_rgb(green)...") await led.set_rgb((0, 255, 0), 128) await asyncio.sleep(1) + _LOGGER.info("set_rgb(blue)...") await led.set_rgb((0, 0, 255), 255) await asyncio.sleep(1) + _LOGGER.info("set_rgbw(white)...") await led.set_rgbw((255, 255, 255, 128), 255) await asyncio.sleep(1) + _LOGGER.info("set_preset_pattern(1)...") + await led.async_set_preset_pattern(1, 100, 100) + await asyncio.sleep(2) + _LOGGER.info("set_preset_pattern(59)...") + await led.async_set_preset_pattern(59, 100, 100) + await asyncio.sleep(2) + _LOGGER.info("turn_off...") await led.turn_off() + _LOGGER.info("update...") await led.update() + _LOGGER.info("finish...") cancel_callback() await scanner.stop() + _LOGGER.info("done") logging.basicConfig(level=logging.INFO) diff --git a/poetry.lock b/poetry.lock index bb86538..ac61503 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiofiles" @@ -24,87 +24,87 @@ files = [ [[package]] name = "aiohttp" -version = "3.11.10" +version = "3.11.11" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" files = [ - {file = "aiohttp-3.11.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cbad88a61fa743c5d283ad501b01c153820734118b65aee2bd7dbb735475ce0d"}, - {file = "aiohttp-3.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80886dac673ceaef499de2f393fc80bb4481a129e6cb29e624a12e3296cc088f"}, - {file = "aiohttp-3.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61b9bae80ed1f338c42f57c16918853dc51775fb5cb61da70d590de14d8b5fb4"}, - {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e2e576caec5c6a6b93f41626c9c02fc87cd91538b81a3670b2e04452a63def6"}, - {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02c13415b5732fb6ee7ff64583a5e6ed1c57aa68f17d2bda79c04888dfdc2769"}, - {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfce37f31f20800a6a6620ce2cdd6737b82e42e06e6e9bd1b36f546feb3c44f"}, - {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3bbbfff4c679c64e6e23cb213f57cc2c9165c9a65d63717108a644eb5a7398df"}, - {file = "aiohttp-3.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49c7dbbc1a559ae14fc48387a115b7d4bbc84b4a2c3b9299c31696953c2a5219"}, - {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68386d78743e6570f054fe7949d6cb37ef2b672b4d3405ce91fafa996f7d9b4d"}, - {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9ef405356ba989fb57f84cac66f7b0260772836191ccefbb987f414bcd2979d9"}, - {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5d6958671b296febe7f5f859bea581a21c1d05430d1bbdcf2b393599b1cdce77"}, - {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:99b7920e7165be5a9e9a3a7f1b680f06f68ff0d0328ff4079e5163990d046767"}, - {file = "aiohttp-3.11.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0dc49f42422163efb7e6f1df2636fe3db72713f6cd94688e339dbe33fe06d61d"}, - {file = "aiohttp-3.11.10-cp310-cp310-win32.whl", hash = "sha256:40d1c7a7f750b5648642586ba7206999650208dbe5afbcc5284bcec6579c9b91"}, - {file = "aiohttp-3.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:68ff6f48b51bd78ea92b31079817aff539f6c8fc80b6b8d6ca347d7c02384e33"}, - {file = "aiohttp-3.11.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:77c4aa15a89847b9891abf97f3d4048f3c2d667e00f8a623c89ad2dccee6771b"}, - {file = "aiohttp-3.11.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:909af95a72cedbefe5596f0bdf3055740f96c1a4baa0dd11fd74ca4de0b4e3f1"}, - {file = "aiohttp-3.11.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:386fbe79863eb564e9f3615b959e28b222259da0c48fd1be5929ac838bc65683"}, - {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3de34936eb1a647aa919655ff8d38b618e9f6b7f250cc19a57a4bf7fd2062b6d"}, - {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c9527819b29cd2b9f52033e7fb9ff08073df49b4799c89cb5754624ecd98299"}, - {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a96e3e03300b41f261bbfd40dfdbf1c301e87eab7cd61c054b1f2e7c89b9e8"}, - {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98f5635f7b74bcd4f6f72fcd85bea2154b323a9f05226a80bc7398d0c90763b0"}, - {file = "aiohttp-3.11.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:03b6002e20938fc6ee0918c81d9e776bebccc84690e2b03ed132331cca065ee5"}, - {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6362cc6c23c08d18ddbf0e8c4d5159b5df74fea1a5278ff4f2c79aed3f4e9f46"}, - {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3691ed7726fef54e928fe26344d930c0c8575bc968c3e239c2e1a04bd8cf7838"}, - {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31d5093d3acd02b31c649d3a69bb072d539d4c7659b87caa4f6d2bcf57c2fa2b"}, - {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8b3cf2dc0f0690a33f2d2b2cb15db87a65f1c609f53c37e226f84edb08d10f52"}, - {file = "aiohttp-3.11.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fbbaea811a2bba171197b08eea288b9402faa2bab2ba0858eecdd0a4105753a3"}, - {file = "aiohttp-3.11.10-cp311-cp311-win32.whl", hash = "sha256:4b2c7ac59c5698a7a8207ba72d9e9c15b0fc484a560be0788b31312c2c5504e4"}, - {file = "aiohttp-3.11.10-cp311-cp311-win_amd64.whl", hash = "sha256:974d3a2cce5fcfa32f06b13ccc8f20c6ad9c51802bb7f829eae8a1845c4019ec"}, - {file = "aiohttp-3.11.10-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b78f053a7ecfc35f0451d961dacdc671f4bcbc2f58241a7c820e9d82559844cf"}, - {file = "aiohttp-3.11.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab7485222db0959a87fbe8125e233b5a6f01f4400785b36e8a7878170d8c3138"}, - {file = "aiohttp-3.11.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cf14627232dfa8730453752e9cdc210966490992234d77ff90bc8dc0dce361d5"}, - {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076bc454a7e6fd646bc82ea7f98296be0b1219b5e3ef8a488afbdd8e81fbac50"}, - {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:482cafb7dc886bebeb6c9ba7925e03591a62ab34298ee70d3dd47ba966370d2c"}, - {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf3d1a519a324af764a46da4115bdbd566b3c73fb793ffb97f9111dbc684fc4d"}, - {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24213ba85a419103e641e55c27dc7ff03536c4873470c2478cce3311ba1eee7b"}, - {file = "aiohttp-3.11.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b99acd4730ad1b196bfb03ee0803e4adac371ae8efa7e1cbc820200fc5ded109"}, - {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:14cdb5a9570be5a04eec2ace174a48ae85833c2aadc86de68f55541f66ce42ab"}, - {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7e97d622cb083e86f18317282084bc9fbf261801b0192c34fe4b1febd9f7ae69"}, - {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:012f176945af138abc10c4a48743327a92b4ca9adc7a0e078077cdb5dbab7be0"}, - {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44224d815853962f48fe124748227773acd9686eba6dc102578defd6fc99e8d9"}, - {file = "aiohttp-3.11.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c87bf31b7fdab94ae3adbe4a48e711bfc5f89d21cf4c197e75561def39e223bc"}, - {file = "aiohttp-3.11.10-cp312-cp312-win32.whl", hash = "sha256:06a8e2ee1cbac16fe61e51e0b0c269400e781b13bcfc33f5425912391a542985"}, - {file = "aiohttp-3.11.10-cp312-cp312-win_amd64.whl", hash = "sha256:be2b516f56ea883a3e14dda17059716593526e10fb6303189aaf5503937db408"}, - {file = "aiohttp-3.11.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8cc5203b817b748adccb07f36390feb730b1bc5f56683445bfe924fc270b8816"}, - {file = "aiohttp-3.11.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ef359ebc6949e3a34c65ce20230fae70920714367c63afd80ea0c2702902ccf"}, - {file = "aiohttp-3.11.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9bca390cb247dbfaec3c664326e034ef23882c3f3bfa5fbf0b56cad0320aaca5"}, - {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:811f23b3351ca532af598405db1093f018edf81368e689d1b508c57dcc6b6a32"}, - {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddf5f7d877615f6a1e75971bfa5ac88609af3b74796ff3e06879e8422729fd01"}, - {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ab29b8a0beb6f8eaf1e5049252cfe74adbaafd39ba91e10f18caeb0e99ffb34"}, - {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c49a76c1038c2dd116fa443eba26bbb8e6c37e924e2513574856de3b6516be99"}, - {file = "aiohttp-3.11.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f3dc0e330575f5b134918976a645e79adf333c0a1439dcf6899a80776c9ab39"}, - {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:efb15a17a12497685304b2d976cb4939e55137df7b09fa53f1b6a023f01fcb4e"}, - {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:db1d0b28fcb7f1d35600150c3e4b490775251dea70f894bf15c678fdd84eda6a"}, - {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:15fccaf62a4889527539ecb86834084ecf6e9ea70588efde86e8bc775e0e7542"}, - {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:593c114a2221444f30749cc5e5f4012488f56bd14de2af44fe23e1e9894a9c60"}, - {file = "aiohttp-3.11.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7852bbcb4d0d2f0c4d583f40c3bc750ee033265d80598d0f9cb6f372baa6b836"}, - {file = "aiohttp-3.11.10-cp313-cp313-win32.whl", hash = "sha256:65e55ca7debae8faaffee0ebb4b47a51b4075f01e9b641c31e554fd376595c6c"}, - {file = "aiohttp-3.11.10-cp313-cp313-win_amd64.whl", hash = "sha256:beb39a6d60a709ae3fb3516a1581777e7e8b76933bb88c8f4420d875bb0267c6"}, - {file = "aiohttp-3.11.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0580f2e12de2138f34debcd5d88894786453a76e98febaf3e8fe5db62d01c9bf"}, - {file = "aiohttp-3.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a55d2ad345684e7c3dd2c20d2f9572e9e1d5446d57200ff630e6ede7612e307f"}, - {file = "aiohttp-3.11.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04814571cb72d65a6899db6099e377ed00710bf2e3eafd2985166f2918beaf59"}, - {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e44a9a3c053b90c6f09b1bb4edd880959f5328cf63052503f892c41ea786d99f"}, - {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:502a1464ccbc800b4b1995b302efaf426e8763fadf185e933c2931df7db9a199"}, - {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:613e5169f8ae77b1933e42e418a95931fb4867b2991fc311430b15901ed67079"}, - {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cca22a61b7fe45da8fc73c3443150c3608750bbe27641fc7558ec5117b27fdf"}, - {file = "aiohttp-3.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86a5dfcc39309470bd7b68c591d84056d195428d5d2e0b5ccadfbaf25b026ebc"}, - {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:77ae58586930ee6b2b6f696c82cf8e78c8016ec4795c53e36718365f6959dc82"}, - {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:78153314f26d5abef3239b4a9af20c229c6f3ecb97d4c1c01b22c4f87669820c"}, - {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:98283b94cc0e11c73acaf1c9698dea80c830ca476492c0fe2622bd931f34b487"}, - {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:53bf2097e05c2accc166c142a2090e4c6fd86581bde3fd9b2d3f9e93dda66ac1"}, - {file = "aiohttp-3.11.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5532f0441fc09c119e1dca18fbc0687e64fbeb45aa4d6a87211ceaee50a74c4"}, - {file = "aiohttp-3.11.10-cp39-cp39-win32.whl", hash = "sha256:47ad15a65fb41c570cd0ad9a9ff8012489e68176e7207ec7b82a0940dddfd8be"}, - {file = "aiohttp-3.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:c6b9e6d7e41656d78e37ce754813fa44b455c3d0d0dced2a047def7dc5570b74"}, - {file = "aiohttp-3.11.10.tar.gz", hash = "sha256:b1fc6b45010a8d0ff9e88f9f2418c6fd408c99c211257334aff41597ebece42e"}, + {file = "aiohttp-3.11.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a60804bff28662cbcf340a4d61598891f12eea3a66af48ecfdc975ceec21e3c8"}, + {file = "aiohttp-3.11.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b4fa1cb5f270fb3eab079536b764ad740bb749ce69a94d4ec30ceee1b5940d5"}, + {file = "aiohttp-3.11.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:731468f555656767cda219ab42e033355fe48c85fbe3ba83a349631541715ba2"}, + {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb23d8bb86282b342481cad4370ea0853a39e4a32a0042bb52ca6bdde132df43"}, + {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f047569d655f81cb70ea5be942ee5d4421b6219c3f05d131f64088c73bb0917f"}, + {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd7659baae9ccf94ae5fe8bfaa2c7bc2e94d24611528395ce88d009107e00c6d"}, + {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af01e42ad87ae24932138f154105e88da13ce7d202a6de93fafdafb2883a00ef"}, + {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5854be2f3e5a729800bac57a8d76af464e160f19676ab6aea74bde18ad19d438"}, + {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6526e5fb4e14f4bbf30411216780c9967c20c5a55f2f51d3abd6de68320cc2f3"}, + {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:85992ee30a31835fc482468637b3e5bd085fa8fe9392ba0bdcbdc1ef5e9e3c55"}, + {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:88a12ad8ccf325a8a5ed80e6d7c3bdc247d66175afedbe104ee2aaca72960d8e"}, + {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0a6d3fbf2232e3a08c41eca81ae4f1dff3d8f1a30bae415ebe0af2d2458b8a33"}, + {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84a585799c58b795573c7fa9b84c455adf3e1d72f19a2bf498b54a95ae0d194c"}, + {file = "aiohttp-3.11.11-cp310-cp310-win32.whl", hash = "sha256:bfde76a8f430cf5c5584553adf9926534352251d379dcb266ad2b93c54a29745"}, + {file = "aiohttp-3.11.11-cp310-cp310-win_amd64.whl", hash = "sha256:0fd82b8e9c383af11d2b26f27a478640b6b83d669440c0a71481f7c865a51da9"}, + {file = "aiohttp-3.11.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ba74ec819177af1ef7f59063c6d35a214a8fde6f987f7661f4f0eecc468a8f76"}, + {file = "aiohttp-3.11.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4af57160800b7a815f3fe0eba9b46bf28aafc195555f1824555fa2cfab6c1538"}, + {file = "aiohttp-3.11.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffa336210cf9cd8ed117011085817d00abe4c08f99968deef0013ea283547204"}, + {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b8fe282183e4a3c7a1b72f5ade1094ed1c6345a8f153506d114af5bf8accd9"}, + {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af41686ccec6a0f2bdc66686dc0f403c41ac2089f80e2214a0f82d001052c03"}, + {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70d1f9dde0e5dd9e292a6d4d00058737052b01f3532f69c0c65818dac26dc287"}, + {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:249cc6912405917344192b9f9ea5cd5b139d49e0d2f5c7f70bdfaf6b4dbf3a2e"}, + {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eb98d90b6690827dcc84c246811feeb4e1eea683c0eac6caed7549be9c84665"}, + {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec82bf1fda6cecce7f7b915f9196601a1bd1a3079796b76d16ae4cce6d0ef89b"}, + {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9fd46ce0845cfe28f108888b3ab17abff84ff695e01e73657eec3f96d72eef34"}, + {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bd176afcf8f5d2aed50c3647d4925d0db0579d96f75a31e77cbaf67d8a87742d"}, + {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ec2aa89305006fba9ffb98970db6c8221541be7bee4c1d027421d6f6df7d1ce2"}, + {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:92cde43018a2e17d48bb09c79e4d4cb0e236de5063ce897a5e40ac7cb4878773"}, + {file = "aiohttp-3.11.11-cp311-cp311-win32.whl", hash = "sha256:aba807f9569455cba566882c8938f1a549f205ee43c27b126e5450dc9f83cc62"}, + {file = "aiohttp-3.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:ae545f31489548c87b0cced5755cfe5a5308d00407000e72c4fa30b19c3220ac"}, + {file = "aiohttp-3.11.11-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e595c591a48bbc295ebf47cb91aebf9bd32f3ff76749ecf282ea7f9f6bb73886"}, + {file = "aiohttp-3.11.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ea1b59dc06396b0b424740a10a0a63974c725b1c64736ff788a3689d36c02d2"}, + {file = "aiohttp-3.11.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8811f3f098a78ffa16e0ea36dffd577eb031aea797cbdba81be039a4169e242c"}, + {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7227b87a355ce1f4bf83bfae4399b1f5bb42e0259cb9405824bd03d2f4336a"}, + {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d40f9da8cabbf295d3a9dae1295c69975b86d941bc20f0a087f0477fa0a66231"}, + {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffb3dc385f6bb1568aa974fe65da84723210e5d9707e360e9ecb51f59406cd2e"}, + {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f5f7515f3552d899c61202d99dcb17d6e3b0de777900405611cd747cecd1b8"}, + {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3499c7ffbfd9c6a3d8d6a2b01c26639da7e43d47c7b4f788016226b1e711caa8"}, + {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8e2bf8029dbf0810c7bfbc3e594b51c4cc9101fbffb583a3923aea184724203c"}, + {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6212a60e5c482ef90f2d788835387070a88d52cf6241d3916733c9176d39eab"}, + {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d119fafe7b634dbfa25a8c597718e69a930e4847f0b88e172744be24515140da"}, + {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:6fba278063559acc730abf49845d0e9a9e1ba74f85f0ee6efd5803f08b285853"}, + {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:92fc484e34b733704ad77210c7957679c5c3877bd1e6b6d74b185e9320cc716e"}, + {file = "aiohttp-3.11.11-cp312-cp312-win32.whl", hash = "sha256:9f5b3c1ed63c8fa937a920b6c1bec78b74ee09593b3f5b979ab2ae5ef60d7600"}, + {file = "aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d"}, + {file = "aiohttp-3.11.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:541d823548ab69d13d23730a06f97460f4238ad2e5ed966aaf850d7c369782d9"}, + {file = "aiohttp-3.11.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:929f3ed33743a49ab127c58c3e0a827de0664bfcda566108989a14068f820194"}, + {file = "aiohttp-3.11.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0882c2820fd0132240edbb4a51eb8ceb6eef8181db9ad5291ab3332e0d71df5f"}, + {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63de12e44935d5aca7ed7ed98a255a11e5cb47f83a9fded7a5e41c40277d104"}, + {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa54f8ef31d23c506910c21163f22b124facb573bff73930735cf9fe38bf7dff"}, + {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a344d5dc18074e3872777b62f5f7d584ae4344cd6006c17ba12103759d407af3"}, + {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7fb429ab1aafa1f48578eb315ca45bd46e9c37de11fe45c7f5f4138091e2f1"}, + {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c341c7d868750e31961d6d8e60ff040fb9d3d3a46d77fd85e1ab8e76c3e9a5c4"}, + {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed9ee95614a71e87f1a70bc81603f6c6760128b140bc4030abe6abaa988f1c3d"}, + {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:de8d38f1c2810fa2a4f1d995a2e9c70bb8737b18da04ac2afbf3971f65781d87"}, + {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a9b7371665d4f00deb8f32208c7c5e652059b0fda41cf6dbcac6114a041f1cc2"}, + {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:620598717fce1b3bd14dd09947ea53e1ad510317c85dda2c9c65b622edc96b12"}, + {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf8d9bfee991d8acc72d060d53860f356e07a50f0e0d09a8dfedea1c554dd0d5"}, + {file = "aiohttp-3.11.11-cp313-cp313-win32.whl", hash = "sha256:9d73ee3725b7a737ad86c2eac5c57a4a97793d9f442599bea5ec67ac9f4bdc3d"}, + {file = "aiohttp-3.11.11-cp313-cp313-win_amd64.whl", hash = "sha256:c7a06301c2fb096bdb0bd25fe2011531c1453b9f2c163c8031600ec73af1cc99"}, + {file = "aiohttp-3.11.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3e23419d832d969f659c208557de4a123e30a10d26e1e14b73431d3c13444c2e"}, + {file = "aiohttp-3.11.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21fef42317cf02e05d3b09c028712e1d73a9606f02467fd803f7c1f39cc59add"}, + {file = "aiohttp-3.11.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1f21bb8d0235fc10c09ce1d11ffbd40fc50d3f08a89e4cf3a0c503dc2562247a"}, + {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1642eceeaa5ab6c9b6dfeaaa626ae314d808188ab23ae196a34c9d97efb68350"}, + {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2170816e34e10f2fd120f603e951630f8a112e1be3b60963a1f159f5699059a6"}, + {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8be8508d110d93061197fd2d6a74f7401f73b6d12f8822bbcd6d74f2b55d71b1"}, + {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4eed954b161e6b9b65f6be446ed448ed3921763cc432053ceb606f89d793927e"}, + {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6c9af134da4bc9b3bd3e6a70072509f295d10ee60c697826225b60b9959acdd"}, + {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44167fc6a763d534a6908bdb2592269b4bf30a03239bcb1654781adf5e49caf1"}, + {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:479b8c6ebd12aedfe64563b85920525d05d394b85f166b7873c8bde6da612f9c"}, + {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:10b4ff0ad793d98605958089fabfa350e8e62bd5d40aa65cdc69d6785859f94e"}, + {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b540bd67cfb54e6f0865ceccd9979687210d7ed1a1cc8c01f8e67e2f1e883d28"}, + {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1dac54e8ce2ed83b1f6b1a54005c87dfed139cf3f777fdc8afc76e7841101226"}, + {file = "aiohttp-3.11.11-cp39-cp39-win32.whl", hash = "sha256:568c1236b2fde93b7720f95a890741854c1200fba4a3471ff48b2934d2d93fd3"}, + {file = "aiohttp-3.11.11-cp39-cp39-win_amd64.whl", hash = "sha256:943a8b052e54dfd6439fd7989f67fc6a7f2138d0a2cf0a7de5f18aa4fe7eb3b1"}, + {file = "aiohttp-3.11.11.tar.gz", hash = "sha256:bb49c7f1e6ebf3821a42d81d494f538107610c3a705987f53068546b0e90303e"}, ] [package.dependencies] @@ -122,13 +122,13 @@ speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" -version = "1.3.1" +version = "1.3.2" description = "aiosignal: a list of registered asynchronous callbacks" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, - {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, + {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, + {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, ] [package.dependencies] @@ -158,19 +158,19 @@ files = [ [[package]] name = "attrs" -version = "24.2.0" +version = "24.3.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, + {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, + {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, ] [package.extras] benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] @@ -210,13 +210,13 @@ pyobjc-framework-libdispatch = {version = ">=9.0.1,<10.0.0", markers = "platform [[package]] name = "bleak-retry-connector" -version = "2.13.1" +version = "3.1.1" description = "A connector for Bleak Clients that handles transient connection failures" optional = false -python-versions = ">=3.9,<4.0" +python-versions = ">=3.10,<4.0" files = [ - {file = "bleak_retry_connector-2.13.1-py3-none-any.whl", hash = "sha256:9fdab97d7f1cc1b1948412af2cc6f7721e843fb9d2f9b02b7cc26eb52c7ee486"}, - {file = "bleak_retry_connector-2.13.1.tar.gz", hash = "sha256:af344bd81d0f7d33a0994e30fe9e28dfdc3cb970095cc1ba547a3b6ae2ee4543"}, + {file = "bleak_retry_connector-3.1.1-py3-none-any.whl", hash = "sha256:0a9e2e0930c692248ba3d89f86fa30450391fb61f63353b10931f58094a9d582"}, + {file = "bleak_retry_connector-3.1.1.tar.gz", hash = "sha256:276796ec9ca287fa2a1634a4f4bfdfa9712b2e2efa1494bd6d911cb2d23f7566"}, ] [package.dependencies] @@ -272,13 +272,13 @@ docs = ["Sphinx (>=5,<8)", "myst-parser (>=0.18,<2.1)", "sphinx-rtd-theme (>=1,< [[package]] name = "certifi" -version = "2024.8.30" +version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = true python-versions = ">=3.6" files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] [[package]] @@ -698,29 +698,6 @@ files = [ {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] -[[package]] -name = "importlib-metadata" -version = "8.5.0" -description = "Read metadata from Python packages" -optional = true -python-versions = ">=3.8" -files = [ - {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, - {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, -] - -[package.dependencies] -zipp = ">=3.20" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] -type = ["pytest-mypy"] - [[package]] name = "iniconfig" version = "2.0.0" @@ -734,13 +711,13 @@ files = [ [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.5" description = "A very fast and expressive template engine." optional = true python-versions = ">=3.7" files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, + {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, ] [package.dependencies] @@ -1377,7 +1354,6 @@ babel = ">=2.9" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} docutils = ">=0.14,<0.20" imagesize = ">=1.3" -importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} Jinja2 = ">=3.0" packaging = ">=21.0" Pygments = ">=2.12" @@ -1709,29 +1685,10 @@ idna = ">=2.0" multidict = ">=4.0" propcache = ">=0.2.0" -[[package]] -name = "zipp" -version = "3.21.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = true -python-versions = ">=3.9" -files = [ - {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, - {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] -type = ["pytest-mypy"] - [extras] docs = ["Sphinx", "myst-parser", "sphinx-rtd-theme"] [metadata] lock-version = "2.0" -python-versions = "^3.9" -content-hash = "f61a333d52c9aa4bc151318b491602c44354f5cb7af06e0119bb523913a16472" +python-versions = "^3.10" +content-hash = "eb948256c098479a473d806402d0cd27ef27fb21f93fb1d616c5ae05df3b0d8e" diff --git a/pyproject.toml b/pyproject.toml index 824f884..61041da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ packages = [ "Changelog" = "https://github.com/bluetooth-devices/led-ble/blob/main/CHANGELOG.md" [tool.poetry.dependencies] -python = "^3.9" +python = "^3.10" # Documentation Dependencies Sphinx = {version = "^5.0", optional = true} diff --git a/src/led_ble/const.py b/src/led_ble/const.py index cc904af..0ca7485 100644 --- a/src/led_ble/const.py +++ b/src/led_ble/const.py @@ -11,11 +11,16 @@ class CharacteristicMissingError(Exception): """Raised when a characteristic is missing.""" +HELLO_FAIRY_WRITE_CHARACTERISTIC = "49535343-8841-43f4-a8d4-ecbe34729bb3" +HELLO_FAIRY_READ_CHARACTERISTIC = "49535343-1e4d-4bd9-ba61-23c647249616" + POSSIBLE_WRITE_CHARACTERISTIC_UUIDS = [ BASE_UUID_FORMAT.format(part) for part in ["ff01", "ffd5", "ffd9", "ffe5", "ffe9"] -] +] + [HELLO_FAIRY_WRITE_CHARACTERISTIC] + POSSIBLE_READ_CHARACTERISTIC_UUIDS = [ BASE_UUID_FORMAT.format(part) for part in ["ff02", "ffd0", "ffd4", "ffe0", "ffe4"] -] +] + [HELLO_FAIRY_READ_CHARACTERISTIC] + QUERY_STATE_BYTES = bytearray([0xEF, 0x01, 0x77]) diff --git a/src/led_ble/led_ble.py b/src/led_ble/led_ble.py index c7c05f6..91164eb 100644 --- a/src/led_ble/led_ble.py +++ b/src/led_ble/led_ble.py @@ -25,8 +25,10 @@ from flux_led.utils import rgbw_brightness from led_ble.model_db import LEDBLEModel +from led_ble.protocol import ProtocolFairy from .const import ( + HELLO_FAIRY_READ_CHARACTERISTIC, POSSIBLE_READ_CHARACTERISTIC_UUIDS, POSSIBLE_WRITE_CHARACTERISTIC_UUIDS, STATE_COMMAND, @@ -279,10 +281,14 @@ def _generate_preset_pattern( brightness = int(brightness * 255 / 100) speed = int(speed * 255 / 100) return bytearray([0x9E, 0x00, pattern, speed, brightness, 0x00, 0xE9]) - PresetPattern.valid_or_raise(pattern) + if not self._is_hello_fairy(): + PresetPattern.valid_or_raise(pattern) if not (1 <= brightness <= 100): raise ValueError("Brightness must be between 1 and 100") assert self._protocol is not None # nosec + if self._is_hello_fairy() and pattern > 58: + rgb = [[255, 0, 0], [0, 255, 0], [0, 0, 255]] * 8 + [[255, 0, 0]] + return self._protocol.construct_custom_effect(rgb, speed, "") return self._protocol.construct_preset_pattern(pattern, speed, brightness) async def async_set_preset_pattern( @@ -431,29 +437,64 @@ def _named_effect(self) -> str | None: """Returns the named effect.""" return EFFECT_ID_NAME.get(self.preset_pattern_num) + # ideally replace with classes to encapsulate the differences between device makes + def _is_hello_fairy(self) -> bool: + if self._read_char is None: + return False + d = self._read_char.descriptors + c = d[0].characteristic_uuid if (len(d) > 0) else None + return c == HELLO_FAIRY_READ_CHARACTERISTIC + def _notification_handler(self, _sender: int, data: bytearray) -> None: """Handle notification responses.""" _LOGGER.debug("%s: Notification received: %s", self.name, data.hex()) - if len(data) == 4 and data[0] == 0xCC: - on = data[1] == 0x23 - self._state = replace(self._state, power=on) - return - if len(data) < 11: - return - model_num = data[1] - on = data[2] == 0x23 - preset_pattern = data[3] - mode = data[4] - speed = data[5] - r = data[6] - g = data[7] - b = data[8] - w = data[9] - version = data[10] - self._state = LEDBLEState( - on, (r, g, b), w, model_num, preset_pattern, mode, speed, version - ) + model_num = 0 + if self._is_hello_fairy(): + if data[0] == 0xAA: + if data[1] == 0x00: # hw info + if len(data) > 7: + version_string = data[3:8].decode("ascii") + _LOGGER.debug("version %s", version_string) + self._state = replace( + self._state, + version_num=(data[3] - 48) * 100 + + (data[5] - 48) * 10 + + (data[7] - 48), + ) + if len(data) > 12: + model = data[8:13].decode("ascii") + _LOGGER.debug("model %s", model) + if len(data) > 24: + lights = data[24] # guessing + _LOGGER.debug("lights %d", lights) + if len(data) > 33: + effects = data[33] # guessing + _LOGGER.debug("effects %d", effects) + + if data[1] == 0x01: # state info + if len(data) > 6: + self._state = replace(self._state, power=data[6] > 0) + else: + if len(data) == 4 and data[0] == 0xCC: + on = data[1] == 0x23 + self._state = replace(self._state, power=on) + return + if len(data) < 11: + return + model_num = data[1] + on = data[2] == 0x23 + preset_pattern = data[3] + mode = data[4] + speed = data[5] + r = data[6] + g = data[7] + b = data[8] + w = data[9] + version = data[10] + self._state = LEDBLEState( + on, (r, g, b), w, model_num, preset_pattern, mode, speed, version + ) _LOGGER.debug( "%s: Notification received; RSSI: %s: %s %s", @@ -466,8 +507,10 @@ def _notification_handler(self, _sender: int, data: bytearray) -> None: if not self._resolve_protocol_event.is_set(): self._resolve_protocol_event.set() self._model_data = get_model(model_num) - self._set_protocol(self._model_data.protocol_for_version_num(version)) - + if self._is_hello_fairy(): + self._protocol = ProtocolFairy() + else: + self._set_protocol(self._model_data.protocol_for_version_num(version)) self._fire_callbacks() def _reset_disconnect_timer(self) -> None: @@ -622,13 +665,23 @@ def _resolve_characteristics(self, services: BleakGATTServiceCollection) -> bool if char := services.get_characteristic(characteristic): self._write_char = char break + _LOGGER.debug( + "using characteristic %s for read, characteristic %s for write", + self._read_char, + self._write_char, + ) return bool(self._read_char and self._write_char) async def _resolve_protocol(self) -> None: """Resolve protocol.""" if self._resolve_protocol_event.is_set(): return - await self._send_command_while_connected([STATE_COMMAND]) + if self._is_hello_fairy(): + await self._send_command_while_connected( + [b"\xaa\x00\x00\xaa"] + ) # get version and capabilities + else: + await self._send_command_while_connected([STATE_COMMAND]) async with asyncio_timeout(10): await self._resolve_protocol_event.wait() diff --git a/src/led_ble/model_db.py b/src/led_ble/model_db.py index 70cb25b..ec455ed 100644 --- a/src/led_ble/model_db.py +++ b/src/led_ble/model_db.py @@ -31,6 +31,15 @@ def protocol_for_version_num(self, version_num: int) -> str: MODELS = [ + LEDBLEModel( + model_num=0x00, + models=["Hello Fairy:BMSL6"], + description="Controller RGB", + protocols=[ + MinVersionProtocol(0, "Fairy"), + ], + color_modes=COLOR_MODES_RGB_W, # Formerly rgbwcapable + ), LEDBLEModel( model_num=0x04, models=["Triones:C10511000166"], diff --git a/src/led_ble/protocol.py b/src/led_ble/protocol.py new file mode 100644 index 0000000..fa3ba40 --- /dev/null +++ b/src/led_ble/protocol.py @@ -0,0 +1,119 @@ +import colorsys +from math import floor +from flux_led.protocol import ProtocolBase +from led_ble.led_ble import LevelWriteMode + + +class ProtocolFairy(ProtocolBase): + """Protocol for Hello Fairy devices.""" + + @property + def name(self) -> str: + """The name of the protocol.""" + return "Fairy" + + def construct_state_query(self) -> bytearray: + """The bytes to send for a query request.""" + return self.construct_message(bytearray([0xAA, 0x01, 0x00])) + + def construct_state_change(self, turn_on: int) -> bytearray: + """The bytes to send for a state change request.""" + return self.construct_message( + bytearray([0xAA, 0x02, 0x01, 1 if turn_on else 0]) + ) + + def construct_message(self, raw_bytes: bytearray) -> bytearray: + """Calculate checksum of byte array and add to end.""" + csum = sum(raw_bytes) & 0xFF + raw_bytes.append(csum) + return raw_bytes + + def construct_levels_change( + self, + persist: int, + red: int | None, + green: int | None, + blue: int | None, + warm_white: int | None, + cool_white: int | None, + write_mode: LevelWriteMode, + ) -> list[bytearray]: + """The bytes to send for a level change request.""" + h, s, v = colorsys.rgb_to_hsv( + (red or 0) / 255, (green or 0) / 255, (blue or 0) / 255 + ) + h_scaled = min(359, floor(h * 360)) + s_scaled = round(s * 1000) + v_scaled = round(v * 1000) + return [ + self.construct_message( + bytearray( + [ + 0xAA, + 0x03, + 0x07, + 0x01, + h_scaled >> 8, + h_scaled & 0xFF, + s_scaled >> 8, + s_scaled & 0xFF, + v_scaled >> 8, + v_scaled & 0xFF, + ] + ) + ) + ] + + def construct_preset_pattern( + self, pattern: int, speed: int, brightness: int + ) -> list[bytearray]: + """The bytes to send for a preset pattern.""" + return [ + self.construct_message( + bytearray( + [ + 0xAA, + 0x03, + 0x04, + 0x02, + pattern & 0xFF, + (brightness >> 8) & 0xFF, + brightness & 0xFF, + ] + ) + ), + self.construct_message(bytearray([0xAA, 0x0C, 0x01, min(speed, 100)])), + ] + + def construct_custom_effect( + self, rgb_list: list[tuple[int, int, int]], speed: int, transition_type: str + ) -> list[bytearray]: + """The bytes to send for a custom effect.""" + data_bytes = len(rgb_list) * 3 + 1 + hue_message = bytearray(data_bytes + 3) + hue_message[0:4] = [0xAA, 0xDA, data_bytes, 0x01] + for [i, [r, g, b]] in enumerate(rgb_list): + h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255) + if v < 0.25: + h = 0xFE # black + elif s < 0.25: + h = 0xFF # white + else: + h = floor(h * 0xAF) + # necessary to satisfy both flake and ruff: + a = i * 3 + 4 + b = a + 3 + hue_message[a:b] = [i >> 8, i & 0xFF, h] + return [ + *self.construct_motion(speed, 0), + self.construct_message(hue_message), + *self.construct_motion(speed, 2), + ] + + def construct_motion(self, speed: int, transition: int) -> list[bytearray]: + """The bytes to send for motion speed and transition.""" + return [ + self.construct_message( + bytearray([0xAA, 0xD0, 0x04, transition, 0x64, speed, 0x01]) + ) + ] From 19fb87cfc05b154f62d10904f679f717fdc4596f Mon Sep 17 00:00:00 2001 From: jr4 Date: Sat, 21 Dec 2024 13:37:33 -0600 Subject: [PATCH 2/3] chore: package as a new lib for pypi --- CHANGELOG.md | 142 +----------------- CONTRIBUTING.md | 2 +- README.md | 16 +- docs/source/installation.md | 2 +- docs/source/usage.md | 2 +- examples/run.py | 4 +- pyproject.toml | 23 +-- setup.py | 2 +- src/{led_ble => led_ble_hf}/__init__.py | 4 +- src/{led_ble => led_ble_hf}/const.py | 0 src/{led_ble => led_ble_hf}/exceptions.py | 0 .../led_ble.py => led_ble_hf/led_ble_hf.py} | 4 +- src/{led_ble => led_ble_hf}/model_db.py | 0 src/{led_ble => led_ble_hf}/models.py | 0 src/{led_ble => led_ble_hf}/protocol.py | 2 +- src/{led_ble => led_ble_hf}/py.typed | 0 src/{led_ble => led_ble_hf}/util.py | 0 tests/test_init.py | 4 +- 18 files changed, 37 insertions(+), 170 deletions(-) rename src/{led_ble => led_ble_hf}/__init__.py (75%) rename src/{led_ble => led_ble_hf}/const.py (100%) rename src/{led_ble => led_ble_hf}/exceptions.py (100%) rename src/{led_ble/led_ble.py => led_ble_hf/led_ble_hf.py} (99%) rename src/{led_ble => led_ble_hf}/model_db.py (100%) rename src/{led_ble => led_ble_hf}/models.py (100%) rename src/{led_ble => led_ble_hf}/protocol.py (98%) rename src/{led_ble => led_ble_hf}/py.typed (100%) rename src/{led_ble => led_ble_hf}/util.py (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a37f16..9d23b4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,144 +2,6 @@ -## v1.1.1 (2024-12-11) +## v1.0.0 (2024-12-21) -### Fix - -* Refactor to use kwargs for construct_levels_change ([#53](https://github.com/Bluetooth-Devices/led-ble/issues/53)) ([`efd92ac`](https://github.com/Bluetooth-Devices/led-ble/commit/efd92aca9bcb05ac9d5ab72a19196c7717631552)) - -## v1.1.0 (2024-12-11) - -### Feature - -* Add Python 3.13 support ([#55](https://github.com/Bluetooth-Devices/led-ble/issues/55)) ([`05f3818`](https://github.com/Bluetooth-Devices/led-ble/commit/05f38188572e898af89f53a0bf1cc4f146186876)) - -## v1.0.2 (2024-06-24) - -### Fix - -* Fix license classifier ([#41](https://github.com/Bluetooth-Devices/led-ble/issues/41)) ([`b331b97`](https://github.com/Bluetooth-Devices/led-ble/commit/b331b9744caeb5fded22d8435bb8c5db7be8a362)) - -## v1.0.1 (2023-09-25) - -### Fix - -* Bump psr to fix CI ([#38](https://github.com/Bluetooth-Devices/led-ble/issues/38)) ([`ab09fed`](https://github.com/Bluetooth-Devices/led-ble/commit/ab09fedd632f937cb4064254c8e61c349f8c8d6d)) -* Drop async_timeout on py3.11+ ([#37](https://github.com/Bluetooth-Devices/led-ble/issues/37)) ([`fba769f`](https://github.com/Bluetooth-Devices/led-ble/commit/fba769f33cf7ac1f89105e29615e3d15707ecdcf)) -* Do not try to stop notify if read char is missing ([#36](https://github.com/Bluetooth-Devices/led-ble/issues/36)) ([`03c84f9`](https://github.com/Bluetooth-Devices/led-ble/commit/03c84f99deba04c3d04236f608e24ad137540b8c)) - -## v1.0.0 (2022-10-16) -### Feature -* Update for new bleak version ([#33](https://github.com/Bluetooth-Devices/led-ble/issues/33)) ([`2be176c`](https://github.com/Bluetooth-Devices/led-ble/commit/2be176cfc5492f35bc3fc019e385a3698ea572bb)) - -### Breaking -* The set_ble_device function has been renamed set_ble_device_and_advertisement_data and now requires the advertisement_data. ([`2be176c`](https://github.com/Bluetooth-Devices/led-ble/commit/2be176cfc5492f35bc3fc019e385a3698ea572bb)) -* The constructor no longer takes a retry count since this does not need to be configurable ([`2be176c`](https://github.com/Bluetooth-Devices/led-ble/commit/2be176cfc5492f35bc3fc019e385a3698ea572bb)) - -## v0.10.1 (2022-09-15) -### Fix -* Handle additional bleak exceptions ([#31](https://github.com/Bluetooth-Devices/led-ble/issues/31)) ([`1ff94f7`](https://github.com/Bluetooth-Devices/led-ble/commit/1ff94f770e86d630892261178018d861d4e74a72)) - -## v0.10.0 (2022-09-13) -### Feature -* Update for bleak 0.17 support ([#29](https://github.com/Bluetooth-Devices/led-ble/issues/29)) ([`530de76`](https://github.com/Bluetooth-Devices/led-ble/commit/530de767892a51bb93a81830f418b168b3f13fd8)) - -## v0.9.1 (2022-09-11) -### Fix -* Typo in bleak-retry-connector min version pin ([#28](https://github.com/Bluetooth-Devices/led-ble/issues/28)) ([`8638ab8`](https://github.com/Bluetooth-Devices/led-ble/commit/8638ab86a73fae3a8407b4b6b3f9fe3c4193bfb0)) - -## v0.9.0 (2022-09-11) -### Feature -* Implement smart backoff via bleak-retry-connector ([#27](https://github.com/Bluetooth-Devices/led-ble/issues/27)) ([`a7bb1b1`](https://github.com/Bluetooth-Devices/led-ble/commit/a7bb1b1707c103010398091d5291d8827b730d7e)) - -## v0.8.5 (2022-09-11) -### Fix -* Bump bleak-retry-connector ([#26](https://github.com/Bluetooth-Devices/led-ble/issues/26)) ([`ac3823e`](https://github.com/Bluetooth-Devices/led-ble/commit/ac3823e546e7263e345b1deae8a7f0b94487a89e)) - -## v0.8.4 (2022-09-11) -### Fix -* Bump bleak-retry-connector ([#25](https://github.com/Bluetooth-Devices/led-ble/issues/25)) ([`0ad8e7b`](https://github.com/Bluetooth-Devices/led-ble/commit/0ad8e7bc240bcd9abfffb7efccef93186072c25c)) - -## v0.8.3 (2022-09-10) -### Fix -* Address property ([#24](https://github.com/Bluetooth-Devices/led-ble/issues/24)) ([`b85439f`](https://github.com/Bluetooth-Devices/led-ble/commit/b85439febb7fbcfb9fa7e41a7a6f6991bd25dff4)) - -## v0.8.2 (2022-09-10) -### Fix -* Bump bleak retry connector ([#23](https://github.com/Bluetooth-Devices/led-ble/issues/23)) ([`1fd8778`](https://github.com/Bluetooth-Devices/led-ble/commit/1fd8778e738b09122a15ec486bc83c7313545692)) - -## v0.8.1 (2022-09-10) -### Fix -* Bump bleak-retry-connector min version ([#22](https://github.com/Bluetooth-Devices/led-ble/issues/22)) ([`2112b18`](https://github.com/Bluetooth-Devices/led-ble/commit/2112b18c4a7afbb5ea04a6d8c5ddb2f8232816da)) - -## v0.8.0 (2022-09-10) -### Feature -* Export get_device from bleak-retry-connector ([#21](https://github.com/Bluetooth-Devices/led-ble/issues/21)) ([`5f41511`](https://github.com/Bluetooth-Devices/led-ble/commit/5f41511cd1684eb9277fc63896da63d50127b168)) - -## v0.7.1 (2022-09-06) -### Fix -* Effects on dream models ([#20](https://github.com/Bluetooth-Devices/led-ble/issues/20)) ([`b8126c1`](https://github.com/Bluetooth-Devices/led-ble/commit/b8126c1f5fe098efcc8c3d3a43a42ed5cc9136d8)) - -## v0.7.0 (2022-09-05) -### Feature -* Add newly discovered model 0x15 ([#17](https://github.com/Bluetooth-Devices/led-ble/issues/17)) ([`3c5f15c`](https://github.com/Bluetooth-Devices/led-ble/commit/3c5f15c80520b76fe6fa9e0933f64c3419cd3b07)) - -## v0.6.0 (2022-09-04) -### Feature -* Add support for more protocols ([#16](https://github.com/Bluetooth-Devices/led-ble/issues/16)) ([`c7bbb15`](https://github.com/Bluetooth-Devices/led-ble/commit/c7bbb15ec2dd291f5918850b3bdddec8cf1abae6)) - -## v0.5.4 (2022-08-29) -### Fix -* W channel not being cleared on rgb set ([#15](https://github.com/Bluetooth-Devices/led-ble/issues/15)) ([`048bdff`](https://github.com/Bluetooth-Devices/led-ble/commit/048bdffd52ea78ba66a1d33793db58a725bc894b)) - -## v0.5.3 (2022-08-29) -### Fix -* Brightness ([#14](https://github.com/Bluetooth-Devices/led-ble/issues/14)) ([`01dcf7b`](https://github.com/Bluetooth-Devices/led-ble/commit/01dcf7bd5f92a0c487924211490ba0498708100d)) - -## v0.5.2 (2022-08-29) -### Fix -* Missing exports ([#13](https://github.com/Bluetooth-Devices/led-ble/issues/13)) ([`911c2a0`](https://github.com/Bluetooth-Devices/led-ble/commit/911c2a0dcbdc4041247fe53a060ae4a50a85faa7)) - -## v0.5.1 (2022-08-29) -### Fix -* Cleanups ([#12](https://github.com/Bluetooth-Devices/led-ble/issues/12)) ([`9d3ae2a`](https://github.com/Bluetooth-Devices/led-ble/commit/9d3ae2a80bfc9d17bc9603003852b010a56a2494)) - -## v0.5.0 (2022-08-29) -### Feature -* Add rgbw support ([#11](https://github.com/Bluetooth-Devices/led-ble/issues/11)) ([`14ae97b`](https://github.com/Bluetooth-Devices/led-ble/commit/14ae97ba4b51fb7ebb81634028e1eac623e9a3f5)) - -## v0.4.2 (2022-08-29) -### Fix -* Add log ([#10](https://github.com/Bluetooth-Devices/led-ble/issues/10)) ([`d95fc61`](https://github.com/Bluetooth-Devices/led-ble/commit/d95fc61d0745002709558bc05812e8b5589ada62)) - -## v0.4.1 (2022-08-29) -### Fix -* Add state to log ([#9](https://github.com/Bluetooth-Devices/led-ble/issues/9)) ([`ee85bdd`](https://github.com/Bluetooth-Devices/led-ble/commit/ee85bddec3b5dac4de1aa38742662ccf97fc0fda)) - -## v0.4.0 (2022-08-29) -### Feature -* Add model data ([#8](https://github.com/Bluetooth-Devices/led-ble/issues/8)) ([`6df04cf`](https://github.com/Bluetooth-Devices/led-ble/commit/6df04cf9d0dfeaf6836830634df8df1a2bcbeb95)) - -## v0.3.0 (2022-08-29) -### Feature -* Add white channel ([#7](https://github.com/Bluetooth-Devices/led-ble/issues/7)) ([`3112249`](https://github.com/Bluetooth-Devices/led-ble/commit/31122499beb71f7af68ad5854fb58f112803c654)) - -## v0.2.2 (2022-08-29) -### Fix -* Remove scaling ([#6](https://github.com/Bluetooth-Devices/led-ble/issues/6)) ([`89ac78e`](https://github.com/Bluetooth-Devices/led-ble/commit/89ac78e5e41e4c5123cb8ef39505ca6bb9c5e24e)) - -## v0.2.1 (2022-08-29) -### Fix -* Fix disconnect ([#5](https://github.com/Bluetooth-Devices/led-ble/issues/5)) ([`44f79ee`](https://github.com/Bluetooth-Devices/led-ble/commit/44f79eea35fb027299cda5b6c3fa06da9572f258)) - -## v0.2.0 (2022-08-29) -### Feature -* Add example ([#4](https://github.com/Bluetooth-Devices/led-ble/issues/4)) ([`9d25f2a`](https://github.com/Bluetooth-Devices/led-ble/commit/9d25f2a2fd1043cf4679215ce16c0888f9ed6fa8)) - -## v0.1.0 (2022-08-29) -### Feature -* First release ([#3](https://github.com/Bluetooth-Devices/led-ble/issues/3)) ([`0875dc4`](https://github.com/Bluetooth-Devices/led-ble/commit/0875dc4ca17960cb634b66c3a3c61f9ff2c5f490)) -* Build out the class ([#2](https://github.com/Bluetooth-Devices/led-ble/issues/2)) ([`f70c1a3`](https://github.com/Bluetooth-Devices/led-ble/commit/f70c1a3288dfcf749200cab167f1ee67b2ffcd3e)) - -### Fix -* Ci ([#1](https://github.com/Bluetooth-Devices/led-ble/issues/1)) ([`dba3484`](https://github.com/Bluetooth-Devices/led-ble/commit/dba3484f8aabb76db51365179cfecfb1caeed528)) +* Initial release. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a809f02..441c077 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,4 +114,4 @@ $ pytest tests The deployment should be automated and can be triggered from the Semantic Release workflow in GitHub. The next version will be based on [the commit logs](https://python-semantic-release.readthedocs.io/en/latest/commit-log-parsing.html#commit-log-parsing). This is done by [python-semantic-release](https://python-semantic-release.readthedocs.io/en/latest/index.html) via a GitHub action. -[gh-issues]: https://github.com/bluetooth-devices/led-ble/issues +[gh-issues]: https://github.com/jr4/led-ble/issues diff --git a/README.md b/README.md index 8a74146..52387dd 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # LED BLE

- - CI Status + + CI Status Documentation Status - - Test coverage percentage + + Test coverage percentage

@@ -30,13 +30,17 @@ License

-Control a wide range of LED BLE devices +Control a wide range of LED BLE devices. + +This is a fork of the excellent [led-ble](https://github.com/Bluetooth-Devices/led-ble). This fork contains support +for devices that can be controlled by the Hello Fairy app. (It does not drop support for the original library's devices, but +is not tested on them as this author does not own any.) ## Installation Install this via pip (or your favourite package manager): -`pip install led-ble` +`pip install led-ble-hf` ## Contributors ✨ diff --git a/docs/source/installation.md b/docs/source/installation.md index 1df699f..163007a 100644 --- a/docs/source/installation.md +++ b/docs/source/installation.md @@ -3,5 +3,5 @@ The package is published on [PyPI](https://pypi.org/project/deezer-python/) and can be installed with `pip` (or any equivalent): ```bash -pip install led-ble +pip install led-ble-hf ``` diff --git a/docs/source/usage.md b/docs/source/usage.md index 9ebb731..d16efad 100644 --- a/docs/source/usage.md +++ b/docs/source/usage.md @@ -3,7 +3,7 @@ To use this package, import it: ```python -import led_ble +import led_ble_hf ``` TODO: Document usage diff --git a/examples/run.py b/examples/run.py index 43ad8c0..463d11e 100644 --- a/examples/run.py +++ b/examples/run.py @@ -5,7 +5,7 @@ from bleak.backends.device import BLEDevice from bleak.backends.scanner import AdvertisementData -from led_ble import LEDBLE, LEDBLEState +from led_ble_hf import LEDBLE, LEDBLEState _LOGGER = logging.getLogger(__name__) @@ -66,5 +66,5 @@ def on_state_changed(state: LEDBLEState) -> None: logging.basicConfig(level=logging.INFO) -logging.getLogger("led_ble").setLevel(logging.DEBUG) +logging.getLogger("led_ble_hf").setLevel(logging.DEBUG) asyncio.run(run()) diff --git a/pyproject.toml b/pyproject.toml index 61041da..5a7251b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,12 @@ [tool.poetry] -name = "led-ble" -version = "1.1.1" +name = "led-ble-hf" +version = "1.0.0" description = "Control a wide range of LED BLE devices" -authors = ["J. Nick Koston "] +authors = ["Jon "] # forked from https://github.com/Bluetooth-Devices/led-ble by J. Nick Koston " + readme = "README.md" -repository = "https://github.com/bluetooth-devices/led-ble" -documentation = "https://led-ble.readthedocs.io" +repository = "https://github.com/jr4/led-ble" +documentation = "https://github.com/jr4/led-ble" classifiers = [ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", @@ -15,12 +16,12 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", ] packages = [ - { include = "led_ble", from = "src" }, + { include = "led_ble_hf", from = "src" }, ] [tool.poetry.urls] -"Bug Tracker" = "https://github.com/bluetooth-devices/led-ble/issues" -"Changelog" = "https://github.com/bluetooth-devices/led-ble/blob/main/CHANGELOG.md" +"Bug Tracker" = "https://github.com/jr4/led-ble/issues" +"Changelog" = "https://github.com/jr4/led-ble/blob/main/CHANGELOG.md" [tool.poetry.dependencies] python = "^3.10" @@ -48,11 +49,11 @@ pytest-cov = "^3.0" [tool.semantic_release] branch = "main" version_toml = "pyproject.toml:tool.poetry.version" -version_variable = "src/led_ble/__init__.py:__version__" +version_variable = "src/led_ble_hf/__init__.py:__version__" build_command = "pip install poetry && poetry build" [tool.pytest.ini_options] -addopts = "-v -Wdefault --cov=led_ble --cov-report=term-missing:skip-covered" +addopts = "-v -Wdefault --cov=led_ble_hf --cov-report=term-missing:skip-covered" pythonpath = ["src"] [tool.coverage.run] @@ -68,7 +69,7 @@ exclude_lines = [ [tool.isort] profile = "black" -known_first_party = ["led_ble", "tests"] +known_first_party = ["led_ble_hf", "tests"] [tool.mypy] check_untyped_defs = true diff --git a/setup.py b/setup.py index cccadac..550e697 100644 --- a/setup.py +++ b/setup.py @@ -6,4 +6,4 @@ import setuptools if __name__ == "__main__": - setuptools.setup(name="led-ble") + setuptools.setup(name="led-ble-hf") diff --git a/src/led_ble/__init__.py b/src/led_ble_hf/__init__.py similarity index 75% rename from src/led_ble/__init__.py rename to src/led_ble_hf/__init__.py index 3e39c9a..4bbbd30 100644 --- a/src/led_ble/__init__.py +++ b/src/led_ble_hf/__init__.py @@ -1,12 +1,12 @@ from __future__ import annotations -__version__ = "1.1.1" +__version__ = "1.0.0" from bleak_retry_connector import get_device from .exceptions import CharacteristicMissingError -from .led_ble import BLEAK_EXCEPTIONS, LEDBLE, LEDBLEState +from .led_ble_hf import BLEAK_EXCEPTIONS, LEDBLE, LEDBLEState __all__ = [ "BLEAK_EXCEPTIONS", diff --git a/src/led_ble/const.py b/src/led_ble_hf/const.py similarity index 100% rename from src/led_ble/const.py rename to src/led_ble_hf/const.py diff --git a/src/led_ble/exceptions.py b/src/led_ble_hf/exceptions.py similarity index 100% rename from src/led_ble/exceptions.py rename to src/led_ble_hf/exceptions.py diff --git a/src/led_ble/led_ble.py b/src/led_ble_hf/led_ble_hf.py similarity index 99% rename from src/led_ble/led_ble.py rename to src/led_ble_hf/led_ble_hf.py index 91164eb..3255afc 100644 --- a/src/led_ble/led_ble.py +++ b/src/led_ble_hf/led_ble_hf.py @@ -24,8 +24,8 @@ from flux_led.pattern import EFFECT_ID_NAME, EFFECT_LIST, PresetPattern from flux_led.utils import rgbw_brightness -from led_ble.model_db import LEDBLEModel -from led_ble.protocol import ProtocolFairy +from led_ble_hf.model_db import LEDBLEModel +from led_ble_hf.protocol import ProtocolFairy from .const import ( HELLO_FAIRY_READ_CHARACTERISTIC, diff --git a/src/led_ble/model_db.py b/src/led_ble_hf/model_db.py similarity index 100% rename from src/led_ble/model_db.py rename to src/led_ble_hf/model_db.py diff --git a/src/led_ble/models.py b/src/led_ble_hf/models.py similarity index 100% rename from src/led_ble/models.py rename to src/led_ble_hf/models.py diff --git a/src/led_ble/protocol.py b/src/led_ble_hf/protocol.py similarity index 98% rename from src/led_ble/protocol.py rename to src/led_ble_hf/protocol.py index fa3ba40..e9e87fb 100644 --- a/src/led_ble/protocol.py +++ b/src/led_ble_hf/protocol.py @@ -1,7 +1,7 @@ import colorsys from math import floor from flux_led.protocol import ProtocolBase -from led_ble.led_ble import LevelWriteMode +from led_ble_hf.led_ble_hf import LevelWriteMode class ProtocolFairy(ProtocolBase): diff --git a/src/led_ble/py.typed b/src/led_ble_hf/py.typed similarity index 100% rename from src/led_ble/py.typed rename to src/led_ble_hf/py.typed diff --git a/src/led_ble/util.py b/src/led_ble_hf/util.py similarity index 100% rename from src/led_ble/util.py rename to src/led_ble_hf/util.py diff --git a/tests/test_init.py b/tests/test_init.py index 39e5c2b..af536e4 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -1,5 +1,5 @@ -import led_ble +import led_ble_hf def test_add(): - assert led_ble + assert led_ble_hf From cb107037428483523ea04213e820fe7fbb658ee0 Mon Sep 17 00:00:00 2001 From: jr4 Date: Sat, 21 Dec 2024 13:48:49 -0600 Subject: [PATCH 3/3] feat: protocol for pause and IR enable --- src/led_ble_hf/protocol.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/led_ble_hf/protocol.py b/src/led_ble_hf/protocol.py index e9e87fb..d640a62 100644 --- a/src/led_ble_hf/protocol.py +++ b/src/led_ble_hf/protocol.py @@ -22,11 +22,15 @@ def construct_state_change(self, turn_on: int) -> bytearray: bytearray([0xAA, 0x02, 0x01, 1 if turn_on else 0]) ) - def construct_message(self, raw_bytes: bytearray) -> bytearray: - """Calculate checksum of byte array and add to end.""" - csum = sum(raw_bytes) & 0xFF - raw_bytes.append(csum) - return raw_bytes + def construct_pause(self, pause: bool) -> bytearray: + """The bytes to send for pausing or unpausing.""" + return self.construct_message(bytearray([0xAA, 0x11, 0x01, 1 if pause else 0])) + + def construct_ir_state(self, turn_on: bool) -> bytearray: + """The bytes to send for enabling/disabling the IR remote.""" + return self.construct_message( + bytearray([0xAA, 0x0F, 0x01, 1 if turn_on else 0]) + ) def construct_levels_change( self, @@ -117,3 +121,9 @@ def construct_motion(self, speed: int, transition: int) -> list[bytearray]: bytearray([0xAA, 0xD0, 0x04, transition, 0x64, speed, 0x01]) ) ] + + def construct_message(self, raw_bytes: bytearray) -> bytearray: + """Calculate checksum of byte array and add to end.""" + csum = sum(raw_bytes) & 0xFF + raw_bytes.append(csum) + return raw_bytes