mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-31 21:17:47 +00:00
Merge branch 'dev' into entity_registry_mass_units
This commit is contained in:
commit
a9a69a8995
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 90 days stale policy
|
- name: 90 days stale policy
|
||||||
uses: actions/stale@v5.2.0
|
uses: actions/stale@v6.0.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
days-before-stale: 90
|
days-before-stale: 90
|
||||||
|
@ -68,6 +68,7 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
hidden_by: null,
|
hidden_by: null,
|
||||||
entity_category: null,
|
entity_category: null,
|
||||||
has_entity_name: false,
|
has_entity_name: false,
|
||||||
|
unique_id: "co2_intensity",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
config_entry_id: "co2signal",
|
config_entry_id: "co2signal",
|
||||||
@ -82,6 +83,7 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
hidden_by: null,
|
hidden_by: null,
|
||||||
entity_category: null,
|
entity_category: null,
|
||||||
has_entity_name: false,
|
has_entity_name: false,
|
||||||
|
unique_id: "grid_fossil_fuel_percentage",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -11,14 +11,12 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
|
|||||||
{
|
{
|
||||||
stat_energy_from: "sensor.energy_consumption_tarif_1",
|
stat_energy_from: "sensor.energy_consumption_tarif_1",
|
||||||
stat_cost: "sensor.energy_consumption_tarif_1_cost",
|
stat_cost: "sensor.energy_consumption_tarif_1_cost",
|
||||||
entity_energy_from: "sensor.energy_consumption_tarif_1",
|
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
stat_energy_from: "sensor.energy_consumption_tarif_2",
|
stat_energy_from: "sensor.energy_consumption_tarif_2",
|
||||||
stat_cost: "sensor.energy_consumption_tarif_2_cost",
|
stat_cost: "sensor.energy_consumption_tarif_2_cost",
|
||||||
entity_energy_from: "sensor.energy_consumption_tarif_2",
|
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
},
|
},
|
||||||
@ -27,14 +25,12 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
|
|||||||
{
|
{
|
||||||
stat_energy_to: "sensor.energy_production_tarif_1",
|
stat_energy_to: "sensor.energy_production_tarif_1",
|
||||||
stat_compensation: "sensor.energy_production_tarif_1_compensation",
|
stat_compensation: "sensor.energy_production_tarif_1_compensation",
|
||||||
entity_energy_to: "sensor.energy_production_tarif_1",
|
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
stat_energy_to: "sensor.energy_production_tarif_2",
|
stat_energy_to: "sensor.energy_production_tarif_2",
|
||||||
stat_compensation: "sensor.energy_production_tarif_2_compensation",
|
stat_compensation: "sensor.energy_production_tarif_2_compensation",
|
||||||
entity_energy_to: "sensor.energy_production_tarif_2",
|
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
},
|
},
|
||||||
@ -55,7 +51,6 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
|
|||||||
type: "gas",
|
type: "gas",
|
||||||
stat_energy_from: "sensor.energy_gas",
|
stat_energy_from: "sensor.energy_gas",
|
||||||
stat_cost: "sensor.energy_gas_cost",
|
stat_cost: "sensor.energy_gas_cost",
|
||||||
entity_energy_from: "sensor.energy_gas",
|
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
},
|
},
|
||||||
|
@ -196,6 +196,7 @@ const createEntityRegistryEntries = (
|
|||||||
icon: null,
|
icon: null,
|
||||||
platform: "updater",
|
platform: "updater",
|
||||||
has_entity_name: false,
|
has_entity_name: false,
|
||||||
|
unique_id: "updater",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -46,6 +46,14 @@ frontend:
|
|||||||
# development_repo: ${WD}" >> "${WD}/config/configuration.yaml"
|
# development_repo: ${WD}" >> "${WD}/config/configuration.yaml"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "${CODESPACES}" ]; then
|
||||||
|
echo "
|
||||||
|
http:
|
||||||
|
use_x_forwarded_for: true
|
||||||
|
trusted_proxies:
|
||||||
|
- 127.0.0.1
|
||||||
|
" >> "${WD}/config/configuration.yaml"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
hass -c "${WD}/config"
|
hass -c "${WD}/config"
|
||||||
|
@ -41,7 +41,7 @@ export class HaSelectSelector extends LitElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!this.selector.select.custom_value && this._mode === "list") {
|
if (!this.selector.select.custom_value && this._mode === "list") {
|
||||||
if (!this.selector.select.multiple || this.required) {
|
if (!this.selector.select.multiple) {
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
${this.label}
|
${this.label}
|
||||||
@ -64,7 +64,8 @@ export class HaSelectSelector extends LitElement {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
${this.label}${options.map(
|
${this.label}
|
||||||
|
${options.map(
|
||||||
(item: SelectOption) => html`
|
(item: SelectOption) => html`
|
||||||
<ha-formfield .label=${item.label}>
|
<ha-formfield .label=${item.label}>
|
||||||
<ha-checkbox
|
<ha-checkbox
|
||||||
@ -114,7 +115,7 @@ export class HaSelectSelector extends LitElement {
|
|||||||
.required=${this.required && !value.length}
|
.required=${this.required && !value.length}
|
||||||
.value=${this._filter}
|
.value=${this._filter}
|
||||||
.items=${options.filter(
|
.items=${options.filter(
|
||||||
(item) => !item.disabled && !this.value?.includes(item.value)
|
(option) => !option.disabled && !value?.includes(option.value)
|
||||||
)}
|
)}
|
||||||
@filter-changed=${this._filterChanged}
|
@filter-changed=${this._filterChanged}
|
||||||
@value-changed=${this._comboBoxValueChanged}
|
@value-changed=${this._comboBoxValueChanged}
|
||||||
@ -290,6 +291,9 @@ export class HaSelectSelector extends LitElement {
|
|||||||
ha-formfield {
|
ha-formfield {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
mwc-list-item[disabled] {
|
||||||
|
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ export const emptyFlowFromGridSourceEnergyPreference =
|
|||||||
(): FlowFromGridSourceEnergyPreference => ({
|
(): FlowFromGridSourceEnergyPreference => ({
|
||||||
stat_energy_from: "",
|
stat_energy_from: "",
|
||||||
stat_cost: null,
|
stat_cost: null,
|
||||||
entity_energy_from: null,
|
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
});
|
});
|
||||||
@ -38,7 +37,6 @@ export const emptyFlowToGridSourceEnergyPreference =
|
|||||||
(): FlowToGridSourceEnergyPreference => ({
|
(): FlowToGridSourceEnergyPreference => ({
|
||||||
stat_energy_to: "",
|
stat_energy_to: "",
|
||||||
stat_compensation: null,
|
stat_compensation: null,
|
||||||
entity_energy_to: null,
|
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
});
|
});
|
||||||
@ -68,7 +66,6 @@ export const emptyGasEnergyPreference = (): GasSourceTypeEnergyPreference => ({
|
|||||||
type: "gas",
|
type: "gas",
|
||||||
stat_energy_from: "",
|
stat_energy_from: "",
|
||||||
stat_cost: null,
|
stat_cost: null,
|
||||||
entity_energy_from: null,
|
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
});
|
});
|
||||||
@ -93,7 +90,6 @@ export interface FlowFromGridSourceEnergyPreference {
|
|||||||
stat_cost: string | null;
|
stat_cost: string | null;
|
||||||
|
|
||||||
// Can be used to generate costs if stat_cost omitted
|
// Can be used to generate costs if stat_cost omitted
|
||||||
entity_energy_from: string | null;
|
|
||||||
entity_energy_price: string | null;
|
entity_energy_price: string | null;
|
||||||
number_energy_price: number | null;
|
number_energy_price: number | null;
|
||||||
}
|
}
|
||||||
@ -105,8 +101,7 @@ export interface FlowToGridSourceEnergyPreference {
|
|||||||
// $ meter
|
// $ meter
|
||||||
stat_compensation: string | null;
|
stat_compensation: string | null;
|
||||||
|
|
||||||
// Can be used to generate costs if stat_cost omitted
|
// Can be used to generate costs if stat_compensation omitted
|
||||||
entity_energy_to: string | null;
|
|
||||||
entity_energy_price: string | null;
|
entity_energy_price: string | null;
|
||||||
number_energy_price: number | null;
|
number_energy_price: number | null;
|
||||||
}
|
}
|
||||||
@ -142,7 +137,6 @@ export interface GasSourceTypeEnergyPreference {
|
|||||||
stat_cost: string | null;
|
stat_cost: string | null;
|
||||||
|
|
||||||
// Can be used to generate costs if stat_cost omitted
|
// Can be used to generate costs if stat_cost omitted
|
||||||
entity_energy_from: string | null;
|
|
||||||
entity_energy_price: string | null;
|
entity_energy_price: string | null;
|
||||||
number_energy_price: number | null;
|
number_energy_price: number | null;
|
||||||
unit_of_measurement?: string | null;
|
unit_of_measurement?: string | null;
|
||||||
|
@ -20,10 +20,10 @@ export interface EntityRegistryEntry {
|
|||||||
entity_category: "config" | "diagnostic" | null;
|
entity_category: "config" | "diagnostic" | null;
|
||||||
has_entity_name: boolean;
|
has_entity_name: boolean;
|
||||||
original_name?: string;
|
original_name?: string;
|
||||||
|
unique_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtEntityRegistryEntry extends EntityRegistryEntry {
|
export interface ExtEntityRegistryEntry extends EntityRegistryEntry {
|
||||||
unique_id: string;
|
|
||||||
capabilities: Record<string, unknown>;
|
capabilities: Record<string, unknown>;
|
||||||
original_icon?: string;
|
original_icon?: string;
|
||||||
device_class?: string;
|
device_class?: string;
|
||||||
@ -61,7 +61,7 @@ export interface EntityRegistryEntryUpdateParams {
|
|||||||
hidden_by: string | null;
|
hidden_by: string | null;
|
||||||
new_entity_id?: string;
|
new_entity_id?: string;
|
||||||
options_domain?: string;
|
options_domain?: string;
|
||||||
options?: SensorEntityOptions | WeatherEntityOptions;
|
options?: SensorEntityOptions | NumberEntityOptions | WeatherEntityOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const findBatteryEntity = (
|
export const findBatteryEntity = (
|
||||||
|
@ -93,6 +93,8 @@ export interface LovelaceViewConfig {
|
|||||||
panel?: boolean;
|
panel?: boolean;
|
||||||
background?: string;
|
background?: string;
|
||||||
visible?: boolean | ShowViewConfig[];
|
visible?: boolean | ShowViewConfig[];
|
||||||
|
subview?: boolean;
|
||||||
|
back_path?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LovelaceViewElement extends HTMLElement {
|
export interface LovelaceViewElement extends HTMLElement {
|
||||||
|
@ -309,7 +309,7 @@ export const fetchCommandsForCluster = (
|
|||||||
cluster_type: clusterType,
|
cluster_type: clusterType,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const fetchClustersForZhaNode = (
|
export const fetchClustersForZhaDevice = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
ieeeAddress: string
|
ieeeAddress: string
|
||||||
): Promise<Cluster[]> =>
|
): Promise<Cluster[]> =>
|
||||||
|
@ -90,7 +90,7 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
const stateObj = this.hass.states[entityId];
|
const stateObj = this.hass.states[entityId];
|
||||||
|
|
||||||
const domain = computeDomain(entityId);
|
const domain = computeDomain(entityId);
|
||||||
const name = stateObj ? computeStateName(stateObj) : entityId;
|
const name = (stateObj && computeStateName(stateObj)) || entityId;
|
||||||
const tabs = this._getTabs(entityId, this.hass.user!.is_admin);
|
const tabs = this._getTabs(entityId, this.hass.user!.is_admin);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
|
import { mdiOpenInNew } from "@mdi/js";
|
||||||
|
import { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import "../../../components/ha-circular-progress";
|
import "../../../components/ha-circular-progress";
|
||||||
import "../../../components/ha-combo-box";
|
import "../../../components/ha-combo-box";
|
||||||
@ -10,14 +11,15 @@ import { createCloseHeading } from "../../../components/ha-dialog";
|
|||||||
import "../../../components/ha-markdown";
|
import "../../../components/ha-markdown";
|
||||||
import "../../../components/ha-textfield";
|
import "../../../components/ha-textfield";
|
||||||
import {
|
import {
|
||||||
fetchApplicationCredentialsConfig,
|
|
||||||
createApplicationCredential,
|
|
||||||
ApplicationCredentialsConfig,
|
|
||||||
ApplicationCredential,
|
ApplicationCredential,
|
||||||
|
ApplicationCredentialsConfig,
|
||||||
|
createApplicationCredential,
|
||||||
|
fetchApplicationCredentialsConfig,
|
||||||
} from "../../../data/application_credential";
|
} from "../../../data/application_credential";
|
||||||
import { domainToName } from "../../../data/integration";
|
import { domainToName } from "../../../data/integration";
|
||||||
import { haStyleDialog } from "../../../resources/styles";
|
import { haStyleDialog } from "../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import { AddApplicationCredentialDialogParams } from "./show-dialog-add-application-credential";
|
import { AddApplicationCredentialDialogParams } from "./show-dialog-add-application-credential";
|
||||||
|
|
||||||
interface Domain {
|
interface Domain {
|
||||||
@ -98,6 +100,25 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
|
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
|
||||||
|
<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.application_credentials.editor.description"
|
||||||
|
)}
|
||||||
|
<br />
|
||||||
|
<a
|
||||||
|
href=${documentationUrl(
|
||||||
|
this.hass!,
|
||||||
|
"/integrations/application_credentials"
|
||||||
|
)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.application_credentials.editor.view_documentation"
|
||||||
|
)}
|
||||||
|
<ha-svg-icon .path=${mdiOpenInNew}></ha-svg-icon>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
<ha-combo-box
|
<ha-combo-box
|
||||||
name="domain"
|
name="domain"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -143,6 +164,10 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
@input=${this._handleValueChanged}
|
@input=${this._handleValueChanged}
|
||||||
error-message=${this.hass.localize("ui.common.error_required")}
|
error-message=${this.hass.localize("ui.common.error_required")}
|
||||||
dialogInitialFocus
|
dialogInitialFocus
|
||||||
|
.helper=${this.hass.localize(
|
||||||
|
"ui.panel.config.application_credentials.editor.client_id_helper"
|
||||||
|
)}
|
||||||
|
helperPersistent
|
||||||
></ha-textfield>
|
></ha-textfield>
|
||||||
<ha-textfield
|
<ha-textfield
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
@ -154,6 +179,10 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
required
|
required
|
||||||
@input=${this._handleValueChanged}
|
@input=${this._handleValueChanged}
|
||||||
error-message=${this.hass.localize("ui.common.error_required")}
|
error-message=${this.hass.localize("ui.common.error_required")}
|
||||||
|
.helper=${this.hass.localize(
|
||||||
|
"ui.panel.config.application_credentials.editor.client_secret_helper"
|
||||||
|
)}
|
||||||
|
helperPersistent
|
||||||
></ha-textfield>
|
></ha-textfield>
|
||||||
</div>
|
</div>
|
||||||
${this._loading
|
${this._loading
|
||||||
@ -163,15 +192,18 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
|
<mwc-button slot="primaryAction" @click=${this._abortDialog}>
|
||||||
|
${this.hass.localize("ui.common.cancel")}
|
||||||
|
</mwc-button>
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
.disabled=${!this._domain ||
|
.disabled=${!this._domain ||
|
||||||
!this._clientId ||
|
!this._clientId ||
|
||||||
!this._clientSecret}
|
!this._clientSecret}
|
||||||
@click=${this._createApplicationCredential}
|
@click=${this._addApplicationCredential}
|
||||||
>
|
>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.application_credentials.editor.create"
|
"ui.panel.config.application_credentials.editor.add"
|
||||||
)}
|
)}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
`}
|
`}
|
||||||
@ -213,7 +245,7 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _createApplicationCredential(ev) {
|
private async _addApplicationCredential(ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
if (!this._domain || !this._clientId || !this._clientSecret) {
|
if (!this._domain || !this._clientId || !this._clientSecret) {
|
||||||
return;
|
return;
|
||||||
@ -260,6 +292,12 @@ export class DialogAddApplicationCredential extends LitElement {
|
|||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a ha-svg-icon {
|
||||||
|
--mdc-icon-size: 16px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -575,10 +575,15 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
private async _deleteConfirm() {
|
private async _deleteConfirm() {
|
||||||
showConfirmationDialog(this, {
|
showConfirmationDialog(this, {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.panel.config.automation.picker.delete_confirm_title"
|
||||||
|
),
|
||||||
text: this.hass.localize(
|
text: this.hass.localize(
|
||||||
"ui.panel.config.automation.picker.delete_confirm"
|
"ui.panel.config.automation.picker.delete_confirm_text",
|
||||||
|
{ name: this._config?.alias }
|
||||||
),
|
),
|
||||||
confirmText: this.hass!.localize("ui.common.delete"),
|
confirmText: this.hass!.localize("ui.common.delete"),
|
||||||
|
destructive: true,
|
||||||
dismissText: this.hass!.localize("ui.common.cancel"),
|
dismissText: this.hass!.localize("ui.common.cancel"),
|
||||||
confirm: () => this._delete(),
|
confirm: () => this._delete(),
|
||||||
});
|
});
|
||||||
|
@ -341,12 +341,17 @@ class HaAutomationPicker extends LitElement {
|
|||||||
|
|
||||||
private async _deleteConfirm(automation) {
|
private async _deleteConfirm(automation) {
|
||||||
showConfirmationDialog(this, {
|
showConfirmationDialog(this, {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.panel.config.automation.picker.delete_confirm_title"
|
||||||
|
),
|
||||||
text: this.hass.localize(
|
text: this.hass.localize(
|
||||||
"ui.panel.config.automation.picker.delete_confirm"
|
"ui.panel.config.automation.picker.delete_confirm_text",
|
||||||
|
{ name: automation.name }
|
||||||
),
|
),
|
||||||
confirmText: this.hass!.localize("ui.common.delete"),
|
confirmText: this.hass!.localize("ui.common.delete"),
|
||||||
dismissText: this.hass!.localize("ui.common.cancel"),
|
dismissText: this.hass!.localize("ui.common.cancel"),
|
||||||
confirm: () => this._delete(automation),
|
confirm: () => this._delete(automation),
|
||||||
|
destructive: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
|
import { mdiOpenInNew } from "@mdi/js";
|
||||||
import { css, html, LitElement, TemplateResult } from "lit";
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
@ -105,28 +106,42 @@ class DialogImportBlueprint extends LitElement {
|
|||||||
>
|
>
|
||||||
<pre>${this._result.raw_data}</pre>
|
<pre>${this._result.raw_data}</pre>
|
||||||
</ha-expansion-panel>`
|
</ha-expansion-panel>`
|
||||||
: html`${this.hass.localize(
|
: html`
|
||||||
"ui.panel.config.blueprint.add.import_introduction_link",
|
<p>
|
||||||
"community_link",
|
${this.hass.localize(
|
||||||
html`<a
|
"ui.panel.config.blueprint.add.import_introduction"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
href="https://www.home-assistant.io/get-blueprints"
|
href="https://www.home-assistant.io/get-blueprints"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer noopener"
|
rel="noreferrer noopener"
|
||||||
>${this.hass.localize(
|
>
|
||||||
|
${this.hass.localize(
|
||||||
"ui.panel.config.blueprint.add.community_forums"
|
"ui.panel.config.blueprint.add.community_forums"
|
||||||
)}</a
|
)}
|
||||||
>`
|
<ha-svg-icon .path=${mdiOpenInNew}></ha-svg-icon>
|
||||||
)}<ha-textfield
|
</a>
|
||||||
|
<ha-textfield
|
||||||
id="input"
|
id="input"
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.blueprint.add.url"
|
"ui.panel.config.blueprint.add.url"
|
||||||
)}
|
)}
|
||||||
.value=${this._url || ""}
|
.value=${this._url || ""}
|
||||||
dialogInitialFocus
|
dialogInitialFocus
|
||||||
></ha-textfield>`}
|
></ha-textfield>
|
||||||
|
`}
|
||||||
</div>
|
</div>
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${this.closeDialog}
|
||||||
|
.disabled=${this._saving}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.common.cancel")}
|
||||||
|
</mwc-button>
|
||||||
${!this._result
|
${!this._result
|
||||||
? html`<mwc-button
|
? html`
|
||||||
|
<mwc-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
@click=${this._import}
|
@click=${this._import}
|
||||||
.disabled=${this._importing}
|
.disabled=${this._importing}
|
||||||
@ -140,15 +155,12 @@ class DialogImportBlueprint extends LitElement {
|
|||||||
)}
|
)}
|
||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.hass.localize("ui.panel.config.blueprint.add.import_btn")}
|
${this.hass.localize(
|
||||||
</mwc-button>`
|
"ui.panel.config.blueprint.add.import_btn"
|
||||||
: html`<mwc-button
|
)}
|
||||||
slot="secondaryAction"
|
|
||||||
@click=${this.closeDialog}
|
|
||||||
.disabled=${this._saving}
|
|
||||||
>
|
|
||||||
${this.hass.localize("ui.common.cancel")}
|
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
@click=${this._save}
|
@click=${this._save}
|
||||||
@ -164,7 +176,8 @@ class DialogImportBlueprint extends LitElement {
|
|||||||
></ha-circular-progress>`
|
></ha-circular-progress>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.hass.localize("ui.panel.config.blueprint.add.save_btn")}
|
${this.hass.localize("ui.panel.config.blueprint.add.save_btn")}
|
||||||
</mwc-button>`}
|
</mwc-button>
|
||||||
|
`}
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -215,9 +228,19 @@ class DialogImportBlueprint extends LitElement {
|
|||||||
static styles = [
|
static styles = [
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
css`
|
css`
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
ha-textfield {
|
ha-textfield {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 8px;
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a ha-svg-icon {
|
||||||
|
--mdc-icon-size: 16px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
mdiCogRefresh,
|
mdiCogRefresh,
|
||||||
mdiDelete,
|
mdiDelete,
|
||||||
mdiDrawPen,
|
|
||||||
mdiFamilyTree,
|
mdiFamilyTree,
|
||||||
mdiFileTree,
|
|
||||||
mdiGroup,
|
mdiGroup,
|
||||||
mdiPlus,
|
mdiPlus,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
@ -12,9 +10,7 @@ import type { DeviceRegistryEntry } from "../../../../../../data/device_registry
|
|||||||
import { fetchZHADevice } from "../../../../../../data/zha";
|
import { fetchZHADevice } from "../../../../../../data/zha";
|
||||||
import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box";
|
import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box";
|
||||||
import type { HomeAssistant } from "../../../../../../types";
|
import type { HomeAssistant } from "../../../../../../types";
|
||||||
import { showZHAClusterDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-cluster";
|
import { showZHAManageZigbeeDeviceDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-manage-zigbee-device";
|
||||||
import { showZHADeviceChildrenDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-device-children";
|
|
||||||
import { showZHADeviceZigbeeInfoDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-device-zigbee-info";
|
|
||||||
import { showZHAReconfigureDeviceDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-reconfigure-device";
|
import { showZHAReconfigureDeviceDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-reconfigure-device";
|
||||||
import type { DeviceAction } from "../../../ha-config-device-page";
|
import type { DeviceAction } from "../../../ha-config-device-page";
|
||||||
|
|
||||||
@ -59,13 +55,6 @@ export const getZHADeviceActions = async (
|
|||||||
icon: mdiPlus,
|
icon: mdiPlus,
|
||||||
action: () => navigate(`/config/zha/add/${zhaDevice!.ieee}`),
|
action: () => navigate(`/config/zha/add/${zhaDevice!.ieee}`),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: hass.localize(
|
|
||||||
"ui.dialogs.zha_device_info.buttons.device_children"
|
|
||||||
),
|
|
||||||
icon: mdiFileTree,
|
|
||||||
action: () => showZHADeviceChildrenDialog(el, { device: zhaDevice! }),
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -73,16 +62,10 @@ export const getZHADeviceActions = async (
|
|||||||
actions.push(
|
actions.push(
|
||||||
...[
|
...[
|
||||||
{
|
{
|
||||||
label: hass.localize(
|
label: hass.localize("ui.dialogs.zha_device_info.buttons.manage"),
|
||||||
"ui.dialogs.zha_device_info.buttons.zigbee_information"
|
|
||||||
),
|
|
||||||
icon: mdiDrawPen,
|
|
||||||
action: () => showZHADeviceZigbeeInfoDialog(el, { device: zhaDevice }),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: hass.localize("ui.dialogs.zha_device_info.buttons.clusters"),
|
|
||||||
icon: mdiGroup,
|
icon: mdiGroup,
|
||||||
action: () => showZHAClusterDialog(el, { device: zhaDevice }),
|
action: () =>
|
||||||
|
showZHAManageZigbeeDeviceDialog(el, { device: zhaDevice }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: hass.localize("ui.dialogs.zha_device_info.buttons.view_network"),
|
label: hass.localize("ui.dialogs.zha_device_info.buttons.view_network"),
|
||||||
|
@ -23,6 +23,7 @@ export class HaDeviceActionsZha extends LitElement {
|
|||||||
@state() private _zhaDevice?: ZHADevice;
|
@state() private _zhaDevice?: ZHADevice;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues) {
|
protected updated(changedProperties: PropertyValues) {
|
||||||
|
super.updated(changedProperties);
|
||||||
if (changedProperties.has("device")) {
|
if (changedProperties.has("device")) {
|
||||||
const zigbeeConnection = this.device.connections.find(
|
const zigbeeConnection = this.device.connections.find(
|
||||||
(conn) => conn[0] === "zigbee"
|
(conn) => conn[0] === "zigbee"
|
||||||
|
@ -280,7 +280,6 @@ export class DialogEnergyGasSettings
|
|||||||
this._source = {
|
this._source = {
|
||||||
...this._source!,
|
...this._source!,
|
||||||
stat_energy_from: ev.detail.value,
|
stat_energy_from: ev.detail.value,
|
||||||
entity_energy_from: ev.detail.value,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,9 +269,6 @@ export class DialogEnergyGridFlowSettings
|
|||||||
[this._params!.direction === "from"
|
[this._params!.direction === "from"
|
||||||
? "stat_energy_from"
|
? "stat_energy_from"
|
||||||
: "stat_energy_to"]: ev.detail.value,
|
: "stat_energy_to"]: ev.detail.value,
|
||||||
[this._params!.direction === "from"
|
|
||||||
? "entity_energy_from"
|
|
||||||
: "entity_energy_to"]: ev.detail.value,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,9 +111,12 @@ const OVERRIDE_NUMBER_UNITS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const OVERRIDE_SENSOR_UNITS = {
|
const OVERRIDE_SENSOR_UNITS = {
|
||||||
|
distance: ["cm", "ft", "in", "km", "m", "mi", "mm", "yd"],
|
||||||
mass: ["g", "kg", "lb", "mg", "oz", "µg"],
|
mass: ["g", "kg", "lb", "mg", "oz", "µg"],
|
||||||
pressure: ["hPa", "Pa", "kPa", "bar", "cbar", "mbar", "mmHg", "inHg", "psi"],
|
pressure: ["hPa", "Pa", "kPa", "bar", "cbar", "mbar", "mmHg", "inHg", "psi"],
|
||||||
|
speed: ["ft/s", "in/d", "in/h", "km/h", "kn", "m/s", "mm/d", "mph"],
|
||||||
temperature: ["°C", "°F", "K"],
|
temperature: ["°C", "°F", "K"],
|
||||||
|
volume: ["fl. oz.", "ft³", "gal", "L", "mL", "m³"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const OVERRIDE_WEATHER_UNITS = {
|
const OVERRIDE_WEATHER_UNITS = {
|
||||||
|
@ -68,10 +68,12 @@ import type { HomeAssistant, Route } from "../../../types";
|
|||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "../integrations/ha-integration-overflow-menu";
|
import "../integrations/ha-integration-overflow-menu";
|
||||||
|
|
||||||
export interface StateEntity extends Omit<EntityRegistryEntry, "id"> {
|
export interface StateEntity
|
||||||
|
extends Omit<EntityRegistryEntry, "id" | "unique_id"> {
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
selectable?: boolean;
|
selectable?: boolean;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
unique_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EntityRow extends StateEntity {
|
export interface EntityRow extends StateEntity {
|
||||||
|
@ -1,142 +0,0 @@
|
|||||||
import {
|
|
||||||
CSSResultGroup,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
PropertyValues,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import "../../../../../components/ha-code-editor";
|
|
||||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
|
||||||
import {
|
|
||||||
Cluster,
|
|
||||||
fetchBindableDevices,
|
|
||||||
fetchGroups,
|
|
||||||
ZHADevice,
|
|
||||||
ZHAGroup,
|
|
||||||
} from "../../../../../data/zha";
|
|
||||||
import { haStyleDialog } from "../../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../../types";
|
|
||||||
import { sortZHADevices, sortZHAGroups } from "./functions";
|
|
||||||
import { ZHADeviceZigbeeInfoDialogParams } from "./show-dialog-zha-device-zigbee-info";
|
|
||||||
import { ZHAClusterSelectedParams } from "./types";
|
|
||||||
import "./zha-cluster-attributes";
|
|
||||||
import "./zha-cluster-commands";
|
|
||||||
import "./zha-clusters";
|
|
||||||
import "./zha-device-binding";
|
|
||||||
import "./zha-group-binding";
|
|
||||||
|
|
||||||
@customElement("dialog-zha-cluster")
|
|
||||||
class DialogZHACluster extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _device?: ZHADevice;
|
|
||||||
|
|
||||||
@state() private _selectedCluster?: Cluster;
|
|
||||||
|
|
||||||
@state() private _bindableDevices: ZHADevice[] = [];
|
|
||||||
|
|
||||||
@state() private _groups: ZHAGroup[] = [];
|
|
||||||
|
|
||||||
public async showDialog(
|
|
||||||
params: ZHADeviceZigbeeInfoDialogParams
|
|
||||||
): Promise<void> {
|
|
||||||
this._device = params.device;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
|
||||||
super.update(changedProperties);
|
|
||||||
if (changedProperties.has("_device")) {
|
|
||||||
this._fetchData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this._device) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<ha-dialog
|
|
||||||
open
|
|
||||||
hideActions
|
|
||||||
@closed=${this._close}
|
|
||||||
.heading=${createCloseHeading(
|
|
||||||
this.hass,
|
|
||||||
this.hass.localize("ui.panel.config.zha.clusters.header")
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<zha-clusters
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedDevice=${this._device}
|
|
||||||
@zha-cluster-selected=${this._onClusterSelected}
|
|
||||||
></zha-clusters>
|
|
||||||
${this._selectedCluster
|
|
||||||
? html`
|
|
||||||
<zha-cluster-attributes
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedNode=${this._device}
|
|
||||||
.selectedCluster=${this._selectedCluster}
|
|
||||||
></zha-cluster-attributes>
|
|
||||||
<zha-cluster-commands
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedNode=${this._device}
|
|
||||||
.selectedCluster=${this._selectedCluster}
|
|
||||||
></zha-cluster-commands>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._bindableDevices.length > 0
|
|
||||||
? html`
|
|
||||||
<zha-device-binding-control
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedDevice=${this._device}
|
|
||||||
.bindableDevices=${this._bindableDevices}
|
|
||||||
></zha-device-binding-control>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._device && this._groups.length > 0
|
|
||||||
? html`
|
|
||||||
<zha-group-binding-control
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selectedDevice=${this._device}
|
|
||||||
.groups=${this._groups}
|
|
||||||
></zha-group-binding-control>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</ha-dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onClusterSelected(
|
|
||||||
selectedClusterEvent: HASSDomEvent<ZHAClusterSelectedParams>
|
|
||||||
): void {
|
|
||||||
this._selectedCluster = selectedClusterEvent.detail.cluster;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _close(): void {
|
|
||||||
this._device = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _fetchData(): Promise<void> {
|
|
||||||
if (this._device && this.hass) {
|
|
||||||
this._bindableDevices =
|
|
||||||
this._device && this._device.device_type !== "Coordinator"
|
|
||||||
? (await fetchBindableDevices(this.hass, this._device.ieee)).sort(
|
|
||||||
sortZHADevices
|
|
||||||
)
|
|
||||||
: [];
|
|
||||||
this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return haStyleDialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"dialog-zha-cluster": DialogZHACluster;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import "../../../../../components/ha-code-editor";
|
|
||||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
|
||||||
import { haStyleDialog } from "../../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../../types";
|
|
||||||
import { ZHADeviceZigbeeInfoDialogParams } from "./show-dialog-zha-device-zigbee-info";
|
|
||||||
|
|
||||||
@customElement("dialog-zha-device-zigbee-info")
|
|
||||||
class DialogZHADeviceZigbeeInfo extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _signature: any;
|
|
||||||
|
|
||||||
public async showDialog(
|
|
||||||
params: ZHADeviceZigbeeInfoDialogParams
|
|
||||||
): Promise<void> {
|
|
||||||
this._signature = JSON.stringify(
|
|
||||||
{
|
|
||||||
...params.device.signature,
|
|
||||||
manufacturer: params.device.manufacturer,
|
|
||||||
model: params.device.model,
|
|
||||||
class: params.device.quirk_class,
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this._signature) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<ha-dialog
|
|
||||||
open
|
|
||||||
hideActions
|
|
||||||
@closed=${this._close}
|
|
||||||
.heading=${createCloseHeading(
|
|
||||||
this.hass,
|
|
||||||
this.hass.localize(`ui.dialogs.zha_device_info.device_signature`)
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<ha-code-editor
|
|
||||||
mode="yaml"
|
|
||||||
readOnly
|
|
||||||
.value=${this._signature}
|
|
||||||
dir="ltr"
|
|
||||||
>
|
|
||||||
</ha-code-editor>
|
|
||||||
</ha-dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _close(): void {
|
|
||||||
this._signature = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return haStyleDialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"dialog-zha-device-zigbee-info": DialogZHADeviceZigbeeInfo;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,291 @@
|
|||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { mdiClose } from "@mdi/js";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { cache } from "lit/directives/cache";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
import "../../../../../components/ha-code-editor";
|
||||||
|
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||||
|
import {
|
||||||
|
fetchBindableDevices,
|
||||||
|
fetchGroups,
|
||||||
|
ZHADevice,
|
||||||
|
ZHAGroup,
|
||||||
|
} from "../../../../../data/zha";
|
||||||
|
import { haStyleDialog } from "../../../../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
import { sortZHADevices, sortZHAGroups } from "./functions";
|
||||||
|
import "./zha-cluster-attributes";
|
||||||
|
import "./zha-cluster-commands";
|
||||||
|
import "./zha-manage-clusters";
|
||||||
|
import "./zha-device-binding";
|
||||||
|
import "./zha-group-binding";
|
||||||
|
import "./zha-device-children";
|
||||||
|
import "./zha-device-signature";
|
||||||
|
import {
|
||||||
|
Tab,
|
||||||
|
ZHAManageZigbeeDeviceDialogParams,
|
||||||
|
} from "./show-dialog-zha-manage-zigbee-device";
|
||||||
|
import "../../../../../components/ha-header-bar";
|
||||||
|
import "@material/mwc-tab-bar/mwc-tab-bar";
|
||||||
|
import "@material/mwc-tab/mwc-tab";
|
||||||
|
|
||||||
|
@customElement("dialog-zha-manage-zigbee-device")
|
||||||
|
class DialogZHAManageZigbeeDevice extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean, reflect: true }) public large = false;
|
||||||
|
|
||||||
|
@state() private _currTab: Tab = "clusters";
|
||||||
|
|
||||||
|
@state() private _device?: ZHADevice;
|
||||||
|
|
||||||
|
@state() private _bindableDevices: ZHADevice[] = [];
|
||||||
|
|
||||||
|
@state() private _groups: ZHAGroup[] = [];
|
||||||
|
|
||||||
|
public async showDialog(
|
||||||
|
params: ZHAManageZigbeeDeviceDialogParams
|
||||||
|
): Promise<void> {
|
||||||
|
this._device = params.device;
|
||||||
|
if (!this._device) {
|
||||||
|
this.closeDialog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._currTab = params.tab || "clusters";
|
||||||
|
this.large = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog() {
|
||||||
|
this._device = undefined;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this.addEventListener("close-dialog", () => this.closeDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected willUpdate(changedProps: PropertyValues) {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
|
if (!this._device) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (changedProps.has("_device")) {
|
||||||
|
const tabs = this._getTabs(this._device);
|
||||||
|
if (!tabs.includes(this._currTab)) {
|
||||||
|
this._currTab = tabs[0];
|
||||||
|
}
|
||||||
|
this._fetchData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._device) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs = this._getTabs(this._device);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
hideActions
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
.heading=${createCloseHeading(
|
||||||
|
this.hass,
|
||||||
|
this.hass.localize("ui.dialogs.zha_manage_device.heading")
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div slot="heading" class="heading">
|
||||||
|
<ha-header-bar>
|
||||||
|
<ha-icon-button
|
||||||
|
slot="navigationIcon"
|
||||||
|
dialogAction="cancel"
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.dialogs.more_info_control.dismiss"
|
||||||
|
)}
|
||||||
|
.path=${mdiClose}
|
||||||
|
></ha-icon-button>
|
||||||
|
<div
|
||||||
|
slot="title"
|
||||||
|
class="main-title"
|
||||||
|
.title=${this.hass.localize(
|
||||||
|
"ui.dialogs.zha_manage_device.heading"
|
||||||
|
)}
|
||||||
|
@click=${this._enlarge}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.dialogs.zha_manage_device.heading")}
|
||||||
|
</div>
|
||||||
|
</ha-header-bar>
|
||||||
|
<mwc-tab-bar
|
||||||
|
.activeIndex=${tabs.indexOf(this._currTab)}
|
||||||
|
@MDCTabBar:activated=${this._handleTabChanged}
|
||||||
|
>
|
||||||
|
${tabs.map(
|
||||||
|
(tab) => html`
|
||||||
|
<mwc-tab
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.dialogs.zha_manage_device.tabs.${tab}`
|
||||||
|
)}
|
||||||
|
></mwc-tab>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</mwc-tab-bar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content" tabindex="-1" dialogInitialFocus>
|
||||||
|
${cache(
|
||||||
|
this._currTab === "clusters"
|
||||||
|
? html`
|
||||||
|
<zha-manage-clusters
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
></zha-manage-clusters>
|
||||||
|
`
|
||||||
|
: this._currTab === "bindings"
|
||||||
|
? html`
|
||||||
|
${this._bindableDevices.length > 0
|
||||||
|
? html`
|
||||||
|
<zha-device-binding-control
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
.bindableDevices=${this._bindableDevices}
|
||||||
|
></zha-device-binding-control>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this._device && this._groups.length > 0
|
||||||
|
? html`
|
||||||
|
<zha-group-binding-control
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
.groups=${this._groups}
|
||||||
|
></zha-group-binding-control>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
`
|
||||||
|
: this._currTab === "signature"
|
||||||
|
? html`
|
||||||
|
<zha-device-zigbee-info
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
></zha-device-zigbee-info>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<zha-device-children
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this._device}
|
||||||
|
></zha-device-children>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _fetchData(): Promise<void> {
|
||||||
|
if (this._device && this.hass) {
|
||||||
|
this._bindableDevices =
|
||||||
|
this._device && this._device.device_type !== "Coordinator"
|
||||||
|
? (await fetchBindableDevices(this.hass, this._device.ieee)).sort(
|
||||||
|
sortZHADevices
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
this._groups = (await fetchGroups(this.hass!)).sort(sortZHAGroups);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _enlarge() {
|
||||||
|
this.large = !this.large;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleTabChanged(ev: CustomEvent): void {
|
||||||
|
const newTab = this._getTabs(this._device)[ev.detail.index];
|
||||||
|
if (newTab === this._currTab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._currTab = newTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getTabs = memoizeOne((device: ZHADevice | undefined) => {
|
||||||
|
const tabs: Tab[] = ["clusters", "bindings", "signature"];
|
||||||
|
|
||||||
|
if (
|
||||||
|
device &&
|
||||||
|
(device.device_type === "Router" || device.device_type === "Coordinator")
|
||||||
|
) {
|
||||||
|
tabs.push("children");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabs;
|
||||||
|
});
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
ha-dialog {
|
||||||
|
--dialog-surface-position: static;
|
||||||
|
--dialog-content-position: static;
|
||||||
|
--vertial-align-dialog: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-header-bar {
|
||||||
|
--mdc-theme-on-primary: var(--primary-text-color);
|
||||||
|
--mdc-theme-primary: var(--mdc-theme-surface);
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||||
|
ha-header-bar {
|
||||||
|
--mdc-theme-primary: var(--app-header-background-color);
|
||||||
|
--mdc-theme-on-primary: var(--app-header-text-color, white);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
border-bottom: 1px solid
|
||||||
|
var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (min-width: 600px) and (min-height: 501px) {
|
||||||
|
ha-dialog {
|
||||||
|
--mdc-dialog-min-width: 560px;
|
||||||
|
--mdc-dialog-max-width: 560px;
|
||||||
|
--dialog-surface-margin-top: 40px;
|
||||||
|
--mdc-dialog-max-height: calc(100% - 72px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([large]) ha-dialog,
|
||||||
|
ha-dialog[data-domain="camera"] {
|
||||||
|
--mdc-dialog-min-width: 90vw;
|
||||||
|
--mdc-dialog-max-width: 90vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-zha-manage-zigbee-device": DialogZHAManageZigbeeDevice;
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ import {
|
|||||||
Cluster,
|
Cluster,
|
||||||
ClusterConfigurationEvent,
|
ClusterConfigurationEvent,
|
||||||
ClusterConfigurationStatus,
|
ClusterConfigurationStatus,
|
||||||
fetchClustersForZhaNode,
|
fetchClustersForZhaDevice,
|
||||||
reconfigureNode,
|
reconfigureNode,
|
||||||
ZHA_CHANNEL_CFG_DONE,
|
ZHA_CHANNEL_CFG_DONE,
|
||||||
ZHA_CHANNEL_MSG_BIND,
|
ZHA_CHANNEL_MSG_BIND,
|
||||||
@ -321,16 +321,16 @@ class DialogZHAReconfigureDevice extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._clusterConfigurationStatuses = new Map(
|
this._clusterConfigurationStatuses = new Map(
|
||||||
(await fetchClustersForZhaNode(this.hass, this._params.device.ieee)).map(
|
(
|
||||||
(cluster: Cluster) => [
|
await fetchClustersForZhaDevice(this.hass, this._params.device.ieee)
|
||||||
|
).map((cluster: Cluster) => [
|
||||||
cluster.id,
|
cluster.id,
|
||||||
{
|
{
|
||||||
cluster: cluster,
|
cluster: cluster,
|
||||||
bindSuccess: undefined,
|
bindSuccess: undefined,
|
||||||
attributes: new Map<number, AttributeConfigurationStatus>(),
|
attributes: new Map<number, AttributeConfigurationStatus>(),
|
||||||
},
|
},
|
||||||
]
|
])
|
||||||
)
|
|
||||||
);
|
);
|
||||||
this._subscribe(this._params);
|
this._subscribe(this._params);
|
||||||
this._status = "started";
|
this._status = "started";
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import { ZHADevice } from "../../../../../data/zha";
|
|
||||||
|
|
||||||
export interface ZHAClusterDialogParams {
|
|
||||||
device: ZHADevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadZHAClusterDialog = () => import("./dialog-zha-cluster");
|
|
||||||
|
|
||||||
export const showZHAClusterDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
params: ZHAClusterDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-zha-cluster",
|
|
||||||
dialogImport: loadZHAClusterDialog,
|
|
||||||
dialogParams: params,
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import { ZHADevice } from "../../../../../data/zha";
|
|
||||||
|
|
||||||
export interface ZHADeviceChildrenDialogParams {
|
|
||||||
device: ZHADevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadZHADeviceChildrenDialog = () =>
|
|
||||||
import("./dialog-zha-device-children");
|
|
||||||
|
|
||||||
export const showZHADeviceChildrenDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
zhaDeviceChildrenParams: ZHADeviceChildrenDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-zha-device-children",
|
|
||||||
dialogImport: loadZHADeviceChildrenDialog,
|
|
||||||
dialogParams: zhaDeviceChildrenParams,
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import { ZHADevice } from "../../../../../data/zha";
|
|
||||||
|
|
||||||
export interface ZHADeviceZigbeeInfoDialogParams {
|
|
||||||
device: ZHADevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadZHADeviceZigbeeInfoDialog = () =>
|
|
||||||
import("./dialog-zha-device-zigbee-info");
|
|
||||||
|
|
||||||
export const showZHADeviceZigbeeInfoDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
zhaDeviceZigbeeInfoParams: ZHADeviceZigbeeInfoDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-zha-device-zigbee-info",
|
|
||||||
dialogImport: loadZHADeviceZigbeeInfoDialog,
|
|
||||||
dialogParams: zhaDeviceZigbeeInfoParams,
|
|
||||||
});
|
|
||||||
};
|
|
@ -0,0 +1,23 @@
|
|||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
import { ZHADevice } from "../../../../../data/zha";
|
||||||
|
|
||||||
|
export type Tab = "clusters" | "bindings" | "signature" | "children";
|
||||||
|
|
||||||
|
export interface ZHAManageZigbeeDeviceDialogParams {
|
||||||
|
device: ZHADevice;
|
||||||
|
tab?: Tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadZHAManageZigbeeDeviceDialog = () =>
|
||||||
|
import("./dialog-zha-manage-zigbee-device");
|
||||||
|
|
||||||
|
export const showZHAManageZigbeeDeviceDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
params: ZHAManageZigbeeDeviceDialogParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-zha-manage-zigbee-device",
|
||||||
|
dialogImport: loadZHAManageZigbeeDeviceDialog,
|
||||||
|
dialogParams: params,
|
||||||
|
});
|
||||||
|
};
|
@ -1,5 +1,5 @@
|
|||||||
import { HaSelect } from "../../../../../components/ha-select";
|
import { HaSelect } from "../../../../../components/ha-select";
|
||||||
import { Cluster, ZHADevice } from "../../../../../data/zha";
|
import { ZHADevice } from "../../../../../data/zha";
|
||||||
|
|
||||||
export interface ItemSelectedEvent {
|
export interface ItemSelectedEvent {
|
||||||
target?: HaSelect;
|
target?: HaSelect;
|
||||||
@ -41,10 +41,6 @@ export interface ZHADeviceSelectedParams {
|
|||||||
node: ZHADevice;
|
node: ZHADevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ZHAClusterSelectedParams {
|
|
||||||
cluster: Cluster;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NodeServiceData {
|
export interface NodeServiceData {
|
||||||
ieee_address: string;
|
ieee_address: string;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import "@material/mwc-button";
|
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
@ -10,13 +8,12 @@ import {
|
|||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-call-service-button";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-select";
|
import "../../../../../components/ha-select";
|
||||||
import "../../../../../components/ha-service-description";
|
import "../../../../../components/buttons/ha-progress-button";
|
||||||
import {
|
import {
|
||||||
Attribute,
|
Attribute,
|
||||||
Cluster,
|
Cluster,
|
||||||
@ -27,7 +24,7 @@ import {
|
|||||||
} from "../../../../../data/zha";
|
} from "../../../../../data/zha";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
import { forwardHaptic } from "../../../../../data/haptics";
|
||||||
import { formatAsPaddedHex } from "./functions";
|
import { formatAsPaddedHex } from "./functions";
|
||||||
import {
|
import {
|
||||||
ChangeEvent,
|
ChangeEvent,
|
||||||
@ -35,18 +32,15 @@ import {
|
|||||||
SetAttributeServiceData,
|
SetAttributeServiceData,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
|
@customElement("zha-cluster-attributes")
|
||||||
export class ZHAClusterAttributes extends LitElement {
|
export class ZHAClusterAttributes extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() public isWide?: boolean;
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
@property() public showHelp = false;
|
|
||||||
|
|
||||||
@property() public selectedNode?: ZHADevice;
|
|
||||||
|
|
||||||
@property() public selectedCluster?: Cluster;
|
@property() public selectedCluster?: Cluster;
|
||||||
|
|
||||||
@state() private _attributes: Attribute[] = [];
|
@state() private _attributes: Attribute[] | undefined;
|
||||||
|
|
||||||
@state() private _selectedAttributeId?: number;
|
@state() private _selectedAttributeId?: number;
|
||||||
|
|
||||||
@ -54,42 +48,26 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
|
|
||||||
@state() private _manufacturerCodeOverride?: string | number;
|
@state() private _manufacturerCodeOverride?: string | number;
|
||||||
|
|
||||||
|
@state() private _readingAttribute = false;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _setAttributeServiceData?: SetAttributeServiceData;
|
private _setAttributeServiceData?: SetAttributeServiceData;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("selectedCluster")) {
|
if (changedProperties.has("selectedCluster")) {
|
||||||
this._attributes = [];
|
this._attributes = undefined;
|
||||||
this._selectedAttributeId = undefined;
|
this._selectedAttributeId = undefined;
|
||||||
this._attributeValue = "";
|
this._attributeValue = "";
|
||||||
this._fetchAttributesForCluster();
|
this._fetchAttributesForCluster();
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.updated(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (!this.device || !this.selectedCluster || !this._attributes) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="header" slot="header">
|
|
||||||
<span>
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_attributes.header"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_attributes.introduction"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="attribute-picker">
|
<div class="attribute-picker">
|
||||||
<ha-select
|
<ha-select
|
||||||
@ -106,26 +84,16 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
${this._attributes.map(
|
${this._attributes.map(
|
||||||
(entry) => html`
|
(entry) => html`
|
||||||
<mwc-list-item .value=${String(entry.id)}>
|
<mwc-list-item .value=${String(entry.id)}>
|
||||||
${entry.name + " (id: " + formatAsPaddedHex(entry.id) + ")"}
|
${`${entry.name} (id: ${formatAsPaddedHex(entry.id)})`}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
</div>
|
</div>
|
||||||
${this.showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_attributes.help_attribute_dropdown"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._selectedAttributeId !== undefined
|
${this._selectedAttributeId !== undefined
|
||||||
? this._renderAttributeInteractions()
|
? this._renderAttributeInteractions()
|
||||||
: ""}
|
: ""}
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,20 +120,15 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
></paper-input>
|
></paper-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button @click=${this._onGetZigbeeAttributeClick}>
|
<ha-progress-button
|
||||||
|
@click=${this._onGetZigbeeAttributeClick}
|
||||||
|
.progress=${this._readingAttribute}
|
||||||
|
.disabled=${this._readingAttribute}
|
||||||
|
>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.cluster_attributes.get_zigbee_attribute"
|
"ui.panel.config.zha.cluster_attributes.read_zigbee_attribute"
|
||||||
)}
|
)}
|
||||||
</mwc-button>
|
</ha-progress-button>
|
||||||
${this.showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text2">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_attributes.help_get_zigbee_attribute"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<ha-call-service-button
|
<ha-call-service-button
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
domain="zha"
|
domain="zha"
|
||||||
@ -173,44 +136,37 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
.serviceData=${this._setAttributeServiceData}
|
.serviceData=${this._setAttributeServiceData}
|
||||||
>
|
>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.cluster_attributes.set_zigbee_attribute"
|
"ui.panel.config.zha.cluster_attributes.write_zigbee_attribute"
|
||||||
)}
|
)}
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
${this.showHelp
|
|
||||||
? html`
|
|
||||||
<ha-service-description
|
|
||||||
.hass=${this.hass}
|
|
||||||
domain="zha"
|
|
||||||
service="set_zigbee_cluster_attribute"
|
|
||||||
class="help-text2"
|
|
||||||
></ha-service-description>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchAttributesForCluster(): Promise<void> {
|
private async _fetchAttributesForCluster(): Promise<void> {
|
||||||
if (this.selectedNode && this.selectedCluster && this.hass) {
|
if (this.device && this.selectedCluster && this.hass) {
|
||||||
this._attributes = await fetchAttributesForCluster(
|
this._attributes = await fetchAttributesForCluster(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedNode!.ieee,
|
this.device!.ieee,
|
||||||
this.selectedCluster!.endpoint_id,
|
this.selectedCluster!.endpoint_id,
|
||||||
this.selectedCluster!.id,
|
this.selectedCluster!.id,
|
||||||
this.selectedCluster!.type
|
this.selectedCluster!.type
|
||||||
);
|
);
|
||||||
this._attributes.sort((a, b) => a.name.localeCompare(b.name));
|
this._attributes.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
if (this._attributes.length > 0) {
|
||||||
|
this._selectedAttributeId = this._attributes[0].id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeReadAttributeServiceData():
|
private _computeReadAttributeServiceData():
|
||||||
| ReadAttributeServiceData
|
| ReadAttributeServiceData
|
||||||
| undefined {
|
| undefined {
|
||||||
if (!this.selectedCluster || !this.selectedNode) {
|
if (!this.selectedCluster || !this.device) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ieee: this.selectedNode!.ieee,
|
ieee: this.device!.ieee,
|
||||||
endpoint_id: this.selectedCluster!.endpoint_id,
|
endpoint_id: this.selectedCluster!.endpoint_id,
|
||||||
cluster_id: this.selectedCluster!.id,
|
cluster_id: this.selectedCluster!.id,
|
||||||
cluster_type: this.selectedCluster!.type,
|
cluster_type: this.selectedCluster!.type,
|
||||||
@ -224,11 +180,11 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
private _computeSetAttributeServiceData():
|
private _computeSetAttributeServiceData():
|
||||||
| SetAttributeServiceData
|
| SetAttributeServiceData
|
||||||
| undefined {
|
| undefined {
|
||||||
if (!this.selectedCluster || !this.selectedNode) {
|
if (!this.selectedCluster || !this.device) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ieee: this.selectedNode!.ieee,
|
ieee: this.device!.ieee,
|
||||||
endpoint_id: this.selectedCluster!.endpoint_id,
|
endpoint_id: this.selectedCluster!.endpoint_id,
|
||||||
cluster_id: this.selectedCluster!.id,
|
cluster_id: this.selectedCluster!.id,
|
||||||
cluster_type: this.selectedCluster!.type,
|
cluster_type: this.selectedCluster!.type,
|
||||||
@ -250,15 +206,22 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
this._setAttributeServiceData = this._computeSetAttributeServiceData();
|
this._setAttributeServiceData = this._computeSetAttributeServiceData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onGetZigbeeAttributeClick(): Promise<void> {
|
private async _onGetZigbeeAttributeClick(ev: CustomEvent): Promise<void> {
|
||||||
|
const button = ev.currentTarget as any;
|
||||||
const data = this._computeReadAttributeServiceData();
|
const data = this._computeReadAttributeServiceData();
|
||||||
if (data && this.hass) {
|
if (data && this.hass) {
|
||||||
|
this._readingAttribute = true;
|
||||||
|
try {
|
||||||
this._attributeValue = await readAttributeValue(this.hass, data);
|
this._attributeValue = await readAttributeValue(this.hass, data);
|
||||||
|
forwardHaptic("success");
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
forwardHaptic("failure");
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._readingAttribute = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
|
||||||
this.showHelp = !this.showHelp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _selectedAttributeChanged(event: ItemSelectedEvent): void {
|
private _selectedAttributeChanged(event: ItemSelectedEvent): void {
|
||||||
@ -278,14 +241,6 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
.card-actions.warning ha-call-service-button {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
@ -306,33 +261,6 @@ export class ZHAClusterAttributes extends LitElement {
|
|||||||
.header {
|
.header {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
float: right;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
padding-right: 0px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.help-text {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
.help-text2 {
|
|
||||||
color: grey;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -343,5 +271,3 @@ declare global {
|
|||||||
"zha-cluster-attributes": ZHAClusterAttributes;
|
"zha-cluster-attributes": ZHAClusterAttributes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("zha-cluster-attributes", ZHAClusterAttributes);
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
@ -13,9 +12,7 @@ import { property, state } from "lit/decorators";
|
|||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-call-service-button";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-select";
|
import "../../../../../components/ha-select";
|
||||||
import "../../../../../components/ha-service-description";
|
|
||||||
import {
|
import {
|
||||||
Cluster,
|
Cluster,
|
||||||
Command,
|
Command,
|
||||||
@ -24,7 +21,6 @@ import {
|
|||||||
} from "../../../../../data/zha";
|
} from "../../../../../data/zha";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
|
||||||
import { formatAsPaddedHex } from "./functions";
|
import { formatAsPaddedHex } from "./functions";
|
||||||
import { ChangeEvent, IssueCommandServiceData } from "./types";
|
import { ChangeEvent, IssueCommandServiceData } from "./types";
|
||||||
|
|
||||||
@ -33,13 +29,11 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
|
|
||||||
@property() public isWide?: boolean;
|
@property() public isWide?: boolean;
|
||||||
|
|
||||||
@property() public selectedNode?: ZHADevice;
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
@property() public selectedCluster?: Cluster;
|
@property() public selectedCluster?: Cluster;
|
||||||
|
|
||||||
@state() private _showHelp = false;
|
@state() private _commands: Command[] | undefined;
|
||||||
|
|
||||||
@state() private _commands: Command[] = [];
|
|
||||||
|
|
||||||
@state() private _selectedCommandId?: number;
|
@state() private _selectedCommandId?: number;
|
||||||
|
|
||||||
@ -50,36 +44,18 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("selectedCluster")) {
|
if (changedProperties.has("selectedCluster")) {
|
||||||
this._commands = [];
|
this._commands = undefined;
|
||||||
this._selectedCommandId = undefined;
|
this._selectedCommandId = undefined;
|
||||||
this._fetchCommandsForCluster();
|
this._fetchCommandsForCluster();
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.updated(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (!this.device || !this.selectedCluster || !this._commands) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="header" slot="header">
|
|
||||||
<span>
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_commands.header"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_commands.introduction"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<ha-select
|
<ha-select
|
||||||
@ -102,15 +78,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
</div>
|
</div>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.cluster_commands.help_command_dropdown"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._selectedCommandId !== undefined
|
${this._selectedCommandId !== undefined
|
||||||
? html`
|
? html`
|
||||||
<div class="input-text">
|
<div class="input-text">
|
||||||
@ -137,45 +104,37 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
"ui.panel.config.zha.cluster_commands.issue_zigbee_command"
|
"ui.panel.config.zha.cluster_commands.issue_zigbee_command"
|
||||||
)}
|
)}
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<ha-service-description
|
|
||||||
.hass=${this.hass}
|
|
||||||
domain="zha"
|
|
||||||
service="issue_zigbee_cluster_command"
|
|
||||||
class="help-text2"
|
|
||||||
></ha-service-description>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchCommandsForCluster(): Promise<void> {
|
private async _fetchCommandsForCluster(): Promise<void> {
|
||||||
if (this.selectedNode && this.selectedCluster && this.hass) {
|
if (this.device && this.selectedCluster && this.hass) {
|
||||||
this._commands = await fetchCommandsForCluster(
|
this._commands = await fetchCommandsForCluster(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedNode!.ieee,
|
this.device!.ieee,
|
||||||
this.selectedCluster!.endpoint_id,
|
this.selectedCluster!.endpoint_id,
|
||||||
this.selectedCluster!.id,
|
this.selectedCluster!.id,
|
||||||
this.selectedCluster!.type
|
this.selectedCluster!.type
|
||||||
);
|
);
|
||||||
this._commands.sort((a, b) => a.name.localeCompare(b.name));
|
this._commands.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
if (this._commands.length > 0) {
|
||||||
|
this._selectedCommandId = this._commands[0].id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeIssueClusterCommandServiceData():
|
private _computeIssueClusterCommandServiceData():
|
||||||
| IssueCommandServiceData
|
| IssueCommandServiceData
|
||||||
| undefined {
|
| undefined {
|
||||||
if (!this.selectedNode || !this.selectedCluster) {
|
if (!this.device || !this.selectedCluster || !this._commands) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ieee: this.selectedNode!.ieee,
|
ieee: this.device!.ieee,
|
||||||
endpoint_id: this.selectedCluster!.endpoint_id,
|
endpoint_id: this.selectedCluster!.endpoint_id,
|
||||||
cluster_id: this.selectedCluster!.id,
|
cluster_id: this.selectedCluster!.id,
|
||||||
cluster_type: this.selectedCluster!.type,
|
cluster_type: this.selectedCluster!.type,
|
||||||
@ -192,10 +151,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
this._computeIssueClusterCommandServiceData();
|
this._computeIssueClusterCommandServiceData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
|
||||||
this._showHelp = !this._showHelp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _selectedCommandChanged(event): void {
|
private _selectedCommandChanged(event): void {
|
||||||
this._selectedCommandId = Number(event.target.value);
|
this._selectedCommandId = Number(event.target.value);
|
||||||
this._issueClusterCommandServiceData =
|
this._issueClusterCommandServiceData =
|
||||||
@ -213,14 +168,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
.card-actions.warning ha-call-service-button {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
@ -238,18 +185,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-text {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text2 {
|
|
||||||
color: grey;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
@ -261,15 +196,6 @@ export class ZHAClusterCommands extends LitElement {
|
|||||||
padding-right: 0px;
|
padding-right: 0px;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ export class ZHAClustersDataTable extends LitElement {
|
|||||||
title: "ID",
|
title: "ID",
|
||||||
template: (id: number) => html` ${formatAsPaddedHex(id)} `,
|
template: (id: number) => html` ${formatAsPaddedHex(id)} `,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
width: "15%",
|
width: "25%",
|
||||||
},
|
},
|
||||||
endpoint_id: {
|
endpoint_id: {
|
||||||
title: "Endpoint ID",
|
title: "Endpoint ID",
|
||||||
|
@ -1,195 +0,0 @@
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import {
|
|
||||||
css,
|
|
||||||
CSSResultGroup,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
PropertyValues,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit";
|
|
||||||
import { property, state } from "lit/decorators";
|
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
|
||||||
import "../../../../../components/ha-card";
|
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-select";
|
|
||||||
import "../../../../../components/ha-service-description";
|
|
||||||
import {
|
|
||||||
Cluster,
|
|
||||||
fetchClustersForZhaNode,
|
|
||||||
ZHADevice,
|
|
||||||
} from "../../../../../data/zha";
|
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../../types";
|
|
||||||
import "../../../ha-config-section";
|
|
||||||
import { computeClusterKey } from "./functions";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// for fire event
|
|
||||||
interface HASSDomEvents {
|
|
||||||
"zha-cluster-selected": {
|
|
||||||
cluster?: Cluster;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ZHAClusters extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@property() public isWide?: boolean;
|
|
||||||
|
|
||||||
@property() public selectedDevice?: ZHADevice;
|
|
||||||
|
|
||||||
@property() public showHelp = false;
|
|
||||||
|
|
||||||
@state() private _selectedClusterIndex = -1;
|
|
||||||
|
|
||||||
@state() private _clusters: Cluster[] = [];
|
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
|
||||||
if (changedProperties.has("selectedDevice")) {
|
|
||||||
this._clusters = [];
|
|
||||||
this._selectedClusterIndex = -1;
|
|
||||||
fireEvent(this, "zha-cluster-selected", {
|
|
||||||
cluster: undefined,
|
|
||||||
});
|
|
||||||
this._fetchClustersForZhaNode();
|
|
||||||
}
|
|
||||||
super.update(changedProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="header" slot="header">
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">
|
|
||||||
${this.hass!.localize("ui.panel.config.zha.clusters.introduction")}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
|
||||||
<div class="node-picker">
|
|
||||||
<ha-select
|
|
||||||
.label=${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.common.clusters"
|
|
||||||
)}
|
|
||||||
class="menu"
|
|
||||||
.value=${String(this._selectedClusterIndex)}
|
|
||||||
@selected=${this._selectedClusterChanged}
|
|
||||||
@closed=${stopPropagation}
|
|
||||||
fixedMenuPosition
|
|
||||||
naturalMenuWidth
|
|
||||||
>
|
|
||||||
${this._clusters.map(
|
|
||||||
(entry, idx) => html`
|
|
||||||
<mwc-list-item .value=${String(idx)}
|
|
||||||
>${computeClusterKey(entry)}</mwc-list-item
|
|
||||||
>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-select>
|
|
||||||
</div>
|
|
||||||
${this.showHelp
|
|
||||||
? html`
|
|
||||||
<div class="help-text">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.clusters.help_cluster_dropdown"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</ha-card>
|
|
||||||
</ha-config-section>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _fetchClustersForZhaNode(): Promise<void> {
|
|
||||||
if (this.hass) {
|
|
||||||
this._clusters = await fetchClustersForZhaNode(
|
|
||||||
this.hass,
|
|
||||||
this.selectedDevice!.ieee
|
|
||||||
);
|
|
||||||
this._clusters.sort((a, b) => a.name.localeCompare(b.name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _selectedClusterChanged(event): void {
|
|
||||||
this._selectedClusterIndex = Number(event.target!.value);
|
|
||||||
fireEvent(this, "zha-cluster-selected", {
|
|
||||||
cluster: this._clusters[this._selectedClusterIndex],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
|
||||||
this.showHelp = !this.showHelp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return [
|
|
||||||
haStyle,
|
|
||||||
css`
|
|
||||||
ha-select {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.menu {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.node-picker {
|
|
||||||
align-items: center;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
float: right;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
padding-right: 0px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"zha-cluster": ZHAClusters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("zha-clusters", ZHAClusters);
|
|
@ -1,6 +1,4 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -11,26 +9,19 @@ import {
|
|||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-progress-button";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-select";
|
import "../../../../../components/ha-select";
|
||||||
import "../../../../../components/ha-service-description";
|
|
||||||
import { bindDevices, unbindDevices, ZHADevice } from "../../../../../data/zha";
|
import { bindDevices, unbindDevices, ZHADevice } from "../../../../../data/zha";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
|
||||||
import { ItemSelectedEvent } from "./types";
|
import { ItemSelectedEvent } from "./types";
|
||||||
|
|
||||||
@customElement("zha-device-binding-control")
|
@customElement("zha-device-binding-control")
|
||||||
export class ZHADeviceBindingControl extends LitElement {
|
export class ZHADeviceBindingControl extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() public isWide?: boolean;
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
@property() public selectedDevice?: ZHADevice;
|
|
||||||
|
|
||||||
@state() private _showHelp = false;
|
|
||||||
|
|
||||||
@state() private _bindTargetIndex = -1;
|
@state() private _bindTargetIndex = -1;
|
||||||
|
|
||||||
@ -38,32 +29,23 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
|
|
||||||
@state() private _deviceToBind?: ZHADevice;
|
@state() private _deviceToBind?: ZHADevice;
|
||||||
|
|
||||||
|
@state() private _bindingOperationInProgress = false;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("selectedDevice")) {
|
if (changedProperties.has("device")) {
|
||||||
this._bindTargetIndex = -1;
|
this._bindTargetIndex = -1;
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.updated(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="header" slot="header">
|
|
||||||
<span>Device Binding</span>
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction">Bind and unbind devices.</span>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<ha-select
|
<ha-select
|
||||||
label="Bindable Devices"
|
label=${this.hass!.localize(
|
||||||
|
"ui.panel.config.zha.device_binding.picker_label"
|
||||||
|
)}
|
||||||
class="menu"
|
class="menu"
|
||||||
.value=${String(this._bindTargetIndex)}
|
.value=${String(this._bindTargetIndex)}
|
||||||
@selected=${this._bindTargetIndexChanged}
|
@selected=${this._bindTargetIndexChanged}
|
||||||
@ -82,33 +64,23 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
</div>
|
</div>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
Select a device to issue a bind command.
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button
|
<ha-progress-button
|
||||||
@click=${this._onBindDevicesClick}
|
@click=${this._onBindDevicesClick}
|
||||||
.disabled=${!(this._deviceToBind && this.selectedDevice)}
|
.disabled=${!(this._deviceToBind && this.device) ||
|
||||||
>Bind</mwc-button
|
this._bindingOperationInProgress}
|
||||||
>
|
>
|
||||||
${this._showHelp
|
${this.hass!.localize("ui.panel.config.zha.device_binding.bind")}
|
||||||
? html` <div class="helpText">Bind devices.</div> `
|
</ha-progress-button>
|
||||||
: ""}
|
<ha-progress-button
|
||||||
<mwc-button
|
|
||||||
@click=${this._onUnbindDevicesClick}
|
@click=${this._onUnbindDevicesClick}
|
||||||
.disabled=${!(this._deviceToBind && this.selectedDevice)}
|
.disabled=${!(this._deviceToBind && this.device) ||
|
||||||
>Unbind</mwc-button
|
this._bindingOperationInProgress}
|
||||||
>
|
>
|
||||||
${this._showHelp
|
${this.hass!.localize("ui.panel.config.zha.device_binding.unbind")}
|
||||||
? html` <div class="helpText">Unbind devices.</div> `
|
</ha-progress-button>
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,27 +92,41 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
: this.bindableDevices[this._bindTargetIndex];
|
: this.bindableDevices[this._bindTargetIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
private async _onBindDevicesClick(ev: CustomEvent): Promise<void> {
|
||||||
this._showHelp = !this._showHelp;
|
const button = ev.currentTarget as any;
|
||||||
|
if (this.hass && this._deviceToBind && this.device) {
|
||||||
|
this._bindingOperationInProgress = true;
|
||||||
|
button.progress = true;
|
||||||
|
try {
|
||||||
|
await bindDevices(this.hass, this.device.ieee, this._deviceToBind.ieee);
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._bindingOperationInProgress = false;
|
||||||
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onBindDevicesClick(): Promise<void> {
|
|
||||||
if (this.hass && this._deviceToBind && this.selectedDevice) {
|
|
||||||
await bindDevices(
|
|
||||||
this.hass,
|
|
||||||
this.selectedDevice.ieee,
|
|
||||||
this._deviceToBind.ieee
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onUnbindDevicesClick(): Promise<void> {
|
private async _onUnbindDevicesClick(ev: CustomEvent): Promise<void> {
|
||||||
if (this.hass && this._deviceToBind && this.selectedDevice) {
|
const button = ev.currentTarget as any;
|
||||||
|
if (this.hass && this._deviceToBind && this.device) {
|
||||||
|
this._bindingOperationInProgress = true;
|
||||||
|
button.progress = true;
|
||||||
|
try {
|
||||||
await unbindDevices(
|
await unbindDevices(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedDevice.ieee,
|
this.device.ieee,
|
||||||
this._deviceToBind.ieee
|
this._deviceToBind.ieee
|
||||||
);
|
);
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._bindingOperationInProgress = false;
|
||||||
|
button.progress = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,18 +138,6 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
|
||||||
color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-picker {
|
.command-picker {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
@ -171,33 +145,9 @@ export class ZHADeviceBindingControl extends LitElement {
|
|||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.helpText {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
float: right;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
padding-right: 0px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { computeRTLDirection } from "../../../../../common/util/compute_rtl";
|
import { computeRTLDirection } from "../../../../../common/util/compute_rtl";
|
||||||
import "../../../../../components/ha-code-editor";
|
import "../../../../../components/ha-code-editor";
|
||||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
|
||||||
import { haStyleDialog } from "../../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import { ZHADeviceChildrenDialogParams } from "./show-dialog-zha-device-children";
|
|
||||||
import "../../../../../components/data-table/ha-data-table";
|
import "../../../../../components/data-table/ha-data-table";
|
||||||
import type {
|
import type {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
@ -14,7 +11,6 @@ import type {
|
|||||||
} from "../../../../../components/data-table/ha-data-table";
|
} from "../../../../../components/data-table/ha-data-table";
|
||||||
import "../../../../../components/ha-circular-progress";
|
import "../../../../../components/ha-circular-progress";
|
||||||
import { fetchDevices, ZHADevice } from "../../../../../data/zha";
|
import { fetchDevices, ZHADevice } from "../../../../../data/zha";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
|
||||||
|
|
||||||
export interface DeviceRowData extends DataTableRowData {
|
export interface DeviceRowData extends DataTableRowData {
|
||||||
id: string;
|
id: string;
|
||||||
@ -22,14 +18,21 @@ export interface DeviceRowData extends DataTableRowData {
|
|||||||
lqi: number;
|
lqi: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("dialog-zha-device-children")
|
@customElement("zha-device-children")
|
||||||
class DialogZHADeviceChildren extends LitElement {
|
class ZHADeviceChildren extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() private _device: ZHADevice | undefined;
|
@property() public device: ZHADevice | undefined;
|
||||||
|
|
||||||
@state() private _devices: Map<string, ZHADevice> | undefined;
|
@state() private _devices: Map<string, ZHADevice> | undefined;
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues) {
|
||||||
|
super.updated(changedProperties);
|
||||||
|
if (this.hass && changedProperties.has("device")) {
|
||||||
|
this._fetchData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _deviceChildren = memoizeOne(
|
private _deviceChildren = memoizeOne(
|
||||||
(
|
(
|
||||||
device: ZHADevice | undefined,
|
device: ZHADevice | undefined,
|
||||||
@ -69,31 +72,11 @@ class DialogZHADeviceChildren extends LitElement {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
public showDialog(params: ZHADeviceChildrenDialogParams): void {
|
|
||||||
this._device = params.device;
|
|
||||||
this._fetchData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeDialog(): void {
|
|
||||||
this._device = undefined;
|
|
||||||
this._devices = undefined;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._device) {
|
if (!this.device) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
|
||||||
hideActions
|
|
||||||
open
|
|
||||||
@closed=${this.closeDialog}
|
|
||||||
.heading=${createCloseHeading(
|
|
||||||
this.hass,
|
|
||||||
this.hass.localize(`ui.dialogs.zha_device_info.device_children`)
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
${!this._devices
|
${!this._devices
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
alt="Loading"
|
alt="Loading"
|
||||||
@ -103,7 +86,7 @@ class DialogZHADeviceChildren extends LitElement {
|
|||||||
: html`<ha-data-table
|
: html`<ha-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.columns=${this._columns}
|
.columns=${this._columns}
|
||||||
.data=${this._deviceChildren(this._device, this._devices)}
|
.data=${this._deviceChildren(this.device, this._devices)}
|
||||||
auto-height
|
auto-height
|
||||||
.dir=${computeRTLDirection(this.hass)}
|
.dir=${computeRTLDirection(this.hass)}
|
||||||
.searchLabel=${this.hass.localize(
|
.searchLabel=${this.hass.localize(
|
||||||
@ -113,26 +96,21 @@ class DialogZHADeviceChildren extends LitElement {
|
|||||||
"ui.components.data-table.no-data"
|
"ui.components.data-table.no-data"
|
||||||
)}
|
)}
|
||||||
></ha-data-table>`}
|
></ha-data-table>`}
|
||||||
</ha-dialog>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchData(): Promise<void> {
|
private async _fetchData(): Promise<void> {
|
||||||
if (this._device && this.hass) {
|
if (this.device && this.hass) {
|
||||||
const devices = await fetchDevices(this.hass!);
|
const devices = await fetchDevices(this.hass!);
|
||||||
this._devices = new Map(
|
this._devices = new Map(
|
||||||
devices.map((device: ZHADevice) => [device.ieee, device])
|
devices.map((device: ZHADevice) => [device.ieee, device])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return haStyleDialog;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"dialog-zha-device-children": DialogZHADeviceChildren;
|
"zha-device-children": ZHADeviceChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../../../components/ha-code-editor";
|
||||||
|
import { ZHADevice } from "../../../../../data/zha";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
|
||||||
|
@customElement("zha-device-zigbee-info")
|
||||||
|
class ZHADeviceZigbeeInfo extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public device: ZHADevice | undefined;
|
||||||
|
|
||||||
|
@state() private _signature: any;
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
|
if (changedProperties.has("device") && this.hass && this.device) {
|
||||||
|
this._signature = JSON.stringify(
|
||||||
|
{
|
||||||
|
...this.device.signature,
|
||||||
|
manufacturer: this.device.manufacturer,
|
||||||
|
model: this.device.model,
|
||||||
|
class: this.device.quirk_class,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
super.updated(changedProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._signature) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-code-editor mode="yaml" readOnly .value=${this._signature} dir="ltr">
|
||||||
|
</ha-code-editor>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"zha-device-zigbee-info": ZHADeviceZigbeeInfo;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
|
||||||
import { mdiHelpCircle } from "@mdi/js";
|
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -11,37 +9,29 @@ import {
|
|||||||
import { customElement, property, state, query } from "lit/decorators";
|
import { customElement, property, state, query } from "lit/decorators";
|
||||||
import type { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
import type { HASSDomEvent } from "../../../../../common/dom/fire_event";
|
||||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
import "../../../../../components/buttons/ha-call-service-button";
|
import "../../../../../components/buttons/ha-progress-button";
|
||||||
import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table";
|
import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
import "../../../../../components/ha-icon-button";
|
|
||||||
import "../../../../../components/ha-service-description";
|
|
||||||
import {
|
import {
|
||||||
bindDeviceToGroup,
|
bindDeviceToGroup,
|
||||||
Cluster,
|
Cluster,
|
||||||
fetchClustersForZhaNode,
|
fetchClustersForZhaDevice,
|
||||||
unbindDeviceFromGroup,
|
unbindDeviceFromGroup,
|
||||||
ZHADevice,
|
ZHADevice,
|
||||||
ZHAGroup,
|
ZHAGroup,
|
||||||
} from "../../../../../data/zha";
|
} from "../../../../../data/zha";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../../types";
|
import type { HomeAssistant } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
|
||||||
import { ItemSelectedEvent } from "./types";
|
import { ItemSelectedEvent } from "./types";
|
||||||
import "./zha-clusters-data-table";
|
import "./zha-clusters-data-table";
|
||||||
import type { ZHAClustersDataTable } from "./zha-clusters-data-table";
|
import type { ZHAClustersDataTable } from "./zha-clusters-data-table";
|
||||||
|
import "@material/mwc-list/mwc-list-item";
|
||||||
|
|
||||||
@customElement("zha-group-binding-control")
|
@customElement("zha-group-binding-control")
|
||||||
export class ZHAGroupBindingControl extends LitElement {
|
export class ZHAGroupBindingControl extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() public isWide?: boolean;
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
@property() public narrow?: boolean;
|
|
||||||
|
|
||||||
@property() public selectedDevice?: ZHADevice;
|
|
||||||
|
|
||||||
@state() private _showHelp = false;
|
|
||||||
|
|
||||||
@state() private _bindTargetIndex = -1;
|
@state() private _bindTargetIndex = -1;
|
||||||
|
|
||||||
@ -51,6 +41,8 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
|
|
||||||
@state() private _clusters: Cluster[] = [];
|
@state() private _clusters: Cluster[] = [];
|
||||||
|
|
||||||
|
@state() private _bindingOperationInProgress = false;
|
||||||
|
|
||||||
private _groupToBind?: ZHAGroup;
|
private _groupToBind?: ZHAGroup;
|
||||||
|
|
||||||
private _clustersToBind?: Cluster[];
|
private _clustersToBind?: Cluster[];
|
||||||
@ -59,38 +51,17 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
private _zhaClustersDataTable!: ZHAClustersDataTable;
|
private _zhaClustersDataTable!: ZHAClustersDataTable;
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
if (changedProperties.has("selectedDevice")) {
|
if (changedProperties.has("device")) {
|
||||||
this._bindTargetIndex = -1;
|
this._bindTargetIndex = -1;
|
||||||
this._selectedClusters = [];
|
this._selectedClusters = [];
|
||||||
this._clustersToBind = [];
|
this._clustersToBind = [];
|
||||||
this._fetchClustersForZhaNode();
|
this._fetchClustersForZhaNode();
|
||||||
}
|
}
|
||||||
super.update(changedProperties);
|
super.updated(changedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
|
||||||
<div class="sectionHeader" slot="header">
|
|
||||||
<span
|
|
||||||
>${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.header"
|
|
||||||
)}</span
|
|
||||||
>
|
|
||||||
<ha-icon-button
|
|
||||||
class="toggle-help-icon"
|
|
||||||
@click=${this._onHelpTap}
|
|
||||||
.path=${mdiHelpCircle}
|
|
||||||
.label=${this.hass!.localize("ui.common.help")}
|
|
||||||
>
|
|
||||||
</ha-icon-button>
|
|
||||||
</div>
|
|
||||||
<span slot="introduction"
|
|
||||||
>${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.introduction"
|
|
||||||
)}</span
|
|
||||||
>
|
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<ha-select
|
<ha-select
|
||||||
@ -112,66 +83,32 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-select>
|
</ha-select>
|
||||||
</div>
|
</div>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.group_picker_help"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<div class="command-picker">
|
<div class="command-picker">
|
||||||
<zha-clusters-data-table
|
<zha-clusters-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.narrow=${this.narrow}
|
|
||||||
.clusters=${this._clusters}
|
.clusters=${this._clusters}
|
||||||
@selection-changed=${this._handleClusterSelectionChanged}
|
@selection-changed=${this._handleClusterSelectionChanged}
|
||||||
class="menu"
|
class="menu"
|
||||||
></zha-clusters-data-table>
|
></zha-clusters-data-table>
|
||||||
</div>
|
</div>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.cluster_selection_help"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button
|
<ha-progress-button
|
||||||
@click=${this._onBindGroupClick}
|
@click=${this._onBindGroupClick}
|
||||||
.disabled=${!this._canBind}
|
.disabled=${!this._canBind || this._bindingOperationInProgress}
|
||||||
>${this.hass!.localize(
|
>
|
||||||
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.group_binding.bind_button_label"
|
"ui.panel.config.zha.group_binding.bind_button_label"
|
||||||
)}</mwc-button
|
|
||||||
>
|
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.bind_button_help"
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</ha-progress-button>
|
||||||
`
|
|
||||||
: ""}
|
<ha-progress-button
|
||||||
<mwc-button
|
|
||||||
@click=${this._onUnbindGroupClick}
|
@click=${this._onUnbindGroupClick}
|
||||||
.disabled=${!this._canBind}
|
.disabled=${!this._canBind || this._bindingOperationInProgress}
|
||||||
>${this.hass!.localize(
|
|
||||||
"ui.panel.config.zha.group_binding.unbind_button_label"
|
|
||||||
)}</mwc-button
|
|
||||||
>
|
>
|
||||||
${this._showHelp
|
|
||||||
? html`
|
|
||||||
<div class="helpText">
|
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.config.zha.group_binding.unbind_button_help"
|
"ui.panel.config.zha.group_binding.unbind_button_label"
|
||||||
)}
|
)}
|
||||||
</div>
|
</ha-progress-button>
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
@ -186,31 +123,49 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
: this.groups[this._bindTargetIndex];
|
: this.groups[this._bindTargetIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHelpTap(): void {
|
private async _onBindGroupClick(ev: CustomEvent): Promise<void> {
|
||||||
this._showHelp = !this._showHelp;
|
const button = ev.currentTarget as any;
|
||||||
}
|
|
||||||
|
|
||||||
private async _onBindGroupClick(): Promise<void> {
|
|
||||||
if (this.hass && this._canBind) {
|
if (this.hass && this._canBind) {
|
||||||
|
this._bindingOperationInProgress = true;
|
||||||
|
button.progress = true;
|
||||||
|
try {
|
||||||
await bindDeviceToGroup(
|
await bindDeviceToGroup(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedDevice!.ieee,
|
this.device!.ieee,
|
||||||
this._groupToBind!.group_id,
|
this._groupToBind!.group_id,
|
||||||
this._clustersToBind!
|
this._clustersToBind!
|
||||||
);
|
);
|
||||||
this._zhaClustersDataTable.clearSelection();
|
this._zhaClustersDataTable.clearSelection();
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._bindingOperationInProgress = false;
|
||||||
|
button.progress = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onUnbindGroupClick(): Promise<void> {
|
private async _onUnbindGroupClick(ev: CustomEvent): Promise<void> {
|
||||||
|
const button = ev.currentTarget as any;
|
||||||
if (this.hass && this._canBind) {
|
if (this.hass && this._canBind) {
|
||||||
|
this._bindingOperationInProgress = true;
|
||||||
|
button.progress = true;
|
||||||
|
try {
|
||||||
await unbindDeviceFromGroup(
|
await unbindDeviceFromGroup(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedDevice!.ieee,
|
this.device!.ieee,
|
||||||
this._groupToBind!.group_id,
|
this._groupToBind!.group_id,
|
||||||
this._clustersToBind!
|
this._clustersToBind!
|
||||||
);
|
);
|
||||||
this._zhaClustersDataTable.clearSelection();
|
this._zhaClustersDataTable.clearSelection();
|
||||||
|
button.actionSuccess();
|
||||||
|
} catch (err: any) {
|
||||||
|
button.actionError();
|
||||||
|
} finally {
|
||||||
|
this._bindingOperationInProgress = false;
|
||||||
|
button.progress = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,9 +185,9 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
|
|
||||||
private async _fetchClustersForZhaNode(): Promise<void> {
|
private async _fetchClustersForZhaNode(): Promise<void> {
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
this._clusters = await fetchClustersForZhaNode(
|
this._clusters = await fetchClustersForZhaDevice(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.selectedDevice!.ieee
|
this.device!.ieee
|
||||||
);
|
);
|
||||||
this._clusters = this._clusters
|
this._clusters = this._clusters
|
||||||
.filter((cluster) => cluster.type.toLowerCase() === "out")
|
.filter((cluster) => cluster.type.toLowerCase() === "out")
|
||||||
@ -245,7 +200,7 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
this._groupToBind &&
|
this._groupToBind &&
|
||||||
this._clustersToBind &&
|
this._clustersToBind &&
|
||||||
this._clustersToBind?.length > 0 &&
|
this._clustersToBind?.length > 0 &&
|
||||||
this.selectedDevice
|
this.device
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,18 +212,6 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-card {
|
|
||||||
max-width: 680px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions.warning ha-call-service-button {
|
|
||||||
color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.command-picker {
|
.command-picker {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
@ -285,30 +228,6 @@ export class ZHAGroupBindingControl extends LitElement {
|
|||||||
.sectionHeader {
|
.sectionHeader {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.helpText {
|
|
||||||
color: grey;
|
|
||||||
padding-left: 28px;
|
|
||||||
padding-right: 28px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-help-icon {
|
|
||||||
float: right;
|
|
||||||
top: -6px;
|
|
||||||
right: 0;
|
|
||||||
padding-right: 0px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-service-description {
|
|
||||||
display: block;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,198 @@
|
|||||||
|
import "@material/mwc-list/mwc-list-item";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { cache } from "lit/directives/cache";
|
||||||
|
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||||
|
import "../../../../../components/ha-card";
|
||||||
|
import "../../../../../components/ha-select";
|
||||||
|
import {
|
||||||
|
Cluster,
|
||||||
|
fetchClustersForZhaDevice,
|
||||||
|
ZHADevice,
|
||||||
|
} from "../../../../../data/zha";
|
||||||
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
import { computeClusterKey } from "./functions";
|
||||||
|
import "@material/mwc-tab-bar/mwc-tab-bar";
|
||||||
|
import "@material/mwc-tab/mwc-tab";
|
||||||
|
import "./zha-cluster-attributes";
|
||||||
|
import "./zha-cluster-commands";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// for fire event
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"zha-cluster-selected": {
|
||||||
|
cluster?: Cluster;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs = ["attributes", "commands"] as const;
|
||||||
|
|
||||||
|
@customElement("zha-manage-clusters")
|
||||||
|
export class ZHAManageClusters extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public isWide?: boolean;
|
||||||
|
|
||||||
|
@property() public device?: ZHADevice;
|
||||||
|
|
||||||
|
@state() private _selectedClusterIndex = -1;
|
||||||
|
|
||||||
|
@state() private _clusters: Cluster[] = [];
|
||||||
|
|
||||||
|
@state() private _selectedCluster?: Cluster;
|
||||||
|
|
||||||
|
@state() private _currTab: typeof tabs[number] = "attributes";
|
||||||
|
|
||||||
|
@state() private _clustersLoaded = false;
|
||||||
|
|
||||||
|
protected willUpdate(changedProps: PropertyValues) {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
|
if (!this.device) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!tabs.includes(this._currTab)) {
|
||||||
|
this._currTab = tabs[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
|
if (changedProperties.has("device")) {
|
||||||
|
this._clusters = [];
|
||||||
|
this._selectedClusterIndex = -1;
|
||||||
|
this._clustersLoaded = false;
|
||||||
|
this._fetchClustersForZhaDevice();
|
||||||
|
}
|
||||||
|
super.updated(changedProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.device || !this._clustersLoaded) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-card class="content">
|
||||||
|
<div class="node-picker">
|
||||||
|
<ha-select
|
||||||
|
.label=${this.hass!.localize("ui.panel.config.zha.common.clusters")}
|
||||||
|
class="menu"
|
||||||
|
.value=${String(this._selectedClusterIndex)}
|
||||||
|
@selected=${this._selectedClusterChanged}
|
||||||
|
@closed=${stopPropagation}
|
||||||
|
fixedMenuPosition
|
||||||
|
naturalMenuWidth
|
||||||
|
>
|
||||||
|
${this._clusters.map(
|
||||||
|
(entry, idx) => html`
|
||||||
|
<mwc-list-item .value=${String(idx)}
|
||||||
|
>${computeClusterKey(entry)}</mwc-list-item
|
||||||
|
>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-select>
|
||||||
|
</div>
|
||||||
|
${this._selectedCluster
|
||||||
|
? html`
|
||||||
|
<mwc-tab-bar
|
||||||
|
.activeIndex=${tabs.indexOf(this._currTab)}
|
||||||
|
@MDCTabBar:activated=${this._handleTabChanged}
|
||||||
|
>
|
||||||
|
${tabs.map(
|
||||||
|
(tab) => html`
|
||||||
|
<mwc-tab
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.panel.config.zha.clusters.tabs.${tab}`
|
||||||
|
)}
|
||||||
|
></mwc-tab>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</mwc-tab-bar>
|
||||||
|
|
||||||
|
<div class="content" tabindex="-1" dialogInitialFocus>
|
||||||
|
${cache(
|
||||||
|
this._currTab === "attributes"
|
||||||
|
? html`
|
||||||
|
<zha-cluster-attributes
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this.device}
|
||||||
|
.selectedCluster=${this._selectedCluster}
|
||||||
|
></zha-cluster-attributes>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<zha-cluster-commands
|
||||||
|
.hass=${this.hass}
|
||||||
|
.device=${this.device}
|
||||||
|
.selectedCluster=${this._selectedCluster}
|
||||||
|
></zha-cluster-commands>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _fetchClustersForZhaDevice(): Promise<void> {
|
||||||
|
if (this.hass) {
|
||||||
|
this._clusters = await fetchClustersForZhaDevice(
|
||||||
|
this.hass,
|
||||||
|
this.device!.ieee
|
||||||
|
);
|
||||||
|
this._clusters.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
if (this._clusters.length > 0) {
|
||||||
|
this._selectedClusterIndex = 0;
|
||||||
|
this._selectedCluster = this._clusters[0];
|
||||||
|
}
|
||||||
|
this._clustersLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleTabChanged(ev: CustomEvent): void {
|
||||||
|
const newTab = tabs[ev.detail.index];
|
||||||
|
if (newTab === this._currTab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._currTab = newTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _selectedClusterChanged(event): void {
|
||||||
|
this._selectedClusterIndex = Number(event.target!.value);
|
||||||
|
this._selectedCluster = this._clusters[this._selectedClusterIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
ha-select {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.menu {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.node-picker {
|
||||||
|
align-items: center;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"zha-manage-clusters": ZHAManageClusters;
|
||||||
|
}
|
||||||
|
}
|
@ -332,7 +332,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
"yaml-mode": this._mode === "yaml",
|
"yaml-mode": this._mode === "yaml",
|
||||||
})}"
|
})}"
|
||||||
>
|
>
|
||||||
${this._errors ? html`<div class="errors">${this._errors}</div>` : ""}
|
|
||||||
${this._mode === "gui"
|
${this._mode === "gui"
|
||||||
? html`
|
? html`
|
||||||
<div
|
<div
|
||||||
@ -343,6 +342,13 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
${this._config
|
${this._config
|
||||||
? html`
|
? html`
|
||||||
<div class="config-container">
|
<div class="config-container">
|
||||||
|
${this._errors
|
||||||
|
? html`
|
||||||
|
<ha-alert alert-type="error">
|
||||||
|
${this._errors}
|
||||||
|
</ha-alert>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
<ha-card outlined>
|
<ha-card outlined>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<ha-form
|
<ha-form
|
||||||
@ -382,6 +388,11 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
`
|
`
|
||||||
: this._mode === "yaml"
|
: this._mode === "yaml"
|
||||||
? html`
|
? html`
|
||||||
|
${this._errors
|
||||||
|
? html`
|
||||||
|
<ha-alert alert-type="error">${this._errors}</ha-alert>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
<ha-yaml-editor
|
<ha-yaml-editor
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.defaultValue=${this._preprocessYaml()}
|
.defaultValue=${this._preprocessYaml()}
|
||||||
@ -546,28 +557,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _modeChanged(mode) {
|
private _computeEntityIdFromAlias(alias: string) {
|
||||||
const curMode = this._config!.mode || MODES[0];
|
|
||||||
|
|
||||||
if (mode === curMode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._config = { ...this._config!, mode };
|
|
||||||
if (!isMaxMode(mode)) {
|
|
||||||
delete this._config.max;
|
|
||||||
}
|
|
||||||
this._dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _aliasChanged(alias: string) {
|
|
||||||
if (
|
|
||||||
this.scriptEntityId ||
|
|
||||||
(this._entityId && this._entityId !== slugify(this._config!.alias))
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const aliasSlugify = slugify(alias);
|
const aliasSlugify = slugify(alias);
|
||||||
let id = aliasSlugify;
|
let id = aliasSlugify;
|
||||||
let i = 2;
|
let i = 2;
|
||||||
@ -575,11 +565,10 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
id = `${aliasSlugify}_${i}`;
|
id = `${aliasSlugify}_${i}`;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
return id;
|
||||||
this._entityId = id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _idChanged(id: string) {
|
private _setEntityId(id?: string) {
|
||||||
this._entityId = id;
|
this._entityId = id;
|
||||||
if (this.hass.states[`script.${this._entityId}`]) {
|
if (this.hass.states[`script.${this._entityId}`]) {
|
||||||
this._idError = true;
|
this._idError = true;
|
||||||
@ -588,47 +577,60 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateEntityId(
|
||||||
|
newId: string | undefined,
|
||||||
|
newAlias: string | undefined
|
||||||
|
) {
|
||||||
|
const currentAlias = this._config?.alias ?? "";
|
||||||
|
const currentEntityId = this._entityId ?? "";
|
||||||
|
|
||||||
|
if (newId !== this._entityId) {
|
||||||
|
this._setEntityId(newId || undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentComputedEntity = this._computeEntityIdFromAlias(currentAlias);
|
||||||
|
|
||||||
|
if (currentComputedEntity === currentEntityId || !this._entityId) {
|
||||||
|
const newComputedId = newAlias
|
||||||
|
? this._computeEntityIdFromAlias(newAlias)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
this._setEntityId(newComputedId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _valueChanged(ev: CustomEvent) {
|
private _valueChanged(ev: CustomEvent) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
this._errors = undefined;
|
||||||
const values = ev.detail.value as any;
|
const values = ev.detail.value as any;
|
||||||
const currentId = this._entityId;
|
|
||||||
let changed = false;
|
let changed = false;
|
||||||
|
const newValues: Omit<ScriptConfig, "sequence"> = {
|
||||||
|
alias: values.alias ?? "",
|
||||||
|
icon: values.icon,
|
||||||
|
mode: values.mode,
|
||||||
|
max: isMaxMode(values.mode) ? values.max : undefined,
|
||||||
|
};
|
||||||
|
|
||||||
for (const key of Object.keys(values)) {
|
if (!this.scriptEntityId) {
|
||||||
if (key === "sequence") {
|
this.updateEntityId(values.id, values.alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of Object.keys(newValues)) {
|
||||||
|
const value = newValues[key];
|
||||||
|
|
||||||
|
if (value === this._config![key]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (value === undefined) {
|
||||||
const value = values[key];
|
|
||||||
|
|
||||||
if (
|
|
||||||
value === this._config![key] ||
|
|
||||||
(key === "id" && currentId === value)
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
changed = true;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case "id":
|
|
||||||
this._idChanged(value);
|
|
||||||
break;
|
|
||||||
case "alias":
|
|
||||||
this._aliasChanged(value);
|
|
||||||
break;
|
|
||||||
case "mode":
|
|
||||||
this._modeChanged(value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values[key] === undefined) {
|
|
||||||
const newConfig = { ...this._config! };
|
const newConfig = { ...this._config! };
|
||||||
delete newConfig![key];
|
delete newConfig![key];
|
||||||
this._config = newConfig;
|
this._config = newConfig;
|
||||||
} else {
|
} else {
|
||||||
this._config = { ...this._config!, [key]: value };
|
this._config = { ...this._config!, [key]: value };
|
||||||
}
|
}
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
@ -638,6 +640,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
private _configChanged(ev) {
|
private _configChanged(ev) {
|
||||||
this._config = ev.detail.value;
|
this._config = ev.detail.value;
|
||||||
|
this._errors = undefined;
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,7 +762,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
this.hass!.callApi("POST", "config/script/config/" + id, this._config).then(
|
this.hass!.callApi("POST", "config/script/config/" + id, this._config).then(
|
||||||
() => {
|
() => {
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
|
|
||||||
if (!this.scriptEntityId) {
|
if (!this.scriptEntityId) {
|
||||||
navigate(`/config/script/edit/${id}`, { replace: true });
|
navigate(`/config/script/edit/${id}`, { replace: true });
|
||||||
}
|
}
|
||||||
@ -806,6 +808,10 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
max-width: 1040px;
|
max-width: 1040px;
|
||||||
padding: 28px 20px 0;
|
padding: 28px 20px 0;
|
||||||
}
|
}
|
||||||
|
.config-container ha-alert {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
ha-yaml-editor {
|
ha-yaml-editor {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
--code-mirror-height: 100%;
|
--code-mirror-height: 100%;
|
||||||
|
@ -130,13 +130,18 @@ class MoveDatadiskDialog extends LitElement {
|
|||||||
@selected=${this._select_device}
|
@selected=${this._select_device}
|
||||||
@closed=${stopPropagation}
|
@closed=${stopPropagation}
|
||||||
dialogInitialFocus
|
dialogInitialFocus
|
||||||
|
fixedMenuPosition
|
||||||
>
|
>
|
||||||
${this._devices.map(
|
${this._devices.map(
|
||||||
(device) =>
|
(device) =>
|
||||||
html`<mwc-list-item .value=${device}
|
html`<mwc-list-item .value=${device}>
|
||||||
>${device}</mwc-list-item
|
${device}
|
||||||
>`
|
</mwc-list-item>`
|
||||||
)}
|
)}
|
||||||
|
<mwc-list-item>Test</mwc-list-item>
|
||||||
|
<mwc-list-item>Test</mwc-list-item>
|
||||||
|
<mwc-list-item>Test</mwc-list-item>
|
||||||
|
<mwc-list-item>Test</mwc-list-item>
|
||||||
</ha-select>
|
</ha-select>
|
||||||
|
|
||||||
<mwc-button
|
<mwc-button
|
||||||
@ -175,8 +180,9 @@ class MoveDatadiskDialog extends LitElement {
|
|||||||
),
|
),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
this.closeDialog();
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
this.closeDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { PropertyValues, ReactiveElement } from "lit";
|
import { PropertyValues, ReactiveElement } from "lit";
|
||||||
import { property } from "lit/decorators";
|
import { property } from "lit/decorators";
|
||||||
import { navigate, NavigateOptions } from "../../common/navigate";
|
import { navigate, NavigateOptions } from "../../common/navigate";
|
||||||
|
import { deepEqual } from "../../common/util/deep-equal";
|
||||||
import { CustomPanelInfo } from "../../data/panel_custom";
|
import { CustomPanelInfo } from "../../data/panel_custom";
|
||||||
import { HomeAssistant, Route } from "../../types";
|
import { HomeAssistant, Route } from "../../types";
|
||||||
import { createCustomPanelElement } from "../../util/custom-panel/create-custom-panel-element";
|
import { createCustomPanelElement } from "../../util/custom-panel/create-custom-panel-element";
|
||||||
@ -54,13 +55,16 @@ export class HaPanelCustom extends ReactiveElement {
|
|||||||
protected update(changedProps: PropertyValues) {
|
protected update(changedProps: PropertyValues) {
|
||||||
super.update(changedProps);
|
super.update(changedProps);
|
||||||
if (changedProps.has("panel")) {
|
if (changedProps.has("panel")) {
|
||||||
// Clean up old things if we had a panel
|
// Clean up old things if we had a panel and the new one is different.
|
||||||
if (changedProps.get("panel")) {
|
const oldPanel = changedProps.get("panel") as CustomPanelInfo | undefined;
|
||||||
|
if (!deepEqual(oldPanel, this.panel)) {
|
||||||
|
if (oldPanel) {
|
||||||
this._cleanupPanel();
|
this._cleanupPanel();
|
||||||
}
|
}
|
||||||
this._createPanel(this.panel);
|
this._createPanel(this.panel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!this._setProperties) {
|
if (!this._setProperties) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import "../../../../components/ha-form/ha-form";
|
|
||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { slugify } from "../../../../common/string/slugify";
|
import { slugify } from "../../../../common/string/slugify";
|
||||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
|
import "../../../../components/ha-form/ha-form";
|
||||||
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
||||||
import type { LovelaceViewConfig } from "../../../../data/lovelace";
|
import type { LovelaceViewConfig } from "../../../../data/lovelace";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
@ -33,7 +33,7 @@ export class HuiViewEditor extends LitElement {
|
|||||||
private _suggestedPath = false;
|
private _suggestedPath = false;
|
||||||
|
|
||||||
private _schema = memoizeOne(
|
private _schema = memoizeOne(
|
||||||
(localize: LocalizeFunc) =>
|
(localize: LocalizeFunc, subview: boolean, showAdvanced: boolean) =>
|
||||||
[
|
[
|
||||||
{ name: "title", selector: { text: {} } },
|
{ name: "title", selector: { text: {} } },
|
||||||
{
|
{
|
||||||
@ -63,6 +63,20 @@ export class HuiViewEditor extends LitElement {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "subview",
|
||||||
|
selector: {
|
||||||
|
boolean: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...(subview && showAdvanced
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
name: "back_path",
|
||||||
|
selector: { navigation: {} },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
] as const
|
] as const
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -84,7 +98,12 @@ export class HuiViewEditor extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
const schema = this._schema(this.hass.localize);
|
const schema = this._schema(
|
||||||
|
this.hass.localize,
|
||||||
|
this._config.subview ?? false,
|
||||||
|
this.hass.userData?.showAdvanced ?? false
|
||||||
|
);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
theme: "Backend-selected",
|
theme: "Backend-selected",
|
||||||
...this._config,
|
...this._config,
|
||||||
@ -96,18 +115,22 @@ export class HuiViewEditor extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.data=${data}
|
.data=${data}
|
||||||
.schema=${schema}
|
.schema=${schema}
|
||||||
.computeLabel=${this._computeLabelCallback}
|
.computeLabel=${this._computeLabel}
|
||||||
|
.computeHelper=${this._computeHelper}
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
></ha-form>
|
></ha-form>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _valueChanged(ev: CustomEvent): void {
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
const config = ev.detail.value;
|
const config = ev.detail.value as LovelaceViewConfig;
|
||||||
|
|
||||||
if (config.type === "masonry") {
|
if (config.type === "masonry") {
|
||||||
delete config.type;
|
delete config.type;
|
||||||
}
|
}
|
||||||
|
if (!config.subview) {
|
||||||
|
delete config.back_path;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.isNew &&
|
this.isNew &&
|
||||||
@ -122,7 +145,7 @@ export class HuiViewEditor extends LitElement {
|
|||||||
fireEvent(this, "view-config-changed", { config });
|
fireEvent(this, "view-config-changed", { config });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeLabelCallback = (
|
private _computeLabel = (
|
||||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||||
) => {
|
) => {
|
||||||
switch (schema.name) {
|
switch (schema.name) {
|
||||||
@ -130,12 +153,35 @@ export class HuiViewEditor extends LitElement {
|
|||||||
return this.hass!.localize("ui.panel.lovelace.editor.card.generic.url");
|
return this.hass!.localize("ui.panel.lovelace.editor.card.generic.url");
|
||||||
case "type":
|
case "type":
|
||||||
return this.hass.localize("ui.panel.lovelace.editor.edit_view.type");
|
return this.hass.localize("ui.panel.lovelace.editor.edit_view.type");
|
||||||
|
case "subview":
|
||||||
|
return this.hass.localize("ui.panel.lovelace.editor.edit_view.subview");
|
||||||
|
case "back_path":
|
||||||
|
return this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.edit_view.back_path"
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return this.hass!.localize(
|
return this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _computeHelper = (
|
||||||
|
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||||
|
) => {
|
||||||
|
switch (schema.name) {
|
||||||
|
case "subview":
|
||||||
|
return this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.edit_view.subview_helper"
|
||||||
|
);
|
||||||
|
case "back_path":
|
||||||
|
return this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.edit_view.back_path_helper"
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -112,6 +112,11 @@ class HUIRoot extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
const views = this.lovelace?.config.views ?? [];
|
||||||
|
|
||||||
|
const curViewConfig =
|
||||||
|
typeof this._curView === "number" ? views[this._curView] : undefined;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-app-layout
|
<ha-app-layout
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
@ -229,11 +234,21 @@ class HUIRoot extends LitElement {
|
|||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<app-toolbar>
|
<app-toolbar>
|
||||||
|
${curViewConfig?.subview
|
||||||
|
? html`
|
||||||
|
<ha-icon-button-arrow-prev
|
||||||
|
@click=${this._goBack}
|
||||||
|
></ha-icon-button-arrow-prev>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
<ha-menu-button
|
<ha-menu-button
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
></ha-menu-button>
|
></ha-menu-button>
|
||||||
${this.lovelace!.config.views.length > 1
|
`}
|
||||||
|
${curViewConfig?.subview
|
||||||
|
? html`<div main-title>${curViewConfig.title}</div>`
|
||||||
|
: views.filter((view) => !view.subview).length > 1
|
||||||
? html`
|
? html`
|
||||||
<ha-tabs
|
<ha-tabs
|
||||||
scrollable
|
scrollable
|
||||||
@ -241,18 +256,20 @@ class HUIRoot extends LitElement {
|
|||||||
@iron-activate=${this._handleViewSelected}
|
@iron-activate=${this._handleViewSelected}
|
||||||
dir=${computeRTLDirection(this.hass!)}
|
dir=${computeRTLDirection(this.hass!)}
|
||||||
>
|
>
|
||||||
${this.lovelace!.config.views.map(
|
${views.map(
|
||||||
(view) => html`
|
(view) => html`
|
||||||
<paper-tab
|
<paper-tab
|
||||||
aria-label=${ifDefined(view.title)}
|
aria-label=${ifDefined(view.title)}
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
"hide-tab": Boolean(
|
"hide-tab": Boolean(
|
||||||
view.visible !== undefined &&
|
view.subview ||
|
||||||
|
(view.visible !== undefined &&
|
||||||
((Array.isArray(view.visible) &&
|
((Array.isArray(view.visible) &&
|
||||||
!view.visible.some(
|
!view.visible.some(
|
||||||
(e) => e.user === this.hass!.user!.id
|
(e) =>
|
||||||
|
e.user === this.hass!.user!.id
|
||||||
)) ||
|
)) ||
|
||||||
view.visible === false)
|
view.visible === false))
|
||||||
),
|
),
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@ -473,7 +490,7 @@ class HUIRoot extends LitElement {
|
|||||||
@iron-activate=${this._handleViewSelected}
|
@iron-activate=${this._handleViewSelected}
|
||||||
dir=${computeRTLDirection(this.hass!)}
|
dir=${computeRTLDirection(this.hass!)}
|
||||||
>
|
>
|
||||||
${this.lovelace!.config.views.map(
|
${views.map(
|
||||||
(view) => html`
|
(view) => html`
|
||||||
<paper-tab
|
<paper-tab
|
||||||
aria-label=${ifDefined(view.title)}
|
aria-label=${ifDefined(view.title)}
|
||||||
@ -505,6 +522,9 @@ class HUIRoot extends LitElement {
|
|||||||
${view.icon
|
${view.icon
|
||||||
? html`
|
? html`
|
||||||
<ha-icon
|
<ha-icon
|
||||||
|
class=${classMap({
|
||||||
|
"child-view-icon": Boolean(view.subview),
|
||||||
|
})}
|
||||||
title=${ifDefined(view.title)}
|
title=${ifDefined(view.title)}
|
||||||
.icon=${view.icon}
|
.icon=${view.icon}
|
||||||
></ha-icon>
|
></ha-icon>
|
||||||
@ -528,7 +548,7 @@ class HUIRoot extends LitElement {
|
|||||||
class="edit-icon view"
|
class="edit-icon view"
|
||||||
@click=${this._moveViewRight}
|
@click=${this._moveViewRight}
|
||||||
?disabled=${(this._curView! as number) + 1 ===
|
?disabled=${(this._curView! as number) + 1 ===
|
||||||
this.lovelace!.config.views.length}
|
views.length}
|
||||||
></ha-icon-button-arrow-next>
|
></ha-icon-button-arrow-next>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@ -720,6 +740,20 @@ class HUIRoot extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _goBack(): void {
|
||||||
|
const views = this.lovelace?.config.views ?? [];
|
||||||
|
const curViewConfig =
|
||||||
|
typeof this._curView === "number" ? views[this._curView] : undefined;
|
||||||
|
|
||||||
|
if (curViewConfig?.back_path) {
|
||||||
|
navigate(curViewConfig.back_path);
|
||||||
|
} else if (history.length > 0) {
|
||||||
|
history.back();
|
||||||
|
} else {
|
||||||
|
navigate(views[0].path!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _handleRawEditor(ev: CustomEvent<RequestSelectedDetail>): void {
|
private _handleRawEditor(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||||
return;
|
return;
|
||||||
@ -1019,6 +1053,9 @@ class HUIRoot extends LitElement {
|
|||||||
--mdc-button-outline-color: var(--app-header-edit-text-color, #fff);
|
--mdc-button-outline-color: var(--app-header-edit-text-color, #fff);
|
||||||
--mdc-typography-button-font-size: 14px;
|
--mdc-typography-button-font-size: 14px;
|
||||||
}
|
}
|
||||||
|
.child-view-icon {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1002,6 +1002,15 @@
|
|||||||
"attribute": "Attribute",
|
"attribute": "Attribute",
|
||||||
"min_max_change": "min/max/change"
|
"min_max_change": "min/max/change"
|
||||||
},
|
},
|
||||||
|
"zha_manage_device": {
|
||||||
|
"heading": "Manage Zigbee Device",
|
||||||
|
"tabs": {
|
||||||
|
"clusters": "Clusters",
|
||||||
|
"bindings": "Bindings",
|
||||||
|
"signature": "Signature",
|
||||||
|
"children": "Children"
|
||||||
|
}
|
||||||
|
},
|
||||||
"zha_device_info": {
|
"zha_device_info": {
|
||||||
"manuf": "by {manufacturer}",
|
"manuf": "by {manufacturer}",
|
||||||
"no_area": "No Area",
|
"no_area": "No Area",
|
||||||
@ -1010,10 +1019,8 @@
|
|||||||
"buttons": {
|
"buttons": {
|
||||||
"add": "Add devices via this device",
|
"add": "Add devices via this device",
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
"clusters": "Manage clusters",
|
"manage": "Manage zigbee device",
|
||||||
"reconfigure": "Reconfigure",
|
"reconfigure": "Reconfigure",
|
||||||
"zigbee_information": "Zigbee signature",
|
|
||||||
"device_children": "View children",
|
|
||||||
"view_network": "View network"
|
"view_network": "View network"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
@ -1796,7 +1803,8 @@
|
|||||||
"dev_automation": "Debug automation",
|
"dev_automation": "Debug automation",
|
||||||
"show_info_automation": "Show info about automation",
|
"show_info_automation": "Show info about automation",
|
||||||
"delete": "[%key:ui::common::delete%]",
|
"delete": "[%key:ui::common::delete%]",
|
||||||
"delete_confirm": "Are you sure you want to delete this automation?",
|
"delete_confirm_title": "Delete automation?",
|
||||||
|
"delete_confirm_text": "{name} will be permanently deleted.",
|
||||||
"duplicate": "[%key:ui::common::duplicate%]",
|
"duplicate": "[%key:ui::common::duplicate%]",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"headers": {
|
"headers": {
|
||||||
@ -2257,15 +2265,15 @@
|
|||||||
"add": {
|
"add": {
|
||||||
"header": "Import a blueprint",
|
"header": "Import a blueprint",
|
||||||
"import_header": "Blueprint ''{name}''",
|
"import_header": "Blueprint ''{name}''",
|
||||||
"import_introduction_link": "You can import blueprints of other users from Github and the {community_link}. Enter the URL of the blueprint below.",
|
"import_introduction": "Import blueprints of other users from GitHub and the community forums by pasting the address below.",
|
||||||
"community_forums": "community forums",
|
"community_forums": "View blueprints on the community forums",
|
||||||
"url": "URL of the blueprint",
|
"url": "Blueprint address",
|
||||||
"raw_blueprint": "Blueprint content",
|
"raw_blueprint": "Blueprint content",
|
||||||
"importing": "Loading blueprint…",
|
"importing": "Loading blueprint…",
|
||||||
"import_btn": "Preview blueprint",
|
"import_btn": "Preview",
|
||||||
"saving": "Importing blueprint…",
|
"saving": "Importing blueprint…",
|
||||||
"save_btn": "Import blueprint",
|
"save_btn": "Import blueprint",
|
||||||
"error_no_url": "Please enter the URL of the blueprint.",
|
"error_no_url": "Please enter the blueprint address.",
|
||||||
"unsupported_blueprint": "This blueprint is not supported",
|
"unsupported_blueprint": "This blueprint is not supported",
|
||||||
"file_name": "Blueprint Path"
|
"file_name": "Blueprint Path"
|
||||||
}
|
}
|
||||||
@ -3013,12 +3021,16 @@
|
|||||||
"caption": "Application Credentials",
|
"caption": "Application Credentials",
|
||||||
"description": "Manage the OAuth Application Credentials used by Integrations",
|
"description": "Manage the OAuth Application Credentials used by Integrations",
|
||||||
"editor": {
|
"editor": {
|
||||||
"caption": "Add Application Credential",
|
"caption": "Add Credential",
|
||||||
"create": "Create",
|
"description": "OAuth is used to grant Home Assistant access to information on other websites without giving a passwords. This mechanism is used by companies such as Spotify, Google, Withings, Microsoft, and Twitter.",
|
||||||
|
"view_documentation": "View documentation",
|
||||||
|
"add": "Add",
|
||||||
"domain": "Integration",
|
"domain": "Integration",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"client_id": "OAuth Client ID",
|
"client_id": "OAuth Client ID",
|
||||||
"client_secret": "OAuth Client Secret"
|
"client_id_helper": "Public identifier of the OAuth application",
|
||||||
|
"client_secret": "OAuth Client Secret",
|
||||||
|
"client_secret_helper": "Secret of the OAuth application"
|
||||||
},
|
},
|
||||||
"picker": {
|
"picker": {
|
||||||
"add_application_credential": "Add Application Credential",
|
"add_application_credential": "Add Application Credential",
|
||||||
@ -3073,17 +3085,17 @@
|
|||||||
"clusters": {
|
"clusters": {
|
||||||
"header": "Clusters",
|
"header": "Clusters",
|
||||||
"help_cluster_dropdown": "Select a cluster to view attributes and commands.",
|
"help_cluster_dropdown": "Select a cluster to view attributes and commands.",
|
||||||
"introduction": "Clusters are the building blocks for Zigbee functionality. They separate functionality into logical units. There are client and server types and that are comprised of attributes and commands."
|
"tabs": {
|
||||||
|
"attributes": "Attributes",
|
||||||
|
"commands": "Commands"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"cluster_attributes": {
|
"cluster_attributes": {
|
||||||
"header": "Cluster Attributes",
|
"header": "Cluster Attributes",
|
||||||
"introduction": "View and edit cluster attributes.",
|
"introduction": "View and edit cluster attributes.",
|
||||||
"attributes_of_cluster": "Attributes of the selected cluster",
|
"attributes_of_cluster": "Attributes of the selected cluster",
|
||||||
"get_zigbee_attribute": "Get Zigbee Attribute",
|
"read_zigbee_attribute": "Read Attribute",
|
||||||
"set_zigbee_attribute": "Set Zigbee Attribute",
|
"write_zigbee_attribute": "Write Attribute"
|
||||||
"help_attribute_dropdown": "Select an attribute to view or set its value.",
|
|
||||||
"help_get_zigbee_attribute": "Get the value for the selected attribute.",
|
|
||||||
"help_set_zigbee_attribute": "Set attribute value for the specified cluster on the specified entity."
|
|
||||||
},
|
},
|
||||||
"cluster_commands": {
|
"cluster_commands": {
|
||||||
"header": "Cluster Commands",
|
"header": "Cluster Commands",
|
||||||
@ -3133,6 +3145,11 @@
|
|||||||
"enable_physics": "Enable Physics",
|
"enable_physics": "Enable Physics",
|
||||||
"refresh_topology": "Refresh Topology"
|
"refresh_topology": "Refresh Topology"
|
||||||
},
|
},
|
||||||
|
"device_binding": {
|
||||||
|
"bind": "Bind",
|
||||||
|
"unbind": "Unbind",
|
||||||
|
"picker_label": "Bindable Devices"
|
||||||
|
},
|
||||||
"group_binding": {
|
"group_binding": {
|
||||||
"header": "Group Binding",
|
"header": "Group Binding",
|
||||||
"introduction": "Bind and unbind groups.",
|
"introduction": "Bind and unbind groups.",
|
||||||
@ -3748,7 +3765,11 @@
|
|||||||
"masonry": "Masonry (default)",
|
"masonry": "Masonry (default)",
|
||||||
"sidebar": "Sidebar",
|
"sidebar": "Sidebar",
|
||||||
"panel": "Panel (1 card)"
|
"panel": "Panel (1 card)"
|
||||||
}
|
},
|
||||||
|
"subview": "Subview",
|
||||||
|
"subview_helper": "Subviews don't appear in tabs and have a back button.",
|
||||||
|
"back_path": "Back path (optional)",
|
||||||
|
"back_path_helper": "Only for subviews. If empty, clicking on back button will go to the previous page."
|
||||||
},
|
},
|
||||||
"edit_badges": {
|
"edit_badges": {
|
||||||
"view_no_badges": "Badges are not be supported by the current view type."
|
"view_no_badges": "Badges are not be supported by the current view type."
|
||||||
|
Loading…
x
Reference in New Issue
Block a user