Add bluetooth diagnostics to esphome (#82761)

This commit is contained in:
J. Nick Koston 2022-11-27 09:59:37 -10:00 committed by GitHub
parent 3e3138ef1b
commit f0ae1cc6ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 116 additions and 17 deletions

View File

@ -67,12 +67,14 @@ class BaseHaScanner:
"""Return diagnostic information about the scanner.""" """Return diagnostic information about the scanner."""
return { return {
"type": self.__class__.__name__, "type": self.__class__.__name__,
"discovered_devices": [ "discovered_devices_and_advertisement_data": [
{ {
"name": device.name, "name": device_adv[0].name,
"address": device.address, "address": device_adv[0].address,
"rssi": device_adv[0].rssi,
"advertisement_data": device_adv[1],
} }
for device in self.discovered_devices for device_adv in self.discovered_devices_and_advertisement_data.values()
], ],
} }

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import re import re
from typing import Any
from aioesphomeapi import BluetoothLEAdvertisement from aioesphomeapi import BluetoothLEAdvertisement
@ -27,3 +28,18 @@ class ESPHomeScanner(BaseHaRemoteScanner):
adv.manufacturer_data, adv.manufacturer_data,
None, None,
) )
async def async_diagnostics(self) -> dict[str, Any]:
"""Return diagnostic information about the scanner."""
return await super().async_diagnostics() | {
"type": self.__class__.__name__,
"discovered_devices_and_advertisement_data": [
{
"name": device_adv[0].name,
"address": device_adv[0].address,
"rssi": device_adv[0].rssi,
"advertisement_data": device_adv[1],
}
for device_adv in self.discovered_devices_and_advertisement_data.values()
],
}

View File

@ -3,6 +3,7 @@ from __future__ import annotations
from typing import Any, cast from typing import Any, cast
from homeassistant.components.bluetooth import async_scanner_by_source
from homeassistant.components.diagnostics import async_redact_data from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD from homeassistant.const import CONF_PASSWORD
@ -29,4 +30,13 @@ async def async_get_config_entry_diagnostics(
storage_data = cast("dict[str, Any]", storage_data) storage_data = cast("dict[str, Any]", storage_data)
diag["storage_data"] = storage_data diag["storage_data"] = storage_data
if config_entry.unique_id and (
scanner := async_scanner_by_source(hass, config_entry.unique_id)
):
diag["bluetooth"] = {
"connections_free": entry_data.ble_connections_free,
"connections_limit": entry_data.ble_connections_limit,
"scanner": await scanner.async_diagnostics(),
}
return async_redact_data(diag, REDACT_KEYS) return async_redact_data(diag, REDACT_KEYS)

View File

@ -24,8 +24,13 @@ async def test_diagnostics(
# error if the test is not running on linux since we won't have the correct # error if the test is not running on linux since we won't have the correct
# deps installed when testing on MacOS. # deps installed when testing on MacOS.
with patch( with patch(
"homeassistant.components.bluetooth.scanner.HaScanner.discovered_devices", "homeassistant.components.bluetooth.scanner.HaScanner.discovered_devices_and_advertisement_data",
[BLEDevice(name="x", rssi=-60, address="44:44:33:11:23:45")], {
"44:44:33:11:23:45": (
BLEDevice(name="x", rssi=-60, address="44:44:33:11:23:45"),
generate_advertisement_data(local_name="x"),
)
},
), patch( ), patch(
"homeassistant.components.bluetooth.diagnostics.platform.system", "homeassistant.components.bluetooth.diagnostics.platform.system",
return_value="Linux", return_value="Linux",
@ -120,8 +125,21 @@ async def test_diagnostics(
"scanners": [ "scanners": [
{ {
"adapter": "hci0", "adapter": "hci0",
"discovered_devices": [ "discovered_devices_and_advertisement_data": [
{"address": "44:44:33:11:23:45", "name": "x"} {
"address": "44:44:33:11:23:45",
"advertisement_data": [
"x",
{},
{},
[],
-127,
-127,
[[]],
],
"name": "x",
"rssi": -60,
}
], ],
"last_detection": ANY, "last_detection": ANY,
"name": "hci0 (00:00:00:00:00:01)", "name": "hci0 (00:00:00:00:00:01)",
@ -131,8 +149,21 @@ async def test_diagnostics(
}, },
{ {
"adapter": "hci0", "adapter": "hci0",
"discovered_devices": [ "discovered_devices_and_advertisement_data": [
{"address": "44:44:33:11:23:45", "name": "x"} {
"address": "44:44:33:11:23:45",
"advertisement_data": [
"x",
{},
{},
[],
-127,
-127,
[[]],
],
"name": "x",
"rssi": -60,
}
], ],
"last_detection": ANY, "last_detection": ANY,
"name": "hci0 (00:00:00:00:00:01)", "name": "hci0 (00:00:00:00:00:01)",
@ -142,8 +173,21 @@ async def test_diagnostics(
}, },
{ {
"adapter": "hci1", "adapter": "hci1",
"discovered_devices": [ "discovered_devices_and_advertisement_data": [
{"address": "44:44:33:11:23:45", "name": "x"} {
"address": "44:44:33:11:23:45",
"advertisement_data": [
"x",
{},
{},
[],
-127,
-127,
[[]],
],
"name": "x",
"rssi": -60,
}
], ],
"last_detection": ANY, "last_detection": ANY,
"name": "hci1 (00:00:00:00:00:02)", "name": "hci1 (00:00:00:00:00:02)",
@ -171,8 +215,13 @@ async def test_diagnostics_macos(
) )
with patch( with patch(
"homeassistant.components.bluetooth.scanner.HaScanner.discovered_devices", "homeassistant.components.bluetooth.scanner.HaScanner.discovered_devices_and_advertisement_data",
[BLEDevice(name="x", rssi=-60, address="44:44:33:11:23:45")], {
"44:44:33:11:23:45": (
BLEDevice(name="x", rssi=-60, address="44:44:33:11:23:45"),
switchbot_adv,
)
},
), patch( ), patch(
"homeassistant.components.bluetooth.diagnostics.platform.system", "homeassistant.components.bluetooth.diagnostics.platform.system",
return_value="Darwin", return_value="Darwin",
@ -274,8 +323,26 @@ async def test_diagnostics_macos(
"scanners": [ "scanners": [
{ {
"adapter": "Core Bluetooth", "adapter": "Core Bluetooth",
"discovered_devices": [ "discovered_devices_and_advertisement_data": [
{"address": "44:44:33:11:23:45", "name": "x"} {
"address": "44:44:33:11:23:45",
"advertisement_data": [
"wohand",
{
"1": {
"__type": "<class " "'bytes'>",
"repr": "b'\\x01'",
}
},
{},
[],
-127,
-127,
[[]],
],
"name": "x",
"rssi": -60,
}
], ],
"last_detection": ANY, "last_detection": ANY,
"name": "Core Bluetooth", "name": "Core Bluetooth",

View File

@ -1,6 +1,7 @@
"""Tests for the diagnostics data provided by the ESPHome integration.""" """Tests for the diagnostics data provided by the ESPHome integration."""
from aiohttp import ClientSession from aiohttp import ClientSession
import pytest
from homeassistant.components.esphome import CONF_NOISE_PSK from homeassistant.components.esphome import CONF_NOISE_PSK
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT
@ -11,7 +12,10 @@ from tests.components.diagnostics import get_diagnostics_for_config_entry
async def test_diagnostics( async def test_diagnostics(
hass: HomeAssistant, hass_client: ClientSession, init_integration: MockConfigEntry hass: HomeAssistant,
hass_client: ClientSession,
init_integration: MockConfigEntry,
enable_bluetooth: pytest.fixture,
): ):
"""Test diagnostics for config entry.""" """Test diagnostics for config entry."""
result = await get_diagnostics_for_config_entry(hass, hass_client, init_integration) result = await get_diagnostics_for_config_entry(hass, hass_client, init_integration)