mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-30 21:12:18 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1605ba196 |
@@ -1,191 +0,0 @@
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||
import "../../../../src/components/ha-circular-progress";
|
||||
import "../../../../src/components/ha-markdown";
|
||||
import {
|
||||
extractApiErrorMessage,
|
||||
ignoreSupervisorError,
|
||||
} from "../../../../src/data/hassio/common";
|
||||
import {
|
||||
DatadiskList,
|
||||
listDatadisks,
|
||||
moveDatadisk,
|
||||
} from "../../../../src/data/hassio/host";
|
||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
||||
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
import { HassioDatatiskDialogParams } from "./show-dialog-hassio-datadisk";
|
||||
|
||||
const calculateMoveTime = memoizeOne((supervisor: Supervisor): number => {
|
||||
const speed = supervisor.host.disk_life_time !== "" ? 30 : 10;
|
||||
const moveTime = (supervisor.host.disk_used * 1000) / 60 / speed;
|
||||
const rebootTime = (supervisor.host.startup_time * 4) / 60;
|
||||
return Math.ceil((moveTime + rebootTime) / 10) * 10;
|
||||
});
|
||||
|
||||
@customElement("dialog-hassio-datadisk")
|
||||
class HassioDatadiskDialog extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private dialogParams?: HassioDatatiskDialogParams;
|
||||
|
||||
@state() private selectedDevice?: string;
|
||||
|
||||
@state() private devices?: DatadiskList["devices"];
|
||||
|
||||
@state() private moving = false;
|
||||
|
||||
public showDialog(params: HassioDatatiskDialogParams) {
|
||||
this.dialogParams = params;
|
||||
listDatadisks(this.hass).then((data) => {
|
||||
this.devices = data.devices;
|
||||
});
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this.dialogParams = undefined;
|
||||
this.selectedDevice = undefined;
|
||||
this.devices = undefined;
|
||||
this.moving = false;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.dialogParams) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
scrimClickAction
|
||||
escapeKeyAction
|
||||
@closed=${this.closeDialog}
|
||||
?hideActions=${this.moving}
|
||||
>
|
||||
${this.moving
|
||||
? html`<slot name="heading">
|
||||
<h2 id="title" class="header_title">
|
||||
${this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.moving"
|
||||
)}
|
||||
</h2>
|
||||
</slot>
|
||||
<ha-circular-progress alt="Moving" size="large" active>
|
||||
</ha-circular-progress>
|
||||
<p class="progress-text">
|
||||
${this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.moving_desc"
|
||||
)}
|
||||
</p>`
|
||||
: html`<slot name="heading">
|
||||
<h2 id="title" class="header_title">
|
||||
${this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.title"
|
||||
)}
|
||||
</h2>
|
||||
</slot>
|
||||
${this.devices?.length
|
||||
? html`
|
||||
${this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.description",
|
||||
{
|
||||
current_path: this.dialogParams.supervisor.os.data_disk,
|
||||
time: calculateMoveTime(this.dialogParams.supervisor),
|
||||
}
|
||||
)}
|
||||
<br /><br />
|
||||
|
||||
<paper-dropdown-menu
|
||||
.label=${this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.select_device"
|
||||
)}
|
||||
@value-changed=${this._select_device}
|
||||
>
|
||||
<paper-listbox slot="dropdown-content">
|
||||
${this.devices.map(
|
||||
(device) => html`<paper-item>${device}</paper-item>`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
`
|
||||
: this.devices === undefined
|
||||
? this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.loading_devices"
|
||||
)
|
||||
: this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.no_devices"
|
||||
)}
|
||||
|
||||
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
|
||||
${this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.cancel"
|
||||
)}
|
||||
</mwc-button>
|
||||
|
||||
<mwc-button
|
||||
.disabled=${!this.selectedDevice}
|
||||
slot="primaryAction"
|
||||
@click=${this._moveDatadisk}
|
||||
>
|
||||
${this.dialogParams.supervisor.localize(
|
||||
"dialog.datadisk_move.move"
|
||||
)}
|
||||
</mwc-button>`}
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _select_device(event) {
|
||||
this.selectedDevice = event.detail.value;
|
||||
}
|
||||
|
||||
private async _moveDatadisk() {
|
||||
this.moving = true;
|
||||
try {
|
||||
await moveDatadisk(this.hass, this.selectedDevice!);
|
||||
} catch (err) {
|
||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||
showAlertDialog(this, {
|
||||
title: this.dialogParams!.supervisor.localize(
|
||||
"system.host.failed_to_move"
|
||||
),
|
||||
text: extractApiErrorMessage(err),
|
||||
});
|
||||
this.closeDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
paper-dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
ha-circular-progress {
|
||||
display: block;
|
||||
margin: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-hassio-datadisk": HassioDatadiskDialog;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||
|
||||
export interface HassioDatatiskDialogParams {
|
||||
supervisor: Supervisor;
|
||||
}
|
||||
|
||||
export const showHassioDatadiskDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: HassioDatatiskDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-hassio-datadisk",
|
||||
dialogImport: () => import("./dialog-hassio-datadisk"),
|
||||
dialogParams,
|
||||
});
|
||||
};
|
||||
@@ -18,6 +18,7 @@ import { fetchHassioHardwareInfo } from "../../../src/data/hassio/hardware";
|
||||
import {
|
||||
changeHostOptions,
|
||||
configSyncOS,
|
||||
dataDiskMove,
|
||||
rebootHost,
|
||||
shutdownHost,
|
||||
updateOS,
|
||||
@@ -39,9 +40,8 @@ import {
|
||||
roundWithOneDecimal,
|
||||
} from "../../../src/util/calculate";
|
||||
import "../components/supervisor-metric";
|
||||
import { showHassioDatadiskDialog } from "../dialogs/datadisk/show-dialog-hassio-datadisk";
|
||||
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
|
||||
import { showNetworkDialog } from "../dialogs/network/show-dialog-network";
|
||||
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
|
||||
import { hassioStyle } from "../resources/hassio-style";
|
||||
|
||||
@customElement("hassio-host-info")
|
||||
@@ -189,18 +189,17 @@ class HassioHostInfo extends LitElement {
|
||||
</mwc-list-item>
|
||||
${this.supervisor.host.features.includes("haos")
|
||||
? html`<mwc-list-item
|
||||
@click=${() => this._handleMenuAction("import_from_usb")}
|
||||
>
|
||||
${this.supervisor.localize("system.host.import_from_usb")}
|
||||
</mwc-list-item>
|
||||
${this.supervisor.host.features.includes("os_agent") &&
|
||||
atLeastVersion(this.supervisor.host.agent_version, 1, 2, 0)
|
||||
? html`<mwc-list-item
|
||||
@click=${() => this._handleMenuAction("move_datadisk")}
|
||||
>
|
||||
${this.supervisor.localize("system.host.move_datadisk")}
|
||||
</mwc-list-item>`
|
||||
: ""} `
|
||||
@click=${() => this._handleMenuAction("import_from_usb")}
|
||||
>
|
||||
${this.supervisor.localize("system.host.import_from_usb")}
|
||||
</mwc-list-item>`
|
||||
: ""}
|
||||
${this.supervisor.host.features.includes("agent")
|
||||
? html`<mwc-list-item
|
||||
@click=${() => this._handleMenuAction("data_disk_move")}
|
||||
>
|
||||
${this.supervisor.localize("system.host.data_disk_move")}
|
||||
</mwc-list-item>`
|
||||
: ""}
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
@@ -231,18 +230,12 @@ class HassioHostInfo extends LitElement {
|
||||
case "import_from_usb":
|
||||
await this._importFromUSB();
|
||||
break;
|
||||
case "move_datadisk":
|
||||
await this._moveDatadisk();
|
||||
case "data_disk_move":
|
||||
await this._dataDiskMove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _moveDatadisk(): void {
|
||||
showHassioDatadiskDialog(this, {
|
||||
supervisor: this.supervisor,
|
||||
});
|
||||
}
|
||||
|
||||
private async _showHardware(): Promise<void> {
|
||||
let hardware;
|
||||
try {
|
||||
@@ -411,6 +404,34 @@ class HassioHostInfo extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _dataDiskMove(): Promise<void> {
|
||||
const confirmed = await showConfirmationDialog(this, {
|
||||
title: this.supervisor.localize("system.host.data_disk_move"),
|
||||
text: html`${this.supervisor.localize(
|
||||
"dialog.data_disk_move.description",
|
||||
{ current_path: this.supervisor.os.data_disk }
|
||||
)} <br /><br />${this.supervisor.localize(
|
||||
"dialog.data_disk_move.confirm_text"
|
||||
)}`,
|
||||
confirmText: this.supervisor.localize("dialog.data_disk_move.move"),
|
||||
dismissText: this.supervisor.localize("dialog.data_disk_move.cancel"),
|
||||
});
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await dataDiskMove(this.hass);
|
||||
} catch (err) {
|
||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||
showAlertDialog(this, {
|
||||
title: this.supervisor.localize("system.host.failed_to_move"),
|
||||
text: extractApiErrorMessage(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _loadData(): Promise<void> {
|
||||
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
|
||||
fireEvent(this, "supervisor-collection-refresh", {
|
||||
|
||||
@@ -34,18 +34,16 @@ import { hassioStyle } from "../resources/hassio-style";
|
||||
const UNSUPPORTED_REASON_URL = {
|
||||
apparmor: "/more-info/unsupported/apparmor",
|
||||
container: "/more-info/unsupported/container",
|
||||
content_trust: "/more-info/unsupported/content_trust",
|
||||
dbus: "/more-info/unsupported/dbus",
|
||||
docker_configuration: "/more-info/unsupported/docker_configuration",
|
||||
docker_version: "/more-info/unsupported/docker_version",
|
||||
job_conditions: "/more-info/unsupported/job_conditions",
|
||||
lxc: "/more-info/unsupported/lxc",
|
||||
network_manager: "/more-info/unsupported/network_manager",
|
||||
os_agent: "/more-info/unsupported/content_trust",
|
||||
os: "/more-info/unsupported/os",
|
||||
privileged: "/more-info/unsupported/privileged",
|
||||
source_mods: "/more-info/unsupported/source_mods",
|
||||
systemd: "/more-info/unsupported/systemd",
|
||||
content_trust: "/more-info/unsupported/content_trust",
|
||||
};
|
||||
|
||||
const UNHEALTHY_REASON_URL = {
|
||||
|
||||
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20210922.0",
|
||||
version="20210911.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/frontend",
|
||||
author="The Home Assistant Authors",
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/** Return an icon representing a alarm panel state. */
|
||||
|
||||
export const alarmPanelIcon = (state?: string) => {
|
||||
switch (state) {
|
||||
case "armed_away":
|
||||
return "hass:shield-lock";
|
||||
case "armed_vacation":
|
||||
return "hass:shield-airplane";
|
||||
case "armed_home":
|
||||
return "hass:shield-home";
|
||||
case "armed_night":
|
||||
return "hass:shield-moon";
|
||||
case "armed_custom_bypass":
|
||||
return "hass:security";
|
||||
case "pending":
|
||||
return "hass:shield-outline";
|
||||
case "triggered":
|
||||
return "hass:bell-ring";
|
||||
case "disarmed":
|
||||
return "hass:shield-off";
|
||||
default:
|
||||
return "hass:shield";
|
||||
}
|
||||
};
|
||||
@@ -5,7 +5,6 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
* Optionally pass in a state to influence the domain icon.
|
||||
*/
|
||||
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../const";
|
||||
import { alarmPanelIcon } from "./alarm_panel_icon";
|
||||
import { binarySensorIcon } from "./binary_sensor_icon";
|
||||
import { coverIcon } from "./cover_icon";
|
||||
import { sensorIcon } from "./sensor_icon";
|
||||
@@ -19,7 +18,18 @@ export const domainIcon = (
|
||||
|
||||
switch (domain) {
|
||||
case "alarm_control_panel":
|
||||
return alarmPanelIcon(compareState);
|
||||
switch (compareState) {
|
||||
case "armed_home":
|
||||
return "hass:bell-plus";
|
||||
case "armed_night":
|
||||
return "hass:bell-sleep";
|
||||
case "disarmed":
|
||||
return "hass:bell-outline";
|
||||
case "triggered":
|
||||
return "hass:bell-ring";
|
||||
default:
|
||||
return "hass:bell";
|
||||
}
|
||||
|
||||
case "binary_sensor":
|
||||
return binarySensorIcon(compareState, stateObj);
|
||||
|
||||
@@ -15,7 +15,7 @@ const haTabFixBehaviorImpl = {
|
||||
},
|
||||
};
|
||||
|
||||
// paper-dialog that uses the haTabFixBehaviorImpl behavior
|
||||
// paper-dialog that uses the haTabFixBehaviorImpl behvaior
|
||||
// export class HaPaperDialog extends paperDialogClass {}
|
||||
// @ts-ignore
|
||||
export class HaPaperDialog
|
||||
|
||||
@@ -13,6 +13,7 @@ import secondsToDuration from "../../common/datetime/seconds_to_duration";
|
||||
import { computeStateDisplay } from "../../common/entity/compute_state_display";
|
||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { domainIcon } from "../../common/entity/domain_icon";
|
||||
import { stateIcon } from "../../common/entity/state_icon";
|
||||
import { timerTimeRemaining } from "../../data/timer";
|
||||
import { formatNumber } from "../../common/string/format_number";
|
||||
@@ -140,6 +141,26 @@ export class HaStateLabelBadge extends LitElement {
|
||||
}
|
||||
switch (domain) {
|
||||
case "alarm_control_panel":
|
||||
if (entityState.state === "pending") {
|
||||
return "hass:clock-fast";
|
||||
}
|
||||
if (entityState.state === "armed_away") {
|
||||
return "hass:nature";
|
||||
}
|
||||
if (entityState.state === "armed_home") {
|
||||
return "hass:home-variant";
|
||||
}
|
||||
if (entityState.state === "armed_night") {
|
||||
return "hass:weather-night";
|
||||
}
|
||||
if (entityState.state === "armed_custom_bypass") {
|
||||
return "hass:shield-home";
|
||||
}
|
||||
if (entityState.state === "triggered") {
|
||||
return "hass:alert-circle";
|
||||
}
|
||||
// state == 'disarmed'
|
||||
return domainIcon(domain, entityState);
|
||||
case "binary_sensor":
|
||||
case "device_tracker":
|
||||
case "updater":
|
||||
|
||||
@@ -82,7 +82,7 @@ export class HaTracePathDetails extends LitElement {
|
||||
] as ChooseActionTraceStep[];
|
||||
|
||||
if (parentTraceInfo && parentTraceInfo[0]?.result?.choice === "default") {
|
||||
return "The default action was executed because no options matched.";
|
||||
return "The default node was executed because no choices matched.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -325,15 +325,13 @@ class ActionRenderer {
|
||||
if (defaultExecuted) {
|
||||
this._renderEntry(choosePath, `${name}: Default action executed`);
|
||||
} else if (chooseTrace.result) {
|
||||
const choiceNumeric =
|
||||
chooseTrace.result.choice !== "default"
|
||||
? chooseTrace.result.choice + 1
|
||||
: undefined;
|
||||
const choiceConfig = this._getDataFromPath(
|
||||
`${this.keys[index]}/choose/${chooseTrace.result.choice}`
|
||||
) as ChooseActionChoice | undefined;
|
||||
const choiceName = choiceConfig
|
||||
? `${choiceConfig.alias || `Option ${choiceNumeric}`} executed`
|
||||
? `${
|
||||
choiceConfig.alias || `Choice ${chooseTrace.result.choice}`
|
||||
} executed`
|
||||
: `Error: ${chooseTrace.error}`;
|
||||
this._renderEntry(choosePath, `${name}: ${choiceName}`);
|
||||
} else {
|
||||
|
||||
+7
-96
@@ -11,13 +11,7 @@ import { subscribeOne } from "../common/util/subscribe-one";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { ConfigEntry, getConfigEntries } from "./config_entries";
|
||||
import { subscribeEntityRegistry } from "./entity_registry";
|
||||
import {
|
||||
calculateStatisticsSumDecreaseGrowth,
|
||||
calculateStatisticsSumGrowth,
|
||||
calculateStatisticsSumIncreaseGrowth,
|
||||
fetchStatistics,
|
||||
Statistics,
|
||||
} from "./history";
|
||||
import { fetchStatistics, Statistics } from "./history";
|
||||
|
||||
const energyCollectionKeys: (string | undefined)[] = [];
|
||||
|
||||
@@ -44,7 +38,6 @@ export const emptyGridSourceEnergyPreference =
|
||||
type: "grid",
|
||||
flow_from: [],
|
||||
flow_to: [],
|
||||
flow_net: [],
|
||||
cost_adjustment_day: 0,
|
||||
});
|
||||
|
||||
@@ -85,12 +78,12 @@ export interface DeviceConsumptionEnergyPreference {
|
||||
export interface FlowFromGridSourceEnergyPreference {
|
||||
// kWh meter
|
||||
stat_energy_from: string;
|
||||
entity_energy_from: string | null;
|
||||
|
||||
// $ meter
|
||||
stat_cost: string | null;
|
||||
|
||||
// Can be used to generate costs if stat_cost omitted
|
||||
entity_energy_from: string | null;
|
||||
entity_energy_price: string | null;
|
||||
number_energy_price: number | null;
|
||||
}
|
||||
@@ -98,39 +91,21 @@ export interface FlowFromGridSourceEnergyPreference {
|
||||
export interface FlowToGridSourceEnergyPreference {
|
||||
// kWh meter
|
||||
stat_energy_to: string;
|
||||
entity_energy_to: string | null;
|
||||
|
||||
// $ meter
|
||||
stat_compensation: string | null;
|
||||
|
||||
// Can be used to generate costs if stat_cost omitted
|
||||
entity_energy_to: string | null;
|
||||
entity_energy_price: string | null;
|
||||
number_energy_price: number | null;
|
||||
}
|
||||
|
||||
export interface FlowNetGridSourceEnergyPreference {
|
||||
// kWh meter
|
||||
stat_energy_net: string;
|
||||
entity_energy_net: string | null;
|
||||
|
||||
// $ meter to
|
||||
stat_cost: string | null;
|
||||
|
||||
// Can be used to generate to costs if stat_cost omitted
|
||||
entity_energy_price_to: string | null;
|
||||
number_energy_price_to: number | null;
|
||||
|
||||
// Can be used to generate from costs if stat_cost omitted
|
||||
entity_energy_price_from: string | null;
|
||||
number_energy_price_from: number | null;
|
||||
}
|
||||
|
||||
export interface GridSourceTypeEnergyPreference {
|
||||
type: "grid";
|
||||
|
||||
flow_from: FlowFromGridSourceEnergyPreference[];
|
||||
flow_to: FlowToGridSourceEnergyPreference[];
|
||||
flow_net?: FlowNetGridSourceEnergyPreference[];
|
||||
|
||||
cost_adjustment_day: number;
|
||||
}
|
||||
@@ -174,7 +149,7 @@ export interface EnergyPreferences {
|
||||
}
|
||||
|
||||
export interface EnergyInfo {
|
||||
cost_sensors: Record<string, Record<string, string>>;
|
||||
cost_sensors: Record<string, string>;
|
||||
solar_forecast_domains: string[];
|
||||
}
|
||||
|
||||
@@ -288,7 +263,7 @@ const getEnergyData = async (
|
||||
if (source.stat_cost) {
|
||||
statIDs.push(source.stat_cost);
|
||||
}
|
||||
const costStatId = info.cost_sensors[source.stat_energy_from].none;
|
||||
const costStatId = info.cost_sensors[source.stat_energy_from];
|
||||
if (costStatId) {
|
||||
statIDs.push(costStatId);
|
||||
}
|
||||
@@ -307,7 +282,7 @@ const getEnergyData = async (
|
||||
if (flowFrom.stat_cost) {
|
||||
statIDs.push(flowFrom.stat_cost);
|
||||
}
|
||||
const costStatId = info.cost_sensors[flowFrom.stat_energy_from].none;
|
||||
const costStatId = info.cost_sensors[flowFrom.stat_energy_from];
|
||||
if (costStatId) {
|
||||
statIDs.push(costStatId);
|
||||
}
|
||||
@@ -317,29 +292,11 @@ const getEnergyData = async (
|
||||
if (flowTo.stat_compensation) {
|
||||
statIDs.push(flowTo.stat_compensation);
|
||||
}
|
||||
const costStatId = info.cost_sensors[flowTo.stat_energy_to].none;
|
||||
const costStatId = info.cost_sensors[flowTo.stat_energy_to];
|
||||
if (costStatId) {
|
||||
statIDs.push(costStatId);
|
||||
}
|
||||
}
|
||||
if (source.flow_net) {
|
||||
for (const flowTo of source.flow_net) {
|
||||
statIDs.push(flowTo.stat_energy_net);
|
||||
if (flowTo.stat_cost) {
|
||||
statIDs.push(flowTo.stat_cost);
|
||||
}
|
||||
const costStatIdInc =
|
||||
info.cost_sensors[flowTo.stat_energy_net].increase;
|
||||
if (costStatIdInc) {
|
||||
statIDs.push(costStatIdInc);
|
||||
}
|
||||
const costStatIdDec =
|
||||
info.cost_sensors[flowTo.stat_energy_net].decrease;
|
||||
if (costStatIdDec) {
|
||||
statIDs.push(costStatIdDec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stats = await fetchStatistics(hass!, addHours(start, -1), end, statIDs); // Subtract 1 hour from start to get starting point data
|
||||
@@ -496,49 +453,3 @@ export const getEnergySolarForecasts = (hass: HomeAssistant) =>
|
||||
hass.callWS<EnergySolarForecasts>({
|
||||
type: "energy/solar_forecast",
|
||||
});
|
||||
|
||||
export const getTotalGridConsumption = (
|
||||
stats: Statistics,
|
||||
gridSource: GridSourceTypeEnergyPreference
|
||||
) => {
|
||||
const consumedFromGrid = calculateStatisticsSumGrowth(
|
||||
stats,
|
||||
gridSource.flow_from.map((flow) => flow.stat_energy_from)
|
||||
);
|
||||
|
||||
const consumedFromGridNetto = gridSource.flow_net
|
||||
? calculateStatisticsSumIncreaseGrowth(
|
||||
stats,
|
||||
gridSource.flow_net.map((flow) => flow.stat_energy_net)
|
||||
) ?? 0
|
||||
: null;
|
||||
|
||||
if (consumedFromGrid === null && consumedFromGridNetto === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (consumedFromGrid || 0) + (consumedFromGridNetto || 0);
|
||||
};
|
||||
|
||||
export const getTotalGridReturn = (
|
||||
stats: Statistics,
|
||||
gridSource: GridSourceTypeEnergyPreference
|
||||
) => {
|
||||
const returnedToGrid = calculateStatisticsSumGrowth(
|
||||
stats,
|
||||
gridSource.flow_to.map((flow) => flow.stat_energy_to)
|
||||
);
|
||||
|
||||
const returnedToGridNetto = gridSource.flow_net
|
||||
? calculateStatisticsSumDecreaseGrowth(
|
||||
stats,
|
||||
gridSource.flow_net.map((flow) => flow.stat_energy_net)
|
||||
) ?? 0
|
||||
: null;
|
||||
|
||||
if (returnedToGrid === null && returnedToGridNetto === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (returnedToGrid || 0) + (returnedToGridNetto || 0);
|
||||
};
|
||||
|
||||
+13
-38
@@ -3,7 +3,6 @@ import { HomeAssistant } from "../../types";
|
||||
import { hassioApiResultExtractor, HassioResponse } from "./common";
|
||||
|
||||
export type HassioHostInfo = {
|
||||
agent_version: string;
|
||||
chassis: string;
|
||||
cpe: string;
|
||||
deployment: string;
|
||||
@@ -15,8 +14,6 @@ export type HassioHostInfo = {
|
||||
hostname: string;
|
||||
kernel: string;
|
||||
operating_system: string;
|
||||
boot_timestamp: number;
|
||||
startup_time: number;
|
||||
};
|
||||
|
||||
export interface HassioHassOSInfo {
|
||||
@@ -28,10 +25,6 @@ export interface HassioHassOSInfo {
|
||||
data_disk: string;
|
||||
}
|
||||
|
||||
export interface DatadiskList {
|
||||
devices: string[];
|
||||
}
|
||||
|
||||
export const fetchHassioHostInfo = async (
|
||||
hass: HomeAssistant
|
||||
): Promise<HassioHostInfo> => {
|
||||
@@ -121,6 +114,19 @@ export const configSyncOS = async (hass: HomeAssistant) => {
|
||||
return hass.callApi<HassioResponse<void>>("POST", "hassio/os/config/sync");
|
||||
};
|
||||
|
||||
export const dataDiskMove = async (hass: HomeAssistant) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/os/datadisk/move",
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
}
|
||||
|
||||
return hass.callApi<HassioResponse<void>>("POST", "hassio/os/datadisk/move");
|
||||
};
|
||||
|
||||
export const changeHostOptions = async (hass: HomeAssistant, options: any) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
@@ -137,34 +143,3 @@ export const changeHostOptions = async (hass: HomeAssistant, options: any) => {
|
||||
options
|
||||
);
|
||||
};
|
||||
|
||||
export const moveDatadisk = async (hass: HomeAssistant, device: string) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/os/datadisk/move",
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { device },
|
||||
});
|
||||
}
|
||||
|
||||
return hass.callApi<HassioResponse<void>>("POST", "hassio/os/datadisk/move");
|
||||
};
|
||||
|
||||
export const listDatadisks = async (
|
||||
hass: HomeAssistant
|
||||
): Promise<DatadiskList> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS<DatadiskList>({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/os/datadisk/list",
|
||||
method: "get",
|
||||
timeout: null,
|
||||
});
|
||||
}
|
||||
|
||||
return hassioApiResultExtractor(
|
||||
await hass.callApi<HassioResponse<DatadiskList>>("GET", "/os/datadisk/list")
|
||||
);
|
||||
};
|
||||
|
||||
+7
-21
@@ -68,8 +68,6 @@ export interface StatisticValue {
|
||||
mean: number | null;
|
||||
min: number | null;
|
||||
sum: number | null;
|
||||
sum_decrease?: number;
|
||||
sum_increase?: number;
|
||||
state: number | null;
|
||||
}
|
||||
|
||||
@@ -308,18 +306,17 @@ export const fetchStatistics = (
|
||||
});
|
||||
|
||||
export const calculateStatisticSumGrowth = (
|
||||
values: StatisticValue[],
|
||||
sumKey: "sum" | "sum_increase" | "sum_decrease" = "sum"
|
||||
values: StatisticValue[]
|
||||
): number | null => {
|
||||
if (!values || values.length < 2) {
|
||||
return null;
|
||||
}
|
||||
const endSum = values[values.length - 1][sumKey];
|
||||
if (endSum === null || endSum === undefined) {
|
||||
const endSum = values[values.length - 1].sum;
|
||||
if (endSum === null) {
|
||||
return null;
|
||||
}
|
||||
const startSum = values[0][sumKey];
|
||||
if (startSum === null || startSum === undefined) {
|
||||
const startSum = values[0].sum;
|
||||
if (startSum === null) {
|
||||
return endSum;
|
||||
}
|
||||
return endSum - startSum;
|
||||
@@ -327,8 +324,7 @@ export const calculateStatisticSumGrowth = (
|
||||
|
||||
export const calculateStatisticsSumGrowth = (
|
||||
data: Statistics,
|
||||
stats: string[],
|
||||
sumKey: "sum" | "sum_increase" | "sum_decrease" = "sum"
|
||||
stats: string[]
|
||||
): number | null => {
|
||||
let totalGrowth: number | null = null;
|
||||
|
||||
@@ -336,7 +332,7 @@ export const calculateStatisticsSumGrowth = (
|
||||
if (!(stat in data)) {
|
||||
continue;
|
||||
}
|
||||
const statGrowth = calculateStatisticSumGrowth(data[stat], sumKey);
|
||||
const statGrowth = calculateStatisticSumGrowth(data[stat]);
|
||||
|
||||
if (statGrowth === null) {
|
||||
continue;
|
||||
@@ -351,16 +347,6 @@ export const calculateStatisticsSumGrowth = (
|
||||
return totalGrowth;
|
||||
};
|
||||
|
||||
export const calculateStatisticsSumIncreaseGrowth = (
|
||||
data: Statistics,
|
||||
stats: string[]
|
||||
): number | null => calculateStatisticsSumGrowth(data, stats, "sum_increase");
|
||||
|
||||
export const calculateStatisticsSumDecreaseGrowth = (
|
||||
data: Statistics,
|
||||
stats: string[]
|
||||
): number | null => calculateStatisticsSumGrowth(data, stats, "sum_decrease");
|
||||
|
||||
export const statisticsHaveType = (
|
||||
stats: StatisticValue[],
|
||||
type: StatisticType
|
||||
|
||||
@@ -29,7 +29,7 @@ import { HomeAssistant } from "../types";
|
||||
import "./action-badge";
|
||||
import "./integration-badge";
|
||||
|
||||
const HIDDEN_DOMAINS = new Set(["met", "rpi_power", "hassio"]);
|
||||
const HIDDEN_DOMAINS = new Set(["met", "rpi_power"]);
|
||||
|
||||
@customElement("onboarding-integrations")
|
||||
class OnboardingIntegrations extends LitElement {
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
mdiDelete,
|
||||
mdiHomeExportOutline,
|
||||
mdiHomeImportOutline,
|
||||
mdiHomePlusOutline,
|
||||
mdiPencil,
|
||||
mdiTransmissionTower,
|
||||
} from "@mdi/js";
|
||||
@@ -174,41 +173,6 @@ export class EnergyGridSettings extends LitElement {
|
||||
<mwc-button @click=${this._addToSource}>Add return</mwc-button>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
If your meter goes down when your return to the grid, add a net
|
||||
source.
|
||||
</p>
|
||||
<h3>Combined consumption and return</h3>
|
||||
${gridSource.flow_net?.map((flow) => {
|
||||
const entityState = this.hass.states[flow.stat_energy_net];
|
||||
return html`
|
||||
<div class="row" .source=${flow}>
|
||||
${entityState?.attributes.icon
|
||||
? html`<ha-icon
|
||||
.icon=${entityState.attributes.icon}
|
||||
></ha-icon>`
|
||||
: html`<ha-svg-icon
|
||||
.path=${mdiHomePlusOutline}
|
||||
></ha-svg-icon>`}
|
||||
<span class="content"
|
||||
>${entityState
|
||||
? computeStateName(entityState)
|
||||
: flow.stat_energy_net}</span
|
||||
>
|
||||
<mwc-icon-button @click=${this._editToSource}>
|
||||
<ha-svg-icon .path=${mdiPencil}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<mwc-icon-button @click=${this._deleteToSource}>
|
||||
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
<div class="row border-bottom">
|
||||
<ha-svg-icon .path=${mdiHomePlusOutline}></ha-svg-icon>
|
||||
<mwc-button @click=${this._addToSource}>Add net</mwc-button>
|
||||
</div>
|
||||
|
||||
<h3>Grid carbon footprint</h3>
|
||||
${this._configEntries?.map(
|
||||
(entry) => html`<div class="row" .entry=${entry}>
|
||||
|
||||
@@ -279,14 +279,9 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
removeDashboard: async () => {
|
||||
if (
|
||||
!(await showConfirmationDialog(this, {
|
||||
title: this.hass!.localize(
|
||||
"ui.panel.config.lovelace.dashboards.confirm_delete_title",
|
||||
{ dashboard_title: dashboard!.title }
|
||||
),
|
||||
text: this.hass!.localize(
|
||||
"ui.panel.config.lovelace.dashboards.confirm_delete_text"
|
||||
"ui.panel.config.lovelace.dashboards.confirm_delete"
|
||||
),
|
||||
confirmText: this.hass!.localize("ui.common.delete"),
|
||||
}))
|
||||
) {
|
||||
return false;
|
||||
|
||||
@@ -46,8 +46,7 @@ export class EnergyStrategy {
|
||||
const hasGrid = prefs.energy_sources.find(
|
||||
(source) => source.type === "grid"
|
||||
) as GridSourceTypeEnergyPreference;
|
||||
const hasReturn =
|
||||
hasGrid && (hasGrid.flow_to.length || hasGrid.flow_net?.length);
|
||||
const hasReturn = hasGrid && hasGrid.flow_to.length;
|
||||
const hasSolar = prefs.energy_sources.some(
|
||||
(source) => source.type === "solar"
|
||||
);
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
EnergyData,
|
||||
energySourcesByType,
|
||||
getEnergyDataCollection,
|
||||
getTotalGridConsumption,
|
||||
} from "../../../../data/energy";
|
||||
import {
|
||||
calculateStatisticsSumGrowth,
|
||||
@@ -78,9 +77,9 @@ class HuiEnergyCarbonGaugeCard
|
||||
const prefs = this._data.prefs;
|
||||
const types = energySourcesByType(prefs);
|
||||
|
||||
const totalGridConsumption = getTotalGridConsumption(
|
||||
const totalGridConsumption = calculateStatisticsSumGrowth(
|
||||
this._data.stats,
|
||||
types.grid![0]
|
||||
types.grid![0].flow_from.map((flow) => flow.stat_energy_from)
|
||||
);
|
||||
|
||||
let value: number | undefined;
|
||||
@@ -130,9 +129,9 @@ class HuiEnergyCarbonGaugeCard
|
||||
<ha-svg-icon id="info" .path=${mdiInformation}></ha-svg-icon>
|
||||
<paper-tooltip animation-delay="0" for="info" position="left">
|
||||
<span>
|
||||
This card indicates how much of the energy consumed by your
|
||||
This card represents how much of the energy consumed by your
|
||||
home was generated using non-fossil fuels like solar, wind and
|
||||
nuclear. The higher, the better!
|
||||
nuclear.
|
||||
</span>
|
||||
</paper-tooltip>
|
||||
<ha-gauge
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import "@material/mwc-button";
|
||||
import {
|
||||
mdiArrowDown,
|
||||
mdiArrowLeft,
|
||||
@@ -15,6 +14,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, svg } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import "@material/mwc-button";
|
||||
import { formatNumber } from "../../../../common/string/format_number";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
@@ -22,8 +22,6 @@ import {
|
||||
EnergyData,
|
||||
energySourcesByType,
|
||||
getEnergyDataCollection,
|
||||
getTotalGridConsumption,
|
||||
getTotalGridReturn,
|
||||
} from "../../../../data/energy";
|
||||
import {
|
||||
calculateStatisticsSumGrowth,
|
||||
@@ -83,12 +81,13 @@ class HuiEnergyDistrubutionCard
|
||||
const hasSolarProduction = types.solar !== undefined;
|
||||
const hasBattery = types.battery !== undefined;
|
||||
const hasGas = types.gas !== undefined;
|
||||
const hasReturnToGrid =
|
||||
hasConsumption &&
|
||||
(types.grid![0].flow_to.length || types.grid![0].flow_net?.length);
|
||||
const hasReturnToGrid = hasConsumption && types.grid![0].flow_to.length > 0;
|
||||
|
||||
const totalFromGrid =
|
||||
getTotalGridConsumption(this._data.stats, types.grid![0]) ?? 0;
|
||||
calculateStatisticsSumGrowth(
|
||||
this._data.stats,
|
||||
types.grid![0].flow_from.map((flow) => flow.stat_energy_from)
|
||||
) ?? 0;
|
||||
|
||||
let gasUsage: number | null = null;
|
||||
if (hasGas) {
|
||||
@@ -129,7 +128,10 @@ class HuiEnergyDistrubutionCard
|
||||
|
||||
if (hasReturnToGrid) {
|
||||
returnedToGrid =
|
||||
getTotalGridReturn(this._data.stats, types.grid![0]) ?? 0;
|
||||
calculateStatisticsSumGrowth(
|
||||
this._data.stats,
|
||||
types.grid![0].flow_to.map((flow) => flow.stat_energy_to)
|
||||
) || 0;
|
||||
}
|
||||
|
||||
let solarConsumption: number | null = null;
|
||||
@@ -215,11 +217,6 @@ class HuiEnergyDistrubutionCard
|
||||
.grid![0].flow_from.map(
|
||||
(flow) => this._data!.stats[flow.stat_energy_from]
|
||||
)
|
||||
.concat(
|
||||
types.grid![0].flow_net?.map(
|
||||
(flow) => this._data!.stats[flow.stat_energy_net]
|
||||
) || []
|
||||
)
|
||||
.filter(Boolean)
|
||||
);
|
||||
|
||||
|
||||
@@ -11,11 +11,9 @@ import type { LevelDefinition } from "../../../../components/ha-gauge";
|
||||
import {
|
||||
EnergyData,
|
||||
getEnergyDataCollection,
|
||||
getTotalGridConsumption,
|
||||
getTotalGridReturn,
|
||||
GridSourceTypeEnergyPreference,
|
||||
} from "../../../../data/energy";
|
||||
|
||||
import { calculateStatisticsSumGrowth } from "../../../../data/history";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LovelaceCard } from "../../types";
|
||||
@@ -77,12 +75,15 @@ class HuiEnergyGridGaugeCard
|
||||
return html``;
|
||||
}
|
||||
|
||||
const consumedFromGrid = getTotalGridConsumption(
|
||||
const consumedFromGrid = calculateStatisticsSumGrowth(
|
||||
this._data.stats,
|
||||
gridSource
|
||||
gridSource.flow_from.map((flow) => flow.stat_energy_from)
|
||||
);
|
||||
|
||||
const returnedToGrid = getTotalGridReturn(this._data.stats, gridSource);
|
||||
const returnedToGrid = calculateStatisticsSumGrowth(
|
||||
this._data.stats,
|
||||
gridSource.flow_to.map((flow) => flow.stat_energy_to)
|
||||
);
|
||||
|
||||
if (consumedFromGrid !== null && returnedToGrid !== null) {
|
||||
if (returnedToGrid > consumedFromGrid) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
EnergyData,
|
||||
energySourcesByType,
|
||||
getEnergyDataCollection,
|
||||
getTotalGridReturn,
|
||||
} from "../../../../data/energy";
|
||||
import { calculateStatisticsSumGrowth } from "../../../../data/history";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
@@ -70,19 +69,19 @@ class HuiEnergySolarGaugeCard
|
||||
types.solar.map((source) => source.stat_energy_from)
|
||||
);
|
||||
|
||||
const productionReturnedToGrid = getTotalGridReturn(
|
||||
const productionReturnedToGrid = calculateStatisticsSumGrowth(
|
||||
this._data.stats,
|
||||
types.grid![0]
|
||||
types.grid![0].flow_to.map((flow) => flow.stat_energy_to)
|
||||
);
|
||||
|
||||
let value: number | undefined;
|
||||
|
||||
if (productionReturnedToGrid !== null && totalSolarProduction) {
|
||||
const consumedSolar = Math.max(
|
||||
const cosumedSolar = Math.max(
|
||||
0,
|
||||
totalSolarProduction - productionReturnedToGrid
|
||||
);
|
||||
value = (consumedSolar / totalSolarProduction) * 100;
|
||||
value = (cosumedSolar / totalSolarProduction) * 100;
|
||||
}
|
||||
|
||||
return html`
|
||||
@@ -92,13 +91,12 @@ class HuiEnergySolarGaugeCard
|
||||
<ha-svg-icon id="info" .path=${mdiInformation}></ha-svg-icon>
|
||||
<paper-tooltip animation-delay="0" for="info" position="left">
|
||||
<span>
|
||||
This card indicates how much of the solar energy you produced
|
||||
was used by your home instead of being returned to the grid.
|
||||
This card represents how much of the solar energy was used by
|
||||
your home and was not returned to the grid.
|
||||
<br /><br />
|
||||
If this number is typically very low, indicating excess solar
|
||||
production, you might want to consider charging a home battery
|
||||
or electric car from your solar panels at times of high solar
|
||||
production.
|
||||
If you frequently produce more than you consume, try to
|
||||
conserve this energy by installing a battery or buying an
|
||||
electric car to charge.
|
||||
</span>
|
||||
</paper-tooltip>
|
||||
<ha-gauge
|
||||
@@ -111,11 +109,11 @@ class HuiEnergySolarGaugeCard
|
||||
"--gauge-color": this._computeSeverity(value),
|
||||
})}
|
||||
></ha-gauge>
|
||||
<div class="name">Self-consumed solar energy</div>
|
||||
<div class="name">Self consumed solar energy</div>
|
||||
`
|
||||
: totalSolarProduction === 0
|
||||
? "You have not produced any solar energy"
|
||||
: "Self-consumed solar energy couldn't be calculated"}
|
||||
: "Self consumed solar energy couldn't be calculated"}
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -111,20 +111,12 @@ export class HuiEnergySourcesTableCard
|
||||
flow.entity_energy_price ||
|
||||
flow.number_energy_price
|
||||
) ||
|
||||
types.grid?.[0].flow_net?.some(
|
||||
(flow) =>
|
||||
flow.stat_cost ||
|
||||
flow.entity_energy_price_from ||
|
||||
flow.number_energy_price_from ||
|
||||
flow.entity_energy_price_to ||
|
||||
flow.number_energy_price_to
|
||||
) ||
|
||||
types.gas?.some(
|
||||
(flow) =>
|
||||
flow.stat_cost || flow.entity_energy_price || flow.number_energy_price
|
||||
);
|
||||
|
||||
return html`<ha-card>
|
||||
return html` <ha-card>
|
||||
${this._config.title
|
||||
? html`<h1 class="card-header">${this._config.title}</h1>`
|
||||
: ""}
|
||||
@@ -317,7 +309,7 @@ export class HuiEnergySourcesTableCard
|
||||
totalGrid += energy;
|
||||
const cost_stat =
|
||||
flow.stat_cost ||
|
||||
this._data!.info.cost_sensors[flow.stat_energy_from].none;
|
||||
this._data!.info.cost_sensors[flow.stat_energy_from];
|
||||
const cost = cost_stat
|
||||
? calculateStatisticSumGrowth(
|
||||
this._data!.stats[cost_stat]
|
||||
@@ -377,7 +369,7 @@ export class HuiEnergySourcesTableCard
|
||||
totalGrid += energy;
|
||||
const cost_stat =
|
||||
flow.stat_compensation ||
|
||||
this._data!.info.cost_sensors[flow.stat_energy_to].none;
|
||||
this._data!.info.cost_sensors[flow.stat_energy_to];
|
||||
const cost = cost_stat
|
||||
? (calculateStatisticSumGrowth(
|
||||
this._data!.stats[cost_stat]
|
||||
@@ -423,145 +415,6 @@ export class HuiEnergySourcesTableCard
|
||||
</td>`
|
||||
: ""}
|
||||
</tr>`;
|
||||
})}
|
||||
${source.flow_net?.map((flow, idx) => {
|
||||
const entity = this.hass.states[flow.stat_energy_net];
|
||||
const energy_from =
|
||||
calculateStatisticSumGrowth(
|
||||
this._data!.stats[flow.stat_energy_net],
|
||||
"sum_increase"
|
||||
) || 0;
|
||||
const energy_to =
|
||||
(calculateStatisticSumGrowth(
|
||||
this._data!.stats[flow.stat_energy_net],
|
||||
"sum_decrease"
|
||||
) || 0) * -1;
|
||||
totalGrid += energy_from + energy_to;
|
||||
let costIncrease: number | null = null;
|
||||
let costDecrease: number | null = null;
|
||||
if (flow.stat_cost) {
|
||||
costIncrease =
|
||||
calculateStatisticSumGrowth(
|
||||
this._data!.stats[flow.stat_cost],
|
||||
"sum_increase"
|
||||
) || 0;
|
||||
costDecrease =
|
||||
(calculateStatisticSumGrowth(
|
||||
this._data!.stats[flow.stat_cost],
|
||||
"sum_decrease"
|
||||
) || 0) * 1;
|
||||
} else {
|
||||
const cost_stat_increase =
|
||||
this._data!.info.cost_sensors[flow.stat_energy_net]
|
||||
.increase;
|
||||
const cost_stat_decrease =
|
||||
this._data!.info.cost_sensors[flow.stat_energy_net]
|
||||
.decrease;
|
||||
costIncrease = cost_stat_increase
|
||||
? calculateStatisticSumGrowth(
|
||||
this._data!.stats[cost_stat_increase]
|
||||
) || 0
|
||||
: null;
|
||||
costDecrease = cost_stat_decrease
|
||||
? (calculateStatisticSumGrowth(
|
||||
this._data!.stats[cost_stat_decrease]
|
||||
) || 0) * -1
|
||||
: null;
|
||||
}
|
||||
if (costIncrease !== null) {
|
||||
totalGridCost += costIncrease;
|
||||
}
|
||||
if (costDecrease !== null) {
|
||||
totalGridCost += costDecrease;
|
||||
}
|
||||
const colorFrom =
|
||||
idx > 0
|
||||
? rgb2hex(
|
||||
lab2rgb(
|
||||
labDarken(
|
||||
rgb2lab(hex2rgb(consumptionColor)),
|
||||
source.flow_from.length + idx
|
||||
)
|
||||
)
|
||||
)
|
||||
: returnColor;
|
||||
const colorTo =
|
||||
idx > 0
|
||||
? rgb2hex(
|
||||
lab2rgb(
|
||||
labDarken(
|
||||
rgb2lab(hex2rgb(returnColor)),
|
||||
source.flow_to.length + idx
|
||||
)
|
||||
)
|
||||
)
|
||||
: returnColor;
|
||||
return html`<tr class="mdc-data-table__row">
|
||||
<td class="mdc-data-table__cell cell-bullet">
|
||||
<div
|
||||
class="bullet"
|
||||
style=${styleMap({
|
||||
borderColor: colorFrom,
|
||||
backgroundColor: colorFrom + "7F",
|
||||
})}
|
||||
></div>
|
||||
</td>
|
||||
<th class="mdc-data-table__cell" scope="row">
|
||||
${entity
|
||||
? computeStateName(entity)
|
||||
: flow.stat_energy_net}
|
||||
</th>
|
||||
<td
|
||||
class="mdc-data-table__cell mdc-data-table__cell--numeric"
|
||||
>
|
||||
${formatNumber(energy_from, this.hass.locale)} kWh
|
||||
</td>
|
||||
${showCosts
|
||||
? html` <td
|
||||
class="mdc-data-table__cell mdc-data-table__cell--numeric"
|
||||
>
|
||||
${costIncrease !== null
|
||||
? formatNumber(costIncrease, this.hass.locale, {
|
||||
style: "currency",
|
||||
currency: this.hass.config.currency!,
|
||||
})
|
||||
: ""}
|
||||
</td>`
|
||||
: ""}
|
||||
</tr>
|
||||
<tr class="mdc-data-table__row">
|
||||
<td class="mdc-data-table__cell cell-bullet">
|
||||
<div
|
||||
class="bullet"
|
||||
style=${styleMap({
|
||||
borderColor: colorTo,
|
||||
backgroundColor: colorTo + "7F",
|
||||
})}
|
||||
></div>
|
||||
</td>
|
||||
<th class="mdc-data-table__cell" scope="row">
|
||||
${entity
|
||||
? computeStateName(entity)
|
||||
: flow.stat_energy_net}
|
||||
</th>
|
||||
<td
|
||||
class="mdc-data-table__cell mdc-data-table__cell--numeric"
|
||||
>
|
||||
${formatNumber(energy_to, this.hass.locale)} kWh
|
||||
</td>
|
||||
${showCosts
|
||||
? html` <td
|
||||
class="mdc-data-table__cell mdc-data-table__cell--numeric"
|
||||
>
|
||||
${costDecrease !== null
|
||||
? formatNumber(costDecrease, this.hass.locale, {
|
||||
style: "currency",
|
||||
currency: this.hass.config.currency!,
|
||||
})
|
||||
: ""}
|
||||
</td>`
|
||||
: ""}
|
||||
</tr>`;
|
||||
})}`
|
||||
)}
|
||||
${types.grid
|
||||
@@ -594,7 +447,7 @@ export class HuiEnergySourcesTableCard
|
||||
totalGas += energy;
|
||||
const cost_stat =
|
||||
source.stat_cost ||
|
||||
this._data!.info.cost_sensors[source.stat_energy_from].none;
|
||||
this._data!.info.cost_sensors[source.stat_energy_from];
|
||||
const cost = cost_stat
|
||||
? calculateStatisticSumGrowth(this._data!.stats[cost_stat]) ||
|
||||
0
|
||||
|
||||
@@ -231,7 +231,6 @@ export class HuiEnergyUsageGraphCard
|
||||
const statistics: {
|
||||
to_grid?: string[];
|
||||
from_grid?: string[];
|
||||
net_grid?: string[];
|
||||
solar?: string[];
|
||||
to_battery?: string[];
|
||||
from_battery?: string[];
|
||||
@@ -277,15 +276,6 @@ export class HuiEnergyUsageGraphCard
|
||||
statistics.to_grid = [flowTo.stat_energy_to];
|
||||
}
|
||||
}
|
||||
if (source.flow_net) {
|
||||
for (const flowNet of source.flow_net) {
|
||||
if (statistics.net_grid) {
|
||||
statistics.net_grid.push(flowNet.stat_energy_net);
|
||||
} else {
|
||||
statistics.net_grid = [flowNet.stat_energy_net];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dayDifference = differenceInDays(
|
||||
@@ -335,8 +325,6 @@ export class HuiEnergyUsageGraphCard
|
||||
to_battery?: { [start: string]: number };
|
||||
from_battery?: { [start: string]: number };
|
||||
solar?: { [start: string]: number };
|
||||
net_grid_increased?: { [start: string]: number };
|
||||
net_grid_decreased?: { [start: string]: number };
|
||||
} = {};
|
||||
|
||||
const computedStyles = getComputedStyle(this);
|
||||
@@ -378,15 +366,9 @@ export class HuiEnergyUsageGraphCard
|
||||
"to_battery",
|
||||
"from_battery",
|
||||
].includes(key);
|
||||
const add = !["solar", "from_battery", "net_grid"].includes(key);
|
||||
const add = !["solar", "from_battery"].includes(key);
|
||||
const totalStats: { [start: string]: number } = {};
|
||||
const totalStatsInc: { [start: string]: number } = {};
|
||||
const totalStatsDec: { [start: string]: number } = {};
|
||||
const sets: { [statId: string]: { [start: string]: number } } = {};
|
||||
const setsNet: {
|
||||
setInc: { [statId: string]: { [start: string]: number } };
|
||||
setDec: { [statId: string]: { [start: string]: number } };
|
||||
} = { setInc: {}, setDec: {} };
|
||||
statIds!.forEach((id) => {
|
||||
const stats =
|
||||
dayDifference > 35
|
||||
@@ -398,111 +380,39 @@ export class HuiEnergyUsageGraphCard
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === "net_grid") {
|
||||
const setInc = {};
|
||||
const setDec = {};
|
||||
let prevValueInc: number;
|
||||
let prevValueDec: number;
|
||||
stats.forEach((stat) => {
|
||||
if (
|
||||
stat.sum_decrease === null ||
|
||||
stat.sum_decrease === undefined ||
|
||||
stat.sum_increase === null ||
|
||||
stat.sum_increase === undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (prevValueInc === undefined) {
|
||||
prevValueInc = stat.sum_increase;
|
||||
prevValueDec = stat.sum_decrease;
|
||||
return;
|
||||
}
|
||||
const valIncrease = stat.sum_increase - prevValueInc;
|
||||
const valDecrease = stat.sum_decrease - prevValueDec;
|
||||
totalStatsInc[stat.start] =
|
||||
stat.start in totalStatsInc
|
||||
? totalStatsInc[stat.start] + valIncrease
|
||||
: valIncrease;
|
||||
totalStatsDec[stat.start] =
|
||||
stat.start in totalStatsDec
|
||||
? totalStatsDec[stat.start] + valDecrease
|
||||
: valDecrease;
|
||||
if (!(stat.start in setInc)) {
|
||||
setInc[stat.start] = valIncrease;
|
||||
setDec[stat.start] = valDecrease;
|
||||
}
|
||||
prevValueInc = stat.sum_increase;
|
||||
prevValueDec = stat.sum_decrease;
|
||||
});
|
||||
setsNet.setInc[id] = setInc;
|
||||
setsNet.setDec[id] = setDec;
|
||||
} else {
|
||||
const set = {};
|
||||
let prevValue: number;
|
||||
stats.forEach((stat) => {
|
||||
if (stat.sum === null) {
|
||||
return;
|
||||
}
|
||||
if (prevValue === undefined) {
|
||||
prevValue = stat.sum;
|
||||
return;
|
||||
}
|
||||
const val = stat.sum - prevValue;
|
||||
if (sum) {
|
||||
totalStats[stat.start] =
|
||||
stat.start in totalStats ? totalStats[stat.start] + val : val;
|
||||
}
|
||||
if (add && !(stat.start in set)) {
|
||||
set[stat.start] = val;
|
||||
}
|
||||
const set = {};
|
||||
let prevValue: number;
|
||||
stats.forEach((stat) => {
|
||||
if (stat.sum === null) {
|
||||
return;
|
||||
}
|
||||
if (prevValue === undefined) {
|
||||
prevValue = stat.sum;
|
||||
});
|
||||
sets[id] = set;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const val = stat.sum - prevValue;
|
||||
// Get total of solar and to grid to calculate the solar energy used
|
||||
if (sum) {
|
||||
totalStats[stat.start] =
|
||||
stat.start in totalStats ? totalStats[stat.start] + val : val;
|
||||
}
|
||||
if (add && !(stat.start in set)) {
|
||||
set[stat.start] = val;
|
||||
}
|
||||
prevValue = stat.sum;
|
||||
});
|
||||
sets[id] = set;
|
||||
});
|
||||
if (key === "net_grid") {
|
||||
combinedData.from_grid = {
|
||||
...combinedData.from_grid,
|
||||
...setsNet.setInc,
|
||||
};
|
||||
combinedData.to_grid = { ...combinedData.to_grid, ...setsNet.setDec };
|
||||
summedData.net_grid_increased = totalStatsInc;
|
||||
summedData.net_grid_decreased = totalStatsDec;
|
||||
return;
|
||||
}
|
||||
if (sum) {
|
||||
summedData[key] = totalStats;
|
||||
}
|
||||
if (add) {
|
||||
combinedData[key] = { ...combinedData[key], ...sets };
|
||||
combinedData[key] = sets;
|
||||
}
|
||||
});
|
||||
|
||||
if (summedData.net_grid_increased && summedData.net_grid_decreased) {
|
||||
if (!summedData.to_grid && !summedData.from_grid) {
|
||||
summedData.to_grid = summedData.net_grid_increased;
|
||||
summedData.from_grid = summedData.net_grid_decreased;
|
||||
} else {
|
||||
if (!summedData.to_grid) {
|
||||
summedData.to_grid = {};
|
||||
}
|
||||
if (!summedData.from_grid) {
|
||||
summedData.from_grid = {};
|
||||
}
|
||||
for (const start of Object.keys(summedData.net_grid_increased)) {
|
||||
summedData.to_grid[start] =
|
||||
(summedData.to_grid[start] || 0) +
|
||||
summedData.net_grid_increased[start];
|
||||
summedData.from_grid[start] =
|
||||
(summedData.from_grid[start] || 0) +
|
||||
summedData.net_grid_decreased[start];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const grid_to_battery = {};
|
||||
const battery_to_grid = {};
|
||||
|
||||
if ((summedData.to_grid || summedData.to_battery) && summedData.solar) {
|
||||
const used_solar = {};
|
||||
for (const start of Object.keys(summedData.solar)) {
|
||||
|
||||
@@ -12,7 +12,6 @@ import { customElement, property, state, query } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { alarmPanelIcon } from "../../../common/entity/alarm_panel_icon";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-label-badge";
|
||||
import {
|
||||
@@ -25,6 +24,17 @@ import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import type { LovelaceCard } from "../types";
|
||||
import { AlarmPanelCardConfig } from "./types";
|
||||
|
||||
const ICONS = {
|
||||
armed_away: "hass:shield-lock",
|
||||
armed_custom_bypass: "hass:security",
|
||||
armed_home: "hass:shield-home",
|
||||
armed_night: "hass:shield-moon",
|
||||
armed_vacation: "hass:shield-lock",
|
||||
disarmed: "hass:shield-check",
|
||||
pending: "hass:shield-outline",
|
||||
triggered: "hass:bell-ring",
|
||||
};
|
||||
|
||||
const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"];
|
||||
|
||||
@customElement("hui-alarm-panel-card")
|
||||
@@ -152,7 +162,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
>
|
||||
<ha-label-badge
|
||||
class="${classMap({ [stateObj.state]: true })}"
|
||||
.icon="${alarmPanelIcon(stateObj.state)}"
|
||||
.icon="${ICONS[stateObj.state] || "hass:shield-outline"}"
|
||||
.label="${this._stateIconLabel(stateObj.state)}"
|
||||
@click=${this._handleMoreInfo}
|
||||
></ha-label-badge>
|
||||
|
||||
@@ -55,7 +55,6 @@ export class HuiCreateDialogCard
|
||||
public closeDialog(): boolean {
|
||||
this._params = undefined;
|
||||
this._currTabIndex = 0;
|
||||
this._selectedEntities = [];
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import deepFreeze from "deep-freeze";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property, state, query } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/dialog/ha-paper-dialog";
|
||||
import type { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialog";
|
||||
import type { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
@@ -18,18 +19,16 @@ export class HuiDialogDeleteCard extends LitElement {
|
||||
|
||||
@state() private _cardConfig?: LovelaceCardConfig;
|
||||
|
||||
@query("ha-paper-dialog", true) private _dialog!: HaPaperDialog;
|
||||
|
||||
public async showDialog(params: DeleteCardDialogParams): Promise<void> {
|
||||
this._params = params;
|
||||
this._cardConfig = params.cardConfig;
|
||||
if (!Object.isFrozen(this._cardConfig)) {
|
||||
this._cardConfig = deepFreeze(this._cardConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this._params = undefined;
|
||||
this._cardConfig = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
await this.updateComplete;
|
||||
fireEvent(this._dialog as HTMLElement, "iron-resize");
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
@@ -38,12 +37,9 @@ export class HuiDialogDeleteCard extends LitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
@closed=${this.closeDialog}
|
||||
.heading=${this.hass.localize("ui.panel.lovelace.cards.confirm_delete")}
|
||||
>
|
||||
<div>
|
||||
<ha-paper-dialog with-backdrop opened modal>
|
||||
<h2>${this.hass.localize("ui.panel.lovelace.cards.confirm_delete")}</h2>
|
||||
<paper-dialog-scrollable>
|
||||
${this._cardConfig
|
||||
? html`
|
||||
<div class="element-preview">
|
||||
@@ -54,18 +50,16 @@ export class HuiDialogDeleteCard extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</paper-dialog-scrollable>
|
||||
<div class="paper-dialog-buttons">
|
||||
<mwc-button @click="${this._close}">
|
||||
${this.hass!.localize("ui.common.cancel")}
|
||||
</mwc-button>
|
||||
<mwc-button class="warning" @click="${this._delete}">
|
||||
${this.hass!.localize("ui.common.delete")}
|
||||
</mwc-button>
|
||||
</div>
|
||||
<mwc-button slot="secondaryAction" @click="${this.closeDialog}">
|
||||
${this.hass!.localize("ui.common.cancel")}
|
||||
</mwc-button>
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
class="warning"
|
||||
@click="${this._delete}"
|
||||
>
|
||||
${this.hass!.localize("ui.common.delete")}
|
||||
</mwc-button>
|
||||
</ha-dialog>
|
||||
</ha-paper-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -86,12 +80,17 @@ export class HuiDialogDeleteCard extends LitElement {
|
||||
];
|
||||
}
|
||||
|
||||
private _close(): void {
|
||||
this._params = undefined;
|
||||
this._cardConfig = undefined;
|
||||
}
|
||||
|
||||
private _delete(): void {
|
||||
if (!this._params?.deleteCard) {
|
||||
return;
|
||||
}
|
||||
this._params.deleteCard();
|
||||
this.closeDialog();
|
||||
this._close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import deepFreeze from "deep-freeze";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { customElement, property, state, query } from "lit/decorators";
|
||||
import "../../../../components/dialog/ha-paper-dialog";
|
||||
import "../../../../components/ha-yaml-editor";
|
||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||
@@ -48,26 +47,16 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this._params = undefined;
|
||||
this._cardConfig = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._params) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
scrimClickAction
|
||||
@closed=${this.closeDialog}
|
||||
.heading=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.suggest_card.header"
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<ha-paper-dialog with-backdrop opened>
|
||||
<h2>
|
||||
${this.hass!.localize("ui.panel.lovelace.editor.suggest_card.header")}
|
||||
</h2>
|
||||
<paper-dialog-scrollable>
|
||||
${this._cardConfig
|
||||
? html`
|
||||
<div class="element-preview">
|
||||
@@ -91,39 +80,37 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</paper-dialog-scrollable>
|
||||
<div class="paper-dialog-buttons">
|
||||
<mwc-button @click="${this._close}">
|
||||
${this._params.yaml
|
||||
? this.hass!.localize("ui.common.close")
|
||||
: this.hass!.localize("ui.common.cancel")}
|
||||
</mwc-button>
|
||||
${!this._params.yaml
|
||||
? html`
|
||||
<mwc-button @click="${this._pickCard}"
|
||||
>${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.suggest_card.create_own"
|
||||
)}</mwc-button
|
||||
>
|
||||
<mwc-button ?disabled="${this._saving}" @click="${this._save}">
|
||||
${this._saving
|
||||
? html`
|
||||
<ha-circular-progress
|
||||
active
|
||||
title="Saving"
|
||||
size="small"
|
||||
></ha-circular-progress>
|
||||
`
|
||||
: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.suggest_card.add"
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<mwc-button slot="secondaryAction" @click="${this.closeDialog}">
|
||||
${this._params.yaml
|
||||
? this.hass!.localize("ui.common.close")
|
||||
: this.hass!.localize("ui.common.cancel")}
|
||||
</mwc-button>
|
||||
${!this._params.yaml
|
||||
? html`
|
||||
<mwc-button slot="primaryAction" @click="${this._pickCard}"
|
||||
>${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.suggest_card.create_own"
|
||||
)}</mwc-button
|
||||
>
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
.disabled="${this._saving}"
|
||||
@click="${this._save}"
|
||||
>
|
||||
${this._saving
|
||||
? html`
|
||||
<ha-circular-progress
|
||||
active
|
||||
title="Saving"
|
||||
size="small"
|
||||
></ha-circular-progress>
|
||||
`
|
||||
: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.suggest_card.add"
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
</ha-dialog>
|
||||
</ha-paper-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -133,17 +120,17 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
css`
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
/* overrule the ha-style-dialog max-height on small screens */
|
||||
ha-dialog {
|
||||
ha-paper-dialog {
|
||||
max-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
@media all and (min-width: 850px) {
|
||||
ha-dialog {
|
||||
ha-paper-dialog {
|
||||
width: 845px;
|
||||
}
|
||||
}
|
||||
ha-dialog {
|
||||
ha-paper-dialog {
|
||||
max-width: 845px;
|
||||
--dialog-z-index: 5;
|
||||
}
|
||||
@@ -167,6 +154,11 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
];
|
||||
}
|
||||
|
||||
private _close(): void {
|
||||
this._params = undefined;
|
||||
this._cardConfig = undefined;
|
||||
}
|
||||
|
||||
private _pickCard(): void {
|
||||
if (
|
||||
!this._params?.lovelaceConfig ||
|
||||
@@ -182,7 +174,7 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
path: this._params!.path,
|
||||
entities: this._params!.entities,
|
||||
});
|
||||
this.closeDialog();
|
||||
this._close();
|
||||
}
|
||||
|
||||
private async _save(): Promise<void> {
|
||||
@@ -204,7 +196,7 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
);
|
||||
this._saving = false;
|
||||
showSaveSuccessToast(this, this.hass);
|
||||
this.closeDialog();
|
||||
this._close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,9 @@ export class HuiEntityPickerTable extends LitElement {
|
||||
<div @click=${this._handleEntityClicked} style="cursor: pointer;">
|
||||
${name}
|
||||
${narrow
|
||||
? html` <div class="secondary">${entity.entity_id}</div> `
|
||||
? html`
|
||||
<div class="secondary">${entity.stateObj.entity_id}</div>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`,
|
||||
|
||||
@@ -89,9 +89,9 @@ export class HuiUnusedEntities extends LitElement {
|
||||
icon: "",
|
||||
entity_id: entity,
|
||||
stateObj,
|
||||
name: stateObj ? computeStateName(stateObj) : "Unavailable",
|
||||
name: computeStateName(stateObj),
|
||||
domain: computeDomain(entity),
|
||||
last_changed: stateObj?.last_changed,
|
||||
last_changed: stateObj!.last_changed,
|
||||
};
|
||||
}) as DataTableRowData[]}
|
||||
@selected-changed=${this._handleSelectedChanged}
|
||||
|
||||
@@ -1117,13 +1117,9 @@
|
||||
"title": "Unexpected unit of measurement",
|
||||
"description": "The following entities do not have the expected units of measurement ''{currency}/kWh'' or ''{currency}/Wh'':"
|
||||
},
|
||||
"entity_unexpected_state_class": {
|
||||
"entity_unexpected_state_class_total_increasing": {
|
||||
"title": "Unexpected state class",
|
||||
"description": "The following entities do not have the expected state class:"
|
||||
},
|
||||
"entity_state_class_measurement_no_last_reset": {
|
||||
"title": "Last reset missing",
|
||||
"description": "The following entities have state class 'measurement' but 'last_reset' is missing:"
|
||||
"description": "The following entities do not have the expected state class 'total_increasing'"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1254,8 +1250,7 @@
|
||||
"open": "Open",
|
||||
"add_dashboard": "Add dashboard"
|
||||
},
|
||||
"confirm_delete_title": "Delete {dashboard_title}?",
|
||||
"confirm_delete_text": "Your dashboard will be permanently deleted.",
|
||||
"confirm_delete": "Are you sure you want to delete this dashboard?",
|
||||
"cant_edit_yaml": "Dashboards defined in YAML cannot be edited from the UI. Change them in configuration.yaml.",
|
||||
"cant_edit_default": "The standard Lovelace dashboard cannot be edited from the UI. You can hide it by setting another dashboard as default.",
|
||||
"detail": {
|
||||
@@ -4079,7 +4074,7 @@
|
||||
"unsupported_reason": {
|
||||
"apparmor": "AppArmor is not enabled on the host",
|
||||
"container": "Containers known to cause issues",
|
||||
"content_trust": "Content-trust validation is disabled",
|
||||
"content-trust": "Content-trust validation is disabled",
|
||||
"dbus": "DBUS",
|
||||
"docker_configuration": "Docker Configuration",
|
||||
"docker_version": "Docker Version",
|
||||
@@ -4087,9 +4082,7 @@
|
||||
"lxc": "LXC",
|
||||
"network_manager": "Network Manager",
|
||||
"os": "Operating System",
|
||||
"os_agent": "OS Agent",
|
||||
"privileged": "Supervisor is not privileged",
|
||||
"source_mods": "Source modifications",
|
||||
"systemd": "Systemd"
|
||||
},
|
||||
"unhealthy_reason": {
|
||||
@@ -4106,7 +4099,7 @@
|
||||
"failed_to_shutdown": "Failed to shutdown the host",
|
||||
"failed_to_set_hostname": "Setting hostname failed",
|
||||
"failed_to_import_from_usb": "Failed to import from USB",
|
||||
"failed_to_move": "Failed to move datadisk",
|
||||
"failed_to_move": "Failed to move data disk",
|
||||
"used_space": "Used space",
|
||||
"hostname": "Hostname",
|
||||
"change_hostname": "Change Hostname",
|
||||
@@ -4123,7 +4116,7 @@
|
||||
"shutdown_host": "Shutdown host",
|
||||
"hardware": "Hardware",
|
||||
"import_from_usb": "Import from USB",
|
||||
"move_datadisk": "Move datadisk"
|
||||
"data_disk_move": "Move to data disk"
|
||||
},
|
||||
"core": {
|
||||
"cpu_usage": "Core CPU Usage",
|
||||
@@ -4211,14 +4204,9 @@
|
||||
"attributes": "Attributes",
|
||||
"device_path": "Device path"
|
||||
},
|
||||
"datadisk_move": {
|
||||
"title": "[%key:supervisor::system::host::move_datadisk%]",
|
||||
"description": "You are currently using ''{current_path}'' as datadisk. Moving data disks will reboot your device and it's estimated to take {time} minutes. Your Home Assistant installation will not be accessible during this period. Do not disconnect the power during the move!",
|
||||
"select_device": "Select new datadisk",
|
||||
"no_devices": "No suitable attached devices found",
|
||||
"moving_desc": "Rebooting and moving datadisk. Please have patience",
|
||||
"moving": "Moving datadisk",
|
||||
"loading_devices": "Loading devices",
|
||||
"data_disk_move": {
|
||||
"description": "The current path to the data disk is ''{current_path}'', moving the disk will require a reboot of the host which will be done automatically.",
|
||||
"confirm_text": "Do you want to move now?",
|
||||
"cancel": "[%key:ui::common::cancel%]",
|
||||
"move": "Move"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user