And vacuum commands extra for tile card (#14434)
This commit is contained in:
parent
566b93ec1f
commit
fcfdad3d94
|
@ -2,21 +2,63 @@ import {
|
|||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { UNAVAILABLE } from "./entity";
|
||||
|
||||
export const VACUUM_SUPPORT_PAUSE = 4;
|
||||
export const VACUUM_SUPPORT_STOP = 8;
|
||||
export const VACUUM_SUPPORT_RETURN_HOME = 16;
|
||||
export const VACUUM_SUPPORT_FAN_SPEED = 32;
|
||||
export const VACUUM_SUPPORT_BATTERY = 64;
|
||||
export const VACUUM_SUPPORT_STATUS = 128;
|
||||
export const VACUUM_SUPPORT_LOCATE = 512;
|
||||
export const VACUUM_SUPPORT_CLEAN_SPOT = 1024;
|
||||
export const VACUUM_SUPPORT_START = 8192;
|
||||
export type VacuumEntityState =
|
||||
| "on"
|
||||
| "off"
|
||||
| "cleaning"
|
||||
| "docked"
|
||||
| "idle"
|
||||
| "paused"
|
||||
| "returning"
|
||||
| "error";
|
||||
|
||||
export type VacuumEntity = HassEntityBase & {
|
||||
attributes: HassEntityAttributeBase & {
|
||||
battery_level: number;
|
||||
fan_speed: any;
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
export const enum VacuumEntityFeature {
|
||||
TURN_ON = 1,
|
||||
TURN_OFF = 2,
|
||||
PAUSE = 4,
|
||||
STOP = 8,
|
||||
RETURN_HOME = 16,
|
||||
FAN_SPEED = 32,
|
||||
BATTERY = 64,
|
||||
STATUS = 128,
|
||||
SEND_COMMAND = 256,
|
||||
LOCATE = 512,
|
||||
CLEAN_SPOT = 1024,
|
||||
MAP = 2048,
|
||||
STATE = 4096,
|
||||
START = 8192,
|
||||
}
|
||||
|
||||
interface VacuumEntityAttributes extends HassEntityAttributeBase {
|
||||
battery_level?: number;
|
||||
fan_speed?: any;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface VacuumEntity extends HassEntityBase {
|
||||
attributes: VacuumEntityAttributes;
|
||||
}
|
||||
|
||||
export function isCleaning(stateObj: VacuumEntity): boolean {
|
||||
return ["cleaning", "on"].includes(stateObj.state);
|
||||
}
|
||||
|
||||
export function canStart(stateObj: VacuumEntity): boolean {
|
||||
if (stateObj.state === UNAVAILABLE) {
|
||||
return false;
|
||||
}
|
||||
return !isCleaning(stateObj);
|
||||
}
|
||||
|
||||
export function canStop(stateObj: VacuumEntity): boolean {
|
||||
return !["docked", "off"].includes(stateObj.state);
|
||||
}
|
||||
|
||||
export function canReturnHome(stateObj: VacuumEntity): boolean {
|
||||
if (stateObj.state === UNAVAILABLE) {
|
||||
return false;
|
||||
}
|
||||
return stateObj.state !== "returning";
|
||||
}
|
||||
|
|
|
@ -18,18 +18,7 @@ import "../../../components/ha-icon";
|
|||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-select";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
import {
|
||||
VacuumEntity,
|
||||
VACUUM_SUPPORT_BATTERY,
|
||||
VACUUM_SUPPORT_CLEAN_SPOT,
|
||||
VACUUM_SUPPORT_FAN_SPEED,
|
||||
VACUUM_SUPPORT_LOCATE,
|
||||
VACUUM_SUPPORT_PAUSE,
|
||||
VACUUM_SUPPORT_RETURN_HOME,
|
||||
VACUUM_SUPPORT_START,
|
||||
VACUUM_SUPPORT_STATUS,
|
||||
VACUUM_SUPPORT_STOP,
|
||||
} from "../../../data/vacuum";
|
||||
import { VacuumEntity, VacuumEntityFeature } from "../../../data/vacuum";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
interface VacuumCommand {
|
||||
|
@ -44,7 +33,8 @@ const VACUUM_COMMANDS: VacuumCommand[] = [
|
|||
translationKey: "start",
|
||||
icon: mdiPlay,
|
||||
serviceName: "start",
|
||||
isVisible: (stateObj) => supportsFeature(stateObj, VACUUM_SUPPORT_START),
|
||||
isVisible: (stateObj) =>
|
||||
supportsFeature(stateObj, VacuumEntityFeature.START),
|
||||
},
|
||||
{
|
||||
translationKey: "pause",
|
||||
|
@ -52,8 +42,8 @@ const VACUUM_COMMANDS: VacuumCommand[] = [
|
|||
serviceName: "pause",
|
||||
isVisible: (stateObj) =>
|
||||
// We need also to check if Start is supported because if not we show play-pause
|
||||
supportsFeature(stateObj, VACUUM_SUPPORT_START) &&
|
||||
supportsFeature(stateObj, VACUUM_SUPPORT_PAUSE),
|
||||
supportsFeature(stateObj, VacuumEntityFeature.START) &&
|
||||
supportsFeature(stateObj, VacuumEntityFeature.PAUSE),
|
||||
},
|
||||
{
|
||||
translationKey: "start_pause",
|
||||
|
@ -61,34 +51,36 @@ const VACUUM_COMMANDS: VacuumCommand[] = [
|
|||
serviceName: "start_pause",
|
||||
isVisible: (stateObj) =>
|
||||
// If start is supported, we don't show this button
|
||||
!supportsFeature(stateObj, VACUUM_SUPPORT_START) &&
|
||||
supportsFeature(stateObj, VACUUM_SUPPORT_PAUSE),
|
||||
!supportsFeature(stateObj, VacuumEntityFeature.START) &&
|
||||
supportsFeature(stateObj, VacuumEntityFeature.PAUSE),
|
||||
},
|
||||
{
|
||||
translationKey: "stop",
|
||||
icon: mdiStop,
|
||||
serviceName: "stop",
|
||||
isVisible: (stateObj) => supportsFeature(stateObj, VACUUM_SUPPORT_STOP),
|
||||
isVisible: (stateObj) =>
|
||||
supportsFeature(stateObj, VacuumEntityFeature.STOP),
|
||||
},
|
||||
{
|
||||
translationKey: "clean_spot",
|
||||
icon: mdiTargetVariant,
|
||||
serviceName: "clean_spot",
|
||||
isVisible: (stateObj) =>
|
||||
supportsFeature(stateObj, VACUUM_SUPPORT_CLEAN_SPOT),
|
||||
supportsFeature(stateObj, VacuumEntityFeature.CLEAN_SPOT),
|
||||
},
|
||||
{
|
||||
translationKey: "locate",
|
||||
icon: mdiMapMarker,
|
||||
serviceName: "locate",
|
||||
isVisible: (stateObj) => supportsFeature(stateObj, VACUUM_SUPPORT_LOCATE),
|
||||
isVisible: (stateObj) =>
|
||||
supportsFeature(stateObj, VacuumEntityFeature.LOCATE),
|
||||
},
|
||||
{
|
||||
translationKey: "return_home",
|
||||
icon: mdiHomeMapMarker,
|
||||
serviceName: "return_to_base",
|
||||
isVisible: (stateObj) =>
|
||||
supportsFeature(stateObj, VACUUM_SUPPORT_RETURN_HOME),
|
||||
supportsFeature(stateObj, VacuumEntityFeature.RETURN_HOME),
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -111,7 +103,7 @@ class MoreInfoVacuum extends LitElement {
|
|||
return html`
|
||||
${stateObj.state !== UNAVAILABLE
|
||||
? html` <div class="flex-horizontal">
|
||||
${supportsFeature(stateObj, VACUUM_SUPPORT_STATUS)
|
||||
${supportsFeature(stateObj, VacuumEntityFeature.STATUS)
|
||||
? html`
|
||||
<div>
|
||||
<span class="status-subtitle"
|
||||
|
@ -131,7 +123,7 @@ class MoreInfoVacuum extends LitElement {
|
|||
</div>
|
||||
`
|
||||
: ""}
|
||||
${supportsFeature(stateObj, VACUUM_SUPPORT_BATTERY) &&
|
||||
${supportsFeature(stateObj, VacuumEntityFeature.BATTERY) &&
|
||||
stateObj.attributes.battery_level
|
||||
? html`
|
||||
<div>
|
||||
|
@ -177,7 +169,7 @@ class MoreInfoVacuum extends LitElement {
|
|||
</div>
|
||||
`
|
||||
: ""}
|
||||
${supportsFeature(stateObj, VACUUM_SUPPORT_FAN_SPEED)
|
||||
${supportsFeature(stateObj, VacuumEntityFeature.FAN_SPEED)
|
||||
? html`
|
||||
<div>
|
||||
<div class="flex-horizontal">
|
||||
|
|
|
@ -6,11 +6,13 @@ import {
|
|||
import "../tile-extra/hui-cover-open-close-tile-extra";
|
||||
import "../tile-extra/hui-cover-tilt-tile-extra";
|
||||
import "../tile-extra/hui-light-brightness-tile-extra";
|
||||
import "../tile-extra/hui-vacuum-commands-tile-extra";
|
||||
|
||||
const TYPES: Set<LovelaceTileExtraConfig["type"]> = new Set([
|
||||
"cover-open-close",
|
||||
"cover-tilt",
|
||||
"light-brightness",
|
||||
"vacuum-commands",
|
||||
]);
|
||||
|
||||
export const createTileExtraElement = (config: LovelaceTileExtraConfig) =>
|
||||
|
|
|
@ -20,7 +20,10 @@ import "../../../../components/ha-form/ha-form";
|
|||
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { TileCardConfig } from "../../cards/types";
|
||||
import { LovelaceTileExtraConfig } from "../../tile-extra/types";
|
||||
import {
|
||||
LovelaceTileExtraConfig,
|
||||
LovelaceTileExtraContext,
|
||||
} from "../../tile-extra/types";
|
||||
import type { LovelaceCardEditor } from "../../types";
|
||||
import "../hui-sub-element-editor";
|
||||
import { actionConfigStruct } from "../structs/action-struct";
|
||||
|
@ -129,6 +132,10 @@ export class HuiTileCardEditor
|
|||
] as const
|
||||
);
|
||||
|
||||
private _context = memoizeOne(
|
||||
(entity_id?: string): LovelaceTileExtraContext => ({ entity_id })
|
||||
);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
|
@ -149,6 +156,7 @@ export class HuiTileCardEditor
|
|||
<hui-sub-element-editor
|
||||
.hass=${this.hass}
|
||||
.config=${this._subElementEditorConfig}
|
||||
.context=${this._context(this._config.entity)}
|
||||
@go-back=${this._goBack}
|
||||
@config-changed=${this.subElementChanged}
|
||||
>
|
||||
|
|
|
@ -33,6 +33,7 @@ const EXTRAS_TYPE: LovelaceTileExtraConfig["type"][] = [
|
|||
"cover-open-close",
|
||||
"cover-tilt",
|
||||
"light-brightness",
|
||||
"vacuum-commands",
|
||||
];
|
||||
|
||||
declare global {
|
||||
|
@ -227,7 +228,7 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||
|
||||
let newExtra: LovelaceTileExtraConfig;
|
||||
if (elClass && elClass.getStubConfig) {
|
||||
newExtra = await elClass.getStubConfig(this.hass!);
|
||||
newExtra = await elClass.getStubConfig(this.hass!, this.stateObj);
|
||||
} else {
|
||||
newExtra = { type: value } as LovelaceTileExtraConfig;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { supportsVacuumCommand } from "../../tile-extra/hui-vacuum-commands-tile-extra";
|
||||
import {
|
||||
LovelaceTileExtraContext,
|
||||
VacuumCommandsTileExtraConfig,
|
||||
VACUUM_COMMANDS,
|
||||
} from "../../tile-extra/types";
|
||||
import type { LovelaceTileExtraEditor } from "../../types";
|
||||
|
||||
@customElement("hui-vacuum-commands-tile-extra-editor")
|
||||
export class HuiVacuumCommandsTileExtraEditor
|
||||
extends LitElement
|
||||
implements LovelaceTileExtraEditor
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceTileExtraContext;
|
||||
|
||||
@state() private _config?: VacuumCommandsTileExtraConfig;
|
||||
|
||||
public setConfig(config: VacuumCommandsTileExtraConfig): void {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(localize: LocalizeFunc, stateObj?: HassEntity) =>
|
||||
[
|
||||
{
|
||||
name: "commands",
|
||||
selector: {
|
||||
select: {
|
||||
multiple: true,
|
||||
options: VACUUM_COMMANDS.filter(
|
||||
(command) =>
|
||||
stateObj && supportsVacuumCommand(stateObj, command)
|
||||
).map((command) => ({
|
||||
value: command,
|
||||
label: `${localize(
|
||||
`ui.panel.lovelace.editor.card.tile.extras.types.vacuum-commands.commands_list.${command}`
|
||||
)}`,
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
] as const
|
||||
);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const stateObj = this.context?.entity_id
|
||||
? this.hass.states[this.context?.entity_id]
|
||||
: undefined;
|
||||
|
||||
const schema = this._schema(this.hass.localize, stateObj);
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${this._config}
|
||||
.schema=${schema}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
fireEvent(this, "config-changed", { config: ev.detail.value });
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
) => {
|
||||
switch (schema.name) {
|
||||
case "commands":
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.tile.extras.types.vacuum-commands.${schema.name}`
|
||||
);
|
||||
default:
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-vacuum-commands-tile-extra-editor": HuiVacuumCommandsTileExtraEditor;
|
||||
}
|
||||
}
|
|
@ -57,11 +57,13 @@ export interface UIConfigChangedEvent extends Event {
|
|||
};
|
||||
}
|
||||
|
||||
export abstract class HuiElementEditor<T> extends LitElement {
|
||||
export abstract class HuiElementEditor<T, C = any> extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public lovelace?: LovelaceConfig;
|
||||
|
||||
@property({ attribute: false }) public context?: C;
|
||||
|
||||
@state() private _yaml?: string;
|
||||
|
||||
@state() private _config?: T;
|
||||
|
@ -275,6 +277,9 @@ export abstract class HuiElementEditor<T> extends LitElement {
|
|||
) {
|
||||
this._configElement.lovelace = this.lovelace;
|
||||
}
|
||||
if (this._configElement && changedProperties.has("context")) {
|
||||
this._configElement.context = this.context;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleUIConfigChanged(ev: UIConfigChangedEvent) {
|
||||
|
@ -328,6 +333,7 @@ export abstract class HuiElementEditor<T> extends LitElement {
|
|||
if ("lovelace" in configElement) {
|
||||
configElement.lovelace = this.lovelace;
|
||||
}
|
||||
configElement.context = this.context;
|
||||
configElement.addEventListener("config-changed", (ev) =>
|
||||
this._handleUIConfigChanged(ev as UIConfigChangedEvent)
|
||||
);
|
||||
|
|
|
@ -25,6 +25,8 @@ export class HuiSubElementEditor extends LitElement {
|
|||
|
||||
@property({ attribute: false }) public config!: SubElementEditorConfig;
|
||||
|
||||
@property({ attribute: false }) public context?: any;
|
||||
|
||||
@state() private _guiModeAvailable = true;
|
||||
|
||||
@state() private _guiMode = true;
|
||||
|
@ -66,6 +68,7 @@ export class HuiSubElementEditor extends LitElement {
|
|||
class="editor"
|
||||
.hass=${this.hass}
|
||||
.value=${this.config.elementConfig}
|
||||
.context=${this.context}
|
||||
@config-changed=${this._handleConfigChanged}
|
||||
@GUImode-changed=${this._handleGUIModeChanged}
|
||||
></hui-row-element-editor>
|
||||
|
@ -76,6 +79,7 @@ export class HuiSubElementEditor extends LitElement {
|
|||
class="editor"
|
||||
.hass=${this.hass}
|
||||
.value=${this.config.elementConfig}
|
||||
.context=${this.context}
|
||||
@config-changed=${this._handleConfigChanged}
|
||||
@GUImode-changed=${this._handleGUIModeChanged}
|
||||
></hui-headerfooter-element-editor>
|
||||
|
@ -86,6 +90,7 @@ export class HuiSubElementEditor extends LitElement {
|
|||
class="editor"
|
||||
.hass=${this.hass}
|
||||
.value=${this.config.elementConfig}
|
||||
.context=${this.context}
|
||||
@config-changed=${this._handleConfigChanged}
|
||||
@GUImode-changed=${this._handleGUIModeChanged}
|
||||
></hui-tile-extra-element-editor>
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import { customElement } from "lit/decorators";
|
||||
import { getTileExtraElementClass } from "../../create-element/create-tile-extra-element";
|
||||
import { LovelaceTileExtraConfig } from "../../tile-extra/types";
|
||||
import {
|
||||
LovelaceTileExtraConfig,
|
||||
LovelaceTileExtraContext,
|
||||
} from "../../tile-extra/types";
|
||||
import type { LovelaceTileExtraEditor } from "../../types";
|
||||
import { HuiElementEditor } from "../hui-element-editor";
|
||||
|
||||
@customElement("hui-tile-extra-element-editor")
|
||||
export class HuiTileExtraElementEditor extends HuiElementEditor<LovelaceTileExtraConfig> {
|
||||
export class HuiTileExtraElementEditor extends HuiElementEditor<
|
||||
LovelaceTileExtraConfig,
|
||||
LovelaceTileExtraContext
|
||||
> {
|
||||
protected async getConfigElement(): Promise<
|
||||
LovelaceTileExtraEditor | undefined
|
||||
> {
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
import {
|
||||
mdiHomeMapMarker,
|
||||
mdiMapMarker,
|
||||
mdiPause,
|
||||
mdiPlay,
|
||||
mdiPlayPause,
|
||||
mdiStop,
|
||||
mdiTargetVariant,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import "../../../components/tile/ha-tile-button";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
import {
|
||||
canReturnHome,
|
||||
canStart,
|
||||
canStop,
|
||||
isCleaning,
|
||||
VacuumEntity,
|
||||
VacuumEntityFeature,
|
||||
} from "../../../data/vacuum";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceTileExtra, LovelaceTileExtraEditor } from "../types";
|
||||
import {
|
||||
VacuumCommand,
|
||||
VacuumCommandsTileExtraConfig,
|
||||
VACUUM_COMMANDS,
|
||||
} from "./types";
|
||||
|
||||
interface VacuumButton {
|
||||
translationKey: string;
|
||||
icon: string;
|
||||
serviceName: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const VACUUM_COMMANDS_FEATURES: Record<
|
||||
VacuumCommand,
|
||||
VacuumEntityFeature[]
|
||||
> = {
|
||||
start_pause: [VacuumEntityFeature.PAUSE],
|
||||
stop: [VacuumEntityFeature.STOP],
|
||||
clean_spot: [VacuumEntityFeature.CLEAN_SPOT],
|
||||
locate: [VacuumEntityFeature.LOCATE],
|
||||
return_home: [VacuumEntityFeature.RETURN_HOME],
|
||||
};
|
||||
|
||||
export const supportsVacuumCommand = (
|
||||
stateObj: HassEntity,
|
||||
command: VacuumCommand
|
||||
): boolean =>
|
||||
VACUUM_COMMANDS_FEATURES[command].some((feature) =>
|
||||
supportsFeature(stateObj, feature)
|
||||
);
|
||||
|
||||
export const VACUUM_COMMANDS_BUTTONS: Record<
|
||||
VacuumCommand,
|
||||
(stateObj: VacuumEntity) => VacuumButton
|
||||
> = {
|
||||
start_pause: (stateObj) => {
|
||||
const startPauseOnly =
|
||||
!supportsFeature(stateObj, VacuumEntityFeature.START) &&
|
||||
supportsFeature(stateObj, VacuumEntityFeature.PAUSE);
|
||||
|
||||
if (startPauseOnly) {
|
||||
return {
|
||||
translationKey: "start_pause",
|
||||
icon: mdiPlayPause,
|
||||
serviceName: "start_pause",
|
||||
};
|
||||
}
|
||||
const canPause =
|
||||
isCleaning(stateObj) &&
|
||||
supportsFeature(stateObj, VacuumEntityFeature.PAUSE);
|
||||
|
||||
return canPause
|
||||
? {
|
||||
translationKey: "pause",
|
||||
icon: mdiPause,
|
||||
serviceName: "pause",
|
||||
}
|
||||
: {
|
||||
translationKey: "start",
|
||||
icon: mdiPlay,
|
||||
serviceName: "start",
|
||||
disabled: canStart(stateObj),
|
||||
};
|
||||
},
|
||||
stop: (stateObj) => ({
|
||||
translationKey: "stop",
|
||||
icon: mdiStop,
|
||||
serviceName: "stop",
|
||||
disabled: !canStop(stateObj),
|
||||
}),
|
||||
clean_spot: () => ({
|
||||
translationKey: "clean_spot",
|
||||
icon: mdiTargetVariant,
|
||||
serviceName: "clean_spot",
|
||||
}),
|
||||
locate: () => ({
|
||||
translationKey: "locate",
|
||||
icon: mdiMapMarker,
|
||||
serviceName: "locate",
|
||||
}),
|
||||
return_home: (stateObj) => ({
|
||||
translationKey: "return_home",
|
||||
icon: mdiHomeMapMarker,
|
||||
serviceName: "return_to_base",
|
||||
disabled: !canReturnHome(stateObj),
|
||||
}),
|
||||
};
|
||||
|
||||
@customElement("hui-vacuum-commands-tile-extra")
|
||||
class HuiVacuumCommandTileExtra
|
||||
extends LitElement
|
||||
implements LovelaceTileExtra
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public stateObj?: HassEntity;
|
||||
|
||||
@state() private _config?: VacuumCommandsTileExtraConfig;
|
||||
|
||||
static getStubConfig(
|
||||
_,
|
||||
stateObj?: HassEntity
|
||||
): VacuumCommandsTileExtraConfig {
|
||||
return {
|
||||
type: "vacuum-commands",
|
||||
commands: stateObj
|
||||
? VACUUM_COMMANDS.filter((c) =>
|
||||
supportsVacuumCommand(stateObj, c)
|
||||
).slice(0, 3)
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
public static async getConfigElement(): Promise<LovelaceTileExtraEditor> {
|
||||
await import(
|
||||
"../editor/config-elements/hui-vacuum-commands-tile-extra-editor"
|
||||
);
|
||||
return document.createElement("hui-vacuum-commands-tile-extra-editor");
|
||||
}
|
||||
|
||||
public setConfig(config: VacuumCommandsTileExtraConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
private _onCommandTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
const entry = (ev.target! as any).entry as VacuumButton;
|
||||
this.hass!.callService("vacuum", entry.serviceName, {
|
||||
entity_id: this.stateObj!.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._config || !this.hass || !this.stateObj) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const stateObj = this.stateObj as VacuumEntity;
|
||||
|
||||
return html`
|
||||
<div class="container">
|
||||
${VACUUM_COMMANDS.filter(
|
||||
(command) =>
|
||||
supportsVacuumCommand(stateObj, command) &&
|
||||
this._config?.commands?.includes(command)
|
||||
).map((command) => {
|
||||
const button = VACUUM_COMMANDS_BUTTONS[command](stateObj);
|
||||
return html`
|
||||
<ha-tile-button
|
||||
.entry=${button}
|
||||
.label=${this.hass!.localize(
|
||||
// @ts-ignore
|
||||
`ui.dialogs.more_info_control.vacuum.${button.translationKey}`
|
||||
)}
|
||||
@click=${this._onCommandTap}
|
||||
.disabled=${button.disabled || stateObj.state === UNAVAILABLE}
|
||||
>
|
||||
<ha-svg-icon .path=${button.icon}></ha-svg-icon>
|
||||
</ha-tile-button>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 0 12px 12px 12px;
|
||||
width: auto;
|
||||
}
|
||||
ha-tile-button {
|
||||
flex: 1;
|
||||
}
|
||||
ha-tile-button:not(:last-child) {
|
||||
margin-right: 12px;
|
||||
margin-inline-end: 12px;
|
||||
margin-inline-start: initial;
|
||||
direction: var(--direction);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-vacuum-commands-tile-extra": HuiVacuumCommandTileExtra;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,8 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
|||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { CoverEntityFeature } from "../../../data/cover";
|
||||
import { lightSupportsBrightness } from "../../../data/light";
|
||||
import { LovelaceTileExtraConfig } from "./types";
|
||||
import { supportsVacuumCommand } from "./hui-vacuum-commands-tile-extra";
|
||||
import { LovelaceTileExtraConfig, VACUUM_COMMANDS } from "./types";
|
||||
|
||||
type TileExtraType = LovelaceTileExtraConfig["type"];
|
||||
export type SupportsTileExtra = (stateObj: HassEntity) => boolean;
|
||||
|
@ -20,9 +21,12 @@ const TILE_EXTRAS_SUPPORT: Record<TileExtraType, SupportsTileExtra> = {
|
|||
"light-brightness": (stateObj) =>
|
||||
computeDomain(stateObj.entity_id) === "light" &&
|
||||
lightSupportsBrightness(stateObj),
|
||||
"vacuum-commands": (stateObj) =>
|
||||
computeDomain(stateObj.entity_id) === "vacuum" &&
|
||||
VACUUM_COMMANDS.some((c) => supportsVacuumCommand(stateObj, c)),
|
||||
};
|
||||
|
||||
const TILE_EXTRAS_EDITABLE: Set<TileExtraType> = new Set([]);
|
||||
const TILE_EXTRAS_EDITABLE: Set<TileExtraType> = new Set(["vacuum-commands"]);
|
||||
|
||||
export const supportsTileExtra = (
|
||||
stateObj: HassEntity,
|
||||
|
|
|
@ -10,7 +10,27 @@ export interface LightBrightnessTileExtraConfig {
|
|||
type: "light-brightness";
|
||||
}
|
||||
|
||||
export const VACUUM_COMMANDS = [
|
||||
"start_pause",
|
||||
"stop",
|
||||
"clean_spot",
|
||||
"locate",
|
||||
"return_home",
|
||||
] as const;
|
||||
|
||||
export type VacuumCommand = typeof VACUUM_COMMANDS[number];
|
||||
|
||||
export interface VacuumCommandsTileExtraConfig {
|
||||
type: "vacuum-commands";
|
||||
commands?: VacuumCommand[];
|
||||
}
|
||||
|
||||
export type LovelaceTileExtraConfig =
|
||||
| CoverOpenCloseTileExtraConfig
|
||||
| CoverTiltTileExtraConfig
|
||||
| LightBrightnessTileExtraConfig;
|
||||
| LightBrightnessTileExtraConfig
|
||||
| VacuumCommandsTileExtraConfig;
|
||||
|
||||
export type LovelaceTileExtraContext = {
|
||||
entity_id?: string;
|
||||
};
|
||||
|
|
|
@ -88,9 +88,10 @@ export interface LovelaceRowEditor extends LovelaceGenericElementEditor {
|
|||
setConfig(config: LovelaceRowConfig): void;
|
||||
}
|
||||
|
||||
export interface LovelaceGenericElementEditor extends HTMLElement {
|
||||
export interface LovelaceGenericElementEditor<C = any> extends HTMLElement {
|
||||
hass?: HomeAssistant;
|
||||
lovelace?: LovelaceConfig;
|
||||
context?: C;
|
||||
setConfig(config: any): void;
|
||||
focusYamlEditor?: () => void;
|
||||
}
|
||||
|
@ -104,7 +105,10 @@ export interface LovelaceTileExtra extends HTMLElement {
|
|||
export interface LovelaceTileExtraConstructor
|
||||
extends Constructor<LovelaceTileExtra> {
|
||||
getConfigElement?: () => LovelaceTileExtraEditor;
|
||||
getStubConfig?: (hass: HomeAssistant) => LovelaceTileExtraConfig;
|
||||
getStubConfig?: (
|
||||
hass: HomeAssistant,
|
||||
stateObj?: HassEntity
|
||||
) => LovelaceTileExtraConfig;
|
||||
}
|
||||
|
||||
export interface LovelaceTileExtraEditor extends LovelaceGenericElementEditor {
|
||||
|
|
|
@ -4237,6 +4237,17 @@
|
|||
},
|
||||
"light-brightness": {
|
||||
"label": "Light brightness"
|
||||
},
|
||||
"vacuum-commands": {
|
||||
"label": "Vacuum commands",
|
||||
"commands": "Commands",
|
||||
"commands_list": {
|
||||
"start_pause": "[%key:ui::dialogs::more_info_control::vacuum::start_pause%]",
|
||||
"stop": "[%key:ui::dialogs::more_info_control::vacuum::stop%]",
|
||||
"clean_spot": "[%key:ui::dialogs::more_info_control::vacuum::clean_spot%]",
|
||||
"locate": "[%key:ui::dialogs::more_info_control::vacuum::locate%]",
|
||||
"return_home": "[%key:ui::dialogs::more_info_control::vacuum::return_home%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue