Compare commits

...

1 Commits

Author SHA1 Message Date
Paul Bottein 2aa1c99117 Distinguish unknown from unavailable entity state 2026-05-18 12:52:38 +02:00
51 changed files with 207 additions and 185 deletions
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { isUnavailableState } from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import type { HomeAssistant } from "../../types";
interface EntityUnitStubConfig {
@@ -21,32 +21,24 @@ export const computeEntityUnitDisplay = (
stateObj: HassEntity | undefined,
config: EntityUnitStubConfig
): string => {
let unit;
if (
stateObj &&
!isUnavailableState(stateObj.state) &&
(config.attribute || stateObj.attributes.device_class !== "duration")
!stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN ||
(!config.attribute && stateObj.attributes.device_class === "duration")
) {
// check for an explicitly defined unit in config
unit = config.unit;
if (!unit) {
if (!config.attribute) {
// use entity's unit_of_measurement
const stateParts = hass.formatEntityStateToParts(stateObj);
unit = stateParts.find((part) => part.type === "unit")?.value;
} else {
// use attribute's unit if available
const attrParts = hass.formatEntityAttributeValueToParts(
stateObj,
config.attribute
);
unit = attrParts.find((part) => part.type === "unit")?.value;
}
}
return unit ?? "";
return "";
}
return "";
// check for an explicitly defined unit in config
if (config.unit) {
return config.unit;
}
// otherwise derive from the entity's state or attribute
const parts = config.attribute
? hass.formatEntityAttributeValueToParts(stateObj, config.attribute)
: hass.formatEntityStateToParts(stateObj);
return parts.find((part) => part.type === "unit")?.value ?? "";
};
+2 -2
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE_STATES } from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import type { HomeAssistant } from "../../types";
import { stringCompare } from "../string/compare";
import { computeDomain } from "./compute_domain";
@@ -253,7 +253,7 @@ export const getStatesDomain = (
if (!attribute) {
// All entities can have unavailable states
result.push(...UNAVAILABLE_STATES);
result.push(UNAVAILABLE, UNKNOWN);
}
if (!attribute && domain in FIXED_DOMAIN_STATES) {
+11 -5
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { isUnavailableState, UNAVAILABLE } from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import type { HomeAssistant } from "../../types";
import { computeStateDomain } from "./compute_state_domain";
@@ -8,14 +8,20 @@ export const computeGroupEntitiesState = (states: HassEntity[]): string => {
return UNAVAILABLE;
}
const validState = states.some(
(stateObj) => !isUnavailableState(stateObj.state)
const allUnavailable = states.every(
(stateObj) => stateObj.state === UNAVAILABLE
);
if (!validState) {
if (allUnavailable) {
return UNAVAILABLE;
}
const hasValidState = states.some(
(stateObj) => stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN
);
if (!hasValidState) {
return UNKNOWN;
}
// Use the first state to determine the domain
// This assumes all states in the group have the same domain
const domain = computeStateDomain(states[0]);
+2 -2
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { isUnavailableState, OFF, UNAVAILABLE } from "../../data/entity/entity";
import { OFF, UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { computeDomain } from "./compute_domain";
export function stateActive(stateObj: HassEntity, state?: string): boolean {
@@ -19,7 +19,7 @@ export function stateActive(stateObj: HassEntity, state?: string): boolean {
return compareState !== UNAVAILABLE;
}
if (isUnavailableState(compareState)) {
if (compareState === UNAVAILABLE || compareState === UNKNOWN) {
return false;
}
+3 -6
View File
@@ -6,11 +6,7 @@ import { customElement, property, state } from "lit/decorators";
import { STATES_OFF } from "../../common/const";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import {
UNAVAILABLE,
UNKNOWN,
isUnavailableState,
} from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { forwardHaptic } from "../../data/haptics";
import type { HomeAssistant } from "../../types";
import "../ha-formfield";
@@ -20,7 +16,8 @@ import "../ha-switch";
const isOn = (stateObj?: HassEntity) =>
stateObj !== undefined &&
!STATES_OFF.includes(stateObj.state) &&
!isUnavailableState(stateObj.state);
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN;
/**
* @element ha-entity-toggle
@@ -9,7 +9,7 @@ import secondsToDuration from "../../common/datetime/seconds_to_duration";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { FIXED_DOMAIN_STATES } from "../../common/entity/get_states";
import { isUnavailableState, UNAVAILABLE } from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import type { EntityRegistryDisplayEntry } from "../../data/entity/entity_registry";
import { timerTimeRemaining } from "../../data/timer";
import type { HomeAssistant } from "../../types";
@@ -170,7 +170,8 @@ export class HaStateLabelBadge extends LitElement {
}
// eslint-disable-next-line: disable=no-fallthrough
default:
return isUnavailableState(entityState.state)
return entityState.state === UNAVAILABLE ||
entityState.state === UNKNOWN
? "—"
: this.hass!.formatEntityStateToParts(entityState).find(
(part) => part.type === "value"
@@ -209,7 +210,7 @@ export class HaStateLabelBadge extends LitElement {
_timerTimeRemaining = 0
) {
// For unavailable states or certain domains, use a special translation that is truncated to fit within the badge label
if (isUnavailableState(entityState.state)) {
if (entityState.state === UNAVAILABLE || entityState.state === UNKNOWN) {
return this.hass!.localize(`state_badge.default.${entityState.state}`);
}
const domainStateKey = getTruncatedKey(domain, entityState.state);
+9 -4
View File
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import type { ClimateEntity } from "../data/climate";
import { CLIMATE_PRESET_NONE } from "../data/climate";
import { isUnavailableState, OFF } from "../data/entity/entity";
import { OFF, UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import type { HomeAssistant } from "../types";
@customElement("ha-climate-state")
@@ -14,9 +14,11 @@ class HaClimateState extends LitElement {
protected render(): TemplateResult {
const currentStatus = this._computeCurrentStatus();
const noValue =
this.stateObj.state === UNAVAILABLE || this.stateObj.state === UNKNOWN;
return html`<div class="target">
${!isUnavailableState(this.stateObj.state)
${!noValue
? html`<span class="state-label">
${this._localizeState()}
${this.stateObj.attributes.preset_mode &&
@@ -32,7 +34,7 @@ class HaClimateState extends LitElement {
: this._localizeState()}
</div>
${currentStatus && !isUnavailableState(this.stateObj.state)
${currentStatus && !noValue
? html`
<div class="current">
${this.hass.localize("ui.card.climate.currently")}:
@@ -119,7 +121,10 @@ class HaClimateState extends LitElement {
}
private _localizeState(): string {
if (isUnavailableState(this.stateObj.state)) {
if (
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
) {
return this.hass.localize(`state.default.${this.stateObj.state}`);
}
+9 -4
View File
@@ -1,7 +1,7 @@
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { isUnavailableState, OFF } from "../data/entity/entity";
import { OFF, UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import type { HumidifierEntity } from "../data/humidifier";
import type { HomeAssistant } from "../types";
@@ -13,9 +13,11 @@ class HaHumidifierState extends LitElement {
protected render(): TemplateResult {
const currentStatus = this._computeCurrentStatus();
const noValue =
this.stateObj.state === UNAVAILABLE || this.stateObj.state === UNKNOWN;
return html`<div class="target">
${!isUnavailableState(this.stateObj.state)
${!noValue
? html`<span class="state-label">
${this._localizeState()}
${this.stateObj.attributes.mode
@@ -30,7 +32,7 @@ class HaHumidifierState extends LitElement {
: this._localizeState()}
</div>
${currentStatus && !isUnavailableState(this.stateObj.state)
${currentStatus && !noValue
? html`<div class="current">
${this.hass.localize("ui.card.humidifier.currently")}:
<div class="unit">${currentStatus}</div>
@@ -69,7 +71,10 @@ class HaHumidifierState extends LitElement {
}
private _localizeState(): string {
if (isUnavailableState(this.stateObj.state)) {
if (
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
) {
return this.hass.localize(`state.default.${this.stateObj.state}`);
}
@@ -17,7 +17,7 @@ import { until } from "lit/directives/until";
import { fireEvent } from "../../common/dom/fire_event";
import { slugify } from "../../common/string/slugify";
import { debounce } from "../../common/util/debounce";
import { isUnavailableState } from "../../data/entity/entity";
import { UNAVAILABLE } from "../../data/entity/entity";
import type {
MediaPickedEvent,
MediaPlayerBrowseAction,
@@ -290,7 +290,7 @@ export class HaMediaPlayerBrowse extends LitElement {
} else if (
err.code === "entity_not_found" &&
this.entityId &&
isUnavailableState(this.hass.states[this.entityId]?.state)
this.hass.states[this.entityId]?.state === UNAVAILABLE
) {
this._setError({
message: this.hass.localize(
+2 -2
View File
@@ -6,7 +6,7 @@ import { getColorByIndex } from "../common/color/colors";
import { computeDomain } from "../common/entity/compute_domain";
import { computeStateName } from "../common/entity/compute_state_name";
import type { HomeAssistant } from "../types";
import { isUnavailableState } from "./entity/entity";
import { UNAVAILABLE } from "./entity/entity";
import type { EntityRegistryEntry } from "./entity/entity_registry";
export interface Calendar {
@@ -120,7 +120,7 @@ export const getCalendars = (
.filter(
(eid) =>
computeDomain(eid) === "calendar" &&
!isUnavailableState(hass.states[eid].state) &&
hass.states[eid].state !== UNAVAILABLE &&
hass.entities[eid]?.hidden !== true
)
.sort()
-2
View File
@@ -6,10 +6,8 @@ export const UNKNOWN = "unknown";
export const ON = "on";
export const OFF = "off";
export const UNAVAILABLE_STATES = [UNAVAILABLE, UNKNOWN] as const;
export const OFF_STATES = [UNAVAILABLE, UNKNOWN, OFF] as const;
export const isUnavailableState = arrayLiteralIncludes(UNAVAILABLE_STATES);
export const isOffState = arrayLiteralIncludes(OFF_STATES);
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
+2 -2
View File
@@ -2,7 +2,7 @@ import { computeDomain } from "../common/entity/compute_domain";
import { computeStateName } from "../common/entity/compute_state_name";
import { stringCompare } from "../common/string/compare";
import type { HomeAssistant, ServiceCallResponse } from "../types";
import { isUnavailableState } from "./entity/entity";
import { UNAVAILABLE } from "./entity/entity";
export interface TodoList {
entity_id: string;
@@ -49,7 +49,7 @@ export const getTodoLists = (
.filter(
(entityId) =>
computeDomain(entityId) === "todo" &&
!isUnavailableState(hass.states[entityId].state) &&
hass.states[entityId].state !== UNAVAILABLE &&
(includeHidden || hass.entities[entityId]?.hidden !== true)
)
.map((entityId) => ({
@@ -18,7 +18,7 @@ import "../../../components/ha-slider";
import "../../../components/ha-time-input";
import "../../../components/input/ha-input";
import { isTiltOnly } from "../../../data/cover";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ImageEntity } from "../../../data/image";
import { computeImageUrl } from "../../../data/image";
import "../../../panels/lovelace/components/hui-timestamp-display";
@@ -108,14 +108,13 @@ class EntityPreviewRow extends LitElement {
private _renderEntityState(stateObj: HassEntity): TemplateResult | string {
const domain = stateObj.entity_id.split(".", 1)[0];
const disabled = stateObj.state === UNAVAILABLE;
const noValue =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
if (domain === "button") {
return html`
<ha-button
appearance="plain"
size="small"
.disabled=${isUnavailableState(stateObj.state)}
>
<ha-button appearance="plain" size="small" .disabled=${disabled}>
${this.hass.localize("ui.card.button.press")}
</ha-button>
`;
@@ -151,19 +150,15 @@ class EntityPreviewRow extends LitElement {
return html`
<ha-date-input
.locale=${this.hass.locale}
.disabled=${isUnavailableState(stateObj.state)}
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
.disabled=${disabled}
.value=${noValue ? undefined : stateObj.state}
>
</ha-date-input>
`;
}
if (domain === "datetime") {
const dateObj = isUnavailableState(stateObj.state)
? undefined
: new Date(stateObj.state);
const dateObj = noValue ? undefined : new Date(stateObj.state);
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
return html`
@@ -172,12 +167,12 @@ class EntityPreviewRow extends LitElement {
.label=${computeStateName(stateObj)}
.locale=${this.hass.locale}
.value=${date}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
>
</ha-date-input>
<ha-time-input
.value=${time}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
.locale=${this.hass.locale}
></ha-time-input>
</div>
@@ -187,7 +182,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "event") {
return html`
<div class="when">
${isUnavailableState(stateObj.state)
${noValue
? this.hass.formatEntityState(stateObj)
: html`<hui-timestamp-display
.hass=${this.hass}
@@ -196,7 +191,7 @@ class EntityPreviewRow extends LitElement {
></hui-timestamp-display>`}
</div>
<div class="what">
${isUnavailableState(stateObj.state)
${noValue
? nothing
: this.hass.formatEntityAttributeValue(stateObj, "event_type")}
</div>
@@ -206,9 +201,7 @@ class EntityPreviewRow extends LitElement {
const toggleDomains = ["fan", "light", "remote", "siren", "switch"];
if (toggleDomains.includes(domain)) {
const showToggle =
stateObj.state === "on" ||
stateObj.state === "off" ||
isUnavailableState(stateObj.state);
stateObj.state === "on" || stateObj.state === "off" || noValue;
return html`
${showToggle
? html`
@@ -241,7 +234,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "lock") {
return html`
<ha-button
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
class="text-content"
appearance="plain"
size="small"
@@ -266,7 +259,7 @@ class EntityPreviewRow extends LitElement {
<div class="numberflex">
<ha-slider
labeled
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${disabled}
.step=${Number(stateObj.attributes.step)}
.min=${Number(stateObj.attributes.min)}
.max=${Number(stateObj.attributes.max)}
@@ -280,7 +273,7 @@ class EntityPreviewRow extends LitElement {
: html`<div class="numberflex numberstate">
<ha-input
auto-validate
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${disabled}
pattern="[0-9]+([\\.][0-9]+)?"
.step=${Number(stateObj.attributes.step)}
.min=${Number(stateObj.attributes.min)}
@@ -303,7 +296,7 @@ class EntityPreviewRow extends LitElement {
<ha-select
.label=${computeStateName(stateObj)}
.value=${stateObj.state}
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${disabled}
.options=${stateObj.attributes.options?.map((option) => ({
value: option,
label: this.hass!.formatEntityState(stateObj, option),
@@ -317,7 +310,7 @@ class EntityPreviewRow extends LitElement {
const showSensor =
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
stateObj.attributes.device_class
) && !isUnavailableState(stateObj.state);
) && !noValue;
return html`
${showSensor
? html`
@@ -339,7 +332,7 @@ class EntityPreviewRow extends LitElement {
return html`
<ha-input
.label=${computeStateName(stateObj)}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
.value=${stateObj.state}
.minlength=${stateObj.attributes.min}
.maxlength=${stateObj.attributes.max}
@@ -354,11 +347,9 @@ class EntityPreviewRow extends LitElement {
if (domain === "time") {
return html`
<ha-time-input
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
.value=${noValue ? undefined : stateObj.state}
.locale=${this.hass.locale}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
></ha-time-input>
`;
}
@@ -366,7 +357,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "weather") {
return html`
<div>
${isUnavailableState(stateObj.state) ||
${noValue ||
stateObj.attributes.temperature === undefined ||
stateObj.attributes.temperature === null
? this.hass.formatEntityState(stateObj)
@@ -3,7 +3,7 @@ import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-absolute-time";
import "../../../components/ha-relative-time";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { LightEntity } from "../../../data/light";
import { SENSOR_DEVICE_CLASS_TIMESTAMP } from "../../../data/sensor";
import "../../../panels/lovelace/components/hui-timestamp-display";
@@ -24,7 +24,8 @@ export class HaMoreInfoStateHeader extends LitElement {
private _localizeState(): TemplateResult | string {
if (
this.stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP &&
!isUnavailableState(this.stateObj.state)
this.stateObj.state !== UNAVAILABLE &&
this.stateObj.state !== UNKNOWN
) {
return html`
<hui-timestamp-display
@@ -4,7 +4,7 @@ import { customElement, property } from "lit/decorators";
import "../../../components/ha-button";
import "../../../components/ha-relative-time";
import { triggerAutomationActions } from "../../../data/automation";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
@customElement("more-info-automation")
@@ -34,7 +34,7 @@ class MoreInfoAutomation extends LitElement {
appearance="plain"
size="small"
@click=${this._runActions}
.disabled=${isUnavailableState(this.stateObj!.state)}
.disabled=${this.stateObj!.state === UNAVAILABLE}
>
${this.hass.localize("ui.card.automation.trigger")}
</ha-button>
@@ -2,7 +2,7 @@ import type { HassEntity } from "home-assistant-js-websocket";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../components/ha-button";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
@customElement("more-info-counter")
@@ -16,7 +16,7 @@ class MoreInfoCounter extends LitElement {
return nothing;
}
const disabled = isUnavailableState(this.stateObj.state);
const disabled = this.stateObj.state === UNAVAILABLE;
return html`
<div class="actions">
@@ -4,7 +4,7 @@ import { customElement, property } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { setDateValue } from "../../../data/date";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@customElement("more-info-date")
@@ -21,10 +21,9 @@ class MoreInfoDate extends LitElement {
return html`
<ha-date-input
.locale=${this.hass.locale}
.value=${isUnavailableState(this.stateObj.state)
.value=${this.stateObj.state === UNKNOWN
? undefined
: this.stateObj.state}
.disabled=${this.stateObj.state === UNAVAILABLE}
@value-changed=${this._dateChanged}
>
</ha-date-input>
@@ -5,7 +5,7 @@ import { customElement, property } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { setDateTimeValue } from "../../../data/datetime";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@customElement("more-info-datetime")
@@ -19,23 +19,22 @@ class MoreInfoDatetime extends LitElement {
return nothing;
}
const dateObj = isUnavailableState(this.stateObj.state)
? undefined
: new Date(this.stateObj.state);
const dateObj =
this.stateObj.state === UNKNOWN
? undefined
: new Date(this.stateObj.state);
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
return html`<ha-date-input
.locale=${this.hass.locale}
.value=${date}
.disabled=${this.stateObj.state === UNAVAILABLE}
@value-changed=${this._dateChanged}
>
</ha-date-input>
<ha-time-input
.value=${time}
.locale=${this.hass.locale}
.disabled=${this.stateObj.state === UNAVAILABLE}
@value-changed=${this._timeChanged}
@click=${this._stopEventPropagation}
></ha-time-input>`;
@@ -11,7 +11,7 @@ import "../../../components/ha-control-button-group";
import "../../../components/ha-markdown";
import "../../../components/ha-relative-time";
import "../../../components/ha-service-control";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type { ExtEntityRegistryEntry } from "../../../data/entity/entity_registry";
import type { ScriptEntity } from "../../../data/script";
import {
@@ -141,7 +141,7 @@ class MoreInfoScript extends LitElement {
<ha-control-button
class="run-button"
@click=${this._runScript}
.disabled=${isUnavailableState(stateObj.state) || !this._canRun()}
.disabled=${stateObj.state === UNAVAILABLE || !this._canRun()}
>
<ha-svg-icon .path=${mdiPlay}></ha-svg-icon>
${this.hass!.localize("ui.card.script.run")}
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { setTimeValue } from "../../../data/time";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@@ -20,11 +20,10 @@ class MoreInfoTime extends LitElement {
return html`
<ha-time-input
.value=${isUnavailableState(this.stateObj.state)
.value=${this.stateObj.state === UNKNOWN
? undefined
: this.stateObj.state}
.locale=${this.hass.locale}
.disabled=${this.stateObj.state === UNAVAILABLE}
@value-changed=${this._timeChanged}
@click=${this._stopEventPropagation}
></ha-time-input>
@@ -15,7 +15,7 @@ import "../../../components/item/ha-row-item";
import "../../../components/progress/ha-progress-bar";
import type { BackupConfig } from "../../../data/backup";
import { fetchBackupConfig } from "../../../data/backup";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { EntitySources } from "../../../data/entity/entity_sources";
import { fetchEntitySourcesWithCache } from "../../../data/entity/entity_sources";
import { getSupervisorUpdateConfig } from "../../../data/supervisor/update";
@@ -176,7 +176,8 @@ class MoreInfoUpdate extends LitElement {
if (
!this.hass ||
!this.stateObj ||
isUnavailableState(this.stateObj.state)
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
) {
return nothing;
}
@@ -7,7 +7,7 @@ import type { DataTableColumnData } from "../../../components/data-table/ha-data
import { slugify } from "../../../common/string/slugify";
import { relativeTime } from "../../../common/datetime/relative_time";
import { formatShortDateTimeWithConditionalYear } from "../../../common/datetime/format_date_time";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import "../../../components/ha-tooltip";
import "../../../components/ha-svg-icon";
@@ -146,7 +146,11 @@ export const renderRelativeTimeColumn = (
localize: LocalizeFunc,
hass: HomeAssistant
) => {
if (!valueRelativeTime || isUnavailableState(valueRelativeTime)) {
if (
!valueRelativeTime ||
valueRelativeTime === UNAVAILABLE ||
valueRelativeTime === UNKNOWN
) {
return localize("ui.components.relative_time.never");
}
const date = new Date(valueRelativeTime);
@@ -26,7 +26,7 @@ import { stateActive } from "../../../common/entity/state_active";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-control-button";
import "../../../components/ha-control-button-group";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type {
ControlButton,
MediaPlayerEntity,
@@ -233,7 +233,7 @@ class HuiMediaPlayerPlaybackCardFeature
case "turn_on":
if (
(!active || assumedState) &&
!isUnavailableState(stateObj.state) &&
stateObj.state !== UNAVAILABLE &&
supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON)
) {
buttons.push({
@@ -4,7 +4,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
import { supportsFeature } from "../../../common/entity/supports-feature";
import { clamp } from "../../../common/number/clamp";
import "../../../components/ha-control-number-buttons";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import {
MediaPlayerEntityFeature,
type MediaPlayerEntity,
@@ -89,7 +89,7 @@ class HuiMediaPlayerVolumeButtonsCardFeature
}
const stateObj = this._stateObj;
const disabled = isUnavailableState(stateObj.state);
const disabled = stateObj.state === UNAVAILABLE;
const position =
stateObj.attributes.volume_level != null
@@ -4,7 +4,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
import { stateActive } from "../../../common/entity/state_active";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-control-slider";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import {
MediaPlayerEntityFeature,
type MediaPlayerEntity,
@@ -88,7 +88,7 @@ class HuiMediaPlayerVolumeSliderCardFeature
}
const stateObj = this._stateObj;
const disabled = isUnavailableState(stateObj.state);
const disabled = stateObj.state === UNAVAILABLE;
const position =
stateObj.attributes.volume_level != null
+9 -4
View File
@@ -32,7 +32,7 @@ import "../../../components/tile/ha-tile-badge";
import "../../../components/tile/ha-tile-container";
import "../../../components/tile/ha-tile-icon";
import "../../../components/tile/ha-tile-info";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features";
@@ -419,7 +419,9 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[area.temperature_entity_id] as
| HassEntity
| undefined;
return !stateObj || isUnavailableState(stateObj.state)
return !stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN
? ""
: this.hass.formatEntityState(stateObj);
}
@@ -427,7 +429,9 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[area.humidity_entity_id] as
| HassEntity
| undefined;
return !stateObj || isUnavailableState(stateObj.state)
return !stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN
? ""
: this.hass.formatEntityState(stateObj);
}
@@ -444,7 +448,8 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[entityId];
if (
stateObj &&
!isUnavailableState(stateObj.state) &&
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN &&
isNumericState(stateObj) &&
!isNaN(Number(stateObj.state))
) {
+3 -2
View File
@@ -9,7 +9,7 @@ import "../../../components/entity/state-badge";
import "../../../components/ha-card";
import "../../../components/ha-icon";
import "../../../components/ha-relative-time";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type {
CallServiceActionConfig,
@@ -293,7 +293,8 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
stateObj.attributes.device_class
) &&
!isUnavailableState(stateObj.state)
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN
? html`
<hui-timestamp-display
.hass=${this.hass}
+4 -4
View File
@@ -11,7 +11,7 @@ import { stateColorBrightness } from "../../../common/entity/state_color";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
import "../../../components/ha-state-icon";
import { UNAVAILABLE, isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { LightEntity } from "../../../data/light";
import { lightSupportsBrightness } from "../../../data/light";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
@@ -113,7 +113,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
min="1"
max="100"
.value=${brightness}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${stateObj.state === UNAVAILABLE}
@value-changing=${this._dragEvent}
@value-changed=${this._setBrightness}
style=${styleMap({
@@ -128,7 +128,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
"state-on": stateObj.state === "on",
"state-unavailable": stateObj.state === UNAVAILABLE,
})}"
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${stateObj.state === UNAVAILABLE}
style=${styleMap({
filter: this._computeBrightness(stateObj),
color: this._computeColor(stateObj),
@@ -149,7 +149,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
</div>
<div id="info" .title=${name}>
${isUnavailableState(stateObj.state)
${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? html` <div>${this.hass.formatEntityState(stateObj)}</div> `
: html` <div class="brightness">%</div> `}
${name}
@@ -21,7 +21,7 @@ import type { HaSlider } from "../../../components/ha-slider";
import "../../../components/ha-state-icon";
import { showJoinMediaPlayersDialog } from "../../../components/media-player/show-join-media-players-dialog";
import { showMediaBrowserDialog } from "../../../components/media-player/show-media-browser-dialog";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type {
MediaPickedEvent,
MediaPlayerEntity,
@@ -173,9 +173,12 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
const entityState = stateObj.state;
const isOffState =
!stateActive(stateObj) && !isUnavailableState(entityState);
!stateActive(stateObj) &&
entityState !== UNAVAILABLE &&
entityState !== UNKNOWN;
const isUnavailable =
isUnavailableState(entityState) ||
entityState === UNAVAILABLE ||
entityState === UNKNOWN ||
(isOffState &&
!supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON));
const hasNoImage = !this._image;
@@ -45,7 +45,7 @@ import "../../../components/ha-sortable";
import "../../../components/ha-svg-icon";
import "../../../components/input/ha-input";
import type { HaInput } from "../../../components/input/ha-input";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { TodoItem } from "../../../data/todo";
import {
TodoItemStatus,
@@ -383,7 +383,8 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
`;
}
const unavailable = isUnavailableState(stateObj.state);
const unavailable =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
// Discard memoization when we rollover to a new day, so filters can be recalculated
const memoTime = this._config.due_date_period
@@ -13,7 +13,7 @@ import { stringCompare } from "../../../../common/string/compare";
import "../../../../components/ha-spinner";
import "../../../../components/input/ha-input-search";
import type { HaInputSearch } from "../../../../components/input/ha-input-search";
import { isUnavailableState } from "../../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../../data/entity/entity";
import type { LovelaceBadgeConfig } from "../../../../data/lovelace/config/badge";
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
import type { CustomBadgeEntry } from "../../../../data/lovelace_custom_cards";
@@ -235,12 +235,14 @@ export class HuiBadgePicker extends LitElement {
this._usedEntities = [...usedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
!isUnavailableState(this.hass!.states[eid].state)
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
);
this._unusedEntities = [...unusedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
!isUnavailableState(this.hass!.states[eid].state)
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
);
this._loadBages();
@@ -13,7 +13,7 @@ import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-spinner";
import "../../../../components/input/ha-input-search";
import type { HaInputSearch } from "../../../../components/input/ha-input-search";
import { isUnavailableState } from "../../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../../data/entity/entity";
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
import type { CustomCardEntry } from "../../../../data/lovelace_custom_cards";
@@ -270,12 +270,14 @@ export class HuiCardPicker extends LitElement {
this._usedEntities = [...usedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
!isUnavailableState(this.hass!.states[eid].state)
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
);
this._unusedEntities = [...unusedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
!isUnavailableState(this.hass!.states[eid].state)
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
);
this._loadCards();
@@ -5,7 +5,7 @@ import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { computeStateName } from "../../../common/entity/compute_state_name";
import "../../../components/entity/ha-state-label-badge";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
@@ -36,7 +36,7 @@ export class HuiStateBadgeElement
const includeDomains = ["light", "switch", "sensor"];
const maxEntities = 1;
const entityFilter = (stateObj: HassEntity): boolean =>
!isUnavailableState(stateObj.state);
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
const foundEntities = findEntities(
hass,
maxEntities,
@@ -4,7 +4,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import "../../../components/entity/state-badge";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { computeTooltip } from "../common/compute-tooltip";
@@ -33,7 +33,7 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement {
const includeDomains = ["light", "switch", "sensor"];
const maxEntities = 1;
const entityFilter = (stateObj: HassEntity): boolean =>
!isUnavailableState(stateObj.state);
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
const foundEntities = findEntities(
hass,
maxEntities,
@@ -3,7 +3,7 @@ import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { computeTooltip } from "../common/compute-tooltip";
@@ -32,7 +32,7 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
const includeDomains = ["light", "switch", "sensor"];
const maxEntities = 1;
const entityFilter = (stateObj: HassEntity): boolean =>
!isUnavailableState(stateObj.state);
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
const foundEntities = findEntities(
hass,
maxEntities,
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-date-input";
import { setDateValue } from "../../../data/date";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -49,7 +49,7 @@ class HuiDateEntityRow extends LitElement implements LovelaceRow {
<ha-date-input
.locale=${this.hass.locale}
.disabled=${unavailable}
.value=${isUnavailableState(stateObj.state)
.value=${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? undefined
: stateObj.state}
@value-changed=${this._dateChanged}
@@ -5,7 +5,7 @@ import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { setDateTimeValue } from "../../../data/datetime";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -46,9 +46,10 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
const unavailable = stateObj.state === UNAVAILABLE;
const dateObj = isUnavailableState(stateObj.state)
? undefined
: new Date(stateObj.state);
const dateObj =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? undefined
: new Date(stateObj.state);
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
@@ -1,7 +1,7 @@
import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import type { EntitiesCardEntityConfig } from "../cards/types";
@@ -51,6 +51,9 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
`;
}
const noValue =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
return html`
<hui-generic-entity-row
.hass=${this.hass}
@@ -65,7 +68,7 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
})}
>
<div class="when">
${isUnavailableState(stateObj.state)
${noValue
? this.hass.formatEntityState(stateObj)
: html`<hui-timestamp-display
.hass=${this.hass}
@@ -75,7 +78,7 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
></hui-timestamp-display>`}
</div>
<div class="what">
${isUnavailableState(stateObj.state)
${noValue
? nothing
: this.hass.formatEntityAttributeValue(stateObj, "event_type")}
</div>
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/input/ha-input";
import type { HaInput } from "../../../components/input/ha-input";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { setValue } from "../../../data/input_text";
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
@@ -74,7 +74,7 @@ class HuiInputTextEntityRow extends LitElement implements LovelaceRow {
const newValue = target.value ?? "";
// Filter out invalid text states
if (newValue && isUnavailableState(newValue)) {
if (newValue && (newValue === UNAVAILABLE || newValue === UNKNOWN)) {
target.value = stateObj.state;
return;
}
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-button";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { callProtectedLockService } from "../../../data/lock";
import type { HomeAssistant } from "../../../types";
import { confirmAction } from "../common/confirm-action";
@@ -49,7 +49,7 @@ class HuiLockEntityRow extends LitElement implements LovelaceRow {
appearance="plain"
size="small"
@click=${this._callService}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${stateObj.state === UNAVAILABLE}
class="text-content"
>
${stateObj.state === "locked"
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-button";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type { ScriptEntity } from "../../../data/script";
import { canRun, hasScriptFields } from "../../../data/script";
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
@@ -68,8 +68,7 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
appearance="plain"
size="small"
@click=${this._runScript}
.disabled=${isUnavailableState(stateObj.state) ||
!canRun(stateObj)}
.disabled=${stateObj.state === UNAVAILABLE || !canRun(stateObj)}
>
${this._config.action_name ||
this.hass!.localize("ui.card.script.run")}
@@ -1,7 +1,7 @@
import type { PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import {
SENSOR_DEVICE_CLASS_UPTIME,
SENSOR_TIMESTAMP_DEVICE_CLASSES,
@@ -55,7 +55,9 @@ class HuiSensorEntityRow extends LitElement implements LovelaceRow {
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
${SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
stateObj.attributes.device_class
) && !isUnavailableState(stateObj.state)
) &&
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN
? html`
<hui-timestamp-display
.hass=${this.hass}
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/input/ha-input";
import type { HaInput } from "../../../components/input/ha-input";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { TextEntity } from "../../../data/text";
import { setValue } from "../../../data/text";
import type { HomeAssistant } from "../../../types";
@@ -76,7 +76,7 @@ class HuiTextEntityRow extends LitElement implements LovelaceRow {
const newValue = target.value ?? "";
// Filter out invalid text states
if (newValue && isUnavailableState(newValue)) {
if (newValue && (newValue === UNAVAILABLE || newValue === UNKNOWN)) {
target.value = stateObj.state;
return;
}
@@ -3,7 +3,7 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { setTimeValue } from "../../../data/time";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
@@ -48,7 +48,7 @@ class HuiTimeEntityRow extends LitElement implements LovelaceRow {
return html`
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
<ha-time-input
.value=${isUnavailableState(stateObj.state)
.value=${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? undefined
: stateObj.state}
.locale=${this.hass.locale}
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/entity/ha-entity-toggle";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -44,7 +44,8 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
const showToggle =
stateObj.state === "on" ||
stateObj.state === "off" ||
isUnavailableState(stateObj.state);
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN;
return html`
<hui-generic-entity-row
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/entity/ha-entity-toggle";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -44,7 +44,8 @@ class HuiValveEntityRow extends LitElement implements LovelaceRow {
const showToggle =
stateObj.state === "open" ||
stateObj.state === "closed" ||
isUnavailableState(stateObj.state);
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN;
return html`
<hui-generic-entity-row
@@ -3,7 +3,7 @@ import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { ForecastEvent, WeatherEntity } from "../../../data/weather";
import {
@@ -193,7 +193,8 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
})}
>
<div>
${isUnavailableState(stateObj.state) ||
${stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN ||
stateObj.attributes.temperature === undefined ||
stateObj.attributes.temperature === null
? this.hass.formatEntityState(stateObj)
+5 -3
View File
@@ -7,7 +7,7 @@ import { ensureArray } from "../common/array/ensure-array";
import { computeStateDomain } from "../common/entity/compute_state_domain";
import { STRINGS_SEPARATOR_DOT } from "../common/const";
import "../components/ha-relative-time";
import { isUnavailableState } from "../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import {
SENSOR_TIMESTAMP_DEVICE_CLASSES,
SENSOR_DEVICE_CLASS_UPTIME,
@@ -89,7 +89,9 @@ class StateDisplay extends LitElement {
const domain = computeStateDomain(stateObj);
if (content === "state") {
if (this.dashUnavailable && isUnavailableState(stateObj.state)) {
const noValue =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
if (this.dashUnavailable && noValue) {
return "—";
}
if (
@@ -97,7 +99,7 @@ class StateDisplay extends LitElement {
this.stateObj.attributes.device_class
) ||
TIMESTAMP_STATE_DOMAINS.includes(domain)) &&
!isUnavailableState(stateObj.state)
!noValue
) {
return html`
<hui-timestamp-display
+3 -2
View File
@@ -5,7 +5,7 @@ import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { computeDomain } from "../common/entity/compute_domain";
import "../components/entity/state-info";
import { isUnavailableState } from "../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import {
SENSOR_TIMESTAMP_DEVICE_CLASSES,
SENSOR_DEVICE_CLASS_UPTIME,
@@ -44,7 +44,8 @@ class StateCardDisplay extends LitElement {
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
this.stateObj.attributes.device_class
) &&
!isUnavailableState(this.stateObj.state)
this.stateObj.state !== UNAVAILABLE &&
this.stateObj.state !== UNKNOWN
? html`<hui-timestamp-display
.hass=${this.hass}
.ts=${new Date(this.stateObj.state)}
+2 -3
View File
@@ -5,7 +5,7 @@ import { customElement, property } from "lit/decorators";
import "../components/entity/ha-entity-toggle";
import "../components/entity/state-info";
import "../components/ha-button";
import { isUnavailableState } from "../data/entity/entity";
import { UNAVAILABLE } from "../data/entity/entity";
import type { ScriptEntity } from "../data/script";
import { canRun, hasScriptFields } from "../data/script";
import { showMoreInfoDialog } from "../dialogs/more-info/show-ha-more-info-dialog";
@@ -48,8 +48,7 @@ class StateCardScript extends LitElement {
appearance="plain"
size="small"
@click=${this._runScript}
.disabled=${isUnavailableState(stateObj.state) ||
!canRun(stateObj)}
.disabled=${stateObj.state === UNAVAILABLE || !canRun(stateObj)}
>
${this.hass!.localize("ui.card.script.run")}
</ha-button>`
+2 -2
View File
@@ -6,7 +6,7 @@ import { computeStateName } from "../common/entity/compute_state_name";
import "../components/entity/state-badge";
import "../components/input/ha-input";
import type { HaInput } from "../components/input/ha-input";
import { isUnavailableState, UNAVAILABLE } from "../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import type { TextEntity } from "../data/text";
import { setValue } from "../data/text";
import type { HomeAssistant } from "../types";
@@ -40,7 +40,7 @@ class StateCardText extends LitElement {
const value = (ev.target as HaInput).value ?? "";
// Filter out invalid text states
if (value && isUnavailableState(value)) {
if (value && (value === UNAVAILABLE || value === UNKNOWN)) {
(ev.target as HaInput).value = this.stateObj.state;
return;
}