diff --git a/src/data/fan.ts b/src/data/fan.ts
index 7fe1e8af52..67a4e376b3 100644
--- a/src/data/fan.ts
+++ b/src/data/fan.ts
@@ -1,4 +1,24 @@
-export const SUPPORT_SET_SPEED = 1;
-export const SUPPORT_OSCILLATE = 2;
-export const SUPPORT_DIRECTION = 4;
-export const SUPPORT_PRESET_MODE = 8;
+import {
+ HassEntityAttributeBase,
+ HassEntityBase,
+} from "home-assistant-js-websocket";
+
+export const enum FanEntityFeature {
+ SET_SPEED = 1,
+ OSCILLATE = 2,
+ DIRECTION = 4,
+ PRESET_MODE = 8,
+}
+
+interface FanEntityAttributes extends HassEntityAttributeBase {
+ direction?: number;
+ oscillating?: boolean;
+ percentage?: number;
+ percentage_step?: number;
+ preset_mode?: string;
+ preset_modes?: string[];
+}
+
+export interface FanEntity extends HassEntityBase {
+ attributes: FanEntityAttributes;
+}
diff --git a/src/dialogs/more-info/controls/more-info-fan.js b/src/dialogs/more-info/controls/more-info-fan.js
index 3da9229e1c..2ec3925e49 100644
--- a/src/dialogs/more-info/controls/more-info-fan.js
+++ b/src/dialogs/more-info/controls/more-info-fan.js
@@ -11,7 +11,7 @@ import "../../../components/ha-icon-button";
import "../../../components/ha-labeled-slider";
import "../../../components/ha-select";
import "../../../components/ha-switch";
-import { SUPPORT_SET_SPEED } from "../../../data/fan";
+import { FanEntityFeature } from "../../../data/fan";
import { EventsMixin } from "../../../mixins/events-mixin";
import LocalizeMixin from "../../../mixins/localize-mixin";
@@ -161,7 +161,9 @@ class MoreInfoFan extends LocalizeMixin(EventsMixin(PolymerElement)) {
computeClassNames(stateObj) {
return (
"more-info-fan " +
- (supportsFeature(stateObj, SUPPORT_SET_SPEED) ? "has-percentage " : "") +
+ (supportsFeature(stateObj, FanEntityFeature.SET_SPEED)
+ ? "has-percentage "
+ : "") +
(stateObj.attributes.preset_modes &&
stateObj.attributes.preset_modes.length
? "has-preset_modes "
diff --git a/src/panels/lovelace/cards/hui-tile-card.ts b/src/panels/lovelace/cards/hui-tile-card.ts
index 4274ee4d5b..ce8f41e531 100644
--- a/src/panels/lovelace/cards/hui-tile-card.ts
+++ b/src/panels/lovelace/cards/hui-tile-card.ts
@@ -18,7 +18,10 @@ import "../../../components/tile/ha-tile-icon";
import "../../../components/tile/ha-tile-image";
import "../../../components/tile/ha-tile-info";
import { cameraUrlWithWidthHeight } from "../../../data/camera";
-import { UNAVAILABLE_STATES } from "../../../data/entity";
+import { CoverEntity } from "../../../data/cover";
+import { ON, UNAVAILABLE_STATES } from "../../../data/entity";
+import { FanEntity } from "../../../data/fan";
+import { LightEntity } from "../../../data/light";
import { ActionHandlerEvent } from "../../../data/lovelace";
import { SENSOR_DEVICE_CLASS_TIMESTAMP } from "../../../data/sensor";
import { HomeAssistant } from "../../../types";
@@ -152,6 +155,52 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
return stateColor;
});
+ private _computeStateDisplay(stateObj: HassEntity): TemplateResult | string {
+ const domain = computeDomain(stateObj.entity_id);
+
+ if (
+ (stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP ||
+ TIMESTAMP_STATE_DOMAINS.includes(domain)) &&
+ !UNAVAILABLE_STATES.includes(stateObj.state)
+ ) {
+ return html`
+
+ `;
+ }
+
+ if (domain === "light" && stateObj.state === ON) {
+ const brightness = (stateObj as LightEntity).attributes.brightness;
+ if (brightness) {
+ return `${Math.round((brightness * 100) / 255)}%`;
+ }
+ }
+
+ if (domain === "cover" && stateObj.state === "open") {
+ const position = (stateObj as CoverEntity).attributes.current_position;
+ if (position) {
+ return `${Math.round(position)}%`;
+ }
+ }
+
+ if (domain === "fan" && stateObj.state === ON) {
+ const speed = (stateObj as FanEntity).attributes.percentage;
+ if (speed) {
+ return `${Math.round(speed)}%`;
+ }
+ }
+
+ return computeStateDisplay(
+ this.hass!.localize,
+ stateObj,
+ this.hass!.locale
+ );
+ }
+
protected render(): TemplateResult {
if (!this._config || !this.hass) {
return html``;
@@ -175,25 +224,12 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
`;
}
- const domain = computeDomain(stateObj.entity_id);
-
const icon = this._config.icon || stateObj.attributes.icon;
const iconPath = stateIconPath(stateObj);
const name = this._config.name || stateObj.attributes.friendly_name;
- const stateDisplay =
- (stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP ||
- TIMESTAMP_STATE_DOMAINS.includes(domain)) &&
- !UNAVAILABLE_STATES.includes(stateObj.state)
- ? html`
-
- `
- : computeStateDisplay(this.hass!.localize, stateObj, this.hass.locale);
+
+ const stateDisplay = this._computeStateDisplay(stateObj);
const color = this._computeStateColor(stateObj, this._config.color);