mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Ignore empty output from MQTT fan's value template (#50122)
* Allow empty payload * Add tests for ignoring empty payload * logging on empty state and osccilation with tests * Improve warning log when invalid value is received
This commit is contained in:
parent
7a87846146
commit
7ab505633d
@ -344,6 +344,9 @@ class MqttFan(MqttEntity, FanEntity):
|
|||||||
def state_received(msg):
|
def state_received(msg):
|
||||||
"""Handle new received MQTT message."""
|
"""Handle new received MQTT message."""
|
||||||
payload = self._value_templates[CONF_STATE](msg.payload)
|
payload = self._value_templates[CONF_STATE](msg.payload)
|
||||||
|
if not payload:
|
||||||
|
_LOGGER.debug("Ignoring empty state from '%s'", msg.topic)
|
||||||
|
return
|
||||||
if payload == self._payload["STATE_ON"]:
|
if payload == self._payload["STATE_ON"]:
|
||||||
self._state = True
|
self._state = True
|
||||||
elif payload == self._payload["STATE_OFF"]:
|
elif payload == self._payload["STATE_OFF"]:
|
||||||
@ -362,22 +365,27 @@ class MqttFan(MqttEntity, FanEntity):
|
|||||||
def percentage_received(msg):
|
def percentage_received(msg):
|
||||||
"""Handle new received MQTT message for the percentage."""
|
"""Handle new received MQTT message for the percentage."""
|
||||||
numeric_val_str = self._value_templates[ATTR_PERCENTAGE](msg.payload)
|
numeric_val_str = self._value_templates[ATTR_PERCENTAGE](msg.payload)
|
||||||
|
if not numeric_val_str:
|
||||||
|
_LOGGER.debug("Ignoring empty speed from '%s'", msg.topic)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
percentage = ranged_value_to_percentage(
|
percentage = ranged_value_to_percentage(
|
||||||
self._speed_range, int(numeric_val_str)
|
self._speed_range, int(numeric_val_str)
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"'%s' received on topic %s is not a valid speed within the speed range",
|
"'%s' received on topic %s. '%s' is not a valid speed within the speed range",
|
||||||
msg.payload,
|
msg.payload,
|
||||||
msg.topic,
|
msg.topic,
|
||||||
|
numeric_val_str,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if percentage < 0 or percentage > 100:
|
if percentage < 0 or percentage > 100:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"'%s' received on topic %s is not a valid speed within the speed range",
|
"'%s' received on topic %s. '%s' is not a valid speed within the speed range",
|
||||||
msg.payload,
|
msg.payload,
|
||||||
msg.topic,
|
msg.topic,
|
||||||
|
numeric_val_str,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
self._percentage = percentage
|
self._percentage = percentage
|
||||||
@ -396,11 +404,15 @@ class MqttFan(MqttEntity, FanEntity):
|
|||||||
def preset_mode_received(msg):
|
def preset_mode_received(msg):
|
||||||
"""Handle new received MQTT message for preset mode."""
|
"""Handle new received MQTT message for preset mode."""
|
||||||
preset_mode = self._value_templates[ATTR_PRESET_MODE](msg.payload)
|
preset_mode = self._value_templates[ATTR_PRESET_MODE](msg.payload)
|
||||||
|
if not preset_mode:
|
||||||
|
_LOGGER.debug("Ignoring empty preset_mode from '%s'", msg.topic)
|
||||||
|
return
|
||||||
if preset_mode not in self.preset_modes:
|
if preset_mode not in self.preset_modes:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"'%s' received on topic %s is not a valid preset mode",
|
"'%s' received on topic %s. '%s' is not a valid preset mode",
|
||||||
msg.payload,
|
msg.payload,
|
||||||
msg.topic,
|
msg.topic,
|
||||||
|
preset_mode,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -436,9 +448,10 @@ class MqttFan(MqttEntity, FanEntity):
|
|||||||
self._speed = speed
|
self._speed = speed
|
||||||
else:
|
else:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"'%s' received on topic %s is not a valid speed",
|
"'%s' received on topic %s. '%s' is not a valid speed",
|
||||||
msg.payload,
|
msg.payload,
|
||||||
msg.topic,
|
msg.topic,
|
||||||
|
speed,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -464,6 +477,9 @@ class MqttFan(MqttEntity, FanEntity):
|
|||||||
def oscillation_received(msg):
|
def oscillation_received(msg):
|
||||||
"""Handle new received MQTT message for the oscillation."""
|
"""Handle new received MQTT message for the oscillation."""
|
||||||
payload = self._value_templates[ATTR_OSCILLATING](msg.payload)
|
payload = self._value_templates[ATTR_OSCILLATING](msg.payload)
|
||||||
|
if not payload:
|
||||||
|
_LOGGER.debug("Ignoring empty oscillation from '%s'", msg.topic)
|
||||||
|
return
|
||||||
if payload == self._payload["OSCILLATE_ON_PAYLOAD"]:
|
if payload == self._payload["OSCILLATE_ON_PAYLOAD"]:
|
||||||
self._oscillation = True
|
self._oscillation = True
|
||||||
elif payload == self._payload["OSCILLATE_OFF_PAYLOAD"]:
|
elif payload == self._payload["OSCILLATE_OFF_PAYLOAD"]:
|
||||||
|
@ -408,6 +408,10 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
|
|||||||
state = hass.states.get("fan.test")
|
state = hass.states.get("fan.test")
|
||||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100
|
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100
|
||||||
|
|
||||||
|
async_fire_mqtt_message(hass, "percentage-state-topic", '{"otherval": 100}')
|
||||||
|
assert "Ignoring empty speed from" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "low"}')
|
async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "low"}')
|
||||||
assert "not a valid preset mode" in caplog.text
|
assert "not a valid preset mode" in caplog.text
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
@ -424,6 +428,99 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
|
|||||||
state = hass.states.get("fan.test")
|
state = hass.states.get("fan.test")
|
||||||
assert state.attributes.get("preset_mode") == "silent"
|
assert state.attributes.get("preset_mode") == "silent"
|
||||||
|
|
||||||
|
async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"otherval": 100}')
|
||||||
|
assert "Ignoring empty preset_mode from" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_controlling_state_via_topic_and_json_message_shared_topic(
|
||||||
|
hass, mqtt_mock, caplog
|
||||||
|
):
|
||||||
|
"""Test the controlling state via topic and JSON message using a shared topic."""
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
fan.DOMAIN,
|
||||||
|
{
|
||||||
|
fan.DOMAIN: {
|
||||||
|
"platform": "mqtt",
|
||||||
|
"name": "test",
|
||||||
|
"state_topic": "shared-state-topic",
|
||||||
|
"command_topic": "command-topic",
|
||||||
|
"oscillation_state_topic": "shared-state-topic",
|
||||||
|
"oscillation_command_topic": "oscillation-command-topic",
|
||||||
|
"percentage_state_topic": "shared-state-topic",
|
||||||
|
"percentage_command_topic": "percentage-command-topic",
|
||||||
|
"preset_mode_state_topic": "shared-state-topic",
|
||||||
|
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||||
|
"preset_modes": [
|
||||||
|
"auto",
|
||||||
|
"smart",
|
||||||
|
"whoosh",
|
||||||
|
"eco",
|
||||||
|
"breeze",
|
||||||
|
"silent",
|
||||||
|
],
|
||||||
|
"state_value_template": "{{ value_json.state }}",
|
||||||
|
"oscillation_value_template": "{{ value_json.oscillation }}",
|
||||||
|
"percentage_value_template": "{{ value_json.percentage }}",
|
||||||
|
"preset_mode_value_template": "{{ value_json.preset_mode }}",
|
||||||
|
"speed_range_min": 1,
|
||||||
|
"speed_range_max": 100,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("fan.test")
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
assert not state.attributes.get(ATTR_ASSUMED_STATE)
|
||||||
|
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"shared-state-topic",
|
||||||
|
'{"state":"ON","preset_mode":"eco","oscillation":"oscillate_on","percentage": 50}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("fan.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes.get("oscillating") is True
|
||||||
|
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 50
|
||||||
|
assert state.attributes.get("preset_mode") == "eco"
|
||||||
|
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"shared-state-topic",
|
||||||
|
'{"state":"ON","preset_mode":"auto","oscillation":"oscillate_off","percentage": 10}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("fan.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes.get("oscillating") is False
|
||||||
|
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 10
|
||||||
|
assert state.attributes.get("preset_mode") == "auto"
|
||||||
|
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"shared-state-topic",
|
||||||
|
'{"state":"OFF","preset_mode":"auto","oscillation":"oscillate_off","percentage": 0}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("fan.test")
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
assert state.attributes.get("oscillating") is False
|
||||||
|
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0
|
||||||
|
assert state.attributes.get("preset_mode") == "auto"
|
||||||
|
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"shared-state-topic",
|
||||||
|
'{"percentage": 100}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("fan.test")
|
||||||
|
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100
|
||||||
|
assert state.attributes.get("preset_mode") == "auto"
|
||||||
|
assert "Ignoring empty preset_mode from" in caplog.text
|
||||||
|
assert "Ignoring empty state from" in caplog.text
|
||||||
|
assert "Ignoring empty oscillation from" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
|
||||||
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
|
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
|
||||||
"""Test optimistic mode without state topic."""
|
"""Test optimistic mode without state topic."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user