mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Show battery charging state in the config panels (#6356)
This commit is contained in:
parent
def1ec3518
commit
3bc54aa9e0
28
src/common/entity/battery_icon.ts
Normal file
28
src/common/entity/battery_icon.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/** Return an icon representing a battery state. */
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
|
||||||
|
export const batteryIcon = (
|
||||||
|
batteryState: HassEntity,
|
||||||
|
batteryChargingState?: HassEntity
|
||||||
|
) => {
|
||||||
|
const battery = Number(batteryState.state);
|
||||||
|
const battery_charging =
|
||||||
|
batteryChargingState && batteryChargingState.state === "on";
|
||||||
|
|
||||||
|
if (isNaN(battery)) {
|
||||||
|
return "hass:battery-unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
var icon = "hass:battery";
|
||||||
|
const batteryRound = Math.round(battery / 10) * 10;
|
||||||
|
if (battery_charging && battery > 10) {
|
||||||
|
icon += `-charging-${batteryRound}`;
|
||||||
|
} else if (battery_charging) {
|
||||||
|
icon += "-outline";
|
||||||
|
} else if (battery <= 5) {
|
||||||
|
icon += "-alert";
|
||||||
|
} else if (battery > 5 && battery < 95) {
|
||||||
|
icon += `-${batteryRound}`;
|
||||||
|
}
|
||||||
|
return icon;
|
||||||
|
};
|
@ -2,6 +2,7 @@
|
|||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { UNIT_C, UNIT_F } from "../const";
|
import { UNIT_C, UNIT_F } from "../const";
|
||||||
import { domainIcon } from "./domain_icon";
|
import { domainIcon } from "./domain_icon";
|
||||||
|
import { batteryIcon } from "./battery_icon";
|
||||||
|
|
||||||
const fixedDeviceClassIcons = {
|
const fixedDeviceClassIcons = {
|
||||||
humidity: "hass:water-percent",
|
humidity: "hass:water-percent",
|
||||||
@ -19,29 +20,7 @@ export const sensorIcon = (state: HassEntity) => {
|
|||||||
return fixedDeviceClassIcons[dclass];
|
return fixedDeviceClassIcons[dclass];
|
||||||
}
|
}
|
||||||
if (dclass === "battery") {
|
if (dclass === "battery") {
|
||||||
const battery = Number(state.state);
|
return batteryIcon(state);
|
||||||
if (isNaN(battery)) {
|
|
||||||
return "hass:battery-unknown";
|
|
||||||
}
|
|
||||||
const batteryRound = Math.round(battery / 10) * 10;
|
|
||||||
if (batteryRound >= 100) {
|
|
||||||
return "hass:battery";
|
|
||||||
}
|
|
||||||
if (batteryRound <= 0) {
|
|
||||||
return "hass:battery-alert";
|
|
||||||
}
|
|
||||||
// Will return one of the following icons: (listed so extractor picks up)
|
|
||||||
// hass:battery-10
|
|
||||||
// hass:battery-20
|
|
||||||
// hass:battery-30
|
|
||||||
// hass:battery-40
|
|
||||||
// hass:battery-50
|
|
||||||
// hass:battery-60
|
|
||||||
// hass:battery-70
|
|
||||||
// hass:battery-80
|
|
||||||
// hass:battery-90
|
|
||||||
// We obscure 'hass' in iconname so this name does not get picked up
|
|
||||||
return `${"hass"}:battery-${batteryRound}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const unit = state.attributes.unit_of_measurement;
|
const unit = state.attributes.unit_of_measurement;
|
||||||
|
20
src/components/entity/ha-battery-icon.ts
Normal file
20
src/components/entity/ha-battery-icon.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { batteryIcon } from "../../common/entity/battery_icon";
|
||||||
|
import "../ha-icon";
|
||||||
|
import { customElement, html, property, LitElement } from "lit-element";
|
||||||
|
|
||||||
|
@customElement("ha-battery-icon")
|
||||||
|
class HaBatteryIcon extends LitElement {
|
||||||
|
@property() public batteryStateObj;
|
||||||
|
|
||||||
|
@property() public batteryChargingStateObj;
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`
|
||||||
|
<ha-icon
|
||||||
|
.icon=${batteryIcon(this.batteryStateObj, this.batteryChargingStateObj)}
|
||||||
|
></ha-icon>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("ha-battery-icon", HaBatteryIcon);
|
@ -37,6 +37,17 @@ export const findBatteryEntity = (
|
|||||||
hass.states[entity.entity_id].attributes.device_class === "battery"
|
hass.states[entity.entity_id].attributes.device_class === "battery"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const findBatteryChargingEntity = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entities: EntityRegistryEntry[]
|
||||||
|
): EntityRegistryEntry | undefined =>
|
||||||
|
entities.find(
|
||||||
|
(entity) =>
|
||||||
|
hass.states[entity.entity_id] &&
|
||||||
|
hass.states[entity.entity_id].attributes.device_class ===
|
||||||
|
"battery_charging"
|
||||||
|
);
|
||||||
|
|
||||||
export const computeEntityRegistryName = (
|
export const computeEntityRegistryName = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry: EntityRegistryEntry
|
entry: EntityRegistryEntry
|
||||||
|
@ -14,7 +14,7 @@ import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
|||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { createValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { createValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
import { compare } from "../../../common/string/compare";
|
import { compare } from "../../../common/string/compare";
|
||||||
import "../../../components/entity/ha-state-icon";
|
import "../../../components/entity/ha-battery-icon";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
import { AreaRegistryEntry } from "../../../data/area_registry";
|
import { AreaRegistryEntry } from "../../../data/area_registry";
|
||||||
import { ConfigEntry } from "../../../data/config_entries";
|
import { ConfigEntry } from "../../../data/config_entries";
|
||||||
@ -26,6 +26,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
EntityRegistryEntry,
|
EntityRegistryEntry,
|
||||||
findBatteryEntity,
|
findBatteryEntity,
|
||||||
|
findBatteryChargingEntity,
|
||||||
updateEntityRegistryEntry,
|
updateEntityRegistryEntry,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import { SceneEntities, showSceneEditor } from "../../../data/scene";
|
import { SceneEntities, showSceneEditor } from "../../../data/scene";
|
||||||
@ -117,6 +118,11 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
| EntityRegistryEntry
|
| EntityRegistryEntry
|
||||||
| undefined => findBatteryEntity(this.hass, entities));
|
| undefined => findBatteryEntity(this.hass, entities));
|
||||||
|
|
||||||
|
private _batteryChargingEntity = memoizeOne(
|
||||||
|
(entities: EntityRegistryEntry[]): EntityRegistryEntry | undefined =>
|
||||||
|
findBatteryChargingEntity(this.hass, entities)
|
||||||
|
);
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
protected firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
loadDeviceRegistryDetailDialog();
|
loadDeviceRegistryDetailDialog();
|
||||||
@ -145,9 +151,13 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
const integrations = this._integrations(device, this.entries);
|
const integrations = this._integrations(device, this.entries);
|
||||||
const entities = this._entities(this.deviceId, this.entities);
|
const entities = this._entities(this.deviceId, this.entities);
|
||||||
const batteryEntity = this._batteryEntity(entities);
|
const batteryEntity = this._batteryEntity(entities);
|
||||||
|
const batteryChargingEntity = this._batteryChargingEntity(entities);
|
||||||
const batteryState = batteryEntity
|
const batteryState = batteryEntity
|
||||||
? this.hass.states[batteryEntity.entity_id]
|
? this.hass.states[batteryEntity.entity_id]
|
||||||
: undefined;
|
: undefined;
|
||||||
|
const batteryChargingState = batteryChargingEntity
|
||||||
|
? this.hass.states[batteryChargingEntity.entity_id]
|
||||||
|
: undefined;
|
||||||
const area = this._computeArea(this.areas, device);
|
const area = this._computeArea(this.areas, device);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
@ -201,10 +211,11 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<div class="battery">
|
<div class="battery">
|
||||||
${batteryState.state}%
|
${batteryState.state}%
|
||||||
<ha-state-icon
|
<ha-battery-icon
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
.stateObj=${batteryState}
|
.batteryStateObj=${batteryState}
|
||||||
></ha-state-icon>
|
.batteryChargingStateObj=${batteryChargingState}
|
||||||
|
></ha-battery-icon>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""
|
: ""
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
DataTableRowData,
|
DataTableRowData,
|
||||||
RowClickedEvent,
|
RowClickedEvent,
|
||||||
} from "../../../components/data-table/ha-data-table";
|
} from "../../../components/data-table/ha-data-table";
|
||||||
import "../../../components/entity/ha-state-icon";
|
import "../../../components/entity/ha-battery-icon";
|
||||||
import { AreaRegistryEntry } from "../../../data/area_registry";
|
import { AreaRegistryEntry } from "../../../data/area_registry";
|
||||||
import { ConfigEntry } from "../../../data/config_entries";
|
import { ConfigEntry } from "../../../data/config_entries";
|
||||||
import {
|
import {
|
||||||
@ -25,6 +25,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
EntityRegistryEntry,
|
EntityRegistryEntry,
|
||||||
findBatteryEntity,
|
findBatteryEntity,
|
||||||
|
findBatteryChargingEntity,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import { domainToName } from "../../../data/integration";
|
import { domainToName } from "../../../data/integration";
|
||||||
import "../../../layouts/hass-tabs-subpage-data-table";
|
import "../../../layouts/hass-tabs-subpage-data-table";
|
||||||
@ -35,7 +36,7 @@ interface DeviceRowData extends DeviceRegistryEntry {
|
|||||||
device?: DeviceRowData;
|
device?: DeviceRowData;
|
||||||
area?: string;
|
area?: string;
|
||||||
integration?: string;
|
integration?: string;
|
||||||
battery_entity?: string;
|
battery_entity?: [string | undefined, string | undefined];
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("ha-config-devices-dashboard")
|
@customElement("ha-config-devices-dashboard")
|
||||||
@ -167,7 +168,10 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
)
|
)
|
||||||
.join(", ")
|
.join(", ")
|
||||||
: "No integration",
|
: "No integration",
|
||||||
battery_entity: this._batteryEntity(device.id, deviceEntityLookup),
|
battery_entity: [
|
||||||
|
this._batteryEntity(device.id, deviceEntityLookup),
|
||||||
|
this._batteryChargingEntity(device.id, deviceEntityLookup),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -201,17 +205,25 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
type: "numeric",
|
type: "numeric",
|
||||||
width: "90px",
|
width: "90px",
|
||||||
template: (batteryEntity: string) => {
|
template: (
|
||||||
const battery = batteryEntity
|
batteryEntityPair: DeviceRowData["battery_entity"]
|
||||||
? this.hass.states[batteryEntity]
|
) => {
|
||||||
: undefined;
|
const battery =
|
||||||
|
batteryEntityPair && batteryEntityPair[0]
|
||||||
|
? this.hass.states[batteryEntityPair[0]]
|
||||||
|
: undefined;
|
||||||
|
const batteryCharging =
|
||||||
|
batteryEntityPair && batteryEntityPair[1]
|
||||||
|
? this.hass.states[batteryEntityPair[1]]
|
||||||
|
: undefined;
|
||||||
return battery
|
return battery
|
||||||
? html`
|
? html`
|
||||||
${isNaN(battery.state as any) ? "-" : battery.state}%
|
${isNaN(battery.state as any) ? "-" : battery.state}%
|
||||||
<ha-state-icon
|
<ha-battery-icon
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
.stateObj=${battery}
|
.batteryStateObj=${battery}
|
||||||
></ha-state-icon>
|
.batteryChargingStateObj=${batteryCharging}
|
||||||
|
></ha-battery-icon>
|
||||||
`
|
`
|
||||||
: html` - `;
|
: html` - `;
|
||||||
},
|
},
|
||||||
@ -267,17 +279,25 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
type: "numeric",
|
type: "numeric",
|
||||||
width: "15%",
|
width: "15%",
|
||||||
maxWidth: "90px",
|
maxWidth: "90px",
|
||||||
template: (batteryEntity: string) => {
|
template: (
|
||||||
const battery = batteryEntity
|
batteryEntityPair: DeviceRowData["battery_entity"]
|
||||||
? this.hass.states[batteryEntity]
|
) => {
|
||||||
: undefined;
|
const battery =
|
||||||
|
batteryEntityPair && batteryEntityPair[0]
|
||||||
|
? this.hass.states[batteryEntityPair[0]]
|
||||||
|
: undefined;
|
||||||
|
const batteryCharging =
|
||||||
|
batteryEntityPair && batteryEntityPair[1]
|
||||||
|
? this.hass.states[batteryEntityPair[1]]
|
||||||
|
: undefined;
|
||||||
return battery && !isNaN(battery.state as any)
|
return battery && !isNaN(battery.state as any)
|
||||||
? html`
|
? html`
|
||||||
${battery.state}%
|
${battery.state}%
|
||||||
<ha-state-icon
|
<ha-battery-icon
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
.stateObj=${battery}
|
.batteryStateObj=${battery}
|
||||||
></ha-state-icon>
|
.batteryChargingStateObj=${batteryCharging}
|
||||||
|
></ha-battery-icon>
|
||||||
`
|
`
|
||||||
: html` - `;
|
: html` - `;
|
||||||
},
|
},
|
||||||
@ -336,6 +356,17 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
return batteryEntity ? batteryEntity.entity_id : undefined;
|
return batteryEntity ? batteryEntity.entity_id : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _batteryChargingEntity(
|
||||||
|
deviceId: string,
|
||||||
|
deviceEntityLookup: DeviceEntityLookup
|
||||||
|
): string | undefined {
|
||||||
|
const batteryChargingEntity = findBatteryChargingEntity(
|
||||||
|
this.hass,
|
||||||
|
deviceEntityLookup[deviceId] || []
|
||||||
|
);
|
||||||
|
return batteryChargingEntity ? batteryChargingEntity.entity_id : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
||||||
const deviceId = ev.detail.id;
|
const deviceId = ev.detail.id;
|
||||||
navigate(this, `/config/devices/device/${deviceId}`);
|
navigate(this, `/config/devices/device/${deviceId}`);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user