mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-22 00:36:34 +00:00
Add network configuration (#9210)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
a66b966e7d
commit
b0e1f0f73a
172
src/components/ha-network.ts
Normal file
172
src/components/ha-network.ts
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, state, property } from "lit/decorators";
|
||||||
|
import {
|
||||||
|
Adapter,
|
||||||
|
NetworkConfig,
|
||||||
|
IPv6ConfiguredAddress,
|
||||||
|
IPv4ConfiguredAddress,
|
||||||
|
} from "../data/network";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { haStyle } from "../resources/styles";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
import "./ha-checkbox";
|
||||||
|
import type { HaCheckbox } from "./ha-checkbox";
|
||||||
|
import "./ha-settings-row";
|
||||||
|
import "./ha-icon";
|
||||||
|
|
||||||
|
const format_addresses = (
|
||||||
|
addresses: IPv6ConfiguredAddress[] | IPv4ConfiguredAddress[]
|
||||||
|
): TemplateResult[] =>
|
||||||
|
addresses.map(
|
||||||
|
(address) => html`<span>${address.address}/${address.network_prefix}</span>`
|
||||||
|
);
|
||||||
|
|
||||||
|
const format_auto_detected_interfaces = (
|
||||||
|
adapters: Adapter[]
|
||||||
|
): Array<TemplateResult | string> =>
|
||||||
|
adapters.map((adapter) =>
|
||||||
|
adapter.auto
|
||||||
|
? html`${adapter.name} (${format_addresses(adapter.ipv4)}
|
||||||
|
${format_addresses(adapter.ipv6)} )`
|
||||||
|
: ""
|
||||||
|
);
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"network-config-changed": { configured_adapters: string[] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@customElement("ha-network")
|
||||||
|
export class HaNetwork extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public networkConfig?: NetworkConfig;
|
||||||
|
|
||||||
|
@state() private _expanded?: boolean;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (this.networkConfig === undefined) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
const configured_adapters = this.networkConfig.configured_adapters || [];
|
||||||
|
return html`
|
||||||
|
<ha-settings-row>
|
||||||
|
<span slot="prefix">
|
||||||
|
<ha-checkbox
|
||||||
|
id="auto_configure"
|
||||||
|
@change=${this._handleAutoConfigureCheckboxClick}
|
||||||
|
.checked=${!configured_adapters.length}
|
||||||
|
name="auto_configure"
|
||||||
|
>
|
||||||
|
</ha-checkbox>
|
||||||
|
</span>
|
||||||
|
<span slot="heading" data-for="auto_configure"> Auto Configure </span>
|
||||||
|
<span slot="description" data-for="auto_configure">
|
||||||
|
Detected:
|
||||||
|
${format_auto_detected_interfaces(this.networkConfig.adapters)}
|
||||||
|
</span>
|
||||||
|
</ha-settings-row>
|
||||||
|
${configured_adapters.length || this._expanded
|
||||||
|
? this.networkConfig.adapters.map(
|
||||||
|
(adapter) =>
|
||||||
|
html`<ha-settings-row>
|
||||||
|
<span slot="prefix">
|
||||||
|
<ha-checkbox
|
||||||
|
id=${adapter.name}
|
||||||
|
@change=${this._handleAdapterCheckboxClick}
|
||||||
|
.checked=${configured_adapters.includes(adapter.name)}
|
||||||
|
.adapter=${adapter.name}
|
||||||
|
name=${adapter.name}
|
||||||
|
>
|
||||||
|
</ha-checkbox>
|
||||||
|
</span>
|
||||||
|
<span slot="heading">
|
||||||
|
Adapter: ${adapter.name}
|
||||||
|
${adapter.default
|
||||||
|
? html`<ha-icon .icon="hass:star"></ha-icon> (Default)`
|
||||||
|
: ""}
|
||||||
|
</span>
|
||||||
|
<span slot="description">
|
||||||
|
${format_addresses(adapter.ipv4)}
|
||||||
|
${format_addresses(adapter.ipv6)}
|
||||||
|
</span>
|
||||||
|
</ha-settings-row>`
|
||||||
|
)
|
||||||
|
: ""}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleAutoConfigureCheckboxClick(ev: Event) {
|
||||||
|
const checkbox = ev.currentTarget as HaCheckbox;
|
||||||
|
if (this.networkConfig === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let configured_adapters = [...this.networkConfig.configured_adapters];
|
||||||
|
|
||||||
|
if (checkbox.checked) {
|
||||||
|
this._expanded = false;
|
||||||
|
configured_adapters = [];
|
||||||
|
} else {
|
||||||
|
this._expanded = true;
|
||||||
|
for (const adapter of this.networkConfig.adapters) {
|
||||||
|
if (adapter.default) {
|
||||||
|
configured_adapters = [adapter.name];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent(this, "network-config-changed", {
|
||||||
|
configured_adapters: configured_adapters,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleAdapterCheckboxClick(ev: Event) {
|
||||||
|
const checkbox = ev.currentTarget as HaCheckbox;
|
||||||
|
const adapter_name = (checkbox as any).name;
|
||||||
|
if (this.networkConfig === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const configured_adapters = [...this.networkConfig.configured_adapters];
|
||||||
|
|
||||||
|
if (checkbox.checked) {
|
||||||
|
configured_adapters.push(adapter_name);
|
||||||
|
} else {
|
||||||
|
const index = configured_adapters.indexOf(adapter_name, 0);
|
||||||
|
configured_adapters.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent(this, "network-config-changed", {
|
||||||
|
configured_adapters: configured_adapters,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
.error {
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-settings-row {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
span[slot="heading"],
|
||||||
|
span[slot="description"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-network": HaNetwork;
|
||||||
|
}
|
||||||
|
}
|
43
src/data/network.ts
Normal file
43
src/data/network.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
export interface IPv6ConfiguredAddress {
|
||||||
|
address: string;
|
||||||
|
flowinfo: number;
|
||||||
|
scope_id: number;
|
||||||
|
network_prefix: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPv4ConfiguredAddress {
|
||||||
|
address: string;
|
||||||
|
network_prefix: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Adapter {
|
||||||
|
name: string;
|
||||||
|
enabled: boolean;
|
||||||
|
auto: boolean;
|
||||||
|
default: boolean;
|
||||||
|
ipv6: IPv6ConfiguredAddress[];
|
||||||
|
ipv4: IPv4ConfiguredAddress[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NetworkConfig {
|
||||||
|
adapters: Adapter[];
|
||||||
|
configured_adapters: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getNetworkConfig = (hass: HomeAssistant) =>
|
||||||
|
hass.callWS<NetworkConfig>({
|
||||||
|
type: "network",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setNetworkConfig = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
configured_adapters: string[]
|
||||||
|
) =>
|
||||||
|
hass.callWS<string[]>({
|
||||||
|
type: "network/configure",
|
||||||
|
config: {
|
||||||
|
configured_adapters: configured_adapters,
|
||||||
|
},
|
||||||
|
});
|
131
src/panels/config/core/ha-config-network.ts
Normal file
131
src/panels/config/core/ha-config-network.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import "@material/mwc-button/mwc-button";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
|
import "../../../components/ha-network";
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-checkbox";
|
||||||
|
import "../../../components/ha-settings-row";
|
||||||
|
import {
|
||||||
|
NetworkConfig,
|
||||||
|
getNetworkConfig,
|
||||||
|
setNetworkConfig,
|
||||||
|
} from "../../../data/network";
|
||||||
|
import { haStyle } from "../../../resources/styles";
|
||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
|
||||||
|
@customElement("ha-config-network")
|
||||||
|
class ConfigNetwork extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _networkConfig?: NetworkConfig;
|
||||||
|
|
||||||
|
@state() private _error?: string;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.hass.userData?.showAdvanced) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = this._error
|
||||||
|
? this._error
|
||||||
|
: !isComponentLoaded(this.hass, "network")
|
||||||
|
? "Network integration not loaded"
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-card header="Network">
|
||||||
|
<div class="card-content">
|
||||||
|
${error ? html`<div class="error">${error}</div>` : ""}
|
||||||
|
<p>
|
||||||
|
Configure which network adapters integrations will use. Currently
|
||||||
|
this setting only affects multicast traffic. A restart is required
|
||||||
|
for these settings to apply.
|
||||||
|
</p>
|
||||||
|
<ha-network
|
||||||
|
@network-config-changed=${this._configChanged}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.networkConfig=${this._networkConfig}
|
||||||
|
></ha-network>
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<mwc-button @click=${this._save}>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.core.section.core.core_config.save_button"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
if (isComponentLoaded(this.hass, "network")) {
|
||||||
|
this._load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _load() {
|
||||||
|
this._error = undefined;
|
||||||
|
try {
|
||||||
|
this._networkConfig = await getNetworkConfig(this.hass);
|
||||||
|
} catch (err) {
|
||||||
|
this._error = err.message || err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _save() {
|
||||||
|
this._error = undefined;
|
||||||
|
try {
|
||||||
|
await setNetworkConfig(
|
||||||
|
this.hass,
|
||||||
|
this._networkConfig?.configured_adapters || []
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
this._error = err.message || err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _configChanged(event: CustomEvent): void {
|
||||||
|
this._networkConfig = {
|
||||||
|
...this._networkConfig!,
|
||||||
|
configured_adapters: event.detail.configured_adapters,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
.error {
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
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": ConfigNetwork;
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import "../ha-config-section";
|
|||||||
import "./ha-config-analytics";
|
import "./ha-config-analytics";
|
||||||
import "./ha-config-core-form";
|
import "./ha-config-core-form";
|
||||||
import "./ha-config-name-form";
|
import "./ha-config-name-form";
|
||||||
|
import "./ha-config-network";
|
||||||
import "./ha-config-url-form";
|
import "./ha-config-url-form";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -30,6 +31,7 @@ class HaConfigSectionCore extends LocalizeMixin(PolymerElement) {
|
|||||||
<ha-config-name-form hass="[[hass]]"></ha-config-name-form>
|
<ha-config-name-form hass="[[hass]]"></ha-config-name-form>
|
||||||
<ha-config-core-form hass="[[hass]]"></ha-config-core-form>
|
<ha-config-core-form hass="[[hass]]"></ha-config-core-form>
|
||||||
<ha-config-url-form hass="[[hass]]"></ha-config-url-form>
|
<ha-config-url-form hass="[[hass]]"></ha-config-url-form>
|
||||||
|
<ha-config-network hass="[[hass]]"></ha-config-network>
|
||||||
<ha-config-analytics hass="[[hass]]"></ha-config-analytics>
|
<ha-config-analytics hass="[[hass]]"></ha-config-analytics>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
`;
|
`;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user