diff --git a/src/common/entity/group_entities.ts b/src/common/entity/group_entities.ts
new file mode 100644
index 0000000000..32f9634af5
--- /dev/null
+++ b/src/common/entity/group_entities.ts
@@ -0,0 +1,68 @@
+import { callService, type HassEntity } from "home-assistant-js-websocket";
+import { computeStateDomain } from "./compute_state_domain";
+import { isUnavailableState, UNAVAILABLE } from "../../data/entity";
+import type { HomeAssistant } from "../../types";
+
+export const computeGroupEntitiesState = (states: HassEntity[]): string => {
+ if (!states.length) {
+ return UNAVAILABLE;
+ }
+
+ const validState = states.filter((stateObj) => isUnavailableState(stateObj));
+
+ if (!validState) {
+ return UNAVAILABLE;
+ }
+
+ // Use the first state to determine the domain
+ // This assumes all states in the group have the same domain
+ const domain = computeStateDomain(states[0]);
+
+ if (domain === "cover") {
+ for (const s of ["opening", "closing", "open"]) {
+ if (states.some((stateObj) => stateObj.state === s)) {
+ return s;
+ }
+ }
+ return "closed";
+ }
+
+ if (states.some((stateObj) => stateObj.state === "on")) {
+ return "on";
+ }
+ return "off";
+};
+
+export const toggleGroupEntities = (
+ hass: HomeAssistant,
+ states: HassEntity[]
+) => {
+ if (!states.length) {
+ return;
+ }
+
+ // Use the first state to determine the domain
+ // This assumes all states in the group have the same domain
+ const domain = computeStateDomain(states[0]);
+
+ const state = computeGroupEntitiesState(states);
+
+ const isOn = state === "on" || state === "open";
+
+ let service = isOn ? "turn_off" : "turn_on";
+ if (domain === "cover") {
+ if (state === "opening" || state === "closing") {
+ // If the cover is opening or closing, we toggle it to stop it
+ service = "stop_cover";
+ } else {
+ // For covers, we use the open/close service
+ service = isOn ? "close_cover" : "open_cover";
+ }
+ }
+
+ const entitiesIds = states.map((stateObj) => stateObj.entity_id);
+
+ callService(hass.connection, domain, service, {
+ entity_id: entitiesIds,
+ });
+};
diff --git a/src/common/entity/state_color.ts b/src/common/entity/state_color.ts
index 474fee0e59..976f56ab11 100644
--- a/src/common/entity/state_color.ts
+++ b/src/common/entity/state_color.ts
@@ -64,15 +64,27 @@ export const domainStateColorProperties = (
const compareState = state !== undefined ? state : stateObj.state;
const active = stateActive(stateObj, state);
+ return domainColorProperties(
+ domain,
+ stateObj.attributes.device_class,
+ compareState,
+ active
+ );
+};
+
+export const domainColorProperties = (
+ domain: string,
+ deviceClass: string | undefined,
+ state: string,
+ active: boolean
+) => {
const properties: string[] = [];
- const stateKey = slugify(compareState, "_");
+ const stateKey = slugify(state, "_");
const activeKey = active ? "active" : "inactive";
- const dc = stateObj.attributes.device_class;
-
- if (dc) {
- properties.push(`--state-${domain}-${dc}-${stateKey}-color`);
+ if (deviceClass) {
+ properties.push(`--state-${domain}-${deviceClass}-${stateKey}-color`);
}
properties.push(
diff --git a/src/components/ha-control-button-group.ts b/src/components/ha-control-button-group.ts
index 5c59d0801f..fa9d0717c1 100644
--- a/src/components/ha-control-button-group.ts
+++ b/src/components/ha-control-button-group.ts
@@ -26,6 +26,7 @@ export class HaControlButtonGroup extends LitElement {
.container {
display: flex;
flex-direction: row;
+ justify-content: var(--control-button-group-alignment, start);
width: 100%;
height: 100%;
}
diff --git a/src/components/ha-domain-icon.ts b/src/components/ha-domain-icon.ts
index 6994c32c99..7d30d2f4a9 100644
--- a/src/components/ha-domain-icon.ts
+++ b/src/components/ha-domain-icon.ts
@@ -18,6 +18,8 @@ export class HaDomainIcon extends LitElement {
@property({ attribute: false }) public deviceClass?: string;
+ @property({ attribute: false }) public state?: string;
+
@property() public icon?: string;
@property({ attribute: "brand-fallback", type: Boolean })
@@ -36,14 +38,17 @@ export class HaDomainIcon extends LitElement {
return this._renderFallback();
}
- const icon = domainIcon(this.hass, this.domain, this.deviceClass).then(
- (icn) => {
- if (icn) {
- return html``;
- }
- return this._renderFallback();
+ const icon = domainIcon(
+ this.hass,
+ this.domain,
+ this.deviceClass,
+ this.state
+ ).then((icn) => {
+ if (icn) {
+ return html``;
}
- );
+ return this._renderFallback();
+ });
return html`${until(icon)}`;
}
diff --git a/src/data/icons.ts b/src/data/icons.ts
index 5d870aac2e..4c6699c038 100644
--- a/src/data/icons.ts
+++ b/src/data/icons.ts
@@ -504,14 +504,25 @@ export const serviceSectionIcon = async (
export const domainIcon = async (
hass: HomeAssistant,
domain: string,
- deviceClass?: string
+ deviceClass?: string,
+ state?: string
): Promise => {
const entityComponentIcons = await getComponentIcons(hass, domain);
if (entityComponentIcons) {
const translations =
(deviceClass && entityComponentIcons[deviceClass]) ||
entityComponentIcons._;
- return translations?.default;
+ // First check for exact state match
+ if (state && translations.state?.[state]) {
+ return translations.state[state];
+ }
+ // Then check for range-based icons if we have a numeric state
+ if (state !== undefined && translations.range && !isNaN(Number(state))) {
+ return getIconFromRange(Number(state), translations.range);
+ }
+ // Fallback to default icon
+ return translations.default;
}
+
return undefined;
};
diff --git a/src/panels/lovelace/card-features/common/card-feature-styles.ts b/src/panels/lovelace/card-features/common/card-feature-styles.ts
index 799570cc99..15a6cebcd1 100644
--- a/src/panels/lovelace/card-features/common/card-feature-styles.ts
+++ b/src/panels/lovelace/card-features/common/card-feature-styles.ts
@@ -25,6 +25,9 @@ export const cardFeatureStyles = css`
flex-basis: 20px;
--control-button-padding: 0px;
}
+ ha-control-button-group[no-stretch] > ha-control-button {
+ max-width: 48px;
+ }
ha-control-button {
--control-button-focus-color: var(--feature-color);
}
diff --git a/src/panels/lovelace/card-features/hui-area-controls-card-feature.ts b/src/panels/lovelace/card-features/hui-area-controls-card-feature.ts
index 353be677b9..ceb789d02c 100644
--- a/src/panels/lovelace/card-features/hui-area-controls-card-feature.ts
+++ b/src/panels/lovelace/card-features/hui-area-controls-card-feature.ts
@@ -1,17 +1,22 @@
-import { mdiFan, mdiLightbulb, mdiToggleSwitch } from "@mdi/js";
-import { callService, type HassEntity } from "home-assistant-js-websocket";
-import { LitElement, css, html, nothing } from "lit";
+import type { HassEntity } from "home-assistant-js-websocket";
+import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
+import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one";
+import { ensureArray } from "../../../common/array/ensure-array";
+import { generateEntityFilter } from "../../../common/entity/entity_filter";
import {
- generateEntityFilter,
- type EntityFilter,
-} from "../../../common/entity/entity_filter";
+ computeGroupEntitiesState,
+ toggleGroupEntities,
+} from "../../../common/entity/group_entities";
import { stateActive } from "../../../common/entity/state_active";
+import { domainColorProperties } from "../../../common/entity/state_color";
import "../../../components/ha-control-button";
import "../../../components/ha-control-button-group";
import "../../../components/ha-svg-icon";
import type { AreaRegistryEntry } from "../../../data/area_registry";
+import { forwardHaptic } from "../../../data/haptics";
+import { computeCssVariable } from "../../../resources/css-variables";
import type { HomeAssistant } from "../../../types";
import type { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
import { cardFeatureStyles } from "./common/card-feature-styles";
@@ -19,41 +24,55 @@ import type {
AreaControl,
AreaControlsCardFeatureConfig,
LovelaceCardFeatureContext,
+ LovelaceCardFeaturePosition,
} from "./types";
import { AREA_CONTROLS } from "./types";
interface AreaControlsButton {
- iconPath: string;
- onService: string;
- offService: string;
- filter: EntityFilter;
+ offIcon?: string;
+ onIcon?: string;
+ filter: {
+ domain: string;
+ device_class?: string;
+ };
}
+const coverButton = (deviceClass: string) => ({
+ filter: {
+ domain: "cover",
+ device_class: deviceClass,
+ },
+});
+
export const AREA_CONTROLS_BUTTONS: Record = {
light: {
- iconPath: mdiLightbulb,
+ // Overrides the icons for lights
+ offIcon: "mdi:lightbulb-off",
+ onIcon: "mdi:lightbulb",
filter: {
domain: "light",
},
- onService: "light.turn_on",
- offService: "light.turn_off",
},
fan: {
- iconPath: mdiFan,
filter: {
domain: "fan",
},
- onService: "fan.turn_on",
- offService: "fan.turn_off",
},
switch: {
- iconPath: mdiToggleSwitch,
filter: {
domain: "switch",
},
- onService: "switch.turn_on",
- offService: "switch.turn_off",
},
+ "cover-blind": coverButton("blind"),
+ "cover-curtain": coverButton("curtain"),
+ "cover-damper": coverButton("damper"),
+ "cover-awning": coverButton("awning"),
+ "cover-door": coverButton("door"),
+ "cover-garage": coverButton("garage"),
+ "cover-gate": coverButton("gate"),
+ "cover-shade": coverButton("shade"),
+ "cover-shutter": coverButton("shutter"),
+ "cover-window": coverButton("window"),
};
export const supportsAreaControlsCardFeature = (
@@ -87,6 +106,8 @@ export const getAreaControlEntities = (
{} as Record
);
+export const MAX_DEFAULT_AREA_CONTROLS = 4;
+
@customElement("hui-area-controls-card-feature")
class HuiAreaControlsCardFeature
extends LitElement
@@ -96,6 +117,9 @@ class HuiAreaControlsCardFeature
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
+ @property({ attribute: false })
+ public position?: LovelaceCardFeaturePosition;
+
@state() private _config?: AreaControlsCardFeatureConfig;
private get _area() {
@@ -151,17 +175,12 @@ class HuiAreaControlsCardFeature
);
const entitiesIds = controlEntities[control];
- const { onService, offService } = AREA_CONTROLS_BUTTONS[control];
+ const entities = entitiesIds
+ .map((entityId) => this.hass!.states[entityId] as HassEntity | undefined)
+ .filter((v): v is HassEntity => Boolean(v));
- const isOn = entitiesIds.some((entityId) =>
- stateActive(this.hass!.states[entityId] as HassEntity)
- );
-
- const [domain, service] = (isOn ? offService : onService).split(".");
-
- callService(this.hass!.connection, domain, service, {
- entity_id: entitiesIds,
- });
+ forwardHaptic("light");
+ toggleGroupEntities(this.hass, entities);
}
private _controlEntities = memoizeOne(
@@ -200,33 +219,67 @@ class HuiAreaControlsCardFeature
(control) => controlEntities[control].length > 0
);
- if (!supportedControls.length) {
+ const displayControls = this._config.controls
+ ? supportedControls
+ : supportedControls.slice(0, MAX_DEFAULT_AREA_CONTROLS); // Limit to max if using default controls
+
+ if (!displayControls.length) {
return nothing;
}
return html`
-
- ${supportedControls.map((control) => {
+
+ ${displayControls.map((control) => {
const button = AREA_CONTROLS_BUTTONS[control];
- const entities = controlEntities[control];
- const active = entities.some((entityId) => {
- const stateObj = this.hass!.states[entityId] as
- | HassEntity
- | undefined;
- if (!stateObj) {
- return false;
- }
- return stateActive(stateObj);
- });
+ const entityIds = controlEntities[control];
+
+ const entities = entityIds
+ .map(
+ (entityId) =>
+ this.hass!.states[entityId] as HassEntity | undefined
+ )
+ .filter((v): v is HassEntity => Boolean(v));
+
+ const groupState = computeGroupEntitiesState(entities);
+
+ const active = entities[0]
+ ? stateActive(entities[0], groupState)
+ : false;
+
+ const label = this.hass!.localize(
+ `ui.card_features.area_controls.${control}.${active ? "off" : "on"}`
+ );
+
+ const icon = active ? button.onIcon : button.offIcon;
+
+ const domain = button.filter.domain;
+ const deviceClass = button.filter.device_class
+ ? ensureArray(button.filter.device_class)[0]
+ : undefined;
+
+ const activeColor = computeCssVariable(
+ domainColorProperties(domain, deviceClass, groupState, true)
+ );
return html`
-
+
`;
})}
@@ -238,6 +291,9 @@ class HuiAreaControlsCardFeature
return [
cardFeatureStyles,
css`
+ ha-control-button-group {
+ --control-button-group-alignment: flex-end;
+ }
ha-control-button {
--active-color: var(--state-active-color);
--control-button-focus-color: var(--state-active-color);
diff --git a/src/panels/lovelace/card-features/hui-card-feature.ts b/src/panels/lovelace/card-features/hui-card-feature.ts
index 12592b4fba..fa92cc89ae 100644
--- a/src/panels/lovelace/card-features/hui-card-feature.ts
+++ b/src/panels/lovelace/card-features/hui-card-feature.ts
@@ -7,6 +7,7 @@ import type { LovelaceCardFeature } from "../types";
import type {
LovelaceCardFeatureConfig,
LovelaceCardFeatureContext,
+ LovelaceCardFeaturePosition,
} from "./types";
@customElement("hui-card-feature")
@@ -19,6 +20,9 @@ export class HuiCardFeature extends LitElement {
@property({ attribute: false }) public color?: string;
+ @property({ attribute: false })
+ public position?: LovelaceCardFeaturePosition;
+
private _element?: LovelaceCardFeature | HuiErrorCard;
private _getFeatureElement(feature: LovelaceCardFeatureConfig) {
@@ -41,6 +45,7 @@ export class HuiCardFeature extends LitElement {
element.hass = this.hass;
element.context = this.context;
element.color = this.color;
+ element.position = this.position;
// Backwards compatibility from custom card features
if (this.context.entity_id) {
const stateObj = this.hass.states[this.context.entity_id];
diff --git a/src/panels/lovelace/card-features/hui-card-features.ts b/src/panels/lovelace/card-features/hui-card-features.ts
index b723c3f2a0..138e639657 100644
--- a/src/panels/lovelace/card-features/hui-card-features.ts
+++ b/src/panels/lovelace/card-features/hui-card-features.ts
@@ -5,6 +5,7 @@ import "./hui-card-feature";
import type {
LovelaceCardFeatureConfig,
LovelaceCardFeatureContext,
+ LovelaceCardFeaturePosition,
} from "./types";
@customElement("hui-card-features")
@@ -17,6 +18,9 @@ export class HuiCardFeatures extends LitElement {
@property({ attribute: false }) public color?: string;
+ @property({ attribute: false })
+ public position?: LovelaceCardFeaturePosition;
+
protected render() {
if (!this.features) {
return nothing;
@@ -29,6 +33,7 @@ export class HuiCardFeatures extends LitElement {
.context=${this.context}
.color=${this.color}
.feature=${feature}
+ .position=${this.position}
>
`
)}
diff --git a/src/panels/lovelace/card-features/types.ts b/src/panels/lovelace/card-features/types.ts
index b486fa1c4d..4b74481431 100644
--- a/src/panels/lovelace/card-features/types.ts
+++ b/src/panels/lovelace/card-features/types.ts
@@ -158,7 +158,21 @@ export interface UpdateActionsCardFeatureConfig {
backup?: "yes" | "no" | "ask";
}
-export const AREA_CONTROLS = ["light", "fan", "switch"] as const;
+export const AREA_CONTROLS = [
+ "light",
+ "fan",
+ "cover-shutter",
+ "cover-blind",
+ "cover-curtain",
+ "cover-shade",
+ "cover-awning",
+ "cover-garage",
+ "cover-gate",
+ "cover-door",
+ "cover-window",
+ "cover-damper",
+ "switch",
+] as const;
export type AreaControl = (typeof AREA_CONTROLS)[number];
@@ -168,6 +182,8 @@ export interface AreaControlsCardFeatureConfig {
exclude_entities?: string[];
}
+export type LovelaceCardFeaturePosition = "bottom" | "inline";
+
export type LovelaceCardFeatureConfig =
| AlarmModesCardFeatureConfig
| ClimateFanModesCardFeatureConfig
diff --git a/src/panels/lovelace/cards/hui-area-card.ts b/src/panels/lovelace/cards/hui-area-card.ts
index 3f87f13f65..dc2844e731 100644
--- a/src/panels/lovelace/cards/hui-area-card.ts
+++ b/src/panels/lovelace/cards/hui-area-card.ts
@@ -514,6 +514,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
.context=${this._featureContext}
.color=${this._config.color}
.features=${features}
+ .position=${featurePosition}
>
`
: nothing}
diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts
index 5e04bfb1f0..38c58a6bed 100644
--- a/src/panels/lovelace/cards/types.ts
+++ b/src/panels/lovelace/cards/types.ts
@@ -9,7 +9,10 @@ import type {
ThemeMode,
TranslationDict,
} from "../../../types";
-import type { LovelaceCardFeatureConfig } from "../card-features/types";
+import type {
+ LovelaceCardFeatureConfig,
+ LovelaceCardFeaturePosition,
+} from "../card-features/types";
import type { LegacyStateFilter } from "../common/evaluate-filter";
import type { Condition, LegacyCondition } from "../common/validate-condition";
import type { HuiImage } from "../components/hui-image";
@@ -113,7 +116,7 @@ export interface AreaCardConfig extends LovelaceCardConfig {
sensor_classes?: string[];
alert_classes?: string[];
features?: LovelaceCardFeatureConfig[];
- features_position?: "bottom" | "inline";
+ features_position?: LovelaceCardFeaturePosition;
}
export interface ButtonCardConfig extends LovelaceCardConfig {
@@ -564,7 +567,7 @@ export interface TileCardConfig extends LovelaceCardConfig {
icon_hold_action?: ActionConfig;
icon_double_tap_action?: ActionConfig;
features?: LovelaceCardFeatureConfig[];
- features_position?: "bottom" | "inline";
+ features_position?: LovelaceCardFeaturePosition;
}
export interface HeadingCardConfig extends LovelaceCardConfig {
diff --git a/src/panels/lovelace/editor/config-elements/hui-area-controls-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-area-controls-card-feature-editor.ts
index ac79793497..819ce72dfb 100644
--- a/src/panels/lovelace/editor/config-elements/hui-area-controls-card-feature-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-area-controls-card-feature-editor.ts
@@ -9,7 +9,10 @@ import type {
SchemaUnion,
} from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types";
-import { getAreaControlEntities } from "../../card-features/hui-area-controls-card-feature";
+import {
+ getAreaControlEntities,
+ MAX_DEFAULT_AREA_CONTROLS,
+} from "../../card-features/hui-area-controls-card-feature";
import {
AREA_CONTROLS,
type AreaControl,
@@ -72,7 +75,7 @@ export class HuiAreaControlsCardFeatureEditor
] as const satisfies readonly HaFormSchema[]
);
- private _compatibleControls = memoizeOne(
+ private _supportedControls = memoizeOne(
(
areaId: string,
// needed to update memoized function when entities, devices or areas change
@@ -99,14 +102,14 @@ export class HuiAreaControlsCardFeatureEditor
return nothing;
}
- const compatibleControls = this._compatibleControls(
+ const supportedControls = this._supportedControls(
this.context.area_id,
this.hass.entities,
this.hass.devices,
this.hass.areas
);
- if (compatibleControls.length === 0) {
+ if (supportedControls.length === 0) {
return html`
${this.hass.localize(
@@ -124,7 +127,7 @@ export class HuiAreaControlsCardFeatureEditor
const schema = this._schema(
this.hass.localize,
data.customize_controls,
- compatibleControls
+ supportedControls
);
return html`
@@ -143,12 +146,12 @@ export class HuiAreaControlsCardFeatureEditor
.value as AreaControlsCardFeatureData;
if (customize_controls && !config.controls) {
- config.controls = this._compatibleControls(
+ config.controls = this._supportedControls(
this.context!.area_id!,
this.hass!.entities,
this.hass!.devices,
this.hass!.areas
- ).concat();
+ ).slice(0, MAX_DEFAULT_AREA_CONTROLS); // Limit to max default controls
}
if (!customize_controls && config.controls) {
diff --git a/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts b/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts
index 4fdd45c075..3ff37a0b7c 100644
--- a/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts
+++ b/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts
@@ -6,7 +6,7 @@ import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/sec
import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
import type { HomeAssistant } from "../../../../types";
import { getAreaControlEntities } from "../../card-features/hui-area-controls-card-feature";
-import type { AreaControl } from "../../card-features/types";
+import { AREA_CONTROLS, type AreaControl } from "../../card-features/types";
import type { AreaCardConfig, HeadingCardConfig } from "../../cards/types";
import type { EntitiesDisplay } from "./area-view-strategy";
import { computeAreaPath, getAreas } from "./helpers/areas-strategy-helper";
@@ -77,7 +77,9 @@ export class AreasOverviewViewStrategy extends ReactiveElement {
.map((display) => display.hidden || [])
.flat();
- const controls: AreaControl[] = ["light", "fan"];
+ const controls: AreaControl[] = AREA_CONTROLS.filter(
+ (a) => a !== "switch" // Exclude switches control for areas as we don't know what the switches control
+ );
const controlEntities = getAreaControlEntities(
controls,
area.area_id,
@@ -112,6 +114,11 @@ export class AreasOverviewViewStrategy extends ReactiveElement {
},
]
: [],
+ grid_options: {
+ rows: 1,
+ columns: 12,
+ },
+ features_position: "inline",
navigation_path: path,
};
});
diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts
index 40534349bf..ea580f59d8 100644
--- a/src/panels/lovelace/types.ts
+++ b/src/panels/lovelace/types.ts
@@ -13,6 +13,7 @@ import type { Constructor, HomeAssistant } from "../../types";
import type {
LovelaceCardFeatureConfig,
LovelaceCardFeatureContext,
+ LovelaceCardFeaturePosition,
} from "./card-features/types";
import type { LovelaceElement, LovelaceElementConfig } from "./elements/types";
import type { LovelaceRow, LovelaceRowConfig } from "./entity-rows/types";
@@ -179,6 +180,7 @@ export interface LovelaceCardFeature extends HTMLElement {
context?: LovelaceCardFeatureContext;
setConfig(config: LovelaceCardFeatureConfig);
color?: string;
+ position?: LovelaceCardFeaturePosition;
}
export interface LovelaceCardFeatureConstructor
diff --git a/src/translations/en.json b/src/translations/en.json
index 5bb35b2aab..ae3efff279 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -325,6 +325,62 @@
"low": "Low"
}
},
+ "card_features": {
+ "area_controls": {
+ "light": {
+ "on": "Turn on area lights",
+ "off": "Turn off area lights"
+ },
+ "fan": {
+ "on": "Turn on area fans",
+ "off": "Turn off area fans"
+ },
+ "switch": {
+ "on": "Turn on area switches",
+ "off": "Turn off area switches"
+ },
+ "cover-awning": {
+ "on": "Open area awnings",
+ "off": "Close area awnings"
+ },
+ "cover-blind": {
+ "on": "Open area blinds",
+ "off": "Close area blinds"
+ },
+ "cover-curtain": {
+ "on": "Open area curtains",
+ "off": "Close area curtains"
+ },
+ "cover-damper": {
+ "on": "Open area dampers",
+ "off": "Close area dampers"
+ },
+ "cover-door": {
+ "on": "Open area doors",
+ "off": "Close area doors"
+ },
+ "cover-garage": {
+ "on": "Open garage door",
+ "off": "Close garage door"
+ },
+ "cover-gate": {
+ "on": "Open area gates",
+ "off": "Close area gates"
+ },
+ "cover-shade": {
+ "on": "Open area shades",
+ "off": "Close area shades"
+ },
+ "cover-shutter": {
+ "on": "Open area shutters",
+ "off": "Close area shutters"
+ },
+ "cover-window": {
+ "on": "Open area windows",
+ "off": "Close area windows"
+ }
+ }
+ },
"common": {
"and": "and",
"continue": "Continue",
@@ -383,6 +439,7 @@
"markdown": "Markdown",
"suggest_ai": "Suggest with AI"
},
+
"components": {
"selectors": {
"media": {
@@ -7857,7 +7914,17 @@
"controls_options": {
"light": "Lights",
"fan": "Fans",
- "switch": "Switches"
+ "switch": "Switches",
+ "cover-awning": "Awnings",
+ "cover-blind": "Blinds",
+ "cover-curtain": "Curtains",
+ "cover-damper": "Dampers",
+ "cover-door": "Doors",
+ "cover-garage": "Garage doors",
+ "cover-gate": "Gates",
+ "cover-shade": "Shades",
+ "cover-shutter": "Shutters",
+ "cover-window": "Windows"
},
"no_compatible_controls": "No compatible controls available for this area"
}