diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 8d29941..bf524b0 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -33,7 +33,7 @@ jobs: - name: Install Python modules run: | - pip install --constraint=.github/workflows/constraints.txt pre-commit black flake8 reorder-python-imports + pip install --constraint=.github/workflows/constraints.txt pre-commit black flake8 isort - name: Run pre-commit on all files run: | diff --git a/.gitignore b/.gitignore index 2f4cb75..22445ec 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ config/blueprint* config/.HA_VERSION config/configuration.yaml config/known_devices.yaml + +node_modules/.cache* diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..d9e5b68 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,4 @@ +[settings] +add_imports=from __future__ import annotations +force_single_line=true +profile=black diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 13b7d33..74d81e8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,13 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - - repo: local + - repo: https://github.com/psf/black + rev: 24.2.0 hooks: - id: black name: black @@ -14,19 +15,19 @@ repos: language: system types: [python] require_serial: true + - repo: local + hooks: - id: flake8 name: flake8 entry: flake8 language: system types: [python] require_serial: true - - id: reorder-python-imports - name: Reorder python imports - entry: reorder-python-imports - language: system - types: [python] - args: [--application-directories=custom_components] + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.2 + rev: v4.0.0-alpha.8 hooks: - id: prettier diff --git a/custom_components/__init__.py b/custom_components/__init__.py index 9e5dc14..6f53023 100644 --- a/custom_components/__init__.py +++ b/custom_components/__init__.py @@ -1 +1,3 @@ """Dummy init so that pytest works.""" + +from __future__ import annotations diff --git a/custom_components/bermuda/__init__.py b/custom_components/bermuda/__init__.py index f7e1ad8..d23cf1e 100644 --- a/custom_components/bermuda/__init__.py +++ b/custom_components/bermuda/__init__.py @@ -4,20 +4,20 @@ For more details about this integration, please refer to https://github.com/agittins/bermuda """ + from __future__ import annotations import asyncio import logging from datetime import datetime from datetime import timedelta -from typing import TYPE_CHECKING import voluptuous as vol from homeassistant.components import bluetooth +from homeassistant.components.bluetooth import MONOTONIC_TIME from homeassistant.components.bluetooth import BluetoothChange from homeassistant.components.bluetooth import BluetoothScannerDevice from homeassistant.components.bluetooth import BluetoothServiceInfoBleak -from homeassistant.components.bluetooth import MONOTONIC_TIME from homeassistant.components.bluetooth.active_update_coordinator import ( PassiveBluetoothDataUpdateCoordinator, ) @@ -25,10 +25,10 @@ from homeassistant.const import STATE_HOME from homeassistant.const import STATE_NOT_HOME from homeassistant.const import STATE_UNAVAILABLE -from homeassistant.core import callback from homeassistant.core import Config from homeassistant.core import HomeAssistant from homeassistant.core import SupportsResponse +from homeassistant.core import callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import area_registry from homeassistant.helpers import config_validation as cv @@ -57,10 +57,12 @@ from .const import SIGNAL_DEVICE_NEW from .const import STARTUP_MESSAGE +# from typing import TYPE_CHECKING + # from bthome_ble import BTHomeBluetoothDeviceData -if TYPE_CHECKING: - from bleak.backends.device import BLEDevice +# if TYPE_CHECKING: +# from bleak.backends.device import BLEDevice SCAN_INTERVAL = timedelta(seconds=5) @@ -135,24 +137,34 @@ class BermudaPBDUCoordinator( Looks like this needs to be run through setup, with a specific BLEDevice (address) already specified, so won't do "all adverts" + + We (plan to) use it to capture each monitored addresses' events so we can update more + frequently than UPDATE_INTERVAL, and respond in realtime. + The co-ordinator will create one of these for each device we create + sensors for, and this will just call the coordinator's update routine + whenever something changes. + + WORK IN PROGRESS: this doesn't currently do anything. """ def __init__( self, hass: HomeAssistant, logger: logging.Logger, - ble_device: BLEDevice, + address: str, device: BermudaDevice, + coordinator: BermudaDataUpdateCoordinator, ) -> None: """Init""" super().__init__( hass=hass, logger=logger, - address=ble_device.address, - mode=bluetooth.BluetoothScanningMode.ACTIVE, + address=address, + mode=bluetooth.BluetoothScanningMode.PASSIVE, connectable=False, ) self.device = device + self.coordinator = coordinator @callback def _async_handle_unavailable( @@ -164,6 +176,10 @@ def _async_handle_unavailable( def _async_handle_bluetooth_event( self, service_info: BluetoothServiceInfoBleak, change: BluetoothChange ) -> None: + _LOGGER.warning( + "Update triggered by device %s (this is a good thing)", self.device.name + ) + self.coordinator.async_refresh() return super()._async_handle_bluetooth_event(service_info, change) @@ -462,6 +478,7 @@ def __init__( self.options[key] = val self.devices: dict[str, BermudaDevice] = {} + self.updaters: dict[str, BermudaPBDUCoordinator] = {} self.area_reg = area_registry.async_get(hass) @@ -490,6 +507,11 @@ def sensor_created(self, address): dev = self._get_device(address) if dev is not None: dev.create_sensor_done = True + self.updaters[address] = pduc = BermudaPBDUCoordinator( + self.hass, _LOGGER, address, dev, self + ) + _LOGGER.debug("Registering PDUC for %s", dev.name) + self.config_entry.async_on_unload(pduc.async_start()) else: _LOGGER.warning("Very odd, we got sensor_created for non-tracked device") diff --git a/custom_components/bermuda/binary_sensor.py b/custom_components/bermuda/binary_sensor.py index 2e1c106..c974a45 100644 --- a/custom_components/bermuda/binary_sensor.py +++ b/custom_components/bermuda/binary_sensor.py @@ -1,4 +1,7 @@ """Binary sensor platform for Bermuda BLE Trilateration.""" + +from __future__ import annotations + from homeassistant.components.binary_sensor import BinarySensorEntity from .const import BINARY_SENSOR diff --git a/custom_components/bermuda/config_flow.py b/custom_components/bermuda/config_flow.py index e14a9ac..7437f5c 100644 --- a/custom_components/bermuda/config_flow.py +++ b/custom_components/bermuda/config_flow.py @@ -1,4 +1,7 @@ """Adds config flow for Bermuda BLE Trilateration.""" + +from __future__ import annotations + import voluptuous as vol from homeassistant import config_entries from homeassistant.components import bluetooth diff --git a/custom_components/bermuda/const.py b/custom_components/bermuda/const.py index 5174667..f6fdefd 100644 --- a/custom_components/bermuda/const.py +++ b/custom_components/bermuda/const.py @@ -1,5 +1,8 @@ """Constants for Bermuda BLE Trilateration.""" + # Base component constants +from __future__ import annotations + NAME = "Bermuda BLE Trilateration" DOMAIN = "bermuda" DOMAIN_DATA = f"{DOMAIN}_data" @@ -56,9 +59,9 @@ DOCS[CONF_MAX_RADIUS] = "For simple area-detection, max radius from receiver" CONF_DEVTRACK_TIMEOUT, DEFAULT_DEVTRACK_TIMEOUT = "devtracker_nothome_timeout", 30 -DOCS[ - CONF_DEVTRACK_TIMEOUT -] = "Timeout in seconds for setting devices as `Not Home` / `Away`." +DOCS[CONF_DEVTRACK_TIMEOUT] = ( + "Timeout in seconds for setting devices as `Not Home` / `Away`." # fmt: skip +) CONF_ATTENUATION, DEFAULT_ATTENUATION = "attenuation", 3 DOCS[CONF_ATTENUATION] = "Factor for environmental signal attenuation." diff --git a/custom_components/bermuda/device_tracker.py b/custom_components/bermuda/device_tracker.py index e5377f5..7b62a42 100644 --- a/custom_components/bermuda/device_tracker.py +++ b/custom_components/bermuda/device_tracker.py @@ -1,4 +1,5 @@ """Create device_tracker entities for Bermuda devices""" + from __future__ import annotations import logging diff --git a/custom_components/bermuda/entity.py b/custom_components/bermuda/entity.py index 6440e9d..ab6a0f8 100644 --- a/custom_components/bermuda/entity.py +++ b/custom_components/bermuda/entity.py @@ -1,4 +1,5 @@ """BermudaEntity class""" + from __future__ import annotations from typing import TYPE_CHECKING diff --git a/custom_components/bermuda/sensor.py b/custom_components/bermuda/sensor.py index f99ff8b..842c38a 100644 --- a/custom_components/bermuda/sensor.py +++ b/custom_components/bermuda/sensor.py @@ -1,4 +1,7 @@ """Sensor platform for Bermuda BLE Trilateration.""" + +from __future__ import annotations + from collections.abc import Mapping from typing import Any @@ -6,8 +9,8 @@ from homeassistant.components.sensor import SensorDeviceClass from homeassistant.components.sensor import SensorStateClass from homeassistant.const import UnitOfLength -from homeassistant.core import callback from homeassistant.core import HomeAssistant +from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback diff --git a/custom_components/bermuda/switch.py b/custom_components/bermuda/switch.py index 04dbefe..ca18bae 100644 --- a/custom_components/bermuda/switch.py +++ b/custom_components/bermuda/switch.py @@ -1,4 +1,7 @@ """Switch platform for Bermuda BLE Trilateration.""" + +from __future__ import annotations + from homeassistant.components.switch import SwitchEntity from .const import DEFAULT_NAME diff --git a/requirements_test.txt b/requirements_test.txt index 2a3cdac..04e4d68 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -3,6 +3,7 @@ pytest-asyncio pytest-homeassistant-custom-component #==0.13.50 pre-commit -reorder-python-imports +isort +black==24.2.0 pyserial-asyncio==0.6 pyserial==3.5 diff --git a/tests/__init__.py b/tests/__init__.py index d2559b4..fa3be76 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +1,3 @@ """Tests for Bermuda BLE Trilateration integration.""" + +from __future__ import annotations diff --git a/tests/conftest.py b/tests/conftest.py index 015968e..3b921a2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,7 @@ """Global fixtures for Bermuda BLE Trilateration integration.""" + +from __future__ import annotations + from unittest.mock import patch import pytest diff --git a/tests/const.py b/tests/const.py index c99b331..2a71fd9 100644 --- a/tests/const.py +++ b/tests/const.py @@ -1,4 +1,5 @@ """Constants for Bermuda BLE Trilateration tests.""" + # AJG: We don't use these vars in our flow. TODO: Add some we _do_ use! # from custom_components.bermuda.const import ( # CONF_PASSWORD, @@ -7,4 +8,6 @@ # CONF_USERNAME, # ) # MOCK_CONFIG = {CONF_USERNAME: "test_username", CONF_PASSWORD: "test_password"} +from __future__ import annotations + MOCK_CONFIG = {} diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py index f7ca6ee..1849d58 100644 --- a/tests/test_config_flow.py +++ b/tests/test_config_flow.py @@ -1,26 +1,20 @@ """Test Bermuda BLE Trilateration config flow.""" + +from __future__ import annotations + from unittest.mock import patch import pytest -from custom_components.bermuda.const import ( - BINARY_SENSOR, -) -from custom_components.bermuda.const import ( - DOMAIN, -) -from custom_components.bermuda.const import ( - PLATFORMS, -) -from custom_components.bermuda.const import ( - SENSOR, -) -from custom_components.bermuda.const import ( - SWITCH, -) from homeassistant import config_entries from homeassistant import data_entry_flow from pytest_homeassistant_custom_component.common import MockConfigEntry +from custom_components.bermuda.const import BINARY_SENSOR +from custom_components.bermuda.const import DOMAIN +from custom_components.bermuda.const import PLATFORMS +from custom_components.bermuda.const import SENSOR +from custom_components.bermuda.const import SWITCH + from .const import MOCK_CONFIG diff --git a/tests/test_init.py b/tests/test_init.py index 6bceace..85dc8d5 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -1,23 +1,17 @@ """Test Bermuda BLE Trilateration setup process.""" + +from __future__ import annotations + import pytest -from custom_components.bermuda import ( - async_reload_entry, -) -from custom_components.bermuda import ( - async_setup_entry, -) -from custom_components.bermuda import ( - async_unload_entry, -) -from custom_components.bermuda import ( - BermudaDataUpdateCoordinator, -) -from custom_components.bermuda.const import ( - DOMAIN, -) from homeassistant.exceptions import ConfigEntryNotReady from pytest_homeassistant_custom_component.common import MockConfigEntry +from custom_components.bermuda import BermudaDataUpdateCoordinator +from custom_components.bermuda import async_reload_entry +from custom_components.bermuda import async_setup_entry +from custom_components.bermuda import async_unload_entry +from custom_components.bermuda.const import DOMAIN + from .const import MOCK_CONFIG # from pytest_homeassistant_custom_component.common import AsyncMock diff --git a/tests/test_switch.py b/tests/test_switch.py index 6da17de..0ebcb36 100644 --- a/tests/test_switch.py +++ b/tests/test_switch.py @@ -1,24 +1,20 @@ """Test Bermuda BLE Trilateration switch.""" + +from __future__ import annotations + from unittest.mock import call from unittest.mock import patch -from custom_components.bermuda import ( - async_setup_entry, -) -from custom_components.bermuda.const import ( - DEFAULT_NAME, -) -from custom_components.bermuda.const import ( - DOMAIN, -) -from custom_components.bermuda.const import ( - SWITCH, -) from homeassistant.components.switch import SERVICE_TURN_OFF from homeassistant.components.switch import SERVICE_TURN_ON from homeassistant.const import ATTR_ENTITY_ID from pytest_homeassistant_custom_component.common import MockConfigEntry +from custom_components.bermuda import async_setup_entry +from custom_components.bermuda.const import DEFAULT_NAME +from custom_components.bermuda.const import DOMAIN +from custom_components.bermuda.const import SWITCH + from .const import MOCK_CONFIG