Improve mqtt value template error logging (#110492)
* Refactor mqtt value template error logging * Remove import
This commit is contained in:
parent
5227976aa2
commit
c13231fc00
6 changed files with 81 additions and 45 deletions
|
@ -29,7 +29,6 @@ from .const import (
|
|||
CONF_STATE_TOPIC,
|
||||
PAYLOAD_EMPTY_JSON,
|
||||
PAYLOAD_NONE,
|
||||
TEMPLATE_ERRORS,
|
||||
)
|
||||
from .debug_info import log_messages
|
||||
from .mixins import (
|
||||
|
@ -39,6 +38,7 @@ from .mixins import (
|
|||
)
|
||||
from .models import (
|
||||
MqttValueTemplate,
|
||||
MqttValueTemplateException,
|
||||
PayloadSentinel,
|
||||
ReceiveMessage,
|
||||
ReceivePayloadType,
|
||||
|
@ -134,7 +134,8 @@ class MqttEvent(MqttEntity, EventEntity):
|
|||
event_type: str
|
||||
try:
|
||||
payload = self._template(msg.payload, PayloadSentinel.DEFAULT)
|
||||
except TEMPLATE_ERRORS:
|
||||
except MqttValueTemplateException as exc:
|
||||
_LOGGER.warning(exc)
|
||||
return
|
||||
if (
|
||||
not payload
|
||||
|
|
|
@ -24,14 +24,19 @@ from homeassistant.util import dt as dt_util
|
|||
|
||||
from . import subscription
|
||||
from .config import MQTT_BASE_SCHEMA
|
||||
from .const import CONF_ENCODING, CONF_QOS, TEMPLATE_ERRORS
|
||||
from .const import CONF_ENCODING, CONF_QOS
|
||||
from .debug_info import log_messages
|
||||
from .mixins import (
|
||||
MQTT_ENTITY_COMMON_SCHEMA,
|
||||
MqttEntity,
|
||||
async_setup_entity_entry_helper,
|
||||
)
|
||||
from .models import MessageCallbackType, MqttValueTemplate, ReceiveMessage
|
||||
from .models import (
|
||||
MessageCallbackType,
|
||||
MqttValueTemplate,
|
||||
MqttValueTemplateException,
|
||||
ReceiveMessage,
|
||||
)
|
||||
from .util import get_mqtt_data, valid_subscribe_topic
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -191,7 +196,8 @@ class MqttImage(MqttEntity, ImageEntity):
|
|||
try:
|
||||
url = cv.url(self._url_template(msg.payload))
|
||||
self._attr_image_url = url
|
||||
except TEMPLATE_ERRORS:
|
||||
except MqttValueTemplateException as exc:
|
||||
_LOGGER.warning(exc)
|
||||
return
|
||||
except vol.Invalid:
|
||||
_LOGGER.error(
|
||||
|
|
|
@ -94,7 +94,6 @@ from .const import (
|
|||
DOMAIN,
|
||||
MQTT_CONNECTED,
|
||||
MQTT_DISCONNECTED,
|
||||
TEMPLATE_ERRORS,
|
||||
)
|
||||
from .debug_info import log_message, log_messages
|
||||
from .discovery import (
|
||||
|
@ -109,6 +108,7 @@ from .discovery import (
|
|||
from .models import (
|
||||
MessageCallbackType,
|
||||
MqttValueTemplate,
|
||||
MqttValueTemplateException,
|
||||
PublishPayloadType,
|
||||
ReceiveMessage,
|
||||
)
|
||||
|
@ -482,7 +482,8 @@ def write_state_on_attr_change(
|
|||
}
|
||||
try:
|
||||
msg_callback(msg)
|
||||
except TEMPLATE_ERRORS:
|
||||
except MqttValueTemplateException as exc:
|
||||
_LOGGER.warning(exc)
|
||||
return
|
||||
if not _attrs_have_changed(tracked_attrs):
|
||||
return
|
||||
|
|
|
@ -223,6 +223,36 @@ class MqttCommandTemplate:
|
|||
) from exc
|
||||
|
||||
|
||||
class MqttValueTemplateException(TemplateError):
|
||||
"""Handle MqttValueTemplate exceptions."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args: object,
|
||||
base_exception: Exception,
|
||||
value_template: str,
|
||||
default: ReceivePayloadType | PayloadSentinel,
|
||||
payload: ReceivePayloadType,
|
||||
entity_id: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize exception."""
|
||||
super().__init__(base_exception, *args)
|
||||
entity_id_log = "" if entity_id is None else f" for entity '{entity_id}'"
|
||||
default_log = str(default)
|
||||
default_payload_log = (
|
||||
"" if default is PayloadSentinel.NONE else f", default value: {default_log}"
|
||||
)
|
||||
payload_log = str(payload)
|
||||
self._message = (
|
||||
f"{type(base_exception).__name__}: {base_exception} rendering template{entity_id_log}"
|
||||
f", template: '{value_template}'{default_payload_log} and payload: {payload_log}"
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return exception message string."""
|
||||
return self._message
|
||||
|
||||
|
||||
class MqttValueTemplate:
|
||||
"""Class for rendering MQTT value template with possible json values."""
|
||||
|
||||
|
@ -291,14 +321,13 @@ class MqttValueTemplate:
|
|||
)
|
||||
)
|
||||
except TEMPLATE_ERRORS as exc:
|
||||
_LOGGER.error(
|
||||
"%s: %s rendering template for entity '%s', template: '%s'",
|
||||
type(exc).__name__,
|
||||
exc,
|
||||
self._entity.entity_id if self._entity else "n/a",
|
||||
self._value_template.template,
|
||||
)
|
||||
raise
|
||||
raise MqttValueTemplateException(
|
||||
base_exception=exc,
|
||||
value_template=self._value_template.template,
|
||||
default=default,
|
||||
payload=payload,
|
||||
entity_id=self._entity.entity_id if self._entity else None,
|
||||
) from exc
|
||||
return rendered_payload
|
||||
|
||||
_LOGGER.debug(
|
||||
|
@ -318,17 +347,13 @@ class MqttValueTemplate:
|
|||
)
|
||||
)
|
||||
except TEMPLATE_ERRORS as exc:
|
||||
_LOGGER.error(
|
||||
"%s: %s rendering template for entity '%s', template: "
|
||||
"'%s', default value: %s and payload: %s",
|
||||
type(exc).__name__,
|
||||
exc,
|
||||
self._entity.entity_id if self._entity else "n/a",
|
||||
self._value_template.template,
|
||||
default,
|
||||
payload,
|
||||
)
|
||||
raise
|
||||
raise MqttValueTemplateException(
|
||||
base_exception=exc,
|
||||
value_template=self._value_template.template,
|
||||
default=default,
|
||||
payload=payload,
|
||||
entity_id=self._entity.entity_id if self._entity else None,
|
||||
) from exc
|
||||
return rendered_payload
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from collections.abc import Callable
|
||||
import functools
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
|
@ -15,7 +16,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|||
|
||||
from . import subscription
|
||||
from .config import MQTT_BASE_SCHEMA
|
||||
from .const import ATTR_DISCOVERY_HASH, CONF_QOS, CONF_TOPIC, TEMPLATE_ERRORS
|
||||
from .const import ATTR_DISCOVERY_HASH, CONF_QOS, CONF_TOPIC
|
||||
from .discovery import MQTTDiscoveryPayload
|
||||
from .mixins import (
|
||||
MQTT_ENTITY_DEVICE_INFO_SCHEMA,
|
||||
|
@ -25,10 +26,17 @@ from .mixins import (
|
|||
send_discovery_done,
|
||||
update_device,
|
||||
)
|
||||
from .models import MqttValueTemplate, ReceiveMessage, ReceivePayloadType
|
||||
from .models import (
|
||||
MqttValueTemplate,
|
||||
MqttValueTemplateException,
|
||||
ReceiveMessage,
|
||||
ReceivePayloadType,
|
||||
)
|
||||
from .subscription import EntitySubscription
|
||||
from .util import get_mqtt_data, valid_subscribe_topic
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
LOG_NAME = "Tag"
|
||||
|
||||
TAG = "tag"
|
||||
|
@ -138,7 +146,8 @@ class MQTTTagScanner(MqttDiscoveryDeviceUpdate):
|
|||
async def tag_scanned(msg: ReceiveMessage) -> None:
|
||||
try:
|
||||
tag_id = str(self._value_template(msg.payload, "")).strip()
|
||||
except TEMPLATE_ERRORS:
|
||||
except MqttValueTemplateException as exc:
|
||||
_LOGGER.warning(exc)
|
||||
return
|
||||
if not tag_id: # No output from template, ignore
|
||||
return
|
||||
|
|
|
@ -19,6 +19,7 @@ from homeassistant.components.mqtt.mixins import MQTT_ENTITY_DEVICE_INFO_SCHEMA
|
|||
from homeassistant.components.mqtt.models import (
|
||||
MessageCallbackType,
|
||||
MqttCommandTemplateException,
|
||||
MqttValueTemplateException,
|
||||
ReceiveMessage,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntryDisabler, ConfigEntryState
|
||||
|
@ -433,37 +434,30 @@ async def test_value_template_value(hass: HomeAssistant) -> None:
|
|||
assert template_state_calls.call_count == 1
|
||||
|
||||
|
||||
async def test_value_template_fails(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
async def test_value_template_fails(hass: HomeAssistant) -> None:
|
||||
"""Test the rendering of MQTT value template fails."""
|
||||
|
||||
# test rendering a value fails
|
||||
entity = MockEntity(entity_id="sensor.test")
|
||||
entity.hass = hass
|
||||
tpl = template.Template("{{ value_json.some_var * 2 }}")
|
||||
val_tpl = mqtt.MqttValueTemplate(tpl, hass=hass, entity=entity)
|
||||
with pytest.raises(TypeError) as exc:
|
||||
with pytest.raises(MqttValueTemplateException) as exc:
|
||||
val_tpl.async_render_with_possible_json_value('{"some_var": null }')
|
||||
assert str(exc.value) == "unsupported operand type(s) for *: 'NoneType' and 'int'"
|
||||
assert (
|
||||
assert str(exc.value) == (
|
||||
"TypeError: unsupported operand type(s) for *: 'NoneType' and 'int' "
|
||||
"rendering template for entity 'sensor.test', "
|
||||
"template: '{{ value_json.some_var * 2 }}'"
|
||||
) in caplog.text
|
||||
caplog.clear()
|
||||
with pytest.raises(TypeError) as exc:
|
||||
"template: '{{ value_json.some_var * 2 }}' "
|
||||
'and payload: {"some_var": null }'
|
||||
)
|
||||
with pytest.raises(MqttValueTemplateException) as exc:
|
||||
val_tpl.async_render_with_possible_json_value(
|
||||
'{"some_var": null }', default=100
|
||||
)
|
||||
assert str(exc.value) == "unsupported operand type(s) for *: 'NoneType' and 'int'"
|
||||
assert (
|
||||
assert str(exc.value) == (
|
||||
"TypeError: unsupported operand type(s) for *: 'NoneType' and 'int' "
|
||||
"rendering template for entity 'sensor.test', "
|
||||
"template: '{{ value_json.some_var * 2 }}', default value: 100 and payload: "
|
||||
'{"some_var": null }'
|
||||
) in caplog.text
|
||||
await hass.async_block_till_done()
|
||||
)
|
||||
|
||||
|
||||
async def test_service_call_without_topic_does_not_publish(
|
||||
|
|
Loading…
Add table
Reference in a new issue