diff --git a/src/data/entity_registry.ts b/src/data/entity_registry.ts index 9063a8eade..70b0b30209 100644 --- a/src/data/entity_registry.ts +++ b/src/data/entity_registry.ts @@ -129,20 +129,20 @@ export interface EntityRegistryEntryUpdateParams { aliases?: string[]; } -export const findBatteryEntity = ( +export const findBatteryEntity = ( hass: HomeAssistant, - entities: EntityRegistryEntry[] -): EntityRegistryEntry | undefined => + entities: T[] +): T | undefined => entities.find( (entity) => hass.states[entity.entity_id] && hass.states[entity.entity_id].attributes.device_class === "battery" ); -export const findBatteryChargingEntity = ( +export const findBatteryChargingEntity = ( hass: HomeAssistant, - entities: EntityRegistryEntry[] -): EntityRegistryEntry | undefined => + entities: T[] +): T | undefined => entities.find( (entity) => hass.states[entity.entity_id] && diff --git a/src/dialogs/more-info/controls/more-info-vacuum.ts b/src/dialogs/more-info/controls/more-info-vacuum.ts index d1ca0ae75c..6487749d23 100644 --- a/src/dialogs/more-info/controls/more-info-vacuum.ts +++ b/src/dialogs/more-info/controls/more-info-vacuum.ts @@ -9,17 +9,26 @@ import { mdiStop, mdiTargetVariant, } from "@mdi/js"; -import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; +import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { stopPropagation } from "../../../common/dom/stop_propagation"; import { computeAttributeValueDisplay } from "../../../common/entity/compute_attribute_display"; import { computeStateDisplay } from "../../../common/entity/compute_state_display"; +import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { supportsFeature } from "../../../common/entity/supports-feature"; +import { blankBeforePercent } from "../../../common/translations/blank_before_percent"; +import "../../../components/entity/ha-battery-icon"; import "../../../components/ha-attributes"; import "../../../components/ha-icon"; import "../../../components/ha-icon-button"; import "../../../components/ha-select"; import { UNAVAILABLE } from "../../../data/entity"; +import { + EntityRegistryDisplayEntry, + findBatteryChargingEntity, + findBatteryEntity, +} from "../../../data/entity_registry"; import { VacuumEntity, VacuumEntityFeature } from "../../../data/vacuum"; import { HomeAssistant } from "../../../types"; @@ -137,19 +146,7 @@ class MoreInfoVacuum extends LitElement { - ${supportsFeature(stateObj, VacuumEntityFeature.BATTERY) && - stateObj.attributes.battery_level - ? html` -
- - ${stateObj.attributes.battery_level} % - - -
- ` - : ""} + ${this._renderBattery()} ` : ""} ${VACUUM_COMMANDS.some((item) => item.isVisible(stateObj)) @@ -243,6 +240,81 @@ class MoreInfoVacuum extends LitElement { `; } + private _deviceEntities = memoizeOne( + ( + deviceId: string, + entities: HomeAssistant["entities"] + ): EntityRegistryDisplayEntry[] => { + const entries = Object.values(entities); + return entries.filter((entity) => entity.device_id === deviceId); + } + ); + + private _renderBattery() { + const stateObj = this.stateObj!; + + const deviceId = this.hass.entities[stateObj.entity_id]?.device_id; + + const entities = deviceId + ? this._deviceEntities(deviceId, this.hass.entities) + : []; + + const batteryEntity = findBatteryEntity(this.hass, entities); + const battery = batteryEntity + ? this.hass.states[batteryEntity.entity_id] + : undefined; + + const batteryIsBinary = + battery && computeStateDomain(battery) === "binary_sensor"; + + // Use device battery entity + if (battery && (batteryIsBinary || !isNaN(battery.state as any))) { + const batteryChargingEntity = findBatteryChargingEntity( + this.hass, + entities + ); + const batteryCharging = batteryChargingEntity + ? this.hass.states[batteryChargingEntity?.entity_id] + : undefined; + + return html` +
+ + ${batteryIsBinary + ? "" + : `${Number(battery.state).toFixed()}${blankBeforePercent( + this.hass.locale + )}%`} + + +
+ `; + } + + // Use battery_level and battery_icon deprecated attributes + if ( + supportsFeature(stateObj, VacuumEntityFeature.BATTERY) && + stateObj.attributes.battery_level + ) { + return html` +
+ + ${stateObj.attributes.battery_level.toFixed()}${blankBeforePercent( + this.hass.locale + )}% + + +
+ `; + } + + return nothing; + } + private callService(ev: CustomEvent) { const entry = (ev.target! as any).entry as VacuumCommand; this.hass.callService("vacuum", entry.serviceName, {