Add hvac_action support for MQTT HVAC (#25260)

* Add hvac_action support

* Add tests
pull/25275/head
definitio 2019-07-18 21:17:26 +04:00 committed by Paulus Schoutsen
parent cfc2c58fe0
commit 93970b5621
2 changed files with 45 additions and 0 deletions

View File

@ -31,6 +31,8 @@ _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'MQTT HVAC'
CONF_ACTION_TEMPLATE = 'action_template'
CONF_ACTION_TOPIC = 'action_topic'
CONF_AUX_COMMAND_TOPIC = 'aux_command_topic'
CONF_AUX_STATE_TEMPLATE = 'aux_state_template'
CONF_AUX_STATE_TOPIC = 'aux_state_topic'
@ -83,6 +85,7 @@ TEMPLATE_KEYS = (
CONF_HOLD_STATE_TEMPLATE,
CONF_MODE_STATE_TEMPLATE,
CONF_POWER_STATE_TEMPLATE,
CONF_ACTION_TEMPLATE,
CONF_SWING_MODE_STATE_TEMPLATE,
CONF_TEMP_HIGH_STATE_TEMPLATE,
CONF_TEMP_LOW_STATE_TEMPLATE,
@ -103,6 +106,7 @@ TOPIC_KEYS = (
CONF_MODE_STATE_TOPIC,
CONF_POWER_COMMAND_TOPIC,
CONF_POWER_STATE_TOPIC,
CONF_ACTION_TOPIC,
CONF_SWING_MODE_COMMAND_TOPIC,
CONF_SWING_MODE_STATE_TOPIC,
CONF_TEMP_COMMAND_TOPIC,
@ -149,6 +153,8 @@ PLATFORM_SCHEMA = SCHEMA_BASE.extend({
vol.Optional(CONF_POWER_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_SEND_IF_OFF, default=True): cv.boolean,
vol.Optional(CONF_ACTION_TEMPLATE): cv.template,
vol.Optional(CONF_ACTION_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_SWING_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SWING_MODE_LIST,
default=[STATE_ON, HVAC_MODE_OFF]): cv.ensure_list,
@ -214,6 +220,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate,
self._sub_state = None
self.hass = hass
self._action = None
self._aux = False
self._away = False
self._current_fan_mode = None
@ -279,6 +286,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate,
self._current_swing_mode = HVAC_MODE_OFF
if self._topic[CONF_MODE_STATE_TOPIC] is None:
self._current_operation = HVAC_MODE_OFF
self._action = None
self._away = False
self._hold = None
self._aux = False
@ -314,6 +322,17 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate,
template = self._value_templates[template_name]
return template(msg.payload)
@callback
def handle_action_received(msg):
"""Handle receiving action via MQTT."""
payload = render_template(msg, CONF_ACTION_TEMPLATE)
self._action = payload
self.async_write_ha_state()
add_subscription(topics, CONF_ACTION_TOPIC,
handle_action_received)
@callback
def handle_temperature_received(msg, template_name, attr):
"""Handle temperature coming via MQTT."""
@ -503,6 +522,11 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate,
"""Return the high target temperature we try to reach."""
return self._target_temp_high
@property
def hvac_action(self):
"""Return the current running hvac operation if supported."""
return self._action
@property
def hvac_mode(self):
"""Return current operation ie. heat, cool, idle."""

View File

@ -432,6 +432,20 @@ async def test_set_away_mode(hass, mqtt_mock):
assert state.attributes.get('preset_mode') is None
async def test_set_hvac_action(hass, mqtt_mock):
"""Test setting of the HVAC action."""
config = copy.deepcopy(DEFAULT_CONFIG)
config['climate']['action_topic'] = 'action'
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get('hvac_action') is None
async_fire_mqtt_message(hass, 'action', 'cool')
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get('hvac_action') == 'cool'
async def test_set_hold_pessimistic(hass, mqtt_mock):
"""Test setting the hold mode in pessimistic mode."""
config = copy.deepcopy(DEFAULT_CONFIG)
@ -548,6 +562,7 @@ async def test_set_with_templates(hass, mqtt_mock, caplog):
config = copy.deepcopy(DEFAULT_CONFIG)
# By default, just unquote the JSON-strings
config['climate']['value_template'] = '{{ value_json }}'
config['climate']['action_template'] = '{{ value_json }}'
# Something more complicated for hold mode
config['climate']['hold_state_template'] = \
'{{ value_json.attribute }}'
@ -555,6 +570,7 @@ async def test_set_with_templates(hass, mqtt_mock, caplog):
config['climate']['aux_state_template'] = \
"{{ value == 'switchmeon' }}"
config['climate']['action_topic'] = 'action'
config['climate']['mode_state_topic'] = 'mode-state'
config['climate']['fan_mode_state_topic'] = 'fan-state'
config['climate']['swing_mode_state_topic'] = 'swing-state'
@ -636,6 +652,11 @@ async def test_set_with_templates(hass, mqtt_mock, caplog):
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get('current_temperature') == 74656
# Action
async_fire_mqtt_message(hass, 'action', '"cool"')
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get('hvac_action') == 'cool'
async def test_min_temp_custom(hass, mqtt_mock):
"""Test a custom min temp."""