Refactor energy validation issue reporting (#85523)
* Refactor energy validation issue reporting * Update English translations * Adjust translations
This commit is contained in:
parent
e4e96d3394
commit
8418a30cc0
4 changed files with 311 additions and 173 deletions
|
@ -1,3 +1,61 @@
|
|||
{
|
||||
"title": "Energy"
|
||||
"title": "Energy",
|
||||
"issues": {
|
||||
"entity_not_defined": {
|
||||
"title": "Entity not defined",
|
||||
"description": "Check the integration or your configuration that provides:"
|
||||
},
|
||||
"recorder_untracked": {
|
||||
"title": "Entity not tracked",
|
||||
"description": "The recorder has been configured to exclude these configured entities:"
|
||||
},
|
||||
"entity_unavailable": {
|
||||
"title": "Entity unavailable",
|
||||
"description": "The state of these configured entities are currently not available:"
|
||||
},
|
||||
"entity_state_non_numeric": {
|
||||
"title": "Entity has non-numeric state",
|
||||
"description": "The following entities have a state that cannot be parsed as a number:"
|
||||
},
|
||||
"entity_negative_state": {
|
||||
"title": "Entity has a negative state",
|
||||
"description": "The following entities have a negative state while a positive state is expected:"
|
||||
},
|
||||
"entity_unexpected_unit_energy": {
|
||||
"title": "Unexpected unit of measurement",
|
||||
"description": "The following entities do not have an expected unit of measurement (either of {energy_units}):"
|
||||
},
|
||||
"entity_unexpected_unit_gas": {
|
||||
"title": "[%key:component::energy::issues::entity_unexpected_unit_energy::title%]",
|
||||
"description": "The following entities do not have an expected unit of measurement (either of {energy_units} for an energy sensor or either of {gas_units} for a gas sensor:)"
|
||||
},
|
||||
"entity_unexpected_unit_water": {
|
||||
"title": "[%key:component::energy::issues::entity_unexpected_unit_energy::title%]",
|
||||
"description": "The following entities do not have the expected unit of measurement (either of {water_units}):"
|
||||
},
|
||||
"entity_unexpected_unit_energy_price": {
|
||||
"title": "[%key:component::energy::issues::entity_unexpected_unit_energy::title%]",
|
||||
"description": "The following entities do not have an expected unit of measurement {price_units}:"
|
||||
},
|
||||
"entity_unexpected_unit_gas_price": {
|
||||
"title": "[%key:component::energy::issues::entity_unexpected_unit_energy_price::title%]",
|
||||
"description": "[%key:component::energy::issues::entity_unexpected_unit_energy::description%]"
|
||||
},
|
||||
"entity_unexpected_unit_water_price": {
|
||||
"title": "[%key:component::energy::issues::entity_unexpected_unit_energy::title%]",
|
||||
"description": "[%key:component::energy::issues::entity_unexpected_unit_energy::description%]"
|
||||
},
|
||||
"entity_unexpected_state_class": {
|
||||
"title": "Unexpected state class",
|
||||
"description": "The following entities do not have the expected state class:"
|
||||
},
|
||||
"entity_unexpected_device_class": {
|
||||
"title": "Unexpected device class",
|
||||
"description": "The following entities do not have the expected device 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:"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,61 @@
|
|||
{
|
||||
"issues": {
|
||||
"entity_negative_state": {
|
||||
"description": "The following entities have a negative state while a positive state is expected:",
|
||||
"title": "Entity has a negative state"
|
||||
},
|
||||
"entity_not_defined": {
|
||||
"description": "Check the integration or your configuration that provides:",
|
||||
"title": "Entity not defined"
|
||||
},
|
||||
"entity_state_class_measurement_no_last_reset": {
|
||||
"description": "The following entities have state class 'measurement' but 'last_reset' is missing:",
|
||||
"title": "Last reset missing"
|
||||
},
|
||||
"entity_state_non_numeric": {
|
||||
"description": "The following entities have a state that cannot be parsed as a number:",
|
||||
"title": "Entity has non-numeric state"
|
||||
},
|
||||
"entity_unavailable": {
|
||||
"description": "The state of these configured entities are currently not available:",
|
||||
"title": "Entity unavailable"
|
||||
},
|
||||
"entity_unexpected_device_class": {
|
||||
"description": "The following entities do not have the expected device class:",
|
||||
"title": "Unexpected device class"
|
||||
},
|
||||
"entity_unexpected_state_class": {
|
||||
"description": "The following entities do not have the expected state class:",
|
||||
"title": "Unexpected state class"
|
||||
},
|
||||
"entity_unexpected_unit_energy": {
|
||||
"description": "The following entities do not have an expected unit of measurement (either of {energy_units}):",
|
||||
"title": "Unexpected unit of measurement"
|
||||
},
|
||||
"entity_unexpected_unit_energy_price": {
|
||||
"description": "The following entities do not have an expected unit of measurement {price_units}:",
|
||||
"title": "Unexpected unit of measurement"
|
||||
},
|
||||
"entity_unexpected_unit_gas": {
|
||||
"description": "The following entities do not have an expected unit of measurement (either of {energy_units} for an energy sensor or either of {gas_units} for a gas sensor:)",
|
||||
"title": "Unexpected unit of measurement"
|
||||
},
|
||||
"entity_unexpected_unit_gas_price": {
|
||||
"description": "The following entities do not have an expected unit of measurement (either of {energy_units}):",
|
||||
"title": "Unexpected unit of measurement"
|
||||
},
|
||||
"entity_unexpected_unit_water": {
|
||||
"description": "The following entities do not have the expected unit of measurement (either of {water_units}):",
|
||||
"title": "Unexpected unit of measurement"
|
||||
},
|
||||
"entity_unexpected_unit_water_price": {
|
||||
"description": "The following entities do not have an expected unit of measurement (either of {energy_units}):",
|
||||
"title": "Unexpected unit of measurement"
|
||||
},
|
||||
"recorder_untracked": {
|
||||
"description": "The recorder has been configured to exclude these configured entities:",
|
||||
"title": "Entity not tracked"
|
||||
}
|
||||
},
|
||||
"title": "Energy"
|
||||
}
|
|
@ -4,7 +4,6 @@ from __future__ import annotations
|
|||
from collections.abc import Mapping, Sequence
|
||||
import dataclasses
|
||||
import functools
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components import recorder, sensor
|
||||
from homeassistant.const import (
|
||||
|
@ -72,29 +71,94 @@ WATER_UNIT_ERROR = "entity_unexpected_unit_water"
|
|||
WATER_PRICE_UNIT_ERROR = "entity_unexpected_unit_water_price"
|
||||
|
||||
|
||||
def _get_placeholders(hass: HomeAssistant, issue_type: str) -> dict[str, str] | None:
|
||||
currency = hass.config.currency
|
||||
if issue_type == ENERGY_UNIT_ERROR:
|
||||
return {
|
||||
"energy_units": ", ".join(
|
||||
ENERGY_USAGE_UNITS[sensor.SensorDeviceClass.ENERGY]
|
||||
),
|
||||
}
|
||||
if issue_type == ENERGY_PRICE_UNIT_ERROR:
|
||||
return {
|
||||
"price_units": ", ".join(
|
||||
f"{currency}{unit}" for unit in ENERGY_PRICE_UNITS
|
||||
),
|
||||
}
|
||||
if issue_type == GAS_UNIT_ERROR:
|
||||
return {
|
||||
"energy_units": ", ".join(GAS_USAGE_UNITS[sensor.SensorDeviceClass.ENERGY]),
|
||||
"gas_units": ", ".join(GAS_USAGE_UNITS[sensor.SensorDeviceClass.GAS]),
|
||||
}
|
||||
if issue_type == GAS_PRICE_UNIT_ERROR:
|
||||
return {
|
||||
"price_units": ", ".join(f"{currency}{unit}" for unit in GAS_PRICE_UNITS),
|
||||
}
|
||||
if issue_type == WATER_UNIT_ERROR:
|
||||
return {
|
||||
"water_units": ", ".join(WATER_USAGE_UNITS[sensor.SensorDeviceClass.WATER]),
|
||||
}
|
||||
if issue_type == WATER_PRICE_UNIT_ERROR:
|
||||
return {
|
||||
"price_units": ", ".join(f"{currency}{unit}" for unit in WATER_PRICE_UNITS),
|
||||
}
|
||||
return None
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class ValidationIssue:
|
||||
"""Error or warning message."""
|
||||
|
||||
type: str
|
||||
identifier: str
|
||||
value: Any | None = None
|
||||
affected_entities: set[tuple[str, float | str | None]] = dataclasses.field(
|
||||
default_factory=set
|
||||
)
|
||||
translation_placeholders: dict[str, str] | None = None
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class ValidationIssues:
|
||||
"""Container for validation issues."""
|
||||
|
||||
issues: dict[str, ValidationIssue] = dataclasses.field(default_factory=dict)
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Container for validiation issues."""
|
||||
self.issues = {}
|
||||
|
||||
def add_issue(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
issue_type: str,
|
||||
affected_entity: str,
|
||||
detail: float | str | None = None,
|
||||
) -> None:
|
||||
"""Add an issue for an entity."""
|
||||
if not (issue := self.issues.get(issue_type)):
|
||||
self.issues[issue_type] = issue = ValidationIssue(issue_type)
|
||||
issue.translation_placeholders = _get_placeholders(hass, issue_type)
|
||||
issue.affected_entities.add((affected_entity, detail))
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class EnergyPreferencesValidation:
|
||||
"""Dictionary holding validation information."""
|
||||
|
||||
energy_sources: list[list[ValidationIssue]] = dataclasses.field(
|
||||
default_factory=list
|
||||
)
|
||||
device_consumption: list[list[ValidationIssue]] = dataclasses.field(
|
||||
default_factory=list
|
||||
)
|
||||
energy_sources: list[ValidationIssues] = dataclasses.field(default_factory=list)
|
||||
device_consumption: list[ValidationIssues] = dataclasses.field(default_factory=list)
|
||||
|
||||
def as_dict(self) -> dict:
|
||||
"""Return dictionary version."""
|
||||
return dataclasses.asdict(self)
|
||||
return {
|
||||
"energy_sources": [
|
||||
[dataclasses.asdict(issue) for issue in issues.issues.values()]
|
||||
for issues in self.energy_sources
|
||||
],
|
||||
"device_consumption": [
|
||||
[dataclasses.asdict(issue) for issue in issues.issues.values()]
|
||||
for issues in self.device_consumption
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@callback
|
||||
|
@ -105,11 +169,11 @@ def _async_validate_usage_stat(
|
|||
allowed_device_classes: Sequence[str],
|
||||
allowed_units: Mapping[str, Sequence[str]],
|
||||
unit_error: str,
|
||||
result: list[ValidationIssue],
|
||||
issues: ValidationIssues,
|
||||
) -> None:
|
||||
"""Validate a statistic."""
|
||||
if stat_id not in metadata:
|
||||
result.append(ValidationIssue("statistics_not_defined", stat_id))
|
||||
issues.add_issue(hass, "statistics_not_defined", stat_id)
|
||||
|
||||
has_entity_source = valid_entity_id(stat_id)
|
||||
|
||||
|
@ -119,54 +183,36 @@ def _async_validate_usage_stat(
|
|||
entity_id = stat_id
|
||||
|
||||
if not recorder.is_entity_recorded(hass, entity_id):
|
||||
result.append(
|
||||
ValidationIssue(
|
||||
"recorder_untracked",
|
||||
entity_id,
|
||||
)
|
||||
)
|
||||
issues.add_issue(hass, "recorder_untracked", entity_id)
|
||||
return
|
||||
|
||||
if (state := hass.states.get(entity_id)) is None:
|
||||
result.append(
|
||||
ValidationIssue(
|
||||
"entity_not_defined",
|
||||
entity_id,
|
||||
)
|
||||
)
|
||||
issues.add_issue(hass, "entity_not_defined", entity_id)
|
||||
return
|
||||
|
||||
if state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN):
|
||||
result.append(ValidationIssue("entity_unavailable", entity_id, state.state))
|
||||
issues.add_issue(hass, "entity_unavailable", entity_id, state.state)
|
||||
return
|
||||
|
||||
try:
|
||||
current_value: float | None = float(state.state)
|
||||
except ValueError:
|
||||
result.append(
|
||||
ValidationIssue("entity_state_non_numeric", entity_id, state.state)
|
||||
)
|
||||
issues.add_issue(hass, "entity_state_non_numeric", entity_id, state.state)
|
||||
return
|
||||
|
||||
if current_value is not None and current_value < 0:
|
||||
result.append(
|
||||
ValidationIssue("entity_negative_state", entity_id, current_value)
|
||||
)
|
||||
issues.add_issue(hass, "entity_negative_state", entity_id, current_value)
|
||||
|
||||
device_class = state.attributes.get(ATTR_DEVICE_CLASS)
|
||||
if device_class not in allowed_device_classes:
|
||||
result.append(
|
||||
ValidationIssue(
|
||||
"entity_unexpected_device_class",
|
||||
entity_id,
|
||||
device_class,
|
||||
)
|
||||
issues.add_issue(
|
||||
hass, "entity_unexpected_device_class", entity_id, device_class
|
||||
)
|
||||
else:
|
||||
unit = state.attributes.get("unit_of_measurement")
|
||||
|
||||
if device_class and unit not in allowed_units.get(device_class, []):
|
||||
result.append(ValidationIssue(unit_error, entity_id, unit))
|
||||
issues.add_issue(hass, unit_error, entity_id, unit)
|
||||
|
||||
state_class = state.attributes.get(sensor.ATTR_STATE_CLASS)
|
||||
|
||||
|
@ -176,20 +222,14 @@ def _async_validate_usage_stat(
|
|||
sensor.SensorStateClass.TOTAL_INCREASING,
|
||||
]
|
||||
if state_class not in allowed_state_classes:
|
||||
result.append(
|
||||
ValidationIssue(
|
||||
"entity_unexpected_state_class",
|
||||
entity_id,
|
||||
state_class,
|
||||
)
|
||||
)
|
||||
issues.add_issue(hass, "entity_unexpected_state_class", entity_id, state_class)
|
||||
|
||||
if (
|
||||
state_class == sensor.SensorStateClass.MEASUREMENT
|
||||
and sensor.ATTR_LAST_RESET not in state.attributes
|
||||
):
|
||||
result.append(
|
||||
ValidationIssue("entity_state_class_measurement_no_last_reset", entity_id)
|
||||
issues.add_issue(
|
||||
hass, "entity_state_class_measurement_no_last_reset", entity_id
|
||||
)
|
||||
|
||||
|
||||
|
@ -197,32 +237,25 @@ def _async_validate_usage_stat(
|
|||
def _async_validate_price_entity(
|
||||
hass: HomeAssistant,
|
||||
entity_id: str,
|
||||
result: list[ValidationIssue],
|
||||
issues: ValidationIssues,
|
||||
allowed_units: tuple[str, ...],
|
||||
unit_error: str,
|
||||
) -> None:
|
||||
"""Validate that the price entity is correct."""
|
||||
if (state := hass.states.get(entity_id)) is None:
|
||||
result.append(
|
||||
ValidationIssue(
|
||||
"entity_not_defined",
|
||||
entity_id,
|
||||
)
|
||||
)
|
||||
issues.add_issue(hass, "entity_not_defined", entity_id)
|
||||
return
|
||||
|
||||
try:
|
||||
float(state.state)
|
||||
except ValueError:
|
||||
result.append(
|
||||
ValidationIssue("entity_state_non_numeric", entity_id, state.state)
|
||||
)
|
||||
issues.add_issue(hass, "entity_state_non_numeric", entity_id, state.state)
|
||||
return
|
||||
|
||||
unit = state.attributes.get("unit_of_measurement")
|
||||
|
||||
if unit is None or not unit.endswith(allowed_units):
|
||||
result.append(ValidationIssue(unit_error, entity_id, unit))
|
||||
issues.add_issue(hass, unit_error, entity_id, unit)
|
||||
|
||||
|
||||
@callback
|
||||
|
@ -230,11 +263,11 @@ def _async_validate_cost_stat(
|
|||
hass: HomeAssistant,
|
||||
metadata: dict[str, tuple[int, recorder.models.StatisticMetaData]],
|
||||
stat_id: str,
|
||||
result: list[ValidationIssue],
|
||||
issues: ValidationIssues,
|
||||
) -> None:
|
||||
"""Validate that the cost stat is correct."""
|
||||
if stat_id not in metadata:
|
||||
result.append(ValidationIssue("statistics_not_defined", stat_id))
|
||||
issues.add_issue(hass, "statistics_not_defined", stat_id)
|
||||
|
||||
has_entity = valid_entity_id(stat_id)
|
||||
|
||||
|
@ -242,10 +275,10 @@ def _async_validate_cost_stat(
|
|||
return
|
||||
|
||||
if not recorder.is_entity_recorded(hass, stat_id):
|
||||
result.append(ValidationIssue("recorder_untracked", stat_id))
|
||||
issues.add_issue(hass, "recorder_untracked", stat_id)
|
||||
|
||||
if (state := hass.states.get(stat_id)) is None:
|
||||
result.append(ValidationIssue("entity_not_defined", stat_id))
|
||||
issues.add_issue(hass, "entity_not_defined", stat_id)
|
||||
return
|
||||
|
||||
state_class = state.attributes.get("state_class")
|
||||
|
@ -256,22 +289,18 @@ def _async_validate_cost_stat(
|
|||
sensor.SensorStateClass.TOTAL_INCREASING,
|
||||
]
|
||||
if state_class not in supported_state_classes:
|
||||
result.append(
|
||||
ValidationIssue("entity_unexpected_state_class", stat_id, state_class)
|
||||
)
|
||||
issues.add_issue(hass, "entity_unexpected_state_class", stat_id, state_class)
|
||||
|
||||
if (
|
||||
state_class == sensor.SensorStateClass.MEASUREMENT
|
||||
and sensor.ATTR_LAST_RESET not in state.attributes
|
||||
):
|
||||
result.append(
|
||||
ValidationIssue("entity_state_class_measurement_no_last_reset", stat_id)
|
||||
)
|
||||
issues.add_issue(hass, "entity_state_class_measurement_no_last_reset", stat_id)
|
||||
|
||||
|
||||
@callback
|
||||
def _async_validate_auto_generated_cost_entity(
|
||||
hass: HomeAssistant, energy_entity_id: str, result: list[ValidationIssue]
|
||||
hass: HomeAssistant, energy_entity_id: str, issues: ValidationIssues
|
||||
) -> None:
|
||||
"""Validate that the auto generated cost entity is correct."""
|
||||
if energy_entity_id not in hass.data[DOMAIN]["cost_sensors"]:
|
||||
|
@ -280,7 +309,7 @@ def _async_validate_auto_generated_cost_entity(
|
|||
|
||||
cost_entity_id = hass.data[DOMAIN]["cost_sensors"][energy_entity_id]
|
||||
if not recorder.is_entity_recorded(hass, cost_entity_id):
|
||||
result.append(ValidationIssue("recorder_untracked", cost_entity_id))
|
||||
issues.add_issue(hass, "recorder_untracked", cost_entity_id)
|
||||
|
||||
|
||||
async def async_validate(hass: HomeAssistant) -> EnergyPreferencesValidation:
|
||||
|
@ -297,7 +326,7 @@ async def async_validate(hass: HomeAssistant) -> EnergyPreferencesValidation:
|
|||
|
||||
# Create a list of validation checks
|
||||
for source in manager.data["energy_sources"]:
|
||||
source_result: list[ValidationIssue] = []
|
||||
source_result = ValidationIssues()
|
||||
result.energy_sources.append(source_result)
|
||||
|
||||
if source["type"] == "grid":
|
||||
|
@ -550,7 +579,7 @@ async def async_validate(hass: HomeAssistant) -> EnergyPreferencesValidation:
|
|||
)
|
||||
|
||||
for device in manager.data["device_consumption"]:
|
||||
device_result: list[ValidationIssue] = []
|
||||
device_result = ValidationIssues()
|
||||
result.device_consumption.append(device_result)
|
||||
wanted_statistics_metadata.add(device["stat_consumption"])
|
||||
validate_calls.append(
|
||||
|
|
|
@ -118,13 +118,13 @@ async def test_validation_device_consumption_entity_missing(hass, mock_energy_ma
|
|||
[
|
||||
{
|
||||
"type": "statistics_not_defined",
|
||||
"identifier": "sensor.not_exist",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.not_exist", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
{
|
||||
"type": "entity_not_defined",
|
||||
"identifier": "sensor.not_exist",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.not_exist", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
]
|
||||
],
|
||||
|
@ -142,8 +142,8 @@ async def test_validation_device_consumption_stat_missing(hass, mock_energy_mana
|
|||
[
|
||||
{
|
||||
"type": "statistics_not_defined",
|
||||
"identifier": "external:not_exist",
|
||||
"value": None,
|
||||
"affected_entities": {("external:not_exist", None)},
|
||||
"translation_placeholders": None,
|
||||
}
|
||||
]
|
||||
],
|
||||
|
@ -165,8 +165,8 @@ async def test_validation_device_consumption_entity_unavailable(
|
|||
[
|
||||
{
|
||||
"type": "entity_unavailable",
|
||||
"identifier": "sensor.unavailable",
|
||||
"value": "unavailable",
|
||||
"affected_entities": {("sensor.unavailable", "unavailable")},
|
||||
"translation_placeholders": None,
|
||||
}
|
||||
]
|
||||
],
|
||||
|
@ -188,8 +188,8 @@ async def test_validation_device_consumption_entity_non_numeric(
|
|||
[
|
||||
{
|
||||
"type": "entity_state_non_numeric",
|
||||
"identifier": "sensor.non_numeric",
|
||||
"value": "123,123.10",
|
||||
"affected_entities": {("sensor.non_numeric", "123,123.10")},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
]
|
||||
],
|
||||
|
@ -219,8 +219,8 @@ async def test_validation_device_consumption_entity_unexpected_unit(
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy",
|
||||
"identifier": "sensor.unexpected_unit",
|
||||
"value": "beers",
|
||||
"affected_entities": {("sensor.unexpected_unit", "beers")},
|
||||
"translation_placeholders": {"energy_units": "GJ, kWh, MWh, Wh"},
|
||||
}
|
||||
]
|
||||
],
|
||||
|
@ -242,8 +242,8 @@ async def test_validation_device_consumption_recorder_not_tracked(
|
|||
[
|
||||
{
|
||||
"type": "recorder_untracked",
|
||||
"identifier": "sensor.not_recorded",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.not_recorded", None)},
|
||||
"translation_placeholders": None,
|
||||
}
|
||||
]
|
||||
],
|
||||
|
@ -273,8 +273,8 @@ async def test_validation_device_consumption_no_last_reset(
|
|||
[
|
||||
{
|
||||
"type": "entity_state_class_measurement_no_last_reset",
|
||||
"identifier": "sensor.no_last_reset",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.no_last_reset", None)},
|
||||
"translation_placeholders": None,
|
||||
}
|
||||
]
|
||||
],
|
||||
|
@ -305,8 +305,8 @@ async def test_validation_solar(hass, mock_energy_manager, mock_get_metadata):
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy",
|
||||
"identifier": "sensor.solar_production",
|
||||
"value": "beers",
|
||||
"affected_entities": {("sensor.solar_production", "beers")},
|
||||
"translation_placeholders": {"energy_units": "GJ, kWh, MWh, Wh"},
|
||||
}
|
||||
]
|
||||
],
|
||||
|
@ -351,13 +351,11 @@ async def test_validation_battery(hass, mock_energy_manager, mock_get_metadata):
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy",
|
||||
"identifier": "sensor.battery_import",
|
||||
"value": "beers",
|
||||
},
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy",
|
||||
"identifier": "sensor.battery_export",
|
||||
"value": "beers",
|
||||
"affected_entities": {
|
||||
("sensor.battery_import", "beers"),
|
||||
("sensor.battery_export", "beers"),
|
||||
},
|
||||
"translation_placeholders": {"energy_units": "GJ, kWh, MWh, Wh"},
|
||||
},
|
||||
]
|
||||
],
|
||||
|
@ -422,43 +420,35 @@ async def test_validation_grid(
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy",
|
||||
"identifier": "sensor.grid_consumption_1",
|
||||
"value": "beers",
|
||||
"affected_entities": {
|
||||
("sensor.grid_consumption_1", "beers"),
|
||||
("sensor.grid_production_1", "beers"),
|
||||
},
|
||||
"translation_placeholders": {"energy_units": "GJ, kWh, MWh, Wh"},
|
||||
},
|
||||
{
|
||||
"type": "statistics_not_defined",
|
||||
"identifier": "sensor.grid_cost_1",
|
||||
"value": None,
|
||||
"affected_entities": {
|
||||
("sensor.grid_cost_1", None),
|
||||
("sensor.grid_compensation_1", None),
|
||||
},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
{
|
||||
"type": "recorder_untracked",
|
||||
"identifier": "sensor.grid_cost_1",
|
||||
"value": None,
|
||||
"affected_entities": {
|
||||
("sensor.grid_cost_1", None),
|
||||
("sensor.grid_compensation_1", None),
|
||||
},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
{
|
||||
"type": "entity_not_defined",
|
||||
"identifier": "sensor.grid_cost_1",
|
||||
"value": None,
|
||||
},
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy",
|
||||
"identifier": "sensor.grid_production_1",
|
||||
"value": "beers",
|
||||
},
|
||||
{
|
||||
"type": "statistics_not_defined",
|
||||
"identifier": "sensor.grid_compensation_1",
|
||||
"value": None,
|
||||
},
|
||||
{
|
||||
"type": "recorder_untracked",
|
||||
"identifier": "sensor.grid_compensation_1",
|
||||
"value": None,
|
||||
},
|
||||
{
|
||||
"type": "entity_not_defined",
|
||||
"identifier": "sensor.grid_compensation_1",
|
||||
"value": None,
|
||||
"affected_entities": {
|
||||
("sensor.grid_cost_1", None),
|
||||
("sensor.grid_compensation_1", None),
|
||||
},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
]
|
||||
],
|
||||
|
@ -517,23 +507,19 @@ async def test_validation_grid_external_cost_compensation(
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy",
|
||||
"identifier": "sensor.grid_consumption_1",
|
||||
"value": "beers",
|
||||
"affected_entities": {
|
||||
("sensor.grid_consumption_1", "beers"),
|
||||
("sensor.grid_production_1", "beers"),
|
||||
},
|
||||
"translation_placeholders": {"energy_units": "GJ, kWh, MWh, Wh"},
|
||||
},
|
||||
{
|
||||
"type": "statistics_not_defined",
|
||||
"identifier": "external:grid_cost_1",
|
||||
"value": None,
|
||||
},
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy",
|
||||
"identifier": "sensor.grid_production_1",
|
||||
"value": "beers",
|
||||
},
|
||||
{
|
||||
"type": "statistics_not_defined",
|
||||
"identifier": "external:grid_compensation_1",
|
||||
"value": None,
|
||||
"affected_entities": {
|
||||
("external:grid_cost_1", None),
|
||||
("external:grid_compensation_1", None),
|
||||
},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
]
|
||||
],
|
||||
|
@ -599,18 +585,16 @@ async def test_validation_grid_price_not_exist(
|
|||
[
|
||||
{
|
||||
"type": "entity_not_defined",
|
||||
"identifier": "sensor.grid_price_1",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.grid_price_1", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
{
|
||||
"type": "recorder_untracked",
|
||||
"identifier": "sensor.grid_consumption_1_cost",
|
||||
"value": None,
|
||||
},
|
||||
{
|
||||
"type": "recorder_untracked",
|
||||
"identifier": "sensor.grid_production_1_compensation",
|
||||
"value": None,
|
||||
"affected_entities": {
|
||||
("sensor.grid_consumption_1_cost", None),
|
||||
("sensor.grid_production_1_compensation", None),
|
||||
},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
]
|
||||
],
|
||||
|
@ -683,8 +667,8 @@ async def test_validation_grid_auto_cost_entity_errors(
|
|||
"$/kWh",
|
||||
{
|
||||
"type": "entity_state_non_numeric",
|
||||
"identifier": "sensor.grid_price_1",
|
||||
"value": "123,123.12",
|
||||
"affected_entities": {("sensor.grid_price_1", "123,123.12")},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
),
|
||||
(
|
||||
|
@ -692,8 +676,10 @@ async def test_validation_grid_auto_cost_entity_errors(
|
|||
"$/Ws",
|
||||
{
|
||||
"type": "entity_unexpected_unit_energy_price",
|
||||
"identifier": "sensor.grid_price_1",
|
||||
"value": "$/Ws",
|
||||
"affected_entities": {("sensor.grid_price_1", "$/Ws")},
|
||||
"translation_placeholders": {
|
||||
"price_units": "EUR/GJ, EUR/kWh, EUR/MWh, EUR/Wh"
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -834,18 +820,21 @@ async def test_validation_gas(
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_gas",
|
||||
"identifier": "sensor.gas_consumption_1",
|
||||
"value": "beers",
|
||||
"affected_entities": {("sensor.gas_consumption_1", "beers")},
|
||||
"translation_placeholders": {
|
||||
"energy_units": "GJ, kWh, MWh, Wh",
|
||||
"gas_units": "CCF, ft³, m³",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "recorder_untracked",
|
||||
"identifier": "sensor.gas_cost_1",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.gas_cost_1", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
{
|
||||
"type": "entity_not_defined",
|
||||
"identifier": "sensor.gas_cost_1",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.gas_cost_1", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
],
|
||||
[],
|
||||
|
@ -853,15 +842,17 @@ async def test_validation_gas(
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_device_class",
|
||||
"identifier": "sensor.gas_consumption_4",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.gas_consumption_4", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_gas_price",
|
||||
"identifier": "sensor.gas_price_2",
|
||||
"value": "EUR/invalid",
|
||||
"affected_entities": {("sensor.gas_price_2", "EUR/invalid")},
|
||||
"translation_placeholders": {
|
||||
"price_units": "EUR/GJ, EUR/kWh, EUR/MWh, EUR/Wh, EUR/CCF, EUR/ft³, EUR/m³"
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
|
@ -1039,18 +1030,18 @@ async def test_validation_water(
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_water",
|
||||
"identifier": "sensor.water_consumption_1",
|
||||
"value": "beers",
|
||||
"affected_entities": {("sensor.water_consumption_1", "beers")},
|
||||
"translation_placeholders": {"water_units": "CCF, ft³, m³, gal, L"},
|
||||
},
|
||||
{
|
||||
"type": "recorder_untracked",
|
||||
"identifier": "sensor.water_cost_1",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.water_cost_1", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
{
|
||||
"type": "entity_not_defined",
|
||||
"identifier": "sensor.water_cost_1",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.water_cost_1", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
],
|
||||
[],
|
||||
|
@ -1058,15 +1049,17 @@ async def test_validation_water(
|
|||
[
|
||||
{
|
||||
"type": "entity_unexpected_device_class",
|
||||
"identifier": "sensor.water_consumption_4",
|
||||
"value": None,
|
||||
"affected_entities": {("sensor.water_consumption_4", None)},
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
"type": "entity_unexpected_unit_water_price",
|
||||
"identifier": "sensor.water_price_2",
|
||||
"value": "EUR/invalid",
|
||||
"affected_entities": {("sensor.water_price_2", "EUR/invalid")},
|
||||
"translation_placeholders": {
|
||||
"price_units": "EUR/CCF, EUR/ft³, EUR/m³, EUR/gal, EUR/L"
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
|
|
Loading…
Add table
Reference in a new issue