Update a few Condition Descriptions (#13404)

* Update a few Describe-conditions

* Update to multiple states
This commit is contained in:
Zack Barett 2022-08-23 09:12:55 -05:00 committed by GitHub
parent c82782fa1b
commit f5b44656cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 225 additions and 22 deletions

View File

@ -1,20 +1,41 @@
import { dump } from "js-yaml";
import { html, css, LitElement, TemplateResult } from "lit";
import { customElement, state } from "lit/decorators";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-yaml-editor";
import { Condition } from "../../../../src/data/automation";
import { describeCondition } from "../../../../src/data/automation_i18n";
import { getEntity } from "../../../../src/fake_data/entity";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import { HomeAssistant } from "../../../../src/types";
const ENTITIES = [
getEntity("light", "kitchen", "on", {
friendly_name: "Kitchen Light",
}),
getEntity("device_tracker", "person", "home", {
friendly_name: "Person",
}),
getEntity("zone", "home", "", {
friendly_name: "Home",
}),
];
const conditions = [
{ condition: "and" },
{ condition: "not" },
{ condition: "or" },
{ condition: "state" },
{ condition: "numeric_state" },
{ condition: "state", entity_id: "light.kitchen", state: "on" },
{
condition: "numeric_state",
entity_id: "light.kitchen",
attribute: "brightness",
below: 80,
above: 20,
},
{ condition: "sun", after: "sunset" },
{ condition: "sun", after: "sunrise" },
{ condition: "zone" },
{ condition: "sun", after: "sunrise", offset: "-01:00" },
{ condition: "zone", entity_id: "device_tracker.person", zone: "zone.home" },
{ condition: "time" },
{ condition: "template" },
];
@ -27,15 +48,21 @@ const initialCondition: Condition = {
@customElement("demo-automation-describe-condition")
export class DemoAutomationDescribeCondition extends LitElement {
@property({ attribute: false }) hass!: HomeAssistant;
@state() _condition = initialCondition;
protected render(): TemplateResult {
if (!this.hass) {
return html``;
}
return html`
<ha-card header="Conditions">
<div class="condition">
<span>
${this._condition
? describeCondition(this._condition)
? describeCondition(this._condition, this.hass)
: "<invalid YAML>"}
</span>
<ha-yaml-editor
@ -48,7 +75,7 @@ export class DemoAutomationDescribeCondition extends LitElement {
${conditions.map(
(conf) => html`
<div class="condition">
<span>${describeCondition(conf as any)}</span>
<span>${describeCondition(conf as any, this.hass)}</span>
<pre>${dump(conf)}</pre>
</div>
`
@ -57,6 +84,13 @@ export class DemoAutomationDescribeCondition extends LitElement {
`;
}
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
const hass = provideHass(this);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
private _dataChanged(ev: CustomEvent): void {
ev.stopPropagation();
this._condition = ev.detail.isValid ? ev.detail.value : undefined;

View File

@ -1,3 +1,6 @@
import secondsToDuration from "../common/datetime/seconds_to_duration";
import { computeStateName } from "../common/entity/compute_state_name";
import type { HomeAssistant } from "../types";
import { Condition, Trigger } from "./automation";
export const describeTrigger = (trigger: Trigger) => {
@ -7,12 +10,176 @@ export const describeTrigger = (trigger: Trigger) => {
return `${trigger.platform || "Unknown"} trigger`;
};
export const describeCondition = (condition: Condition) => {
export const describeCondition = (
condition: Condition,
hass: HomeAssistant
) => {
if (condition.alias) {
return condition.alias;
}
if (["or", "and", "not"].includes(condition.condition)) {
return `multiple conditions using "${condition.condition}"`;
}
// State Condition
if (condition.condition === "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`;
}
let states = "";
if (Array.isArray(condition.state)) {
for (const [index, state] of condition.state.entries()) {
states += `${index > 0 ? "," : ""} ${
condition.state.length > 1 && index === condition.state.length - 1
? "or"
: ""
} ${state}`;
}
} else {
states = condition.state.toString();
}
base += ` ${entity} is ${states}`;
if ("for" in condition) {
let duration: string;
if (typeof condition.for === "number") {
duration = `for ${secondsToDuration(condition.for)!}`;
} else if (typeof condition.for === "string") {
duration = `for ${condition.for}`;
} else {
duration = `for ${JSON.stringify(condition.for)}`;
}
base += ` for ${duration}`;
}
return base;
}
// 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`;
}
base += ` ${entity} is`;
if ("above" in condition) {
base += ` above ${condition.above}`;
}
if ("below" in condition && "above" in condition) {
base += " and";
}
if ("below" in condition) {
base += ` below ${condition.below}`;
}
return base;
}
// Sun condition
if (
condition.condition === "sun" &&
("before" in condition || "after" in condition)
) {
let base = "Confirm";
if (!condition.after && !condition.before) {
base += " sun";
return base;
}
base += " sun";
if (condition.after) {
let duration = "";
if (condition.after_offset) {
if (typeof condition.after_offset === "number") {
duration = ` offset by ${secondsToDuration(condition.after_offset)!}`;
} else if (typeof condition.after_offset === "string") {
duration = ` offset by ${condition.after_offset}`;
} else {
duration = ` offset by ${JSON.stringify(condition.after_offset)}`;
}
}
base += ` after ${condition.after}${duration}`;
}
if (condition.before) {
base += ` before ${condition.before}`;
}
return base;
}
// Zone condition
if (condition.condition === "zone" && condition.entity_id && condition.zone) {
let entities = "";
let entitiesPlural = false;
let zones = "";
let zonesPlural = false;
const states = hass.states;
if (Array.isArray(condition.entity_id)) {
if (condition.entity_id.length > 1) {
entitiesPlural = true;
}
for (const [index, entity] of condition.entity_id.entries()) {
if (states[entity]) {
entities += `${index > 0 ? "," : ""} ${
condition.entity_id.length > 1 &&
index === condition.entity_id.length - 1
? "or"
: ""
} ${computeStateName(states[entity]) || entity}`;
}
}
} else {
entities = states[condition.entity_id]
? computeStateName(states[condition.entity_id])
: condition.entity_id;
}
if (Array.isArray(condition.zone)) {
if (condition.zone.length > 1) {
zonesPlural = true;
}
for (const [index, zone] of condition.zone.entries()) {
if (states[zone]) {
zones += `${index > 0 ? "," : ""} ${
condition.zone.length > 1 && index === condition.zone.length - 1
? "or"
: ""
} ${computeStateName(states[zone]) || zone}`;
}
}
} else {
zones = states[condition.zone]
? computeStateName(states[condition.zone])
: condition.zone;
}
return `Confirm ${entities} ${entitiesPlural ? "are" : "is"} in ${zones} ${
zonesPlural ? "zones" : "zone"
}`;
}
return `${condition.condition} condition`;
};

View File

@ -163,7 +163,7 @@ export const describeAction = <T extends ActionType>(
}
if (actionType === "check_condition") {
return `Test ${describeCondition(action as Condition)}`;
return `Test ${describeCondition(action as Condition, hass)}`;
}
if (actionType === "stop") {
@ -177,7 +177,7 @@ export const describeAction = <T extends ActionType>(
typeof config.if === "string"
? config.if
: ensureArray(config.if)
.map((condition) => describeCondition(condition))
.map((condition) => describeCondition(condition, hass))
.join(", ")
} then ${ensureArray(config.then).map((thenAction) =>
describeAction(hass, thenAction)
@ -200,7 +200,7 @@ export const describeAction = <T extends ActionType>(
typeof chooseAction.conditions === "string"
? chooseAction.conditions
: ensureArray(chooseAction.conditions)
.map((condition) => describeCondition(condition))
.map((condition) => describeCondition(condition, hass))
.join(", ")
} then ${ensureArray(chooseAction.sequence)
.map((chooseSeq) => describeAction(hass, chooseSeq))
@ -223,11 +223,11 @@ export const describeAction = <T extends ActionType>(
)} ${"count" in config.repeat ? `${config.repeat.count} times` : ""}${
"while" in config.repeat
? `while ${ensureArray(config.repeat.while)
.map((condition) => describeCondition(condition))
.map((condition) => describeCondition(condition, hass))
.join(", ")} is true`
: "until" in config.repeat
? `until ${ensureArray(config.repeat.until)
.map((condition) => describeCondition(condition))
.map((condition) => describeCondition(condition, hass))
.join(", ")} is true`
: "for_each" in config.repeat
? `for every item: ${ensureArray(config.repeat.for_each)
@ -238,7 +238,7 @@ export const describeAction = <T extends ActionType>(
}
if (actionType === "check_condition") {
return `Test ${describeCondition(action as Condition)}`;
return `Test ${describeCondition(action as Condition, hass)}`;
}
if (actionType === "device_action") {

View File

@ -5,14 +5,17 @@ import { css, CSSResultGroup, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../../../../common/dom/fire_event";
import { capitalizeFirstLetter } from "../../../../common/string/capitalize-first-letter";
import { handleStructError } from "../../../../common/structs/handle-errors";
import "../../../../components/ha-button-menu";
import "../../../../components/ha-card";
import "../../../../components/buttons/ha-progress-button";
import type { HaProgressButton } from "../../../../components/buttons/ha-progress-button";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-button-menu";
import "../../../../components/ha-card";
import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-icon-button";
import { Condition, testCondition } from "../../../../data/automation";
import { describeCondition } from "../../../../data/automation_i18n";
import { validateConfig } from "../../../../data/config";
import {
showAlertDialog,
showConfirmationDialog,
@ -20,9 +23,6 @@ import {
import { haStyle } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
import "./ha-automation-condition-editor";
import { validateConfig } from "../../../../data/config";
import { describeCondition } from "../../../../data/automation_i18n";
import { capitalizeFirstLetter } from "../../../../common/string/capitalize-first-letter";
export interface ConditionElement extends LitElement {
condition: Condition;
@ -81,7 +81,9 @@ export default class HaAutomationConditionRow extends LitElement {
<ha-expansion-panel
leftChevron
.header=${capitalizeFirstLetter(describeCondition(this.condition))}
.header=${capitalizeFirstLetter(
describeCondition(this.condition, this.hass)
)}
>
<ha-progress-button slot="icons" @click=${this._testCondition}>
${this.hass.localize(