mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-11 19:36:35 +00:00
Use supported_color_modes
to determine what UI elements to show (#8961)
This commit is contained in:
parent
20c351949f
commit
36586b798e
@ -9,13 +9,10 @@ import {
|
|||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
SUPPORT_BRIGHTNESS,
|
LightColorModes,
|
||||||
SUPPORT_COLOR,
|
|
||||||
SUPPORT_COLOR_TEMP,
|
|
||||||
SUPPORT_EFFECT,
|
SUPPORT_EFFECT,
|
||||||
SUPPORT_FLASH,
|
SUPPORT_FLASH,
|
||||||
SUPPORT_TRANSITION,
|
SUPPORT_TRANSITION,
|
||||||
SUPPORT_WHITE_VALUE,
|
|
||||||
} from "../../../src/data/light";
|
} from "../../../src/data/light";
|
||||||
import "../../../src/dialogs/more-info/more-info-content";
|
import "../../../src/dialogs/more-info/more-info-content";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
@ -32,7 +29,8 @@ const ENTITIES = [
|
|||||||
getEntity("light", "kitchen_light", "on", {
|
getEntity("light", "kitchen_light", "on", {
|
||||||
friendly_name: "Brightness Light",
|
friendly_name: "Brightness Light",
|
||||||
brightness: 200,
|
brightness: 200,
|
||||||
supported_features: SUPPORT_BRIGHTNESS,
|
supported_color_modes: [LightColorModes.BRIGHTNESS],
|
||||||
|
color_mode: LightColorModes.BRIGHTNESS,
|
||||||
}),
|
}),
|
||||||
getEntity("light", "color_temperature_light", "on", {
|
getEntity("light", "color_temperature_light", "on", {
|
||||||
friendly_name: "White Color Temperature Light",
|
friendly_name: "White Color Temperature Light",
|
||||||
@ -40,20 +38,96 @@ const ENTITIES = [
|
|||||||
color_temp: 75,
|
color_temp: 75,
|
||||||
min_mireds: 30,
|
min_mireds: 30,
|
||||||
max_mireds: 150,
|
max_mireds: 150,
|
||||||
supported_features: SUPPORT_BRIGHTNESS + SUPPORT_COLOR_TEMP,
|
supported_color_modes: [
|
||||||
|
LightColorModes.BRIGHTNESS,
|
||||||
|
LightColorModes.COLOR_TEMP,
|
||||||
|
],
|
||||||
|
color_mode: LightColorModes.COLOR_TEMP,
|
||||||
}),
|
}),
|
||||||
getEntity("light", "color_effectslight", "on", {
|
getEntity("light", "color_hs_light", "on", {
|
||||||
friendly_name: "Color Effets Light",
|
friendly_name: "Color HS Light",
|
||||||
brightness: 255,
|
brightness: 255,
|
||||||
hs_color: [30, 100],
|
hs_color: [30, 100],
|
||||||
white_value: 36,
|
rgb_color: [30, 100, 255],
|
||||||
supported_features:
|
min_mireds: 30,
|
||||||
SUPPORT_BRIGHTNESS +
|
max_mireds: 150,
|
||||||
SUPPORT_EFFECT +
|
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||||
SUPPORT_FLASH +
|
supported_color_modes: [
|
||||||
SUPPORT_COLOR +
|
LightColorModes.BRIGHTNESS,
|
||||||
SUPPORT_TRANSITION +
|
LightColorModes.COLOR_TEMP,
|
||||||
SUPPORT_WHITE_VALUE,
|
LightColorModes.HS,
|
||||||
|
],
|
||||||
|
color_mode: LightColorModes.HS,
|
||||||
|
effect_list: ["random", "colorloop"],
|
||||||
|
}),
|
||||||
|
getEntity("light", "color_rgb_ct_light", "on", {
|
||||||
|
friendly_name: "Color RGB + CT Light",
|
||||||
|
brightness: 255,
|
||||||
|
color_temp: 75,
|
||||||
|
min_mireds: 30,
|
||||||
|
max_mireds: 150,
|
||||||
|
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||||
|
supported_color_modes: [
|
||||||
|
LightColorModes.BRIGHTNESS,
|
||||||
|
LightColorModes.COLOR_TEMP,
|
||||||
|
LightColorModes.RGB,
|
||||||
|
],
|
||||||
|
color_mode: LightColorModes.COLOR_TEMP,
|
||||||
|
effect_list: ["random", "colorloop"],
|
||||||
|
}),
|
||||||
|
getEntity("light", "color_RGB_light", "on", {
|
||||||
|
friendly_name: "Color Effets Light",
|
||||||
|
brightness: 255,
|
||||||
|
rgb_color: [30, 100, 255],
|
||||||
|
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||||
|
supported_color_modes: [LightColorModes.BRIGHTNESS, LightColorModes.RGB],
|
||||||
|
color_mode: LightColorModes.RGB,
|
||||||
|
effect_list: ["random", "colorloop"],
|
||||||
|
}),
|
||||||
|
getEntity("light", "color_rgbw_light", "on", {
|
||||||
|
friendly_name: "Color RGBW Light",
|
||||||
|
brightness: 255,
|
||||||
|
rgbw_color: [30, 100, 255, 125],
|
||||||
|
min_mireds: 30,
|
||||||
|
max_mireds: 150,
|
||||||
|
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||||
|
supported_color_modes: [
|
||||||
|
LightColorModes.BRIGHTNESS,
|
||||||
|
LightColorModes.COLOR_TEMP,
|
||||||
|
LightColorModes.RGBW,
|
||||||
|
],
|
||||||
|
color_mode: LightColorModes.RGBW,
|
||||||
|
effect_list: ["random", "colorloop"],
|
||||||
|
}),
|
||||||
|
getEntity("light", "color_rgbww_light", "on", {
|
||||||
|
friendly_name: "Color RGBWW Light",
|
||||||
|
brightness: 255,
|
||||||
|
rgbww_color: [30, 100, 255, 125, 10],
|
||||||
|
min_mireds: 30,
|
||||||
|
max_mireds: 150,
|
||||||
|
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||||
|
supported_color_modes: [
|
||||||
|
LightColorModes.BRIGHTNESS,
|
||||||
|
LightColorModes.COLOR_TEMP,
|
||||||
|
LightColorModes.RGBWW,
|
||||||
|
],
|
||||||
|
color_mode: LightColorModes.RGBWW,
|
||||||
|
effect_list: ["random", "colorloop"],
|
||||||
|
}),
|
||||||
|
getEntity("light", "color_xy_light", "on", {
|
||||||
|
friendly_name: "Color XY Light",
|
||||||
|
brightness: 255,
|
||||||
|
xy_color: [30, 100],
|
||||||
|
rgb_color: [30, 100, 255],
|
||||||
|
min_mireds: 30,
|
||||||
|
max_mireds: 150,
|
||||||
|
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||||
|
supported_color_modes: [
|
||||||
|
LightColorModes.BRIGHTNESS,
|
||||||
|
LightColorModes.COLOR_TEMP,
|
||||||
|
LightColorModes.XY,
|
||||||
|
],
|
||||||
|
color_mode: LightColorModes.XY,
|
||||||
effect_list: ["random", "colorloop"],
|
effect_list: ["random", "colorloop"],
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
@ -102,3 +102,18 @@ export const lab2hex = (lab: [number, number, number]): string => {
|
|||||||
const rgb = lab2rgb(lab);
|
const rgb = lab2rgb(lab);
|
||||||
return rgb2hex(rgb);
|
return rgb2hex(rgb);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const rgb2hsv = (
|
||||||
|
rgb: [number, number, number]
|
||||||
|
): [number, number, number] => {
|
||||||
|
const [r, g, b] = rgb;
|
||||||
|
const v = Math.max(r, g, b);
|
||||||
|
const c = v - Math.min(r, g, b);
|
||||||
|
const h =
|
||||||
|
c && (v === r ? (g - b) / c : v === g ? 2 + (b - r) / c : 4 + (r - g) / c);
|
||||||
|
return [60 * (h < 0 ? h + 6 : h), v && c / v, v];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const rgb2hs = (rgb: [number, number, number]): [number, number] => {
|
||||||
|
return rgb2hsv(rgb).slice(0, 2) as [number, number];
|
||||||
|
};
|
||||||
|
@ -15,6 +15,7 @@ import { computeActiveState } from "../../common/entity/compute_active_state";
|
|||||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||||
import { stateIcon } from "../../common/entity/state_icon";
|
import { stateIcon } from "../../common/entity/state_icon";
|
||||||
import { iconColorCSS } from "../../common/style/icon_color_css";
|
import { iconColorCSS } from "../../common/style/icon_color_css";
|
||||||
|
import { getLightRgbColor, LightEntity } from "../../data/light";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import "../ha-icon";
|
import "../ha-icon";
|
||||||
|
|
||||||
@ -99,11 +100,13 @@ export class StateBadge extends LitElement {
|
|||||||
hostStyle.backgroundImage = `url(${imageUrl})`;
|
hostStyle.backgroundImage = `url(${imageUrl})`;
|
||||||
this._showIcon = false;
|
this._showIcon = false;
|
||||||
} else if (stateObj.state === "on") {
|
} else if (stateObj.state === "on") {
|
||||||
if (stateObj.attributes.hs_color && this.stateColor !== false) {
|
if (
|
||||||
const hue = stateObj.attributes.hs_color[0];
|
computeStateDomain(stateObj) === "light" &&
|
||||||
const sat = stateObj.attributes.hs_color[1];
|
this.stateColor !== false
|
||||||
if (sat > 10) {
|
) {
|
||||||
iconStyle.color = `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
|
const rgb = getLightRgbColor(stateObj as LightEntity);
|
||||||
|
if (rgb) {
|
||||||
|
iconStyle.color = `rgb(${rgb.slice(0, 3).join(",")})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stateObj.attributes.brightness && this.stateColor !== false) {
|
if (stateObj.attributes.brightness && this.stateColor !== false) {
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
|
import { styleMap } from "lit-html/directives/style-map";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import type { ToggleButton } from "../types";
|
import type { ToggleButton } from "../types";
|
||||||
import "./ha-svg-icon";
|
import "./ha-svg-icon";
|
||||||
@ -19,6 +20,8 @@ export class HaButtonToggleGroup extends LitElement {
|
|||||||
|
|
||||||
@property() public active?: string;
|
@property() public active?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public fullWidth = false;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
@ -33,6 +36,11 @@ export class HaButtonToggleGroup extends LitElement {
|
|||||||
<ha-svg-icon .path=${button.iconPath}></ha-svg-icon>
|
<ha-svg-icon .path=${button.iconPath}></ha-svg-icon>
|
||||||
</mwc-icon-button>`
|
</mwc-icon-button>`
|
||||||
: html`<mwc-button
|
: html`<mwc-button
|
||||||
|
style=${styleMap({
|
||||||
|
width: this.fullWidth
|
||||||
|
? `${100 / this.buttons.length}%`
|
||||||
|
: "initial",
|
||||||
|
})}
|
||||||
.value=${button.value}
|
.value=${button.value}
|
||||||
?active=${this.active === button.value}
|
?active=${this.active === button.value}
|
||||||
@click=${this._handleClick}
|
@click=${this._handleClick}
|
||||||
|
@ -2,7 +2,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|||||||
/* eslint-plugin-disable lit */
|
/* eslint-plugin-disable lit */
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import { EventsMixin } from "../mixins/events-mixin";
|
import { EventsMixin } from "../mixins/events-mixin";
|
||||||
|
import { rgb2hs } from "../common/color/convert-color";
|
||||||
/**
|
/**
|
||||||
* Color-picker custom element
|
* Color-picker custom element
|
||||||
*
|
*
|
||||||
@ -114,6 +114,12 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
|||||||
observer: "applyHsColor",
|
observer: "applyHsColor",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// use these properties to update the state via attributes
|
||||||
|
desiredRgbColor: {
|
||||||
|
type: Object,
|
||||||
|
observer: "applyRgbColor",
|
||||||
|
},
|
||||||
|
|
||||||
// width, height and radius apply to the coordinates of
|
// width, height and radius apply to the coordinates of
|
||||||
// of the canvas.
|
// of the canvas.
|
||||||
// border width are relative to these numbers
|
// border width are relative to these numbers
|
||||||
@ -177,8 +183,11 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
|||||||
this.drawMarker();
|
this.drawMarker();
|
||||||
|
|
||||||
if (this.desiredHsColor) {
|
if (this.desiredHsColor) {
|
||||||
this.setMarkerOnColor(this.desiredHsColor);
|
this.applyHsColor(this.desiredHsColor);
|
||||||
this.applyColorToCanvas(this.desiredHsColor);
|
}
|
||||||
|
|
||||||
|
if (this.desiredRgbColor) {
|
||||||
|
this.applyRgbColor(this.desiredRgbColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.interactionLayer.addEventListener("mousedown", (ev) =>
|
this.interactionLayer.addEventListener("mousedown", (ev) =>
|
||||||
@ -282,12 +291,13 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
|||||||
processUserSelect(ev) {
|
processUserSelect(ev) {
|
||||||
const canvasXY = this.convertToCanvasCoordinates(ev.clientX, ev.clientY);
|
const canvasXY = this.convertToCanvasCoordinates(ev.clientX, ev.clientY);
|
||||||
const hs = this.getColor(canvasXY.x, canvasXY.y);
|
const hs = this.getColor(canvasXY.x, canvasXY.y);
|
||||||
this.onColorSelect(hs);
|
const rgb = this.getRgbColor(canvasXY.x, canvasXY.y);
|
||||||
|
this.onColorSelect(hs, rgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply color to marker position and canvas
|
// apply color to marker position and canvas
|
||||||
onColorSelect(hs) {
|
onColorSelect(hs, rgb) {
|
||||||
this.setMarkerOnColor(hs); // marker always follows mounse 'raw' hs value (= mouse position)
|
this.setMarkerOnColor(hs); // marker always follows mouse 'raw' hs value (= mouse position)
|
||||||
if (!this.ignoreSegments) {
|
if (!this.ignoreSegments) {
|
||||||
// apply segments if needed
|
// apply segments if needed
|
||||||
hs = this.applySegmentFilter(hs);
|
hs = this.applySegmentFilter(hs);
|
||||||
@ -301,11 +311,11 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
|||||||
// eventually after throttle limit has passed
|
// eventually after throttle limit has passed
|
||||||
clearTimeout(this.ensureFinalSelect);
|
clearTimeout(this.ensureFinalSelect);
|
||||||
this.ensureFinalSelect = setTimeout(() => {
|
this.ensureFinalSelect = setTimeout(() => {
|
||||||
this.fireColorSelected(hs); // do it for the final time
|
this.fireColorSelected(hs, rgb); // do it for the final time
|
||||||
}, this.throttle);
|
}, this.throttle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.fireColorSelected(hs); // do it
|
this.fireColorSelected(hs, rgb); // do it
|
||||||
this.colorSelectIsThrottled = true;
|
this.colorSelectIsThrottled = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.colorSelectIsThrottled = false;
|
this.colorSelectIsThrottled = false;
|
||||||
@ -313,9 +323,9 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set color values and fire colorselected event
|
// set color values and fire colorselected event
|
||||||
fireColorSelected(hs) {
|
fireColorSelected(hs, rgb) {
|
||||||
this.hsColor = hs;
|
this.hsColor = hs;
|
||||||
this.fire("colorselected", { hs: { h: hs.h, s: hs.s } });
|
this.fire("colorselected", { hs, rgb });
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -363,6 +373,11 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
|||||||
this.applyColorToCanvas(hs);
|
this.applyColorToCanvas(hs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyRgbColor(rgb) {
|
||||||
|
const [h, s] = rgb2hs(rgb);
|
||||||
|
this.applyHsColor({ h, s });
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* input processing helpers
|
* input processing helpers
|
||||||
*/
|
*/
|
||||||
@ -395,6 +410,15 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
|||||||
return { h: hue, s: sat };
|
return { h: hue, s: sat };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRgbColor(x, y) {
|
||||||
|
// get current pixel
|
||||||
|
const imageData = this.backgroundLayer
|
||||||
|
.getContext("2d")
|
||||||
|
.getImageData(x + 250, y + 250, 1, 1);
|
||||||
|
const pixel = imageData.data;
|
||||||
|
return { r: pixel[0], g: pixel[1], b: pixel[2] };
|
||||||
|
}
|
||||||
|
|
||||||
applySegmentFilter(hs) {
|
applySegmentFilter(hs) {
|
||||||
// apply hue segment steps
|
// apply hue segment steps
|
||||||
if (this.hueSegments) {
|
if (this.hueSegments) {
|
||||||
@ -468,7 +492,7 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
|||||||
.getPropertyValue("--wheel-bordercolor")
|
.getPropertyValue("--wheel-bordercolor")
|
||||||
.trim();
|
.trim();
|
||||||
const wheelShadow = wheelStyle.getPropertyValue("--wheel-shadow").trim();
|
const wheelShadow = wheelStyle.getPropertyValue("--wheel-shadow").trim();
|
||||||
// extract shadow properties from CCS variable
|
// extract shadow properties from CSS variable
|
||||||
// the shadow should be defined as: "10px 5px 5px 0px COLOR"
|
// the shadow should be defined as: "10px 5px 5px 0px COLOR"
|
||||||
if (wheelShadow !== "none") {
|
if (wheelShadow !== "none") {
|
||||||
const values = wheelShadow.split("px ");
|
const values = wheelShadow.split("px ");
|
||||||
|
@ -3,26 +3,82 @@ import {
|
|||||||
HassEntityBase,
|
HassEntityBase,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
|
|
||||||
|
export enum LightColorModes {
|
||||||
|
UNKNOWN = "unknown",
|
||||||
|
ONOFF = "onoff",
|
||||||
|
BRIGHTNESS = "brightness",
|
||||||
|
COLOR_TEMP = "color_temp",
|
||||||
|
HS = "hs",
|
||||||
|
XY = "xy",
|
||||||
|
RGB = "rgb",
|
||||||
|
RGBW = "rgbw",
|
||||||
|
RGBWW = "rgbww",
|
||||||
|
}
|
||||||
|
|
||||||
|
const modesSupportingColor = [
|
||||||
|
LightColorModes.HS,
|
||||||
|
LightColorModes.XY,
|
||||||
|
LightColorModes.RGB,
|
||||||
|
LightColorModes.RGBW,
|
||||||
|
LightColorModes.RGBWW,
|
||||||
|
];
|
||||||
|
|
||||||
|
const modesSupportingDimming = [
|
||||||
|
...modesSupportingColor,
|
||||||
|
LightColorModes.COLOR_TEMP,
|
||||||
|
LightColorModes.BRIGHTNESS,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const SUPPORT_EFFECT = 4;
|
||||||
|
export const SUPPORT_FLASH = 8;
|
||||||
|
export const SUPPORT_TRANSITION = 32;
|
||||||
|
|
||||||
|
export const lightSupportsColorMode = (
|
||||||
|
entity: LightEntity,
|
||||||
|
mode: LightColorModes
|
||||||
|
) => {
|
||||||
|
return entity.attributes.supported_color_modes?.includes(mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lightIsInColorMode = (entity: LightEntity) => {
|
||||||
|
return modesSupportingColor.includes(entity.attributes.color_mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lightSupportsColor = (entity: LightEntity) => {
|
||||||
|
return entity.attributes.supported_color_modes?.some((mode) =>
|
||||||
|
modesSupportingColor.includes(mode)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lightSupportsDimming = (entity: LightEntity) => {
|
||||||
|
return entity.attributes.supported_color_modes?.some((mode) =>
|
||||||
|
modesSupportingDimming.includes(mode)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getLightRgbColor = (entity: LightEntity): number[] | undefined =>
|
||||||
|
entity.attributes.color_mode === LightColorModes.RGBWW
|
||||||
|
? entity.attributes.rgbww_color
|
||||||
|
: entity.attributes.color_mode === LightColorModes.RGBW
|
||||||
|
? entity.attributes.rgbw_color
|
||||||
|
: entity.attributes.rgb_color;
|
||||||
|
|
||||||
interface LightEntityAttributes extends HassEntityAttributeBase {
|
interface LightEntityAttributes extends HassEntityAttributeBase {
|
||||||
min_mireds: number;
|
min_mireds: number;
|
||||||
max_mireds: number;
|
max_mireds: number;
|
||||||
friendly_name: string;
|
friendly_name: string;
|
||||||
brightness: number;
|
brightness: number;
|
||||||
hs_color: number[];
|
hs_color: [number, number];
|
||||||
|
rgb_color: [number, number, number];
|
||||||
|
rgbw_color: [number, number, number, number];
|
||||||
|
rgbww_color: [number, number, number, number, number];
|
||||||
color_temp: number;
|
color_temp: number;
|
||||||
white_value: number;
|
|
||||||
effect?: string;
|
effect?: string;
|
||||||
effect_list: string[] | null;
|
effect_list: string[] | null;
|
||||||
|
supported_color_modes: LightColorModes[];
|
||||||
|
color_mode: LightColorModes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LightEntity extends HassEntityBase {
|
export interface LightEntity extends HassEntityBase {
|
||||||
attributes: LightEntityAttributes;
|
attributes: LightEntityAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SUPPORT_BRIGHTNESS = 1;
|
|
||||||
export const SUPPORT_COLOR_TEMP = 2;
|
|
||||||
export const SUPPORT_EFFECT = 4;
|
|
||||||
export const SUPPORT_FLASH = 8;
|
|
||||||
export const SUPPORT_COLOR = 16;
|
|
||||||
export const SUPPORT_TRANSITION = 32;
|
|
||||||
export const SUPPORT_WHITE_VALUE = 128;
|
|
||||||
|
@ -11,7 +11,6 @@ import {
|
|||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { classMap } from "lit-html/directives/class-map";
|
|
||||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
import "../../../components/ha-attributes";
|
import "../../../components/ha-attributes";
|
||||||
import "../../../components/ha-color-picker";
|
import "../../../components/ha-color-picker";
|
||||||
@ -19,20 +18,22 @@ import "../../../components/ha-icon-button";
|
|||||||
import "../../../components/ha-labeled-slider";
|
import "../../../components/ha-labeled-slider";
|
||||||
import "../../../components/ha-paper-dropdown-menu";
|
import "../../../components/ha-paper-dropdown-menu";
|
||||||
import {
|
import {
|
||||||
|
getLightRgbColor,
|
||||||
|
LightColorModes,
|
||||||
LightEntity,
|
LightEntity,
|
||||||
SUPPORT_BRIGHTNESS,
|
lightIsInColorMode,
|
||||||
SUPPORT_COLOR,
|
lightSupportsColor,
|
||||||
SUPPORT_COLOR_TEMP,
|
lightSupportsColorMode,
|
||||||
|
lightSupportsDimming,
|
||||||
SUPPORT_EFFECT,
|
SUPPORT_EFFECT,
|
||||||
SUPPORT_WHITE_VALUE,
|
|
||||||
} from "../../../data/light";
|
} from "../../../data/light";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import "../../../components/ha-button-toggle-group";
|
||||||
|
|
||||||
interface HueSatColor {
|
const toggleButtons = [
|
||||||
h: number;
|
{ label: "Color", value: "color" },
|
||||||
s: number;
|
{ label: "Temperature", value: LightColorModes.COLOR_TEMP },
|
||||||
}
|
];
|
||||||
|
|
||||||
@customElement("more-info-light")
|
@customElement("more-info-light")
|
||||||
class MoreInfoLight extends LitElement {
|
class MoreInfoLight extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -41,28 +42,51 @@ class MoreInfoLight extends LitElement {
|
|||||||
|
|
||||||
@internalProperty() private _brightnessSliderValue = 0;
|
@internalProperty() private _brightnessSliderValue = 0;
|
||||||
|
|
||||||
@internalProperty() private _ctSliderValue = 0;
|
@internalProperty() private _ctSliderValue?: number;
|
||||||
|
|
||||||
@internalProperty() private _wvSliderValue = 0;
|
@internalProperty() private _cwSliderValue?: number;
|
||||||
|
|
||||||
|
@internalProperty() private _wwSliderValue?: number;
|
||||||
|
|
||||||
|
@internalProperty() private _wvSliderValue?: number;
|
||||||
|
|
||||||
|
@internalProperty() private _colorBrightnessSliderValue?: number;
|
||||||
|
|
||||||
|
@internalProperty() private _brightnessAdjusted?: number;
|
||||||
|
|
||||||
@internalProperty() private _hueSegments = 24;
|
@internalProperty() private _hueSegments = 24;
|
||||||
|
|
||||||
@internalProperty() private _saturationSegments = 8;
|
@internalProperty() private _saturationSegments = 8;
|
||||||
|
|
||||||
@internalProperty() private _colorPickerColor?: HueSatColor;
|
@internalProperty() private _colorPickerColor?: [number, number, number];
|
||||||
|
|
||||||
|
@internalProperty() private _mode?: "color" | LightColorModes.COLOR_TEMP;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.hass || !this.stateObj) {
|
if (!this.hass || !this.stateObj) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const supportsTemp = lightSupportsColorMode(
|
||||||
|
this.stateObj,
|
||||||
|
LightColorModes.COLOR_TEMP
|
||||||
|
);
|
||||||
|
|
||||||
|
const supportsRgbww = lightSupportsColorMode(
|
||||||
|
this.stateObj,
|
||||||
|
LightColorModes.RGBWW
|
||||||
|
);
|
||||||
|
|
||||||
|
const supportsRgbw =
|
||||||
|
!supportsRgbww &&
|
||||||
|
lightSupportsColorMode(this.stateObj, LightColorModes.RGBW);
|
||||||
|
|
||||||
|
const supportsColor =
|
||||||
|
supportsRgbww || supportsRgbw || lightSupportsColor(this.stateObj);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div class="content">
|
||||||
class="content ${classMap({
|
${lightSupportsDimming(this.stateObj)
|
||||||
"is-on": this.stateObj.state === "on",
|
|
||||||
})}"
|
|
||||||
>
|
|
||||||
${supportsFeature(this.stateObj!, SUPPORT_BRIGHTNESS)
|
|
||||||
? html`
|
? html`
|
||||||
<ha-labeled-slider
|
<ha-labeled-slider
|
||||||
caption=${this.hass.localize("ui.card.light.brightness")}
|
caption=${this.hass.localize("ui.card.light.brightness")}
|
||||||
@ -77,7 +101,17 @@ class MoreInfoLight extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
${this.stateObj.state === "on"
|
${this.stateObj.state === "on"
|
||||||
? html`
|
? html`
|
||||||
${supportsFeature(this.stateObj, SUPPORT_COLOR_TEMP)
|
${supportsTemp || supportsColor ? html`<hr></hr>` : ""}
|
||||||
|
${supportsTemp && supportsColor
|
||||||
|
? html`<ha-button-toggle-group
|
||||||
|
fullWidth
|
||||||
|
.buttons=${toggleButtons}
|
||||||
|
.active=${this._mode}
|
||||||
|
@value-changed=${this._modeChanged}
|
||||||
|
></ha-button-toggle-group>`
|
||||||
|
: ""}
|
||||||
|
${supportsTemp &&
|
||||||
|
(!supportsColor || this._mode === LightColorModes.COLOR_TEMP)
|
||||||
? html`
|
? html`
|
||||||
<ha-labeled-slider
|
<ha-labeled-slider
|
||||||
class="color_temp"
|
class="color_temp"
|
||||||
@ -91,27 +125,16 @@ class MoreInfoLight extends LitElement {
|
|||||||
@change=${this._ctSliderChanged}
|
@change=${this._ctSliderChanged}
|
||||||
pin
|
pin
|
||||||
></ha-labeled-slider>
|
></ha-labeled-slider>
|
||||||
|
<hr></hr>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${supportsFeature(this.stateObj, SUPPORT_WHITE_VALUE)
|
${supportsColor && (!supportsTemp || this._mode === "color")
|
||||||
? html`
|
|
||||||
<ha-labeled-slider
|
|
||||||
caption=${this.hass.localize("ui.card.light.white_value")}
|
|
||||||
icon="hass:file-word-box"
|
|
||||||
max="255"
|
|
||||||
.value=${this._wvSliderValue}
|
|
||||||
@change=${this._wvSliderChanged}
|
|
||||||
pin
|
|
||||||
></ha-labeled-slider>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${supportsFeature(this.stateObj, SUPPORT_COLOR)
|
|
||||||
? html`
|
? html`
|
||||||
<div class="segmentationContainer">
|
<div class="segmentationContainer">
|
||||||
<ha-color-picker
|
<ha-color-picker
|
||||||
class="color"
|
class="color"
|
||||||
@colorselected=${this._colorPicked}
|
@colorselected=${this._colorPicked}
|
||||||
.desiredHsColor=${this._colorPickerColor}
|
.desiredRgbColor=${this._colorPickerColor}
|
||||||
throttle="500"
|
throttle="500"
|
||||||
.hueSegments=${this._hueSegments}
|
.hueSegments=${this._hueSegments}
|
||||||
.saturationSegments=${this._saturationSegments}
|
.saturationSegments=${this._saturationSegments}
|
||||||
@ -123,6 +146,67 @@ class MoreInfoLight extends LitElement {
|
|||||||
class="segmentationButton"
|
class="segmentationButton"
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
${
|
||||||
|
supportsRgbw || supportsRgbww
|
||||||
|
? html`<ha-labeled-slider
|
||||||
|
.caption=${this.hass.localize(
|
||||||
|
"ui.card.light.color_brightness"
|
||||||
|
)}
|
||||||
|
icon="hass:brightness-7"
|
||||||
|
max="100"
|
||||||
|
.value=${this._colorBrightnessSliderValue ?? 255}
|
||||||
|
@change=${this._colorBrightnessSliderChanged}
|
||||||
|
pin
|
||||||
|
></ha-labeled-slider>`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
supportsRgbw
|
||||||
|
? html`
|
||||||
|
<ha-labeled-slider
|
||||||
|
.caption=${this.hass.localize(
|
||||||
|
"ui.card.light.white_value"
|
||||||
|
)}
|
||||||
|
icon="hass:file-word-box"
|
||||||
|
max="100"
|
||||||
|
.name=${"wv"}
|
||||||
|
.value=${this._wvSliderValue}
|
||||||
|
@change=${this._wvSliderChanged}
|
||||||
|
pin
|
||||||
|
></ha-labeled-slider>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
supportsRgbww
|
||||||
|
? html`
|
||||||
|
<ha-labeled-slider
|
||||||
|
.caption=${this.hass.localize(
|
||||||
|
"ui.card.light.cold_white_value"
|
||||||
|
)}
|
||||||
|
icon="hass:file-word-box-outline"
|
||||||
|
max="100"
|
||||||
|
.name=${"cw"}
|
||||||
|
.value=${this._cwSliderValue}
|
||||||
|
@change=${this._wvSliderChanged}
|
||||||
|
pin
|
||||||
|
></ha-labeled-slider>
|
||||||
|
<ha-labeled-slider
|
||||||
|
.caption=${this.hass.localize(
|
||||||
|
"ui.card.light.warm_white_value"
|
||||||
|
)}
|
||||||
|
icon="hass:file-word-box"
|
||||||
|
max="100"
|
||||||
|
.name=${"ww"}
|
||||||
|
.value=${this._wwSliderValue}
|
||||||
|
@change=${this._wvSliderChanged}
|
||||||
|
pin
|
||||||
|
></ha-labeled-slider>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
<hr></hr>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${supportsFeature(this.stateObj, SUPPORT_EFFECT) &&
|
${supportsFeature(this.stateObj, SUPPORT_EFFECT) &&
|
||||||
@ -151,32 +235,83 @@ class MoreInfoLight extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
<ha-attributes
|
<ha-attributes
|
||||||
.stateObj=${this.stateObj}
|
.stateObj=${this.stateObj}
|
||||||
extra-filters="brightness,color_temp,white_value,effect_list,effect,hs_color,rgb_color,xy_color,min_mireds,max_mireds,entity_id,supported_color_modes,color_mode"
|
extra-filters="brightness,color_temp,white_value,effect_list,effect,hs_color,rgb_color,rgbw_color,rgbww_color,xy_color,min_mireds,max_mireds,entity_id,supported_color_modes,color_mode"
|
||||||
></ha-attributes>
|
></ha-attributes>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues): void {
|
protected updated(changedProps: PropertyValues<this>) {
|
||||||
|
if (!changedProps.has("stateObj")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const stateObj = this.stateObj! as LightEntity;
|
const stateObj = this.stateObj! as LightEntity;
|
||||||
if (changedProps.has("stateObj")) {
|
const oldStateObj = changedProps.get("stateObj") as LightEntity | undefined;
|
||||||
|
|
||||||
if (stateObj.state === "on") {
|
if (stateObj.state === "on") {
|
||||||
|
// Don't change tab when the color mode changes
|
||||||
|
if (
|
||||||
|
oldStateObj?.entity_id !== stateObj.entity_id ||
|
||||||
|
oldStateObj?.state !== stateObj.state
|
||||||
|
) {
|
||||||
|
this._mode = lightIsInColorMode(this.stateObj!)
|
||||||
|
? "color"
|
||||||
|
: LightColorModes.COLOR_TEMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
let brightnessAdjust = 100;
|
||||||
|
if (
|
||||||
|
stateObj.attributes.color_mode === LightColorModes.RGB &&
|
||||||
|
!lightSupportsColorMode(stateObj, LightColorModes.RGBWW) &&
|
||||||
|
!lightSupportsColorMode(stateObj, LightColorModes.RGBW)
|
||||||
|
) {
|
||||||
|
const maxVal = Math.max(...stateObj.attributes.rgb_color);
|
||||||
|
if (maxVal < 255) {
|
||||||
|
this._brightnessAdjusted = maxVal;
|
||||||
|
brightnessAdjust = (this._brightnessAdjusted / 255) * 100;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._brightnessAdjusted = undefined;
|
||||||
|
}
|
||||||
this._brightnessSliderValue = Math.round(
|
this._brightnessSliderValue = Math.round(
|
||||||
(stateObj.attributes.brightness * 100) / 255
|
(stateObj.attributes.brightness * brightnessAdjust) / 255
|
||||||
);
|
);
|
||||||
this._ctSliderValue = stateObj.attributes.color_temp;
|
this._ctSliderValue = stateObj.attributes.color_temp;
|
||||||
this._wvSliderValue = stateObj.attributes.white_value;
|
this._wvSliderValue =
|
||||||
|
stateObj.attributes.color_mode === LightColorModes.RGBW
|
||||||
|
? Math.round((stateObj.attributes.rgbw_color[3] * 100) / 255)
|
||||||
|
: undefined;
|
||||||
|
this._cwSliderValue =
|
||||||
|
stateObj.attributes.color_mode === LightColorModes.RGBWW
|
||||||
|
? Math.round((stateObj.attributes.rgbww_color[3] * 100) / 255)
|
||||||
|
: undefined;
|
||||||
|
this._wwSliderValue =
|
||||||
|
stateObj.attributes.color_mode === LightColorModes.RGBWW
|
||||||
|
? Math.round((stateObj.attributes.rgbww_color[4] * 100) / 255)
|
||||||
|
: undefined;
|
||||||
|
this._colorBrightnessSliderValue =
|
||||||
|
stateObj.attributes.color_mode === LightColorModes.RGBWW
|
||||||
|
? Math.round(
|
||||||
|
(Math.max(...stateObj.attributes.rgbww_color.slice(0, 3)) * 100) /
|
||||||
|
255
|
||||||
|
)
|
||||||
|
: stateObj.attributes.color_mode === LightColorModes.RGBW
|
||||||
|
? Math.round(
|
||||||
|
(Math.max(...stateObj.attributes.rgbw_color.slice(0, 3)) * 100) /
|
||||||
|
255
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
if (stateObj.attributes.hs_color) {
|
this._colorPickerColor = getLightRgbColor(stateObj)?.slice(0, 3) as
|
||||||
this._colorPickerColor = {
|
| [number, number, number]
|
||||||
h: stateObj.attributes.hs_color[0],
|
| undefined;
|
||||||
s: stateObj.attributes.hs_color[1] / 100,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this._brightnessSliderValue = 0;
|
this._brightnessSliderValue = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _modeChanged(ev: CustomEvent) {
|
||||||
|
this._mode = ev.detail.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _effectChanged(ev: CustomEvent) {
|
private _effectChanged(ev: CustomEvent) {
|
||||||
@ -193,12 +328,29 @@ class MoreInfoLight extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _brightnessSliderChanged(ev: CustomEvent) {
|
private _brightnessSliderChanged(ev: CustomEvent) {
|
||||||
const bri = parseInt((ev.target as any).value, 10);
|
const bri = Number((ev.target as any).value);
|
||||||
|
|
||||||
if (isNaN(bri)) {
|
if (isNaN(bri)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._brightnessAdjusted) {
|
||||||
|
const rgb =
|
||||||
|
this.stateObj!.attributes.rgb_color ||
|
||||||
|
([0, 0, 0] as [number, number, number]);
|
||||||
|
|
||||||
|
this.hass.callService("light", "turn_on", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
brightness_pct: bri,
|
||||||
|
rgb_color: this._adjustColorBrightness(
|
||||||
|
rgb,
|
||||||
|
this._brightnessAdjusted,
|
||||||
|
true
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.hass.callService("light", "turn_on", {
|
this.hass.callService("light", "turn_on", {
|
||||||
entity_id: this.stateObj!.entity_id,
|
entity_id: this.stateObj!.entity_id,
|
||||||
brightness_pct: bri,
|
brightness_pct: bri,
|
||||||
@ -206,7 +358,7 @@ class MoreInfoLight extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _ctSliderChanged(ev: CustomEvent) {
|
private _ctSliderChanged(ev: CustomEvent) {
|
||||||
const ct = parseInt((ev.target as any).value, 10);
|
const ct = Number((ev.target as any).value);
|
||||||
|
|
||||||
if (isNaN(ct)) {
|
if (isNaN(ct)) {
|
||||||
return;
|
return;
|
||||||
@ -219,16 +371,62 @@ class MoreInfoLight extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _wvSliderChanged(ev: CustomEvent) {
|
private _wvSliderChanged(ev: CustomEvent) {
|
||||||
const wv = parseInt((ev.target as any).value, 10);
|
const target = ev.target as any;
|
||||||
|
let wv = Number(target.value);
|
||||||
|
const name = target.name;
|
||||||
|
|
||||||
if (isNaN(wv)) {
|
if (isNaN(wv)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wv = (wv * 255) / 100;
|
||||||
|
|
||||||
|
const rgb = getLightRgbColor(this.stateObj!);
|
||||||
|
|
||||||
|
if (name === "wv") {
|
||||||
|
const rgbw_color = rgb || [0, 0, 0, 0];
|
||||||
|
rgbw_color[3] = wv;
|
||||||
this.hass.callService("light", "turn_on", {
|
this.hass.callService("light", "turn_on", {
|
||||||
entity_id: this.stateObj!.entity_id,
|
entity_id: this.stateObj!.entity_id,
|
||||||
white_value: wv,
|
rgbw_color,
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rgbww_color = rgb || [0, 0, 0, 0, 0];
|
||||||
|
while (rgbww_color.length < 5) {
|
||||||
|
rgbww_color.push(0);
|
||||||
|
}
|
||||||
|
rgbww_color[name === "cw" ? 3 : 4] = wv;
|
||||||
|
this.hass.callService("light", "turn_on", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
rgbww_color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _colorBrightnessSliderChanged(ev: CustomEvent) {
|
||||||
|
const target = ev.target as any;
|
||||||
|
const value = Number(target.value);
|
||||||
|
|
||||||
|
const rgb = (getLightRgbColor(this.stateObj!)?.slice(0, 3) || [
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
]) as [number, number, number];
|
||||||
|
|
||||||
|
this._setRgbColor(
|
||||||
|
this._adjustColorBrightness(
|
||||||
|
// first normalize the value
|
||||||
|
this._colorBrightnessSliderValue
|
||||||
|
? this._adjustColorBrightness(
|
||||||
|
rgb,
|
||||||
|
this._colorBrightnessSliderValue,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
: rgb,
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _segmentClick() {
|
private _segmentClick() {
|
||||||
@ -241,16 +439,91 @@ class MoreInfoLight extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _adjustColorBrightness(
|
||||||
|
rgbColor: [number, number, number],
|
||||||
|
value?: number,
|
||||||
|
invert = false
|
||||||
|
) {
|
||||||
|
if (value !== undefined && value !== 255) {
|
||||||
|
let ratio = value / 255;
|
||||||
|
if (invert) {
|
||||||
|
ratio = 1 / ratio;
|
||||||
|
}
|
||||||
|
rgbColor[0] *= ratio;
|
||||||
|
rgbColor[1] *= ratio;
|
||||||
|
rgbColor[2] *= ratio;
|
||||||
|
}
|
||||||
|
return rgbColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _setRgbColor(rgbColor: [number, number, number]) {
|
||||||
|
if (lightSupportsColorMode(this.stateObj!, LightColorModes.RGBWW)) {
|
||||||
|
const rgbww_color: [number, number, number, number, number] = this
|
||||||
|
.stateObj!.attributes.rgbww_color
|
||||||
|
? [...this.stateObj!.attributes.rgbww_color]
|
||||||
|
: [0, 0, 0, 0, 0];
|
||||||
|
this.hass.callService("light", "turn_on", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
rgbww_color: rgbColor.concat(rgbww_color.slice(3)),
|
||||||
|
});
|
||||||
|
} else if (lightSupportsColorMode(this.stateObj!, LightColorModes.RGBW)) {
|
||||||
|
const rgbw_color: [number, number, number, number] = this.stateObj!
|
||||||
|
.attributes.rgbw_color
|
||||||
|
? [...this.stateObj!.attributes.rgbw_color]
|
||||||
|
: [0, 0, 0, 0];
|
||||||
|
this.hass.callService("light", "turn_on", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
rgbw_color: rgbColor.concat(rgbw_color.slice(3)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a new color has been picked.
|
* Called when a new color has been picked.
|
||||||
* should be throttled with the 'throttle=' attribute of the color picker
|
* should be throttled with the 'throttle=' attribute of the color picker
|
||||||
*/
|
*/
|
||||||
private _colorPicked(ev: CustomEvent) {
|
private _colorPicked(ev: CustomEvent) {
|
||||||
|
if (
|
||||||
|
lightSupportsColorMode(this.stateObj!, LightColorModes.RGBWW) ||
|
||||||
|
lightSupportsColorMode(this.stateObj!, LightColorModes.RGBW)
|
||||||
|
) {
|
||||||
|
this._setRgbColor(
|
||||||
|
this._colorBrightnessSliderValue
|
||||||
|
? this._adjustColorBrightness(
|
||||||
|
[ev.detail.rgb.r, ev.detail.rgb.g, ev.detail.rgb.b],
|
||||||
|
this._colorBrightnessSliderValue
|
||||||
|
)
|
||||||
|
: [ev.detail.rgb.r, ev.detail.rgb.g, ev.detail.rgb.b]
|
||||||
|
);
|
||||||
|
} else if (lightSupportsColorMode(this.stateObj!, LightColorModes.RGB)) {
|
||||||
|
const rgb_color = [ev.detail.rgb.r, ev.detail.rgb.g, ev.detail.rgb.b] as [
|
||||||
|
number,
|
||||||
|
number,
|
||||||
|
number
|
||||||
|
];
|
||||||
|
if (this._brightnessAdjusted) {
|
||||||
|
this.hass.callService("light", "turn_on", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
brightness_pct: this._brightnessSliderValue,
|
||||||
|
rgb_color: this._adjustColorBrightness(
|
||||||
|
rgb_color,
|
||||||
|
this._brightnessAdjusted,
|
||||||
|
true
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.hass.callService("light", "turn_on", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
rgb_color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
this.hass.callService("light", "turn_on", {
|
this.hass.callService("light", "turn_on", {
|
||||||
entity_id: this.stateObj!.entity_id,
|
entity_id: this.stateObj!.entity_id,
|
||||||
hs_color: [ev.detail.hs.h, ev.detail.hs.s * 100],
|
hs_color: [ev.detail.hs.h, ev.detail.hs.s * 100],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
@ -275,11 +548,18 @@ class MoreInfoLight extends LitElement {
|
|||||||
);
|
);
|
||||||
/* The color temp minimum value shouldn't be rendered differently. It's not "off". */
|
/* The color temp minimum value shouldn't be rendered differently. It's not "off". */
|
||||||
--paper-slider-knob-start-border-color: var(--primary-color);
|
--paper-slider-knob-start-border-color: var(--primary-color);
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.segmentationContainer {
|
.segmentationContainer {
|
||||||
position: relative;
|
position: relative;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-button-toggle-group {
|
||||||
|
margin: 8px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-color-picker {
|
ha-color-picker {
|
||||||
@ -293,12 +573,19 @@ class MoreInfoLight extends LitElement {
|
|||||||
.segmentationButton {
|
.segmentationButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 5%;
|
top: 5%;
|
||||||
|
left: 0;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-item {
|
paper-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: var(--divider-color);
|
||||||
|
border-bottom: none;
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import { stateIcon } from "../../../common/entity/state_icon";
|
|||||||
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import { LightEntity } from "../../../data/light";
|
import { getLightRgbColor, LightEntity } from "../../../data/light";
|
||||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||||
@ -301,14 +301,14 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _computeColor(stateObj: HassEntity | LightEntity): string {
|
private _computeColor(stateObj: HassEntity | LightEntity): string {
|
||||||
if (!stateObj.attributes.hs_color || !this._config?.state_color) {
|
if (
|
||||||
|
!this._config?.state_color ||
|
||||||
|
computeStateDomain(stateObj) !== "light"
|
||||||
|
) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const [hue, sat] = stateObj.attributes.hs_color;
|
const rgb = getLightRgbColor(stateObj as LightEntity);
|
||||||
if (sat <= 10) {
|
return rgb ? `rgb(${rgb.slice(0, 3).join(",")})` : "";
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleAction(ev: ActionHandlerEvent) {
|
private _handleAction(ev: ActionHandlerEvent) {
|
||||||
|
@ -18,11 +18,14 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
|||||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { stateIcon } from "../../../common/entity/state_icon";
|
import { stateIcon } from "../../../common/entity/state_icon";
|
||||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import { UNAVAILABLE, UNAVAILABLE_STATES } from "../../../data/entity";
|
import { UNAVAILABLE, UNAVAILABLE_STATES } from "../../../data/entity";
|
||||||
import { LightEntity, SUPPORT_BRIGHTNESS } from "../../../data/light";
|
import {
|
||||||
|
getLightRgbColor,
|
||||||
|
LightEntity,
|
||||||
|
lightSupportsDimming,
|
||||||
|
} from "../../../data/light";
|
||||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||||
@ -121,17 +124,14 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
|||||||
@value-changing=${this._dragEvent}
|
@value-changing=${this._dragEvent}
|
||||||
@value-changed=${this._setBrightness}
|
@value-changed=${this._setBrightness}
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
visibility: supportsFeature(stateObj, SUPPORT_BRIGHTNESS)
|
visibility: lightSupportsDimming(stateObj)
|
||||||
? "visible"
|
? "visible"
|
||||||
: "hidden",
|
: "hidden",
|
||||||
})}
|
})}
|
||||||
></round-slider>
|
></round-slider>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
class="light-button ${classMap({
|
class="light-button ${classMap({
|
||||||
"slider-center": supportsFeature(
|
"slider-center": lightSupportsDimming(stateObj),
|
||||||
stateObj,
|
|
||||||
SUPPORT_BRIGHTNESS
|
|
||||||
),
|
|
||||||
"state-on": stateObj.state === "on",
|
"state-on": stateObj.state === "on",
|
||||||
"state-unavailable": stateObj.state === UNAVAILABLE,
|
"state-unavailable": stateObj.state === UNAVAILABLE,
|
||||||
})}"
|
})}"
|
||||||
@ -244,14 +244,11 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _computeColor(stateObj: LightEntity): string {
|
private _computeColor(stateObj: LightEntity): string {
|
||||||
if (stateObj.state === "off" || !stateObj.attributes.hs_color) {
|
if (stateObj.state === "off") {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const [hue, sat] = stateObj.attributes.hs_color;
|
const rgb = getLightRgbColor(stateObj);
|
||||||
if (sat <= 10) {
|
return rgb ? `rgb(${rgb.slice(0, 3).join(",")})` : "";
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleAction(ev: ActionHandlerEvent) {
|
private _handleAction(ev: ActionHandlerEvent) {
|
||||||
|
@ -172,7 +172,10 @@
|
|||||||
"light": {
|
"light": {
|
||||||
"brightness": "Brightness",
|
"brightness": "Brightness",
|
||||||
"color_temperature": "Color temperature",
|
"color_temperature": "Color temperature",
|
||||||
"white_value": "White value",
|
"white_value": "White brightness",
|
||||||
|
"color_brightness": "Color brightness",
|
||||||
|
"cold_white_value": "Cold white brightness",
|
||||||
|
"warm_white_value": "Warm white brightness",
|
||||||
"effect": "Effect"
|
"effect": "Effect"
|
||||||
},
|
},
|
||||||
"lock": {
|
"lock": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user