Fix entity category for sensor fails mqtt sensor platform setup (#103449)
This commit is contained in:
parent
a11091890f
commit
cbccdbc6fa
5 changed files with 125 additions and 33 deletions
|
@ -42,7 +42,6 @@ from .mixins import (
|
||||||
MqttAvailability,
|
MqttAvailability,
|
||||||
MqttEntity,
|
MqttEntity,
|
||||||
async_setup_entity_entry_helper,
|
async_setup_entity_entry_helper,
|
||||||
validate_sensor_entity_category,
|
|
||||||
write_state_on_attr_change,
|
write_state_on_attr_change,
|
||||||
)
|
)
|
||||||
from .models import MqttValueTemplate, ReceiveMessage
|
from .models import MqttValueTemplate, ReceiveMessage
|
||||||
|
@ -69,11 +68,12 @@ _PLATFORM_SCHEMA_BASE = MQTT_RO_SCHEMA.extend(
|
||||||
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
||||||
|
|
||||||
DISCOVERY_SCHEMA = vol.All(
|
DISCOVERY_SCHEMA = vol.All(
|
||||||
validate_sensor_entity_category,
|
|
||||||
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
||||||
)
|
)
|
||||||
|
|
||||||
PLATFORM_SCHEMA_MODERN = vol.All(validate_sensor_entity_category, _PLATFORM_SCHEMA_BASE)
|
PLATFORM_SCHEMA_MODERN = vol.All(
|
||||||
|
_PLATFORM_SCHEMA_BASE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
|
|
|
@ -29,7 +29,7 @@ from homeassistant.const import (
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
EntityCategory,
|
EntityCategory,
|
||||||
)
|
)
|
||||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, async_get_hass, callback
|
||||||
from homeassistant.helpers import (
|
from homeassistant.helpers import (
|
||||||
config_validation as cv,
|
config_validation as cv,
|
||||||
device_registry as dr,
|
device_registry as dr,
|
||||||
|
@ -208,14 +208,60 @@ def validate_device_has_at_least_one_identifier(value: ConfigType) -> ConfigType
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def validate_sensor_entity_category(config: ConfigType) -> ConfigType:
|
def validate_sensor_entity_category(
|
||||||
|
domain: str, discovery: bool
|
||||||
|
) -> Callable[[ConfigType], ConfigType]:
|
||||||
"""Check the sensor's entity category is not set to `config` which is invalid for sensors."""
|
"""Check the sensor's entity category is not set to `config` which is invalid for sensors."""
|
||||||
if (
|
|
||||||
CONF_ENTITY_CATEGORY in config
|
# A guard was added to the core sensor platform with HA core 2023.11.0
|
||||||
and config[CONF_ENTITY_CATEGORY] == EntityCategory.CONFIG
|
# See: https://github.com/home-assistant/core/pull/101471
|
||||||
):
|
# A developers blog from october 2021 explains the correct uses of the entity category
|
||||||
raise vol.Invalid("Entity category `config` is invalid")
|
# See:
|
||||||
return config
|
# https://developers.home-assistant.io/blog/2021/10/26/config-entity/?_highlight=entity_category#entity-categories
|
||||||
|
#
|
||||||
|
# To limitate the impact of the change we use a grace period
|
||||||
|
# of 3 months for user to update there configs.
|
||||||
|
|
||||||
|
def _validate(config: ConfigType) -> ConfigType:
|
||||||
|
if (
|
||||||
|
CONF_ENTITY_CATEGORY in config
|
||||||
|
and config[CONF_ENTITY_CATEGORY] == EntityCategory.CONFIG
|
||||||
|
):
|
||||||
|
config_str: str
|
||||||
|
if not discovery:
|
||||||
|
config_str = yaml_dump(config)
|
||||||
|
config.pop(CONF_ENTITY_CATEGORY)
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Entity category `config` is invalid for sensors, ignoring. "
|
||||||
|
"This stops working from HA Core 2024.2.0"
|
||||||
|
)
|
||||||
|
# We only open an issue if the user can fix it
|
||||||
|
if discovery:
|
||||||
|
return config
|
||||||
|
config_file = getattr(config, "__config_file__", "?")
|
||||||
|
line = getattr(config, "__line__", "?")
|
||||||
|
hass = async_get_hass()
|
||||||
|
async_create_issue(
|
||||||
|
hass,
|
||||||
|
domain=DOMAIN,
|
||||||
|
issue_id="invalid_entity_category",
|
||||||
|
breaks_in_ha_version="2024.2.0",
|
||||||
|
is_fixable=False,
|
||||||
|
severity=IssueSeverity.WARNING,
|
||||||
|
translation_key="invalid_entity_category",
|
||||||
|
learn_more_url=(
|
||||||
|
f"https://www.home-assistant.io/integrations/{domain}.mqtt/"
|
||||||
|
),
|
||||||
|
translation_placeholders={
|
||||||
|
"domain": domain,
|
||||||
|
"config": config_str,
|
||||||
|
"config_file": config_file,
|
||||||
|
"line": line,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return config
|
||||||
|
|
||||||
|
return _validate
|
||||||
|
|
||||||
|
|
||||||
MQTT_ENTITY_DEVICE_INFO_SCHEMA = vol.All(
|
MQTT_ENTITY_DEVICE_INFO_SCHEMA = vol.All(
|
||||||
|
|
|
@ -88,7 +88,7 @@ PLATFORM_SCHEMA_MODERN = vol.All(
|
||||||
# Deprecated in HA Core 2021.11.0 https://github.com/home-assistant/core/pull/54840
|
# Deprecated in HA Core 2021.11.0 https://github.com/home-assistant/core/pull/54840
|
||||||
# Removed in HA Core 2023.6.0
|
# Removed in HA Core 2023.6.0
|
||||||
cv.removed(CONF_LAST_RESET_TOPIC),
|
cv.removed(CONF_LAST_RESET_TOPIC),
|
||||||
validate_sensor_entity_category,
|
validate_sensor_entity_category(sensor.DOMAIN, discovery=False),
|
||||||
_PLATFORM_SCHEMA_BASE,
|
_PLATFORM_SCHEMA_BASE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ DISCOVERY_SCHEMA = vol.All(
|
||||||
# Deprecated in HA Core 2021.11.0 https://github.com/home-assistant/core/pull/54840
|
# Deprecated in HA Core 2021.11.0 https://github.com/home-assistant/core/pull/54840
|
||||||
# Removed in HA Core 2023.6.0
|
# Removed in HA Core 2023.6.0
|
||||||
cv.removed(CONF_LAST_RESET_TOPIC),
|
cv.removed(CONF_LAST_RESET_TOPIC),
|
||||||
validate_sensor_entity_category,
|
validate_sensor_entity_category(sensor.DOMAIN, discovery=True),
|
||||||
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
"title": "MQTT entities with auxiliary heat support found",
|
"title": "MQTT entities with auxiliary heat support found",
|
||||||
"description": "Entity `{entity_id}` has auxiliary heat support enabled, which has been deprecated for MQTT climate devices. Please adjust your configuration and remove deprecated config options from your configuration and restart Home Assistant to fix this issue."
|
"description": "Entity `{entity_id}` has auxiliary heat support enabled, which has been deprecated for MQTT climate devices. Please adjust your configuration and remove deprecated config options from your configuration and restart Home Assistant to fix this issue."
|
||||||
},
|
},
|
||||||
|
"invalid_entity_category": {
|
||||||
|
"title": "An MQTT {domain} with an invalid entity category was found",
|
||||||
|
"description": "Home Assistant detected a manually configured MQTT `{domain}` entity that has an `entity_category` set to `config`. \nConfiguration file: **{config_file}**\nNear line: **{line}**\n\nConfig with invalid setting:\n\n```yaml\n{config}\n```\n\nWhen set, make sure `entity_category` for a `{domain}` is set to `diagnostic` or `None`. Update your YAML configuration and restart Home Assistant to fix this issue."
|
||||||
|
},
|
||||||
"invalid_platform_config": {
|
"invalid_platform_config": {
|
||||||
"title": "Invalid config found for mqtt {domain} item",
|
"title": "Invalid config found for mqtt {domain} item",
|
||||||
"description": "Home Assistant detected an invalid config for a manually configured item.\n\nPlatform domain: **{domain}**\nConfiguration file: **{config_file}**\nNear line: **{line}**\nConfiguration found:\n```yaml\n{config}\n```\nError: **{error}**.\n\nMake sure the configuration is valid and [reload](/developer-tools/yaml) the manually configured MQTT items or restart Home Assistant to fix this issue."
|
"description": "Home Assistant detected an invalid config for a manually configured item.\n\nPlatform domain: **{domain}**\nConfiguration file: **{config_file}**\nNear line: **{line}**\nConfiguration found:\n```yaml\n{config}\n```\nError: **{error}**.\n\nMake sure the configuration is valid and [reload](/developer-tools/yaml) the manually configured MQTT items or restart Home Assistant to fix this issue."
|
||||||
|
|
|
@ -30,7 +30,12 @@ from homeassistant.const import (
|
||||||
import homeassistant.core as ha
|
import homeassistant.core as ha
|
||||||
from homeassistant.core import CoreState, HomeAssistant, callback
|
from homeassistant.core import CoreState, HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er, template
|
from homeassistant.helpers import (
|
||||||
|
device_registry as dr,
|
||||||
|
entity_registry as er,
|
||||||
|
issue_registry as ir,
|
||||||
|
template,
|
||||||
|
)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.entity_platform import async_get_platforms
|
from homeassistant.helpers.entity_platform import async_get_platforms
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
@ -42,6 +47,7 @@ from .test_common import help_all_subscribe_calls
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
MockConfigEntry,
|
MockConfigEntry,
|
||||||
MockEntity,
|
MockEntity,
|
||||||
|
async_capture_events,
|
||||||
async_fire_mqtt_message,
|
async_fire_mqtt_message,
|
||||||
async_fire_time_changed,
|
async_fire_time_changed,
|
||||||
mock_restore_cache,
|
mock_restore_cache,
|
||||||
|
@ -2152,26 +2158,20 @@ async def test_setup_manual_mqtt_with_invalid_config(
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"hass_config",
|
("hass_config", "entity_id"),
|
||||||
[
|
[
|
||||||
{
|
(
|
||||||
mqtt.DOMAIN: {
|
{
|
||||||
"sensor": {
|
mqtt.DOMAIN: {
|
||||||
"name": "test",
|
"sensor": {
|
||||||
"state_topic": "test-topic",
|
"name": "test",
|
||||||
"entity_category": "config",
|
"state_topic": "test-topic",
|
||||||
|
"entity_category": "config",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
"sensor.test",
|
||||||
{
|
),
|
||||||
mqtt.DOMAIN: {
|
|
||||||
"binary_sensor": {
|
|
||||||
"name": "test",
|
|
||||||
"state_topic": "test-topic",
|
|
||||||
"entity_category": "config",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@patch(
|
@patch(
|
||||||
|
@ -2181,10 +2181,52 @@ async def test_setup_manual_mqtt_with_invalid_entity_category(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
entity_id: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test set up a manual sensor item with an invalid entity category."""
|
"""Test set up a manual sensor item with an invalid entity category."""
|
||||||
|
events = async_capture_events(hass, ir.EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED)
|
||||||
assert await mqtt_mock_entry()
|
assert await mqtt_mock_entry()
|
||||||
assert "Entity category `config` is invalid" in caplog.text
|
assert "Entity category `config` is invalid for sensors, ignoring" in caplog.text
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None
|
||||||
|
assert len(events) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("config", "entity_id"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"name": "test",
|
||||||
|
"state_topic": "test-topic",
|
||||||
|
"entity_category": "config",
|
||||||
|
},
|
||||||
|
"sensor.test",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@patch(
|
||||||
|
"homeassistant.components.mqtt.PLATFORMS", [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||||
|
)
|
||||||
|
async def test_setup_discovery_mqtt_with_invalid_entity_category(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
config: dict[str, Any],
|
||||||
|
entity_id: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test set up a discovered sensor item with an invalid entity category."""
|
||||||
|
events = async_capture_events(hass, ir.EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED)
|
||||||
|
assert await mqtt_mock_entry()
|
||||||
|
|
||||||
|
domain = entity_id.split(".")[0]
|
||||||
|
json_config = json.dumps(config)
|
||||||
|
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", json_config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert "Entity category `config` is invalid for sensors, ignoring" in caplog.text
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None
|
||||||
|
assert len(events) == 0
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.components.mqtt.PLATFORMS", [])
|
@patch("homeassistant.components.mqtt.PLATFORMS", [])
|
||||||
|
|
Loading…
Add table
Reference in a new issue