Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

led-ble

Package Overview
Dependencies
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

led-ble - npm Package Compare versions

Comparing version
0.10.1
to
1.0.0
+4
-3
PKG-INFO
Metadata-Version: 2.1
Name: led-ble
Version: 0.10.1
Version: 1.0.0
Summary: Control a wide range of LED BLE devices

@@ -18,2 +18,3 @@ Home-page: https://github.com/bluetooth-devices/led-ble

Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development :: Libraries

@@ -23,4 +24,4 @@ Provides-Extra: docs

Requires-Dist: async-timeout (>=4.0.1)
Requires-Dist: bleak (>=0.17.0)
Requires-Dist: bleak-retry-connector (>=1.17.1)
Requires-Dist: bleak (>=0.19.0)
Requires-Dist: bleak-retry-connector (>=2.3.0)
Requires-Dist: flux-led (>=0.28.32)

@@ -27,0 +28,0 @@ Requires-Dist: myst-parser (>=0.18,<0.19); extra == "docs"

[tool.poetry]
name = "led-ble"
version = "0.10.1"
version = "1.0.0"
description = "Control a wide range of LED BLE devices"

@@ -32,4 +32,4 @@ authors = ["J. Nick Koston <nick@koston.org>"]

myst-parser = {version = "^0.18", optional = true}
bleak-retry-connector = ">=1.17.1"
bleak = ">=0.17.0"
bleak-retry-connector = ">=2.3.0"
bleak = ">=0.19.0"
async-timeout = ">=4.0.1"

@@ -36,0 +36,0 @@ flux-led = ">=0.28.32"

@@ -15,4 +15,4 @@ # -*- coding: utf-8 -*-

['async-timeout>=4.0.1',
'bleak-retry-connector>=1.17.1',
'bleak>=0.17.0',
'bleak-retry-connector>=2.3.0',
'bleak>=0.19.0',
'flux-led>=0.28.32']

@@ -27,3 +27,3 @@

'name': 'led-ble',
'version': '0.10.1',
'version': '1.0.0',
'description': 'Control a wide range of LED BLE devices',

@@ -30,0 +30,0 @@ 'long_description': '# LED BLE\n\n<p align="center">\n <a href="https://github.com/bluetooth-devices/led-ble/actions?query=workflow%3ACI">\n <img src="https://img.shields.io/github/workflow/status/bluetooth-devices/led-ble/CI/main?label=CI&logo=github&style=flat-square" alt="CI Status" >\n </a>\n <a href="https://led-ble.readthedocs.io">\n <img src="https://img.shields.io/readthedocs/led-ble.svg?logo=read-the-docs&logoColor=fff&style=flat-square" alt="Documentation Status">\n </a>\n <a href="https://codecov.io/gh/bluetooth-devices/led-ble">\n <img src="https://img.shields.io/codecov/c/github/bluetooth-devices/led-ble.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">\n </a>\n</p>\n<p align="center">\n <a href="https://python-poetry.org/">\n <img src="https://img.shields.io/badge/packaging-poetry-299bd7?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAYAAABrXO8xAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJJSURBVHgBfZLPa1NBEMe/s7tNXoxW1KJQKaUHkXhQvHgW6UHQQ09CBS/6V3hKc/AP8CqCrUcpmop3Cx48eDB4yEECjVQrlZb80CRN8t6OM/teagVxYZi38+Yz853dJbzoMV3MM8cJUcLMSUKIE8AzQ2PieZzFxEJOHMOgMQQ+dUgSAckNXhapU/NMhDSWLs1B24A8sO1xrN4NECkcAC9ASkiIJc6k5TRiUDPhnyMMdhKc+Zx19l6SgyeW76BEONY9exVQMzKExGKwwPsCzza7KGSSWRWEQhyEaDXp6ZHEr416ygbiKYOd7TEWvvcQIeusHYMJGhTwF9y7sGnSwaWyFAiyoxzqW0PM/RjghPxF2pWReAowTEXnDh0xgcLs8l2YQmOrj3N7ByiqEoH0cARs4u78WgAVkoEDIDoOi3AkcLOHU60RIg5wC4ZuTC7FaHKQm8Hq1fQuSOBvX/sodmNJSB5geaF5CPIkUeecdMxieoRO5jz9bheL6/tXjrwCyX/UYBUcjCaWHljx1xiX6z9xEjkYAzbGVnB8pvLmyXm9ep+W8CmsSHQQY77Zx1zboxAV0w7ybMhQmfqdmmw3nEp1I0Z+FGO6M8LZdoyZnuzzBdjISicKRnpxzI9fPb+0oYXsNdyi+d3h9bm9MWYHFtPeIZfLwzmFDKy1ai3p+PDls1Llz4yyFpferxjnyjJDSEy9CaCx5m2cJPerq6Xm34eTrZt3PqxYO1XOwDYZrFlH1fWnpU38Y9HRze3lj0vOujZcXKuuXm3jP+s3KbZVra7y2EAAAAAASUVORK5CYII=" alt="Poetry">\n </a>\n <a href="https://github.com/ambv/black">\n <img src="https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square" alt="black">\n </a>\n <a href="https://github.com/pre-commit/pre-commit">\n <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">\n </a>\n</p>\n<p align="center">\n <a href="https://pypi.org/project/led-ble/">\n <img src="https://img.shields.io/pypi/v/led-ble.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">\n </a>\n <img src="https://img.shields.io/pypi/pyversions/led-ble.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">\n <img src="https://img.shields.io/pypi/l/led-ble.svg?style=flat-square" alt="License">\n</p>\n\nControl a wide range of LED BLE devices\n\n## Installation\n\nInstall this via pip (or your favourite package manager):\n\n`pip install led-ble`\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- prettier-ignore-start -->\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- markdownlint-disable -->\n<!-- markdownlint-enable -->\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n<!-- prettier-ignore-end -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n## Credits\n\nThis package was created with\n[Cookiecutter](https://github.com/audreyr/cookiecutter) and the\n[browniebroke/cookiecutter-pypackage](https://github.com/browniebroke/cookiecutter-pypackage)\nproject template.\n',

from __future__ import annotations
__version__ = "0.10.1"
__version__ = "1.0.0"

@@ -5,0 +5,0 @@

@@ -8,6 +8,7 @@ from __future__ import annotations

from dataclasses import replace
from typing import Any, TypeVar, cast
from typing import Any, TypeVar
import async_timeout
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData
from bleak.backends.service import BleakGATTCharacteristic, BleakGATTServiceCollection

@@ -20,4 +21,4 @@ from bleak.exc import BleakDBusError

BleakNotFoundError,
ble_device_has_changed,
establish_connection,
retry_bluetooth_connection_error,
)

@@ -59,87 +60,15 @@ from flux_led.base_device import PROTOCOL_NAME_TO_CLS, PROTOCOL_TYPES

def retry_bluetooth_connection_error(func: WrapFuncType) -> WrapFuncType:
"""Define a wrapper to retry on bleak error.
The accessory is allowed to disconnect us any time so
we need to retry the operation.
"""
async def _async_wrap_retry_bluetooth_connection_error(
self: "LEDBLE", *args: Any, **kwargs: Any
) -> Any:
_LOGGER.debug("%s: Starting retry loop", self.name)
attempts = DEFAULT_ATTEMPTS
max_attempts = attempts - 1
for attempt in range(attempts):
try:
return await func(self, *args, **kwargs)
except BleakNotFoundError:
# The lock cannot be found so there is no
# point in retrying.
raise
except RETRY_BACKOFF_EXCEPTIONS as err:
if attempt >= max_attempts:
_LOGGER.debug(
"%s: %s error calling %s, reach max attempts (%s/%s)",
self.name,
type(err),
func,
attempt,
max_attempts,
exc_info=True,
)
raise
_LOGGER.debug(
"%s: %s error calling %s, backing off %ss, retrying (%s/%s)...",
self.name,
type(err),
func,
BLEAK_BACKOFF_TIME,
attempt,
max_attempts,
exc_info=True,
)
await asyncio.sleep(BLEAK_BACKOFF_TIME)
except BLEAK_EXCEPTIONS as err:
if attempt >= max_attempts:
_LOGGER.debug(
"%s: %s error calling %s, reach max attempts (%s/%s): %s",
self.name,
type(err),
func,
attempt,
max_attempts,
err,
exc_info=True,
)
raise
_LOGGER.debug(
"%s: %s error calling %s, retrying (%s/%s)...: %s",
self.name,
type(err),
func,
attempt,
max_attempts,
err,
exc_info=True,
)
return cast(WrapFuncType, _async_wrap_retry_bluetooth_connection_error)
class LEDBLE:
def __init__(
self, ble_device: BLEDevice, retry_count: int = DEFAULT_ATTEMPTS
self, ble_device: BLEDevice, advertisement_data: AdvertisementData | None = None
) -> None:
"""Init the LEDBLE."""
self._ble_device = ble_device
self._advertisement_data = advertisement_data
self._operation_lock = asyncio.Lock()
self._state = LEDBLEState()
self._connect_lock: asyncio.Lock = asyncio.Lock()
self._cached_services: BleakGATTServiceCollection | None = None
self._read_char: BleakGATTCharacteristic | None = None
self._write_char: BleakGATTCharacteristic | None = None
self._disconnect_timer: asyncio.TimerHandle | None = None
self._retry_count = retry_count
self._client: BleakClientWithServiceCache | None = None

@@ -153,10 +82,8 @@ self._expected_disconnect = False

def set_ble_device(self, ble_device: BLEDevice) -> None:
def set_ble_device_and_advertisement_data(
self, ble_device: BLEDevice, advertisement_data: AdvertisementData
) -> None:
"""Set the ble device."""
if self._ble_device and ble_device_has_changed(self._ble_device, ble_device):
_LOGGER.debug(
"%s: New ble device details, clearing cached services", self.name
)
self._cached_services = None
self._ble_device = ble_device
self._advertisement_data = advertisement_data

@@ -185,5 +112,7 @@ @property

@property
def rssi(self) -> str:
"""Get the name of the device."""
return self._ble_device.rssi
def rssi(self) -> int | None:
"""Get the rssi of the device."""
if self._advertisement_data:
return self._advertisement_data.rssi
return None

@@ -224,3 +153,2 @@ @property

@retry_bluetooth_connection_error
async def update(self) -> None:

@@ -235,3 +163,2 @@ """Update the LEDBLE."""

@retry_bluetooth_connection_error
async def turn_on(self) -> None:

@@ -245,3 +172,2 @@ """Turn on."""

@retry_bluetooth_connection_error
async def turn_off(self) -> None:

@@ -268,3 +194,2 @@ """Turn off."""

@retry_bluetooth_connection_error
async def set_rgb(

@@ -295,3 +220,2 @@ self, rgb: tuple[int, int, int], brightness: int | None = None

@retry_bluetooth_connection_error
async def set_rgbw(

@@ -322,3 +246,2 @@ self, rgbw: tuple[int, int, int, int], brightness: int | None = None

@retry_bluetooth_connection_error
async def set_white(self, brightness: int) -> None:

@@ -428,3 +351,3 @@ """Set rgb."""

self._disconnected,
cached_services=self._cached_services,
use_services_cache=True,
ble_device_callback=lambda: self._ble_device,

@@ -437,3 +360,3 @@ )

resolved = self._resolve_characteristics(await client.get_services())
self._cached_services = client.services if resolved else None
self._client = client

@@ -594,2 +517,3 @@ self._reset_disconnect_timer()

@retry_bluetooth_connection_error(DEFAULT_ATTEMPTS)
async def _send_command_locked(self, commands: list[bytes]) -> None:

@@ -633,4 +557,2 @@ """Send command to device and read response."""

"""Send command to device and read response."""
if retry is None:
retry = self._retry_count
_LOGGER.debug(

@@ -641,3 +563,2 @@ "%s: Sending commands %s",

)
max_attempts = retry + 1
if self._operation_lock.locked():

@@ -650,47 +571,26 @@ _LOGGER.debug(

async with self._operation_lock:
for attempt in range(max_attempts):
try:
await self._send_command_locked(commands)
return
except BleakNotFoundError:
_LOGGER.error(
"%s: device not found, no longer in range, or poor RSSI: %s",
self.name,
self.rssi,
exc_info=True,
)
return None
except CharacteristicMissingError as ex:
if attempt == retry:
_LOGGER.error(
"%s: characteristic missing: %s; Stopping trying; RSSI: %s",
self.name,
ex,
self.rssi,
exc_info=True,
)
return None
try:
await self._send_command_locked(commands)
return
except BleakNotFoundError:
_LOGGER.error(
"%s: device not found, no longer in range, or poor RSSI: %s",
self.name,
self.rssi,
exc_info=True,
)
raise
except CharacteristicMissingError as ex:
_LOGGER.debug(
"%s: characteristic missing: %s; RSSI: %s",
self.name,
ex,
self.rssi,
exc_info=True,
)
raise
except BLEAK_EXCEPTIONS:
_LOGGER.debug("%s: communication failed", self.name, exc_info=True)
raise
_LOGGER.debug(
"%s: characteristic missing: %s; RSSI: %s",
self.name,
ex,
self.rssi,
exc_info=True,
)
except BLEAK_EXCEPTIONS as ex:
if attempt == retry:
_LOGGER.error(
"%s: communication failed; Stopping trying; RSSI: %s: %s",
self.name,
self.rssi,
ex,
exc_info=True,
)
return None
_LOGGER.debug(
"%s: communication failed with:", self.name, exc_info=True
)
raise RuntimeError("Unreachable")

@@ -697,0 +597,0 @@