mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-19 15:47:05 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 190ef6bb87 | |||
| 91b6a4c4b6 | |||
| 643cc4ca7d | |||
| 9ef71e6cf4 | |||
| bface72af7 | |||
| 90028b2e22 | |||
| 914c48abd5 | |||
| 79c082acde |
+3
-4
@@ -62,7 +62,6 @@
|
||||
"@lit-labs/virtualizer": "2.1.1",
|
||||
"@lit/context": "1.1.6",
|
||||
"@lit/reactive-element": "2.1.2",
|
||||
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/mwc-base": "0.27.0",
|
||||
"@material/mwc-formfield": "patch:@material/mwc-formfield@npm%3A0.27.0#~/.yarn/patches/@material-mwc-formfield-npm-0.27.0-9528cb60f6.patch",
|
||||
"@material/mwc-list": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
|
||||
@@ -75,8 +74,8 @@
|
||||
"@replit/codemirror-indentation-markers": "6.5.3",
|
||||
"@swc/helpers": "0.5.21",
|
||||
"@thomasloven/round-slider": "0.6.0",
|
||||
"@tsparticles/engine": "4.0.0",
|
||||
"@tsparticles/preset-links": "4.0.0",
|
||||
"@tsparticles/engine": "4.0.1",
|
||||
"@tsparticles/preset-links": "4.0.1",
|
||||
"@vibrant/color": "4.0.4",
|
||||
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
||||
"@webcomponents/webcomponentsjs": "2.8.0",
|
||||
@@ -166,7 +165,7 @@
|
||||
"babel-plugin-template-html-minifier": "4.1.0",
|
||||
"browserslist-useragent-regexp": "4.1.4",
|
||||
"del": "8.0.1",
|
||||
"eslint": "10.3.0",
|
||||
"eslint": "10.4.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-import-resolver-webpack": "0.13.11",
|
||||
"eslint-plugin-import-x": "4.16.2",
|
||||
|
||||
@@ -148,6 +148,7 @@ export interface GridSourceTypeEnergyPreference {
|
||||
power_config?: PowerConfig;
|
||||
|
||||
cost_adjustment_day: number;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface SolarSourceTypeEnergyPreference {
|
||||
@@ -156,6 +157,7 @@ export interface SolarSourceTypeEnergyPreference {
|
||||
stat_energy_from: string;
|
||||
stat_rate?: string;
|
||||
config_entry_solar_forecast: string[] | null;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface BatterySourceTypeEnergyPreference {
|
||||
@@ -165,6 +167,7 @@ export interface BatterySourceTypeEnergyPreference {
|
||||
stat_rate?: string; // always available if power_config is set
|
||||
power_config?: PowerConfig;
|
||||
stat_soc?: string;
|
||||
name?: string;
|
||||
}
|
||||
export interface GasSourceTypeEnergyPreference {
|
||||
type: "gas";
|
||||
|
||||
@@ -200,12 +200,13 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
protected _renderSourceControl() {
|
||||
if (
|
||||
!this.stateObj ||
|
||||
!supportsFeature(this.stateObj, MediaPlayerEntityFeature.SELECT_SOURCE) ||
|
||||
!this.stateObj.attributes.source_list?.length
|
||||
!supportsFeature(this.stateObj, MediaPlayerEntityFeature.SELECT_SOURCE)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const sourceList = this.stateObj.attributes.source_list || [];
|
||||
|
||||
return html`<ha-tooltip for="source-button">
|
||||
${this.hass.localize(`ui.card.media_player.source`)}
|
||||
</ha-tooltip>
|
||||
@@ -217,7 +218,7 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
.path=${mdiLoginVariant}
|
||||
>
|
||||
</ha-icon-button>
|
||||
${this.stateObj.attributes.source_list!.map(
|
||||
${sourceList.map(
|
||||
(source) =>
|
||||
html`<ha-dropdown-item
|
||||
.value=${source}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mdiBatteryHigh, mdiDelete, mdiPencil, mdiPlus } from "@mdi/js";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-card";
|
||||
@@ -100,19 +100,24 @@ export class EnergyBatterySettings extends LitElement {
|
||||
></ha-svg-icon>`}
|
||||
<div class="content">
|
||||
<span class="label"
|
||||
>${getStatisticLabel(
|
||||
>${source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
this.statsMetadata?.[source.stat_energy_from]
|
||||
)}</span
|
||||
>
|
||||
<span class="label"
|
||||
>${getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_to,
|
||||
this.statsMetadata?.[source.stat_energy_to]
|
||||
)}</span
|
||||
>
|
||||
${source.name
|
||||
? nothing
|
||||
: html`
|
||||
<span class="label"
|
||||
>${getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_to,
|
||||
this.statsMetadata?.[source.stat_energy_to]
|
||||
)}</span
|
||||
>
|
||||
`}
|
||||
</div>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
@@ -153,6 +158,7 @@ export class EnergyBatterySettings extends LitElement {
|
||||
|
||||
private _addSource() {
|
||||
showEnergySettingsBatteryDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
battery_sources: this.preferences.energy_sources.filter(
|
||||
(src) => src.type === "battery"
|
||||
) as BatterySourceTypeEnergyPreference[],
|
||||
@@ -169,6 +175,7 @@ export class EnergyBatterySettings extends LitElement {
|
||||
const origSource: BatterySourceTypeEnergyPreference =
|
||||
ev.currentTarget.closest(".row").source;
|
||||
showEnergySettingsBatteryDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
source: { ...origSource },
|
||||
battery_sources: this.preferences.energy_sources.filter(
|
||||
(src) => src.type === "battery"
|
||||
|
||||
@@ -124,13 +124,16 @@ export class EnergyGridSettings extends LitElement {
|
||||
></ha-svg-icon>`}
|
||||
<div class="content">
|
||||
<span class="label"
|
||||
>${getStatisticLabel(
|
||||
>${source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
primaryStat,
|
||||
this.statsMetadata?.[primaryStat]
|
||||
)}</span
|
||||
>
|
||||
${source.stat_energy_from && source.stat_energy_to
|
||||
${source.stat_energy_from &&
|
||||
source.stat_energy_to &&
|
||||
!source.name
|
||||
? html`<span class="label secondary"
|
||||
>${getStatisticLabel(
|
||||
this.hass,
|
||||
@@ -266,6 +269,7 @@ export class EnergyGridSettings extends LitElement {
|
||||
|
||||
private _addSource() {
|
||||
showEnergySettingsGridDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
grid_sources: this._getGridSources(),
|
||||
saveCallback: async (source) => {
|
||||
const preferences: EnergyPreferences = {
|
||||
@@ -283,6 +287,7 @@ export class EnergyGridSettings extends LitElement {
|
||||
const sourceIndex: number = row.sourceIndex;
|
||||
|
||||
showEnergySettingsGridDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
source: { ...origSource },
|
||||
grid_sources: this._getGridSources(),
|
||||
saveCallback: async (newSource) => {
|
||||
|
||||
@@ -101,7 +101,8 @@ export class EnergySolarSettings extends LitElement {
|
||||
.path=${mdiSolarPower}
|
||||
></ha-svg-icon>`}
|
||||
<span class="content"
|
||||
>${getStatisticLabel(
|
||||
>${source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
this.statsMetadata?.[source.stat_energy_from]
|
||||
@@ -154,6 +155,7 @@ export class EnergySolarSettings extends LitElement {
|
||||
|
||||
private _addSource() {
|
||||
showEnergySettingsSolarDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
info: this.info!,
|
||||
solar_sources: this.preferences.energy_sources.filter(
|
||||
(src) => src.type === "solar"
|
||||
@@ -171,6 +173,7 @@ export class EnergySolarSettings extends LitElement {
|
||||
const origSource: SolarSourceTypeEnergyPreference =
|
||||
ev.currentTarget.closest(".row").source;
|
||||
showEnergySettingsSolarDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
info: this.info!,
|
||||
source: { ...origSource },
|
||||
solar_sources: this.preferences.energy_sources.filter(
|
||||
|
||||
@@ -6,6 +6,7 @@ import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-dialog-footer";
|
||||
import "../../../../components/input/ha-input";
|
||||
import type {
|
||||
BatterySourceTypeEnergyPreference,
|
||||
PowerConfig,
|
||||
@@ -14,6 +15,11 @@ import {
|
||||
emptyBatteryEnergyPreference,
|
||||
energyStatisticHelpUrl,
|
||||
} from "../../../../data/energy";
|
||||
import {
|
||||
getStatisticLabel,
|
||||
getStatisticMetadata,
|
||||
isExternalStatistic,
|
||||
} from "../../../../data/recorder";
|
||||
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
|
||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
@@ -27,6 +33,7 @@ import {
|
||||
type PowerType,
|
||||
} from "./ha-energy-power-config";
|
||||
import type { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
|
||||
import type { HaInput } from "../../../../components/input/ha-input";
|
||||
|
||||
const energyUnitClasses = ["energy"];
|
||||
const socStatisticsUnits = ["%"];
|
||||
@@ -174,6 +181,32 @@ export class DialogEnergyBatterySettings
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.display_name"
|
||||
)}
|
||||
type="text"
|
||||
.disabled=${!(
|
||||
this._source?.stat_energy_from || this._source?.stat_energy_to
|
||||
)}
|
||||
.value=${this._source?.name || ""}
|
||||
.placeholder=${this._source?.stat_energy_from
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_from,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_from]
|
||||
)
|
||||
: this._source?.stat_energy_to
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_to,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_to]
|
||||
)
|
||||
: ""}
|
||||
@input=${this._nameChanged}
|
||||
>
|
||||
</ha-input>
|
||||
|
||||
<ha-energy-power-config
|
||||
.hass=${this.hass}
|
||||
.powerType=${this._powerType}
|
||||
@@ -232,12 +265,39 @@ export class DialogEnergyBatterySettings
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _updateMetadata(statId: string) {
|
||||
if (
|
||||
statId &&
|
||||
isExternalStatistic(statId) &&
|
||||
this._params?.statsMetadata &&
|
||||
!(statId in this._params.statsMetadata)
|
||||
) {
|
||||
const [metadata] = await getStatisticMetadata(this.hass, [statId]);
|
||||
if (metadata) {
|
||||
this._params.statsMetadata[statId] = metadata;
|
||||
this.requestUpdate("_params");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _statisticToChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_energy_to: ev.detail.value };
|
||||
this._updateMetadata(ev.detail.value);
|
||||
}
|
||||
|
||||
private _statisticFromChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
|
||||
this._updateMetadata(ev.detail.value);
|
||||
}
|
||||
|
||||
private _nameChanged(ev: InputEvent) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
name: (ev.target as HaInput).value,
|
||||
};
|
||||
if (!this._source.name) {
|
||||
delete this._source.name;
|
||||
}
|
||||
}
|
||||
|
||||
private _handlePowerConfigChanged(
|
||||
@@ -261,6 +321,9 @@ export class DialogEnergyBatterySettings
|
||||
stat_energy_from: this._source!.stat_energy_from,
|
||||
stat_energy_to: this._source!.stat_energy_to,
|
||||
};
|
||||
if (this._source?.name) {
|
||||
source.name = this._source.name;
|
||||
}
|
||||
|
||||
// Only include power_config if a power type is selected
|
||||
if (this._powerType !== "none") {
|
||||
|
||||
@@ -19,7 +19,11 @@ import {
|
||||
emptyGridSourceEnergyPreference,
|
||||
energyStatisticHelpUrl,
|
||||
} from "../../../../data/energy";
|
||||
import { isExternalStatistic } from "../../../../data/recorder";
|
||||
import {
|
||||
getStatisticLabel,
|
||||
getStatisticMetadata,
|
||||
isExternalStatistic,
|
||||
} from "../../../../data/recorder";
|
||||
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
|
||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
@@ -33,6 +37,7 @@ import {
|
||||
type PowerType,
|
||||
} from "./ha-energy-power-config";
|
||||
import type { EnergySettingsGridDialogParams } from "./show-dialogs-energy";
|
||||
import type { HaInput } from "../../../../components/input/ha-input";
|
||||
|
||||
const energyUnitClasses = ["energy"];
|
||||
|
||||
@@ -224,6 +229,33 @@ export class DialogEnergyGridSettings
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-input
|
||||
class="name"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.dialog.display_name"
|
||||
)}
|
||||
type="text"
|
||||
.disabled=${!(
|
||||
this._source?.stat_energy_from || this._source?.stat_energy_to
|
||||
)}
|
||||
.value=${this._source?.name || ""}
|
||||
.placeholder=${this._source?.stat_energy_from
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_from,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_from]
|
||||
)
|
||||
: this._source?.stat_energy_to
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_to,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_to]
|
||||
)
|
||||
: ""}
|
||||
@input=${this._nameChanged}
|
||||
>
|
||||
</ha-input>
|
||||
|
||||
<p class="section-label">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.dialog.import_cost"
|
||||
@@ -444,6 +476,21 @@ export class DialogEnergyGridSettings
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _updateMetadata(statId: string) {
|
||||
if (
|
||||
statId &&
|
||||
isExternalStatistic(statId) &&
|
||||
this._params?.statsMetadata &&
|
||||
!(statId in this._params.statsMetadata)
|
||||
) {
|
||||
const [metadata] = await getStatisticMetadata(this.hass, [statId]);
|
||||
if (metadata) {
|
||||
this._params.statsMetadata[statId] = metadata;
|
||||
this.requestUpdate("_params");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _statisticFromChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
|
||||
// Reset cost type if switching to external statistic with incompatible cost type
|
||||
@@ -459,6 +506,7 @@ export class DialogEnergyGridSettings
|
||||
number_energy_price: null,
|
||||
};
|
||||
}
|
||||
this._updateMetadata(ev.detail.value);
|
||||
}
|
||||
|
||||
private _statisticToChanged(ev: ValueChangedEvent<string>) {
|
||||
@@ -487,6 +535,17 @@ export class DialogEnergyGridSettings
|
||||
number_energy_price_export: null,
|
||||
};
|
||||
}
|
||||
this._updateMetadata(ev.detail.value);
|
||||
}
|
||||
|
||||
private _nameChanged(ev: InputEvent) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
name: (ev.target as HaInput).value,
|
||||
};
|
||||
if (!this._source.name) {
|
||||
delete this._source.name;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleImportCostTypeChanged(ev: Event) {
|
||||
@@ -569,6 +628,9 @@ export class DialogEnergyGridSettings
|
||||
number_energy_price_export: this._source!.number_energy_price_export,
|
||||
cost_adjustment_day: this._source!.cost_adjustment_day,
|
||||
};
|
||||
if (this._source?.name) {
|
||||
source.name = this._source.name;
|
||||
}
|
||||
|
||||
// Only include power_config if a power type is selected
|
||||
if (this._powerType !== "none") {
|
||||
@@ -601,6 +663,9 @@ export class DialogEnergyGridSettings
|
||||
ha-input:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ha-input.name {
|
||||
margin-top: var(--ha-space-4);
|
||||
}
|
||||
ha-radio-group {
|
||||
margin-bottom: var(--ha-space-4);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-dialog-footer";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import "../../../../components/radio/ha-radio-group";
|
||||
import "../../../../components/input/ha-input";
|
||||
import type { HaRadioGroup } from "../../../../components/radio/ha-radio-group";
|
||||
import "../../../../components/radio/ha-radio-option";
|
||||
import type { ConfigEntry } from "../../../../data/config_entries";
|
||||
@@ -27,6 +28,12 @@ import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../../types";
|
||||
import { brandsUrl } from "../../../../util/brands-url";
|
||||
import type { EnergySettingsSolarDialogParams } from "./show-dialogs-energy";
|
||||
import {
|
||||
getStatisticLabel,
|
||||
getStatisticMetadata,
|
||||
isExternalStatistic,
|
||||
} from "../../../../data/recorder";
|
||||
import type { HaInput } from "../../../../components/input/ha-input";
|
||||
|
||||
const energyUnitClasses = ["energy"];
|
||||
const powerUnitClasses = ["power"];
|
||||
@@ -129,6 +136,24 @@ export class DialogEnergySolarSettings
|
||||
autofocus
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.solar.dialog.display_name"
|
||||
)}
|
||||
type="text"
|
||||
.disabled=${!this._source?.stat_energy_from}
|
||||
.value=${this._source?.name || ""}
|
||||
.placeholder=${this._source?.stat_energy_from
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_from,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_from]
|
||||
)
|
||||
: ""}
|
||||
@input=${this._nameChanged}
|
||||
>
|
||||
</ha-input>
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
@@ -284,14 +309,38 @@ export class DialogEnergySolarSettings
|
||||
});
|
||||
}
|
||||
|
||||
private _statisticChanged(ev: ValueChangedEvent<string>) {
|
||||
private async _statisticChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
|
||||
if (
|
||||
ev.detail.value &&
|
||||
isExternalStatistic(ev.detail.value) &&
|
||||
this._params?.statsMetadata &&
|
||||
!(ev.detail.value in this._params.statsMetadata)
|
||||
) {
|
||||
const [metadata] = await getStatisticMetadata(this.hass, [
|
||||
ev.detail.value,
|
||||
]);
|
||||
if (metadata) {
|
||||
this._params.statsMetadata[ev.detail.value] = metadata;
|
||||
this.requestUpdate("_params");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _powerStatisticChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_rate: ev.detail.value };
|
||||
}
|
||||
|
||||
private _nameChanged(ev: InputEvent) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
name: (ev.target as HaInput).value,
|
||||
};
|
||||
if (!this._source.name) {
|
||||
delete this._source.name;
|
||||
}
|
||||
}
|
||||
|
||||
private async _save() {
|
||||
try {
|
||||
if (!this._forecast) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import type { StatisticsMetaData } from "../../../../data/recorder";
|
||||
export interface EnergySettingsGridDialogParams {
|
||||
source?: GridSourceTypeEnergyPreference;
|
||||
grid_sources: GridSourceTypeEnergyPreference[];
|
||||
statsMetadata?: Record<string, StatisticsMetaData>;
|
||||
saveCallback: (source: GridSourceTypeEnergyPreference) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -21,12 +22,14 @@ export interface EnergySettingsSolarDialogParams {
|
||||
info: EnergyInfo;
|
||||
source?: SolarSourceTypeEnergyPreference;
|
||||
solar_sources: SolarSourceTypeEnergyPreference[];
|
||||
statsMetadata?: Record<string, StatisticsMetaData>;
|
||||
saveCallback: (source: SolarSourceTypeEnergyPreference) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface EnergySettingsBatteryDialogParams {
|
||||
source?: BatterySourceTypeEnergyPreference;
|
||||
battery_sources: BatterySourceTypeEnergyPreference[];
|
||||
statsMetadata?: Record<string, StatisticsMetaData>;
|
||||
saveCallback: (source: BatterySourceTypeEnergyPreference) => Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,7 @@ export const supportsMediaPlayerSourceCardFeature = (
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE) &&
|
||||
!!stateObj.attributes.source_list?.length
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -355,11 +355,13 @@ export class HuiEnergySolarGraphCard
|
||||
name: this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_solar_graph.production",
|
||||
{
|
||||
name: getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
statisticsMetaData[source.stat_energy_from]
|
||||
),
|
||||
name:
|
||||
source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
statisticsMetaData[source.stat_energy_from]
|
||||
),
|
||||
}
|
||||
),
|
||||
barMaxWidth: 50,
|
||||
@@ -463,11 +465,13 @@ export class HuiEnergySolarGraphCard
|
||||
name: this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_solar_graph.forecast",
|
||||
{
|
||||
name: getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
statisticsMetaData[source.stat_energy_from]
|
||||
),
|
||||
name:
|
||||
source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
statisticsMetaData[source.stat_energy_from]
|
||||
),
|
||||
}
|
||||
),
|
||||
step: false,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// @ts-ignore
|
||||
import dataTableStyles from "@material/data-table/dist/mdc.data-table.min.css";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { css, html, LitElement, unsafeCSS, nothing } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
@@ -551,7 +549,13 @@ export class HuiEnergySourcesTableCard
|
||||
null,
|
||||
null,
|
||||
showCosts,
|
||||
compare
|
||||
compare,
|
||||
source.name
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_discharged",
|
||||
{ name: source.name }
|
||||
)
|
||||
: ""
|
||||
)}${this._renderRow(
|
||||
computedStyles,
|
||||
"battery_in",
|
||||
@@ -563,7 +567,13 @@ export class HuiEnergySourcesTableCard
|
||||
null,
|
||||
null,
|
||||
showCosts,
|
||||
compare
|
||||
compare,
|
||||
source.name
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_charged",
|
||||
{ name: source.name }
|
||||
)
|
||||
: ""
|
||||
)}`;
|
||||
})}
|
||||
${types.battery
|
||||
@@ -630,6 +640,15 @@ export class HuiEnergySourcesTableCard
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const name = !source.name
|
||||
? ""
|
||||
: source.stat_energy_to
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_grid_imported",
|
||||
{ name: source.name }
|
||||
)
|
||||
: source.name;
|
||||
|
||||
return this._renderRow(
|
||||
computedStyles,
|
||||
"grid_consumption",
|
||||
@@ -641,7 +660,8 @@ export class HuiEnergySourcesTableCard
|
||||
cost,
|
||||
costCompare,
|
||||
showCosts,
|
||||
compare
|
||||
compare,
|
||||
name
|
||||
);
|
||||
})();
|
||||
|
||||
@@ -670,6 +690,15 @@ export class HuiEnergySourcesTableCard
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const name = !source.name
|
||||
? ""
|
||||
: source.stat_energy_from
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_grid_exported",
|
||||
{ name: source.name }
|
||||
)
|
||||
: source.name;
|
||||
|
||||
return this._renderRow(
|
||||
computedStyles,
|
||||
"grid_return",
|
||||
@@ -681,7 +710,8 @@ export class HuiEnergySourcesTableCard
|
||||
-cost,
|
||||
-costCompare,
|
||||
showCosts,
|
||||
compare
|
||||
compare,
|
||||
name
|
||||
);
|
||||
})();
|
||||
|
||||
@@ -756,63 +786,120 @@ export class HuiEnergySourcesTableCard
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
${unsafeCSS(dataTableStyles)}
|
||||
.mdc-data-table {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
.mdc-data-table__header-cell,
|
||||
.mdc-data-table__cell {
|
||||
color: var(--primary-text-color);
|
||||
border-bottom-color: var(--divider-color);
|
||||
text-align: var(--float-start);
|
||||
}
|
||||
.mdc-data-table__row:not(.mdc-data-table__row--selected):hover {
|
||||
background-color: rgba(var(--rgb-primary-text-color), 0.04);
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.total {
|
||||
--mdc-typography-body2-font-weight: var(--ha-font-weight-medium);
|
||||
}
|
||||
.total .mdc-data-table__cell {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
ha-card {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.card-header {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
.has-header {
|
||||
padding-top: 0;
|
||||
}
|
||||
.cell-bullet {
|
||||
width: 32px;
|
||||
padding-right: 0;
|
||||
padding-inline-end: 0;
|
||||
padding-inline-start: 16px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.bullet {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
height: 16px;
|
||||
width: 32px;
|
||||
}
|
||||
.mdc-data-table__cell--numeric {
|
||||
direction: ltr;
|
||||
}
|
||||
`;
|
||||
}
|
||||
static styles: CSSResultGroup = css`
|
||||
.mdc-data-table__content,
|
||||
.mdc-data-table__cell {
|
||||
font-family: var(--ha-font-family-body);
|
||||
-moz-osx-font-smoothing: var(--ha-moz-osx-font-smoothing);
|
||||
-webkit-font-smoothing: var(--ha-font-smoothing);
|
||||
font-size: var(--ha-font-size-m);
|
||||
line-height: var(--ha-line-height-normal);
|
||||
font-weight: var(--ha-font-weight-normal);
|
||||
letter-spacing: 0.0178571429em;
|
||||
text-decoration: inherit;
|
||||
text-transform: inherit;
|
||||
}
|
||||
.mdc-data-table {
|
||||
background-color: var(--card-background-color);
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
border: 0;
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.mdc-data-table__table-container {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.mdc-data-table__table {
|
||||
min-width: 100%;
|
||||
border: 0;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.mdc-data-table__header-row {
|
||||
height: 56px;
|
||||
}
|
||||
.mdc-data-table__row {
|
||||
background-color: inherit;
|
||||
height: 52px;
|
||||
}
|
||||
.mdc-data-table__header-cell,
|
||||
.mdc-data-table__cell {
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
box-sizing: border-box;
|
||||
color: var(--primary-text-color);
|
||||
border-bottom-color: var(--divider-color);
|
||||
overflow: hidden;
|
||||
padding: 0 16px;
|
||||
text-align: var(--float-start);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.mdc-data-table__header-cell {
|
||||
background-color: var(--card-background-color);
|
||||
font-family: var(--ha-font-family-body);
|
||||
-moz-osx-font-smoothing: var(--ha-moz-osx-font-smoothing);
|
||||
-webkit-font-smoothing: var(--ha-font-smoothing);
|
||||
font-size: var(--ha-font-size-m);
|
||||
line-height: var(--ha-line-height-normal);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
letter-spacing: 0.0071428571em;
|
||||
text-decoration: inherit;
|
||||
text-transform: inherit;
|
||||
}
|
||||
.mdc-data-table__row:last-child .mdc-data-table__cell {
|
||||
border-bottom: none;
|
||||
}
|
||||
.mdc-data-table__row:not(.mdc-data-table__row--selected):hover {
|
||||
background-color: rgba(var(--rgb-primary-text-color), 0.04);
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.total .mdc-data-table__cell {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
}
|
||||
ha-card {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.card-header {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
.has-header {
|
||||
padding-top: 0;
|
||||
}
|
||||
.cell-bullet {
|
||||
width: 32px;
|
||||
padding-right: 0;
|
||||
padding-inline-end: 0;
|
||||
padding-inline-start: 16px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.bullet {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
height: 16px;
|
||||
width: 32px;
|
||||
}
|
||||
.mdc-data-table__cell--numeric {
|
||||
text-align: var(--float-end);
|
||||
direction: ltr;
|
||||
}
|
||||
.mdc-data-table__header-cell--numeric {
|
||||
text-align: var(--float-end);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -259,6 +259,16 @@ export class HuiEnergyUsageGraphCard
|
||||
from_battery?: string[];
|
||||
} = {};
|
||||
|
||||
const statLabels: {
|
||||
to_grid: Record<string, string>;
|
||||
from_grid: Record<string, string>;
|
||||
to_battery: Record<string, string>;
|
||||
} = {
|
||||
to_grid: {},
|
||||
from_grid: {},
|
||||
to_battery: {},
|
||||
};
|
||||
|
||||
for (const source of energyData.prefs.energy_sources) {
|
||||
if (source.type === "solar") {
|
||||
if (statIds.solar) {
|
||||
@@ -277,6 +287,12 @@ export class HuiEnergyUsageGraphCard
|
||||
statIds.to_battery = [source.stat_energy_to];
|
||||
statIds.from_battery = [source.stat_energy_from];
|
||||
}
|
||||
if (source.name) {
|
||||
statLabels.to_battery[source.stat_energy_to] = this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_charged",
|
||||
{ name: source.name }
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -291,6 +307,15 @@ export class HuiEnergyUsageGraphCard
|
||||
} else {
|
||||
statIds.from_grid = [gridSource.stat_energy_from];
|
||||
}
|
||||
if (gridSource.name) {
|
||||
statLabels.from_grid[gridSource.stat_energy_from] =
|
||||
gridSource.stat_energy_to
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.named_grid_consumed",
|
||||
{ name: gridSource.name }
|
||||
)
|
||||
: gridSource.name;
|
||||
}
|
||||
}
|
||||
if (gridSource.stat_energy_to) {
|
||||
if (statIds.to_grid) {
|
||||
@@ -298,6 +323,15 @@ export class HuiEnergyUsageGraphCard
|
||||
} else {
|
||||
statIds.to_grid = [gridSource.stat_energy_to];
|
||||
}
|
||||
if (gridSource.name) {
|
||||
statLabels.to_grid[gridSource.stat_energy_to] =
|
||||
gridSource.stat_energy_from
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.named_grid_exported",
|
||||
{ name: gridSource.name }
|
||||
)
|
||||
: gridSource.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +354,7 @@ export class HuiEnergyUsageGraphCard
|
||||
}
|
||||
});
|
||||
|
||||
const labels = {
|
||||
const typeLabels = {
|
||||
used_grid: this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.combined_from_grid"
|
||||
),
|
||||
@@ -354,7 +388,8 @@ export class HuiEnergyUsageGraphCard
|
||||
statIds,
|
||||
colorIndices,
|
||||
computedStyles,
|
||||
labels,
|
||||
typeLabels,
|
||||
statLabels,
|
||||
trackY,
|
||||
true
|
||||
)
|
||||
@@ -381,7 +416,8 @@ export class HuiEnergyUsageGraphCard
|
||||
statIds,
|
||||
colorIndices,
|
||||
computedStyles,
|
||||
labels,
|
||||
typeLabels,
|
||||
statLabels,
|
||||
trackY,
|
||||
false
|
||||
)
|
||||
@@ -415,11 +451,16 @@ export class HuiEnergyUsageGraphCard
|
||||
},
|
||||
colorIndices: Record<string, Record<string, number>>,
|
||||
computedStyles: CSSStyleDeclaration,
|
||||
labels: {
|
||||
typeLabels: {
|
||||
used_grid: string;
|
||||
used_solar: string;
|
||||
used_battery: string;
|
||||
},
|
||||
statLabels: {
|
||||
to_grid: Record<string, string>;
|
||||
from_grid: Record<string, string>;
|
||||
to_battery: Record<string, string>;
|
||||
},
|
||||
trackY: (v: number) => void,
|
||||
compare = false
|
||||
) {
|
||||
@@ -540,9 +581,10 @@ export class HuiEnergyUsageGraphCard
|
||||
type: "bar",
|
||||
cursor: "default",
|
||||
name:
|
||||
type in labels
|
||||
? labels[type]
|
||||
: getStatisticLabel(
|
||||
type in typeLabels
|
||||
? typeLabels[type]
|
||||
: statLabels[type]?.[statId] ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
statId,
|
||||
statisticsMetaData[statId]
|
||||
|
||||
@@ -61,10 +61,11 @@ export const securityEntityFilters: EntityFilter[] = [
|
||||
],
|
||||
entity_category: "none",
|
||||
},
|
||||
// We also want the tamper sensors when they are diagnostic
|
||||
// We also want the tamper and moisture sensors when they are diagnostic
|
||||
// (some integrations, e.g. homee, mark water leak alarms as diagnostic)
|
||||
{
|
||||
domain: "binary_sensor",
|
||||
device_class: ["tamper"],
|
||||
device_class: ["moisture", "tamper"],
|
||||
entity_category: "diagnostic",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1751,7 +1751,7 @@
|
||||
"no_areas_text_non_admin": "Ask an administrator to map your vacuum's segments to areas.",
|
||||
"configure_area_mapping": "Configure area mapping",
|
||||
"configure": "Configure",
|
||||
"clean_areas_order_hint": "Cleaning order may not be supported by your vacuum.",
|
||||
"clean_areas_order_hint": "The order in which areas are cleaned may not be supported by your vacuum.",
|
||||
"other_areas": "Other areas"
|
||||
},
|
||||
"person": {
|
||||
@@ -4115,6 +4115,7 @@
|
||||
"energy_from_helper": "Pick a sensor which measures grid import in either of {unit}.",
|
||||
"energy_to_grid": "Energy exported to grid",
|
||||
"energy_to_helper": "Pick a sensor which measures grid export in either of {unit}.",
|
||||
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
|
||||
"import_cost": "Cost tracking",
|
||||
"import_cost_para": "Select how Home Assistant should keep track of the costs of the imported energy.",
|
||||
"no_cost_tracking": "Do not track costs",
|
||||
@@ -4172,6 +4173,7 @@
|
||||
"dialog": {
|
||||
"header": "Configure solar panels",
|
||||
"entity_para": "Pick a sensor which measures solar production in either of {unit}.",
|
||||
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
|
||||
"solar_production_energy": "Solar production energy",
|
||||
"solar_production_power": "Solar production power",
|
||||
"solar_production_forecast": "Solar production forecast",
|
||||
@@ -4195,6 +4197,7 @@
|
||||
"energy_helper_out": "Pick a sensor that measures the electricity flowing out of the battery in either of {unit}.",
|
||||
"energy_into_battery": "Energy charged into the battery",
|
||||
"energy_out_of_battery": "Energy discharged from the battery",
|
||||
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
|
||||
"state_of_charge": "Battery state of charge sensor",
|
||||
"state_of_charge_helper": "Sensor reporting battery state of charge as %.",
|
||||
"power": "Battery power",
|
||||
@@ -8570,7 +8573,10 @@
|
||||
"total_usage": "+{num} kWh",
|
||||
"combined_from_grid": "Combined from grid",
|
||||
"consumed_solar": "Consumed solar",
|
||||
"consumed_battery": "Consumed battery"
|
||||
"consumed_battery": "Consumed battery",
|
||||
"named_battery_charged": "[%key:ui::panel::lovelace::cards::energy::energy_sources_table::named_battery_charged%]",
|
||||
"named_grid_consumed": "Consumed {name}",
|
||||
"named_grid_exported": "[%key:ui::panel::lovelace::cards::energy::energy_sources_table::named_grid_exported%]"
|
||||
},
|
||||
"energy_sources_table": {
|
||||
"grid_total": "Grid total",
|
||||
@@ -8583,7 +8589,11 @@
|
||||
"previous_energy": "Previous usage",
|
||||
"previous_cost": "Previous cost",
|
||||
"battery_total": "Battery total",
|
||||
"total_costs": "Total costs"
|
||||
"total_costs": "Total costs",
|
||||
"named_battery_charged": "{name} charged",
|
||||
"named_battery_discharged": "{name} discharged",
|
||||
"named_grid_imported": "{name} imported",
|
||||
"named_grid_exported": "{name} exported"
|
||||
},
|
||||
"energy_solar_graph": {
|
||||
"production": "Production {name}",
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
export const IFRAME_SANDBOX =
|
||||
"allow-forms allow-popups allow-pointer-lock allow-scripts allow-modals allow-downloads";
|
||||
"allow-forms allow-popups allow-pointer-lock allow-same-origin allow-scripts allow-modals allow-downloads";
|
||||
|
||||
Reference in New Issue
Block a user