Skip to content
Merged
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
106 changes: 90 additions & 16 deletions gallery/src/demos/demo-more-info-light.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@ import {
} from "lit-element";
import "../../../src/components/ha-card";
import {
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR,
SUPPORT_COLOR_TEMP,
LightColorModes,
SUPPORT_EFFECT,
SUPPORT_FLASH,
SUPPORT_TRANSITION,
SUPPORT_WHITE_VALUE,
} from "../../../src/data/light";
import "../../../src/dialogs/more-info/more-info-content";
import { getEntity } from "../../../src/fake_data/entity";
Expand All @@ -32,28 +29,105 @@ const ENTITIES = [
getEntity("light", "kitchen_light", "on", {
Comment thread
bramkragten marked this conversation as resolved.
friendly_name: "Brightness Light",
brightness: 200,
supported_features: SUPPORT_BRIGHTNESS,
supported_color_modes: [LightColorModes.BRIGHTNESS],
color_mode: LightColorModes.BRIGHTNESS,
}),
getEntity("light", "color_temperature_light", "on", {
friendly_name: "White Color Temperature Light",
brightness: 128,
color_temp: 75,
min_mireds: 30,
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", {
friendly_name: "Color Effets Light",
getEntity("light", "color_hs_light", "on", {
friendly_name: "Color HS Light",
brightness: 255,
hs_color: [30, 100],
white_value: 36,
supported_features:
SUPPORT_BRIGHTNESS +
SUPPORT_EFFECT +
SUPPORT_FLASH +
SUPPORT_COLOR +
SUPPORT_TRANSITION +
SUPPORT_WHITE_VALUE,
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.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"],
}),
];
Expand Down
15 changes: 15 additions & 0 deletions src/common/color/convert-color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,18 @@ export const lab2hex = (lab: [number, number, number]): string => {
const rgb = lab2rgb(lab);
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];
};
13 changes: 8 additions & 5 deletions src/components/entity/state-badge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { computeActiveState } from "../../common/entity/compute_active_state";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { stateIcon } from "../../common/entity/state_icon";
import { iconColorCSS } from "../../common/style/icon_color_css";
import { getLightRgbColor, LightEntity } from "../../data/light";
import type { HomeAssistant } from "../../types";
import "../ha-icon";

Expand Down Expand Up @@ -99,11 +100,13 @@ export class StateBadge extends LitElement {
hostStyle.backgroundImage = `url(${imageUrl})`;
this._showIcon = false;
} else if (stateObj.state === "on") {
if (stateObj.attributes.hs_color && this.stateColor !== false) {
const hue = stateObj.attributes.hs_color[0];
const sat = stateObj.attributes.hs_color[1];
if (sat > 10) {
iconStyle.color = `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
if (
computeStateDomain(stateObj) === "light" &&
this.stateColor !== false
) {
const rgb = getLightRgbColor(stateObj as LightEntity);
if (rgb) {
iconStyle.color = `rgb(${rgb.slice(0, 3).join(",")})`;
}
}
if (stateObj.attributes.brightness && this.stateColor !== false) {
Expand Down
8 changes: 8 additions & 0 deletions src/components/ha-button-toggle-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
property,
TemplateResult,
} from "lit-element";
import { styleMap } from "lit-html/directives/style-map";
import { fireEvent } from "../common/dom/fire_event";
import type { ToggleButton } from "../types";
import "./ha-svg-icon";
Expand All @@ -19,6 +20,8 @@ export class HaButtonToggleGroup extends LitElement {

@property() public active?: string;

@property({ type: Boolean }) public fullWidth = false;

protected render(): TemplateResult {
return html`
<div>
Expand All @@ -33,6 +36,11 @@ export class HaButtonToggleGroup extends LitElement {
<ha-svg-icon .path=${button.iconPath}></ha-svg-icon>
</mwc-icon-button>`
: html`<mwc-button
style=${styleMap({
width: this.fullWidth
? `${100 / this.buttons.length}%`
: "initial",
})}
.value=${button.value}
?active=${this.active === button.value}
@click=${this._handleClick}
Expand Down
46 changes: 35 additions & 11 deletions src/components/ha-color-picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { EventsMixin } from "../mixins/events-mixin";

import { rgb2hs } from "../common/color/convert-color";
/**
* Color-picker custom element
*
Expand Down Expand Up @@ -114,6 +114,12 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
observer: "applyHsColor",
},

// use these properties to update the state via attributes
desiredRgbColor: {
type: Object,
observer: "applyRgbColor",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

observer 😱

},

// width, height and radius apply to the coordinates of
// of the canvas.
// border width are relative to these numbers
Expand Down Expand Up @@ -177,8 +183,11 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
this.drawMarker();

if (this.desiredHsColor) {
this.setMarkerOnColor(this.desiredHsColor);
this.applyColorToCanvas(this.desiredHsColor);
this.applyHsColor(this.desiredHsColor);
}

if (this.desiredRgbColor) {
this.applyRgbColor(this.desiredRgbColor);
}

this.interactionLayer.addEventListener("mousedown", (ev) =>
Expand Down Expand Up @@ -282,12 +291,13 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
processUserSelect(ev) {
const canvasXY = this.convertToCanvasCoordinates(ev.clientX, ev.clientY);
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
onColorSelect(hs) {
this.setMarkerOnColor(hs); // marker always follows mounse 'raw' hs value (= mouse position)
onColorSelect(hs, rgb) {
this.setMarkerOnColor(hs); // marker always follows mouse 'raw' hs value (= mouse position)
if (!this.ignoreSegments) {
// apply segments if needed
hs = this.applySegmentFilter(hs);
Expand All @@ -301,21 +311,21 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
// eventually after throttle limit has passed
clearTimeout(this.ensureFinalSelect);
this.ensureFinalSelect = setTimeout(() => {
this.fireColorSelected(hs); // do it for the final time
this.fireColorSelected(hs, rgb); // do it for the final time
}, this.throttle);
return;
}
this.fireColorSelected(hs); // do it
this.fireColorSelected(hs, rgb); // do it
this.colorSelectIsThrottled = true;
setTimeout(() => {
this.colorSelectIsThrottled = false;
}, this.throttle);
}

// set color values and fire colorselected event
fireColorSelected(hs) {
fireColorSelected(hs, rgb) {
this.hsColor = hs;
this.fire("colorselected", { hs: { h: hs.h, s: hs.s } });
this.fire("colorselected", { hs, rgb });
}

/*
Expand Down Expand Up @@ -363,6 +373,11 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
this.applyColorToCanvas(hs);
}

applyRgbColor(rgb) {
const [h, s] = rgb2hs(rgb);
this.applyHsColor({ h, s });
}

/*
* input processing helpers
*/
Expand Down Expand Up @@ -395,6 +410,15 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
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) {
// apply hue segment steps
if (this.hueSegments) {
Expand Down Expand Up @@ -468,7 +492,7 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
.getPropertyValue("--wheel-bordercolor")
.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"
if (wheelShadow !== "none") {
const values = wheelShadow.split("px ");
Expand Down
Loading