Compare commits

...

2 Commits

Author SHA1 Message Date
Petar Petrov
93d92319b9 remove useless code 2026-01-08 15:45:20 +02:00
Petar Petrov
308721583d Add non standard power sensor support 2026-01-07 16:48:30 +02:00
4 changed files with 516 additions and 54 deletions

View File

@@ -131,9 +131,16 @@ export interface FlowToGridSourceEnergyPreference {
number_energy_price: number | null;
}
export interface PowerConfig {
stat_rate?: string; // Standard single sensor
stat_rate_inverted?: string; // Inverted single sensor
stat_rate_from?: string; // Battery: discharge / Grid: consumption
stat_rate_to?: string; // Battery: charge / Grid: return
}
export interface GridPowerSourceEnergyPreference {
// W meter
stat_rate: string;
power_config?: PowerConfig;
}
export interface GridSourceTypeEnergyPreference {
@@ -159,6 +166,7 @@ export interface BatterySourceTypeEnergyPreference {
stat_energy_from: string;
stat_energy_to: string;
stat_rate?: string;
power_config?: PowerConfig;
}
export interface GasSourceTypeEnergyPreference {
type: "gas";

View File

@@ -6,7 +6,13 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/entity/ha-statistic-picker";
import "../../../../components/ha-dialog";
import "../../../../components/ha-button";
import type { BatterySourceTypeEnergyPreference } from "../../../../data/energy";
import "../../../../components/ha-formfield";
import "../../../../components/ha-radio";
import type { HaRadio } from "../../../../components/ha-radio";
import type {
BatterySourceTypeEnergyPreference,
PowerConfig,
} from "../../../../data/energy";
import {
emptyBatteryEnergyPreference,
energyStatisticHelpUrl,
@@ -20,6 +26,8 @@ import type { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
const energyUnitClasses = ["energy"];
const powerUnitClasses = ["power"];
type PowerType = "none" | "standard" | "inverted" | "two_sensors";
@customElement("dialog-energy-battery-settings")
export class DialogEnergyBatterySettings
extends LitElement
@@ -31,6 +39,10 @@ export class DialogEnergyBatterySettings
@state() private _source?: BatterySourceTypeEnergyPreference;
@state() private _powerType: PowerType = "none";
@state() private _powerConfig: PowerConfig = {};
@state() private _energy_units?: string[];
@state() private _power_units?: string[];
@@ -48,12 +60,37 @@ export class DialogEnergyBatterySettings
this._source = params.source
? { ...params.source }
: emptyBatteryEnergyPreference();
// Initialize power type from existing config
if (params.source?.power_config) {
const pc = params.source.power_config;
this._powerConfig = { ...pc };
if (pc.stat_rate_inverted) {
this._powerType = "inverted";
} else if (pc.stat_rate_from || pc.stat_rate_to) {
this._powerType = "two_sensors";
} else if (pc.stat_rate) {
this._powerType = "standard";
} else {
this._powerType = "none";
}
} else if (params.source?.stat_rate) {
// Legacy format - treat as standard
this._powerType = "standard";
this._powerConfig = { stat_rate: params.source.stat_rate };
} else {
this._powerType = "none";
this._powerConfig = {};
}
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
this._power_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
).units;
// Build energy exclude list
const allSources: string[] = [];
this._params.battery_sources.forEach((entry) => {
allSources.push(entry.stat_energy_from);
@@ -64,16 +101,44 @@ export class DialogEnergyBatterySettings
id !== this._source?.stat_energy_from &&
id !== this._source?.stat_energy_to
);
this._excludeListPower = this._params.battery_sources
.map((entry) => entry.stat_rate)
.filter((id) => id && id !== this._source?.stat_rate) as string[];
// Build power exclude list
const powerIds: string[] = [];
this._params.battery_sources.forEach((entry) => {
if (entry.stat_rate) powerIds.push(entry.stat_rate);
if (entry.power_config) {
if (entry.power_config.stat_rate)
powerIds.push(entry.power_config.stat_rate);
if (entry.power_config.stat_rate_inverted)
powerIds.push(entry.power_config.stat_rate_inverted);
if (entry.power_config.stat_rate_from)
powerIds.push(entry.power_config.stat_rate_from);
if (entry.power_config.stat_rate_to)
powerIds.push(entry.power_config.stat_rate_to);
}
});
const currentPowerIds = [
this._powerConfig.stat_rate,
this._powerConfig.stat_rate_inverted,
this._powerConfig.stat_rate_from,
this._powerConfig.stat_rate_to,
params.source?.stat_rate,
].filter(Boolean) as string[];
this._excludeListPower = powerIds.filter(
(id) => !currentPowerIds.includes(id)
);
}
public closeDialog() {
this._params = undefined;
this._source = undefined;
this._powerType = "none";
this._powerConfig = {};
this._error = undefined;
this._excludeList = undefined;
this._excludeListPower = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
return true;
}
@@ -93,7 +158,7 @@ export class DialogEnergyBatterySettings
${this.hass.localize("ui.panel.config.energy.battery.dialog.header")}`}
@closed=${this.closeDialog}
>
${this._error ? html`<p class="error">${this._error}</p>` : ""}
${this._error ? html`<p class="error">${this._error}</p>` : nothing}
<ha-statistic-picker
.hass=${this.hass}
@@ -134,20 +199,126 @@ export class DialogEnergyBatterySettings
)}
></ha-statistic-picker>
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._source.stat_rate}
<p class="power-section-label">
${this.hass.localize(
"ui.panel.config.energy.battery.dialog.sensor_type"
)}
</p>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power"
"ui.panel.config.energy.battery.dialog.type_none"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._powerChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power_helper",
{ unit: this._power_units?.join(", ") || "" }
>
<ha-radio
value="none"
name="powerType"
.checked=${this._powerType === "none"}
@change=${this._handlePowerTypeChanged}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.type_standard"
)}
></ha-statistic-picker>
>
<ha-radio
value="standard"
name="powerType"
.checked=${this._powerType === "standard"}
@change=${this._handlePowerTypeChanged}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.type_inverted"
)}
>
<ha-radio
value="inverted"
name="powerType"
.checked=${this._powerType === "inverted"}
@change=${this._handlePowerTypeChanged}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.type_two_sensors"
)}
>
<ha-radio
value="two_sensors"
name="powerType"
.checked=${this._powerType === "two_sensors"}
@change=${this._handlePowerTypeChanged}
></ha-radio>
</ha-formfield>
${this._powerType === "standard"
? html`
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._powerConfig.stat_rate}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._standardPowerChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power_helper",
{ unit: this._power_units?.join(", ") || "" }
)}
></ha-statistic-picker>
`
: nothing}
${this._powerType === "inverted"
? html`
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._powerConfig.stat_rate_inverted}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._invertedPowerChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.type_inverted_description"
)}
></ha-statistic-picker>
`
: nothing}
${this._powerType === "two_sensors"
? html`
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._powerConfig.stat_rate_from}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power_discharge"
)}
.excludeStatistics=${[
...(this._excludeListPower || []),
this._powerConfig.stat_rate_to,
].filter((id): id is string => Boolean(id))}
@value-changed=${this._dischargePowerChanged}
></ha-statistic-picker>
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._powerConfig.stat_rate_to}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power_charge"
)}
.excludeStatistics=${[
...(this._excludeListPower || []),
this._powerConfig.stat_rate_from,
].filter((id): id is string => Boolean(id))}
@value-changed=${this._chargePowerChanged}
></ha-statistic-picker>
`
: nothing}
<ha-button
appearance="plain"
@@ -158,8 +329,7 @@ export class DialogEnergyBatterySettings
</ha-button>
<ha-button
@click=${this._save}
.disabled=${!this._source.stat_energy_from ||
!this._source.stat_energy_to}
.disabled=${!this._isValid()}
slot="primaryAction"
>
${this.hass.localize("ui.common.save")}
@@ -168,6 +338,29 @@ export class DialogEnergyBatterySettings
`;
}
private _isValid(): boolean {
// Energy fields are always required
if (!this._source?.stat_energy_from || !this._source?.stat_energy_to) {
return false;
}
// Power fields depend on selected type
switch (this._powerType) {
case "none":
return true;
case "standard":
return !!this._powerConfig.stat_rate;
case "inverted":
return !!this._powerConfig.stat_rate_inverted;
case "two_sensors":
return (
!!this._powerConfig.stat_rate_from && !!this._powerConfig.stat_rate_to
);
default:
return false;
}
}
private _statisticToChanged(ev: CustomEvent<{ value: string }>) {
this._source = { ...this._source!, stat_energy_to: ev.detail.value };
}
@@ -176,13 +369,53 @@ export class DialogEnergyBatterySettings
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
}
private _powerChanged(ev: CustomEvent<{ value: string }>) {
this._source = { ...this._source!, stat_rate: ev.detail.value };
private _handlePowerTypeChanged(ev: Event) {
const input = ev.currentTarget as HaRadio;
this._powerType = input.value as PowerType;
// Clear power config when switching types
this._powerConfig = {};
}
private _standardPowerChanged(ev: CustomEvent<{ value: string }>) {
this._powerConfig = {
stat_rate: ev.detail.value,
};
}
private _invertedPowerChanged(ev: CustomEvent<{ value: string }>) {
this._powerConfig = {
stat_rate_inverted: ev.detail.value,
};
}
private _dischargePowerChanged(ev: CustomEvent<{ value: string }>) {
this._powerConfig = {
...this._powerConfig,
stat_rate_from: ev.detail.value,
};
}
private _chargePowerChanged(ev: CustomEvent<{ value: string }>) {
this._powerConfig = {
...this._powerConfig,
stat_rate_to: ev.detail.value,
};
}
private async _save() {
try {
await this._params!.saveCallback(this._source!);
const source: BatterySourceTypeEnergyPreference = {
type: "battery",
stat_energy_from: this._source!.stat_energy_from,
stat_energy_to: this._source!.stat_energy_to,
};
// Only include power_config if a power type is selected
if (this._powerType !== "none") {
source.power_config = { ...this._powerConfig };
}
await this._params!.saveCallback(source);
this.closeDialog();
} catch (err: any) {
this._error = err.message;
@@ -204,6 +437,13 @@ export class DialogEnergyBatterySettings
ha-statistic-picker:last-of-type {
margin-bottom: 0;
}
ha-formfield {
display: block;
}
.power-section-label {
margin-top: var(--ha-space-4);
margin-bottom: var(--ha-space-2);
}
`,
];
}

View File

@@ -6,7 +6,10 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/entity/ha-statistic-picker";
import "../../../../components/ha-dialog";
import "../../../../components/ha-button";
import type { GridPowerSourceEnergyPreference } from "../../../../data/energy";
import "../../../../components/ha-formfield";
import "../../../../components/ha-radio";
import type { HaRadio } from "../../../../components/ha-radio";
import type { PowerConfig } from "../../../../data/energy";
import { energyStatisticHelpUrl } from "../../../../data/energy";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
@@ -16,6 +19,8 @@ import type { EnergySettingsGridPowerDialogParams } from "./show-dialogs-energy"
const powerUnitClasses = ["power"];
type SensorType = "standard" | "inverted" | "two_sensors";
@customElement("dialog-energy-grid-power-settings")
export class DialogEnergyGridPowerSettings
extends LitElement
@@ -25,7 +30,9 @@ export class DialogEnergyGridPowerSettings
@state() private _params?: EnergySettingsGridPowerDialogParams;
@state() private _source?: GridPowerSourceEnergyPreference;
@state() private _sensorType: SensorType = "standard";
@state() private _powerConfig: PowerConfig = {};
@state() private _power_units?: string[];
@@ -37,23 +44,65 @@ export class DialogEnergyGridPowerSettings
params: EnergySettingsGridPowerDialogParams
): Promise<void> {
this._params = params;
this._source = params.source ? { ...params.source } : { stat_rate: "" };
const initialSourceIdPower = this._source.stat_rate;
// Initialize from existing source
if (params.source?.power_config) {
const pc = params.source.power_config;
this._powerConfig = { ...pc };
if (pc.stat_rate_inverted) {
this._sensorType = "inverted";
} else if (pc.stat_rate_from || pc.stat_rate_to) {
this._sensorType = "two_sensors";
} else {
this._sensorType = "standard";
}
} else if (params.source?.stat_rate) {
// Legacy format - treat as standard
this._sensorType = "standard";
this._powerConfig = { stat_rate: params.source.stat_rate };
} else {
this._sensorType = "standard";
this._powerConfig = {};
}
this._power_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
).units;
this._excludeListPower = [
...(this._params.grid_source?.power?.map((entry) => entry.stat_rate) ||
[]),
].filter((id) => id && id !== initialSourceIdPower) as string[];
// Build exclude list from all power sources
const excludeIds: string[] = [];
this._params.grid_source?.power?.forEach((entry) => {
if (entry.stat_rate) excludeIds.push(entry.stat_rate);
if (entry.power_config) {
if (entry.power_config.stat_rate)
excludeIds.push(entry.power_config.stat_rate);
if (entry.power_config.stat_rate_inverted)
excludeIds.push(entry.power_config.stat_rate_inverted);
if (entry.power_config.stat_rate_from)
excludeIds.push(entry.power_config.stat_rate_from);
if (entry.power_config.stat_rate_to)
excludeIds.push(entry.power_config.stat_rate_to);
}
});
// Filter out current source's IDs
const currentIds = [
this._powerConfig.stat_rate,
this._powerConfig.stat_rate_inverted,
this._powerConfig.stat_rate_from,
this._powerConfig.stat_rate_to,
params.source?.stat_rate,
].filter(Boolean) as string[];
this._excludeListPower = excludeIds.filter(
(id) => !currentIds.includes(id)
);
}
public closeDialog() {
this._params = undefined;
this._source = undefined;
this._powerConfig = {};
this._sensorType = "standard";
this._error = undefined;
this._excludeListPower = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
@@ -61,7 +110,7 @@ export class DialogEnergyGridPowerSettings
}
protected render() {
if (!this._params || !this._source) {
if (!this._params) {
return nothing;
}
@@ -77,24 +126,123 @@ export class DialogEnergyGridPowerSettings
)}`}
@closed=${this.closeDialog}
>
${this._error ? html`<p class="error">${this._error}</p>` : ""}
${this._error ? html`<p class="error">${this._error}</p>` : nothing}
<ha-statistic-picker
.hass=${this.hass}
.helpMissingEntityUrl=${energyStatisticHelpUrl}
.includeUnitClass=${powerUnitClasses}
.value=${this._source.stat_rate}
<p>
${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.sensor_type"
)}
</p>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.power_stat"
"ui.panel.config.energy.grid.power_dialog.type_standard"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._powerStatisticChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.power_helper",
{ unit: this._power_units?.join(", ") || "" }
>
<ha-radio
value="standard"
name="sensorType"
.checked=${this._sensorType === "standard"}
@change=${this._handleSensorTypeChanged}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.type_inverted"
)}
dialogInitialFocus
></ha-statistic-picker>
>
<ha-radio
value="inverted"
name="sensorType"
.checked=${this._sensorType === "inverted"}
@change=${this._handleSensorTypeChanged}
></ha-radio>
</ha-formfield>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.type_two_sensors"
)}
>
<ha-radio
value="two_sensors"
name="sensorType"
.checked=${this._sensorType === "two_sensors"}
@change=${this._handleSensorTypeChanged}
></ha-radio>
</ha-formfield>
${this._sensorType === "standard"
? html`
<ha-statistic-picker
.hass=${this.hass}
.helpMissingEntityUrl=${energyStatisticHelpUrl}
.includeUnitClass=${powerUnitClasses}
.value=${this._powerConfig.stat_rate}
.label=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.power_stat"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._standardStatisticChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.power_helper",
{ unit: this._power_units?.join(", ") || "" }
)}
dialogInitialFocus
></ha-statistic-picker>
`
: nothing}
${this._sensorType === "inverted"
? html`
<ha-statistic-picker
.hass=${this.hass}
.helpMissingEntityUrl=${energyStatisticHelpUrl}
.includeUnitClass=${powerUnitClasses}
.value=${this._powerConfig.stat_rate_inverted}
.label=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.power_stat"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._invertedStatisticChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.type_inverted_description"
)}
dialogInitialFocus
></ha-statistic-picker>
`
: nothing}
${this._sensorType === "two_sensors"
? html`
<ha-statistic-picker
.hass=${this.hass}
.helpMissingEntityUrl=${energyStatisticHelpUrl}
.includeUnitClass=${powerUnitClasses}
.value=${this._powerConfig.stat_rate_from}
.label=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.power_from_grid"
)}
.excludeStatistics=${[
...(this._excludeListPower || []),
this._powerConfig.stat_rate_to,
].filter((id): id is string => Boolean(id))}
@value-changed=${this._fromStatisticChanged}
dialogInitialFocus
></ha-statistic-picker>
<ha-statistic-picker
.hass=${this.hass}
.helpMissingEntityUrl=${energyStatisticHelpUrl}
.includeUnitClass=${powerUnitClasses}
.value=${this._powerConfig.stat_rate_to}
.label=${this.hass.localize(
"ui.panel.config.energy.grid.power_dialog.power_to_grid"
)}
.excludeStatistics=${[
...(this._excludeListPower || []),
this._powerConfig.stat_rate_from,
].filter((id): id is string => Boolean(id))}
@value-changed=${this._toStatisticChanged}
></ha-statistic-picker>
`
: nothing}
<ha-button
appearance="plain"
@@ -105,7 +253,7 @@ export class DialogEnergyGridPowerSettings
</ha-button>
<ha-button
@click=${this._save}
.disabled=${!this._source.stat_rate}
.disabled=${!this._isValid()}
slot="primaryAction"
>
${this.hass.localize("ui.common.save")}
@@ -114,16 +262,61 @@ export class DialogEnergyGridPowerSettings
`;
}
private _powerStatisticChanged(ev: CustomEvent<{ value: string }>) {
this._source = {
...this._source!,
private _isValid(): boolean {
switch (this._sensorType) {
case "standard":
return !!this._powerConfig.stat_rate;
case "inverted":
return !!this._powerConfig.stat_rate_inverted;
case "two_sensors":
return (
!!this._powerConfig.stat_rate_from && !!this._powerConfig.stat_rate_to
);
default:
return false;
}
}
private _handleSensorTypeChanged(ev: Event) {
const input = ev.currentTarget as HaRadio;
this._sensorType = input.value as SensorType;
// Clear config when switching types
this._powerConfig = {};
}
private _standardStatisticChanged(ev: CustomEvent<{ value: string }>) {
this._powerConfig = {
stat_rate: ev.detail.value,
};
}
private _invertedStatisticChanged(ev: CustomEvent<{ value: string }>) {
this._powerConfig = {
stat_rate_inverted: ev.detail.value,
};
}
private _fromStatisticChanged(ev: CustomEvent<{ value: string }>) {
this._powerConfig = {
...this._powerConfig,
stat_rate_from: ev.detail.value,
};
}
private _toStatisticChanged(ev: CustomEvent<{ value: string }>) {
this._powerConfig = {
...this._powerConfig,
stat_rate_to: ev.detail.value,
};
}
private async _save() {
try {
await this._params!.saveCallback(this._source!);
const source = {
stat_rate: "", // will be overridden but needed to satisfy typescript
power_config: { ...this._powerConfig },
};
await this._params!.saveCallback(source);
this.closeDialog();
} catch (err: any) {
this._error = err.message;
@@ -137,9 +330,15 @@ export class DialogEnergyGridPowerSettings
ha-dialog {
--mdc-dialog-max-width: 430px;
}
ha-formfield {
display: block;
}
ha-statistic-picker {
display: block;
margin: var(--ha-space-4) 0;
margin-top: var(--ha-space-4);
}
p {
margin-bottom: var(--ha-space-2);
}
`,
];

View File

@@ -3154,8 +3154,15 @@
"delete_power": "Delete power sensor",
"power_dialog": {
"header": "Configure grid power",
"sensor_type": "Sensor type",
"type_standard": "Standard",
"type_inverted": "Inverted",
"type_inverted_description": "Positive values indicate exporting to the grid, negative values indicate importing from the grid.",
"type_two_sensors": "Two sensors",
"power_stat": "Power sensor",
"power_helper": "Pick a sensor which measures grid power in either of {unit}. Positive values indicate importing electricity from the grid, negative values indicate exporting electricity to the grid."
"power_helper": "Pick a sensor which measures grid power in either of {unit}. Positive values indicate importing electricity from the grid, negative values indicate exporting electricity to the grid.",
"power_from_grid": "Power from grid",
"power_to_grid": "Power to grid"
},
"flow_dialog": {
"cost_entity_helper": "Any sensor with a unit of `{currency}/(valid energy unit)` (e.g. `{currency}/Wh` or `{currency}/kWh`) may be used and will be automatically converted.",
@@ -3227,7 +3234,15 @@
"energy_into_battery": "Energy charged into the battery",
"energy_out_of_battery": "Energy discharged from the battery",
"power": "Battery power",
"power_helper": "Pick a sensor which measures the electricity flowing into and out of the battery in either of {unit}. Positive values indicate discharging the battery, negative values indicate charging the battery."
"power_helper": "Pick a sensor which measures the electricity flowing into and out of the battery in either of {unit}. Positive values indicate discharging the battery, negative values indicate charging the battery.",
"sensor_type": "Power sensor type",
"type_none": "No power sensor",
"type_standard": "Standard",
"type_inverted": "Inverted",
"type_inverted_description": "Positive values indicate charging, negative values indicate discharging.",
"type_two_sensors": "Two sensors",
"power_discharge": "Discharge power",
"power_charge": "Charge power"
}
},
"gas": {