Add current_humidity attribute to mqtt humidifier (#94955)
parent
492ed1b544
commit
31f845bfe0
|
@ -52,6 +52,8 @@ from homeassistant.util.unit_conversion import TemperatureConverter
|
|||
from . import subscription
|
||||
from .config import DEFAULT_RETAIN, MQTT_BASE_SCHEMA
|
||||
from .const import (
|
||||
CONF_CURRENT_HUMIDITY_TEMPLATE,
|
||||
CONF_CURRENT_HUMIDITY_TOPIC,
|
||||
CONF_CURRENT_TEMP_TEMPLATE,
|
||||
CONF_CURRENT_TEMP_TOPIC,
|
||||
CONF_ENCODING,
|
||||
|
@ -94,8 +96,6 @@ CONF_AUX_COMMAND_TOPIC = "aux_command_topic"
|
|||
CONF_AUX_STATE_TEMPLATE = "aux_state_template"
|
||||
CONF_AUX_STATE_TOPIC = "aux_state_topic"
|
||||
|
||||
CONF_CURRENT_HUMIDITY_TEMPLATE = "current_humidity_template"
|
||||
CONF_CURRENT_HUMIDITY_TOPIC = "current_humidity_topic"
|
||||
CONF_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_command_template"
|
||||
CONF_FAN_MODE_COMMAND_TOPIC = "fan_mode_command_topic"
|
||||
CONF_FAN_MODE_LIST = "fan_modes"
|
||||
|
|
|
@ -29,6 +29,8 @@ CONF_WS_HEADERS = "ws_headers"
|
|||
CONF_WILL_MESSAGE = "will_message"
|
||||
CONF_PAYLOAD_RESET = "payload_reset"
|
||||
|
||||
CONF_CURRENT_HUMIDITY_TEMPLATE = "current_humidity_template"
|
||||
CONF_CURRENT_HUMIDITY_TOPIC = "current_humidity_topic"
|
||||
CONF_CURRENT_TEMP_TEMPLATE = "current_temperature_template"
|
||||
CONF_CURRENT_TEMP_TOPIC = "current_temperature_topic"
|
||||
CONF_MODE_COMMAND_TEMPLATE = "mode_command_template"
|
||||
|
|
|
@ -10,6 +10,7 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.components import humidifier
|
||||
from homeassistant.components.humidifier import (
|
||||
ATTR_CURRENT_HUMIDITY,
|
||||
ATTR_HUMIDITY,
|
||||
ATTR_MODE,
|
||||
DEFAULT_MAX_HUMIDITY,
|
||||
|
@ -37,6 +38,8 @@ from .config import MQTT_RW_SCHEMA
|
|||
from .const import (
|
||||
CONF_COMMAND_TEMPLATE,
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_CURRENT_HUMIDITY_TEMPLATE,
|
||||
CONF_CURRENT_HUMIDITY_TOPIC,
|
||||
CONF_ENCODING,
|
||||
CONF_QOS,
|
||||
CONF_RETAIN,
|
||||
|
@ -117,6 +120,8 @@ _PLATFORM_SCHEMA_BASE = MQTT_RW_SCHEMA.extend(
|
|||
): cv.ensure_list,
|
||||
vol.Inclusive(CONF_MODE_COMMAND_TOPIC, "available_modes"): valid_publish_topic,
|
||||
vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_CURRENT_HUMIDITY_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_CURRENT_HUMIDITY_TOPIC): valid_subscribe_topic,
|
||||
vol.Optional(
|
||||
CONF_DEVICE_CLASS, default=HumidifierDeviceClass.HUMIDIFIER
|
||||
): vol.In(
|
||||
|
@ -224,6 +229,7 @@ class MqttHumidifier(MqttEntity, HumidifierEntity):
|
|||
for key in (
|
||||
CONF_STATE_TOPIC,
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_CURRENT_HUMIDITY_TOPIC,
|
||||
CONF_TARGET_HUMIDITY_STATE_TOPIC,
|
||||
CONF_TARGET_HUMIDITY_COMMAND_TOPIC,
|
||||
CONF_MODE_STATE_TOPIC,
|
||||
|
@ -263,6 +269,7 @@ class MqttHumidifier(MqttEntity, HumidifierEntity):
|
|||
|
||||
self._value_templates = {}
|
||||
value_templates: dict[str, Template | None] = {
|
||||
ATTR_CURRENT_HUMIDITY: config.get(CONF_CURRENT_HUMIDITY_TEMPLATE),
|
||||
CONF_STATE: config.get(CONF_STATE_VALUE_TEMPLATE),
|
||||
ATTR_HUMIDITY: config.get(CONF_TARGET_HUMIDITY_STATE_TEMPLATE),
|
||||
ATTR_MODE: config.get(CONF_MODE_STATE_TEMPLATE),
|
||||
|
@ -301,6 +308,49 @@ class MqttHumidifier(MqttEntity, HumidifierEntity):
|
|||
"encoding": self._config[CONF_ENCODING] or None,
|
||||
}
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def current_humidity_received(msg: ReceiveMessage) -> None:
|
||||
"""Handle new received MQTT message for the current humidity."""
|
||||
rendered_current_humidity_payload = self._value_templates[
|
||||
ATTR_CURRENT_HUMIDITY
|
||||
](msg.payload)
|
||||
if rendered_current_humidity_payload == self._payload["HUMIDITY_RESET"]:
|
||||
self._attr_current_humidity = None
|
||||
get_mqtt_data(self.hass).state_write_requests.write_state_request(self)
|
||||
return
|
||||
if not rendered_current_humidity_payload:
|
||||
_LOGGER.debug("Ignoring empty current humidity from '%s'", msg.topic)
|
||||
return
|
||||
try:
|
||||
current_humidity = round(float(rendered_current_humidity_payload))
|
||||
except ValueError:
|
||||
_LOGGER.warning(
|
||||
"'%s' received on topic %s. '%s' is not a valid humidity",
|
||||
msg.payload,
|
||||
msg.topic,
|
||||
rendered_current_humidity_payload,
|
||||
)
|
||||
return
|
||||
if current_humidity < 0 or current_humidity > 100:
|
||||
_LOGGER.warning(
|
||||
"'%s' received on topic %s. '%s' is not a valid humidity",
|
||||
msg.payload,
|
||||
msg.topic,
|
||||
rendered_current_humidity_payload,
|
||||
)
|
||||
return
|
||||
self._attr_current_humidity = current_humidity
|
||||
get_mqtt_data(self.hass).state_write_requests.write_state_request(self)
|
||||
|
||||
if self._topic[CONF_CURRENT_HUMIDITY_TOPIC] is not None:
|
||||
topics[CONF_CURRENT_HUMIDITY_TOPIC] = {
|
||||
"topic": self._topic[CONF_CURRENT_HUMIDITY_TOPIC],
|
||||
"msg_callback": current_humidity_received,
|
||||
"qos": self._config[CONF_QOS],
|
||||
"encoding": self._config[CONF_ENCODING] or None,
|
||||
}
|
||||
|
||||
@callback
|
||||
@log_messages(self.hass, self.entity_id)
|
||||
def target_humidity_received(msg: ReceiveMessage) -> None:
|
||||
|
|
|
@ -8,12 +8,14 @@ from voluptuous.error import MultipleInvalid
|
|||
|
||||
from homeassistant.components import humidifier, mqtt
|
||||
from homeassistant.components.humidifier import (
|
||||
ATTR_CURRENT_HUMIDITY,
|
||||
ATTR_HUMIDITY,
|
||||
ATTR_MODE,
|
||||
DOMAIN,
|
||||
SERVICE_SET_HUMIDITY,
|
||||
SERVICE_SET_MODE,
|
||||
)
|
||||
from homeassistant.components.mqtt.const import CONF_CURRENT_HUMIDITY_TOPIC
|
||||
from homeassistant.components.mqtt.humidifier import (
|
||||
CONF_MODE_COMMAND_TOPIC,
|
||||
CONF_MODE_STATE_TOPIC,
|
||||
|
@ -151,6 +153,7 @@ async def test_fail_setup_if_no_command_topic(
|
|||
"name": "test",
|
||||
"state_topic": "state-topic",
|
||||
"command_topic": "command-topic",
|
||||
"current_humidity_topic": "current-humidity-topic",
|
||||
"payload_off": "StAtE_OfF",
|
||||
"payload_on": "StAtE_On",
|
||||
"target_humidity_state_topic": "humidity-state-topic",
|
||||
|
@ -220,6 +223,26 @@ async def test_controlling_state_via_topic(
|
|||
assert "not a valid mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", "48")
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) == 48
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", "101")
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) == 48
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", "-1.6")
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) == 48
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", "43.6")
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) == 44
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", "invalid")
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) == 44
|
||||
|
||||
async_fire_mqtt_message(hass, "mode-state-topic", "auto")
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_MODE) == "auto"
|
||||
|
@ -258,6 +281,7 @@ async def test_controlling_state_via_topic(
|
|||
"name": "test",
|
||||
"state_topic": "state-topic",
|
||||
"command_topic": "command-topic",
|
||||
"current_humidity_topic": "current-humidity-topic",
|
||||
"target_humidity_state_topic": "humidity-state-topic",
|
||||
"target_humidity_command_topic": "humidity-command-topic",
|
||||
"mode_state_topic": "mode-state-topic",
|
||||
|
@ -267,6 +291,7 @@ async def test_controlling_state_via_topic(
|
|||
"eco",
|
||||
"baby",
|
||||
],
|
||||
"current_humidity_template": "{{ value_json.val }}",
|
||||
"state_value_template": "{{ value_json.val }}",
|
||||
"target_humidity_state_template": "{{ value_json.val }}",
|
||||
"mode_state_template": "{{ value_json.val }}",
|
||||
|
@ -312,6 +337,22 @@ async def test_controlling_state_via_topic_and_json_message(
|
|||
assert state.attributes.get(humidifier.ATTR_HUMIDITY) is None
|
||||
caplog.clear()
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", '{"val": 1}')
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) == 1
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", '{"val": 100}')
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) == 100
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", '{"val": "None"}')
|
||||
state = hass.states.get("humidifier.test")
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) is None
|
||||
|
||||
async_fire_mqtt_message(hass, "current-humidity-topic", '{"otherval": 100}')
|
||||
assert state.attributes.get(humidifier.ATTR_CURRENT_HUMIDITY) is None
|
||||
caplog.clear()
|
||||
|
||||
async_fire_mqtt_message(hass, "mode-state-topic", '{"val": "low"}')
|
||||
assert "not a valid mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
@ -746,6 +787,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(
|
|||
("state_topic", "ON", None, "on"),
|
||||
(CONF_MODE_STATE_TOPIC, "auto", ATTR_MODE, "auto"),
|
||||
(CONF_TARGET_HUMIDITY_STATE_TOPIC, "45", ATTR_HUMIDITY, 45),
|
||||
(CONF_CURRENT_HUMIDITY_TOPIC, "39", ATTR_CURRENT_HUMIDITY, 39),
|
||||
],
|
||||
)
|
||||
async def test_encoding_subscribable_topics(
|
||||
|
|
Loading…
Reference in New Issue