diff --git a/src/data/bluetooth.ts b/src/data/bluetooth.ts index 633de1d058..7c95d32de9 100644 --- a/src/data/bluetooth.ts +++ b/src/data/bluetooth.ts @@ -24,11 +24,14 @@ export interface BluetoothConnectionData extends DataTableRowData { source: string; } +export type HaScannerType = "usb" | "uart" | "remote" | "unknown"; + export interface BluetoothScannerDetails { source: string; connectable: boolean; name: string; adapter: string; + scanner_type?: HaScannerType; } export type BluetoothScannersDetails = Record; diff --git a/src/panels/config/integrations/integration-panels/bluetooth/bluetooth-config-dashboard.ts b/src/panels/config/integrations/integration-panels/bluetooth/bluetooth-config-dashboard.ts index b415dd8dae..0726236beb 100644 --- a/src/panels/config/integrations/integration-panels/bluetooth/bluetooth-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/bluetooth/bluetooth-config-dashboard.ts @@ -14,16 +14,19 @@ import type { HomeAssistant } from "../../../../../types"; import { subscribeBluetoothConnectionAllocations, subscribeBluetoothScannerState, + subscribeBluetoothScannersDetails, +} from "../../../../../data/bluetooth"; +import type { + BluetoothAllocationsData, + BluetoothScannerState, + BluetoothScannersDetails, + HaScannerType, } from "../../../../../data/bluetooth"; import { getValueInPercentage, roundWithOneDecimal, } from "../../../../../util/calculate"; import "../../../../../components/ha-metric"; -import type { - BluetoothAllocationsData, - BluetoothScannerState, -} from "../../../../../data/bluetooth"; @customElement("bluetooth-config-dashboard") export class BluetoothConfigDashboard extends LitElement { @@ -37,6 +40,8 @@ export class BluetoothConfigDashboard extends LitElement { @state() private _scannerState?: BluetoothScannerState; + @state() private _scannerDetails?: BluetoothScannersDetails; + private _configEntry = new URLSearchParams(window.location.search).get( "config_entry" ); @@ -45,11 +50,14 @@ export class BluetoothConfigDashboard extends LitElement { private _unsubScannerState?: (() => Promise) | undefined; + private _unsubScannerDetails?: (() => void) | undefined; + public connectedCallback(): void { super.connectedCallback(); if (this.hass) { this._subscribeBluetoothConnectionAllocations(); this._subscribeBluetoothScannerState(); + this._subscribeScannerDetails(); } } @@ -85,6 +93,18 @@ export class BluetoothConfigDashboard extends LitElement { ); } + private _subscribeScannerDetails(): void { + if (this._unsubScannerDetails) { + return; + } + this._unsubScannerDetails = subscribeBluetoothScannersDetails( + this.hass.connection, + (details) => { + this._scannerDetails = details; + } + ); + } + public disconnectedCallback() { super.disconnectedCallback(); if (this._unsubConnectionAllocations) { @@ -95,6 +115,10 @@ export class BluetoothConfigDashboard extends LitElement { this._unsubScannerState(); this._unsubScannerState = undefined; } + if (this._unsubScannerDetails) { + this._unsubScannerDetails(); + this._unsubScannerDetails = undefined; + } } protected render(): TemplateResult { @@ -171,6 +195,51 @@ export class BluetoothConfigDashboard extends LitElement { private _getUsedAllocations = (used: number, total: number) => roundWithOneDecimal(getValueInPercentage(used, 0, total)); + private _renderScannerMismatchWarning( + scannerState: BluetoothScannerState, + scannerType: HaScannerType, + formatMode: (mode: string | null) => string + ) { + const instructions: string[] = []; + + if (scannerType === "remote" || scannerType === "unknown") { + instructions.push( + this.hass.localize( + "ui.panel.config.bluetooth.scanner_mode_mismatch_remote" + ) + ); + } + if (scannerType === "usb" || scannerType === "unknown") { + instructions.push( + this.hass.localize( + "ui.panel.config.bluetooth.scanner_mode_mismatch_usb" + ) + ); + } + if (scannerType === "uart" || scannerType === "unknown") { + instructions.push( + this.hass.localize( + "ui.panel.config.bluetooth.scanner_mode_mismatch_uart" + ) + ); + } + + return html` +
+ ${this.hass.localize( + "ui.panel.config.bluetooth.scanner_mode_mismatch", + { + requested: formatMode(scannerState.requested_mode), + current: formatMode(scannerState.current_mode), + } + )} +
+
    + ${instructions.map((instruction) => html`
  • ${instruction}
  • `)} +
+
`; + } + private _renderScannerState() { if (!this._configEntry || !this._scannerState) { return html`
@@ -181,6 +250,10 @@ export class BluetoothConfigDashboard extends LitElement { } const scannerState = this._scannerState; + // Find the scanner details for this source + const scannerDetails = this._scannerDetails?.[scannerState.source]; + const scannerType: HaScannerType = + scannerDetails?.scanner_type ?? "unknown"; const formatMode = (mode: string | null) => { switch (mode) { @@ -224,34 +297,11 @@ export class BluetoothConfigDashboard extends LitElement { >
${scannerState.current_mode !== scannerState.requested_mode - ? html` -
- ${this.hass.localize( - "ui.panel.config.bluetooth.scanner_mode_mismatch", - { - requested: formatMode(scannerState.requested_mode), - current: formatMode(scannerState.current_mode), - } - )} -
-
    -
  • - ${this.hass.localize( - "ui.panel.config.bluetooth.scanner_mode_mismatch_proxy" - )} -
  • -
  • - ${this.hass.localize( - "ui.panel.config.bluetooth.scanner_mode_mismatch_usb" - )} -
  • -
  • - ${this.hass.localize( - "ui.panel.config.bluetooth.scanner_mode_mismatch_onboard" - )} -
  • -
-
` + ? this._renderScannerMismatchWarning( + scannerState, + scannerType, + formatMode + ) : nothing} `; diff --git a/src/translations/en.json b/src/translations/en.json index 8738e49a90..1e441df471 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5748,9 +5748,9 @@ "scanning_mode_active": "active", "scanning_mode_passive": "passive", "scanner_mode_mismatch": "Scanner requested {requested} mode but is operating in {current} mode. The scanner is in a bad state and needs to be power cycled.", - "scanner_mode_mismatch_proxy": "For proxies: reboot the device", + "scanner_mode_mismatch_remote": "For proxies: reboot the device", "scanner_mode_mismatch_usb": "For USB adapters: unplug and plug back in", - "scanner_mode_mismatch_onboard": "For onboard adapters: power down the system completely and power it back up", + "scanner_mode_mismatch_uart": "For UART/onboard adapters: power down the system completely and power it back up", "address": "Address", "name": "Name", "source": "Source",