mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +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[];
|
remove?: BluetoothRemoveDeviceData[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const subscribeUpdates = (
|
export interface BluetoothAllocationsData {
|
||||||
|
source: string;
|
||||||
|
slots: number;
|
||||||
|
free: number;
|
||||||
|
allocated: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscribeBluetoothAdvertisementsUpdates = (
|
||||||
conn: Connection,
|
conn: Connection,
|
||||||
store: Store<BluetoothDeviceData[]>
|
store: Store<BluetoothDeviceData[]>
|
||||||
): Promise<UnsubscribeFunc> =>
|
): Promise<UnsubscribeFunc> =>
|
||||||
@ -78,13 +85,32 @@ const subscribeUpdates = (
|
|||||||
|
|
||||||
export const subscribeBluetoothAdvertisements = (
|
export const subscribeBluetoothAdvertisements = (
|
||||||
conn: Connection,
|
conn: Connection,
|
||||||
onChange: (bluetoothDeviceData: BluetoothDeviceData[]) => void
|
callbackFunction: (bluetoothDeviceData: BluetoothDeviceData[]) => void
|
||||||
) =>
|
) =>
|
||||||
createCollection<BluetoothDeviceData[]>(
|
createCollection<BluetoothDeviceData[]>(
|
||||||
"_bluetoothDeviceRows",
|
"_bluetoothDeviceRows",
|
||||||
() => Promise.resolve<BluetoothDeviceData[]>([]), // empty array as initial state
|
() => Promise.resolve<BluetoothDeviceData[]>([]), // empty array as initial state
|
||||||
|
|
||||||
subscribeUpdates,
|
subscribeBluetoothAdvertisementsUpdates,
|
||||||
conn,
|
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 "@material/mwc-button";
|
||||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||||
import { css, html, LitElement } 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-card";
|
||||||
import "../../../../../components/ha-code-editor";
|
import "../../../../../components/ha-code-editor";
|
||||||
import "../../../../../components/ha-formfield";
|
import "../../../../../components/ha-formfield";
|
||||||
@ -11,6 +11,13 @@ import { showOptionsFlowDialog } from "../../../../../dialogs/config-flow/show-d
|
|||||||
import "../../../../../layouts/hass-subpage";
|
import "../../../../../layouts/hass-subpage";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../../types";
|
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")
|
@customElement("bluetooth-config-dashboard")
|
||||||
export class BluetoothConfigDashboard extends LitElement {
|
export class BluetoothConfigDashboard extends LitElement {
|
||||||
@ -18,6 +25,50 @@ export class BluetoothConfigDashboard extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public narrow = false;
|
@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 {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage .narrow=${this.narrow} .hass=${this.hass}>
|
<hass-subpage .narrow=${this.narrow} .hass=${this.hass}>
|
||||||
@ -57,17 +108,68 @@ export class BluetoothConfigDashboard extends LitElement {
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</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>
|
</div>
|
||||||
</hass-subpage>
|
</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() {
|
private async _openOptionFlow() {
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
const configEntryId = this._configEntry;
|
||||||
if (!searchParams.has("config_entry")) {
|
if (!configEntryId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const configEntryId = searchParams.get("config_entry") as string;
|
|
||||||
const configEntries = await getConfigEntries(this.hass, {
|
const configEntries = await getConfigEntries(this.hass, {
|
||||||
domain: "bluetooth",
|
domain: "bluetooth",
|
||||||
});
|
});
|
||||||
@ -92,7 +194,7 @@ export class BluetoothConfigDashboard extends LitElement {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
ha-card:first-child {
|
ha-card {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -5293,8 +5293,13 @@
|
|||||||
"title": "Bluetooth",
|
"title": "Bluetooth",
|
||||||
"settings_title": "Bluetooth settings",
|
"settings_title": "Bluetooth settings",
|
||||||
"option_flow": "Configure Bluetooth options",
|
"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.",
|
"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",
|
"address": "Address",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"source": "Source",
|
"source": "Source",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user