20230928.0 (#18052)
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 10 KiB |
@ -182,7 +182,7 @@
|
||||
"@types/luxon": "3.3.2",
|
||||
"@types/mocha": "10.0.1",
|
||||
"@types/qrcode": "1.5.2",
|
||||
"@types/serve-handler": "6.1.1",
|
||||
"@types/serve-handler": "6.1.2",
|
||||
"@types/sortablejs": "1.15.2",
|
||||
"@types/tar": "6.1.6",
|
||||
"@types/ua-parser-js": "0.7.37",
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 992 B |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 561 B After Width: | Height: | Size: 477 B |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 850 B After Width: | Height: | Size: 597 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 686 B |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.3 KiB |
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20230926.0"
|
||||
version = "20230928.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "The Home Assistant frontend"
|
||||
readme = "README.md"
|
||||
|
@ -138,41 +138,54 @@ const tryDescribeTrigger = (
|
||||
|
||||
// Numeric State Trigger
|
||||
if (trigger.platform === "numeric_state" && trigger.entity_id) {
|
||||
let base = "When";
|
||||
const stateObj = hass.states[trigger.entity_id];
|
||||
const entity = stateObj ? computeStateName(stateObj) : trigger.entity_id;
|
||||
|
||||
if (trigger.attribute) {
|
||||
base += ` ${computeAttributeNameDisplay(
|
||||
hass.localize,
|
||||
stateObj,
|
||||
hass.entities,
|
||||
trigger.attribute
|
||||
)} from`;
|
||||
const attribute = trigger.attribute
|
||||
? computeAttributeNameDisplay(
|
||||
hass.localize,
|
||||
stateObj,
|
||||
hass.entities,
|
||||
trigger.attribute
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const duration = trigger.for ? describeDuration(trigger.for) : undefined;
|
||||
|
||||
if (trigger.above && trigger.below) {
|
||||
return hass.localize(
|
||||
`${triggerTranslationBaseKey}.numeric_state.description.above-below`,
|
||||
{
|
||||
attribute: attribute,
|
||||
entity: entity,
|
||||
above: trigger.above,
|
||||
below: trigger.below,
|
||||
duration: duration,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
base += ` ${entity} is`;
|
||||
|
||||
if (trigger.above !== undefined) {
|
||||
base += ` above ${trigger.above}`;
|
||||
if (trigger.above) {
|
||||
return hass.localize(
|
||||
`${triggerTranslationBaseKey}.numeric_state.description.above`,
|
||||
{
|
||||
attribute: attribute,
|
||||
entity: entity,
|
||||
above: trigger.above,
|
||||
duration: duration,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (trigger.below !== undefined && trigger.above !== undefined) {
|
||||
base += " and";
|
||||
if (trigger.below) {
|
||||
return hass.localize(
|
||||
`${triggerTranslationBaseKey}.numeric_state.description.below`,
|
||||
{
|
||||
attribute: attribute,
|
||||
entity: entity,
|
||||
below: trigger.below,
|
||||
duration: duration,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (trigger.below !== undefined) {
|
||||
base += ` below ${trigger.below}`;
|
||||
}
|
||||
|
||||
if (trigger.for) {
|
||||
const duration = describeDuration(trigger.for);
|
||||
if (duration) {
|
||||
base += ` for ${duration}`;
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// State Trigger
|
||||
@ -825,29 +838,49 @@ const tryDescribeCondition = (
|
||||
|
||||
// Numeric State Condition
|
||||
if (condition.condition === "numeric_state" && condition.entity_id) {
|
||||
let base = "Confirm";
|
||||
const stateObj = hass.states[condition.entity_id];
|
||||
const entity = stateObj ? computeStateName(stateObj) : condition.entity_id;
|
||||
|
||||
if ("attribute" in condition) {
|
||||
base += ` ${condition.attribute} from`;
|
||||
const attribute = condition.attribute
|
||||
? computeAttributeNameDisplay(
|
||||
hass.localize,
|
||||
stateObj,
|
||||
hass.entities,
|
||||
condition.attribute
|
||||
)
|
||||
: undefined;
|
||||
|
||||
if (condition.above && condition.below) {
|
||||
return hass.localize(
|
||||
`${conditionsTranslationBaseKey}.numeric_state.description.above-below`,
|
||||
{
|
||||
attribute: attribute,
|
||||
entity: entity,
|
||||
above: condition.above,
|
||||
below: condition.below,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
base += ` ${entity} is`;
|
||||
|
||||
if ("above" in condition) {
|
||||
base += ` above ${condition.above}`;
|
||||
if (condition.above) {
|
||||
return hass.localize(
|
||||
`${conditionsTranslationBaseKey}.numeric_state.description.above`,
|
||||
{
|
||||
attribute: attribute,
|
||||
entity: entity,
|
||||
above: condition.above,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ("below" in condition && "above" in condition) {
|
||||
base += " and";
|
||||
if (condition.below) {
|
||||
return hass.localize(
|
||||
`${conditionsTranslationBaseKey}.numeric_state.description.below`,
|
||||
{
|
||||
attribute: attribute,
|
||||
entity: entity,
|
||||
below: condition.below,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ("below" in condition) {
|
||||
base += ` below ${condition.below}`;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// Time condition
|
||||
|
@ -192,7 +192,7 @@ export interface ZWaveJSController {
|
||||
supported_function_types: number[];
|
||||
suc_node_id: number;
|
||||
supports_timers: boolean;
|
||||
is_heal_network_active: boolean;
|
||||
is_rebuilding_routes: boolean;
|
||||
inclusion_state: InclusionState;
|
||||
nodes: ZWaveJSNodeStatus[];
|
||||
}
|
||||
@ -278,9 +278,9 @@ export interface ZWaveJSRefreshNodeStatusMessage {
|
||||
stage?: string;
|
||||
}
|
||||
|
||||
export interface ZWaveJSHealNetworkStatusMessage {
|
||||
export interface ZWaveJSRebuildRoutesStatusMessage {
|
||||
event: string;
|
||||
heal_node_status: { [key: number]: string };
|
||||
rebuild_routes_status: { [key: number]: string };
|
||||
}
|
||||
|
||||
export interface ZWaveJSControllerStatisticsUpdatedMessage {
|
||||
@ -651,12 +651,12 @@ export const reinterviewZwaveNode = (
|
||||
}
|
||||
);
|
||||
|
||||
export const healZwaveNode = (
|
||||
export const rebuildZwaveNodeRoutes = (
|
||||
hass: HomeAssistant,
|
||||
device_id: string
|
||||
): Promise<boolean> =>
|
||||
hass.callWS({
|
||||
type: "zwave_js/heal_node",
|
||||
type: "zwave_js/rebuild_node_routes",
|
||||
device_id,
|
||||
});
|
||||
|
||||
@ -673,33 +673,33 @@ export const removeFailedZwaveNode = (
|
||||
}
|
||||
);
|
||||
|
||||
export const healZwaveNetwork = (
|
||||
export const rebuildZwaveNetworkRoutes = (
|
||||
hass: HomeAssistant,
|
||||
entry_id: string
|
||||
): Promise<UnsubscribeFunc> =>
|
||||
hass.callWS({
|
||||
type: "zwave_js/begin_healing_network",
|
||||
type: "zwave_js/begin_rebuilding_routes",
|
||||
entry_id,
|
||||
});
|
||||
|
||||
export const stopHealZwaveNetwork = (
|
||||
export const stopRebuildingZwaveNetworkRoutes = (
|
||||
hass: HomeAssistant,
|
||||
entry_id: string
|
||||
): Promise<UnsubscribeFunc> =>
|
||||
hass.callWS({
|
||||
type: "zwave_js/stop_healing_network",
|
||||
type: "zwave_js/stop_rebuilding_routes",
|
||||
entry_id,
|
||||
});
|
||||
|
||||
export const subscribeHealZwaveNetworkProgress = (
|
||||
export const subscribeRebuildZwaveNetworkRoutesProgress = (
|
||||
hass: HomeAssistant,
|
||||
entry_id: string,
|
||||
callbackFunction: (message: ZWaveJSHealNetworkStatusMessage) => void
|
||||
callbackFunction: (message: ZWaveJSRebuildRoutesStatusMessage) => void
|
||||
): Promise<UnsubscribeFunc> =>
|
||||
hass.connection.subscribeMessage(
|
||||
(message: any) => callbackFunction(message),
|
||||
{
|
||||
type: "zwave_js/subscribe_heal_network_progress",
|
||||
type: "zwave_js/subscribe_rebuild_routes_progress",
|
||||
entry_id,
|
||||
}
|
||||
);
|
||||
|
@ -53,9 +53,8 @@ class DialogLightColorFavorite extends LitElement {
|
||||
): Promise<void> {
|
||||
this._entry = dialogParams.entry;
|
||||
this._dialogParams = dialogParams;
|
||||
this._color = dialogParams.initialColor ?? this._computeCurrentColor();
|
||||
this._updateModes();
|
||||
this._loadCurrentColorAndMode(dialogParams.add, dialogParams.defaultMode);
|
||||
await this.updateComplete;
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
@ -82,19 +81,20 @@ class DialogLightColorFavorite extends LitElement {
|
||||
}
|
||||
|
||||
this._modes = modes;
|
||||
|
||||
if (this._color) {
|
||||
this._mode = "color_temp_kelvin" in this._color ? "color_temp" : "color";
|
||||
} else {
|
||||
this._mode = this._modes[0];
|
||||
}
|
||||
}
|
||||
|
||||
private _loadCurrentColorAndMode(
|
||||
add?: boolean,
|
||||
defaultMode?: LightPickerMode
|
||||
) {
|
||||
private _computeCurrentColor() {
|
||||
const attributes = this.stateObj!.attributes;
|
||||
const color_mode = attributes.color_mode;
|
||||
|
||||
let currentColor: LightColor | undefined;
|
||||
let currentMode: LightPickerMode | undefined;
|
||||
if (color_mode === LightColorMode.XY) {
|
||||
currentMode = "color";
|
||||
// XY color not supported for favorites. Try to grab the hs or rgb instead.
|
||||
if (attributes.hs_color) {
|
||||
currentColor = { hs_color: attributes.hs_color };
|
||||
@ -105,21 +105,16 @@ class DialogLightColorFavorite extends LitElement {
|
||||
color_mode === LightColorMode.COLOR_TEMP &&
|
||||
attributes.color_temp_kelvin
|
||||
) {
|
||||
currentMode = LightColorMode.COLOR_TEMP;
|
||||
currentColor = {
|
||||
color_temp_kelvin: attributes.color_temp_kelvin,
|
||||
};
|
||||
} else if (attributes[color_mode + "_color"]) {
|
||||
currentMode = "color";
|
||||
currentColor = {
|
||||
[color_mode + "_color"]: attributes[color_mode + "_color"],
|
||||
} as LightColor;
|
||||
}
|
||||
|
||||
if (add) {
|
||||
this._color = currentColor;
|
||||
}
|
||||
this._mode = defaultMode ?? currentMode ?? this._modes[0];
|
||||
return currentColor;
|
||||
}
|
||||
|
||||
private _colorChanged(ev: CustomEvent) {
|
||||
@ -230,7 +225,10 @@ class DialogLightColorFavorite extends LitElement {
|
||||
<ha-button slot="secondaryAction" dialogAction="cancel">
|
||||
${this.hass.localize("ui.common.cancel")}
|
||||
</ha-button>
|
||||
<ha-button slot="primaryAction" @click=${this._save}
|
||||
<ha-button
|
||||
slot="primaryAction"
|
||||
@click=${this._save}
|
||||
.disabled=${!this._color}
|
||||
>${this.hass.localize("ui.common.save")}</ha-button
|
||||
>
|
||||
</ha-dialog>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { mdiCheck, mdiMinus, mdiPlus } from "@mdi/js";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
nothing,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
css,
|
||||
html,
|
||||
nothing,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
@ -19,18 +19,17 @@ import {
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../../data/entity_registry";
|
||||
import {
|
||||
computeDefaultFavoriteColors,
|
||||
LightColor,
|
||||
LightEntity,
|
||||
computeDefaultFavoriteColors,
|
||||
} from "../../../../data/light";
|
||||
import { actionHandler } from "../../../../panels/lovelace/common/directives/action-handler-directive";
|
||||
import {
|
||||
loadSortable,
|
||||
SortableInstance,
|
||||
loadSortable,
|
||||
} from "../../../../resources/sortable.ondemand";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { showConfirmationDialog } from "../../../generic/show-dialog-box";
|
||||
import type { LightPickerMode } from "./dialog-light-color-favorite";
|
||||
import "./ha-favorite-color-button";
|
||||
import { showLightColorFavoriteDialog } from "./show-dialog-light-color-favorite";
|
||||
|
||||
@ -141,7 +140,6 @@ export class HaMoreInfoLightFavoriteColors extends LitElement {
|
||||
private _add = async () => {
|
||||
const color = await showLightColorFavoriteDialog(this, {
|
||||
entry: this.entry!,
|
||||
add: true,
|
||||
title: this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.favorite_color.add_title"
|
||||
),
|
||||
@ -156,13 +154,9 @@ export class HaMoreInfoLightFavoriteColors extends LitElement {
|
||||
// Make sure the current favorite color is set
|
||||
fireEvent(this, "favorite-color-edit-started");
|
||||
await this._apply(index);
|
||||
const defaultMode: LightPickerMode =
|
||||
"color_temp_kelvin" in this._favoriteColors[index]
|
||||
? "color_temp"
|
||||
: "color";
|
||||
const color = await showLightColorFavoriteDialog(this, {
|
||||
entry: this.entry!,
|
||||
defaultMode,
|
||||
initialColor: this._favoriteColors[index],
|
||||
title: this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.favorite_color.edit_title"
|
||||
),
|
||||
|
@ -1,13 +1,11 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { ExtEntityRegistryEntry } from "../../../../data/entity_registry";
|
||||
import { LightColor } from "../../../../data/light";
|
||||
import type { LightPickerMode } from "./dialog-light-color-favorite";
|
||||
|
||||
export interface LightColorFavoriteDialogParams {
|
||||
entry: ExtEntityRegistryEntry;
|
||||
title: string;
|
||||
defaultMode?: LightPickerMode;
|
||||
add?: boolean;
|
||||
initialColor?: LightColor;
|
||||
submit?: (color?: LightColor) => void;
|
||||
cancel?: () => void;
|
||||
}
|
||||
|
@ -271,6 +271,7 @@ export const provideHass = (
|
||||
},
|
||||
dockedSidebar: "auto",
|
||||
vibrate: true,
|
||||
debugConnection: false,
|
||||
suspendWhenHidden: false,
|
||||
moreInfoEntityId: null as any,
|
||||
// @ts-ignore
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
} from "../../../../../../data/zwave_js";
|
||||
import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box";
|
||||
import type { HomeAssistant } from "../../../../../../types";
|
||||
import { showZWaveJSHealNodeDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-heal-node";
|
||||
import { showZWaveJSRebuildNodeRoutesDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-rebuild-node-routes";
|
||||
import { showZWaveJSNodeStatisticsDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-node-statistics";
|
||||
import { showZWaveJSReinterviewNodeDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-reinterview-node";
|
||||
import { showZWaveJSRemoveFailedNodeDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-remove-failed-node";
|
||||
@ -69,10 +69,12 @@ export const getZwaveDeviceActions = async (
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: hass.localize("ui.panel.config.zwave_js.device_info.heal_node"),
|
||||
label: hass.localize(
|
||||
"ui.panel.config.zwave_js.device_info.rebuild_routes"
|
||||
),
|
||||
icon: mdiHospitalBox,
|
||||
action: () =>
|
||||
showZWaveJSHealNodeDialog(el, {
|
||||
showZWaveJSRebuildNodeRoutesDialog(el, {
|
||||
device,
|
||||
}),
|
||||
},
|
||||
|
@ -8,18 +8,18 @@ import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||
import {
|
||||
fetchZwaveNetworkStatus,
|
||||
healZwaveNetwork,
|
||||
stopHealZwaveNetwork,
|
||||
subscribeHealZwaveNetworkProgress,
|
||||
ZWaveJSHealNetworkStatusMessage,
|
||||
rebuildZwaveNetworkRoutes,
|
||||
stopRebuildingZwaveNetworkRoutes,
|
||||
subscribeRebuildZwaveNetworkRoutesProgress,
|
||||
ZWaveJSRebuildRoutesStatusMessage,
|
||||
ZWaveJSNetwork,
|
||||
} from "../../../../../data/zwave_js";
|
||||
import { haStyleDialog } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { ZWaveJSHealNetworkDialogParams } from "./show-dialog-zwave_js-heal-network";
|
||||
import { ZWaveJSRebuildNetworkRoutesDialogParams } from "./show-dialog-zwave_js-rebuild-network-routes";
|
||||
|
||||
@customElement("dialog-zwave_js-heal-network")
|
||||
class DialogZWaveJSHealNetwork extends LitElement {
|
||||
@customElement("dialog-zwave_js-rebuild-network-routes")
|
||||
class DialogZWaveJSRebuildNetworkRoutes extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private entry_id?: string;
|
||||
@ -34,7 +34,7 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
|
||||
private _subscribed?: Promise<UnsubscribeFunc>;
|
||||
|
||||
public showDialog(params: ZWaveJSHealNetworkDialogParams): void {
|
||||
public showDialog(params: ZWaveJSRebuildNetworkRoutesDialogParams): void {
|
||||
this._progress_total = 0;
|
||||
this.entry_id = params.entry_id;
|
||||
this._fetchData();
|
||||
@ -61,7 +61,9 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
@closed=${this.closeDialog}
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass.localize("ui.panel.config.zwave_js.heal_network.title")
|
||||
this.hass.localize(
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.title"
|
||||
)
|
||||
)}
|
||||
>
|
||||
${!this._status
|
||||
@ -74,7 +76,7 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.introduction"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.introduction"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@ -82,13 +84,16 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
<p>
|
||||
<em>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.traffic_warning"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.traffic_warning"
|
||||
)}
|
||||
</em>
|
||||
</p>
|
||||
<mwc-button slot="primaryAction" @click=${this._startHeal}>
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
@click=${this._startRebuildingRoutes}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.start_heal"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.start_rebuilding_routes"
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
@ -99,13 +104,13 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
<p>
|
||||
<b>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.in_progress"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.in_progress"
|
||||
)}
|
||||
</b>
|
||||
</p>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.run_in_background"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.run_in_background"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@ -114,9 +119,12 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
<mwc-linear-progress indeterminate> </mwc-linear-progress>
|
||||
`
|
||||
: ""}
|
||||
<mwc-button slot="secondaryAction" @click=${this._stopHeal}>
|
||||
<mwc-button
|
||||
slot="secondaryAction"
|
||||
@click=${this._stopRebuildingRoutes}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.stop_heal"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.stop_rebuilding_routes"
|
||||
)}
|
||||
</mwc-button>
|
||||
<mwc-button slot="primaryAction" @click=${this.closeDialog}>
|
||||
@ -134,7 +142,7 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.healing_failed"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.rebuilding_routes_failed"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@ -154,7 +162,7 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.healing_complete"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.rebuilding_routes_complete"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@ -174,7 +182,7 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_network.healing_cancelled"
|
||||
"ui.panel.config.zwave_js.rebuild_network_routes.rebuilding_routes_cancelled"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@ -205,9 +213,9 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
const network: ZWaveJSNetwork = await fetchZwaveNetworkStatus(this.hass!, {
|
||||
entry_id: this.entry_id!,
|
||||
});
|
||||
if (network.controller.is_heal_network_active) {
|
||||
if (network.controller.is_rebuilding_routes) {
|
||||
this._status = "started";
|
||||
this._subscribed = subscribeHealZwaveNetworkProgress(
|
||||
this._subscribed = subscribeRebuildZwaveNetworkRoutesProgress(
|
||||
this.hass,
|
||||
this.entry_id!,
|
||||
this._handleMessage.bind(this)
|
||||
@ -215,33 +223,33 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _startHeal(): void {
|
||||
private _startRebuildingRoutes(): void {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
healZwaveNetwork(this.hass, this.entry_id!);
|
||||
rebuildZwaveNetworkRoutes(this.hass, this.entry_id!);
|
||||
this._status = "started";
|
||||
this._subscribed = subscribeHealZwaveNetworkProgress(
|
||||
this._subscribed = subscribeRebuildZwaveNetworkRoutesProgress(
|
||||
this.hass,
|
||||
this.entry_id!,
|
||||
this._handleMessage.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
private _stopHeal(): void {
|
||||
private _stopRebuildingRoutes(): void {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
stopHealZwaveNetwork(this.hass, this.entry_id!);
|
||||
stopRebuildingZwaveNetworkRoutes(this.hass, this.entry_id!);
|
||||
this._unsubscribe();
|
||||
this._status = "cancelled";
|
||||
}
|
||||
|
||||
private _handleMessage(message: ZWaveJSHealNetworkStatusMessage): void {
|
||||
if (message.event === "heal network progress") {
|
||||
private _handleMessage(message: ZWaveJSRebuildRoutesStatusMessage): void {
|
||||
if (message.event === "rebuild routes progress") {
|
||||
let finished = 0;
|
||||
let in_progress = 0;
|
||||
for (const status of Object.values(message.heal_node_status)) {
|
||||
for (const status of Object.values(message.rebuild_routes_status)) {
|
||||
if (status === "pending") {
|
||||
in_progress++;
|
||||
}
|
||||
@ -249,11 +257,11 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
finished++;
|
||||
}
|
||||
}
|
||||
this._progress_total = Object.keys(message.heal_node_status).length;
|
||||
this._progress_total = Object.keys(message.rebuild_routes_status).length;
|
||||
this._progress_finished = finished / this._progress_total;
|
||||
this._progress_in_progress = in_progress / this._progress_total;
|
||||
}
|
||||
if (message.event === "heal network done") {
|
||||
if (message.event === "rebuild routes done") {
|
||||
this._unsubscribe();
|
||||
this._status = "finished";
|
||||
}
|
||||
@ -306,6 +314,6 @@ class DialogZWaveJSHealNetwork extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-zwave_js-heal-network": DialogZWaveJSHealNetwork;
|
||||
"dialog-zwave_js-rebuild-network-routes": DialogZWaveJSRebuildNetworkRoutes;
|
||||
}
|
||||
}
|
@ -11,15 +11,15 @@ import {
|
||||
} from "../../../../../data/device_registry";
|
||||
import {
|
||||
fetchZwaveNetworkStatus,
|
||||
healZwaveNode,
|
||||
rebuildZwaveNodeRoutes,
|
||||
ZWaveJSNetwork,
|
||||
} from "../../../../../data/zwave_js";
|
||||
import { haStyleDialog } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { ZWaveJSHealNodeDialogParams } from "./show-dialog-zwave_js-heal-node";
|
||||
import { ZWaveJSRebuildNodeRoutesDialogParams } from "./show-dialog-zwave_js-rebuild-node-routes";
|
||||
|
||||
@customElement("dialog-zwave_js-heal-node")
|
||||
class DialogZWaveJSHealNode extends LitElement {
|
||||
@customElement("dialog-zwave_js-rebuild-node-routes")
|
||||
class DialogZWaveJSRebuildNodeRoutes extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private device?: DeviceRegistryEntry;
|
||||
@ -28,7 +28,7 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
public showDialog(params: ZWaveJSHealNodeDialogParams): void {
|
||||
public showDialog(params: ZWaveJSRebuildNodeRoutesDialogParams): void {
|
||||
this.device = params.device;
|
||||
this._fetchData();
|
||||
}
|
||||
@ -52,7 +52,9 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
@closed=${this.closeDialog}
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass.localize("ui.panel.config.zwave_js.heal_node.title")
|
||||
this.hass.localize(
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.title"
|
||||
)
|
||||
)}
|
||||
>
|
||||
${!this._status
|
||||
@ -65,7 +67,7 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_node.introduction",
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.introduction",
|
||||
{
|
||||
device: html`<em
|
||||
>${computeDeviceName(this.device, this.hass!)}</em
|
||||
@ -78,13 +80,16 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
<p>
|
||||
<em>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_node.traffic_warning"
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.traffic_warning"
|
||||
)}
|
||||
</em>
|
||||
</p>
|
||||
<mwc-button slot="primaryAction" @click=${this._startHeal}>
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
@click=${this._startRebuildingRoutes}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_node.start_heal"
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.start_rebuilding_routes"
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
@ -96,7 +101,7 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_node.in_progress",
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.in_progress",
|
||||
{
|
||||
device: html`<em
|
||||
>${computeDeviceName(this.device, this.hass!)}</em
|
||||
@ -121,7 +126,7 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_node.healing_failed",
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.rebuilding_routes_failed",
|
||||
{
|
||||
device: html`<em
|
||||
>${computeDeviceName(this.device, this.hass!)}</em
|
||||
@ -134,7 +139,7 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
? html` <em>${this._error}</em> `
|
||||
: `
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_node.healing_failed_check_logs"
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.rebuilding_routes_failed_check_logs"
|
||||
)}
|
||||
`}
|
||||
</p>
|
||||
@ -155,7 +160,7 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_node.healing_complete",
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.rebuilding_routes_complete",
|
||||
{
|
||||
device: html`<em
|
||||
>${computeDeviceName(this.device, this.hass!)}</em
|
||||
@ -170,7 +175,7 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
</mwc-button>
|
||||
`
|
||||
: ``}
|
||||
${this._status === "network-healing"
|
||||
${this._status === "rebuilding-routes"
|
||||
? html`
|
||||
<div class="flex-container">
|
||||
<ha-svg-icon
|
||||
@ -180,7 +185,7 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.heal_node.network_heal_in_progress"
|
||||
"ui.panel.config.zwave_js.rebuild_node_routes.routes_rebuild_in_progress"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@ -201,18 +206,18 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
const network: ZWaveJSNetwork = await fetchZwaveNetworkStatus(this.hass!, {
|
||||
device_id: this.device!.id,
|
||||
});
|
||||
if (network.controller.is_heal_network_active) {
|
||||
this._status = "network-healing";
|
||||
if (network.controller.is_rebuilding_routes) {
|
||||
this._status = "rebuilding-routes";
|
||||
}
|
||||
}
|
||||
|
||||
private async _startHeal(): Promise<void> {
|
||||
private async _startRebuildingRoutes(): Promise<void> {
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
this._status = "started";
|
||||
try {
|
||||
this._status = (await healZwaveNode(this.hass, this.device!.id))
|
||||
this._status = (await rebuildZwaveNodeRoutes(this.hass, this.device!.id))
|
||||
? "finished"
|
||||
: "failed";
|
||||
} catch (err: any) {
|
||||
@ -258,6 +263,6 @@ class DialogZWaveJSHealNode extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-zwave_js-heal-node": DialogZWaveJSHealNode;
|
||||
"dialog-zwave_js-rebuild-node-routes": DialogZWaveJSRebuildNodeRoutes;
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
|
||||
export interface ZWaveJSHealNetworkDialogParams {
|
||||
entry_id: string;
|
||||
}
|
||||
|
||||
export const loadHealNetworkDialog = () =>
|
||||
import("./dialog-zwave_js-heal-network");
|
||||
|
||||
export const showZWaveJSHealNetworkDialog = (
|
||||
element: HTMLElement,
|
||||
healNetworkDialogParams: ZWaveJSHealNetworkDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-zwave_js-heal-network",
|
||||
dialogImport: loadHealNetworkDialog,
|
||||
dialogParams: healNetworkDialogParams,
|
||||
});
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
|
||||
export interface ZWaveJSHealNodeDialogParams {
|
||||
device: DeviceRegistryEntry;
|
||||
}
|
||||
|
||||
export const loadHealNodeDialog = () => import("./dialog-zwave_js-heal-node");
|
||||
|
||||
export const showZWaveJSHealNodeDialog = (
|
||||
element: HTMLElement,
|
||||
healNodeDialogParams: ZWaveJSHealNodeDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-zwave_js-heal-node",
|
||||
dialogImport: loadHealNodeDialog,
|
||||
dialogParams: healNodeDialogParams,
|
||||
});
|
||||
};
|
@ -0,0 +1,19 @@
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
|
||||
export interface ZWaveJSRebuildNetworkRoutesDialogParams {
|
||||
entry_id: string;
|
||||
}
|
||||
|
||||
export const loadRebuildNetworkRoutesDialog = () =>
|
||||
import("./dialog-zwave_js-rebuild-network-routes");
|
||||
|
||||
export const showZWaveJSRebuildNetworkRoutesDialog = (
|
||||
element: HTMLElement,
|
||||
rebuildNetworkRoutesDialogParams: ZWaveJSRebuildNetworkRoutesDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-zwave_js-rebuild-network-routes",
|
||||
dialogImport: loadRebuildNetworkRoutesDialog,
|
||||
dialogParams: rebuildNetworkRoutesDialogParams,
|
||||
});
|
||||
};
|
@ -0,0 +1,20 @@
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
|
||||
export interface ZWaveJSRebuildNodeRoutesDialogParams {
|
||||
device: DeviceRegistryEntry;
|
||||
}
|
||||
|
||||
export const loadRebuildNodeRoutesDialog = () =>
|
||||
import("./dialog-zwave_js-rebuild-node-routes");
|
||||
|
||||
export const showZWaveJSRebuildNodeRoutesDialog = (
|
||||
element: HTMLElement,
|
||||
rebuildNodeRoutesDialogParams: ZWaveJSRebuildNodeRoutesDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-zwave_js-rebuild-node-routes",
|
||||
dialogImport: loadRebuildNodeRoutesDialog,
|
||||
dialogParams: rebuildNodeRoutesDialogParams,
|
||||
});
|
||||
};
|
@ -52,7 +52,7 @@ import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import { showZWaveJSAddNodeDialog } from "./show-dialog-zwave_js-add-node";
|
||||
import { showZWaveJSHealNetworkDialog } from "./show-dialog-zwave_js-heal-network";
|
||||
import { showZWaveJSRebuildNetworkRoutesDialog } from "./show-dialog-zwave_js-rebuild-network-routes";
|
||||
import { showZWaveJSRemoveNodeDialog } from "./show-dialog-zwave_js-remove-node";
|
||||
import { configTabs } from "./zwave_js-config-router";
|
||||
|
||||
@ -430,11 +430,11 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
)}
|
||||
</mwc-button>
|
||||
<mwc-button
|
||||
@click=${this._healNetworkClicked}
|
||||
@click=${this._rebuildNetworkRoutesClicked}
|
||||
.disabled=${this._status === "disconnected"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.common.heal_network"
|
||||
"ui.panel.config.zwave_js.common.rebuild_network_routes"
|
||||
)}
|
||||
</mwc-button>
|
||||
<mwc-button @click=${this._openOptionFlow}>
|
||||
@ -612,8 +612,8 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
});
|
||||
}
|
||||
|
||||
private async _healNetworkClicked() {
|
||||
showZWaveJSHealNetworkDialog(this, {
|
||||
private async _rebuildNetworkRoutesClicked() {
|
||||
showZWaveJSRebuildNetworkRoutesDialog(this, {
|
||||
entry_id: this.configEntryId!,
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
nothing,
|
||||
PropertyValues,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { LocalizeKeys } from "../../../../common/translations/localize";
|
||||
@ -6,6 +13,7 @@ import "../../../../components/ha-form/ha-form";
|
||||
import { AssistPipeline } from "../../../../data/assist_pipeline";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { fetchWakeWordInfo, WakeWord } from "../../../../data/wake_word";
|
||||
import { documentationUrl } from "../../../../util/documentation-url";
|
||||
|
||||
@customElement("assist-pipeline-detail-wakeword")
|
||||
export class AssistPipelineDetailWakeWord extends LitElement {
|
||||
@ -67,7 +75,12 @@ export class AssistPipelineDetailWakeWord extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _hasWakeWorkEntities = memoizeOne((states: HomeAssistant["states"]) =>
|
||||
Object.keys(states).some((entityId) => entityId.startsWith("wake_word."))
|
||||
);
|
||||
|
||||
protected render() {
|
||||
const hasWakeWorkEntities = this._hasWakeWorkEntities(this.hass.states);
|
||||
return html`
|
||||
<div class="section">
|
||||
<div class="content">
|
||||
@ -83,11 +96,25 @@ export class AssistPipelineDetailWakeWord extends LitElement {
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
${!hasWakeWorkEntities
|
||||
? html`${this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.assistants.pipeline.detail.steps.wakeword.no_wake_words`
|
||||
)}
|
||||
<a
|
||||
href=${documentationUrl(this.hass, "/docs/assist/")}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>${this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.assistants.pipeline.detail.steps.wakeword.no_wake_words_link`
|
||||
)}</a
|
||||
>`
|
||||
: nothing}
|
||||
<ha-form
|
||||
.schema=${this._schema(this._wakeWords)}
|
||||
.data=${this.data}
|
||||
.hass=${this.hass}
|
||||
.computeLabel=${this._computeLabel}
|
||||
.disabled=${!hasWakeWorkEntities}
|
||||
></ha-form>
|
||||
</div>
|
||||
</div>
|
||||
@ -129,6 +156,9 @@ export class AssistPipelineDetailWakeWord extends LitElement {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { brandsUrl } from "../../../util/brands-url";
|
||||
import { showVoiceAssistantPipelineDetailDialog } from "./show-dialog-voice-assistant-pipeline-detail";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
|
||||
export class AssistPref extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -73,9 +74,9 @@ export class AssistPref extends LitElement {
|
||||
</h1>
|
||||
<div class="header-actions">
|
||||
<a
|
||||
href="https://www.home-assistant.io/docs/assist/"
|
||||
href=${documentationUrl(this.hass, "/docs/assist/")}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
rel="noreferrer noopener"
|
||||
class="icon-link"
|
||||
>
|
||||
<ha-icon-button
|
||||
|
@ -307,9 +307,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
assist-pipeline-detail-config,
|
||||
assist-pipeline-detail-conversation,
|
||||
assist-pipeline-detail-stt {
|
||||
.content > *:not(:last-child) {
|
||||
margin-bottom: 16px;
|
||||
display: block;
|
||||
}
|
||||
|
52
src/panels/developer-tools/debug/developer-tools-debug.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { CSSResultGroup, LitElement, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "./ha-debug-connection-row";
|
||||
|
||||
@customElement("developer-tools-debug")
|
||||
class HaPanelDevDebug extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<div class="content">
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.debug.title"
|
||||
)}
|
||||
class="form"
|
||||
>
|
||||
<div class="card-content">
|
||||
<ha-debug-connection-row
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
></ha-debug-connection-row>
|
||||
</ha-card>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.content {
|
||||
padding: 28px 20px 16px;
|
||||
display: block;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-debug": HaPanelDevDebug;
|
||||
}
|
||||
}
|
50
src/panels/developer-tools/debug/ha-debug-connection-row.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-settings-row";
|
||||
import "../../../components/ha-switch";
|
||||
import type { HaSwitch } from "../../../components/ha-switch";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { storeState } from "../../../util/ha-pref-storage";
|
||||
|
||||
@customElement("ha-debug-connection-row")
|
||||
class HaDebugConnectionRow extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public narrow!: boolean;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-settings-row .narrow=${this.narrow}>
|
||||
<span slot="heading">
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.debug.debug_connection.title"
|
||||
)}
|
||||
</span>
|
||||
<span slot="description">
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.debug.debug_connection.description"
|
||||
)}
|
||||
</span>
|
||||
<ha-switch
|
||||
.checked=${this.hass.debugConnection}
|
||||
@change=${this._checkedChanged}
|
||||
></ha-switch>
|
||||
</ha-settings-row>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _checkedChanged(ev: Event) {
|
||||
const debugConnection = (ev.target as HaSwitch).checked;
|
||||
if (debugConnection === this.hass.debugConnection) {
|
||||
return;
|
||||
}
|
||||
this.hass.debugConnection = debugConnection;
|
||||
storeState(this.hass);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-debug-connection-row": HaDebugConnectionRow;
|
||||
}
|
||||
}
|
@ -49,6 +49,10 @@ class DeveloperToolsRouter extends HassRouterPage {
|
||||
tag: "developer-tools-assist",
|
||||
load: () => import("./assist/developer-tools-assist"),
|
||||
},
|
||||
debug: {
|
||||
tag: "developer-tools-debug",
|
||||
load: () => import("./debug/developer-tools-debug"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,219 +0,0 @@
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { load } from "js-yaml";
|
||||
import "../../../components/ha-code-editor";
|
||||
import "../../../components/ha-textfield";
|
||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import "../../../styles/polymer-ha-style";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
import "./event-subscribe-card";
|
||||
import "./events-list";
|
||||
|
||||
const ERROR_SENTINEL = {};
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class HaPanelDevEvent extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="ha-style iron-flex iron-positioning"></style>
|
||||
<style>
|
||||
.content {
|
||||
padding: 16px;
|
||||
padding: max(16px, env(safe-area-inset-top))
|
||||
max(16px, env(safe-area-inset-right))
|
||||
max(16px, env(safe-area-inset-bottom))
|
||||
max(16px, env(safe-area-inset-left));
|
||||
max-width: 1200px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
:host {
|
||||
-ms-user-select: initial;
|
||||
-webkit-user-select: initial;
|
||||
-moz-user-select: initial;
|
||||
@apply --paper-font-body1;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.inputs {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
mwc-button {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
ha-textfield {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.code-editor {
|
||||
margin-right: 16px;
|
||||
margin-inline-start: initial;
|
||||
margin-inline-end: 16px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply --paper-font-title;
|
||||
}
|
||||
|
||||
event-subscribe-card {
|
||||
display: block;
|
||||
margin: 16px 16px 0 0;
|
||||
margin-inline-start: initial;
|
||||
margin-inline-end: 16px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class$="[[computeFormClasses(narrow)]]">
|
||||
<div class="flex">
|
||||
<p>
|
||||
[[localize( 'ui.panel.developer-tools.tabs.events.description' )]]
|
||||
<a
|
||||
href="[[_computeDocumentationUrl(hass)]]"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
[[localize( 'ui.panel.developer-tools.tabs.events.documentation'
|
||||
)]]
|
||||
</a>
|
||||
</p>
|
||||
<div class="inputs">
|
||||
<ha-textfield
|
||||
label="[[localize(
|
||||
'ui.panel.developer-tools.tabs.events.type'
|
||||
)]]"
|
||||
autofocus
|
||||
required
|
||||
value="[[eventType]]"
|
||||
on-change="eventTypeChanged"
|
||||
></ha-textfield>
|
||||
<p>[[localize( 'ui.panel.developer-tools.tabs.events.data' )]]</p>
|
||||
</div>
|
||||
<div class="code-editor">
|
||||
<ha-code-editor
|
||||
mode="yaml"
|
||||
value="[[eventData]]"
|
||||
error="[[!validJSON]]"
|
||||
on-value-changed="_yamlChanged"
|
||||
dir="ltr"
|
||||
></ha-code-editor>
|
||||
</div>
|
||||
<mwc-button on-click="fireEvent" raised disabled="[[!validJSON]]"
|
||||
>[[localize( 'ui.panel.developer-tools.tabs.events.fire_event'
|
||||
)]]</mwc-button
|
||||
>
|
||||
<event-subscribe-card hass="[[hass]]"></event-subscribe-card>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="header">
|
||||
[[localize( 'ui.panel.developer-tools.tabs.events.active_listeners'
|
||||
)]]
|
||||
</div>
|
||||
<events-list
|
||||
on-event-selected="eventSelected"
|
||||
hass="[[hass]]"
|
||||
></events-list>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {
|
||||
type: Object,
|
||||
},
|
||||
|
||||
eventType: {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
|
||||
eventData: {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
|
||||
parsedJSON: {
|
||||
type: Object,
|
||||
computed: "_computeParsedEventData(eventData)",
|
||||
},
|
||||
|
||||
validJSON: {
|
||||
type: Boolean,
|
||||
computed: "_computeValidJSON(parsedJSON)",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
eventSelected(ev) {
|
||||
this.eventType = ev.detail.eventType;
|
||||
}
|
||||
|
||||
eventTypeChanged(ev) {
|
||||
this.eventType = ev.target.value;
|
||||
}
|
||||
|
||||
_computeParsedEventData(eventData) {
|
||||
try {
|
||||
return eventData.trim() ? load(eventData) : {};
|
||||
} catch (err) {
|
||||
return ERROR_SENTINEL;
|
||||
}
|
||||
}
|
||||
|
||||
_computeDocumentationUrl(hass) {
|
||||
return documentationUrl(hass, "/docs/configuration/events/");
|
||||
}
|
||||
|
||||
_computeValidJSON(parsedJSON) {
|
||||
return parsedJSON !== ERROR_SENTINEL;
|
||||
}
|
||||
|
||||
_yamlChanged(ev) {
|
||||
this.eventData = ev.detail.value;
|
||||
}
|
||||
|
||||
fireEvent() {
|
||||
if (!this.eventType) {
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.alert_event_type"
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.hass
|
||||
.callApi("POST", "events/" + this.eventType, this.parsedJSON)
|
||||
.then(() => {
|
||||
this.fire("hass-notification", {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.notification_event_fired",
|
||||
"type",
|
||||
this.eventType
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
computeFormClasses(narrow) {
|
||||
return narrow ? "content" : "content layout horizontal";
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("developer-tools-event", HaPanelDevEvent);
|
184
src/panels/developer-tools/event/developer-tools-event.ts
Normal file
@ -0,0 +1,184 @@
|
||||
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "@material/mwc-button";
|
||||
import "../../../components/ha-yaml-editor";
|
||||
import "../../../components/ha-textfield";
|
||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
import "./event-subscribe-card";
|
||||
import "./events-list";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
|
||||
@customElement("developer-tools-event")
|
||||
class HaPanelDevEvent extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@state() private _eventType: string = "";
|
||||
|
||||
@state() private _eventData: object = {};
|
||||
|
||||
@state() private _isValid: boolean = true;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div class=${this.narrow ? "content" : "content layout horizontal"}>
|
||||
<div class="flex">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.description"
|
||||
)}
|
||||
<a
|
||||
href=${documentationUrl(this.hass, "/docs/configuration/events/")}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.documentation"
|
||||
)}
|
||||
</a>
|
||||
</p>
|
||||
<div class="inputs">
|
||||
<ha-textfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.type"
|
||||
)}
|
||||
autofocus
|
||||
required
|
||||
.value=${this._eventType}
|
||||
@change=${this._eventTypeChanged}
|
||||
></ha-textfield>
|
||||
<p>
|
||||
${this.hass.localize("ui.panel.developer-tools.tabs.events.data")}
|
||||
</p>
|
||||
</div>
|
||||
<div class="code-editor">
|
||||
<ha-yaml-editor
|
||||
.value=${this._eventData}
|
||||
.error=${!this._isValid}
|
||||
@value-changed=${this._yamlChanged}
|
||||
></ha-yaml-editor>
|
||||
</div>
|
||||
<mwc-button
|
||||
@click=${this._fireEvent}
|
||||
raised
|
||||
.disabled=${!this._isValid}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.fire_event"
|
||||
)}</mwc-button
|
||||
>
|
||||
<event-subscribe-card .hass=${this.hass}></event-subscribe-card>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.active_listeners"
|
||||
)}
|
||||
</div>
|
||||
<events-list
|
||||
@event-selected=${this._eventSelected}
|
||||
.hass=${this.hass}
|
||||
></events-list>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _eventSelected(ev) {
|
||||
this._eventType = ev.detail.eventType;
|
||||
}
|
||||
|
||||
private _eventTypeChanged(ev) {
|
||||
this._eventType = ev.target.value;
|
||||
}
|
||||
|
||||
private _yamlChanged(ev) {
|
||||
this._eventData = ev.detail.value;
|
||||
this._isValid = ev.detail.isValid;
|
||||
}
|
||||
|
||||
private async _fireEvent() {
|
||||
if (!this._eventType) {
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.alert_event_type"
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this.hass.callApi(
|
||||
"POST",
|
||||
`events/${this._eventType}`,
|
||||
this._eventData
|
||||
);
|
||||
fireEvent(this, "hass-notification", {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.notification_event_fired",
|
||||
{ type: this._eventType }
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.content {
|
||||
padding: 16px;
|
||||
padding: max(16px, env(safe-area-inset-top))
|
||||
max(16px, env(safe-area-inset-right))
|
||||
max(16px, env(safe-area-inset-bottom))
|
||||
max(16px, env(safe-area-inset-left));
|
||||
max-width: 1200px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
:host {
|
||||
-ms-user-select: initial;
|
||||
-webkit-user-select: initial;
|
||||
-moz-user-select: initial;
|
||||
@apply --paper-font-body1;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.inputs {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
mwc-button {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
ha-textfield {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply --paper-font-title;
|
||||
}
|
||||
|
||||
event-subscribe-card {
|
||||
display: block;
|
||||
margin: 16px 16px 0 0;
|
||||
margin-inline-start: initial;
|
||||
margin-inline-end: 16px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"developer-tools-event": HaPanelDevEvent;
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { stringCompare } from "../../../common/string/compare";
|
||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class EventsList extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
<ul>
|
||||
<template is="dom-repeat" items="[[events]]" as="event">
|
||||
<li>
|
||||
<a href="#" on-click="eventSelected">{{event.event}}</a>
|
||||
<span>
|
||||
[[localize(
|
||||
"ui.panel.developer-tools.tabs.events.count_listeners", "count",
|
||||
event.listener_count )]]</span
|
||||
>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {
|
||||
type: Object,
|
||||
},
|
||||
|
||||
events: {
|
||||
type: Array,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.hass.callApi("GET", "events").then((events) => {
|
||||
this.events = events.sort((e1, e2) =>
|
||||
stringCompare(e1.event, e2.event, this.hass.locale.language)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
eventSelected(ev) {
|
||||
ev.preventDefault();
|
||||
this.fire("event-selected", { eventType: ev.model.event.event });
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("events-list", EventsList);
|
84
src/panels/developer-tools/event/events-list.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { stringCompare } from "../../../common/string/compare";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
interface EventListenerCount {
|
||||
event: string;
|
||||
listener_count: number;
|
||||
}
|
||||
|
||||
@customElement("events-list")
|
||||
class EventsList extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public events: EventListenerCount[] = [];
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ul>
|
||||
${this.events.map(
|
||||
(event) => html`
|
||||
<li>
|
||||
<a href="#" @click=${this._eventSelected} .event=${event.event}
|
||||
>${event.event}</a
|
||||
>
|
||||
<span>
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.events.count_listeners",
|
||||
{
|
||||
count: event.listener_count,
|
||||
}
|
||||
)}</span
|
||||
>
|
||||
</li>
|
||||
`
|
||||
)}
|
||||
</ul>
|
||||
`;
|
||||
}
|
||||
|
||||
protected async firstUpdated() {
|
||||
const events = await this.hass.callApi<EventListenerCount[]>(
|
||||
"GET",
|
||||
"events"
|
||||
);
|
||||
this.events = events.sort((e1, e2) =>
|
||||
stringCompare(e1.event, e2.event, this.hass.locale.language)
|
||||
);
|
||||
}
|
||||
|
||||
private _eventSelected(ev: Event) {
|
||||
ev.preventDefault();
|
||||
const event: string = (ev.currentTarget! as any).event;
|
||||
fireEvent(this, "event-selected", { eventType: event });
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"events-list": EventsList;
|
||||
}
|
||||
interface HASSDomEvents {
|
||||
"event-selected": { eventType: string };
|
||||
}
|
||||
}
|
@ -1,9 +1,14 @@
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import "@polymer/paper-tabs/paper-tab";
|
||||
import "@polymer/paper-tabs/paper-tabs";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import "../../components/ha-menu-button";
|
||||
import "../../components/ha-button-menu";
|
||||
import "../../components/ha-icon-button";
|
||||
import "../../components/ha-list-item";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import { HomeAssistant, Route } from "../../types";
|
||||
import "./developer-tools-router";
|
||||
@ -34,6 +39,16 @@ class PanelDeveloperTools extends LitElement {
|
||||
<div class="main-title">
|
||||
${this.hass.localize("panel.developer_tools")}
|
||||
</div>
|
||||
<ha-button-menu slot="actionItems" @action=${this._handleMenuAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-list-item>
|
||||
${this.hass.localize("ui.panel.developer-tools.tabs.debug.title")}
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
<paper-tabs
|
||||
scrollable
|
||||
@ -85,6 +100,14 @@ class PanelDeveloperTools extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
navigate(`/developer-tools/debug`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private get _page() {
|
||||
return this.route.path.substr(1);
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
|
||||
translationMetadata,
|
||||
dockedSidebar: "docked",
|
||||
vibrate: true,
|
||||
debugConnection: false,
|
||||
suspendWhenHidden: true,
|
||||
enableShortcuts: true,
|
||||
moreInfoEntityId: null,
|
||||
@ -84,7 +85,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
|
||||
target,
|
||||
notifyOnError = true
|
||||
) => {
|
||||
if (__DEV__) {
|
||||
if (__DEV__ || this.hass?.debugConnection) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
"Calling service",
|
||||
@ -109,7 +110,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
|
||||
) {
|
||||
return { context: { id: "" } };
|
||||
}
|
||||
if (__DEV__) {
|
||||
if (__DEV__ || this.hass?.debugConnection) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
"Error calling service",
|
||||
@ -146,7 +147,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
|
||||
) => fetchWithAuth(auth, `${auth.data.hassUrl}${path}`, init),
|
||||
// For messages that do not get a response
|
||||
sendWS: (msg) => {
|
||||
if (__DEV__) {
|
||||
if (__DEV__ || this.hass?.debugConnection) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Sending", msg);
|
||||
}
|
||||
@ -154,14 +155,14 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
|
||||
},
|
||||
// For messages that expect a response
|
||||
callWS: <R>(msg) => {
|
||||
if (__DEV__) {
|
||||
if (__DEV__ || this.hass?.debugConnection) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Sending", msg);
|
||||
}
|
||||
|
||||
const resp = conn.sendMessagePromise<R>(msg);
|
||||
|
||||
if (__DEV__) {
|
||||
if (__DEV__ || this.hass?.debugConnection) {
|
||||
resp.then(
|
||||
// eslint-disable-next-line no-console
|
||||
(result) => console.log("Received", result),
|
||||
|
@ -2196,7 +2196,9 @@
|
||||
},
|
||||
"wakeword": {
|
||||
"title": "Wake word",
|
||||
"description": "If a device supports wake words, you can activate Assist by saying this word."
|
||||
"description": "If a device supports wake words, you can activate Assist by saying this word.",
|
||||
"no_wake_words": "It looks like you don't have a wake word engine setup yet.",
|
||||
"no_wake_words_link": "Find out more about wake words."
|
||||
}
|
||||
},
|
||||
"no_cloud_message": "You should have an active cloud subscription to use cloud speech services.",
|
||||
@ -2446,7 +2448,12 @@
|
||||
"mode_below": "Below mode",
|
||||
"value_template": "Value template",
|
||||
"type_value": "Fixed number",
|
||||
"type_input": "Numeric value of another entity"
|
||||
"type_input": "Numeric value of another entity",
|
||||
"description": {
|
||||
"above": "When {attribute, select, \n undefined {} \n other {{attribute} from }\n }{entity} is above {above}{duration, select, \n undefined {} \n other { for {duration}}\n }",
|
||||
"below": "When {attribute, select, \n undefined {} \n other {{attribute} from }\n }{entity} is below {below}{duration, select, \n undefined {} \n other { for {duration}}\n }",
|
||||
"above-below": "When {attribute, select, \n undefined {} \n other {{attribute} from }\n }{entity} is above {above} and below {below}{duration, select, \n undefined {} \n other { for {duration}}\n }"
|
||||
}
|
||||
},
|
||||
"persistent_notification": {
|
||||
"label": "Persistent notification",
|
||||
@ -2595,7 +2602,12 @@
|
||||
"below": "[%key:ui::panel::config::automation::editor::triggers::type::numeric_state::below%]",
|
||||
"mode_above": "[%key:ui::panel::config::automation::editor::triggers::type::numeric_state::mode_above%]",
|
||||
"mode_below": "[%key:ui::panel::config::automation::editor::triggers::type::numeric_state::mode_below%]",
|
||||
"value_template": "[%key:ui::panel::config::automation::editor::triggers::type::numeric_state::value_template%]"
|
||||
"value_template": "[%key:ui::panel::config::automation::editor::triggers::type::numeric_state::value_template%]",
|
||||
"description": {
|
||||
"above": "When {attribute, select, \n undefined {} \n other {{attribute} from }\n }{entity} is above {above}",
|
||||
"below": "When {attribute, select, \n undefined {} \n other {{attribute} from }\n }{entity} is below {below}",
|
||||
"above-below": "When {attribute, select, \n undefined {} \n other {{attribute} from }\n }{entity} is above {above} and below {below}"
|
||||
}
|
||||
},
|
||||
"or": {
|
||||
"label": "Or",
|
||||
@ -3922,7 +3934,7 @@
|
||||
"add_node": "Add device",
|
||||
"remove_node": "Remove device",
|
||||
"reconfigure_server": "Re-configure server",
|
||||
"heal_network": "Heal Network",
|
||||
"rebuild_network_routes": "Rebuild network routes",
|
||||
"in_progress_inclusion_exclusion": "Z-Wave JS is searching for devices",
|
||||
"cancel_inclusion_exclusion": "Stop searching"
|
||||
},
|
||||
@ -3982,7 +3994,7 @@
|
||||
"node_ready": "Ready",
|
||||
"device_config": "Configure",
|
||||
"reinterview_device": "Re-interview",
|
||||
"heal_node": "Heal",
|
||||
"rebuild_routes": "Rebuild routes",
|
||||
"remove_failed": "Remove failed",
|
||||
"update_firmware": "Update",
|
||||
"highest_security": "Highest security",
|
||||
@ -4164,28 +4176,28 @@
|
||||
"interview_failed": "The device interview failed. Additional information may be available in the logs.",
|
||||
"interview_complete": "Device interview complete."
|
||||
},
|
||||
"heal_network": {
|
||||
"title": "Heal your Z-Wave network",
|
||||
"introduction": "Start a network heal on your Z-Wave network. A network heal will cause all devices to re-calculate their routes back to the controller and is recommended if you have recently moved devices or your controller.",
|
||||
"traffic_warning": "The healing process generates a large amount of traffic on the Z-Wave network. This may cause devices to respond slowly (or not at all) while the heal is in progress.",
|
||||
"start_heal": "Start healing",
|
||||
"in_progress": "Network healing is in progress. This will take some time.",
|
||||
"run_in_background": "You can close this dialog and the network healing will continue in the background.",
|
||||
"stop_heal": "Stop Healing",
|
||||
"healing_complete": "Network healing is complete.",
|
||||
"healing_failed": "Healing failed. Additional information may be available in the logs.",
|
||||
"healing_cancelled": "Network healing has been cancelled."
|
||||
"rebuild_network_routes": {
|
||||
"title": "Rebuild routes for your Z-Wave network",
|
||||
"introduction": "Start rebuilding routes on your Z-Wave network. Rebuilding routes will cause all devices to re-calculate their routes back to the controller and is recommended if you have recently moved devices or your controller.",
|
||||
"traffic_warning": "The rebuilding process generates a large amount of traffic on the Z-Wave network. This may cause devices to respond slowly (or not at all) while the rebuild is in progress.",
|
||||
"start_rebuilding_routes": "Start rebuilding routes",
|
||||
"in_progress": "Rebuild of network routes is in progress. This will take some time.",
|
||||
"run_in_background": "You can close this dialog and the rebuild of network routes will continue in the background.",
|
||||
"stop_rebuilding_routes": "Stop rebuilding routes",
|
||||
"rebuilding_routes_complete": "Routes have been rebuilt.",
|
||||
"rebuilding_routes_failed": "Route rebuilding failed. Additional information may be available in the logs.",
|
||||
"rebuilding_routes_cancelled": "Rebuilding network routes has been cancelled."
|
||||
},
|
||||
"heal_node": {
|
||||
"title": "Heal a Z-Wave device",
|
||||
"rebuild_node_routes": {
|
||||
"title": "Rebuild routes for a Z-Wave device",
|
||||
"introduction": "Tell {device} to update its routes back to the controller. This can help with communication issues if you have recently moved the device or your controller.",
|
||||
"traffic_warning": "The healing process generates a large amount of traffic on the Z-Wave network. This may cause devices to respond slowly (or not at all) while the heal is in progress.",
|
||||
"start_heal": "Heal Device",
|
||||
"healing_failed": "{device} could not be healed.",
|
||||
"healing_failed_check_logs": "Additional information may be available in the logs.",
|
||||
"healing_complete": "{device} has been healed.",
|
||||
"in_progress": "{device} healing is in progress.",
|
||||
"network_heal_in_progress": "A Z-Wave network heal is already in progress. Please wait for it to finish before healing an individual device."
|
||||
"traffic_warning": "The route rebuilding process generates a large amount of traffic on the Z-Wave network. This may cause devices to respond slowly (or not at all) while the rebuilding is in progress.",
|
||||
"start_rebuilding_routes": "Rebuild Routes for Device",
|
||||
"rebuilding_routes_failed": "{device} routes could not be rebuild.",
|
||||
"rebuilding_routes_failed_check_logs": "Additional information may be available in the logs.",
|
||||
"rebuilding_routes_complete": "{device} routes have been rebuilt.",
|
||||
"in_progress": "{device} routes rebuild is in progress.",
|
||||
"routes_rebuild_in_progress": "A Z-Wave routes rebuild is already in progress. Please wait for it to finish before rebuilding routes for an individual device."
|
||||
},
|
||||
"update_firmware": {
|
||||
"title": "Update device firmware",
|
||||
@ -5562,6 +5574,13 @@
|
||||
"no_match": "No intent matched",
|
||||
"language": "[%key:ui::components::language-picker::language%]"
|
||||
},
|
||||
"debug": {
|
||||
"title": "Debug tools",
|
||||
"debug_connection": {
|
||||
"title": "Debug connection",
|
||||
"description": "Observe requests to the server and responses from the server in browser console."
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"title": "Events",
|
||||
"description": "Fire an event on the event bus.",
|
||||
|
@ -230,6 +230,7 @@ export interface HomeAssistant {
|
||||
suspendWhenHidden: boolean;
|
||||
enableShortcuts: boolean;
|
||||
vibrate: boolean;
|
||||
debugConnection: boolean;
|
||||
dockedSidebar: "docked" | "always_hidden" | "auto";
|
||||
defaultPanel: string;
|
||||
moreInfoEntityId: string | null;
|
||||
|
@ -5,6 +5,7 @@ const STORED_STATE = [
|
||||
"selectedTheme",
|
||||
"selectedLanguage",
|
||||
"vibrate",
|
||||
"debugConnection",
|
||||
"suspendWhenHidden",
|
||||
"enableShortcuts",
|
||||
"defaultPanel",
|
||||
|
16
yarn.lock
@ -4539,12 +4539,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/serve-handler@npm:6.1.1":
|
||||
version: 6.1.1
|
||||
resolution: "@types/serve-handler@npm:6.1.1"
|
||||
"@types/serve-handler@npm:6.1.2":
|
||||
version: 6.1.2
|
||||
resolution: "@types/serve-handler@npm:6.1.2"
|
||||
dependencies:
|
||||
"@types/node": "*"
|
||||
checksum: f519f83b18d7dea80f188f387a56dfe30fe944196849c470902fabf9db344c083c470f67e3362ad3f2294512950bc55924282c5c7a911ec8d507c37c6861d8ce
|
||||
checksum: 6b206cba18bf77b938e340e1015c631d92b492918ba78dfdff57590a25da8c4bc63fba90f43d763f854c5aa523b243c283ba84d14cfeb1841795337c8b978bd6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -9072,9 +9072,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"get-func-name@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "get-func-name@npm:2.0.0"
|
||||
checksum: 8d82e69f3e7fab9e27c547945dfe5cc0c57fc0adf08ce135dddb01081d75684a03e7a0487466f478872b341d52ac763ae49e660d01ab83741f74932085f693c3
|
||||
version: 2.0.2
|
||||
resolution: "get-func-name@npm:2.0.2"
|
||||
checksum: 3f62f4c23647de9d46e6f76d2b3eafe58933a9b3830c60669e4180d6c601ce1b4aa310ba8366143f55e52b139f992087a9f0647274e8745621fa2af7e0acf13b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -9722,7 +9722,7 @@ __metadata:
|
||||
"@types/luxon": 3.3.2
|
||||
"@types/mocha": 10.0.1
|
||||
"@types/qrcode": 1.5.2
|
||||
"@types/serve-handler": 6.1.1
|
||||
"@types/serve-handler": 6.1.2
|
||||
"@types/sortablejs": 1.15.2
|
||||
"@types/tar": 6.1.6
|
||||
"@types/ua-parser-js": 0.7.37
|
||||
|