mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add support for showing Bluetooth connection slot allocations (#23899)
This commit is contained in:
parent
f8d2560104
commit
cbdb7406ad
@ -29,7 +29,14 @@ interface BluetoothAdvertisementSubscriptionMessage {
|
||||
remove?: BluetoothRemoveDeviceData[];
|
||||
}
|
||||
|
||||
const subscribeUpdates = (
|
||||
export interface BluetoothAllocationsData {
|
||||
source: string;
|
||||
slots: number;
|
||||
free: number;
|
||||
allocated: string[];
|
||||
}
|
||||
|
||||
const subscribeBluetoothAdvertisementsUpdates = (
|
||||
conn: Connection,
|
||||
store: Store<BluetoothDeviceData[]>
|
||||
): Promise<UnsubscribeFunc> =>
|
||||
@ -78,13 +85,32 @@ const subscribeUpdates = (
|
||||
|
||||
export const subscribeBluetoothAdvertisements = (
|
||||
conn: Connection,
|
||||
onChange: (bluetoothDeviceData: BluetoothDeviceData[]) => void
|
||||
callbackFunction: (bluetoothDeviceData: BluetoothDeviceData[]) => void
|
||||
) =>
|
||||
createCollection<BluetoothDeviceData[]>(
|
||||
"_bluetoothDeviceRows",
|
||||
() => Promise.resolve<BluetoothDeviceData[]>([]), // empty array as initial state
|
||||
|
||||
subscribeUpdates,
|
||||
subscribeBluetoothAdvertisementsUpdates,
|
||||
conn,
|
||||
onChange
|
||||
callbackFunction
|
||||
);
|
||||
|
||||
export const subscribeBluetoothConnectionAllocations = (
|
||||
conn: Connection,
|
||||
callbackFunction: (
|
||||
bluetoothAllocationsData: BluetoothAllocationsData[]
|
||||
) => void,
|
||||
configEntryId?: string
|
||||
): Promise<() => Promise<void>> => {
|
||||
const params: { type: string; config_entry_id?: string } = {
|
||||
type: "bluetooth/subscribe_connection_allocations",
|
||||
};
|
||||
if (configEntryId) {
|
||||
params.config_entry_id = configEntryId;
|
||||
}
|
||||
return conn.subscribeMessage<BluetoothAllocationsData[]>(
|
||||
(bluetoothAllocationsData) => callbackFunction(bluetoothAllocationsData),
|
||||
params
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import "@material/mwc-button";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-code-editor";
|
||||
import "../../../../../components/ha-formfield";
|
||||
@ -11,6 +11,13 @@ import { showOptionsFlowDialog } from "../../../../../dialogs/config-flow/show-d
|
||||
import "../../../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { subscribeBluetoothConnectionAllocations } from "../../../../../data/bluetooth";
|
||||
import {
|
||||
getValueInPercentage,
|
||||
roundWithOneDecimal,
|
||||
} from "../../../../../util/calculate";
|
||||
import "../../../../../components/ha-metric";
|
||||
import type { BluetoothAllocationsData } from "../../../../../data/bluetooth";
|
||||
|
||||
@customElement("bluetooth-config-dashboard")
|
||||
export class BluetoothConfigDashboard extends LitElement {
|
||||
@ -18,6 +25,50 @@ export class BluetoothConfigDashboard extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state() private _connectionAllocationData: BluetoothAllocationsData[] = [];
|
||||
|
||||
@state() private _connectionAllocationsError?: string;
|
||||
|
||||
private _configEntry = new URLSearchParams(window.location.search).get(
|
||||
"config_entry"
|
||||
);
|
||||
|
||||
private _unsubConnectionAllocations?: (() => Promise<void>) | undefined;
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
if (this.hass) {
|
||||
this._subscribeBluetoothConnectionAllocations();
|
||||
}
|
||||
}
|
||||
|
||||
private async _subscribeBluetoothConnectionAllocations(): Promise<void> {
|
||||
if (this._unsubConnectionAllocations || !this._configEntry) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this._unsubConnectionAllocations =
|
||||
await subscribeBluetoothConnectionAllocations(
|
||||
this.hass.connection,
|
||||
(data) => {
|
||||
this._connectionAllocationData = data;
|
||||
},
|
||||
this._configEntry
|
||||
);
|
||||
} catch (err: any) {
|
||||
this._unsubConnectionAllocations = undefined;
|
||||
this._connectionAllocationsError = err.message;
|
||||
}
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
if (this._unsubConnectionAllocations) {
|
||||
this._unsubConnectionAllocations();
|
||||
this._unsubConnectionAllocations = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-subpage .narrow=${this.narrow} .hass=${this.hass}>
|
||||
@ -57,17 +108,68 @@ export class BluetoothConfigDashboard extends LitElement {
|
||||
>
|
||||
</div>
|
||||
</ha-card>
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.bluetooth.connection_slot_allocations_monitor"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
${this._renderConnectionAllocations()}
|
||||
</div>
|
||||
</ha-card>
|
||||
</div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private _getUsedAllocations = (used: number, total: number) =>
|
||||
roundWithOneDecimal(getValueInPercentage(used, 0, total));
|
||||
|
||||
private _renderConnectionAllocations() {
|
||||
if (this._connectionAllocationsError) {
|
||||
return html`<ha-alert alert-type="error"
|
||||
>${this._connectionAllocationsError}</ha-alert
|
||||
>`;
|
||||
}
|
||||
if (this._connectionAllocationData.length === 0) {
|
||||
return html`<div>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.bluetooth.no_connection_slot_allocations"
|
||||
)}
|
||||
</div>`;
|
||||
}
|
||||
const allocations = this._connectionAllocationData[0];
|
||||
const allocationsUsed = allocations.slots - allocations.free;
|
||||
const allocationsTotal = allocations.slots;
|
||||
if (allocationsTotal === 0) {
|
||||
return html`<div>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.bluetooth.no_active_connection_support"
|
||||
)}
|
||||
</div>`;
|
||||
}
|
||||
return html`
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.bluetooth.connection_slot_allocations_monitor_details",
|
||||
{ slots: allocationsTotal }
|
||||
)}
|
||||
</p>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.bluetooth.used_connection_slot_allocations"
|
||||
)}
|
||||
.value=${this._getUsedAllocations(allocationsUsed, allocationsTotal)}
|
||||
.tooltip=${`${allocationsUsed}/${allocationsTotal}`}
|
||||
></ha-metric>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _openOptionFlow() {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
if (!searchParams.has("config_entry")) {
|
||||
const configEntryId = this._configEntry;
|
||||
if (!configEntryId) {
|
||||
return;
|
||||
}
|
||||
const configEntryId = searchParams.get("config_entry") as string;
|
||||
const configEntries = await getConfigEntries(this.hass, {
|
||||
domain: "bluetooth",
|
||||
});
|
||||
@ -92,7 +194,7 @@ export class BluetoothConfigDashboard extends LitElement {
|
||||
margin: 0 auto;
|
||||
direction: ltr;
|
||||
}
|
||||
ha-card:first-child {
|
||||
ha-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
`,
|
||||
|
@ -5293,8 +5293,13 @@
|
||||
"title": "Bluetooth",
|
||||
"settings_title": "Bluetooth settings",
|
||||
"option_flow": "Configure Bluetooth options",
|
||||
"advertisement_monitor": "Advertisement Monitor",
|
||||
"advertisement_monitor": "Advertisement monitor",
|
||||
"advertisement_monitor_details": "The advertisement monitor listens for Bluetooth advertisements and displays the data in a structured format.",
|
||||
"connection_slot_allocations_monitor": "Connection slot allocations monitor",
|
||||
"connection_slot_allocations_monitor_details": "The connection slot allocations monitor displays the (GATT) connection slot allocations for the adapter. This adapter supports up to {slots} simultaneous connections. Each remote Bluetooth device that requires an active connection will use one connection slot while the Bluetooth device is connecting or connected.",
|
||||
"used_connection_slot_allocations": "Used connection slot allocations",
|
||||
"no_connection_slot_allocations": "No connection slot allocations information available",
|
||||
"no_active_connection_support": "This adapter does not support making active (GATT) connections.",
|
||||
"address": "Address",
|
||||
"name": "Name",
|
||||
"source": "Source",
|
||||
|
Loading…
x
Reference in New Issue
Block a user