Merge pull request #9510 from home-assistant/dev

This commit is contained in:
Bram Kragten 2021-07-06 11:09:42 +02:00 committed by GitHub
commit fabbcac99f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 3302 additions and 424 deletions

View File

@ -302,15 +302,23 @@ gulp.task("gen-index-hassio-prod", async () => {
function writeHassioEntrypoint(latestEntrypoint, es5Entrypoint) {
fs.mkdirSync(paths.hassio_output_root, { recursive: true });
// Safari 12 and below does not have a compliant ES2015 implementation of template literals, so we ship ES5
fs.writeFileSync(
path.resolve(paths.hassio_output_root, "entrypoint.js"),
`
try {
new Function("import('${latestEntrypoint}')")();
} catch (err) {
function loadES5() {
var el = document.createElement('script');
el.src = '${es5Entrypoint}';
document.body.appendChild(el);
}
if (/.*Version\\/(?:11|12)(?:\\.\\d+)*.*Safari\\//.test(navigator.userAgent)) {
loadES5();
} else {
try {
new Function("import('${latestEntrypoint}')")();
} catch (err) {
loadES5();
}
}
`,
{ encoding: "utf-8" }

View File

@ -9,12 +9,6 @@ if [ -z "${DEVCONTAINER}" ]; then
exit 1
fi
if [ ! -z "${CODESPACES}" ]; then
WORKSPACE="/root/workspace/frontend"
else
WORKSPACE="/workspaces/frontend"
fi
if [ -z $(which hass) ]; then
echo "Installing Home Asstant core from dev."
python3 -m pip install --upgrade \
@ -22,9 +16,9 @@ if [ -z $(which hass) ]; then
git+git://github.com/home-assistant/home-assistant.git@dev
fi
if [ ! -d "${WORKSPACE}/config" ]; then
if [ ! -d "/workspaces/frontend/config" ]; then
echo "Creating default configuration."
mkdir -p "${WORKSPACE}/config";
mkdir -p "/workspaces/frontend/config";
hass --script ensure_config -c config
echo "demo:
@ -32,24 +26,24 @@ logger:
default: info
logs:
homeassistant.components.frontend: debug
" >> "${WORKSPACE}/config/configuration.yaml"
" >> /workspaces/frontend/config/configuration.yaml
if [ ! -z "${HASSIO}" ]; then
echo "
# frontend:
# development_repo: ${WORKSPACE}
# development_repo: /workspaces/frontend
hassio:
development_repo: ${WORKSPACE}" >> "${WORKSPACE}/config/configuration.yaml"
development_repo: /workspaces/frontend" >> /workspaces/frontend/config/configuration.yaml
else
echo "
frontend:
development_repo: ${WORKSPACE}
development_repo: /workspaces/frontend
# hassio:
# development_repo: ${WORKSPACE}" >> "${WORKSPACE}/config/configuration.yaml"
# development_repo: /workspaces/frontend" >> /workspaces/frontend/config/configuration.yaml
fi
fi
hass -c "${WORKSPACE}/config"
hass -c /workspaces/frontend/config

View File

@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name="home-assistant-frontend",
version="20210630.0",
version="20210706.0",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/home-assistant-polymer",
author="The Home Assistant Authors",

View File

@ -20,7 +20,7 @@ interface Tooltip extends TooltipModel<any> {
export default class HaChartBase extends LitElement {
public chart?: Chart;
@property()
@property({ attribute: "chart-type", reflect: true })
public chartType: ChartType = "line";
@property({ attribute: false })
@ -228,6 +228,9 @@ export default class HaChartBase extends LitElement {
height: 0;
transition: height 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
:host(:not([chart-type="timeline"])) canvas {
max-height: 400px;
}
.chartLegend {
text-align: center;
}

View File

@ -30,7 +30,7 @@ class StateHistoryChartLine extends LitElement {
<ha-chart-base
.data=${this._chartData}
.options=${this._chartOptions}
chartType="line"
chart-type="line"
></ha-chart-base>
`;
}

View File

@ -98,7 +98,7 @@ export class StateHistoryChartTimeline extends LitElement {
<ha-chart-base
.data=${this._chartData}
.options=${this._chartOptions}
chartType="timeline"
chart-type="timeline"
></ha-chart-base>
`;
}

View File

@ -1,16 +1,16 @@
import { dump } from "js-yaml";
import { html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../../components/ha-code-editor";
import "../../../../components/ha-icon-button";
import { AutomationTraceExtended } from "../../../../data/trace";
import { HomeAssistant } from "../../../../types";
import "../ha-code-editor";
import "../ha-icon-button";
import { TraceExtended } from "../../data/trace";
import { HomeAssistant } from "../../types";
@customElement("ha-automation-trace-blueprint-config")
export class HaAutomationTraceBlueprintConfig extends LitElement {
@customElement("ha-trace-blueprint-config")
export class HaTraceBlueprintConfig extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public trace!: AutomationTraceExtended;
@property({ attribute: false }) public trace!: TraceExtended;
protected render(): TemplateResult {
return html`
@ -24,6 +24,6 @@ export class HaAutomationTraceBlueprintConfig extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"ha-automation-trace-blueprint-config": HaAutomationTraceBlueprintConfig;
"ha-trace-blueprint-config": HaTraceBlueprintConfig;
}
}

View File

@ -1,16 +1,16 @@
import { dump } from "js-yaml";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../../components/ha-code-editor";
import "../../../../components/ha-icon-button";
import { AutomationTraceExtended } from "../../../../data/trace";
import { HomeAssistant } from "../../../../types";
import "../ha-code-editor";
import "../ha-icon-button";
import { TraceExtended } from "../../data/trace";
import { HomeAssistant } from "../../types";
@customElement("ha-automation-trace-config")
export class HaAutomationTraceConfig extends LitElement {
@customElement("ha-trace-config")
export class HaTraceConfig extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public trace!: AutomationTraceExtended;
@property({ attribute: false }) public trace!: TraceExtended;
protected render(): TemplateResult {
return html`
@ -28,6 +28,6 @@ export class HaAutomationTraceConfig extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"ha-automation-trace-config": HaAutomationTraceConfig;
"ha-trace-config": HaTraceConfig;
}
}

View File

@ -1,16 +1,19 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../../components/trace/hat-logbook-note";
import type { LogbookEntry } from "../../../../data/logbook";
import type { HomeAssistant } from "../../../../types";
import "../../../logbook/ha-logbook";
import { LogbookEntry } from "../../data/logbook";
import { HomeAssistant } from "../../types";
import "./hat-logbook-note";
import "../../panels/logbook/ha-logbook";
import { TraceExtended } from "../../data/trace";
@customElement("ha-automation-trace-logbook")
export class HaAutomationTraceLogbook extends LitElement {
@customElement("ha-trace-logbook")
export class HaTraceLogbook extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
@property({ attribute: false }) public trace!: TraceExtended;
@property({ attribute: false }) public logbookEntries!: LogbookEntry[];
protected render(): TemplateResult {
@ -22,7 +25,7 @@ export class HaAutomationTraceLogbook extends LitElement {
.entries=${this.logbookEntries}
.narrow=${this.narrow}
></ha-logbook>
<hat-logbook-note></hat-logbook-note>
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
`
: html`<div class="padded-box">
No Logbook entries found for this step.
@ -42,6 +45,6 @@ export class HaAutomationTraceLogbook extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"ha-automation-trace-logbook": HaAutomationTraceLogbook;
"ha-trace-logbook": HaTraceLogbook;
}
}

View File

@ -2,33 +2,33 @@ import { dump } from "js-yaml";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { formatDateTimeWithSeconds } from "../../../../common/datetime/format_date_time";
import "../../../../components/ha-code-editor";
import "../../../../components/ha-icon-button";
import type { NodeInfo } from "../../../../components/trace/hat-graph";
import "../../../../components/trace/hat-logbook-note";
import { LogbookEntry } from "../../../../data/logbook";
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
import "../ha-code-editor";
import "../ha-icon-button";
import type { NodeInfo } from "./hat-graph";
import "./hat-logbook-note";
import { LogbookEntry } from "../../data/logbook";
import {
ActionTraceStep,
AutomationTraceExtended,
ChooseActionTraceStep,
getDataFromPath,
} from "../../../../data/trace";
import { HomeAssistant } from "../../../../types";
import "../../../logbook/ha-logbook";
import { traceTabStyles } from "./styles";
TraceExtended,
} from "../../data/trace";
import "../../panels/logbook/ha-logbook";
import { traceTabStyles } from "./trace-tab-styles";
import { HomeAssistant } from "../../types";
@customElement("ha-automation-trace-path-details")
export class HaAutomationTracePathDetails extends LitElement {
@customElement("ha-trace-path-details")
export class HaTracePathDetails extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
@property() private selected!: NodeInfo;
@property({ attribute: false }) public trace!: TraceExtended;
@property() public trace!: AutomationTraceExtended;
@property({ attribute: false }) public logbookEntries!: LogbookEntry[];
@property() public logbookEntries!: LogbookEntry[];
@property({ attribute: false }) public selected!: NodeInfo;
@property() renderedNodes: Record<string, any> = {};
@ -230,7 +230,7 @@ export class HaAutomationTracePathDetails extends LitElement {
.entries=${entries}
.narrow=${this.narrow}
></ha-logbook>
<hat-logbook-note></hat-logbook-note>
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
`
: html`<div class="padded-box">
No Logbook entries found for this step.
@ -267,6 +267,6 @@ export class HaAutomationTracePathDetails extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"ha-automation-trace-path-details": HaAutomationTracePathDetails;
"ha-trace-path-details": HaTracePathDetails;
}
}

View File

@ -1,17 +1,17 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import type { NodeInfo } from "../../../../components/trace/hat-graph";
import "../../../../components/trace/hat-logbook-note";
import "../../../../components/trace/hat-trace-timeline";
import type { LogbookEntry } from "../../../../data/logbook";
import type { AutomationTraceExtended } from "../../../../data/trace";
import type { HomeAssistant } from "../../../../types";
import type { NodeInfo } from "./hat-graph";
import "./hat-logbook-note";
import "./hat-trace-timeline";
import type { LogbookEntry } from "../../data/logbook";
import type { TraceExtended } from "../../data/trace";
import type { HomeAssistant } from "../../types";
@customElement("ha-automation-trace-timeline")
export class HaAutomationTraceTimeline extends LitElement {
@customElement("ha-trace-timeline")
export class HaTraceTimeline extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public trace!: AutomationTraceExtended;
@property({ attribute: false }) public trace!: TraceExtended;
@property({ attribute: false }) public logbookEntries!: LogbookEntry[];
@ -27,7 +27,7 @@ export class HaAutomationTraceTimeline extends LitElement {
allowPick
>
</hat-trace-timeline>
<hat-logbook-note></hat-logbook-note>
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
`;
}
@ -45,6 +45,6 @@ export class HaAutomationTraceTimeline extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"ha-automation-trace-timeline": HaAutomationTraceTimeline;
"ha-trace-timeline": HaTraceTimeline;
}
}

View File

@ -8,7 +8,7 @@ export class HatGraphNode extends LitElement {
@property({ reflect: true, type: Boolean }) disabled?: boolean;
@property({ reflect: true, type: Boolean }) graphstart?: boolean;
@property({ reflect: true, type: Boolean }) graphStart?: boolean;
@property({ reflect: true, type: Boolean }) nofocus?: boolean;
@ -21,20 +21,20 @@ export class HatGraphNode extends LitElement {
}
render() {
const height = NODE_SIZE + (this.graphstart ? 2 : SPACING + 1);
const height = NODE_SIZE + (this.graphStart ? 2 : SPACING + 1);
const width = SPACING + NODE_SIZE;
return svg`
<svg
width="${width}px"
height="${height}px"
viewBox="-${Math.ceil(width / 2)} -${
this.graphstart
this.graphStart
? Math.ceil(height / 2)
: Math.ceil((NODE_SIZE + SPACING * 2) / 2)
} ${width} ${height}"
>
${
this.graphstart
this.graphStart
? ``
: svg`
<path

View File

@ -30,16 +30,16 @@ export class HatGraph extends LitElement {
@property({ reflect: true, type: Boolean }) branching?: boolean;
@property({ reflect: true, converter: track_converter })
@property({ converter: track_converter })
track_start?: number[];
@property({ reflect: true, converter: track_converter }) track_end?: number[];
@property({ converter: track_converter }) track_end?: number[];
@property({ reflect: true, type: Boolean }) disabled?: boolean;
@property({ reflect: true, type: Boolean }) selected?: boolean;
@property({ type: Boolean }) selected?: boolean;
@property({ reflect: true, type: Boolean }) short = false;
@property({ type: Boolean }) short = false;
async updateChildren() {
this._num_items = this.children.length;
@ -68,7 +68,7 @@ export class HatGraph extends LitElement {
return html`
<slot name="head" @slotchange=${this.updateChildren}> </slot>
${this.branching
${this.branching && branches.some((branch) => !branch.start)
? svg`
<svg
id="top"

View File

@ -1,11 +1,13 @@
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";
import { customElement, property } from "lit/decorators";
@customElement("hat-logbook-note")
class HatLogbookNote extends LitElement {
@property() public domain = "automation";
render() {
return html`
Not all shown logbook entries might be related to this automation.
Not all shown logbook entries might be related to this ${this.domain}.
`;
}

View File

@ -36,9 +36,9 @@ import {
WaitForTriggerAction,
} from "../../data/script";
import {
AutomationTraceExtended,
ChooseActionTraceStep,
ConditionTraceStep,
TraceExtended,
} from "../../data/trace";
import "../ha-svg-icon";
import { NodeInfo, NODE_SIZE, SPACING } from "./hat-graph";
@ -53,7 +53,7 @@ declare global {
@customElement("hat-script-graph")
class HatScriptGraph extends LitElement {
@property({ attribute: false }) public trace!: AutomationTraceExtended;
@property({ attribute: false }) public trace!: TraceExtended;
@property({ attribute: false }) public selected;
@ -137,7 +137,11 @@ class HatScriptGraph extends LitElement {
`;
}
private render_choose_node(config: ChooseAction, path: string) {
private render_choose_node(
config: ChooseAction,
path: string,
graphStart = false
) {
const trace = this.trace.trace[path] as ChooseActionTraceStep[] | undefined;
const trace_path = trace?.[0].result
? trace[0].result.choice === "default"
@ -157,6 +161,7 @@ class HatScriptGraph extends LitElement {
})}
>
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiCallSplit}
class=${classMap({
track: trace !== undefined,
@ -210,7 +215,11 @@ class HatScriptGraph extends LitElement {
`;
}
private render_condition_node(node: Condition, path: string) {
private render_condition_node(
node: Condition,
path: string,
graphStart = false
) {
const trace = (this.trace.trace[path] as ConditionTraceStep[]) || undefined;
const track_path =
trace?.[0].result === undefined ? 0 : trace[0].result.result ? 1 : 2;
@ -228,23 +237,18 @@ class HatScriptGraph extends LitElement {
short
>
<hat-graph-node
.graphStart=${graphStart}
slot="head"
class=${classMap({
track: Boolean(trace),
})}
.iconPath=${mdiAbTesting}
nofocus
graphEnd
></hat-graph-node>
<div
style=${`width: ${NODE_SIZE + SPACING}px;`}
graphStart
graphEnd
></div>
<div style=${`width: ${NODE_SIZE + SPACING}px;`}></div>
<div></div>
<hat-graph-node
.iconPath=${mdiClose}
graphEnd
nofocus
class=${classMap({
track: track_path === 2,
@ -254,9 +258,14 @@ class HatScriptGraph extends LitElement {
`;
}
private render_delay_node(node: DelayAction, path: string) {
private render_delay_node(
node: DelayAction,
path: string,
graphStart = false
) {
return html`
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiTimerOutline}
@focus=${this.selectNode(node, path)}
class=${classMap({
@ -268,9 +277,14 @@ class HatScriptGraph extends LitElement {
`;
}
private render_device_node(node: DeviceAction, path: string) {
private render_device_node(
node: DeviceAction,
path: string,
graphStart = false
) {
return html`
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiDevices}
@focus=${this.selectNode(node, path)}
class=${classMap({
@ -282,9 +296,14 @@ class HatScriptGraph extends LitElement {
`;
}
private render_event_node(node: EventAction, path: string) {
private render_event_node(
node: EventAction,
path: string,
graphStart = false
) {
return html`
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiExclamation}
@focus=${this.selectNode(node, path)}
class=${classMap({
@ -296,7 +315,11 @@ class HatScriptGraph extends LitElement {
`;
}
private render_repeat_node(node: RepeatAction, path: string) {
private render_repeat_node(
node: RepeatAction,
path: string,
graphStart = false
) {
const trace: any = this.trace.trace[path];
const track_path = trace ? [0, 1] : [];
const repeats = this.trace?.trace[`${path}/repeat/sequence/0`]?.length;
@ -313,6 +336,7 @@ class HatScriptGraph extends LitElement {
})}
>
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiRefresh}
class=${classMap({
track: trace,
@ -337,9 +361,14 @@ class HatScriptGraph extends LitElement {
`;
}
private render_scene_node(node: SceneAction, path: string) {
private render_scene_node(
node: SceneAction,
path: string,
graphStart = false
) {
return html`
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiExclamation}
@focus=${this.selectNode(node, path)}
class=${classMap({
@ -351,9 +380,14 @@ class HatScriptGraph extends LitElement {
`;
}
private render_service_node(node: ServiceAction, path: string) {
private render_service_node(
node: ServiceAction,
path: string,
graphStart = false
) {
return html`
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiChevronRight}
@focus=${this.selectNode(node, path)}
class=${classMap({
@ -367,10 +401,12 @@ class HatScriptGraph extends LitElement {
private render_wait_node(
node: WaitAction | WaitForTriggerAction,
path: string
path: string,
graphStart = false
) {
return html`
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiTrafficLight}
@focus=${this.selectNode(node, path)}
class=${classMap({
@ -382,9 +418,10 @@ class HatScriptGraph extends LitElement {
`;
}
private render_other_node(node: Action, path: string) {
private render_other_node(node: Action, path: string, graphStart = false) {
return html`
<hat-graph-node
.graphStart=${graphStart}
.iconPath=${mdiCodeBrackets}
@focus=${this.selectNode(node, path)}
class=${classMap({
@ -395,7 +432,7 @@ class HatScriptGraph extends LitElement {
`;
}
private render_node(node: Action, path: string) {
private render_node(node: Action, path: string, graphStart = false) {
const NODE_TYPES = {
choose: this.render_choose_node,
condition: this.render_condition_node,
@ -411,7 +448,7 @@ class HatScriptGraph extends LitElement {
};
const type = Object.keys(NODE_TYPES).find((key) => key in node) || "other";
const nodeEl = NODE_TYPES[type].bind(this)(node, path);
const nodeEl = NODE_TYPES[type].bind(this)(node, path, graphStart);
this.renderedNodes[path] = { config: node, path };
if (this.trace && path in this.trace.trace) {
this.trackedNodes[path] = this.renderedNodes[path];
@ -423,35 +460,47 @@ class HatScriptGraph extends LitElement {
const paths = Object.keys(this.trackedNodes);
const manual_triggered = this.trace && "trigger" in this.trace.trace;
let track_path = manual_triggered ? undefined : [0];
const trigger_nodes = ensureArray(this.trace.config.trigger).map(
(trigger, i) => {
if (this.trace && `trigger/${i}` in this.trace.trace) {
track_path = [i];
}
return this.render_trigger(trigger, i);
}
);
const trigger_nodes =
"trigger" in this.trace.config
? ensureArray(this.trace.config.trigger).map((trigger, i) => {
if (this.trace && `trigger/${i}` in this.trace.trace) {
track_path = [i];
}
return this.render_trigger(trigger, i);
})
: undefined;
try {
return html`
<hat-graph class="parent">
<div></div>
<hat-graph
branching
id="trigger"
.short=${trigger_nodes.length < 2}
.track_start=${track_path}
.track_end=${track_path}
>
${trigger_nodes}
</hat-graph>
<hat-graph id="condition">
${ensureArray(this.trace.config.condition)?.map((condition, i) =>
this.render_condition(condition!, i)
)}
</hat-graph>
${ensureArray(this.trace.config.action).map((action, i) =>
this.render_node(action, `action/${i}`)
)}
${trigger_nodes
? html`<hat-graph
branching
id="trigger"
.short=${trigger_nodes.length < 2}
.track_start=${track_path}
.track_end=${track_path}
>
${trigger_nodes}
</hat-graph>`
: ""}
${"condition" in this.trace.config
? html`<hat-graph id="condition">
${ensureArray(
this.trace.config.condition
)?.map((condition, i) => this.render_condition(condition!, i))}
</hat-graph>`
: ""}
${"action" in this.trace.config
? html`${ensureArray(this.trace.config.action).map((action, i) =>
this.render_node(action, `action/${i}`)
)}`
: ""}
${"sequence" in this.trace.config
? html`${ensureArray(this.trace.config.sequence).map((action, i) =>
this.render_node(action, `sequence/${i}`, i === 0)
)}`
: ""}
</hat-graph>
<div class="actions">
<mwc-icon-button
@ -564,6 +613,7 @@ class HatScriptGraph extends LitElement {
}
.parent {
margin-left: 8px;
margin-top: 16px;
}
.error {
padding: 16px;

View File

@ -51,7 +51,18 @@ export interface ForDict {
seconds?: number | string;
}
export interface StateTrigger {
export interface ContextConstraint {
context_id?: string;
parent_id?: string;
user_id?: string | string[];
}
export interface BaseTrigger {
platform: string;
id?: string;
}
export interface StateTrigger extends BaseTrigger {
platform: "state";
entity_id: string;
attribute?: string;
@ -60,25 +71,25 @@ export interface StateTrigger {
for?: string | number | ForDict;
}
export interface MqttTrigger {
export interface MqttTrigger extends BaseTrigger {
platform: "mqtt";
topic: string;
payload?: string;
}
export interface GeoLocationTrigger {
export interface GeoLocationTrigger extends BaseTrigger {
platform: "geo_location";
source: string;
zone: string;
event: "enter" | "leave";
}
export interface HassTrigger {
export interface HassTrigger extends BaseTrigger {
platform: "homeassistant";
event: "start" | "shutdown";
}
export interface NumericStateTrigger {
export interface NumericStateTrigger extends BaseTrigger {
platform: "numeric_state";
entity_id: string;
attribute?: string;
@ -88,54 +99,48 @@ export interface NumericStateTrigger {
for?: string | number | ForDict;
}
export interface SunTrigger {
export interface SunTrigger extends BaseTrigger {
platform: "sun";
offset: number;
event: "sunrise" | "sunset";
}
export interface TimePatternTrigger {
export interface TimePatternTrigger extends BaseTrigger {
platform: "time_pattern";
hours?: number | string;
minutes?: number | string;
seconds?: number | string;
}
export interface WebhookTrigger {
export interface WebhookTrigger extends BaseTrigger {
platform: "webhook";
webhook_id: string;
}
export interface ZoneTrigger {
export interface ZoneTrigger extends BaseTrigger {
platform: "zone";
entity_id: string;
zone: string;
event: "enter" | "leave";
}
export interface TagTrigger {
export interface TagTrigger extends BaseTrigger {
platform: "tag";
tag_id: string;
device_id?: string;
}
export interface TimeTrigger {
export interface TimeTrigger extends BaseTrigger {
platform: "time";
at: string;
}
export interface TemplateTrigger {
export interface TemplateTrigger extends BaseTrigger {
platform: "template";
value_template: string;
}
export interface ContextConstraint {
context_id?: string;
parent_id?: string;
user_id?: string | string[];
}
export interface EventTrigger {
export interface EventTrigger extends BaseTrigger {
platform: "event";
event_type: string;
event_data?: any;
@ -158,24 +163,26 @@ export type Trigger =
| EventTrigger
| DeviceTrigger;
export interface LogicalCondition {
condition: "and" | "not" | "or";
interface BaseCondition {
condition: string;
alias?: string;
}
export interface LogicalCondition extends BaseCondition {
condition: "and" | "not" | "or";
conditions: Condition | Condition[];
}
export interface StateCondition {
export interface StateCondition extends BaseCondition {
condition: "state";
alias?: string;
entity_id: string;
attribute?: string;
state: string | number;
for?: string | number | ForDict;
}
export interface NumericStateCondition {
export interface NumericStateCondition extends BaseCondition {
condition: "numeric_state";
alias?: string;
entity_id: string;
attribute?: string;
above?: number;
@ -183,36 +190,37 @@ export interface NumericStateCondition {
value_template?: string;
}
export interface SunCondition {
export interface SunCondition extends BaseCondition {
condition: "sun";
alias?: string;
after_offset: number;
before_offset: number;
after: "sunrise" | "sunset";
before: "sunrise" | "sunset";
}
export interface ZoneCondition {
export interface ZoneCondition extends BaseCondition {
condition: "zone";
alias?: string;
entity_id: string;
zone: string;
}
export interface TimeCondition {
export interface TimeCondition extends BaseCondition {
condition: "time";
alias?: string;
after?: string;
before?: string;
weekday?: string | string[];
}
export interface TemplateCondition {
export interface TemplateCondition extends BaseCondition {
condition: "template";
alias?: string;
value_template: string;
}
export interface TriggerCondition extends BaseCondition {
condition: "trigger";
id: string;
}
export type Condition =
| StateCondition
| NumericStateCondition
@ -221,7 +229,8 @@ export type Condition =
| TimeCondition
| TemplateCondition
| DeviceCondition
| LogicalCondition;
| LogicalCondition
| TriggerCondition;
export const triggerAutomationActions = (
hass: HomeAssistant,

View File

@ -1,6 +1,7 @@
import { computeStateName } from "../common/entity/compute_state_name";
import { HaFormSchema } from "../components/ha-form/ha-form";
import { HomeAssistant } from "../types";
import { BaseTrigger } from "./automation";
export interface DeviceAutomation {
alias?: string;
@ -20,9 +21,10 @@ export interface DeviceCondition extends DeviceAutomation {
condition: "device";
}
export interface DeviceTrigger extends DeviceAutomation {
platform: "device";
}
export type DeviceTrigger = DeviceAutomation &
BaseTrigger & {
platform: "device";
};
export interface DeviceCapabilities {
extra_fields: HaFormSchema[];

View File

@ -7,6 +7,7 @@ import { computeObjectId } from "../common/entity/compute_object_id";
import { navigate } from "../common/navigate";
import { HomeAssistant } from "../types";
import { Condition, Trigger } from "./automation";
import { BlueprintInput } from "./blueprint";
export const MODES = ["single", "restart", "queued", "parallel"] as const;
export const MODES_MAX = ["queued", "parallel"];
@ -28,6 +29,10 @@ export interface ScriptConfig {
max?: number;
}
export interface BlueprintScriptConfig extends ScriptConfig {
use_blueprint: { path: string; input?: BlueprintInput };
}
export interface EventAction {
alias?: string;
event: string;

View File

@ -4,6 +4,7 @@ import {
BlueprintAutomationConfig,
ManualAutomationConfig,
} from "./automation";
import { BlueprintScriptConfig, ScriptConfig } from "./script";
interface BaseTraceStep {
path: string;
@ -54,7 +55,7 @@ export type ActionTraceStep =
| ChooseActionTraceStep
| ChooseChoiceActionTraceStep;
export interface AutomationTrace {
interface BaseTrace {
domain: string;
item_id: string;
last_step: string | null;
@ -81,23 +82,46 @@ export interface AutomationTrace {
// The exception is in the trace itself or in the last element of the trace
// Script execution stopped by async_stop called on the script run because home assistant is shutting down, script mode is SCRIPT_MODE_RESTART etc:
| "cancelled";
// Automation only, should become it's own type when we support script in frontend
}
interface BaseTraceExtended {
trace: Record<string, ActionTraceStep[]>;
context: Context;
error?: string;
}
export interface AutomationTrace extends BaseTrace {
domain: "automation";
trigger: string;
}
export interface AutomationTraceExtended extends AutomationTrace {
trace: Record<string, ActionTraceStep[]>;
context: Context;
export interface AutomationTraceExtended
extends AutomationTrace,
BaseTraceExtended {
config: ManualAutomationConfig;
blueprint_inputs?: BlueprintAutomationConfig;
error?: string;
}
export interface ScriptTrace extends BaseTrace {
domain: "script";
}
export interface ScriptTraceExtended extends ScriptTrace, BaseTraceExtended {
config: ScriptConfig;
blueprint_inputs?: BlueprintScriptConfig;
}
export type TraceExtended = AutomationTraceExtended | ScriptTraceExtended;
interface TraceTypes {
automation: {
short: AutomationTrace;
extended: AutomationTraceExtended;
};
script: {
short: ScriptTrace;
extended: ScriptTraceExtended;
};
}
export const loadTrace = <T extends keyof TraceTypes>(
@ -141,7 +165,7 @@ export const loadTraceContexts = (
});
export const getDataFromPath = (
config: ManualAutomationConfig,
config: TraceExtended["config"],
path: string
): any => {
const parts = path.split("/").reverse();

View File

@ -20,6 +20,7 @@ import "./types/ha-automation-condition-state";
import "./types/ha-automation-condition-sun";
import "./types/ha-automation-condition-template";
import "./types/ha-automation-condition-time";
import "./types/ha-automation-condition-trigger";
import "./types/ha-automation-condition-zone";
const OPTIONS = [
@ -32,6 +33,7 @@ const OPTIONS = [
"sun",
"template",
"time",
"trigger",
"zone",
];

View File

@ -0,0 +1,99 @@
import { html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../../common/dom/fire_event";
import {
AutomationConfig,
Trigger,
TriggerCondition,
} from "../../../../../data/automation";
import { HomeAssistant } from "../../../../../types";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
import { ensureArray } from "../../../../../common/ensure-array";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
@customElement("ha-automation-condition-trigger")
export class HaTriggerCondition extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public condition!: TriggerCondition;
@state() private _triggers?: Trigger | Trigger[];
private _unsub?: UnsubscribeFunc;
public static get defaultConfig() {
return {
id: "",
};
}
connectedCallback() {
super.connectedCallback();
const details = { callback: (config) => this._automationUpdated(config) };
fireEvent(this, "subscribe-automation-config", details);
this._unsub = (details as any).unsub;
}
disconnectedCallback() {
super.disconnectedCallback();
if (this._unsub) {
this._unsub();
}
}
protected render() {
const { id } = this.condition;
if (!this._triggers) {
return this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.trigger.no_triggers"
);
}
return html`<paper-dropdown-menu-light
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.trigger.id"
)}
no-animations
>
<paper-listbox
slot="dropdown-content"
.selected=${id}
attr-for-selected="data-trigger-id"
@selected-item-changed=${this._triggerPicked}
>
${ensureArray(this._triggers).map((trigger) =>
trigger.id
? html`
<paper-item data-trigger-id=${trigger.id}>
${trigger.id}
</paper-item>
`
: ""
)}
</paper-listbox>
</paper-dropdown-menu-light>`;
}
private _automationUpdated(config?: AutomationConfig) {
this._triggers = config?.trigger;
}
private _triggerPicked(ev: CustomEvent) {
ev.stopPropagation();
if (!ev.detail.value) {
return;
}
const newTrigger = ev.detail.value.dataset.triggerId;
if (this.condition.id === newTrigger) {
return;
}
fireEvent(this, "value-changed", {
value: { ...this.condition, id: newTrigger },
});
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-trigger": HaTriggerCondition;
}
}

View File

@ -1,4 +1,3 @@
import "@polymer/paper-radio-button/paper-radio-button";
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../../../../common/dom/fire_event";

View File

@ -11,6 +11,7 @@ import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
import "@polymer/paper-input/paper-textarea";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import {
css,
CSSResultGroup,
@ -51,12 +52,9 @@ import { HomeAssistant, Route } from "../../../types";
import { showToast } from "../../../util/toast";
import "../ha-config-section";
import { configSections } from "../ha-panel-config";
import "./action/ha-automation-action";
import { HaDeviceAction } from "./action/types/ha-automation-action-device_id";
import "./blueprint-automation-editor";
import "./condition/ha-automation-condition";
import "./manual-automation-editor";
import "./trigger/ha-automation-trigger";
import { HaDeviceTrigger } from "./trigger/types/ha-automation-trigger-device";
declare global {
@ -65,6 +63,10 @@ declare global {
}
// for fire event
interface HASSDomEvents {
"subscribe-automation-config": {
callback: (config: AutomationConfig) => void;
unsub?: UnsubscribeFunc;
};
"ui-mode-not-available": Error;
duplicate: undefined;
}
@ -95,6 +97,13 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
@query("ha-yaml-editor", true) private _editor?: HaYamlEditor;
private _configSubscriptions: Record<
string,
(config?: AutomationConfig) => void
> = {};
private _configSubscriptionsId = 1;
protected render(): TemplateResult {
const stateObj = this._entityId
? this.hass.states[this._entityId]
@ -200,6 +209,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
class="content ${classMap({
"yaml-mode": this._mode === "yaml",
})}"
@subscribe-automation-config=${this._subscribeAutomationConfig}
>
${this._errors
? html` <div class="errors">${this._errors}</div> `
@ -336,6 +346,12 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
) {
this._setEntityId();
}
if (changedProps.has("_config")) {
Object.values(this._configSubscriptions).forEach((sub) =>
sub(this._config)
);
}
}
private _setEntityId() {
@ -516,6 +532,15 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
);
}
private _subscribeAutomationConfig(ev) {
const id = this._configSubscriptionsId++;
this._configSubscriptions[id] = ev.detail.callback;
ev.detail.unsub = () => {
delete this._configSubscriptions[id];
};
ev.detail.callback(this._config);
}
protected handleKeyboardSave() {
this._saveAutomation();
}

View File

@ -9,31 +9,28 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { repeat } from "lit/directives/repeat";
import { isComponentLoaded } from "../../../../common/config/is_component_loaded";
import { formatDateTimeWithSeconds } from "../../../../common/datetime/format_date_time";
import type { NodeInfo } from "../../../../components/trace/hat-graph";
import "../../../../components/trace/hat-script-graph";
import { AutomationEntity } from "../../../../data/automation";
import {
getLogbookDataForContext,
LogbookEntry,
} from "../../../../data/logbook";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
import type { NodeInfo } from "../../../components/trace/hat-graph";
import "../../../components/trace/hat-script-graph";
import { AutomationEntity } from "../../../data/automation";
import { getLogbookDataForContext, LogbookEntry } from "../../../data/logbook";
import {
AutomationTrace,
AutomationTraceExtended,
loadTrace,
loadTraces,
} from "../../../../data/trace";
import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../../resources/styles";
import { HomeAssistant, Route } from "../../../../types";
import { configSections } from "../../ha-panel-config";
import "./ha-automation-trace-blueprint-config";
import "./ha-automation-trace-config";
import "./ha-automation-trace-logbook";
import "./ha-automation-trace-path-details";
import "./ha-automation-trace-timeline";
import { traceTabStyles } from "./styles";
} from "../../../data/trace";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { configSections } from "../ha-panel-config";
import "../../../components/trace/ha-trace-blueprint-config";
import "../../../components/trace/ha-trace-config";
import "../../../components/trace/ha-trace-logbook";
import "../../../components/trace/ha-trace-path-details";
import "../../../components/trace/ha-trace-timeline";
import { traceTabStyles } from "../../../components/trace/trace-tab-styles";
@customElement("ha-automation-trace")
export class HaAutomationTrace extends LitElement {
@ -209,7 +206,7 @@ export class HaAutomationTrace extends LitElement {
@click=${this._showTab}
>
Blueprint Config
</div>
</button>
`
: ""}
</div>
@ -219,46 +216,47 @@ export class HaAutomationTrace extends LitElement {
? ""
: this._view === "details"
? html`
<ha-automation-trace-path-details
<ha-trace-path-details
.hass=${this.hass}
.narrow=${this.narrow}
.trace=${this._trace}
.selected=${this._selected}
.logbookEntries=${this._logbookEntries}
.trackedNodes=${trackedNodes}
.renderedNodes=${renderedNodes}
></ha-automation-trace-path-details>
.renderedNodes=${renderedNodes!}
></ha-trace-path-details>
`
: this._view === "config"
? html`
<ha-automation-trace-config
<ha-trace-config
.hass=${this.hass}
.trace=${this._trace}
></ha-automation-trace-config>
></ha-trace-config>
`
: this._view === "logbook"
? html`
<ha-automation-trace-logbook
<ha-trace-logbook
.hass=${this.hass}
.narrow=${this.narrow}
.trace=${this._trace}
.logbookEntries=${this._logbookEntries}
></ha-automation-trace-logbook>
></ha-trace-logbook>
`
: this._view === "blueprint"
? html`
<ha-automation-trace-blueprint-config
<ha-trace-blueprint-config
.hass=${this.hass}
.trace=${this._trace}
></ha-automation-trace-blueprint-config>
></ha-trace-blueprint-config>
`
: html`
<ha-automation-trace-timeline
<ha-trace-timeline
.hass=${this.hass}
.trace=${this._trace}
.logbookEntries=${this._logbookEntries}
.selected=${this._selected}
@value-changed=${this._timelinePathPicked}
></ha-automation-trace-timeline>
></ha-trace-timeline>
`}
</div>
</div>

View File

@ -51,7 +51,7 @@ class HaConfigAutomation extends HassRouterPage {
},
trace: {
tag: "ha-automation-trace",
load: () => import("./trace/ha-automation-trace"),
load: () => import("./ha-automation-trace"),
},
},
};

View File

@ -162,6 +162,14 @@ export default class HaAutomationTriggerRow extends LitElement {
)}
</paper-listbox>
</paper-dropdown-menu-light>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.id"
)}
.value=${this.trigger.id}
@value-changed=${this._idChanged}
>
</paper-input>
<div>
${dynamicElement(
`ha-automation-trigger-${this.trigger.platform}`,
@ -212,15 +220,35 @@ export default class HaAutomationTriggerRow extends LitElement {
const elClass = customElements.get(`ha-automation-trigger-${type}`);
if (type !== this.trigger.platform) {
const value = {
platform: type,
...elClass.defaultConfig,
};
if (this.trigger.id) {
value.id = this.trigger.id;
}
fireEvent(this, "value-changed", {
value: {
platform: type,
...elClass.defaultConfig,
},
value,
});
}
}
private _idChanged(ev: CustomEvent) {
const newId = ev.detail.value;
if (newId === this.trigger.id) {
return;
}
const value = { ...this.trigger };
if (!newId) {
delete value.id;
} else {
value.id = newId;
}
fireEvent(this, "value-changed", {
value,
});
}
private _onYamlChange(ev: CustomEvent) {
ev.stopPropagation();
if (!ev.detail.isValid) {

View File

@ -42,6 +42,10 @@ class HaConfigScript extends HassRouterPage {
edit: {
tag: "ha-script-editor",
},
trace: {
tag: "ha-script-trace",
load: () => import("./ha-script-trace"),
},
},
};
@ -81,7 +85,7 @@ class HaConfigScript extends HassRouterPage {
if (
(!changedProps || changedProps.has("route")) &&
this._currentPage === "edit"
this._currentPage !== "dashboard"
) {
pageEl.creatingNew = undefined;
const scriptEntityId = this.routeTail.path.substr(1);

View File

@ -297,7 +297,16 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
<div
class="card-actions layout horizontal justified center"
>
<span></span>
<a
href="/config/script/trace/${this
.scriptEntityId}"
>
<mwc-button>
${this.hass.localize(
"ui.panel.config.script.editor.show_trace"
)}
</mwc-button>
</a>
<mwc-button
@click=${this._runScript}
title="${this.hass.localize(

View File

@ -1,6 +1,7 @@
import "@material/mwc-icon-button";
import {
mdiHelpCircle,
mdiHistory,
mdiInformationOutline,
mdiPencil,
mdiPlay,
@ -140,6 +141,21 @@ class HaScriptPicker extends LitElement {
</mwc-icon-button>
`,
};
columns.trace = {
title: "",
type: "icon-button",
template: (_info, script: any) => html`
<a href="/config/script/trace/${script.entity_id}">
<mwc-icon-button
.label=${this.hass.localize(
"ui.panel.config.script.picker.dev_script"
)}
>
<ha-svg-icon .path=${mdiHistory}></ha-svg-icon>
</mwc-icon-button>
</a>
`,
};
columns.edit = {
title: "",
type: "icon-button",

View File

@ -0,0 +1,502 @@
import {
mdiDownload,
mdiPencil,
mdiRayEndArrow,
mdiRayStartArrow,
mdiRefresh,
} from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { repeat } from "lit/directives/repeat";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
import type { NodeInfo } from "../../../components/trace/hat-graph";
import "../../../components/trace/hat-script-graph";
import { getLogbookDataForContext, LogbookEntry } from "../../../data/logbook";
import { ScriptEntity } from "../../../data/script";
import {
loadTrace,
loadTraces,
ScriptTrace,
ScriptTraceExtended,
} from "../../../data/trace";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { traceTabStyles } from "../../../components/trace/trace-tab-styles";
import { configSections } from "../ha-panel-config";
import "../../../components/trace/ha-trace-blueprint-config";
import "../../../components/trace/ha-trace-config";
import "../../../components/trace/ha-trace-logbook";
import "../../../components/trace/ha-trace-path-details";
import "../../../components/trace/ha-trace-timeline";
@customElement("ha-script-trace")
export class HaScriptTrace extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public scriptEntityId!: string;
@property({ attribute: false }) public scripts!: ScriptEntity[];
@property({ type: Boolean }) public isWide?: boolean;
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
@property({ attribute: false }) public route!: Route;
@state() private _traces?: ScriptTrace[];
@state() private _runId?: string;
@state() private _selected?: NodeInfo;
@state() private _trace?: ScriptTraceExtended;
@state() private _logbookEntries?: LogbookEntry[];
@state() private _view:
| "details"
| "config"
| "timeline"
| "logbook"
| "blueprint" = "details";
protected render(): TemplateResult {
const stateObj = this.scriptEntityId
? this.hass.states[this.scriptEntityId]
: undefined;
const graph = this.shadowRoot!.querySelector("hat-script-graph");
const trackedNodes = graph?.trackedNodes;
const renderedNodes = graph?.renderedNodes;
const title = stateObj?.attributes.friendly_name || this.scriptEntityId;
let devButtons: TemplateResult | string = "";
if (__DEV__) {
devButtons = html`<div style="position: absolute; right: 0;">
<button @click=${this._importTrace}>Import trace</button>
<button @click=${this._loadLocalStorageTrace}>Load stored trace</button>
</div>`;
}
const actionButtons = html`
<mwc-icon-button label="Refresh" @click=${() => this._loadTraces()}>
<ha-svg-icon .path=${mdiRefresh}></ha-svg-icon>
</mwc-icon-button>
<mwc-icon-button
.disabled=${!this._trace}
label="Download Trace"
@click=${this._downloadTrace}
>
<ha-svg-icon .path=${mdiDownload}></ha-svg-icon>
</mwc-icon-button>
`;
return html`
${devButtons}
<hass-tabs-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.route=${this.route}
.tabs=${configSections.automation}
>
${this.narrow
? html`<span slot="header"> ${title} </span>
<div slot="toolbar-icon">${actionButtons}</div>`
: ""}
<div class="toolbar">
${!this.narrow
? html`<div>
${title}
<a
class="linkButton"
href="/config/script/edit/${this.scriptEntityId}"
>
<mwc-icon-button label="Edit Script" tabindex="-1">
<ha-svg-icon .path=${mdiPencil}></ha-svg-icon>
</mwc-icon-button>
</a>
</div>`
: ""}
${this._traces && this._traces.length > 0
? html`
<div>
<mwc-icon-button
.disabled=${this._traces[this._traces.length - 1].run_id ===
this._runId}
label="Older trace"
@click=${this._pickOlderTrace}
>
<ha-svg-icon .path=${mdiRayEndArrow}></ha-svg-icon>
</mwc-icon-button>
<select .value=${this._runId} @change=${this._pickTrace}>
${repeat(
this._traces,
(trace) => trace.run_id,
(trace) =>
html`<option value=${trace.run_id}>
${formatDateTimeWithSeconds(
new Date(trace.timestamp.start),
this.hass.locale
)}
</option>`
)}
</select>
<mwc-icon-button
.disabled=${this._traces[0].run_id === this._runId}
label="Newer trace"
@click=${this._pickNewerTrace}
>
<ha-svg-icon .path=${mdiRayStartArrow}></ha-svg-icon>
</mwc-icon-button>
</div>
`
: ""}
${!this.narrow ? html`<div>${actionButtons}</div>` : ""}
</div>
${this._traces === undefined
? html`<div class="container">Loading…</div>`
: this._traces.length === 0
? html`<div class="container">No traces found</div>`
: this._trace === undefined
? ""
: html`
<div class="main">
<div class="graph">
<hat-script-graph
.trace=${this._trace}
.selected=${this._selected?.path}
@graph-node-selected=${this._pickNode}
></hat-script-graph>
</div>
<div class="info">
<div class="tabs top">
${[
["details", "Step Details"],
["timeline", "Trace Timeline"],
["logbook", "Related logbook entries"],
["config", "Script Config"],
].map(
([view, label]) => html`
<button
tabindex="0"
.view=${view}
class=${classMap({ active: this._view === view })}
@click=${this._showTab}
>
${label}
</button>
`
)}
${this._trace.blueprint_inputs
? html`
<button
tabindex="0"
.view=${"blueprint"}
class=${classMap({
active: this._view === "blueprint",
})}
@click=${this._showTab}
>
Blueprint Config
</button>
`
: ""}
</div>
${this._selected === undefined ||
this._logbookEntries === undefined ||
trackedNodes === undefined
? ""
: this._view === "details"
? html`
<ha-trace-path-details
.hass=${this.hass}
.narrow=${this.narrow}
.trace=${this._trace}
.selected=${this._selected}
.logbookEntries=${this._logbookEntries}
.trackedNodes=${trackedNodes}
.renderedNodes=${renderedNodes!}
></ha-trace-path-details>
`
: this._view === "config"
? html`
<ha-trace-config
.hass=${this.hass}
.trace=${this._trace}
></ha-trace-config>
`
: this._view === "logbook"
? html`
<ha-trace-logbook
.hass=${this.hass}
.narrow=${this.narrow}
.trace=${this._trace}
.logbookEntries=${this._logbookEntries}
></ha-trace-logbook>
`
: this._view === "blueprint"
? html`
<ha-trace-blueprint-config
.hass=${this.hass}
.trace=${this._trace}
></ha-trace-blueprint-config>
`
: html`
<ha-trace-timeline
.hass=${this.hass}
.trace=${this._trace}
.logbookEntries=${this._logbookEntries}
.selected=${this._selected}
@value-changed=${this._timelinePathPicked}
></ha-trace-timeline>
`}
</div>
</div>
`}
</hass-tabs-subpage>
`;
}
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
if (!this.scriptEntityId) {
return;
}
const params = new URLSearchParams(location.search);
this._loadTraces(params.get("run_id") || undefined);
}
protected updated(changedProps) {
super.updated(changedProps);
// Only reset if automationId has changed and we had one before.
if (changedProps.get("scriptEntityId")) {
this._traces = undefined;
this._runId = undefined;
this._trace = undefined;
this._logbookEntries = undefined;
if (this.scriptEntityId) {
this._loadTraces();
}
}
if (changedProps.has("_runId") && this._runId) {
this._trace = undefined;
this._logbookEntries = undefined;
this.shadowRoot!.querySelector("select")!.value = this._runId;
this._loadTrace();
}
}
private _pickOlderTrace() {
const curIndex = this._traces!.findIndex((tr) => tr.run_id === this._runId);
this._runId = this._traces![curIndex + 1].run_id;
this._selected = undefined;
}
private _pickNewerTrace() {
const curIndex = this._traces!.findIndex((tr) => tr.run_id === this._runId);
this._runId = this._traces![curIndex - 1].run_id;
this._selected = undefined;
}
private _pickTrace(ev) {
this._runId = ev.target.value;
this._selected = undefined;
}
private _pickNode(ev) {
this._selected = ev.detail;
}
private async _loadTraces(runId?: string) {
this._traces = await loadTraces(
this.hass,
"script",
this.scriptEntityId.split(".")[1]
);
// Newest will be on top.
this._traces.reverse();
if (runId) {
this._runId = runId;
}
// Check if current run ID still exists
if (
this._runId &&
!this._traces.some((trace) => trace.run_id === this._runId)
) {
this._runId = undefined;
this._selected = undefined;
// If we came here from a trace passed into the url, clear it.
if (runId) {
const params = new URLSearchParams(location.search);
params.delete("run_id");
history.replaceState(
null,
"",
`${location.pathname}?${params.toString()}`
);
}
await showAlertDialog(this, {
text: "Chosen trace is no longer available",
});
}
// See if we can set a default runID
if (!this._runId && this._traces.length > 0) {
this._runId = this._traces[0].run_id;
}
}
private async _loadTrace() {
const trace = await loadTrace(
this.hass,
"script",
this.scriptEntityId.split(".")[1],
this._runId!
);
this._logbookEntries = isComponentLoaded(this.hass, "logbook")
? await getLogbookDataForContext(
this.hass,
trace.timestamp.start,
trace.context.id
)
: [];
this._trace = trace;
}
private _downloadTrace() {
const aEl = document.createElement("a");
aEl.download = `trace ${this.scriptEntityId} ${
this._trace!.timestamp.start
}.json`;
aEl.href = `data:application/json;charset=utf-8,${encodeURI(
JSON.stringify(
{
trace: this._trace,
logbookEntries: this._logbookEntries,
},
undefined,
2
)
)}`;
aEl.click();
}
private _importTrace() {
const traceText = prompt("Enter downloaded trace");
if (!traceText) {
return;
}
localStorage.devTrace = traceText;
this._loadLocalTrace(traceText);
}
private _loadLocalStorageTrace() {
if (localStorage.devTrace) {
this._loadLocalTrace(localStorage.devTrace);
}
}
private _loadLocalTrace(traceText: string) {
const traceInfo = JSON.parse(traceText);
this._trace = traceInfo.trace;
this._logbookEntries = traceInfo.logbookEntries;
}
private _showTab(ev) {
this._view = (ev.target as any).view;
}
private _timelinePathPicked(ev) {
const path = ev.detail.value;
const nodes = this.shadowRoot!.querySelector("hat-script-graph")!
.trackedNodes;
if (nodes[path]) {
this._selected = nodes[path];
}
}
static get styles(): CSSResultGroup {
return [
haStyle,
traceTabStyles,
css`
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 20px;
height: var(--header-height);
padding: 0 16px;
background-color: var(--primary-background-color);
font-weight: 400;
color: var(--app-header-text-color, white);
border-bottom: var(--app-header-border-bottom, none);
box-sizing: border-box;
}
.toolbar > * {
display: flex;
align-items: center;
}
:host([narrow]) .toolbar > * {
display: contents;
}
.main {
height: calc(100% - 56px);
display: flex;
background-color: var(--card-background-color);
}
:host([narrow]) .main {
height: auto;
flex-direction: column;
}
.container {
padding: 16px;
}
.graph {
border-right: 1px solid var(--divider-color);
overflow-x: auto;
max-width: 50%;
}
:host([narrow]) .graph {
max-width: 100%;
}
.info {
flex: 1;
background-color: var(--card-background-color);
}
.linkButton {
color: var(--primary-text-color);
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-script-trace": HaScriptTrace;
}
}

View File

@ -126,7 +126,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
this._applyTranslations(this.hass!);
}
protected panelUrlChanged(newPanelUrl) {
protected panelUrlChanged(newPanelUrl: string) {
super.panelUrlChanged(newPanelUrl);
// this may be triggered before hassConnected
this._loadFragmentTranslations(
@ -339,13 +339,16 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
...data,
},
};
const changes: Partial<HomeAssistant> = {
resources,
localize: await computeLocalize(this, language, resources),
};
// Update resources immediately, so when a new update comes in we don't miss values
this._updateHass({ resources });
const localize = await computeLocalize(this, language, resources);
if (language === (this.hass ?? this._pendingHass).language) {
this._updateHass(changes);
this._updateHass({
localize,
});
}
}

View File

@ -303,7 +303,7 @@
"entries_not_found": "No logbook entries found.",
"by": "by",
"by_service": "by service",
"show_trace": "Show trace",
"show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]",
"retrieval_error": "Error during logbook entry retrieval",
"messages": {
"was_away": "was detected away",
@ -1308,6 +1308,7 @@
"introduction": "Triggers are what starts the processing of an automation rule. It is possible to specify multiple triggers for the same rule. Once a trigger starts, Home Assistant will validate the conditions, if any, and call the action.",
"learn_more": "Learn more about triggers",
"add": "Add trigger",
"id": "Trigger ID (used by the trigger condition)",
"duplicate": "Duplicate",
"delete": "[%key:ui::panel::mailbox::delete_button%]",
"delete_confirm": "Are you sure you want to delete this?",
@ -1475,6 +1476,11 @@
"sun": "Sunday"
}
},
"trigger": {
"label": "Trigger",
"no_triggers": "No triggers available",
"id": "Trigger Id"
},
"zone": {
"label": "[%key:ui::panel::config::automation::editor::triggers::type::zone::label%]",
"entity": "[%key:ui::panel::config::automation::editor::triggers::type::zone::entity%]",
@ -1634,6 +1640,7 @@
"show_info": "Show info about script",
"run_script": "Run script",
"edit_script": "Edit script",
"dev_script": "Debug script",
"headers": {
"name": "Name"
},
@ -1647,6 +1654,7 @@
"id_already_exists_save_error": "You can't save this script because the ID is not unique, pick another ID or leave it blank to automatically generate one.",
"id_already_exists": "This ID already exists",
"introduction": "Use scripts to run a sequence of actions.",
"show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]",
"header": "Script: {name}",
"default_name": "New Script",
"modes": {

File diff suppressed because it is too large Load Diff

View File

@ -2319,7 +2319,7 @@
"none": "Encara no hi ha res configurat",
"none_found": "No s'han trobat integracions",
"none_found_detail": "Ajusta els paràmetres de cerca.",
"note_about_integrations": "Encara no es poden configurar totes les integracions a través de la IU.",
"note_about_integrations": "No s'ha trobat cap integració que coincident, és possible que la integració encara no estigui disponible per configurar-se a través de la interfície d'usuari.",
"note_about_website_reference": "En pots trobar més al ",
"reconfigure": "Reconfigura",
"rename_dialog": "Edita el nom de l'entrada de configuració",
@ -2962,6 +2962,7 @@
"common": {
"add_node": "Afegeix node",
"close": "Tanca",
"heal_network": "Guareix la xarxa",
"home_id": "ID principal",
"network": "Xarxa",
"node_id": "ID del node",
@ -2988,6 +2989,18 @@
"node_status": "Estat del node",
"zwave_info": "Informació Z-Wave"
},
"heal_network": {
"healing_cancelled": "La guarició de la xarxa s'ha cancel·lat.",
"healing_complete": "La guarició de la xarxa s'ha completat.",
"healing_failed": "La guarició ha fallat. Pots trobar informació addicional als registres.",
"in_progress": "La guarició de la xarxa està en curs. Trigarà una estona.",
"introduction": "Inicia una guarició de la teva xarxa Z-Wave. La guarició de xarxa farà que tots els dispositius tornin a calcular les seves rutes cap al controlador. Es recomana si recentment has canviat o mogut dispositius o el controlador.",
"run_in_background": "Pots tancar aquest diàleg, la guarició de la xarxa continuarà en segon pla.",
"start_heal": "Comença la guarició",
"stop_heal": "Atura la guarició",
"title": "Guareix la xarxa Z-Wave",
"traffic_warning": "El procés de guarició genera una gran quantitat de trànsit a la xarxa Z-Wave. Això pot fer que els dispositius responguin lentament (o gens) mentre la guarició està en procés."
},
"logs": {
"log_level": "Nivell dels registres",
"log_level_changed": "Nivell de registre canviat a: {level}",

View File

@ -2319,7 +2319,7 @@
"none": "Zatím nic nastaveno",
"none_found": "Žádné integrace nenalezeny.",
"none_found_detail": "Upravte kritéria vyhledávání.",
"note_about_integrations": "Některé integrace zatím nelze nastavit prostřednictvím uživatelského rozhraní.",
"note_about_integrations": "Vašemu vyhledávání neodpovídá žádná integrace, je možné, že integraci, kterou chcete nastavit, ještě nelze nastavit prostřednictvím uživatelského rozhraní.",
"note_about_website_reference": "Další jsou k dispozici na ",
"reconfigure": "Přenastavit",
"rename_dialog": "Upravit název této položky nastavení",

View File

@ -2319,7 +2319,7 @@
"none": "Noch nichts konfiguriert",
"none_found": "Keine Integrationen gefunden",
"none_found_detail": "Passe deine Suchkriterien an.",
"note_about_integrations": "Nicht alle Integrationen können über die Benutzeroberfläche konfiguriert werden.",
"note_about_integrations": "Es wurden keine Integrationen für deine Suche gefunden. Möglicherweise ist die Integration, die du einrichten möchtest, noch nicht zum Einrichten über die Benutzeroberfläche verfügbar.",
"note_about_website_reference": "Weitere Informationen findest du auf der ",
"reconfigure": "Neu konfigurieren",
"rename_dialog": "Bearbeite den Namen dieses Konfigurationseintrags",
@ -2962,6 +2962,7 @@
"common": {
"add_node": "Knoten hinzufügen",
"close": "Schließen",
"heal_network": "Netzwerk heilen",
"home_id": "Heim-ID",
"network": "Netzwerk",
"node_id": "Knoten-ID",
@ -2988,6 +2989,18 @@
"node_status": "Node Status",
"zwave_info": "Z-Wave Info"
},
"heal_network": {
"healing_cancelled": "Die Netzwerkheilung wurde abgebrochen.",
"healing_complete": "Die Netzwerkheilung ist abgeschlossen.",
"healing_failed": "Heilung fehlgeschlagen. Zusätzliche Informationen könnten in den Protokollen verfügbar sein.",
"in_progress": "Die Netzwerkheilung ist im Gange. Dies wird einige Zeit in Anspruch nehmen.",
"introduction": "Startet einen Netzwerk-Heal im Z-Wave-Netzwerk. Ein Netzwerk-Heal veranlasst alle Geräte, ihre Routen zurück zum Controller neu zu berechnen und wird empfohlen, wenn kürzlich Geräte oder Controller verschoben wurden.",
"run_in_background": "Dieser Dialog kann geschlossen werden und die Netzwerkheilung wird im Hintergrund fortgesetzt.",
"start_heal": "Starten der Heilung",
"stop_heal": "Stoppen der Heilung",
"title": "Heile dein Z-Wave-Netzwerk",
"traffic_warning": "Der Heilungsprozess erzeugt eine große Menge an Datenverkehr im Z-Wave-Netzwerk. Dies kann dazu führen, dass Geräte langsam (oder gar nicht) reagieren, während der Heilungsprozess läuft."
},
"logs": {
"log_level": "Protokollstufe",
"log_level_changed": "Log Level geändert auf: {level}",

View File

@ -2319,7 +2319,7 @@
"none": "Todavía no hay nada configurado",
"none_found": "No se han encontrado integraciones",
"none_found_detail": "Ajusta tus criterios de búsqueda.",
"note_about_integrations": "Todavía no se pueden configurar todas las integraciones a través de la interfaz de usuario.",
"note_about_integrations": "No hay integraciones que coincidan con tu búsqueda, es posible que la integración que deseas configurar aún no esté disponible para configurar a través de la interfaz de usuario.",
"note_about_website_reference": "Hay más disponibles en el ",
"reconfigure": "Reconfigurar",
"rename_dialog": "Edita el nombre de esta entrada de configuración",
@ -2990,7 +2990,7 @@
"zwave_info": "Información de Z-Wave"
},
"heal_network": {
"healing_cancelled": "Se ha cancelado la curación en red.",
"healing_cancelled": "Se ha cancelado la curación de la red.",
"healing_complete": "La curación de la red se ha completado.",
"healing_failed": "La curación falló. Puede haber información adicional disponible en los registros.",
"in_progress": "La curación de la red está en curso. Esto llevará algún tiempo.",

View File

@ -2319,7 +2319,7 @@
"none": "Midagi pole veel seadistatud",
"none_found": "Sidumisi ei leitud",
"none_found_detail": "Korrigeerige oma otsingukriteeriume.",
"note_about_integrations": "Kõiki sidumisi ei saa veel kasutajaliidese kaudu seadistada.",
"note_about_integrations": "Otsingule ei vastanud ükski sidumine, soovitud üksus ei pruugi olla veel kasutajaliidese kaudu seadistamiseks saadaval.",
"note_about_website_reference": "Rohkem on saadaval ",
"reconfigure": "Seadistage uuesti",
"rename_dialog": "Muuda selle seadistuskirje nime",

View File

@ -2319,7 +2319,7 @@
"none": "כלום אינו הוגדר עדיין",
"none_found": "לא נמצאו אינטגרציות",
"none_found_detail": "התאם את קריטריוני החיפוש שלך.",
"note_about_integrations": "לא ניתן להגדיר עדיין את כל השילובים דרך ממשק המשתמש.",
"note_about_integrations": "אין שילובים שתאמו לחיפוש שלך, ייתכן שהשילוב שברצונך להגדיר לא יהיה זמין עדיין להגדרה באמצעות ממשק המשתמש.",
"note_about_website_reference": "מידע נוסף זמין ב:",
"reconfigure": "קביעת תצורה מחדש",
"rename_dialog": "ערוך את שם ישות התצורה הזו",
@ -2962,6 +2962,7 @@
"common": {
"add_node": "הוסף צומת",
"close": "סגור",
"heal_network": "ריפוי רשת",
"home_id": "מזהה בית",
"network": "רשת",
"node_id": "מזהה צומת",
@ -2988,6 +2989,18 @@
"node_status": "מצב הצומת",
"zwave_info": "מידע Z-Wave"
},
"heal_network": {
"healing_cancelled": "ריפוי הרשת בוטל.",
"healing_complete": "ריפוי הרשת הושלם.",
"healing_failed": "הריפוי נכשל. מידע נוסף עשוי להיות זמין ביומנים.",
"in_progress": "ריפוי הרשת בעיצומו. זה ייקח קצת זמן.",
"introduction": "התחל ריפוי רשת ברשת Z-Wave שלך. ריפוי רשת יגרום לכל ההתקנים לחשב מחדש את הנתיבים שלהם בחזרה לבקר ומומלץ אם העברת לאחרונה התקנים או הבקר שלך.",
"run_in_background": "באפשרותך לסגור תיבת דו שיח זו וריפוי הרשת ימשיך ברקע.",
"start_heal": "התחל ריפוי",
"stop_heal": "הפסק ריפוי",
"title": "רפא את רשת Z-Wave שלך",
"traffic_warning": "תהליך הריפוי מייצר כמות גדולה של תעבורה ברשת Z-Wave. הדבר עלול לגרום להתקנים להגיב באיטיות (או בכלל לא) בזמן שהריפוי מתבצע."
},
"logs": {
"log_level": "רמת יומן",
"log_level_changed": "רמת היומן שונתה ל: {level}",

View File

@ -121,7 +121,8 @@
"edit_in_ui": "Szerkesztés a felhasználói felületen",
"edit_in_yaml": "Szerkesztés YAML-ben",
"header": "Lehetőségek",
"invalid_yaml": "Érvénytelen YAML"
"invalid_yaml": "Érvénytelen YAML",
"show_unused_optional": "A nem használt opcionális konfigurációs lehetőségek megjelenítése"
}
},
"dashboard": {
@ -194,6 +195,7 @@
"hostname": "Gazdagép neve",
"install": "telepítés",
"new_update_available": "{name} {version} elérhető",
"not_available_arch": "Ez a kiegészítő nem kompatibilis a készülék processzorával vagy az eszközre telepített operációs rendszerrel.",
"not_available_version": "A(z) {core_version_installed} otthoni segédet futtatja, hogy frissítse az Otthoni segéd legalább {core_version_needed} verzióját.",
"open_web_ui": "Webes felhasználói felület megnyitása",
"option": {
@ -328,6 +330,7 @@
"add_new_registry": "Hozzáadás új rendszerleíró adatbázishoz",
"add_registry": "Hozzáadás a rendszerleíró adatbázishoz",
"failed_to_add": "Nem sikerült hozzáadni a rendszerleíró adatbázishoz",
"no_registries": "Nincsenek konfigurálva regiszterek",
"password": "Jelszó",
"registry": "Regisztrálás",
"remove": "Eltávolítás",
@ -678,6 +681,7 @@
"addon": "Bővítmény",
"error": {
"fetch_addons": {
"description": "A kiegészítők lekérése hibát eredményezett.",
"title": "Hiba történt a bővítmények beolvasása közben"
},
"no_supervisor": {
@ -746,6 +750,7 @@
}
},
"history_charts": {
"history_disabled": "Előzményintegráció letiltva",
"loading_history": "Állapot előzmények betöltése...",
"no_history_found": "Nem található előzmény."
},
@ -929,6 +934,7 @@
"enabled_label": "Entitás engedélyezése",
"enabled_restart_confirm": "Az entitások engedélyezésének befejezéséhez indítsd újra a Home Assistant-et",
"entity_id": "Entitás ID",
"follow_device_area": "Kövesse a készülék területét",
"icon": "Ikon",
"icon_error": "Az ikonokat a 'prefix:ikonnév' formátumban kell megadni, pl.: 'mdi:home'",
"name": "Név",
@ -1214,6 +1220,8 @@
"no_type_provided": "Nincs megadva típus."
},
"supervisor": {
"ask": "Kérjen segítséget",
"observer": "Ellenőrizze a Figyelőt",
"reboot": "Próbálja újraindítani a gazdagépet",
"system_health": "Rendszerállapot ellenőrzése"
}
@ -1742,6 +1750,7 @@
"target_browser": "Böngésző"
},
"female": "Nő",
"info": "Csinálj az otthonodnak személyiséget azzal, hogy a szövegfelolvasó szolgáltatásaink segítségével beszélhessünk veled. Ez használható az automatizálásokban és a szkriptekben a(z) {service} szolgáltatás használatával.",
"male": "Férfi",
"title": "Szövegről beszédre",
"try": "Próbálja meg"
@ -1879,6 +1888,7 @@
"title": "Alapvető elemzés"
},
"diagnostics": {
"description": "Megosztja az összeomlási jelentéseket, ha váratlan hibák lépnek fel.",
"title": "Diagnosztika"
},
"statistics": {
@ -2188,8 +2198,10 @@
"services": "{count} {count, plural,\n one {szolgáltatás}\n other {szolgáltatás}\n}",
"state": {
"loaded": "Betöltve",
"migration_error": "Migrációs hiba",
"not_loaded": "Nincs betöltve",
"setup_error": "Nem sikerült beállítani"
"setup_error": "Nem sikerült beállítani",
"setup_retry": "A beállítás újbóli megkísérlése"
},
"system_options": "Rendszerbeállítások",
"unnamed_entry": "Névtelen bejegyzés"
@ -2212,6 +2224,7 @@
"not_all_required_fields": "Nincs kitöltve minden szükséges mező.",
"not_loaded": "Az integrációt nem sikerült betölteni. Próbálja meg újraindítani a Home Assistantot.",
"pick_flow_step": {
"new_flow": "Nem, állítson be egy másik {integration}",
"title": "Felfedeztük ezeket, be akarod állítani őket?"
},
"submit": "Küldés"
@ -2869,6 +2882,7 @@
"zwave_js": {
"add_node": {
"inclusion_finished": "A csomópont hozzá lett adva.",
"introduction": "Ez a varázsló végigvezeti Önt egy csomópont hozzáadásán a Z-Wave-hálózathoz.",
"title": "Adjon hozzá egy Z-Wave csomópontot",
"view_device": "Eszköz megtekintése"
},
@ -2885,8 +2899,10 @@
"dashboard": {
"driver_version": "Illesztőprogram verzió",
"dump_not_ready_confirm": "Letöltés",
"dump_not_ready_title": "Még nem minden csomópont áll készen",
"header": "Kezelje Z-Wave hálózatát",
"home_id": "Otthon azonosító",
"introduction": "A Z-Wave hálózat és a Z-Wave csomópontok kezelése",
"nodes_ready": "Csomópontok készen állnak",
"server_version": "Szerver verzió"
},
@ -3703,6 +3719,7 @@
"working": "Kérlek várj"
},
"initializing": "Inicializálás",
"logging_in_to_with": "Bejelentkezés a következőhöz: ** {locationName} ** a ** {authProviderName} ** szolgáltatással.",
"logging_in_with": "Bejelentkezés **{authProviderName}** használatával.",
"pick_auth_provider": "Vagy válassz a következő bejelentkezési módok közül"
},
@ -3875,6 +3892,7 @@
"header": "Többfaktoros Hitelesítési Modulok"
},
"number_format": {
"description": "Válassza ki a számok formátumát.",
"dropdown_label": "Számformátum",
"formats": {
"comma_decimal": "1 234 567,89",

View File

@ -865,8 +865,10 @@
"related-filter-menu": {
"filter_by_area": "エリアで絞り込む",
"filter_by_device": "デバイスで絞り込む",
"filter_by_entity": "エンティティで絞り込む",
"filtered_by_area": "エリア: {area_name}",
"filtered_by_device": "デバイス: {device_name}"
"filtered_by_device": "デバイス: {device_name}",
"filtered_by_entity": "エンティティ: {entity_name}"
},
"related-items": {
"area": "エリア",
@ -2952,6 +2954,7 @@
"common": {
"add_node": "ノードの追加",
"close": "閉じる",
"heal_network": "ネットワークの修復",
"home_id": "ホームID",
"network": "ネットワーク",
"node_id": "ードID",
@ -2978,6 +2981,18 @@
"node_status": "ノードの状態",
"zwave_info": "Z-Wave情報"
},
"heal_network": {
"healing_cancelled": "ネットワークの修復がキャンセルされました。",
"healing_complete": "ネットワークの修復が完了しました。",
"healing_failed": "修復に失敗しました。追加情報はログで利用できる場合があります。",
"in_progress": "ネットワークの修復が進行中です。これには少し時間がかかります。",
"introduction": "Z-Wave ネットワークでネットワーク修復を開始します。ネットワークの修復は、すべてのデバイスがコントローラに戻ってルートを再計算し、最近デバイスまたはコントローラを移動した場合に推奨されます。",
"run_in_background": "このダイアログを閉じると、ネットワークの修復がバックグラウンドで続行されます。",
"start_heal": "修復を開始する",
"stop_heal": "修復をやめる",
"title": "Z-Waveネットワークの修復",
"traffic_warning": "この修復プロセスでは、Z-Wave ネットワーク上に大量のトラフィックが生成されます。これにより、修復が進行中のデバイスの応答が遅くなる (またはまったく反応しない) ことがあります。"
},
"logs": {
"log_level": "ログレベル",
"log_level_changed": "ログレベルが変更されました。{level}に変更されました。",

View File

@ -2962,6 +2962,7 @@
"common": {
"add_node": "노드 추가하기",
"close": "닫기",
"heal_network": "네트워크 복구",
"home_id": "집 ID",
"network": "네트워크",
"node_id": "노드 ID",
@ -2988,6 +2989,18 @@
"node_status": "노드 상태",
"zwave_info": "Z-Wave 정보"
},
"heal_network": {
"healing_cancelled": "네트워크 복구가 취소되었습니다.",
"healing_complete": "네트워크 복구가 완료되었습니다.",
"healing_failed": "복구에 실패했습니다. 로그에서 추가 정보를 확인할 수 있습니다.",
"in_progress": "네트워크 복구가 진행 중입니다. 시간이 좀 걸립니다.",
"introduction": "Z-Wave 네트워크 복구를 시작합니다. 네트워크 복구 시 모든 장치가 컨트롤러와의 경로를 재설정하며 최근 장치나 컨트롤러의 위치를 이동 한 경우 권장됩니다.",
"run_in_background": "이 대화 상자를 닫을 수 있으며 네트워크 복구는 백그라운드에서 계속됩니다.",
"start_heal": "복구 시작",
"stop_heal": "복구 중지",
"title": "Z-Wave 네트워크 복구",
"traffic_warning": "복구 프로세스는 Z-Wave 네트워크에서 많은 양의 트래픽을 생성합니다. 이로 인해 치료가 진행되는 동안 장치가 느리게 (또는 전혀 응답하지 않을) 수 있습니다."
},
"logs": {
"log_level": "로그 레벨",
"log_level_changed": "로그 레벨이 변경되었습니다: {level}",

View File

@ -2319,7 +2319,7 @@
"none": "Ingenting er konfigurert enda",
"none_found": "Ingen integrasjoner funnet",
"none_found_detail": "Juster dine søkekriterier",
"note_about_integrations": "Ikke alle integrasjoner kan konfigureres via brukergrensesnittet ennå.",
"note_about_integrations": "Ingen integrasjoner samsvarte med søket, integreringen du vil konfigurere, er kanskje ikke tilgjengelig for konfigurering via brukergrensesnittet ennå.",
"note_about_website_reference": "Flere er tilgjengelige på",
"reconfigure": "Konfigurer på nytt",
"rename_dialog": "Redigere navnet på denne config-oppføringen",
@ -2962,6 +2962,7 @@
"common": {
"add_node": "Legg til node",
"close": "Lukk",
"heal_network": "Helbrede nettverk",
"home_id": "Hjem-ID",
"network": "Nettverk",
"node_id": "Node-ID",
@ -2988,6 +2989,18 @@
"node_status": "Node status",
"zwave_info": "Z-Wave Informasjon"
},
"heal_network": {
"healing_cancelled": "Nettverkshelbredelse er avbrutt.",
"healing_complete": "Nettverksheling er fullført.",
"healing_failed": "Helbredelse mislyktes. Ytterligere informasjon kan være tilgjengelig i loggene.",
"in_progress": "Nettverkshelbredelse pågår. Dette vil ta litt tid.",
"introduction": "Start en nettverkshelbredelse på Z-Wave-nettverket. En nettverkshelbredelse vil føre til at alle enheter beregner rutene sine tilbake til kontrolleren, og anbefales hvis du nylig har flyttet enheter eller kontrolleren din.",
"run_in_background": "Du kan lukke denne dialogboksen, og nettverksreparasjonen fortsetter i bakgrunnen.",
"start_heal": "Begynn å helbrede",
"stop_heal": "Stopp helbredelse",
"title": "Helbred ditt Z-Wave-nettverk",
"traffic_warning": "Helbredelsesprosessen genererer stor trafikk på Z-Wave-nettverket. Dette kan føre til at enheter reagerer sakte (eller ikke i det hele tatt) mens legingen pågår."
},
"logs": {
"log_level": "Loggnivå",
"log_level_changed": "Loggnivå endret til: {level}",

View File

@ -942,9 +942,9 @@
},
"dialogs": {
"config_entry_system_options": {
"enable_new_entities_description": "Of nieuw ontdekte apparaten voor {integratie} automatisch moeten worden toegevoegd.",
"enable_new_entities_description": "Of nieuw ontdekte apparaten voor {integration} automatisch moeten worden toegevoegd.",
"enable_new_entities_label": "Voeg nieuwe entiteiten automatisch toe",
"enable_polling_description": "Of Home Assistant automatisch moet pollen voor updates voor {integration} entiteiten",
"enable_polling_description": "Of Home Assistant automatisch moet pollen voor {integration} entiteiten updates.",
"enable_polling_label": "Schakel polling voor updates in.",
"restart_home_assistant": "U moet Home Assistant opnieuw starten om uw wijzigingen door te voeren.",
"title": "Systeeminstellingen voor {integration}",
@ -2319,7 +2319,7 @@
"none": "Er is nog niets geconfigureerd",
"none_found": "Geen integraties gevonden",
"none_found_detail": "Pas uw zoekcriteria aan.",
"note_about_integrations": "Nog niet alle integraties kunnen via de UI worden geconfigureerd.",
"note_about_integrations": "Er kwamen geen integraties overeen met uw zoekopdracht. De integratie die u wilt instellen, is mogelijk nog niet beschikbaar om via de gebruikersinterface in te stellen.",
"note_about_website_reference": "Meer zijn beschikbaar op de ",
"reconfigure": "Herconfigureer",
"rename_dialog": "Bewerk de naam van dit configuratie item",
@ -2962,6 +2962,7 @@
"common": {
"add_node": "Knooppunt toevoegen",
"close": "Sluiten",
"heal_network": "Herstel netwerk",
"home_id": "Home ID",
"network": "Netwerk",
"node_id": "Knooppunt-ID",
@ -2988,6 +2989,18 @@
"node_status": "Knooppuntstatus",
"zwave_info": "Z-Wave info"
},
"heal_network": {
"healing_cancelled": "Netwerkherstel is geannuleerd.",
"healing_complete": "Netwerkherstel is compleet.",
"healing_failed": "Herstellen mislukt. Aanvullende informatie is mogelijk beschikbaar in de logboeken.",
"in_progress": "Netwerkherstel wordt uitgevoerd. Dit zal eveen duren.",
"introduction": "Start een netwerkherstel op uw Z-Wave netwerk. Een netwerkherstel zorgt ervoor dat alle apparaten hun routes naar de controller opnieuw berekenen en wordt aanbevolen als je recent apparaten of uw controller hebt verplaatst.",
"run_in_background": "U kunt dit dialoogvenster sluiten en het netwerkherstel zal voortzetten op de achtergrond.",
"start_heal": "Start herstellen",
"stop_heal": "Stop herstellen",
"title": "Herstel uw Z-Wave netwerk",
"traffic_warning": "Het herstelproces genereert een grote hoeveelheid verkeer op het Z-wave netwerk. Dit kan ertoe leiden dat apparaten traag reageren (of helemaal niet) als het herstel wordt uitgevoerd."
},
"logs": {
"log_level": "Log niveau",
"log_level_changed": "Logboekniveau gewijzigd in: {level}",

View File

@ -205,7 +205,7 @@
}
},
"changelog": "Lista zmian",
"cpu_usage": "Zużycie procesora przez dodatek",
"cpu_usage": "Użycie procesora przez dodatek",
"hostname": "Nazwa hosta",
"install": "zainstaluj",
"new_update_available": "{name} {version} jest dostępna",
@ -239,7 +239,7 @@
"enable": "Włącz tryb ochrony",
"title": "Ostrzeżenie: Tryb ochrony jest wyłączony!"
},
"ram_usage": "Zużycie pamięci przez dodatek",
"ram_usage": "Użycie pamięci przez dodatek",
"rebuild": "przeinstaluj",
"restart": "uruchom ponownie",
"start": "uruchom",
@ -433,8 +433,8 @@
},
"system": {
"core": {
"cpu_usage": "Zużycie procesora przez HA Core",
"ram_usage": "Zużycie pamięci przez HA Core"
"cpu_usage": "Użycie procesora przez HA Core",
"ram_usage": "Użycie pamięci przez HA Core"
},
"host": {
"change": "Zmień",
@ -469,7 +469,7 @@
"beta_release_items": "Obejmuje to wersje beta dla:",
"beta_warning": "Wersje beta są przeznaczone dla testerów i wczesnych użytkowników i mogą zawierać niestabilne zmiany w kodzie",
"channel": "Kanał",
"cpu_usage": "Zużycie procesora przez Supervisora",
"cpu_usage": "Użycie procesora przez Supervisora",
"failed_to_reload": "Nie udało się wczytać ponownie Supervisora",
"failed_to_set_option": "Nie udało się ustawić opcji Supervisora",
"failed_to_update": "Nie udało się zaktualizować Supervisora",
@ -477,7 +477,7 @@
"join_beta_description": "Pobieraj aktualizacje beta dla Home Assistanta (RC), Supervisora i hosta",
"leave_beta_action": "Opuść kanał beta",
"leave_beta_description": "Pobieraj stabilne aktualizacje dla Home Assistanta, Supervisora i hosta",
"ram_usage": "Zużycie pamięci przez Supervisora",
"ram_usage": "Użycie pamięci przez Supervisora",
"reload_supervisor": "Wczytaj ponownie",
"search": "Szukaj",
"share_diagnostics": "Udostępnij dane diagnostyczne",
@ -2319,7 +2319,7 @@
"none": "Nic jeszcze nie zostało skonfigurowane",
"none_found": "Nie znaleziono integracji",
"none_found_detail": "Dostosuj kryteria wyszukiwania.",
"note_about_integrations": "Jeszcze nie wszystkie integracje można skonfigurować za pomocą interfejsu użytkownika.",
"note_about_integrations": "Żadne integracje nie pasują do Twojego wyszukiwania. Integracja, którą chcesz skonfigurować, może być jeszcze niedostępna do skonfigurowania za pomocą interfejsu użytkownika.",
"note_about_website_reference": "Więcej jest dostępnych na stronie integracji ",
"reconfigure": "Zmień konfigurację",
"rename_dialog": "Edytuj nazwę tego wpisu konfiguracji",
@ -2962,6 +2962,7 @@
"common": {
"add_node": "Dodaj węzeł",
"close": "Zamknij",
"heal_network": "Uzdrawiaj sieć",
"home_id": "Identyfikator domu",
"network": "Sieć",
"node_id": "Identyfikator węzła",
@ -2988,6 +2989,18 @@
"node_status": "Stan węzła",
"zwave_info": "Informacje Z-Wave"
},
"heal_network": {
"healing_cancelled": "Uzdrawianie sieci zostało anulowane.",
"healing_complete": "Uzdrawianie sieci zostało zakończone.",
"healing_failed": "Uzdrawianie nie powiodło się. Dodatkowe informacje mogą być dostępne w logach.",
"in_progress": "Trwa uzdrawianie sieci. To zajmie trochę czasu.",
"introduction": "Rozpocznij uzdrawianie sieci Z-Wave. Uzdrawianie sieci spowoduje, że wszystkie urządzenia ponownie obliczą swoje trasy z powrotem do kontrolera i jest zalecane, jeśli niedawno przeniesiono urządzenia lub kontroler.",
"run_in_background": "Możesz zamknąć to okno, a uzdrawianie sieci będzie kontynuowane w tle.",
"start_heal": "Rozpocznij uzdrawianie",
"stop_heal": "Zatrzymaj uzdrawianie",
"title": "Uzdrawianie sieci Z-Wave",
"traffic_warning": "Proces uzdrawiania generuje duży ruch w sieci Z-Wave. Może to spowodować, że urządzenia będą reagować powoli (lub wcale) podczas trwania uzdrawiania."
},
"logs": {
"log_level": "Poziom loga",
"log_level_changed": "Poziom dziennika zmieniony na: {level}",

View File

@ -2319,7 +2319,7 @@
"none": "Пока ничего не настроено",
"none_found": "Интеграции не найдены",
"none_found_detail": "Измените критерии поиска",
"note_about_integrations": "Пока что не все интеграции могут быть настроены через пользовательский интерфейс.",
"note_about_integrations": "Не найдено соответствий по Вашему запросу. Интеграция, которую Вы хотели бы настроить, может быть недоступна для настройки через пользовательский интерфейс.",
"note_about_website_reference": "Все доступные интеграции Вы можете найти на ",
"reconfigure": "Перенастроить",
"rename_dialog": "Название интеграции",

View File

@ -2319,7 +2319,7 @@
"none": "尚未配置任何集成",
"none_found": "未找到集成",
"none_found_detail": "请调整搜索条件。",
"note_about_integrations": "并非所有集成都可以通过 UI 进行配置。",
"note_about_integrations": "未搜索到相关集成,可能是您要配置的集成还不支持通过 UI 配置。",
"note_about_website_reference": "更多可用信息,尽在 ",
"reconfigure": "重新配置",
"rename_dialog": "编辑此配置项的名称",
@ -2962,6 +2962,7 @@
"common": {
"add_node": "添加节点",
"close": "关闭",
"heal_network": "修复网络",
"home_id": "家庭 ID",
"network": "网络",
"node_id": "节点 ID",
@ -2988,6 +2989,18 @@
"node_status": "节点状态",
"zwave_info": "Z-Wave 信息"
},
"heal_network": {
"healing_cancelled": "网络修复已取消。",
"healing_complete": "网络修复完成。",
"healing_failed": "修复失败。日志中会有更多信息。",
"in_progress": "正在修复网络。可能需要一段时间。",
"introduction": "在此 Z-Wave 网络上启动网络修复。网络修复会使所有设备重新计算它们到控制器的路由。如果您最近挪动了设备或控制器,建议使用此功能。",
"run_in_background": "您可以关闭此对话框,网络修复将在后台继续进行。",
"start_heal": "开始修复",
"stop_heal": "停止修复",
"title": "修复 Z-Wave 网络",
"traffic_warning": "修复过程会在 Z-Wave 网络上产生大量流量。修复期间,设备可能会响应缓慢或完全无响应。"
},
"logs": {
"log_level": "日志级别",
"log_level_changed": "日志级别更改为: {level}",

View File

@ -2319,7 +2319,7 @@
"none": "尚未設定",
"none_found": "找不到相關整合。",
"none_found_detail": "調整搜尋條件。",
"note_about_integrations": "目前並非所有整合皆可以透過 UI 進行設定。",
"note_about_integrations": "沒有找到符合的整合,所要設定的整合可能尚未支援透過 UI 進行設定。",
"note_about_website_reference": "更多資訊請參閱",
"reconfigure": "重新設定",
"rename_dialog": "編輯設定實體名稱",
@ -2962,6 +2962,7 @@
"common": {
"add_node": "新增節點",
"close": "關閉",
"heal_network": "修復網路",
"home_id": "家庭 ID",
"network": "網路",
"node_id": "節點 ID",
@ -2988,6 +2989,18 @@
"node_status": "節點狀態",
"zwave_info": "Z-Wave 資訊"
},
"heal_network": {
"healing_cancelled": "網路修復已取消。",
"healing_complete": "網路修復已完成。",
"healing_failed": "修復失敗。日誌中可能包含其他相關資訊。",
"in_progress": "網路修復進行中,可能需要一點時間。",
"introduction": "於 Z-Wave 網路開始網路修復。網路修復將導致所有裝置重新計算其連回控制器的路徑,檢如近期有移動裝置或控制器的話,建議執行此動作。",
"run_in_background": "可以關閉此對話框、網路修復將於背景繼續執行。",
"start_heal": "開始修復",
"stop_heal": "停止修復",
"title": "修復 Z-Wave 網路",
"traffic_warning": "修復過程將對 Z-Wave 網路產生大量流量,過程中可能會導致裝置回應減緩(或失去回應)。"
},
"logs": {
"log_level": "日誌記錄等級",
"log_level_changed": "日誌等級變更為:{level}",