20221212.0 (#14722)

This commit is contained in:
Bram Kragten 2022-12-12 16:08:35 +01:00 committed by GitHub
commit 9f8aa0b4bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 475 additions and 238 deletions

View File

@ -5,33 +5,39 @@
"context": ".."
},
"appPort": "8124:8123",
"context": "..",
"postCreateCommand": "script/bootstrap",
"extensions": [
"github.vscode-pull-request-github",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-tslint-plugin",
"esbenp.prettier-vscode",
"bierner.lit-html",
"runem.lit-plugin",
"ms-python.vscode-pylance"
],
"containerEnv": {
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
},
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"files.eol": "\n",
"editor.tabSize": 2,
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"files.trimTrailingWhitespace": true
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"runem.lit-plugin",
"github.vscode-pull-request-github",
"eamodio.gitlens"
],
"settings": {
"files.eol": "\n",
"editor.tabSize": 2,
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"editor.renderWhitespace": "boundary",
"editor.rulers": [80],
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"files.trimTrailingWhitespace": true,
"terminal.integrated.shell.linux": "/usr/bin/zsh",
"gitlens.showWelcomeOnInstall": false,
"gitlens.showWhatsNewAfterUpgrades": false,
"workbench.startupEditor": "none"
}
}
}
}

90
.github/workflows/cast_deployment.yaml vendored Normal file
View File

@ -0,0 +1,90 @@
name: Cast deployment
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
push:
branches:
- master
env:
NODE_VERSION: 16
NODE_OPTIONS: --max_old_space_size=6144
jobs:
deploy_dev:
runs-on: ubuntu-latest
name: Deploy Development
if: github.event_name != 'push'
environment:
name: Cast Development
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v3
with:
ref: dev
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn
- name: Install dependencies
run: yarn install
env:
CI: true
- name: Build Cast
run: ./node_modules/.bin/gulp build-cast
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=cast/dist --alias dev
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_CAST_SITE_ID }}
deploy_master:
runs-on: ubuntu-latest
name: Deploy Production
if: github.event_name == 'push'
environment:
name: Cast Production
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v3
with:
ref: master
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn
- name: Install dependencies
run: yarn install
env:
CI: true
- name: Build Cast
run: ./node_modules/.bin/gulp build-cast
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=cast/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_CAST_SITE_ID }}

View File

@ -1,6 +1,9 @@
name: Demo
name: Demo deployment
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
push:
branches:
- dev
@ -12,24 +15,34 @@ env:
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: Demo
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v3
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn
- name: Install dependencies
run: yarn install
env:
CI: true
- name: Build Demo
run: ./node_modules/.bin/gulp build-demo
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
run: npx netlify-cli deploy --dir=demo/dist --prod
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=demo/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }}

View File

@ -0,0 +1,45 @@
name: Design deployment
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
env:
NODE_VERSION: 16
NODE_OPTIONS: --max_old_space_size=6144
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: Design
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v3
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn
- name: Install dependencies
run: yarn install
env:
CI: true
- name: Build Gallery
run: ./node_modules/.bin/gulp build-gallery
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=gallery/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}

View File

@ -1,19 +0,0 @@
name: Netlify
on:
schedule:
- cron: "0 0 * * *"
jobs:
trigger_builds:
name: Trigger netlify build preview
runs-on: "ubuntu-latest"
steps:
- name: Trigger Cast build
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_CAST_DEV_BUILD_HOOK }}
- name: Trigger Demo build
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_DEMO_DEV_BUILD_HOOK }}
- name: Trigger Design build
run: curl -X POST -d "NIGHTLY" https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_GALLERY_DEV_BUILD_HOOK }}

View File

@ -2,7 +2,8 @@
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bierner.lit-html",
"runem.lit-plugin"
"runem.lit-plugin",
"github.vscode-pull-request-github",
"eamodio.gitlens"
]
}

View File

@ -1,6 +1,7 @@
#!/bin/bash
TARGET_LABEL="needs design preview"
export SKIP_FETCH_NIGHTLY_TRANSLATIONS="true"
if [[ "$NETLIFY" != "true" ]]; then
echo "This script can only be run on Netlify"
@ -30,6 +31,4 @@ if [[ "${PULL_REQUEST}" == "true" ]]; then
else
createStatus "success" "Build was not requested by PR label"
fi
elif [[ "$INCOMING_HOOK_BODY" == "NIGHTLY" ]]; then
gulp build-gallery
fi

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20221208.0"
version = "20221212.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"

View File

@ -52,7 +52,9 @@ import {
mdiScriptText,
mdiSineWave,
mdiSpeedometer,
mdiSunWireless,
mdiThermometer,
mdiThermometerLines,
mdiThermostat,
mdiTimerOutline,
mdiVideo,
@ -126,6 +128,7 @@ export const FIXED_DOMAIN_ICONS = {
export const FIXED_DEVICE_CLASS_ICONS = {
apparent_power: mdiFlash,
aqi: mdiAirFilter,
atmospheric_pressure: mdiThermometerLines,
// battery: mdiBattery, => not included by design since `sensorIcon()` will dynamically determine the icon
carbon_dioxide: mdiMoleculeCo2,
carbon_monoxide: mdiMoleculeCo,
@ -138,6 +141,7 @@ export const FIXED_DEVICE_CLASS_ICONS = {
gas: mdiMeterGas,
humidity: mdiWaterPercent,
illuminance: mdiBrightness5,
irradiance: mdiSunWireless,
moisture: mdiWaterPercent,
monetary: mdiCash,
nitrogen_dioxide: mdiMolecule,

View File

@ -13,6 +13,8 @@ export const alarmControlPanelColor = (state?: string): string | undefined => {
return "alarm-arming";
case "triggered":
return "alarm-triggered";
case "disarmed":
return "alarm-disarmed";
default:
return undefined;
}

View File

@ -1,5 +1,7 @@
export const lockColor = (state?: string): string | undefined => {
switch (state) {
case "unlocked":
return "lock-unlocked";
case "locked":
return "lock-locked";
case "jammed":

View File

@ -2,6 +2,8 @@ export const personColor = (state: string): string | undefined => {
switch (state) {
case "home":
return "person-home";
case "not_home":
return "person-not-home";
default:
return "person-zone";
}

View File

@ -3,12 +3,12 @@ import { batteryStateColor } from "./battery_color";
export const sensorColor = (
stateObj: HassEntity,
compareState: string
state: string
): string | undefined => {
const deviceClass = stateObj?.attributes.device_class;
if (deviceClass === "battery") {
return batteryStateColor(compareState);
return batteryStateColor(state);
}
return undefined;

View File

@ -16,15 +16,15 @@ export function stateActive(stateObj: HassEntity, state?: string): boolean {
// Custom cases
switch (domain) {
case "alarm_control_panel":
return compareState !== "disarmed";
case "cover":
return !["closed", "closing"].includes(compareState);
case "device_tracker":
case "person":
return compareState !== "not_home";
case "alarm_control_panel":
return compareState !== "disarmed";
case "lock":
return compareState !== "unlocked";
return compareState !== "locked";
case "media_player":
return compareState !== "standby";
case "vacuum":

View File

@ -1,5 +1,6 @@
/** Return an color representing a state. */
import { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE } from "../../data/entity";
import { UpdateEntity, updateIsInstalling } from "../../data/update";
import { alarmControlPanelColor } from "./color/alarm_control_panel_color";
import { binarySensorColor } from "./color/binary_sensor_color";
@ -10,7 +11,7 @@ import { sensorColor } from "./color/sensor_color";
import { computeDomain } from "./compute_domain";
import { stateActive } from "./state_active";
const STATIC_COLORED_DOMAIN = new Set([
const STATIC_ACTIVE_COLORED_DOMAIN = new Set([
"alert",
"automation",
"calendar",
@ -30,25 +31,33 @@ const STATIC_COLORED_DOMAIN = new Set([
"vacuum",
]);
export const stateColorCss = (stateObj?: HassEntity, state?: string) => {
if (!stateObj || !stateActive(stateObj, state)) {
return `var(--rgb-disabled-color)`;
export const stateColorCss = (stateObj: HassEntity, state?: string) => {
const compareState = state !== undefined ? state : stateObj?.state;
if (compareState === UNAVAILABLE) {
return `var(--rgb-state-unavailable-color)`;
}
const color = stateColor(stateObj, state);
const domainColor = stateColor(stateObj, state);
if (color) {
return `var(--rgb-state-${color}-color)`;
if (domainColor) {
return `var(--rgb-state-${domainColor}-color)`;
}
return `var(--rgb-state-default-color)`;
if (!stateActive(stateObj, state)) {
return `var(--rgb-state-inactive-color)`;
}
return undefined;
};
export const stateColor = (stateObj: HassEntity, state?: string) => {
const compareState = state !== undefined ? state : stateObj?.state;
const domain = computeDomain(stateObj.entity_id);
if (STATIC_COLORED_DOMAIN.has(domain)) {
if (
STATIC_ACTIVE_COLORED_DOMAIN.has(domain) &&
stateActive(stateObj, state)
) {
return domain.replace("_", "-");
}

View File

@ -21,6 +21,6 @@ export const iconColorCSS = css`
/* Color the icon if unavailable */
ha-state-icon[data-state="unavailable"] {
color: var(--state-unavailable-color);
color: rgb(var(--rgb-state-unavailable-color));
}
`;

View File

@ -37,8 +37,11 @@ export class TextBarElement extends BarElement {
}
const textColor =
options.textColor ||
(options.backgroundColor &&
(luminosity(hex2rgb(options.backgroundColor)) > 0.5 ? "#000" : "#fff"));
(options?.backgroundColor === "transparent"
? "transparent"
: luminosity(hex2rgb(options.backgroundColor)) > 0.5
? "#000"
: "#fff");
// ctx.font = "12px arial";
ctx.fillStyle = textColor;

View File

@ -5,6 +5,7 @@ import { labBrighten } from "../../../common/color/lab";
import { computeDomain } from "../../../common/entity/compute_domain";
import { stateActive } from "../../../common/entity/state_active";
import { stateColor } from "../../../common/entity/state_color";
import { UNAVAILABLE } from "../../../data/entity";
const DOMAIN_STATE_SHADES: Record<string, Record<string, number>> = {
media_player: {
@ -49,21 +50,23 @@ function computeTimelineStateColor(
computedStyles: CSSStyleDeclaration,
stateObj?: HassEntity
): string | undefined {
if (!stateObj || !stateActive(stateObj, state)) {
const rgb = cssToRgb("--rgb-disabled-color", computedStyles);
if (!stateObj || state === UNAVAILABLE) {
return "transparent";
}
const color = stateColor(stateObj, state);
if (!color && !stateActive(stateObj, state)) {
const rgb = cssToRgb("--rgb-state-inactive-color", computedStyles);
if (!rgb) return undefined;
return rgb2hex(rgb);
}
const color = stateColor(stateObj, state);
if (!color) return undefined;
const domain = computeDomain(stateObj.entity_id);
const rgb = cssToRgb(`--rgb-state-${color}-color`, computedStyles);
if (!rgb) return undefined;
const domain = computeDomain(stateObj.entity_id);
const shade = DOMAIN_STATE_SHADES[domain]?.[state] as number | number;
if (!shade) {
return rgb2hex(rgb);

View File

@ -14,7 +14,7 @@ import { styleMap } from "lit/directives/style-map";
import { computeDomain } from "../../common/entity/compute_domain";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { stateActive } from "../../common/entity/state_active";
import { stateColor } from "../../common/entity/state_color";
import { stateColorCss } from "../../common/entity/state_color";
import { iconColorCSS } from "../../common/style/icon_color_css";
import { cameraUrlWithWidthHeight } from "../../data/camera";
import type { HomeAssistant } from "../../types";
@ -107,12 +107,13 @@ export class StateBadge extends LitElement {
}
hostStyle.backgroundImage = `url(${imageUrl})`;
this._showIcon = false;
} else if (stateActive(stateObj) && this._stateColor) {
const iconColor = stateColor(stateObj);
} else if (this._stateColor && stateActive(stateObj)) {
const color = stateColorCss(stateObj);
if (color) {
iconStyle.color = `rgb(${color})`;
}
if (stateObj.attributes.rgb_color) {
iconStyle.color = `rgb(${stateObj.attributes.rgb_color.join(",")})`;
} else if (iconColor) {
iconStyle.color = `rgb(var(--rgb-state-${iconColor}-color))`;
}
if (stateObj.attributes.brightness) {
const brightness = stateObj.attributes.brightness;

View File

@ -31,7 +31,7 @@ export interface HaFormBaseSchema {
export interface HaFormGridSchema extends HaFormBaseSchema {
type: "grid";
name: "";
name: string;
column_min_width?: string;
schema: readonly HaFormSchema[];
}

View File

@ -69,7 +69,6 @@ const defaultFullCalendarConfig: CalendarOptions = {
initialView: "dayGridMonth",
dayMaxEventRows: true,
height: "parent",
eventDisplay: "list-item",
locales: allLocales,
views: {
listWeek: {
@ -97,6 +96,8 @@ export class HAFullCalendar extends LitElement {
@property() public initialView: FullCalendarView = "dayGridMonth";
@property() public eventDisplay = "auto";
@property({ attribute: false }) public error?: string = undefined;
private calendar?: Calendar;
@ -233,6 +234,10 @@ export class HAFullCalendar extends LitElement {
this._fireViewChanged();
}
if (changedProps.has("eventDisplay")) {
this.calendar!.setOption("eventDisplay", this.eventDisplay);
}
const oldHass = changedProps.get("hass") as HomeAssistant;
if (oldHass && oldHass.language !== this.hass.language) {
@ -246,6 +251,7 @@ export class HAFullCalendar extends LitElement {
locale: this.hass.language,
firstDay: firstWeekdayIndex(this.hass.locale),
initialView: this.initialView,
eventDisplay: this.eventDisplay,
eventTimeFormat: {
hour: useAmPm(this.hass.locale) ? "numeric" : "2-digit",
minute: useAmPm(this.hass.locale) ? "numeric" : "2-digit",
@ -320,6 +326,7 @@ export class HAFullCalendar extends LitElement {
this._activeView = "dayGridDay";
this.calendar!.changeView("dayGridDay");
this.calendar!.gotoDate(info.dateStr);
this._fireViewChanged();
}
private _handleNext(): void {
@ -537,6 +544,7 @@ export class HAFullCalendar extends LitElement {
a.fc-daygrid-day-number {
float: none !important;
font-size: 12px;
cursor: pointer;
}
.fc .fc-daygrid-day-number {
@ -547,12 +555,8 @@ export class HAFullCalendar extends LitElement {
background: inherit;
}
td.fc-day-today .fc-daygrid-day-top {
padding-top: 4px;
}
td.fc-day-today .fc-daygrid-day-number {
height: 24px;
height: 26px;
color: var(--text-primary-color) !important;
background-color: var(--primary-color);
border-radius: 50%;
@ -561,7 +565,6 @@ export class HAFullCalendar extends LitElement {
white-space: nowrap;
width: max-content;
min-width: 24px;
line-height: 140%;
}
.fc-daygrid-day-events {
@ -571,6 +574,7 @@ export class HAFullCalendar extends LitElement {
.fc-event {
border-radius: 4px;
line-height: 1.7;
cursor: pointer;
}
.fc-daygrid-block-event .fc-event-main {

View File

@ -3,6 +3,7 @@ import { customElement, property, state } from "lit/decorators";
import { canShowPage } from "../../../common/config/can_show_page";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { relativeTime } from "../../../common/datetime/relative_time";
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
import "../../../components/ha-card";
import "../../../components/ha-navigation-list";
import "../../../components/ha-tip";
@ -84,7 +85,7 @@ class HaConfigSystemNavigation extends LitElement {
"percent_used",
`${Math.round(
(this._storageInfo.used / this._storageInfo.total) * 100
)}%`,
)}${blankBeforePercent(this.hass.locale)}%`,
"free_space",
`${this._storageInfo.free} GB`
)

View File

@ -1,3 +1,4 @@
import "@material/mwc-list/mwc-list-item";
import {
mdiCog,
mdiDelete,
@ -7,18 +8,19 @@ import {
mdiPencil,
mdiPlusCircle,
} from "@mdi/js";
import "@material/mwc-list/mwc-list-item";
import "@polymer/paper-tooltip/paper-tooltip";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { SENSOR_ENTITIES } from "../../../common/const";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stringCompare } from "../../../common/string/compare";
import { slugify } from "../../../common/string/slugify";
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
import { groupBy } from "../../../common/util/group-by";
import "../../../components/entity/ha-battery-icon";
import "../../../components/ha-alert";
@ -59,6 +61,7 @@ import {
showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-error-screen";
import "../../../layouts/hass-subpage";
import "../../../layouts/hass-tabs-subpage";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
@ -74,8 +77,6 @@ import {
loadDeviceRegistryDetailDialog,
showDeviceRegistryDetailDialog,
} from "./device-registry-detail/show-dialog-device-registry-detail";
import "../../../layouts/hass-subpage";
import { SENSOR_ENTITIES } from "../../../common/const";
export interface EntityRegistryStateEntry extends EntityRegistryEntry {
stateName?: string | null;
@ -639,7 +640,11 @@ export class HaConfigDevicePage extends LitElement {
batteryState
? html`
<div class="battery">
${batteryIsBinary ? "" : batteryState.state + " %"}
${batteryIsBinary
? ""
: batteryState.state +
blankBeforePercent(this.hass.locale) +
"%"}
<ha-battery-icon
.hass=${this.hass!}
.batteryStateObj=${batteryState}

View File

@ -7,6 +7,7 @@ import memoizeOne from "memoize-one";
import { HASSDomEvent } from "../../../common/dom/fire_event";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { navigate } from "../../../common/navigate";
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
import { LocalizeFunc } from "../../../common/translations/localize";
import { computeRTL } from "../../../common/util/compute_rtl";
import {
@ -339,7 +340,9 @@ export class HaConfigDeviceDashboard extends LitElement {
battery && computeStateDomain(battery) === "binary_sensor";
return battery && (batteryIsBinary || !isNaN(battery.state as any))
? html`
${batteryIsBinary ? "" : battery.state + " %"}
${batteryIsBinary
? ""
: battery.state + blankBeforePercent(this.hass.locale) + "%"}
<ha-battery-icon
.hass=${this.hass!}
.batteryStateObj=${battery}

View File

@ -9,6 +9,7 @@ import { ifDefined } from "lit/directives/if-defined";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { numberFormatToLocale } from "../../../common/number/format_number";
import { round } from "../../../common/number/round";
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
import "../../../components/buttons/ha-progress-button";
import "../../../components/chart/ha-chart-base";
import "../../../components/ha-alert";
@ -169,7 +170,8 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
max: 100,
min: 0,
stepSize: 1,
callback: (value) => value + "%",
callback: (value) =>
value + blankBeforePercent(this.hass.locale) + "%",
},
},
x: {
@ -386,7 +388,8 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
)}
</div>
<div class="value">
${this._systemStatusData.cpu_percent || "-"}%
${this._systemStatusData.cpu_percent ||
"-"}${blankBeforePercent(this.hass.locale)}%
</div>
</div>
<div class="card-content">

View File

@ -10,6 +10,8 @@ import { haStyle } from "../../../../../resources/styles";
import { HomeAssistant } from "../../../../../types";
import "./mqtt-subscribe-card";
const qosLevel = ["0", "1", "2"];
@customElement("mqtt-config-panel")
class HaPanelDevMqtt extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@ -20,6 +22,8 @@ class HaPanelDevMqtt extends LitElement {
@state() private payload = "";
@state() private qos = "0";
private inited = false;
protected firstUpdated() {
@ -29,6 +33,9 @@ class HaPanelDevMqtt extends LitElement {
if (localStorage && localStorage["panel-dev-mqtt-payload"]) {
this.payload = localStorage["panel-dev-mqtt-payload"];
}
if (localStorage && localStorage["panel-dev-mqtt-qos"]) {
this.qos = localStorage["panel-dev-mqtt-qos"];
}
this.inited = true;
}
@ -54,6 +61,15 @@ class HaPanelDevMqtt extends LitElement {
.value=${this.topic}
@change=${this._handleTopic}
></ha-textfield>
<ha-select
.label=${this.hass.localize("ui.panel.config.mqtt.qos")}
.value=${this.qos}
@selected=${this._handleQos}
>${qosLevel.map(
(qos) =>
html`<mwc-list-item .value=${qos}>${qos}</mwc-list-item>`
)}
</ha-select>
<p>${this.hass.localize("ui.panel.config.mqtt.payload")}</p>
<ha-code-editor
@ -95,6 +111,14 @@ class HaPanelDevMqtt extends LitElement {
}
}
private _handleQos(ev: CustomEvent) {
const newValue = (ev.target! as any).value;
if (newValue >= 0 && newValue !== this.qos && localStorage && this.inited) {
this.qos = newValue;
localStorage["panel-dev-mqtt-qos"] = this.qos;
}
}
private _publish(): void {
if (!this.hass) {
return;
@ -102,6 +126,7 @@ class HaPanelDevMqtt extends LitElement {
this.hass.callService("mqtt", "publish", {
topic: this.topic,
payload_template: this.payload,
qos: parseInt(this.qos),
});
}

View File

@ -129,7 +129,7 @@ class HuiEnergyCarbonGaugeCard
min="0"
max="100"
.value=${value}
.locale=${this.hass!.locale}
.locale=${this.hass.locale}
label="%"
style=${styleMap({
"--gauge-color": this._computeSeverity(value),

View File

@ -108,7 +108,7 @@ class HuiEnergySolarGaugeCard
min="0"
max="100"
.value=${value}
.locale=${this.hass!.locale}
.locale=${this.hass.locale}
label="%"
style=${styleMap({
"--gauge-color": this._computeSeverity(value),

View File

@ -269,12 +269,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
flex-direction: column;
align-items: center;
box-sizing: border-box;
--alarm-color-disarmed: var(--label-badge-green);
--alarm-color-pending: var(--label-badge-yellow);
--alarm-color-triggered: var(--label-badge-red);
--alarm-color-armed: var(--label-badge-red);
--alarm-color-autoarm: rgba(0, 153, 255, 0.1);
--alarm-state-color: var(--alarm-color-armed);
--alarm-state-color: rgb(var(--rgb-state-alarm-armed-color));
}
ha-chip {
@ -292,25 +287,25 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
}
.unavailable {
--alarm-state-color: var(--state-unavailable-color);
--alarm-state-color: rgb(var(--rgb-state-unavailable-color));
}
.disarmed {
--alarm-state-color: var(--alarm-color-disarmed);
--alarm-state-color: rgb(var(--rgb-state-alarm-disarmed-color));
}
.triggered {
--alarm-state-color: var(--alarm-color-triggered);
--alarm-state-color: rgb(var(--rgb-state-alarm-trigger-color));
animation: pulse 1s infinite;
}
.arming {
--alarm-state-color: var(--alarm-color-pending);
--alarm-state-color: rgb(var(--rgb-state-alarm-arming-color));
animation: pulse 1s infinite;
}
.pending {
--alarm-state-color: var(--alarm-color-pending);
--alarm-state-color: rgb(var(--rgb-state-alarm-pending-color));
animation: pulse 1s infinite;
}

View File

@ -26,7 +26,7 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateActive } from "../../../common/entity/state_active";
import { stateColor } from "../../../common/entity/state_color";
import { stateColorCss } from "../../../common/entity/state_color";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { iconColorCSS } from "../../../common/style/icon_color_css";
import "../../../components/ha-card";
@ -79,6 +79,15 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
@state() private _shouldRenderRipple = false;
private getStateColor(stateObj: HassEntity, config: ButtonCardConfig) {
const domain = stateObj ? computeStateDomain(stateObj) : undefined;
return (
config &&
(config.state_color ||
(domain === "light" && config.state_color !== false))
);
}
public getCardSize(): number {
return (
(this._config?.show_icon ? 4 : 0) + (this._config?.show_name ? 1 : 0)
@ -146,13 +155,9 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
const name = this._config.show_name
? this._config.name || (stateObj ? computeStateName(stateObj) : "")
: "";
const domain = stateObj ? computeStateDomain(stateObj) : undefined;
const active =
(this._config.state_color ||
(domain === "light" && this._config.state_color !== false)) &&
stateObj &&
stateActive(stateObj);
const active = stateObj && stateActive(stateObj);
const colored = active && this.getStateColor(stateObj, this._config);
return html`
<ha-card
@ -187,9 +192,8 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
.icon=${this._config.icon}
.state=${stateObj}
style=${styleMap({
color: stateObj && active ? this._computeColor(stateObj) : "",
filter:
stateObj && active ? this._computeBrightness(stateObj) : "",
color: colored ? this._computeColor(stateObj) : "",
filter: colored ? this._computeBrightness(stateObj) : "",
height: this._config.icon_height
? this._config.icon_height
: "",
@ -305,22 +309,24 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
}
private _computeBrightness(stateObj: HassEntity | LightEntity): string {
if (!stateObj.attributes.brightness) {
if (!stateObj.attributes.brightness && stateActive(stateObj)) {
const brightness = stateObj.attributes.brightness;
return `brightness(${(brightness + 245) / 5}%)`;
}
return "";
}
private _computeColor(stateObj: HassEntity | LightEntity): string {
if (stateObj.attributes.rgb_color) {
private _computeColor(
stateObj: HassEntity | LightEntity
): string | undefined {
if (stateObj.attributes.rgb_color && stateActive(stateObj)) {
return `rgb(${stateObj.attributes.rgb_color.join(",")})`;
}
const iconColor = stateColor(stateObj);
const iconColor = stateColorCss(stateObj);
if (iconColor) {
return `rgb(var(--rgb-state-${iconColor}-color))`;
return `rgb(${iconColor})`;
}
return "";
return undefined;
}
private _handleAction(ev: ActionHandlerEvent) {

View File

@ -66,6 +66,8 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
@state() private _calendars: Calendar[] = [];
@state() private _eventDisplay = "list-item";
@state() private _narrow = false;
@state() private _veryNarrow = false;
@ -134,6 +136,7 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
.hass=${this.hass}
.views=${views}
.initialView=${this._config.initial_view!}
.eventDisplay=${this._eventDisplay}
.error=${this._error}
@view-changed=${this._handleViewChanged}
></ha-full-calendar>
@ -163,6 +166,8 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
}
private _handleViewChanged(ev: HASSDomEvent<CalendarViewChanged>): void {
this._eventDisplay =
ev.detail.view === "dayGridMonth" ? "list-item" : "auto";
this._startDate = ev.detail.start;
this._endDate = ev.detail.end;
this._fetchCalendarEvents();

View File

@ -16,7 +16,7 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateActive } from "../../../common/entity/state_active";
import { stateColor } from "../../../common/entity/state_color";
import { stateColorCss } from "../../../common/entity/state_color";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import {
formatNumber,
@ -76,6 +76,15 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
private _footerElement?: HuiErrorCard | LovelaceHeaderFooter;
private getStateColor(stateObj: HassEntity, config: EntityCardConfig) {
const domain = stateObj ? computeStateDomain(stateObj) : undefined;
return (
config &&
(config.state_color ||
(domain === "light" && config.state_color !== false))
);
}
public setConfig(config: EntityCardConfig): void {
if (!config.entity) {
throw new Error("Entity must be specified");
@ -124,10 +133,8 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
const name = this._config.name || computeStateName(stateObj);
const active =
(this._config.state_color ||
(domain === "light" && this._config.state_color !== false)) &&
stateActive(stateObj);
const active = stateObj && stateActive(stateObj);
const colored = active && this.getStateColor(stateObj, this._config);
return html`
<ha-card @click=${this._handleClick} tabindex="0">
@ -141,7 +148,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
data-domain=${ifDefined(domain)}
data-state=${stateObj.state}
style=${styleMap({
color: active ? this._computeColor(stateObj) : "",
color: colored ? this._computeColor(stateObj) : undefined,
height: this._config.icon_height
? this._config.icon_height
: "",
@ -186,22 +193,14 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
`;
}
private _computeColor(stateObj: HassEntity | LightEntity): string {
const domain = computeStateDomain(stateObj);
if (
!(
this._config?.state_color ||
(domain === "light" && this._config?.state_color !== false)
) ||
!stateActive(stateObj)
) {
return "";
}
const iconColor = stateColor(stateObj);
private _computeColor(
stateObj: HassEntity | LightEntity
): string | undefined {
const iconColor = stateColorCss(stateObj);
if (iconColor) {
return `rgb(var(--rgb-state-${iconColor}-color))`;
return `rgb(${iconColor})`;
}
return "";
return undefined;
}
protected shouldUpdate(changedProps: PropertyValues): boolean {

View File

@ -1,5 +1,5 @@
import { memoize } from "@fullcalendar/common";
import { mdiHelp } from "@mdi/js";
import { mdiExclamationThick, mdiHelp } from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
@ -9,7 +9,6 @@ import { hsv2rgb, rgb2hsv } from "../../../common/color/convert-color";
import { DOMAINS_TOGGLE } from "../../../common/const";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
import { stateActive } from "../../../common/entity/state_active";
import { stateColorCss } from "../../../common/entity/state_color";
import { stateIconPath } from "../../../common/entity/state_icon_path";
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
@ -129,8 +128,9 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
}
private _computeStateColor = memoize((entity: HassEntity, color?: string) => {
if (UNAVAILABLE_STATES.includes(entity.state)) {
return undefined;
// Use custom color
if (color) {
return computeRgbColor(color);
}
// Use default color for person/device_tracker because color is on the badge
@ -141,16 +141,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
return "var(--rgb-state-default-color)";
}
if (!stateActive(entity)) {
return undefined;
}
if (color) {
return computeRgbColor(color);
}
let stateColor = stateColorCss(entity);
// Use light color if the light support rgb
if (
computeDomain(entity.entity_id) === "light" &&
entity.attributes.rgb_color
@ -166,10 +157,11 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
hsvColor[1] = 0.4;
}
}
stateColor = hsv2rgb(hsvColor).join(",");
return hsv2rgb(hsvColor).join(",");
}
return stateColor;
// Fallback to state color
return stateColorCss(entity) ?? "var(--rgb-state-default-color)";
});
private _computeStateDisplay(stateObj: HassEntity): TemplateResult | string {
@ -233,10 +225,21 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
<ha-card class="disabled">
<ha-card
style=${styleMap({
"--tile-color": `var(--rgb-disabled-color)`,
})}
>
<div class="tile">
<div class="icon-container">
<ha-tile-icon .iconPath=${mdiHelp}></ha-tile-icon>
<ha-tile-icon class="icon" .iconPath=${mdiHelp}></ha-tile-icon>
<ha-tile-badge
class="badge"
.iconPath=${mdiExclamationThick}
style=${styleMap({
"--tile-badge-background-color": `rgb(var(--rgb-red-color))`,
})}
></ha-tile-badge>
</div>
<ha-tile-info
.primary=${entityId}
@ -360,16 +363,13 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
static get styles(): CSSResultGroup {
return css`
:host {
--tile-color: var(--rgb-disabled-color);
--tile-color: var(--rgb-state-default-color);
--tile-tap-padding: 6px;
-webkit-tap-highlight-color: transparent;
}
ha-card {
height: 100%;
}
ha-card.disabled {
background: rgba(var(--rgb-disabled-color), 0.1);
}
[role="button"] {
cursor: pointer;
}

View File

@ -22,11 +22,11 @@ function personBadgeIcon(entity: HassEntity) {
function personBadgeColor(entity: HassEntity) {
switch (entity.state) {
case "home":
return "var(--rgb-badge-person-home-color)";
return "var(--rgb-state-person-home-color)";
case "not_home":
return "var(--rgb-badge-person-not-home-color)";
return "var(--rgb-state-person-not-home-color)";
default:
return "var(--rgb-badge-person-zone-color)";
return "var(--rgb-state-person-zone-color)";
}
}

View File

@ -491,9 +491,15 @@ export const generateDefaultViewConfig = (
const areaCards: LovelaceCardConfig[] = [];
for (const [areaId, areaEntities] of Object.entries(
const sortedAreas = Object.entries(
splittedByAreaDevice.areasWithEntities
)) {
).sort((a, b) => {
const areaA = areaEntries[a[0]];
const areaB = areaEntries[b[0]];
return stringCompare(areaA.name, areaB.name);
});
for (const [areaId, areaEntities] of sortedAreas) {
const area = areaEntries[areaId];
areaCards.push(
...computeCards(
@ -506,13 +512,20 @@ export const generateDefaultViewConfig = (
);
}
areaCards.sort((a, b) => stringCompare(a.title || "", b.title || ""));
const deviceCards: LovelaceCardConfig[] = [];
for (const [deviceId, deviceEntities] of Object.entries(
const sortedDevices = Object.entries(
splittedByAreaDevice.devicesWithEntities
)) {
).sort((a, b) => {
const deviceA = deviceEntries[a[0]];
const deviceB = deviceEntries[b[0]];
return stringCompare(
deviceA.name_by_user || deviceA.name || "",
deviceB.name_by_user || deviceB.name || ""
);
});
for (const [deviceId, deviceEntities] of sortedDevices) {
const device = deviceEntries[deviceId];
deviceCards.push(
...computeCards(
@ -534,8 +547,6 @@ export const generateDefaultViewConfig = (
);
}
deviceCards.sort((a, b) => stringCompare(a.title || "", b.title || ""));
let energyCard: LovelaceCardConfig | undefined;
if (energyPrefs) {

View File

@ -93,7 +93,7 @@ export class HuiGaugeCardEditor
...(showSeverity
? ([
{
name: "",
name: "severity",
type: "grid",
schema: [
{

View File

@ -86,15 +86,17 @@ class HuiCoverOpenCloseTileFeature
`
: null}
${supportsFeature(this.stateObj, CoverEntityFeature.STOP)
? html`<ha-tile-button
.label=${this.hass.localize(
"ui.dialogs.more_info_control.cover.stop_cover"
)}
@click=${this._onStopTap}
.disabled=${!canStop(this.stateObj)}
>
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
</ha-tile-button> `
? html`
<ha-tile-button
.label=${this.hass.localize(
"ui.dialogs.more_info_control.cover.stop_cover"
)}
@click=${this._onStopTap}
.disabled=${!canStop(this.stateObj)}
>
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
</ha-tile-button>
`
: null}
${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE)
? html`

View File

@ -80,15 +80,17 @@ class HuiCoverTiltTileFeature
`
: null}
${supportsFeature(this.stateObj, CoverEntityFeature.STOP_TILT)
? html`<ha-tile-button
.label=${this.hass.localize(
"ui.dialogs.more_info_control.cover.stop_cover"
)}
@click=${this._onStopTap}
.disabled=${!canStopTilt(this.stateObj)}
>
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
</ha-tile-button> `
? html`
<ha-tile-button
.label=${this.hass.localize(
"ui.dialogs.more_info_control.cover.stop_cover"
)}
@click=${this._onStopTap}
.disabled=${!canStopTilt(this.stateObj)}
>
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
</ha-tile-button>
`
: null}
${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE_TILT)
? html`

View File

@ -40,7 +40,7 @@ export const VACUUM_COMMANDS_FEATURES: Record<
VacuumCommand,
VacuumEntityFeature[]
> = {
start_pause: [VacuumEntityFeature.PAUSE],
start_pause: [VacuumEntityFeature.PAUSE, VacuumEntityFeature.START],
stop: [VacuumEntityFeature.STOP],
clean_spot: [VacuumEntityFeature.CLEAN_SPOT],
locate: [VacuumEntityFeature.LOCATE],

View File

@ -13,7 +13,7 @@ class HaPickDashboardRow extends LitElement {
@property() public narrow!: boolean;
@state() private _dashboards: LovelaceDashboard[] = [];
@state() private _dashboards?: LovelaceDashboard[];
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
@ -29,30 +29,37 @@ class HaPickDashboardRow extends LitElement {
<span slot="description">
${this.hass.localize("ui.panel.profile.dashboard.description")}
</span>
<ha-select
.label=${this.hass.localize(
"ui.panel.profile.dashboard.dropdown_label"
)}
.disabled=${!this._dashboards.length}
.value=${this.hass.defaultPanel}
@selected=${this._dashboardChanged}
>
<mwc-list-item value="lovelace">
${this.hass.localize(
"ui.panel.profile.dashboard.default_dashboard_label"
)}
</mwc-list-item>
${this._dashboards.map((dashboard) => {
if (!this.hass.user!.is_admin && dashboard.require_admin) {
return "";
}
return html`
<mwc-list-item .value=${dashboard.url_path}>
${dashboard.title}
${this._dashboards
? html`<ha-select
.label=${this.hass.localize(
"ui.panel.profile.dashboard.dropdown_label"
)}
.disabled=${!this._dashboards?.length}
.value=${this.hass.defaultPanel}
@selected=${this._dashboardChanged}
>
<mwc-list-item value="lovelace">
${this.hass.localize(
"ui.panel.profile.dashboard.default_dashboard_label"
)}
</mwc-list-item>
`;
})}
</ha-select>
${this._dashboards.map((dashboard) => {
if (!this.hass.user!.is_admin && dashboard.require_admin) {
return "";
}
return html`
<mwc-list-item .value=${dashboard.url_path}>
${dashboard.title}
</mwc-list-item>
`;
})}
</ha-select>`
: html`<ha-select
.label=${this.hass.localize(
"ui.panel.profile.dashboard.dropdown_label"
)}
disabled
></ha-select>`}
</ha-settings-row>
`;
}

View File

@ -194,6 +194,10 @@ export class HaPickThemeRow extends LitElement {
private _handleThemeSelection(ev) {
const theme = ev.target.value;
if (theme === this.hass.selectedTheme?.theme) {
return;
}
if (theme === "Backend-selected") {
if (this.hass.selectedTheme?.theme) {
fireEvent(this, "settheme", {

View File

@ -134,24 +134,29 @@ documentContainer.innerHTML = `<custom-style>
--rgb-white-color: 255, 255, 255;
/* rgb state color */
--rgb-state-default-color: 68, 115, 158;
--rgb-state-alarm-armed-color: var(--rgb-red-color);
--rgb-state-default-color: var(--rgb-dark-primary-color, 68, 115, 158);
--rgb-state-inactive-color: var(--rgb-grey-color);
--rgb-state-unavailable-color: var(--rgb-disabled-color);
/* rgb state domain colors */
--rgb-state-alarm-armed-color: var(--rgb-green-color);
--rgb-state-alarm-arming-color: var(--rgb-orange-color);
--rgb-state-alarm-disarmed-color: var(--rgb-grey-color);
--rgb-state-alarm-pending-color: var(--rgb-orange-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-alerting-color: var(--rgb-red-color);
--rgb-state-binary-sensor-color: var(--rgb-blue-color);
--rgb-state-calendar-color: var(--rgb-blue-color);
--rgb-state-camera-color: var(--rgb-blue-color);
--rgb-state-binary-sensor-color: var(--rgb-amber-color);
--rgb-state-calendar-color: var(--rgb-amber-color);
--rgb-state-camera-color: var(--rgb-amber-color);
--rgb-state-climate-auto-color: var(--rgb-green-color);
--rgb-state-climate-cool-color: var(--rgb-blue-color);
--rgb-state-climate-dry-color: var(--rgb-orange-color);
--rgb-state-climate-fan-only-color: var(--rgb-cyan-color);
--rgb-state-climate-heat-color: var(--rgb-deep-orange-color);
--rgb-state-climate-heat-cool-color: var(--rgb-amber-color);
--rgb-state-climate-idle-color: var(--rgb-disabled-color);
--rgb-state-climate-idle-color: var(--rgb-off-color);
--rgb-state-cover-color: var(--rgb-purple-color);
--rgb-state-fan-color: var(--rgb-cyan-color);
--rgb-state-group-color: var(--rgb-amber-color);
@ -159,17 +164,19 @@ documentContainer.innerHTML = `<custom-style>
--rgb-state-input-boolean-color: var(--rgb-amber-color);
--rgb-state-light-color: var(--rgb-amber-color);
--rgb-state-lock-jammed-color: var(--rgb-red-color);
--rgb-state-lock-locked-color: var(--rgb-red-color);
--rgb-state-lock-locked-color: var(--rgb-green-color);
--rgb-state-lock-pending-color: var(--rgb-orange-color);
--rgb-state-media-player-color: var(--rgb-indigo-color);
--rgb-state-lock-unlocked-color: var(--rgb-red-color);
--rgb-state-media-player-color: var(--rgb-light-blue-color);
--rgb-state-person-home-color: var(--rgb-green-color);
--rgb-state-person-not-home-color: var(--rgb-grey-color);
--rgb-state-person-zone-color: var(--rgb-blue-color);
--rgb-state-remote-color: var(--rgb-blue-color);
--rgb-state-remote-color: var(--rgb-amber-color);
--rgb-state-script-color: var(--rgb-amber-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-medium-color: var(--rgb-orange-color);
--rgb-state-sensor-battery-unknown-color: var(--rgb-disabled-color);
--rgb-state-sensor-battery-unknown-color: var(--rgb-off-color);
--rgb-state-siren-color: var(--rgb-red-color);
--rgb-state-sun-day-color: var(--rgb-amber-color);
--rgb-state-sun-night-color: var(--rgb-deep-purple-color);
@ -179,11 +186,6 @@ documentContainer.innerHTML = `<custom-style>
--rgb-state-update-installing-color: var(--rgb-orange-color);
--rgb-state-vacuum-color: var(--rgb-teal-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-idle-line-color: rgba(0, 0, 0, 0.42);
--input-hover-line-color: rgba(0, 0, 0, 0.87);

View File

@ -48,7 +48,7 @@ export const darkStyles = {
"energy-grid-return-color": "#a280db",
"map-filter":
"invert(.9) hue-rotate(170deg) brightness(1.5) contrast(1.2) saturate(.3)",
"rgb-disabled-color": "111, 111, 111",
"rgb-disabled-color": "70, 70, 70",
};
export const derivedStyles = {

View File

@ -3233,7 +3233,8 @@
"subscribe_to": "Topic to subscribe to",
"start_listening": "Start listening",
"stop_listening": "Stop listening",
"message_received": "Message {id} received on {topic} at {time}:"
"message_received": "Message {id} received on {topic} at {time}:",
"qos": "QoS"
},
"zha": {
"common": {
@ -4349,6 +4350,7 @@
"primary": "Primary",
"accent": "Accent",
"disabled": "Disabled",
"inactive": "Inactive",
"red": "Red",
"pink": "Pink",
"purple": "Purple",