mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Add support for hardware option flows (#14364)
This commit is contained in:
parent
e6b3475b5b
commit
fce87ff0fe
@ -26,7 +26,9 @@ export interface HardwareInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface HardwareInfoEntry {
|
export interface HardwareInfoEntry {
|
||||||
board: HardwareInfoBoardInfo;
|
board: HardwareInfoBoardInfo | null;
|
||||||
|
dongle: HardwareInfoDongleInfo | null;
|
||||||
|
config_entries: string[];
|
||||||
name: string;
|
name: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
}
|
}
|
||||||
@ -38,6 +40,14 @@ export interface HardwareInfoBoardInfo {
|
|||||||
hassio_board_id?: string;
|
hassio_board_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HardwareInfoDongleInfo {
|
||||||
|
manufacturer: string;
|
||||||
|
description: string;
|
||||||
|
pid?: string;
|
||||||
|
vid?: string;
|
||||||
|
serial_number?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SystemStatusStreamMessage {
|
export interface SystemStatusStreamMessage {
|
||||||
cpu_percent: number;
|
cpu_percent: number;
|
||||||
memory_free_mb: number;
|
memory_free_mb: number;
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import { LocalizeFunc } from "../common/translations/localize";
|
import { LocalizeFunc } from "../common/translations/localize";
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
export type IntegrationType = "device" | "helper" | "hub" | "service";
|
export type IntegrationType =
|
||||||
|
| "device"
|
||||||
|
| "helper"
|
||||||
|
| "hub"
|
||||||
|
| "service"
|
||||||
|
| "hardware";
|
||||||
|
|
||||||
export interface IntegrationManifest {
|
export interface IntegrationManifest {
|
||||||
is_built_in: boolean;
|
is_built_in: boolean;
|
||||||
|
@ -2,6 +2,7 @@ import "@material/mwc-list/mwc-list";
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
import type { ChartOptions } from "chart.js";
|
import type { ChartOptions } from "chart.js";
|
||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
@ -16,6 +17,10 @@ import "../../../components/ha-card";
|
|||||||
import "../../../components/ha-clickable-list-item";
|
import "../../../components/ha-clickable-list-item";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
import "../../../components/ha-settings-row";
|
import "../../../components/ha-settings-row";
|
||||||
|
import {
|
||||||
|
ConfigEntry,
|
||||||
|
subscribeConfigEntries,
|
||||||
|
} from "../../../data/config_entries";
|
||||||
import {
|
import {
|
||||||
BOARD_NAMES,
|
BOARD_NAMES,
|
||||||
HardwareInfo,
|
HardwareInfo,
|
||||||
@ -33,6 +38,7 @@ import {
|
|||||||
rebootHost,
|
rebootHost,
|
||||||
shutdownHost,
|
shutdownHost,
|
||||||
} from "../../../data/hassio/host";
|
} from "../../../data/hassio/host";
|
||||||
|
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@ -75,36 +81,76 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _systemStatusData?: SystemStatusStreamMessage;
|
@state() private _systemStatusData?: SystemStatusStreamMessage;
|
||||||
|
|
||||||
|
@state() private _configEntries?: { [id: string]: ConfigEntry };
|
||||||
|
|
||||||
private _memoryEntries: { x: number; y: number | null }[] = [];
|
private _memoryEntries: { x: number; y: number | null }[] = [];
|
||||||
|
|
||||||
private _cpuEntries: { x: number; y: number | null }[] = [];
|
private _cpuEntries: { x: number; y: number | null }[] = [];
|
||||||
|
|
||||||
public hassSubscribe() {
|
public hassSubscribe(): Array<UnsubscribeFunc | Promise<UnsubscribeFunc>> {
|
||||||
return isComponentLoaded(this.hass, "hardware")
|
const subs = [
|
||||||
? [
|
subscribeConfigEntries(
|
||||||
this.hass.connection.subscribeMessage<SystemStatusStreamMessage>(
|
this.hass,
|
||||||
(message) => {
|
(messages) => {
|
||||||
// Only store the last 60 entries
|
let fullUpdate = false;
|
||||||
this._memoryEntries.shift();
|
const newEntries: ConfigEntry[] = [];
|
||||||
this._cpuEntries.shift();
|
messages.forEach((message) => {
|
||||||
|
if (message.type === null || message.type === "added") {
|
||||||
this._memoryEntries.push({
|
newEntries.push(message.entry);
|
||||||
x: new Date(message.timestamp).getTime(),
|
if (message.type === null) {
|
||||||
y: message.memory_used_percent,
|
fullUpdate = true;
|
||||||
});
|
}
|
||||||
this._cpuEntries.push({
|
} else if (message.type === "removed") {
|
||||||
x: new Date(message.timestamp).getTime(),
|
delete this._configEntries![message.entry.entry_id];
|
||||||
y: message.cpu_percent,
|
} else if (message.type === "updated") {
|
||||||
});
|
const newEntry = message.entry;
|
||||||
|
this._configEntries![message.entry.entry_id] = newEntry;
|
||||||
this._systemStatusData = message;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "hardware/subscribe_system_status",
|
|
||||||
}
|
}
|
||||||
),
|
});
|
||||||
]
|
if (!newEntries.length && !fullUpdate) {
|
||||||
: [];
|
return;
|
||||||
|
}
|
||||||
|
const entries = [
|
||||||
|
...(fullUpdate ? [] : Object.values(this._configEntries!)),
|
||||||
|
...newEntries,
|
||||||
|
];
|
||||||
|
const configEntries: { [id: string]: ConfigEntry } = {};
|
||||||
|
for (const entry of entries) {
|
||||||
|
configEntries[entry.entry_id] = entry;
|
||||||
|
}
|
||||||
|
this._configEntries = configEntries;
|
||||||
|
},
|
||||||
|
{ type: ["hardware"] }
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isComponentLoaded(this.hass, "hardware")) {
|
||||||
|
subs.push(
|
||||||
|
this.hass.connection.subscribeMessage<SystemStatusStreamMessage>(
|
||||||
|
(message) => {
|
||||||
|
// Only store the last 60 entries
|
||||||
|
this._memoryEntries.shift();
|
||||||
|
this._cpuEntries.shift();
|
||||||
|
|
||||||
|
this._memoryEntries.push({
|
||||||
|
x: new Date(message.timestamp).getTime(),
|
||||||
|
y: message.memory_used_percent,
|
||||||
|
});
|
||||||
|
this._cpuEntries.push({
|
||||||
|
x: new Date(message.timestamp).getTime(),
|
||||||
|
y: message.cpu_percent,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._systemStatusData = message;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "hardware/subscribe_system_status",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return subs;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected willUpdate(): void {
|
protected willUpdate(): void {
|
||||||
@ -175,19 +221,27 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
let boardName: string | undefined;
|
let boardName: string | undefined;
|
||||||
let imageURL: string | undefined;
|
let imageURL: string | undefined;
|
||||||
let documentationURL: string | undefined;
|
let documentationURL: string | undefined;
|
||||||
|
let boardConfigEntries: ConfigEntry[] = [];
|
||||||
|
|
||||||
const boardData = this._hardwareInfo?.hardware.find(
|
const boardData = this._hardwareInfo?.hardware.find(
|
||||||
(hw) => hw.board !== null
|
(hw) => hw.board !== null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const dongles = this._hardwareInfo?.hardware.filter(
|
||||||
|
(hw) => hw.dongle !== null
|
||||||
|
);
|
||||||
|
|
||||||
if (boardData) {
|
if (boardData) {
|
||||||
boardId = boardData.board.hassio_board_id;
|
boardConfigEntries = boardData.config_entries
|
||||||
|
.map((id) => this._configEntries?.[id])
|
||||||
|
.filter((entry) => entry?.supports_options) as ConfigEntry[];
|
||||||
|
boardId = boardData.board!.hassio_board_id;
|
||||||
boardName = boardData.name;
|
boardName = boardData.name;
|
||||||
documentationURL = boardData.url;
|
documentationURL = boardData.url;
|
||||||
imageURL = hardwareBrandsUrl({
|
imageURL = hardwareBrandsUrl({
|
||||||
category: "boards",
|
category: "boards",
|
||||||
manufacturer: boardData.board.manufacturer,
|
manufacturer: boardData.board!.manufacturer,
|
||||||
model: boardData.board.model,
|
model: boardData.board!.model,
|
||||||
darkOptimized: this.hass.themes?.darkMode,
|
darkOptimized: this.hass.themes?.darkMode,
|
||||||
});
|
});
|
||||||
} else if (this._OSData?.board) {
|
} else if (this._OSData?.board) {
|
||||||
@ -243,7 +297,7 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
<ha-card outlined>
|
<ha-card outlined>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<mwc-list>
|
<mwc-list>
|
||||||
<mwc-list-item
|
<ha-list-item
|
||||||
noninteractive
|
noninteractive
|
||||||
graphic=${ifDefined(imageURL ? "medium" : undefined)}
|
graphic=${ifDefined(imageURL ? "medium" : undefined)}
|
||||||
.twoline=${Boolean(boardId)}
|
.twoline=${Boolean(boardId)}
|
||||||
@ -262,7 +316,7 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
>
|
>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</mwc-list-item>
|
</ha-list-item>
|
||||||
${documentationURL
|
${documentationURL
|
||||||
? html`
|
? html`
|
||||||
<ha-clickable-list-item
|
<ha-clickable-list-item
|
||||||
@ -287,9 +341,42 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
: ""}
|
: ""}
|
||||||
</mwc-list>
|
</mwc-list>
|
||||||
</div>
|
</div>
|
||||||
|
${boardConfigEntries.length
|
||||||
|
? html`<div class="card-actions">
|
||||||
|
<mwc-button
|
||||||
|
.entry=${boardConfigEntries[0]}
|
||||||
|
@click=${this._openOptionsFlow}
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.hardware.configure"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
${dongles?.length
|
||||||
|
? html`<ha-card>
|
||||||
|
${dongles.map((dongle) => {
|
||||||
|
const configEntry = dongle.config_entries
|
||||||
|
.map((id) => this._configEntries?.[id])
|
||||||
|
.filter((entry) => entry?.supports_options)[0];
|
||||||
|
return html`<div class="row">
|
||||||
|
${dongle.name}${configEntry
|
||||||
|
? html`<mwc-button
|
||||||
|
.entry=${configEntry}
|
||||||
|
@click=${this._openOptionsFlow}
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.hardware.configure"
|
||||||
|
)}
|
||||||
|
</mwc-button>`
|
||||||
|
: ""}
|
||||||
|
</div>`;
|
||||||
|
})}
|
||||||
|
</ha-card>`
|
||||||
|
: ""}
|
||||||
${this._systemStatusData
|
${this._systemStatusData
|
||||||
? html`<ha-card outlined>
|
? html`<ha-card outlined>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@ -372,6 +459,14 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _openOptionsFlow(ev) {
|
||||||
|
const entry = ev.currentTarget.entry;
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showOptionsFlowDialog(this, entry);
|
||||||
|
}
|
||||||
|
|
||||||
private async _openHardware() {
|
private async _openHardware() {
|
||||||
showhardwareAvailableDialog(this);
|
showhardwareAvailableDialog(this);
|
||||||
}
|
}
|
||||||
@ -493,6 +588,13 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
.header .value {
|
.header .value {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 48px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1710,6 +1710,7 @@
|
|||||||
"failed_to_shutdown_host": "Failed to shutdown system",
|
"failed_to_shutdown_host": "Failed to shutdown system",
|
||||||
"board": "Board",
|
"board": "Board",
|
||||||
"documentation": "Documentation",
|
"documentation": "Documentation",
|
||||||
|
"configure": "Configure",
|
||||||
"documentation_description": "Find extra information about your device"
|
"documentation_description": "Find extra information about your device"
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user