mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-27 14:57:20 +00:00
Hardware MVP (#12773)
This commit is contained in:
parent
b35ba4d673
commit
c4624faa71
@ -20,3 +20,20 @@ export const BOARD_NAMES: Record<string, string> = {
|
|||||||
"intel-nuc": "Intel NUC",
|
"intel-nuc": "Intel NUC",
|
||||||
yellow: "Home Assistant Yellow",
|
yellow: "Home Assistant Yellow",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface HardwareInfo {
|
||||||
|
hardware: HardwareInfoEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HardwareInfoEntry {
|
||||||
|
board: HardwareInfoBoardInfo;
|
||||||
|
name: string;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HardwareInfoBoardInfo {
|
||||||
|
manufacturer: string;
|
||||||
|
model?: string;
|
||||||
|
revision?: string;
|
||||||
|
hassio_board_id?: string;
|
||||||
|
}
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
|
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 { 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 { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import "../../../components/buttons/ha-progress-button";
|
import "../../../components/buttons/ha-progress-button";
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-clickable-list-item";
|
||||||
|
import "../../../components/ha-icon-next";
|
||||||
import "../../../components/ha-settings-row";
|
import "../../../components/ha-settings-row";
|
||||||
import { BOARD_NAMES } from "../../../data/hardware";
|
import { BOARD_NAMES, HardwareInfo } from "../../../data/hardware";
|
||||||
import {
|
import {
|
||||||
extractApiErrorMessage,
|
extractApiErrorMessage,
|
||||||
ignoreSupervisorError,
|
ignoreSupervisorError,
|
||||||
@ -28,6 +32,8 @@ import {
|
|||||||
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 { hardwareBrandsUrl } from "../../../util/brands-url";
|
||||||
|
import { showToast } from "../../../util/toast";
|
||||||
import { showhardwareAvailableDialog } from "./show-dialog-hardware-available";
|
import { showhardwareAvailableDialog } from "./show-dialog-hardware-available";
|
||||||
|
|
||||||
@customElement("ha-config-hardware")
|
@customElement("ha-config-hardware")
|
||||||
@ -42,14 +48,36 @@ class HaConfigHardware extends LitElement {
|
|||||||
|
|
||||||
@state() private _hostData?: HassioHostInfo;
|
@state() private _hostData?: HassioHostInfo;
|
||||||
|
|
||||||
|
@state() private _hardwareInfo?: HardwareInfo;
|
||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
if (isComponentLoaded(this.hass, "hassio")) {
|
|
||||||
this._load();
|
this._load();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
let boardId: string | undefined;
|
||||||
|
let boardName: string | undefined;
|
||||||
|
let imageURL: string | undefined;
|
||||||
|
let documentationURL: string | undefined;
|
||||||
|
|
||||||
|
if (this._hardwareInfo?.hardware.length) {
|
||||||
|
const boardData = this._hardwareInfo!.hardware[0];
|
||||||
|
|
||||||
|
boardId = boardData.board.hassio_board_id;
|
||||||
|
boardName = boardData.name;
|
||||||
|
documentationURL = boardData.url;
|
||||||
|
imageURL = hardwareBrandsUrl({
|
||||||
|
category: "boards",
|
||||||
|
manufacturer: boardData.board.manufacturer,
|
||||||
|
model: boardData.board.model,
|
||||||
|
darkOptimized: this.hass.themes?.darkMode,
|
||||||
|
});
|
||||||
|
} else if (this._OSData?.board) {
|
||||||
|
boardId = this._OSData.board;
|
||||||
|
boardName = BOARD_NAMES[this._OSData.board];
|
||||||
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage
|
<hass-subpage
|
||||||
back-path="/config/system"
|
back-path="/config/system"
|
||||||
@ -68,6 +96,20 @@ class HaConfigHardware extends LitElement {
|
|||||||
"ui.panel.config.hardware.available_hardware.title"
|
"ui.panel.config.hardware.available_hardware.title"
|
||||||
)}</mwc-list-item
|
)}</mwc-list-item
|
||||||
>
|
>
|
||||||
|
${this._hostData
|
||||||
|
? html`
|
||||||
|
<mwc-list-item class="warning" @click=${this._hostReboot}
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.hardware.reboot_host"
|
||||||
|
)}</mwc-list-item
|
||||||
|
>
|
||||||
|
<mwc-list-item class="warning" @click=${this._hostShutdown}
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.hardware.shutdown_host"
|
||||||
|
)}</mwc-list-item
|
||||||
|
>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
${this._error
|
${this._error
|
||||||
? html`
|
? html`
|
||||||
@ -76,57 +118,55 @@ class HaConfigHardware extends LitElement {
|
|||||||
>
|
>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this._OSData || this._hostData
|
${boardName
|
||||||
? html`
|
? html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-card outlined>
|
<ha-card outlined>
|
||||||
${this._OSData?.board
|
|
||||||
? html`
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<ha-settings-row>
|
<mwc-list>
|
||||||
<span slot="heading"
|
<mwc-list-item
|
||||||
>${BOARD_NAMES[this._OSData.board] ||
|
graphic=${ifDefined(imageURL ? "medium" : undefined)}
|
||||||
this.hass.localize(
|
.twoline=${Boolean(boardId)}
|
||||||
"ui.panel.config.hardware.board"
|
>
|
||||||
|
${imageURL
|
||||||
|
? html`<img slot="graphic" src=${imageURL} />`
|
||||||
|
: ""}
|
||||||
|
<span class="primary-text">
|
||||||
|
${boardName ||
|
||||||
|
this.hass.localize("ui.panel.config.hardware.board")}
|
||||||
|
</span>
|
||||||
|
${boardId
|
||||||
|
? html`
|
||||||
|
<span class="secondary-text" slot="secondary"
|
||||||
|
>${boardId}</span
|
||||||
|
>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</mwc-list-item>
|
||||||
|
${documentationURL
|
||||||
|
? html`
|
||||||
|
<ha-clickable-list-item
|
||||||
|
.href=${documentationURL}
|
||||||
|
openNewTab
|
||||||
|
twoline
|
||||||
|
hasMeta
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.hardware.documentation"
|
||||||
)}</span
|
)}</span
|
||||||
>
|
>
|
||||||
<div slot="description">
|
<span slot="secondary"
|
||||||
<span class="value">${this._OSData.board}</span>
|
>${this.hass.localize(
|
||||||
</div>
|
"ui.panel.config.hardware.documentation_description"
|
||||||
</ha-settings-row>
|
)}</span
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._hostData
|
|
||||||
? html`
|
|
||||||
<div class="card-actions">
|
|
||||||
${this._hostData.features.includes("reboot")
|
|
||||||
? html`
|
|
||||||
<ha-progress-button
|
|
||||||
class="warning"
|
|
||||||
@click=${this._hostReboot}
|
|
||||||
>
|
>
|
||||||
${this.hass.localize(
|
<ha-icon-next slot="meta"></ha-icon-next>
|
||||||
"ui.panel.config.hardware.reboot_host"
|
</ha-clickable-list-item>
|
||||||
)}
|
|
||||||
</ha-progress-button>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._hostData.features.includes("shutdown")
|
|
||||||
? html`
|
|
||||||
<ha-progress-button
|
|
||||||
class="warning"
|
|
||||||
@click=${this._hostShutdown}
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.hardware.shutdown_host"
|
|
||||||
)}
|
|
||||||
</ha-progress-button>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
</mwc-list>
|
||||||
</div>
|
</div>
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@ -136,9 +176,17 @@ class HaConfigHardware extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _load() {
|
private async _load() {
|
||||||
|
const isHassioLoaded = isComponentLoaded(this.hass, "hassio");
|
||||||
try {
|
try {
|
||||||
|
if (isComponentLoaded(this.hass, "hardware")) {
|
||||||
|
this._hardwareInfo = await this.hass.callWS({ type: "hardware/info" });
|
||||||
|
} else if (isHassioLoaded) {
|
||||||
this._OSData = await fetchHassioHassOsInfo(this.hass);
|
this._OSData = await fetchHassioHassOsInfo(this.hass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHassioLoaded) {
|
||||||
this._hostData = await fetchHassioHostInfo(this.hass);
|
this._hostData = await fetchHassioHostInfo(this.hass);
|
||||||
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = err.message || err;
|
this._error = err.message || err;
|
||||||
}
|
}
|
||||||
@ -148,10 +196,7 @@ class HaConfigHardware extends LitElement {
|
|||||||
showhardwareAvailableDialog(this);
|
showhardwareAvailableDialog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _hostReboot(ev: CustomEvent): Promise<void> {
|
private async _hostReboot(): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
title: this.hass.localize("ui.panel.config.hardware.reboot_host"),
|
title: this.hass.localize("ui.panel.config.hardware.reboot_host"),
|
||||||
text: this.hass.localize("ui.panel.config.hardware.reboot_host_confirm"),
|
text: this.hass.localize("ui.panel.config.hardware.reboot_host_confirm"),
|
||||||
@ -160,10 +205,14 @@ class HaConfigHardware extends LitElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
button.progress = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showToast(this, {
|
||||||
|
message: this.hass.localize("ui.panel.config.hardware.rebooting_host"),
|
||||||
|
duration: 0,
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await rebootHost(this.hass);
|
await rebootHost(this.hass);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@ -177,13 +226,9 @@ class HaConfigHardware extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.progress = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _hostShutdown(ev: CustomEvent): Promise<void> {
|
private async _hostShutdown(): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
title: this.hass.localize("ui.panel.config.hardware.shutdown_host"),
|
title: this.hass.localize("ui.panel.config.hardware.shutdown_host"),
|
||||||
text: this.hass.localize(
|
text: this.hass.localize(
|
||||||
@ -194,10 +239,16 @@ class HaConfigHardware extends LitElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
button.progress = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showToast(this, {
|
||||||
|
message: this.hass.localize(
|
||||||
|
"ui.panel.config.hardware.host_shutting_down"
|
||||||
|
),
|
||||||
|
duration: 0,
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await shutdownHost(this.hass);
|
await shutdownHost(this.hass);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@ -211,7 +262,6 @@ class HaConfigHardware extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.progress = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = [
|
static styles = [
|
||||||
@ -234,17 +284,18 @@ class HaConfigHardware extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 16px 16px 0 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
ha-button-menu {
|
ha-button-menu {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
--mdc-menu-min-width: 200px;
|
--mdc-menu-min-width: 200px;
|
||||||
}
|
}
|
||||||
.card-actions {
|
|
||||||
height: 48px;
|
.primary-text {
|
||||||
display: flex;
|
font-size: 16px;
|
||||||
justify-content: space-between;
|
}
|
||||||
align-items: center;
|
.secondary-text {
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -1569,12 +1569,16 @@
|
|||||||
"attributes": "Attributes"
|
"attributes": "Attributes"
|
||||||
},
|
},
|
||||||
"reboot_host": "Reboot host",
|
"reboot_host": "Reboot host",
|
||||||
|
"rebooting_host": "Rebooting host",
|
||||||
"reboot_host_confirm": "Are you sure you want to reboot your host?",
|
"reboot_host_confirm": "Are you sure you want to reboot your host?",
|
||||||
"failed_to_reboot_host": "Failed to reboot host",
|
"failed_to_reboot_host": "Failed to reboot host",
|
||||||
"shutdown_host": "Shutdown host",
|
"shutdown_host": "Shutdown host",
|
||||||
|
"host_shutting_down": "Host shutting down",
|
||||||
"shutdown_host_confirm": "Are you sure you want to shutdown your host?",
|
"shutdown_host_confirm": "Are you sure you want to shutdown your host?",
|
||||||
"failed_to_shutdown_host": "Failed to shutdown host",
|
"failed_to_shutdown_host": "Failed to shutdown host",
|
||||||
"board": "Board"
|
"board": "Board",
|
||||||
|
"documentation": "Documentation",
|
||||||
|
"documentation_description": "Find extra information about your device"
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
"caption": "About",
|
"caption": "About",
|
||||||
|
@ -5,9 +5,21 @@ export interface BrandsOptions {
|
|||||||
darkOptimized?: boolean;
|
darkOptimized?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HardwareBrandsOptions {
|
||||||
|
category: string;
|
||||||
|
model?: string;
|
||||||
|
manufacturer: string;
|
||||||
|
darkOptimized?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export const brandsUrl = (options: BrandsOptions): string =>
|
export const brandsUrl = (options: BrandsOptions): string =>
|
||||||
`https://brands.home-assistant.io/${options.useFallback ? "_/" : ""}${
|
`https://brands.home-assistant.io/${options.useFallback ? "_/" : ""}${
|
||||||
options.domain
|
options.domain
|
||||||
}/${options.darkOptimized ? "dark_" : ""}${options.type}.png`;
|
}/${options.darkOptimized ? "dark_" : ""}${options.type}.png`;
|
||||||
|
|
||||||
|
export const hardwareBrandsUrl = (options: HardwareBrandsOptions): string =>
|
||||||
|
`https://brands.home-assistant.io/hardware/${options.category}/${
|
||||||
|
options.darkOptimized ? "dark_" : ""
|
||||||
|
}${options.manufacturer}${options.model ? `_${options.model}` : ""}.png`;
|
||||||
|
|
||||||
export const extractDomainFromBrandUrl = (url: string) => url.split("/")[4];
|
export const extractDomainFromBrandUrl = (url: string) => url.split("/")[4];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user