Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial import #1

Merged
merged 4 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,11 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
os:
- ubuntu-latest
- windows-latest
- macOS-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
Expand Down
4 changes: 0 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@ repos:
rev: 23.11.0
hooks:
- id: black
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
hooks:
- id: codespell
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.1
hooks:
Expand Down
1,377 changes: 1,335 additions & 42 deletions poetry.lock

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ packages = [
"Changelog" = "https://github.com/bluetooth-devices/bleak-esphome/blob/main/CHANGELOG.md"

[tool.poetry.dependencies]
python = "^3.8"
python = ">=3.10,<3.13"
aioesphomeapi = ">=21.0.0"
bleak = ">=0.21.1"
bluetooth-data-tools = ">=1.17.0"
habluetooth = ">=1.0.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.0"
Expand Down
1 change: 0 additions & 1 deletion src/bleak_esphome/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
__version__ = "0.0.0"
Empty file.
50 changes: 50 additions & 0 deletions src/bleak_esphome/backend/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Bluetooth cache for esphome."""
from __future__ import annotations

Check warning on line 2 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L2

Added line #L2 was not covered by tests

from collections.abc import MutableMapping
from dataclasses import dataclass, field

Check warning on line 5 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L4-L5

Added lines #L4 - L5 were not covered by tests

from bleak.backends.service import BleakGATTServiceCollection
from lru import LRU # pylint: disable=no-name-in-module

Check warning on line 8 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L7-L8

Added lines #L7 - L8 were not covered by tests

MAX_CACHED_SERVICES = 128

Check warning on line 10 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L10

Added line #L10 was not covered by tests


@dataclass(slots=True)
class ESPHomeBluetoothCache:

Check warning on line 14 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L14

Added line #L14 was not covered by tests
"""Shared cache between all ESPHome bluetooth devices."""

_gatt_services_cache: MutableMapping[int, BleakGATTServiceCollection] = field(
default_factory=lambda: LRU(MAX_CACHED_SERVICES)
)
_gatt_mtu_cache: MutableMapping[int, int] = field(
default_factory=lambda: LRU(MAX_CACHED_SERVICES)
)

def get_gatt_services_cache(

Check warning on line 24 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L24

Added line #L24 was not covered by tests
self, address: int
) -> BleakGATTServiceCollection | None:
"""Get the BleakGATTServiceCollection for the given address."""
return self._gatt_services_cache.get(address)

Check warning on line 28 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L28

Added line #L28 was not covered by tests

def set_gatt_services_cache(

Check warning on line 30 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L30

Added line #L30 was not covered by tests
self, address: int, services: BleakGATTServiceCollection
) -> None:
"""Set the BleakGATTServiceCollection for the given address."""
self._gatt_services_cache[address] = services

Check warning on line 34 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L34

Added line #L34 was not covered by tests

def clear_gatt_services_cache(self, address: int) -> None:

Check warning on line 36 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L36

Added line #L36 was not covered by tests
"""Clear the BleakGATTServiceCollection for the given address."""
self._gatt_services_cache.pop(address, None)

Check warning on line 38 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L38

Added line #L38 was not covered by tests

def get_gatt_mtu_cache(self, address: int) -> int | None:

Check warning on line 40 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L40

Added line #L40 was not covered by tests
"""Get the mtu cache for the given address."""
return self._gatt_mtu_cache.get(address)

Check warning on line 42 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L42

Added line #L42 was not covered by tests

def set_gatt_mtu_cache(self, address: int, mtu: int) -> None:

Check warning on line 44 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L44

Added line #L44 was not covered by tests
"""Set the mtu cache for the given address."""
self._gatt_mtu_cache[address] = mtu

Check warning on line 46 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L46

Added line #L46 was not covered by tests

def clear_gatt_mtu_cache(self, address: int) -> None:

Check warning on line 48 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L48

Added line #L48 was not covered by tests
"""Clear the mtu cache for the given address."""
self._gatt_mtu_cache.pop(address, None)

Check warning on line 50 in src/bleak_esphome/backend/cache.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/cache.py#L50

Added line #L50 was not covered by tests
96 changes: 96 additions & 0 deletions src/bleak_esphome/backend/characteristic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""BleakGATTCharacteristicESPHome."""
from __future__ import annotations

Check warning on line 2 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L2

Added line #L2 was not covered by tests

import contextlib
from uuid import UUID

Check warning on line 5 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L4-L5

Added lines #L4 - L5 were not covered by tests

from aioesphomeapi.model import BluetoothGATTCharacteristic
from bleak.backends.characteristic import BleakGATTCharacteristic
from bleak.backends.descriptor import BleakGATTDescriptor

Check warning on line 9 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L7-L9

Added lines #L7 - L9 were not covered by tests

PROPERTY_MASKS = {
2**n: prop
for n, prop in enumerate(
(
"broadcast",
"read",
"write-without-response",
"write",
"notify",
"indicate",
"authenticated-signed-writes",
"extended-properties",
"reliable-writes",
"writable-auxiliaries",
)
)
}


class BleakGATTCharacteristicESPHome(BleakGATTCharacteristic):

Check warning on line 30 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L30

Added line #L30 was not covered by tests
"""GATT Characteristic implementation for the ESPHome backend."""

obj: BluetoothGATTCharacteristic

Check warning on line 33 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L33

Added line #L33 was not covered by tests

def __init__(

Check warning on line 35 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L35

Added line #L35 was not covered by tests
self,
obj: BluetoothGATTCharacteristic,
max_write_without_response_size: int,
service_uuid: str,
service_handle: int,
) -> None:
"""Init a BleakGATTCharacteristicESPHome."""
super().__init__(obj, max_write_without_response_size)
self.__descriptors: list[BleakGATTDescriptor] = []
self.__service_uuid: str = service_uuid
self.__service_handle: int = service_handle
char_props = self.obj.properties

Check warning on line 47 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L43-L47

Added lines #L43 - L47 were not covered by tests
self.__props: list[str] = [
prop for mask, prop in PROPERTY_MASKS.items() if char_props & mask
]

@property

Check warning on line 52 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L52

Added line #L52 was not covered by tests
def service_uuid(self) -> str:
"""Uuid of the Service containing this characteristic."""
return self.__service_uuid

Check warning on line 55 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L55

Added line #L55 was not covered by tests

@property

Check warning on line 57 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L57

Added line #L57 was not covered by tests
def service_handle(self) -> int:
"""Integer handle of the Service containing this characteristic."""
return self.__service_handle

Check warning on line 60 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L60

Added line #L60 was not covered by tests

@property

Check warning on line 62 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L62

Added line #L62 was not covered by tests
def handle(self) -> int:
"""Integer handle for this characteristic."""
return self.obj.handle

Check warning on line 65 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L65

Added line #L65 was not covered by tests

@property

Check warning on line 67 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L67

Added line #L67 was not covered by tests
def uuid(self) -> str:
"""Uuid of this characteristic."""
return self.obj.uuid

Check warning on line 70 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L70

Added line #L70 was not covered by tests

@property

Check warning on line 72 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L72

Added line #L72 was not covered by tests
def properties(self) -> list[str]:
"""Properties of this characteristic."""
return self.__props

Check warning on line 75 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L75

Added line #L75 was not covered by tests

@property

Check warning on line 77 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L77

Added line #L77 was not covered by tests
def descriptors(self) -> list[BleakGATTDescriptor]:
"""List of descriptors for this service."""
return self.__descriptors

Check warning on line 80 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L80

Added line #L80 was not covered by tests

def get_descriptor(self, specifier: int | str | UUID) -> BleakGATTDescriptor | None:

Check warning on line 82 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L82

Added line #L82 was not covered by tests
"""Get a descriptor by handle (int) or UUID (str or uuid.UUID)."""
with contextlib.suppress(StopIteration):
if isinstance(specifier, int):
return next(filter(lambda x: x.handle == specifier, self.descriptors))
return next(filter(lambda x: x.uuid == str(specifier), self.descriptors))
return None

Check warning on line 88 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L88

Added line #L88 was not covered by tests

def add_descriptor(self, descriptor: BleakGATTDescriptor) -> None:

Check warning on line 90 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L90

Added line #L90 was not covered by tests
"""
Add a :py:class:`~BleakGATTDescriptor` to the characteristic.

Should not be used by end user, but rather by `bleak` itself.
"""
self.__descriptors.append(descriptor)

Check warning on line 96 in src/bleak_esphome/backend/characteristic.py

View check run for this annotation

Codecov / codecov/patch

src/bleak_esphome/backend/characteristic.py#L96

Added line #L96 was not covered by tests
Loading
Loading