Color adjustments for entity state (#14557)

This commit is contained in:
Paul Bottein 2022-12-06 17:45:24 +01:00 committed by GitHub
parent 83ba594cc4
commit e6f2e8058b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 101 additions and 61 deletions

View File

@ -4,14 +4,12 @@ import {
} from "home-assistant-js-websocket"; } from "home-assistant-js-websocket";
import { css, html, LitElement, TemplateResult } from "lit"; import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { computeDomain } from "../../../../src/common/entity/compute_domain"; import { computeDomain } from "../../../../src/common/entity/compute_domain";
import { computeStateDisplay } from "../../../../src/common/entity/compute_state_display"; import { computeStateDisplay } from "../../../../src/common/entity/compute_state_display";
import { stateColorCss } from "../../../../src/common/entity/state_color";
import { stateIconPath } from "../../../../src/common/entity/state_icon_path";
import "../../../../src/components/data-table/ha-data-table"; import "../../../../src/components/data-table/ha-data-table";
import type { DataTableColumnContainer } from "../../../../src/components/data-table/ha-data-table"; import type { DataTableColumnContainer } from "../../../../src/components/data-table/ha-data-table";
import "../../../../src/components/entity/state-badge";
import "../../../../src/components/ha-chip"; import "../../../../src/components/ha-chip";
import { provideHass } from "../../../../src/fake_data/provide_hass"; import { provideHass } from "../../../../src/fake_data/provide_hass";
import { HomeAssistant } from "../../../../src/types"; import { HomeAssistant } from "../../../../src/types";
@ -105,6 +103,12 @@ const ENTITIES: HassEntity[] = [
createEntity("alarm_control_panel.arming", "arming"), createEntity("alarm_control_panel.arming", "arming"),
createEntity("alarm_control_panel.disarming", "disarming"), createEntity("alarm_control_panel.disarming", "disarming"),
createEntity("alarm_control_panel.triggered", "triggered"), createEntity("alarm_control_panel.triggered", "triggered"),
// Alert
createEntity("alert.off", "off"),
createEntity("alert.on", "on"),
// Automation
createEntity("automation.off", "off"),
createEntity("automation.on", "on"),
// Binary Sensor // Binary Sensor
...BINARY_SENSOR_DEVICE_CLASSES.map((dc) => ...BINARY_SENSOR_DEVICE_CLASSES.map((dc) =>
createEntity(`binary_sensor.${dc}`, "on", dc) createEntity(`binary_sensor.${dc}`, "on", dc)
@ -113,8 +117,11 @@ const ENTITIES: HassEntity[] = [
createEntity("button.restart", "unknown", "restart"), createEntity("button.restart", "unknown", "restart"),
createEntity("button.update", "unknown", "update"), createEntity("button.update", "unknown", "update"),
// Calendar // Calendar
createEntity("calendar.on", "on"),
createEntity("calendar.off", "off"), createEntity("calendar.off", "off"),
createEntity("calendar.on", "on"),
// Camera
createEntity("camera.off", "off"),
createEntity("camera.on", "on"),
// Climate // Climate
createEntity("climate.off", "off"), createEntity("climate.off", "off"),
createEntity("climate.heat", "heat"), createEntity("climate.heat", "heat"),
@ -124,10 +131,10 @@ const ENTITIES: HassEntity[] = [
createEntity("climate.dry", "dry"), createEntity("climate.dry", "dry"),
createEntity("climate.fan_only", "fan_only"), createEntity("climate.fan_only", "fan_only"),
// Cover // Cover
createEntity("cover.opening", "opening"),
createEntity("cover.open", "open"),
createEntity("cover.closing", "closing"), createEntity("cover.closing", "closing"),
createEntity("cover.closed", "closed"), createEntity("cover.closed", "closed"),
createEntity("cover.opening", "opening"),
createEntity("cover.open", "open"),
createEntity("cover.awning", "open", "awning"), createEntity("cover.awning", "open", "awning"),
createEntity("cover.blind", "open", "blind"), createEntity("cover.blind", "open", "blind"),
createEntity("cover.curtain", "open", "curtain"), createEntity("cover.curtain", "open", "curtain"),
@ -139,24 +146,27 @@ const ENTITIES: HassEntity[] = [
createEntity("cover.shutter", "open", "shutter"), createEntity("cover.shutter", "open", "shutter"),
createEntity("cover.window", "open", "window"), createEntity("cover.window", "open", "window"),
// Device tracker/person // Device tracker/person
createEntity("device_tracker.home", "home"),
createEntity("device_tracker.not_home", "not_home"), createEntity("device_tracker.not_home", "not_home"),
createEntity("device_tracker.home", "home"),
createEntity("device_tracker.work", "work"), createEntity("device_tracker.work", "work"),
createEntity("person.home", "home"), createEntity("person.home", "home"),
createEntity("person.not_home", "not_home"), createEntity("person.not_home", "not_home"),
createEntity("person.work", "work"), createEntity("person.work", "work"),
// Fan // Fan
createEntity("fan.on", "on"),
createEntity("fan.off", "off"), createEntity("fan.off", "off"),
createEntity("fan.on", "on"),
// Humidifier // Humidifier
createEntity("humidifier.on", "on"),
createEntity("humidifier.off", "off"), createEntity("humidifier.off", "off"),
createEntity("humidifier.on", "on"),
// Helpers
createEntity("input_boolean.off", "off"),
createEntity("input_boolean.on", "on"),
// Light // Light
createEntity("light.on", "on"),
createEntity("light.off", "off"), createEntity("light.off", "off"),
createEntity("light.on", "on"),
// Locks // Locks
createEntity("lock.locked", "locked"),
createEntity("lock.unlocked", "unlocked"), createEntity("lock.unlocked", "unlocked"),
createEntity("lock.locked", "locked"),
createEntity("lock.locking", "locking"), createEntity("lock.locking", "locking"),
createEntity("lock.unlocking", "unlocking"), createEntity("lock.unlocking", "unlocking"),
createEntity("lock.jammed", "jammed"), createEntity("lock.jammed", "jammed"),
@ -180,6 +190,12 @@ const ENTITIES: HassEntity[] = [
createEntity("media_player.speaker_playing", "playing", "speaker"), createEntity("media_player.speaker_playing", "playing", "speaker"),
createEntity("media_player.speaker_paused", "paused", "speaker"), createEntity("media_player.speaker_paused", "paused", "speaker"),
createEntity("media_player.speaker_standby", "standby", "speaker"), createEntity("media_player.speaker_standby", "standby", "speaker"),
// Remote
createEntity("remote.off", "off"),
createEntity("remote.on", "on"),
// Script
createEntity("script.off", "off"),
createEntity("script.on", "on"),
// Sensor // Sensor
...SENSOR_DEVICE_CLASSES.map((dc) => createEntity(`sensor.${dc}`, "10", dc)), ...SENSOR_DEVICE_CLASSES.map((dc) => createEntity(`sensor.${dc}`, "10", dc)),
// Battery sensor // Battery sensor
@ -196,9 +212,12 @@ const ENTITIES: HassEntity[] = [
createEntity("switch.outlet_on", "on", "outlet"), createEntity("switch.outlet_on", "on", "outlet"),
createEntity("switch.switch_off", "off", "switch"), createEntity("switch.switch_off", "off", "switch"),
createEntity("switch.switch_on", "on", "switch"), createEntity("switch.switch_on", "on", "switch"),
// Timer
createEntity("timer.off", "off"),
createEntity("timer.on", "on"),
// Vacuum // Vacuum
createEntity("vacuum.cleaning", "cleaning"),
createEntity("vacuum.docked", "docked"), createEntity("vacuum.docked", "docked"),
createEntity("vacuum.cleaning", "cleaning"),
createEntity("vacuum.paused", "paused"), createEntity("vacuum.paused", "paused"),
createEntity("vacuum.idle", "idle"), createEntity("vacuum.idle", "idle"),
createEntity("vacuum.returning", "returning"), createEntity("vacuum.returning", "returning"),
@ -280,18 +299,12 @@ export class DemoEntityState extends LitElement {
const columns: DataTableColumnContainer<EntityRowData> = { const columns: DataTableColumnContainer<EntityRowData> = {
icon: { icon: {
title: "Icon", title: "Icon",
template: (_, entry) => { template: (_, entry) => html`
const cssColor = stateColorCss(entry.stateObj); <state-badge
return html` .stateObj=${entry.stateObj}
<ha-svg-icon .stateColor=${true}
style=${styleMap({ ></state-badge>
color: `rgb(${cssColor})`, `,
})}
.path=${stateIconPath(entry.stateObj)}
>
</ha-svg-icon>
`;
},
}, },
entity_id: { entity_id: {
title: "Entity id", title: "Entity id",

View File

@ -0,0 +1,10 @@
import { HassEntity } from "home-assistant-js-websocket";
export const personColor = (stateObj: HassEntity): string | undefined => {
switch (stateObj.state) {
case "home":
return "person-home";
default:
return "person-zone";
}
};

View File

@ -5,6 +5,7 @@ import { alarmControlPanelColor } from "./color/alarm_control_panel_color";
import { binarySensorColor } from "./color/binary_sensor_color"; import { binarySensorColor } from "./color/binary_sensor_color";
import { climateColor } from "./color/climate_color"; import { climateColor } from "./color/climate_color";
import { lockColor } from "./color/lock_color"; import { lockColor } from "./color/lock_color";
import { personColor } from "./color/person_color";
import { sensorColor } from "./color/sensor_color"; import { sensorColor } from "./color/sensor_color";
import { computeDomain } from "./compute_domain"; import { computeDomain } from "./compute_domain";
import { stateActive } from "./state_active"; import { stateActive } from "./state_active";
@ -28,6 +29,9 @@ export const stateColor = (stateObj: HassEntity, state?: string) => {
const domain = computeDomain(stateObj.entity_id); const domain = computeDomain(stateObj.entity_id);
switch (domain) { switch (domain) {
case "automation":
return "automation";
case "alarm_control_panel": case "alarm_control_panel":
return alarmControlPanelColor(compareState); return alarmControlPanelColor(compareState);
@ -55,6 +59,10 @@ export const stateColor = (stateObj: HassEntity, state?: string) => {
case "media_player": case "media_player":
return "media-player"; return "media-player";
case "person":
case "device_tracker":
return personColor(stateObj);
case "sensor": case "sensor":
return sensorColor(stateObj); return sensorColor(stateObj);
@ -68,8 +76,20 @@ export const stateColor = (stateObj: HassEntity, state?: string) => {
return compareState === "above_horizon" ? "sun-day" : "sun-night"; return compareState === "above_horizon" ? "sun-day" : "sun-night";
case "switch": case "switch":
case "input_boolean":
return "switch"; return "switch";
case "alert":
return "alert";
case "calendar":
case "camera":
case "remote":
case "script":
case "timer":
case "group":
return "active";
case "update": case "update":
return updateIsInstalling(stateObj as UpdateEntity) return updateIsInstalling(stateObj as UpdateEntity)
? "update-installing" ? "update-installing"

View File

@ -1,29 +1,6 @@
import { css } from "lit"; import { css } from "lit";
export const iconColorCSS = css` export const iconColorCSS = css`
ha-state-icon[data-active][data-domain="alert"],
ha-state-icon[data-active][data-domain="automation"],
ha-state-icon[data-active][data-domain="binary_sensor"],
ha-state-icon[data-active][data-domain="calendar"],
ha-state-icon[data-active][data-domain="camera"],
ha-state-icon[data-active][data-domain="cover"],
ha-state-icon[data-active][data-domain="device_tracker"],
ha-state-icon[data-active][data-domain="fan"],
ha-state-icon[data-active][data-domain="humidifier"],
ha-state-icon[data-active][data-domain="light"],
ha-state-icon[data-active][data-domain="input_boolean"],
ha-state-icon[data-active][data-domain="lock"],
ha-state-icon[data-active][data-domain="media_player"],
ha-state-icon[data-active][data-domain="remote"],
ha-state-icon[data-active][data-domain="script"],
ha-state-icon[data-active][data-domain="sun"],
ha-state-icon[data-active][data-domain="switch"],
ha-state-icon[data-active][data-domain="timer"],
ha-state-icon[data-active][data-domain="vacuum"],
ha-state-icon[data-active][data-domain="group"] {
color: var(--paper-item-icon-active-color, #fdd835);
}
ha-state-icon[data-active][data-domain="alarm_control_panel"][data-state="pending"], ha-state-icon[data-active][data-domain="alarm_control_panel"][data-state="pending"],
ha-state-icon[data-active][data-domain="alarm_control_panel"][data-state="arming"], ha-state-icon[data-active][data-domain="alarm_control_panel"][data-state="arming"],
ha-state-icon[data-active][data-domain="alarm_control_panel"][data-state="triggered"] { ha-state-icon[data-active][data-domain="alarm_control_panel"][data-state="triggered"] {

View File

@ -128,6 +128,18 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
} }
private _computeStateColor = memoize((entity: HassEntity, color?: string) => { private _computeStateColor = memoize((entity: HassEntity, color?: string) => {
if (UNAVAILABLE_STATES.includes(entity.state)) {
return undefined;
}
// Use default color for person/device_tracker because color is on the badge
if (
computeDomain(entity.entity_id) === "person" ||
computeDomain(entity.entity_id) === "device_tracker"
) {
return "var(--rgb-state-default-color)";
}
if (!stateActive(entity)) { if (!stateActive(entity)) {
return undefined; return undefined;
} }

View File

@ -1,6 +1,5 @@
import { mdiHelp, mdiHome, mdiHomeExportOutline } from "@mdi/js"; import { mdiHome, mdiHomeExportOutline } from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket"; import { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE_STATES } from "../../../../../data/entity";
import { HomeAssistant } from "../../../../../types"; import { HomeAssistant } from "../../../../../types";
import { ComputeBadgeFunction } from "./tile-badge"; import { ComputeBadgeFunction } from "./tile-badge";
@ -17,20 +16,18 @@ function getZone(entity: HassEntity, hass: HomeAssistant) {
function personBadgeIcon(entity: HassEntity) { function personBadgeIcon(entity: HassEntity) {
const state = entity.state; const state = entity.state;
if (UNAVAILABLE_STATES.includes(state)) {
return mdiHelp;
}
return state === "not_home" ? mdiHomeExportOutline : mdiHome; return state === "not_home" ? mdiHomeExportOutline : mdiHome;
} }
function personBadgeColor(entity: HassEntity, inZone?: boolean) { function personBadgeColor(entity: HassEntity) {
if (inZone) { switch (entity.state) {
return "var(--rgb-state-person-zone-color)"; case "home":
return "var(--rgb-badge-person-home-color)";
case "not_home":
return "var(--rgb-badge-person-not-home-color)";
default:
return "var(--rgb-badge-person-zone-color)";
} }
const state = entity.state;
return state === "not_home"
? "var(--rgb-state-person-not-home-color)"
: "var(--rgb-state-person-home-color)";
} }
export const computePersonBadge: ComputeBadgeFunction = (stateObj, hass) => { export const computePersonBadge: ComputeBadgeFunction = (stateObj, hass) => {
@ -39,6 +36,6 @@ export const computePersonBadge: ComputeBadgeFunction = (stateObj, hass) => {
return { return {
iconPath: personBadgeIcon(stateObj), iconPath: personBadgeIcon(stateObj),
icon: zone?.attributes.icon, icon: zone?.attributes.icon,
color: personBadgeColor(stateObj, Boolean(zone)), color: personBadgeColor(stateObj),
}; };
}; };

View File

@ -1,5 +1,6 @@
import { HassEntity } from "home-assistant-js-websocket"; import { HassEntity } from "home-assistant-js-websocket";
import { computeDomain } from "../../../../../common/entity/compute_domain"; import { computeDomain } from "../../../../../common/entity/compute_domain";
import { UNAVAILABLE_STATES } from "../../../../../data/entity";
import { HomeAssistant } from "../../../../../types"; import { HomeAssistant } from "../../../../../types";
import { computeClimateBadge } from "./tile-badge-climate"; import { computeClimateBadge } from "./tile-badge-climate";
import { computePersonBadge } from "./tile-badge-person"; import { computePersonBadge } from "./tile-badge-person";
@ -16,6 +17,9 @@ export type ComputeBadgeFunction = (
) => TileBadge | undefined; ) => TileBadge | undefined;
export const computeTileBadge: ComputeBadgeFunction = (stateObj, hass) => { export const computeTileBadge: ComputeBadgeFunction = (stateObj, hass) => {
if (UNAVAILABLE_STATES.includes(stateObj.state)) {
return undefined;
}
const domain = computeDomain(stateObj.entity_id); const domain = computeDomain(stateObj.entity_id);
switch (domain) { switch (domain) {
case "person": case "person":

View File

@ -137,10 +137,13 @@ documentContainer.innerHTML = `<custom-style>
/* rgb state color */ /* rgb state color */
--rgb-state-default-color: 68, 115, 158; --rgb-state-default-color: 68, 115, 158;
--rgb-state-active-color: var(--rgb-primary-color);
--rgb-state-alarm-armed-color: var(--rgb-red-color); --rgb-state-alarm-armed-color: var(--rgb-red-color);
--rgb-state-alarm-pending-color: var(--rgb-orange-color); --rgb-state-alarm-pending-color: var(--rgb-orange-color);
--rgb-state-alarm-arming-color: var(--rgb-orange-color); --rgb-state-alarm-arming-color: var(--rgb-orange-color);
--rgb-state-alarm-triggered-color: var(--rgb-red-color); --rgb-state-alarm-triggered-color: var(--rgb-red-color);
--rgb-state-alert-color: var(--rgb-red-color);
--rgb-state-automation-color: var(--rgb-amber-color);
--rgb-state-binary-sensor-color: var(--rgb-primary-color); --rgb-state-binary-sensor-color: var(--rgb-primary-color);
--rgb-state-binary-sensor-alerting-color: var(--rgb-red-color); --rgb-state-binary-sensor-alerting-color: var(--rgb-red-color);
--rgb-state-cover-color: var(--rgb-purple-color); --rgb-state-cover-color: var(--rgb-purple-color);
@ -152,7 +155,6 @@ documentContainer.innerHTML = `<custom-style>
--rgb-state-lock-pending-color: var(--rgb-orange-color); --rgb-state-lock-pending-color: var(--rgb-orange-color);
--rgb-state-media-player-color: var(--rgb-indigo-color); --rgb-state-media-player-color: var(--rgb-indigo-color);
--rgb-state-person-home-color: var(--rgb-green-color); --rgb-state-person-home-color: var(--rgb-green-color);
--rgb-state-person-not-home-color: var(--rgb-red-color);
--rgb-state-person-zone-color: var(--rgb-blue-color); --rgb-state-person-zone-color: var(--rgb-blue-color);
--rgb-state-sensor-battery-high-color: var(--rgb-green-color); --rgb-state-sensor-battery-high-color: var(--rgb-green-color);
--rgb-state-sensor-battery-low-color: var(--rgb-red-color); --rgb-state-sensor-battery-low-color: var(--rgb-red-color);
@ -173,6 +175,11 @@ documentContainer.innerHTML = `<custom-style>
--rgb-state-climate-heat-cool-color: var(--rgb-state-default-color); --rgb-state-climate-heat-cool-color: var(--rgb-state-default-color);
--rgb-state-climate-idle-color: var(--rgb-disabled-color); --rgb-state-climate-idle-color: var(--rgb-disabled-color);
/* rgb state badge color */
--rgb-badge-person-home-color: var(--rgb-state-person-home-color);
--rgb-badge-person-zone-color: var(--rgb-state-person-zone-color);
--rgb-badge-person-not-home-color: var(--rgb-red-color);
/* input components */ /* input components */
--input-idle-line-color: rgba(0, 0, 0, 0.42); --input-idle-line-color: rgba(0, 0, 0, 0.42);
--input-hover-line-color: rgba(0, 0, 0, 0.87); --input-hover-line-color: rgba(0, 0, 0, 0.87);