Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/data/light.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
HassEntityBase,
} from "home-assistant-js-websocket";
import { temperature2rgb } from "../common/color/convert-light-color";
import type { HomeAssistant } from "../types";

export const enum LightEntityFeature {
EFFECT = 4,
Expand Down Expand Up @@ -72,6 +73,7 @@ export const getLightCurrentModeRgbColor = (
: entity.attributes.rgb_color;

interface LightEntityAttributes extends HassEntityAttributeBase {
entity_id?: string[];
min_color_temp_kelvin?: number;
max_color_temp_kelvin?: number;
min_mireds?: number;
Expand All @@ -94,6 +96,25 @@ export interface LightEntity extends HassEntityBase {
attributes: LightEntityAttributes;
}

export const computeLightAttributeService = (
hass: HomeAssistant,
entity: LightEntity
) => {
const memberIds = entity.attributes.entity_id;

if (!Array.isArray(memberIds)) {
return "turn_on";
}

if (entity.state === "on") {
return "adjust";
}

return memberIds.some((entityId) => hass.states[entityId]?.state === "on")
? "adjust"
: "turn_on";
Comment on lines +113 to +115

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recurse into nested light groups before falling back

The new direct-member check still misses partially-on nested light groups: if a group contains another all: true light group whose own aggregate state is off while one of its child lights is on, none of the immediate memberIds are on, so this returns turn_on and the subsequent brightness/color adjustment wakes the off grandchildren. This leaves the same “partial group turns on everything” regression for users who organize light groups hierarchically; the active-member test needs to expand member groups recursively or otherwise defer the decision to the backend adjust semantics.

Useful? React with 👍 / 👎.

};

export type LightColor =
| {
color_temp_kelvin: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import { UNAVAILABLE } from "../../../../data/entity/entity";
import type { ExtEntityRegistryEntry } from "../../../../data/entity/entity_registry";
import { updateEntityRegistryEntry } from "../../../../data/entity/entity_registry";
import type { LightColor, LightEntity } from "../../../../data/light";
import { computeDefaultFavoriteColors } from "../../../../data/light";
import {
computeDefaultFavoriteColors,
computeLightAttributeService,
type LightColor,
type LightEntity,
} from "../../../../data/light";
import type { HomeAssistant } from "../../../../types";
import { showConfirmationDialog } from "../../../generic/show-dialog-box";
import "../ha-more-info-favorites";
Expand Down Expand Up @@ -53,10 +57,14 @@ export class HaMoreInfoLightFavoriteColors extends LitElement {

private _apply(index: number): void {
const favorite = this._favoriteColors[index];
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj.entity_id,
...favorite,
});
this.hass.callService(
"light",
computeLightAttributeService(this.hass, this.stateObj),
{
entity_id: this.stateObj.entity_id,
...favorite,
}
);
}

private async _save(newFavoriteColors: LightColor[]): Promise<void> {
Expand Down
18 changes: 12 additions & 6 deletions src/dialogs/more-info/components/lights/light-color-rgb-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ import "../../../../components/ha-hs-color-picker";
import "../../../../components/ha-icon";
import "../../../../components/ha-icon-button-prev";
import "../../../../components/ha-labeled-slider";
import type { LightColor, LightEntity } from "../../../../data/light";
import {
computeLightAttributeService,
getLightCurrentModeRgbColor,
LightColorMode,
lightSupportsColorMode,
type LightColor,
type LightEntity,
} from "../../../../data/light";
import type { HomeAssistant } from "../../../../types";

Expand Down Expand Up @@ -346,11 +348,15 @@ class LightRgbColorPicker extends LitElement {

private _applyColor(color: LightColor, params?: Record<string, any>) {
fireEvent(this, "color-changed", color);
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
...color,
...params,
});
this.hass.callService(
"light",
computeLightAttributeService(this.hass, this.stateObj),
{
entity_id: this.stateObj!.entity_id,
...color,
...params,
}
);
}

private _colorBrightnessSliderChanged(ev: CustomEvent) {
Expand Down
22 changes: 15 additions & 7 deletions src/dialogs/more-info/components/lights/light-color-temp-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ import { throttle } from "../../../../common/util/throttle";
import "../../../../components/ha-control-slider";
import { UNAVAILABLE } from "../../../../data/entity/entity";
import { DOMAIN_ATTRIBUTES_UNITS } from "../../../../data/entity/entity_attributes";
import type { LightColor, LightEntity } from "../../../../data/light";
import { LightColorMode } from "../../../../data/light";
import {
computeLightAttributeService,
LightColorMode,
type LightColor,
type LightEntity,
} from "../../../../data/light";
import type { HomeAssistant } from "../../../../types";

declare global {
Expand Down Expand Up @@ -159,11 +163,15 @@ class LightColorTempPicker extends LitElement {

private _applyColor(color: LightColor, params?: Record<string, any>) {
fireEvent(this, "color-changed", color);
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
...color,
...params,
});
this.hass.callService(
"light",
computeLightAttributeService(this.hass, this.stateObj),
{
entity_id: this.stateObj!.entity_id,
...color,
...params,
}
);
}

static get styles(): CSSResultGroup {
Expand Down
27 changes: 18 additions & 9 deletions src/dialogs/more-info/controls/more-info-light.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ import {
type ExtEntityRegistryEntry,
} from "../../../data/entity/entity_registry";
import { forwardHaptic } from "../../../data/haptics";
import type { LightEntity } from "../../../data/light";
import {
computeLightAttributeService,
LightColorMode,
LightEntityFeature,
lightSupportsBrightness,
lightSupportsColor,
lightSupportsColorMode,
lightSupportsFavoriteColors,
type LightEntity,
} from "../../../data/light";
import "../../../state-control/ha-state-control-toggle";
import "../../../state-control/light/ha-state-control-light-brightness";
Expand Down Expand Up @@ -306,10 +307,14 @@ class MoreInfoLight extends LitElement {
};

private _setWhite = () => {
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
white: true,
});
this.hass.callService(
"light",
computeLightAttributeService(this.hass, this.stateObj!),
{
entity_id: this.stateObj!.entity_id,
white: true,
}
);
};

private _handleEffect(ev: HaDropdownSelectEvent) {
Expand All @@ -318,10 +323,14 @@ class MoreInfoLight extends LitElement {

if (!newVal || oldVal === newVal) return;

this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
effect: newVal,
});
this.hass.callService(
"light",
computeLightAttributeService(this.hass, this.stateObj!),
{
entity_id: this.stateObj!.entity_id,
effect: newVal,
}
);
}

static get styles(): CSSResultGroup {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { computeDomain } from "../../../common/entity/compute_domain";
import { stateActive } from "../../../common/entity/state_active";
import "../../../components/ha-control-slider";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { lightSupportsBrightness, type LightEntity } from "../../../data/light";
import {
computeLightAttributeService,
lightSupportsBrightness,
type LightEntity,
} from "../../../data/light";
import type { HomeAssistant } from "../../../types";
import type { LovelaceCardFeature } from "../types";
import { cardFeatureStyles } from "./common/card-feature-styles";
Expand Down Expand Up @@ -94,10 +98,14 @@ class HuiLightBrightnessCardFeature
ev.stopPropagation();
const value = ev.detail.value;

this.hass!.callService("light", "turn_on", {
entity_id: this._stateObj!.entity_id,
brightness_pct: value,
});
this.hass!.callService(
"light",
computeLightAttributeService(this.hass!, this._stateObj!),
{
entity_id: this._stateObj!.entity_id,
brightness_pct: value,
}
);
}

static get styles() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import { computeDomain } from "../../../common/entity/compute_domain";
import { UNAVAILABLE } from "../../../data/entity/entity";
import {
computeLightAttributeService,
computeDefaultFavoriteColors,
type LightEntity,
type LightColor,
Expand Down Expand Up @@ -189,10 +190,14 @@ class HuiLightColorFavoritesCardFeature
const index = (ev.target! as any).index!;

const favorite = this._favoriteColors[index];
this.hass!.callService("light", "turn_on", {
entity_id: this._stateObj!.entity_id,
...favorite,
});
this.hass!.callService(
"light",
computeLightAttributeService(this.hass!, this._stateObj!),
{
entity_id: this._stateObj!.entity_id,
...favorite,
}
);
}

static get styles() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import "../../../components/ha-control-slider";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { DOMAIN_ATTRIBUTES_UNITS } from "../../../data/entity/entity_attributes";
import {
computeLightAttributeService,
LightColorMode,
lightSupportsColorMode,
type LightEntity,
Expand Down Expand Up @@ -121,10 +122,14 @@ class HuiLightColorTempCardFeature
ev.stopPropagation();
const value = ev.detail.value;

this.hass!.callService("light", "turn_on", {
entity_id: this._stateObj!.entity_id,
color_temp_kelvin: value,
});
this.hass!.callService(
"light",
computeLightAttributeService(this.hass!, this._stateObj!),
{
entity_id: this._stateObj!.entity_id,
color_temp_kelvin: value,
}
);
}

static get styles() {
Expand Down
20 changes: 14 additions & 6 deletions src/panels/lovelace/cards/hui-light-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import "../../../components/ha-card";
import "../../../components/ha-icon-button";
import "../../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { LightEntity } from "../../../data/light";
import { lightSupportsBrightness } from "../../../data/light";
import {
computeLightAttributeService,
lightSupportsBrightness,
type LightEntity,
} from "../../../data/light";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
Expand Down Expand Up @@ -213,10 +216,15 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
}

private _setBrightness(e: any): void {
this.hass!.callService("light", "turn_on", {
entity_id: this._config!.entity,
brightness_pct: e.detail.value,
});
const stateObj = this.hass!.states[this._config!.entity] as LightEntity;
this.hass!.callService(
"light",
computeLightAttributeService(this.hass!, stateObj),
{
entity_id: stateObj.entity_id,
brightness_pct: e.detail.value,
}
);
}

private _computeBrightness(stateObj: LightEntity): string {
Expand Down
17 changes: 12 additions & 5 deletions src/state-control/light/ha-state-control-light-brightness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { stateActive } from "../../common/entity/state_active";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-slider";
import { UNAVAILABLE } from "../../data/entity/entity";
import type { LightEntity } from "../../data/light";
import {
computeLightAttributeService,
type LightEntity,
} from "../../data/light";
import type { HomeAssistant } from "../../types";

@customElement("ha-state-control-light-brightness")
Expand All @@ -35,10 +38,14 @@ export class HaStateControlLightBrightness extends LitElement {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;

this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
brightness_pct: value,
});
this.hass.callService(
"light",
computeLightAttributeService(this.hass, this.stateObj),
{
entity_id: this.stateObj!.entity_id,
brightness_pct: value,
}
);
}

protected render(): TemplateResult {
Expand Down
Loading