Filter MQTT JSON attributes (#52076)
* Filter JSON attributes * Apply suggestions from code review Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io> * Refactor, add tests Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
09b3882a5b
commit
04c9665241
3 changed files with 68 additions and 2 deletions
|
@ -67,6 +67,25 @@ CONF_VIA_DEVICE = "via_device"
|
|||
CONF_DEPRECATED_VIA_HUB = "via_hub"
|
||||
CONF_SUGGESTED_AREA = "suggested_area"
|
||||
|
||||
MQTT_ATTRIBUTES_BLOCKED = {
|
||||
"assumed_state",
|
||||
"available",
|
||||
"context_recent_time",
|
||||
"device_class",
|
||||
"device_info",
|
||||
"entity_picture",
|
||||
"entity_registry_enabled_default",
|
||||
"extra_state_attributes",
|
||||
"force_update",
|
||||
"icon",
|
||||
"name",
|
||||
"should_poll",
|
||||
"state",
|
||||
"supported_features",
|
||||
"unique_id",
|
||||
"unit_of_measurement",
|
||||
}
|
||||
|
||||
MQTT_AVAILABILITY_SINGLE_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Exclusive(CONF_AVAILABILITY_TOPIC, "availability"): valid_subscribe_topic,
|
||||
|
@ -175,11 +194,12 @@ async def async_setup_entry_helper(hass, domain, async_setup, schema):
|
|||
class MqttAttributes(Entity):
|
||||
"""Mixin used for platforms that support JSON attributes."""
|
||||
|
||||
def __init__(self, config: dict) -> None:
|
||||
def __init__(self, config: dict, extra_blocked_attributes: list = None) -> None:
|
||||
"""Initialize the JSON attributes mixin."""
|
||||
self._attributes = None
|
||||
self._attributes_sub_state = None
|
||||
self._attributes_config = config
|
||||
self._extra_blocked_attributes = extra_blocked_attributes or []
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Subscribe MQTT events."""
|
||||
|
@ -206,7 +226,13 @@ class MqttAttributes(Entity):
|
|||
payload = attr_tpl.async_render_with_possible_json_value(payload)
|
||||
json_dict = json.loads(payload)
|
||||
if isinstance(json_dict, dict):
|
||||
self._attributes = json_dict
|
||||
filtered_dict = {
|
||||
k: v
|
||||
for k, v in json_dict.items()
|
||||
if k not in MQTT_ATTRIBUTES_BLOCKED
|
||||
and k not in self._extra_blocked_attributes
|
||||
}
|
||||
self._attributes = filtered_dict
|
||||
self.async_write_ha_state()
|
||||
else:
|
||||
_LOGGER.warning("JSON result was not a dictionary")
|
||||
|
|
|
@ -7,6 +7,7 @@ from unittest.mock import ANY, patch
|
|||
from homeassistant.components import mqtt
|
||||
from homeassistant.components.mqtt import debug_info
|
||||
from homeassistant.components.mqtt.const import MQTT_DISCONNECTED
|
||||
from homeassistant.components.mqtt.mixins import MQTT_ATTRIBUTES_BLOCKED
|
||||
from homeassistant.const import ATTR_ASSUMED_STATE, STATE_UNAVAILABLE
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
@ -493,6 +494,37 @@ async def help_test_setting_attribute_via_mqtt_json_message(
|
|||
assert state.attributes.get("val") == "100"
|
||||
|
||||
|
||||
async def help_test_setting_blocked_attribute_via_mqtt_json_message(
|
||||
hass, mqtt_mock, domain, config, extra_blocked_attributes
|
||||
):
|
||||
"""Test the setting of blocked attribute via MQTT with JSON payload.
|
||||
|
||||
This is a test helper for the MqttAttributes mixin.
|
||||
"""
|
||||
extra_blocked_attributes = extra_blocked_attributes or []
|
||||
|
||||
# Add JSON attributes settings to config
|
||||
config = copy.deepcopy(config)
|
||||
config[domain]["json_attributes_topic"] = "attr-topic"
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
domain,
|
||||
config,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
val = "abc123"
|
||||
|
||||
for attr in MQTT_ATTRIBUTES_BLOCKED:
|
||||
async_fire_mqtt_message(hass, "attr-topic", json.dumps({attr: val}))
|
||||
state = hass.states.get(f"{domain}.test")
|
||||
assert state.attributes.get(attr) != val
|
||||
|
||||
for attr in extra_blocked_attributes:
|
||||
async_fire_mqtt_message(hass, "attr-topic", json.dumps({attr: val}))
|
||||
state = hass.states.get(f"{domain}.test")
|
||||
assert state.attributes.get(attr) != val
|
||||
|
||||
|
||||
async def help_test_setting_attribute_with_template(hass, mqtt_mock, domain, config):
|
||||
"""Test the setting of attribute via MQTT with JSON payload.
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ from .test_common import (
|
|||
help_test_entity_id_update_subscriptions,
|
||||
help_test_setting_attribute_via_mqtt_json_message,
|
||||
help_test_setting_attribute_with_template,
|
||||
help_test_setting_blocked_attribute_via_mqtt_json_message,
|
||||
help_test_unique_id,
|
||||
help_test_update_with_json_attrs_bad_JSON,
|
||||
help_test_update_with_json_attrs_not_dict,
|
||||
|
@ -531,6 +532,13 @@ async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
|
|||
)
|
||||
|
||||
|
||||
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
|
||||
"""Test the setting of attribute via MQTT with JSON payload."""
|
||||
await help_test_setting_blocked_attribute_via_mqtt_json_message(
|
||||
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG, None
|
||||
)
|
||||
|
||||
|
||||
async def test_setting_attribute_with_template(hass, mqtt_mock):
|
||||
"""Test the setting of attribute via MQTT with JSON payload."""
|
||||
await help_test_setting_attribute_with_template(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue