mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Add initial SSDP discovery panel (#25217)
* Add initial SSDP discovery panel
This commit is contained in:
parent
ab415188ba
commit
bc582db7fc
@ -9,6 +9,7 @@ export const integrationsWithPanel = {
|
||||
dhcp: "config/dhcp",
|
||||
matter: "config/matter",
|
||||
mqtt: "config/mqtt",
|
||||
ssdp: "config/ssdp",
|
||||
thread: "config/thread",
|
||||
zeroconf: "config/zeroconf",
|
||||
zha: "config/zha/dashboard",
|
||||
|
98
src/data/ssdp.ts
Normal file
98
src/data/ssdp.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import {
|
||||
createCollection,
|
||||
type Connection,
|
||||
type UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket";
|
||||
import type { Store } from "home-assistant-js-websocket/dist/store";
|
||||
import type { DataTableRowData } from "../components/data-table/ha-data-table";
|
||||
|
||||
export interface SSDPDiscoveryData extends DataTableRowData {
|
||||
ssdp_usn: string;
|
||||
ssdp_st: string;
|
||||
upnp: Record<string, unknown>;
|
||||
ssdp_location: string | undefined;
|
||||
ssdp_nt: string | undefined;
|
||||
ssdp_udn: string | undefined;
|
||||
ssdp_ext: string | undefined;
|
||||
ssdp_server: string | undefined;
|
||||
ssdp_headers: Record<string, unknown>;
|
||||
ssdp_all_locations: string[];
|
||||
x_homeassistant_matching_domains: string[];
|
||||
}
|
||||
|
||||
interface SSDPRemoveDiscoveryData {
|
||||
ssdp_st: string;
|
||||
ssdp_location: string | undefined;
|
||||
}
|
||||
|
||||
interface SSDPSubscriptionMessage {
|
||||
add?: SSDPDiscoveryData[];
|
||||
change?: SSDPDiscoveryData[];
|
||||
remove?: SSDPRemoveDiscoveryData[];
|
||||
}
|
||||
|
||||
const subscribeSSDPDiscoveryUpdates = (
|
||||
conn: Connection,
|
||||
store: Store<SSDPDiscoveryData[]>
|
||||
): Promise<UnsubscribeFunc> =>
|
||||
conn.subscribeMessage<SSDPSubscriptionMessage>(
|
||||
(event) => {
|
||||
const data = [...(store.state || [])];
|
||||
if (event.add) {
|
||||
for (const deviceData of event.add) {
|
||||
const index = data.findIndex(
|
||||
(d) =>
|
||||
d.ssdp_st === deviceData.ssdp_st &&
|
||||
d.ssdp_location === deviceData.ssdp_location
|
||||
);
|
||||
if (index === -1) {
|
||||
data.push(deviceData);
|
||||
} else {
|
||||
data[index] = deviceData;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.change) {
|
||||
for (const deviceData of event.change) {
|
||||
const index = data.findIndex(
|
||||
(d) =>
|
||||
d.ssdp_st === deviceData.ssdp_st &&
|
||||
d.ssdp_location === deviceData.ssdp_location
|
||||
);
|
||||
if (index !== -1) {
|
||||
data[index] = deviceData;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.remove) {
|
||||
for (const deviceData of event.remove) {
|
||||
const index = data.findIndex(
|
||||
(d) =>
|
||||
d.ssdp_st === deviceData.ssdp_st &&
|
||||
d.ssdp_location === deviceData.ssdp_location
|
||||
);
|
||||
if (index !== -1) {
|
||||
data.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.setState(data, true);
|
||||
},
|
||||
{
|
||||
type: `ssdp/subscribe_discovery`,
|
||||
}
|
||||
);
|
||||
|
||||
export const subscribeSSDPDiscovery = (
|
||||
conn: Connection,
|
||||
callbackFunction: (ssdpDiscoveryData: SSDPDiscoveryData[]) => void
|
||||
) =>
|
||||
createCollection<SSDPDiscoveryData[]>(
|
||||
"_ssdpDiscoveryRows",
|
||||
() => Promise.resolve<SSDPDiscoveryData[]>([]), // empty array as initial state
|
||||
|
||||
subscribeSSDPDiscoveryUpdates,
|
||||
conn,
|
||||
callbackFunction
|
||||
);
|
@ -560,6 +560,11 @@ class HaPanelConfig extends SubscribeMixin(HassRouterPage) {
|
||||
load: () =>
|
||||
import("./integrations/integration-panels/dhcp/dhcp-config-panel"),
|
||||
},
|
||||
ssdp: {
|
||||
tag: "ssdp-config-panel",
|
||||
load: () =>
|
||||
import("./integrations/integration-panels/ssdp/ssdp-config-panel"),
|
||||
},
|
||||
zeroconf: {
|
||||
tag: "zeroconf-config-panel",
|
||||
load: () =>
|
||||
|
@ -0,0 +1,103 @@
|
||||
import type { TemplateResult } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import type { HassDialog } from "../../../../../dialogs/make-dialog-manager";
|
||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import type { SSDPDiscoveryInfoDialogParams } from "./show-dialog-ssdp-discovery-info";
|
||||
import "../../../../../components/ha-button";
|
||||
import { showToast } from "../../../../../util/toast";
|
||||
import { copyToClipboard } from "../../../../../common/util/copy-clipboard";
|
||||
|
||||
@customElement("dialog-ssdp-device-info")
|
||||
class DialogSSDPDiscoveryInfo extends LitElement implements HassDialog {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _params?: SSDPDiscoveryInfoDialogParams;
|
||||
|
||||
public async showDialog(
|
||||
params: SSDPDiscoveryInfoDialogParams
|
||||
): Promise<void> {
|
||||
this._params = params;
|
||||
}
|
||||
|
||||
public closeDialog(): boolean {
|
||||
this._params = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _copyToClipboard(): Promise<void> {
|
||||
if (!this._params) {
|
||||
return;
|
||||
}
|
||||
|
||||
await copyToClipboard(JSON.stringify(this._params!.entry));
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.common.copied_clipboard"),
|
||||
});
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (!this._params) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
@closed=${this.closeDialog}
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass.localize("ui.panel.config.ssdp.discovery_information")
|
||||
)}
|
||||
>
|
||||
<p>
|
||||
<b>${this.hass.localize("ui.panel.config.ssdp.ssdp_st")}</b>:
|
||||
${this._params.entry.ssdp_st} <br />
|
||||
<b>${this.hass.localize("ui.panel.config.ssdp.ssdp_location")}</b>:
|
||||
${this._params.entry.ssdp_location}
|
||||
</p>
|
||||
|
||||
<h4>${this.hass.localize("ui.panel.config.ssdp.ssdp_headers")}</h4>
|
||||
<table width="100%">
|
||||
<tbody>
|
||||
${Object.entries(this._params.entry.ssdp_headers).map(
|
||||
([key, value]) => html`
|
||||
<tr>
|
||||
<td><b>${key}</b></td>
|
||||
<td>${value}</td>
|
||||
</tr>
|
||||
`
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>${this.hass.localize("ui.panel.config.ssdp.upnp")}</h4>
|
||||
<table width="100%">
|
||||
<tbody>
|
||||
${Object.entries(this._params.entry.upnp).map(
|
||||
([key, value]) => html`
|
||||
<tr>
|
||||
<td><b>${key}</b></td>
|
||||
<td>${value}</td>
|
||||
</tr>
|
||||
`
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<ha-button slot="secondaryAction" @click=${this._copyToClipboard}>
|
||||
${this.hass.localize("ui.panel.config.ssdp.copy_to_clipboard")}
|
||||
</ha-button>
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-ssdp-device-info": DialogSSDPDiscoveryInfo;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import type { SSDPDiscoveryData } from "../../../../../data/ssdp";
|
||||
|
||||
export interface SSDPDiscoveryInfoDialogParams {
|
||||
entry: SSDPDiscoveryData;
|
||||
}
|
||||
|
||||
export const loadSSDPDiscoveryInfoDialog = () =>
|
||||
import("./dialog-ssdp-discovery-info");
|
||||
|
||||
export const showSSDPDiscoveryInfoDialog = (
|
||||
element: HTMLElement,
|
||||
ssdpDiscoveryInfoDialogParams: SSDPDiscoveryInfoDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-ssdp-device-info",
|
||||
dialogImport: loadSSDPDiscoveryInfoDialog,
|
||||
dialogParams: ssdpDiscoveryInfoDialogParams,
|
||||
});
|
||||
};
|
@ -0,0 +1,133 @@
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { LocalizeFunc } from "../../../../../common/translations/localize";
|
||||
import type {
|
||||
RowClickedEvent,
|
||||
DataTableColumnContainer,
|
||||
} from "../../../../../components/data-table/ha-data-table";
|
||||
import "../../../../../components/ha-fab";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "../../../../../layouts/hass-tabs-subpage-data-table";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import type { SSDPDiscoveryData } from "../../../../../data/ssdp";
|
||||
import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin";
|
||||
import { storage } from "../../../../../common/decorators/storage";
|
||||
import type { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
||||
import { subscribeSSDPDiscovery } from "../../../../../data/ssdp";
|
||||
import { showSSDPDiscoveryInfoDialog } from "./show-dialog-ssdp-discovery-info";
|
||||
|
||||
@customElement("ssdp-config-panel")
|
||||
export class SSDPConfigPanel extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
|
||||
|
||||
@state() private _data: SSDPDiscoveryData[] = [];
|
||||
|
||||
@storage({
|
||||
key: "ssdp-discovery-table-grouping",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeGrouping?: string = "ssdp_location";
|
||||
|
||||
@storage({
|
||||
key: "ssdp-discovery-table-collapsed",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeCollapsed: string[] = [];
|
||||
|
||||
public hassSubscribe(): UnsubscribeFunc[] {
|
||||
return [
|
||||
subscribeSSDPDiscovery(this.hass.connection, (data) => {
|
||||
this._data = data;
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(localize: LocalizeFunc): DataTableColumnContainer => {
|
||||
const columns: DataTableColumnContainer<SSDPDiscoveryData> = {
|
||||
ssdp_st: {
|
||||
title: localize("ui.panel.config.ssdp.ssdp_st"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
showNarrow: true,
|
||||
main: true,
|
||||
hideable: false,
|
||||
moveable: false,
|
||||
direction: "asc",
|
||||
},
|
||||
ssdp_location: {
|
||||
title: localize("ui.panel.config.ssdp.ssdp_location"),
|
||||
filterable: true,
|
||||
sortable: true,
|
||||
groupable: true,
|
||||
},
|
||||
};
|
||||
|
||||
return columns;
|
||||
}
|
||||
);
|
||||
|
||||
private _dataWithIds = memoizeOne((data) =>
|
||||
data.map((row) => ({
|
||||
...row,
|
||||
id: [row.ssdp_st, row.ssdp_location].filter(Boolean).join("|"),
|
||||
}))
|
||||
);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-tabs-subpage-data-table
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.columns=${this._columns(this.hass.localize)}
|
||||
.initialGroupColumn=${this._activeGrouping}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
@grouping-changed=${this._handleGroupingChanged}
|
||||
@collapsed-changed=${this._handleCollapseChanged}
|
||||
.data=${this._dataWithIds(this._data)}
|
||||
@row-click=${this._handleRowClicked}
|
||||
clickable
|
||||
></hass-tabs-subpage-data-table>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
||||
const entry = this._data.find(
|
||||
(ent) =>
|
||||
[ent.ssdp_st, ent.ssdp_location].filter(Boolean).join("|") ===
|
||||
ev.detail.id
|
||||
);
|
||||
showSSDPDiscoveryInfoDialog(this, {
|
||||
entry: entry!,
|
||||
});
|
||||
}
|
||||
|
||||
private _handleGroupingChanged(ev: CustomEvent) {
|
||||
this._activeGrouping = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleCollapseChanged(ev: CustomEvent) {
|
||||
this._activeCollapsed = ev.detail.value;
|
||||
}
|
||||
|
||||
static styles: CSSResultGroup = haStyle;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ssdp-config-panel": SSDPConfigPanel;
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-card";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("ha-config-network-discovery")
|
||||
class ConfigNetworkDiscovery extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
protected render() {
|
||||
return isComponentLoaded(this.hass, "zeroconf")
|
||||
? html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.zeroconf"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.zeroconf_info"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<a
|
||||
href="/config/zeroconf"
|
||||
aria-label=${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.zeroconf_browser"
|
||||
)}
|
||||
>
|
||||
<ha-button>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.zeroconf_browser"
|
||||
)}
|
||||
</ha-button>
|
||||
</a>
|
||||
</div>
|
||||
</ha-card>
|
||||
`
|
||||
: "";
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
ha-settings-row {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
`, // row-reverse so we tab first to "save"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-config-network-discovery": ConfigNetworkDiscovery;
|
||||
}
|
||||
}
|
66
src/panels/config/network/ha-config-network-ssdp.ts
Normal file
66
src/panels/config/network/ha-config-network-ssdp.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-card";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("ha-config-network-ssdp")
|
||||
class ConfigNetworkSSDP extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize("ui.panel.config.network.discovery.ssdp")}
|
||||
>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize("ui.panel.config.network.discovery.ssdp_info")}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<a
|
||||
href="/config/ssdp"
|
||||
aria-label=${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.ssdp_browser"
|
||||
)}
|
||||
>
|
||||
<ha-button>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.ssdp_browser"
|
||||
)}
|
||||
</ha-button>
|
||||
</a>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
ha-settings-row {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
`, // row-reverse so we tab first to "save"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-config-network-ssdp": ConfigNetworkSSDP;
|
||||
}
|
||||
}
|
70
src/panels/config/network/ha-config-network-zeroconf.ts
Normal file
70
src/panels/config/network/ha-config-network-zeroconf.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-card";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("ha-config-network-zeroconf")
|
||||
class ConfigNetworkZeroconf extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.zeroconf"
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.zeroconf_info"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<a
|
||||
href="/config/zeroconf"
|
||||
aria-label=${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.zeroconf_browser"
|
||||
)}
|
||||
>
|
||||
<ha-button>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.network.discovery.zeroconf_browser"
|
||||
)}
|
||||
</ha-button>
|
||||
</a>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
ha-settings-row {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
`, // row-reverse so we tab first to "save"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-config-network-zeroconf": ConfigNetworkZeroconf;
|
||||
}
|
||||
}
|
@ -5,7 +5,8 @@ import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import "./ha-config-network";
|
||||
import "./ha-config-network-discovery";
|
||||
import "./ha-config-network-ssdp";
|
||||
import "./ha-config-network-zeroconf";
|
||||
import "./ha-config-url-form";
|
||||
import "./supervisor-hostname";
|
||||
import "./supervisor-network";
|
||||
@ -36,10 +37,15 @@ class HaConfigSectionNetwork extends LitElement {
|
||||
: ""}
|
||||
<ha-config-url-form .hass=${this.hass}></ha-config-url-form>
|
||||
<ha-config-network .hass=${this.hass}></ha-config-network>
|
||||
${isComponentLoaded(this.hass, "zeroconf")
|
||||
? html`<ha-config-network-discovery
|
||||
${isComponentLoaded(this.hass, "ssdp")
|
||||
? html`<ha-config-network-ssdp
|
||||
.hass=${this.hass}
|
||||
></ha-config-network-discovery>`
|
||||
></ha-config-network-ssdp>`
|
||||
: ""}
|
||||
${isComponentLoaded(this.hass, "zeroconf")
|
||||
? html`<ha-config-network-zeroconf
|
||||
.hass=${this.hass}
|
||||
></ha-config-network-zeroconf>`
|
||||
: ""}
|
||||
</div>
|
||||
</hass-subpage>
|
||||
@ -56,7 +62,8 @@ class HaConfigSectionNetwork extends LitElement {
|
||||
supervisor-network,
|
||||
ha-config-url-form,
|
||||
ha-config-network,
|
||||
ha-config-network-discovery {
|
||||
ha-config-network-ssdp,
|
||||
ha-config-network-zeroconf {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 24px;
|
||||
|
@ -118,6 +118,10 @@ export const getMyRedirects = (): Redirects => ({
|
||||
component: "energy",
|
||||
redirect: "/config/energy/dashboard",
|
||||
},
|
||||
config_ssdp: {
|
||||
component: "ssdp",
|
||||
redirect: "/config/ssdp",
|
||||
},
|
||||
config_zeroconf: {
|
||||
component: "zeroconf",
|
||||
redirect: "/config/zeroconf",
|
||||
|
@ -5567,6 +5567,14 @@
|
||||
"thread_network_info": "Thread network information",
|
||||
"thread_network_delete_credentials": "Delete Thread network credentials"
|
||||
},
|
||||
"ssdp": {
|
||||
"ssdp_st": "Search Target (ST)",
|
||||
"ssdp_location": "Device Description URL",
|
||||
"ssdp_headers": "SSDP Headers",
|
||||
"upnp": "Universal Plug and Play (UPnP)",
|
||||
"discovery_information": "Discovery information",
|
||||
"copy_to_clipboard": "Copy to clipboard"
|
||||
},
|
||||
"zeroconf": {
|
||||
"name": "Name",
|
||||
"type": "Type",
|
||||
@ -6382,6 +6390,9 @@
|
||||
}
|
||||
},
|
||||
"discovery": {
|
||||
"ssdp": "SSDP browser",
|
||||
"ssdp_info": "The SSDP browser shows devices discovered by Home Assistant using SSDP/UPnP. Devices that Home Assistant has discovered will appear here.",
|
||||
"ssdp_browser": "View SSDP browser",
|
||||
"zeroconf": "Zeroconf browser",
|
||||
"zeroconf_info": "The Zeroconf browser shows devices discovered by Home Assistant using mDNS. Only devices that Home Assistant is actively searching for will appear here.",
|
||||
"zeroconf_browser": "View Zeroconf browser"
|
||||
|
Loading…
x
Reference in New Issue
Block a user