More support for availability reporting on MQTT components (#11336)
* Abstract MQTT availability from individual components - Moved availability topic and payloads to MQTT base schema. - Updated components that already report availability: - Switch - Binary sensor - Cover * Add availability reporting to additional MQTT components - Light - JSON light - Template light - Lock - Fan - HVAC - Sensor - Vacuum - Alarm control panel * Annotate MQTT platform coroutinespull/10479/merge
parent
541707c3e7
commit
f0bf7b0def
|
@ -17,7 +17,9 @@ from homeassistant.const import (
|
|||
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN,
|
||||
CONF_NAME, CONF_CODE)
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS)
|
||||
CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC, CONF_COMMAND_TOPIC,
|
||||
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS,
|
||||
MqttAvailability)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -54,15 +56,21 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
config.get(CONF_PAYLOAD_DISARM),
|
||||
config.get(CONF_PAYLOAD_ARM_HOME),
|
||||
config.get(CONF_PAYLOAD_ARM_AWAY),
|
||||
config.get(CONF_CODE))])
|
||||
config.get(CONF_CODE),
|
||||
config.get(CONF_AVAILABILITY_TOPIC),
|
||||
config.get(CONF_PAYLOAD_AVAILABLE),
|
||||
config.get(CONF_PAYLOAD_NOT_AVAILABLE))])
|
||||
|
||||
|
||||
class MqttAlarm(alarm.AlarmControlPanel):
|
||||
class MqttAlarm(MqttAvailability, alarm.AlarmControlPanel):
|
||||
"""Representation of a MQTT alarm status."""
|
||||
|
||||
def __init__(self, name, state_topic, command_topic, qos, payload_disarm,
|
||||
payload_arm_home, payload_arm_away, code):
|
||||
payload_arm_home, payload_arm_away, code, availability_topic,
|
||||
payload_available, payload_not_available):
|
||||
"""Init the MQTT Alarm Control Panel."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._state = STATE_UNKNOWN
|
||||
self._name = name
|
||||
self._state_topic = state_topic
|
||||
|
@ -73,11 +81,11 @@ class MqttAlarm(alarm.AlarmControlPanel):
|
|||
self._payload_arm_away = payload_arm_away
|
||||
self._code = code
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe mqtt events.
|
||||
"""Subscribe mqtt events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method must be run in the event loop and returns a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def message_received(topic, payload, qos):
|
||||
"""Run when new MQTT message has been received."""
|
||||
|
@ -89,7 +97,7 @@ class MqttAlarm(alarm.AlarmControlPanel):
|
|||
self._state = payload
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
return mqtt.async_subscribe(
|
||||
yield from mqtt.async_subscribe(
|
||||
self.hass, self._state_topic, message_received, self._qos)
|
||||
|
||||
@property
|
||||
|
|
|
@ -17,19 +17,15 @@ from homeassistant.const import (
|
|||
CONF_NAME, CONF_VALUE_TEMPLATE, CONF_PAYLOAD_ON, CONF_PAYLOAD_OFF,
|
||||
CONF_DEVICE_CLASS)
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_STATE_TOPIC, CONF_AVAILABILITY_TOPIC, CONF_QOS, valid_subscribe_topic)
|
||||
CONF_STATE_TOPIC, CONF_AVAILABILITY_TOPIC, CONF_PAYLOAD_AVAILABLE,
|
||||
CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, MqttAvailability)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_PAYLOAD_AVAILABLE = 'payload_available'
|
||||
CONF_PAYLOAD_NOT_AVAILABLE = 'payload_not_available'
|
||||
|
||||
DEFAULT_NAME = 'MQTT Binary sensor'
|
||||
DEFAULT_PAYLOAD_OFF = 'OFF'
|
||||
DEFAULT_PAYLOAD_ON = 'ON'
|
||||
DEFAULT_PAYLOAD_AVAILABLE = 'online'
|
||||
DEFAULT_PAYLOAD_NOT_AVAILABLE = 'offline'
|
||||
|
||||
DEPENDENCIES = ['mqtt']
|
||||
|
||||
|
@ -38,12 +34,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
|
||||
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
||||
vol.Optional(CONF_AVAILABILITY_TOPIC): valid_subscribe_topic,
|
||||
vol.Optional(CONF_PAYLOAD_AVAILABLE,
|
||||
default=DEFAULT_PAYLOAD_AVAILABLE): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_NOT_AVAILABLE,
|
||||
default=DEFAULT_PAYLOAD_NOT_AVAILABLE): cv.string,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -70,31 +61,29 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
)])
|
||||
|
||||
|
||||
class MqttBinarySensor(BinarySensorDevice):
|
||||
class MqttBinarySensor(MqttAvailability, BinarySensorDevice):
|
||||
"""Representation a binary sensor that is updated by MQTT."""
|
||||
|
||||
def __init__(self, name, state_topic, availability_topic, device_class,
|
||||
qos, payload_on, payload_off, payload_available,
|
||||
payload_not_available, value_template):
|
||||
"""Initialize the MQTT binary sensor."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._name = name
|
||||
self._state = None
|
||||
self._state_topic = state_topic
|
||||
self._availability_topic = availability_topic
|
||||
self._available = True if availability_topic is None else False
|
||||
self._device_class = device_class
|
||||
self._payload_on = payload_on
|
||||
self._payload_off = payload_off
|
||||
self._payload_available = payload_available
|
||||
self._payload_not_available = payload_not_available
|
||||
self._qos = qos
|
||||
self._template = value_template
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe mqtt events.
|
||||
"""Subscribe mqtt events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method must be run in the event loop and returns a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def state_message_received(topic, payload, qos):
|
||||
"""Handle a new received MQTT state message."""
|
||||
|
@ -111,21 +100,6 @@ class MqttBinarySensor(BinarySensorDevice):
|
|||
yield from mqtt.async_subscribe(
|
||||
self.hass, self._state_topic, state_message_received, self._qos)
|
||||
|
||||
@callback
|
||||
def availability_message_received(topic, payload, qos):
|
||||
"""Handle a new received MQTT availability message."""
|
||||
if payload == self._payload_available:
|
||||
self._available = True
|
||||
elif payload == self._payload_not_available:
|
||||
self._available = False
|
||||
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
if self._availability_topic is not None:
|
||||
yield from mqtt.async_subscribe(
|
||||
self.hass, self._availability_topic,
|
||||
availability_message_received, self._qos)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return the polling state."""
|
||||
|
@ -136,11 +110,6 @@ class MqttBinarySensor(BinarySensorDevice):
|
|||
"""Return the name of the binary sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if the binary sensor is available."""
|
||||
return self._available
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if the binary sensor is on."""
|
||||
|
|
|
@ -60,11 +60,9 @@ class MqttCamera(Camera):
|
|||
"""Return the name of this camera."""
|
||||
return self._name
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe MQTT events.
|
||||
|
||||
This method must be run in the event loop and returns a coroutine.
|
||||
"""
|
||||
"""Subscribe MQTT events."""
|
||||
@callback
|
||||
def message_received(topic, payload, qos):
|
||||
"""Handle new MQTT messages."""
|
||||
|
|
|
@ -20,8 +20,9 @@ from homeassistant.components.climate import (
|
|||
SUPPORT_AUX_HEAT)
|
||||
from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, ATTR_TEMPERATURE, CONF_NAME)
|
||||
from homeassistant.components.mqtt import (CONF_QOS, CONF_RETAIN,
|
||||
MQTT_BASE_PLATFORM_SCHEMA)
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_AVAILABILITY_TOPIC, CONF_QOS, CONF_RETAIN, CONF_PAYLOAD_AVAILABLE,
|
||||
CONF_PAYLOAD_NOT_AVAILABLE, MQTT_BASE_PLATFORM_SCHEMA, MqttAvailability)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components.fan import (SPEED_LOW, SPEED_MEDIUM,
|
||||
SPEED_HIGH)
|
||||
|
@ -93,7 +94,7 @@ PLATFORM_SCHEMA = SCHEMA_BASE.extend({
|
|||
vol.Optional(CONF_SEND_IF_OFF, default=True): cv.boolean,
|
||||
vol.Optional(CONF_PAYLOAD_ON, default="ON"): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_OFF, default="OFF"): cv.string,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -134,19 +135,25 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
STATE_OFF, STATE_OFF, False,
|
||||
config.get(CONF_SEND_IF_OFF),
|
||||
config.get(CONF_PAYLOAD_ON),
|
||||
config.get(CONF_PAYLOAD_OFF))
|
||||
config.get(CONF_PAYLOAD_OFF),
|
||||
config.get(CONF_AVAILABILITY_TOPIC),
|
||||
config.get(CONF_PAYLOAD_AVAILABLE),
|
||||
config.get(CONF_PAYLOAD_NOT_AVAILABLE))
|
||||
])
|
||||
|
||||
|
||||
class MqttClimate(ClimateDevice):
|
||||
class MqttClimate(MqttAvailability, ClimateDevice):
|
||||
"""Representation of a demo climate device."""
|
||||
|
||||
def __init__(self, hass, name, topic, qos, retain, mode_list,
|
||||
fan_mode_list, swing_mode_list, target_temperature, away,
|
||||
hold, current_fan_mode, current_swing_mode,
|
||||
current_operation, aux, send_if_off, payload_on,
|
||||
payload_off):
|
||||
payload_off, availability_topic, payload_available,
|
||||
payload_not_available):
|
||||
"""Initialize the climate device."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self.hass = hass
|
||||
self._name = name
|
||||
self._topic = topic
|
||||
|
@ -169,8 +176,11 @@ class MqttClimate(ClimateDevice):
|
|||
self._payload_on = payload_on
|
||||
self._payload_off = payload_off
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Handle being added to home assistant."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
@callback
|
||||
def handle_current_temp_received(topic, payload, qos):
|
||||
"""Handle current temperature coming via MQTT."""
|
||||
|
|
|
@ -21,8 +21,9 @@ from homeassistant.const import (
|
|||
CONF_NAME, CONF_VALUE_TEMPLATE, CONF_OPTIMISTIC, STATE_OPEN,
|
||||
STATE_CLOSED, STATE_UNKNOWN)
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_AVAILABILITY_TOPIC,
|
||||
CONF_QOS, CONF_RETAIN, valid_publish_topic, valid_subscribe_topic)
|
||||
CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC, CONF_COMMAND_TOPIC,
|
||||
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN,
|
||||
valid_publish_topic, valid_subscribe_topic, MqttAvailability)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -37,8 +38,6 @@ CONF_SET_POSITION_TEMPLATE = 'set_position_template'
|
|||
CONF_PAYLOAD_OPEN = 'payload_open'
|
||||
CONF_PAYLOAD_CLOSE = 'payload_close'
|
||||
CONF_PAYLOAD_STOP = 'payload_stop'
|
||||
CONF_PAYLOAD_AVAILABLE = 'payload_available'
|
||||
CONF_PAYLOAD_NOT_AVAILABLE = 'payload_not_available'
|
||||
CONF_STATE_OPEN = 'state_open'
|
||||
CONF_STATE_CLOSED = 'state_closed'
|
||||
CONF_TILT_CLOSED_POSITION = 'tilt_closed_value'
|
||||
|
@ -52,8 +51,6 @@ DEFAULT_NAME = 'MQTT Cover'
|
|||
DEFAULT_PAYLOAD_OPEN = 'OPEN'
|
||||
DEFAULT_PAYLOAD_CLOSE = 'CLOSE'
|
||||
DEFAULT_PAYLOAD_STOP = 'STOP'
|
||||
DEFAULT_PAYLOAD_AVAILABLE = 'online'
|
||||
DEFAULT_PAYLOAD_NOT_AVAILABLE = 'offline'
|
||||
DEFAULT_OPTIMISTIC = False
|
||||
DEFAULT_RETAIN = False
|
||||
DEFAULT_TILT_CLOSED_POSITION = 0
|
||||
|
@ -73,16 +70,11 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_SET_POSITION_TEMPLATE, default=None): cv.template,
|
||||
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
|
||||
vol.Optional(CONF_STATE_TOPIC): valid_subscribe_topic,
|
||||
vol.Optional(CONF_AVAILABILITY_TOPIC, default=None): valid_subscribe_topic,
|
||||
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_OPEN, default=DEFAULT_PAYLOAD_OPEN): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_AVAILABLE,
|
||||
default=DEFAULT_PAYLOAD_AVAILABLE): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_NOT_AVAILABLE,
|
||||
default=DEFAULT_PAYLOAD_NOT_AVAILABLE): cv.string,
|
||||
vol.Optional(CONF_STATE_OPEN, default=STATE_OPEN): cv.string,
|
||||
vol.Optional(CONF_STATE_CLOSED, default=STATE_CLOSED): cv.string,
|
||||
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
||||
|
@ -98,7 +90,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
|
|||
default=DEFAULT_TILT_OPTIMISTIC): cv.boolean,
|
||||
vol.Optional(CONF_TILT_INVERT_STATE,
|
||||
default=DEFAULT_TILT_INVERT_STATE): cv.boolean,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -143,7 +135,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
)])
|
||||
|
||||
|
||||
class MqttCover(CoverDevice):
|
||||
class MqttCover(MqttAvailability, CoverDevice):
|
||||
"""Representation of a cover that can be controlled using MQTT."""
|
||||
|
||||
def __init__(self, name, state_topic, command_topic, availability_topic,
|
||||
|
@ -154,21 +146,19 @@ class MqttCover(CoverDevice):
|
|||
tilt_closed_position, tilt_min, tilt_max, tilt_optimistic,
|
||||
tilt_invert, position_topic, set_position_template):
|
||||
"""Initialize the cover."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._position = None
|
||||
self._state = None
|
||||
self._name = name
|
||||
self._state_topic = state_topic
|
||||
self._command_topic = command_topic
|
||||
self._availability_topic = availability_topic
|
||||
self._available = True if availability_topic is None else False
|
||||
self._tilt_command_topic = tilt_command_topic
|
||||
self._tilt_status_topic = tilt_status_topic
|
||||
self._qos = qos
|
||||
self._payload_open = payload_open
|
||||
self._payload_close = payload_close
|
||||
self._payload_stop = payload_stop
|
||||
self._payload_available = payload_available
|
||||
self._payload_not_available = payload_not_available
|
||||
self._state_open = state_open
|
||||
self._state_closed = state_closed
|
||||
self._retain = retain
|
||||
|
@ -186,10 +176,9 @@ class MqttCover(CoverDevice):
|
|||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe MQTT events.
|
||||
"""Subscribe MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def tilt_updated(topic, payload, qos):
|
||||
"""Handle tilt updates."""
|
||||
|
@ -266,11 +255,6 @@ class MqttCover(CoverDevice):
|
|||
"""Return the name of the cover."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if cover is available."""
|
||||
return self._available
|
||||
|
||||
@property
|
||||
def is_closed(self):
|
||||
"""Return if the cover is closed."""
|
||||
|
|
|
@ -15,7 +15,9 @@ from homeassistant.const import (
|
|||
CONF_NAME, CONF_OPTIMISTIC, CONF_STATE, STATE_ON, STATE_OFF,
|
||||
CONF_PAYLOAD_OFF, CONF_PAYLOAD_ON)
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
|
||||
CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC, CONF_COMMAND_TOPIC,
|
||||
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN,
|
||||
MqttAvailability)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components.fan import (SPEED_LOW, SPEED_MEDIUM,
|
||||
SPEED_HIGH, FanEntity,
|
||||
|
@ -72,7 +74,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
|
|||
default=[SPEED_OFF, SPEED_LOW,
|
||||
SPEED_MEDIUM, SPEED_HIGH]): cv.ensure_list,
|
||||
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -111,15 +113,21 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
},
|
||||
config.get(CONF_SPEED_LIST),
|
||||
config.get(CONF_OPTIMISTIC),
|
||||
config.get(CONF_AVAILABILITY_TOPIC),
|
||||
config.get(CONF_PAYLOAD_AVAILABLE),
|
||||
config.get(CONF_PAYLOAD_NOT_AVAILABLE),
|
||||
)])
|
||||
|
||||
|
||||
class MqttFan(FanEntity):
|
||||
class MqttFan(MqttAvailability, FanEntity):
|
||||
"""A MQTT fan component."""
|
||||
|
||||
def __init__(self, name, topic, templates, qos, retain, payload,
|
||||
speed_list, optimistic):
|
||||
speed_list, optimistic, availability_topic, payload_available,
|
||||
payload_not_available):
|
||||
"""Initialize the MQTT fan."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._name = name
|
||||
self._topic = topic
|
||||
self._qos = qos
|
||||
|
@ -143,10 +151,9 @@ class MqttFan(FanEntity):
|
|||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to MQTT events.
|
||||
"""Subscribe to MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
templates = {}
|
||||
for key, tpl in list(self._templates.items()):
|
||||
if tpl is None:
|
||||
|
|
|
@ -21,7 +21,9 @@ from homeassistant.const import (
|
|||
CONF_OPTIMISTIC, CONF_PAYLOAD_OFF, CONF_PAYLOAD_ON,
|
||||
CONF_RGB, CONF_STATE, CONF_VALUE_TEMPLATE, CONF_WHITE_VALUE, CONF_XY)
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN, CONF_STATE_TOPIC)
|
||||
CONF_AVAILABILITY_TOPIC, CONF_COMMAND_TOPIC, CONF_PAYLOAD_AVAILABLE,
|
||||
CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN, CONF_STATE_TOPIC,
|
||||
MqttAvailability)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -95,7 +97,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_XY_VALUE_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_ON_COMMAND_TYPE, default=DEFAULT_ON_COMMAND_TYPE):
|
||||
vol.In(VALUES_ON_COMMAND_TYPE),
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -148,16 +150,22 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
config.get(CONF_BRIGHTNESS_SCALE),
|
||||
config.get(CONF_WHITE_VALUE_SCALE),
|
||||
config.get(CONF_ON_COMMAND_TYPE),
|
||||
config.get(CONF_AVAILABILITY_TOPIC),
|
||||
config.get(CONF_PAYLOAD_AVAILABLE),
|
||||
config.get(CONF_PAYLOAD_NOT_AVAILABLE),
|
||||
)])
|
||||
|
||||
|
||||
class MqttLight(Light):
|
||||
class MqttLight(MqttAvailability, Light):
|
||||
"""Representation of a MQTT light."""
|
||||
|
||||
def __init__(self, name, effect_list, topic, templates, qos,
|
||||
retain, payload, optimistic, brightness_scale,
|
||||
white_value_scale, on_command_type):
|
||||
white_value_scale, on_command_type, availability_topic,
|
||||
payload_available, payload_not_available):
|
||||
"""Initialize MQTT light."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._name = name
|
||||
self._effect_list = effect_list
|
||||
self._topic = topic
|
||||
|
@ -208,10 +216,9 @@ class MqttLight(Light):
|
|||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to MQTT events.
|
||||
"""Subscribe to MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
templates = {}
|
||||
for key, tpl in list(self._templates.items()):
|
||||
if tpl is None:
|
||||
|
|
|
@ -21,7 +21,9 @@ from homeassistant.const import (
|
|||
CONF_BRIGHTNESS, CONF_COLOR_TEMP, CONF_EFFECT,
|
||||
CONF_NAME, CONF_OPTIMISTIC, CONF_RGB, CONF_WHITE_VALUE, CONF_XY)
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
|
||||
CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC, CONF_COMMAND_TOPIC,
|
||||
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN,
|
||||
MqttAvailability)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -66,7 +68,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_WHITE_VALUE, default=DEFAULT_WHITE_VALUE): cv.boolean,
|
||||
vol.Optional(CONF_XY, default=DEFAULT_XY): cv.boolean,
|
||||
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -97,17 +99,23 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
CONF_FLASH_TIME_SHORT,
|
||||
CONF_FLASH_TIME_LONG
|
||||
)
|
||||
}
|
||||
},
|
||||
config.get(CONF_AVAILABILITY_TOPIC),
|
||||
config.get(CONF_PAYLOAD_AVAILABLE),
|
||||
config.get(CONF_PAYLOAD_NOT_AVAILABLE)
|
||||
)])
|
||||
|
||||
|
||||
class MqttJson(Light):
|
||||
class MqttJson(MqttAvailability, Light):
|
||||
"""Representation of a MQTT JSON light."""
|
||||
|
||||
def __init__(self, name, effect_list, topic, qos, retain, optimistic,
|
||||
brightness, color_temp, effect, rgb, white_value, xy,
|
||||
flash_times):
|
||||
flash_times, availability_topic, payload_available,
|
||||
payload_not_available):
|
||||
"""Initialize MQTT JSON light."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._name = name
|
||||
self._effect_list = effect_list
|
||||
self._topic = topic
|
||||
|
@ -157,10 +165,9 @@ class MqttJson(Light):
|
|||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to MQTT events.
|
||||
"""Subscribe to MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def state_received(topic, payload, qos):
|
||||
"""Handle new MQTT messages."""
|
||||
|
|
|
@ -17,7 +17,9 @@ from homeassistant.components.light import (
|
|||
SUPPORT_RGB_COLOR, SUPPORT_TRANSITION, SUPPORT_WHITE_VALUE)
|
||||
from homeassistant.const import CONF_NAME, CONF_OPTIMISTIC, STATE_ON, STATE_OFF
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
|
||||
CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC, CONF_COMMAND_TOPIC,
|
||||
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN,
|
||||
MqttAvailability)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -60,7 +62,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
|
||||
vol.Optional(CONF_QOS, default=mqtt.DEFAULT_QOS):
|
||||
vol.All(vol.Coerce(int), vol.In([0, 1, 2])),
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -95,16 +97,22 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
},
|
||||
config.get(CONF_OPTIMISTIC),
|
||||
config.get(CONF_QOS),
|
||||
config.get(CONF_RETAIN)
|
||||
config.get(CONF_RETAIN),
|
||||
config.get(CONF_AVAILABILITY_TOPIC),
|
||||
config.get(CONF_PAYLOAD_AVAILABLE),
|
||||
config.get(CONF_PAYLOAD_NOT_AVAILABLE),
|
||||
)])
|
||||
|
||||
|
||||
class MqttTemplate(Light):
|
||||
class MqttTemplate(MqttAvailability, Light):
|
||||
"""Representation of a MQTT Template light."""
|
||||
|
||||
def __init__(self, hass, name, effect_list, topics, templates, optimistic,
|
||||
qos, retain):
|
||||
qos, retain, availability_topic, payload_available,
|
||||
payload_not_available):
|
||||
"""Initialize a MQTT Template light."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._name = name
|
||||
self._effect_list = effect_list
|
||||
self._topics = topics
|
||||
|
@ -145,10 +153,9 @@ class MqttTemplate(Light):
|
|||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to MQTT events.
|
||||
"""Subscribe to MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def state_received(topic, payload, qos):
|
||||
"""Handle new MQTT messages."""
|
||||
|
|
|
@ -12,7 +12,9 @@ import voluptuous as vol
|
|||
from homeassistant.core import callback
|
||||
from homeassistant.components.lock import LockDevice
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN)
|
||||
CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC, CONF_COMMAND_TOPIC,
|
||||
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN,
|
||||
MqttAvailability)
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE)
|
||||
import homeassistant.components.mqtt as mqtt
|
||||
|
@ -36,7 +38,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_PAYLOAD_UNLOCK, default=DEFAULT_PAYLOAD_UNLOCK):
|
||||
cv.string,
|
||||
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -56,15 +58,21 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
config.get(CONF_PAYLOAD_UNLOCK),
|
||||
config.get(CONF_OPTIMISTIC),
|
||||
value_template,
|
||||
config.get(CONF_AVAILABILITY_TOPIC),
|
||||
config.get(CONF_PAYLOAD_AVAILABLE),
|
||||
config.get(CONF_PAYLOAD_NOT_AVAILABLE)
|
||||
)])
|
||||
|
||||
|
||||
class MqttLock(LockDevice):
|
||||
class MqttLock(MqttAvailability, LockDevice):
|
||||
"""Representation of a lock that can be toggled using MQTT."""
|
||||
|
||||
def __init__(self, name, state_topic, command_topic, qos, retain,
|
||||
payload_lock, payload_unlock, optimistic, value_template):
|
||||
payload_lock, payload_unlock, optimistic, value_template,
|
||||
availability_topic, payload_available, payload_not_available):
|
||||
"""Initialize the lock."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._state = False
|
||||
self._name = name
|
||||
self._state_topic = state_topic
|
||||
|
@ -78,10 +86,9 @@ class MqttLock(LockDevice):
|
|||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to MQTT events.
|
||||
"""Subscribe to MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def message_received(topic, payload, qos):
|
||||
"""Handle new MQTT messages."""
|
||||
|
|
|
@ -23,6 +23,7 @@ from homeassistant.loader import bind_hass
|
|||
from homeassistant.helpers import template, config_validation as cv
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect, dispatcher_send)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.util.async import (
|
||||
run_coroutine_threadsafe, run_callback_threadsafe)
|
||||
from homeassistant.const import (
|
||||
|
@ -59,6 +60,8 @@ CONF_WILL_MESSAGE = 'will_message'
|
|||
CONF_STATE_TOPIC = 'state_topic'
|
||||
CONF_COMMAND_TOPIC = 'command_topic'
|
||||
CONF_AVAILABILITY_TOPIC = 'availability_topic'
|
||||
CONF_PAYLOAD_AVAILABLE = 'payload_available'
|
||||
CONF_PAYLOAD_NOT_AVAILABLE = 'payload_not_available'
|
||||
CONF_QOS = 'qos'
|
||||
CONF_RETAIN = 'retain'
|
||||
|
||||
|
@ -73,6 +76,8 @@ DEFAULT_PROTOCOL = PROTOCOL_311
|
|||
DEFAULT_DISCOVERY = False
|
||||
DEFAULT_DISCOVERY_PREFIX = 'homeassistant'
|
||||
DEFAULT_TLS_PROTOCOL = 'auto'
|
||||
DEFAULT_PAYLOAD_AVAILABLE = 'online'
|
||||
DEFAULT_PAYLOAD_NOT_AVAILABLE = 'offline'
|
||||
|
||||
ATTR_TOPIC = 'topic'
|
||||
ATTR_PAYLOAD = 'payload'
|
||||
|
@ -145,6 +150,14 @@ SCHEMA_BASE = {
|
|||
vol.Optional(CONF_QOS, default=DEFAULT_QOS): _VALID_QOS_SCHEMA,
|
||||
}
|
||||
|
||||
MQTT_AVAILABILITY_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_AVAILABILITY_TOPIC): valid_subscribe_topic,
|
||||
vol.Optional(CONF_PAYLOAD_AVAILABLE,
|
||||
default=DEFAULT_PAYLOAD_AVAILABLE): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_NOT_AVAILABLE,
|
||||
default=DEFAULT_PAYLOAD_NOT_AVAILABLE): cv.string,
|
||||
})
|
||||
|
||||
MQTT_BASE_PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(SCHEMA_BASE)
|
||||
|
||||
# Sensor type platforms subscribe to MQTT events
|
||||
|
@ -653,3 +666,41 @@ def _match_topic(subscription, topic):
|
|||
reg = re.compile(reg_ex)
|
||||
|
||||
return reg.match(topic) is not None
|
||||
|
||||
|
||||
class MqttAvailability(Entity):
|
||||
"""Mixin used for platforms that report availability."""
|
||||
|
||||
def __init__(self, availability_topic, qos, payload_available,
|
||||
payload_not_available):
|
||||
"""Initialize the availability mixin."""
|
||||
self._availability_topic = availability_topic
|
||||
self._availability_qos = qos
|
||||
self._available = availability_topic is None
|
||||
self._payload_available = payload_available
|
||||
self._payload_not_available = payload_not_available
|
||||
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe mqtt events.
|
||||
|
||||
This method must be run in the event loop and returns a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def availability_message_received(topic, payload, qos):
|
||||
"""Handle a new received MQTT availability message."""
|
||||
if payload == self._payload_available:
|
||||
self._available = True
|
||||
elif payload == self._payload_not_available:
|
||||
self._available = False
|
||||
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
if self._availability_topic is not None:
|
||||
yield from async_subscribe(
|
||||
self.hass, self._availability_topic,
|
||||
availability_message_received, self. _availability_qos)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if the device is available."""
|
||||
return self._available
|
||||
|
|
|
@ -11,7 +11,9 @@ from datetime import timedelta
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.components.mqtt import CONF_STATE_TOPIC, CONF_QOS
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC, CONF_PAYLOAD_AVAILABLE,
|
||||
CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, MqttAvailability)
|
||||
from homeassistant.const import (
|
||||
CONF_FORCE_UPDATE, CONF_NAME, CONF_VALUE_TEMPLATE, STATE_UNKNOWN,
|
||||
CONF_UNIT_OF_MEASUREMENT)
|
||||
|
@ -34,7 +36,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
||||
vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int,
|
||||
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -55,15 +57,21 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
config.get(CONF_FORCE_UPDATE),
|
||||
config.get(CONF_EXPIRE_AFTER),
|
||||
value_template,
|
||||
config.get(CONF_AVAILABILITY_TOPIC),
|
||||
config.get(CONF_PAYLOAD_AVAILABLE),
|
||||
config.get(CONF_PAYLOAD_NOT_AVAILABLE),
|
||||
)])
|
||||
|
||||
|
||||
class MqttSensor(Entity):
|
||||
class MqttSensor(MqttAvailability, Entity):
|
||||
"""Representation of a sensor that can be updated using MQTT."""
|
||||
|
||||
def __init__(self, name, state_topic, qos, unit_of_measurement,
|
||||
force_update, expire_after, value_template):
|
||||
force_update, expire_after, value_template,
|
||||
availability_topic, payload_available, payload_not_available):
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._state = STATE_UNKNOWN
|
||||
self._name = name
|
||||
self._state_topic = state_topic
|
||||
|
@ -74,11 +82,11 @@ class MqttSensor(Entity):
|
|||
self._expire_after = expire_after
|
||||
self._expiration_trigger = None
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to MQTT events.
|
||||
"""Subscribe to MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method must be run in the event loop and returns a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def message_received(topic, payload, qos):
|
||||
"""Handle new MQTT messages."""
|
||||
|
@ -102,7 +110,7 @@ class MqttSensor(Entity):
|
|||
self._state = payload
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
return mqtt.async_subscribe(
|
||||
yield from mqtt.async_subscribe(
|
||||
self.hass, self._state_topic, message_received, self._qos)
|
||||
|
||||
@callback
|
||||
|
|
|
@ -80,11 +80,9 @@ class MQTTRoomSensor(Entity):
|
|||
self._distance = None
|
||||
self._updated = None
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to MQTT events.
|
||||
|
||||
This method must be run in the event loop and returns a coroutine.
|
||||
"""
|
||||
"""Subscribe to MQTT events."""
|
||||
@callback
|
||||
def update_state(device_id, room, distance):
|
||||
"""Update the sensor state."""
|
||||
|
|
|
@ -11,8 +11,9 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.components.mqtt import (
|
||||
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_AVAILABILITY_TOPIC, CONF_QOS,
|
||||
CONF_RETAIN)
|
||||
CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_AVAILABILITY_TOPIC,
|
||||
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN,
|
||||
MqttAvailability)
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE, CONF_PAYLOAD_OFF,
|
||||
|
@ -24,26 +25,17 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
DEPENDENCIES = ['mqtt']
|
||||
|
||||
CONF_PAYLOAD_AVAILABLE = 'payload_available'
|
||||
CONF_PAYLOAD_NOT_AVAILABLE = 'payload_not_available'
|
||||
|
||||
DEFAULT_NAME = 'MQTT Switch'
|
||||
DEFAULT_PAYLOAD_ON = 'ON'
|
||||
DEFAULT_PAYLOAD_OFF = 'OFF'
|
||||
DEFAULT_OPTIMISTIC = False
|
||||
DEFAULT_PAYLOAD_AVAILABLE = 'ON'
|
||||
DEFAULT_PAYLOAD_NOT_AVAILABLE = 'OFF'
|
||||
|
||||
PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
|
||||
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
||||
vol.Optional(CONF_PAYLOAD_AVAILABLE,
|
||||
default=DEFAULT_PAYLOAD_AVAILABLE): cv.string,
|
||||
vol.Optional(CONF_PAYLOAD_NOT_AVAILABLE,
|
||||
default=DEFAULT_PAYLOAD_NOT_AVAILABLE): cv.string,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -72,34 +64,31 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
)])
|
||||
|
||||
|
||||
class MqttSwitch(SwitchDevice):
|
||||
class MqttSwitch(MqttAvailability, SwitchDevice):
|
||||
"""Representation of a switch that can be toggled using MQTT."""
|
||||
|
||||
def __init__(self, name, state_topic, command_topic, availability_topic,
|
||||
qos, retain, payload_on, payload_off, optimistic,
|
||||
payload_available, payload_not_available, value_template):
|
||||
"""Initialize the MQTT switch."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
self._state = False
|
||||
self._name = name
|
||||
self._state_topic = state_topic
|
||||
self._command_topic = command_topic
|
||||
self._availability_topic = availability_topic
|
||||
self._available = True if availability_topic is None else False
|
||||
self._qos = qos
|
||||
self._retain = retain
|
||||
self._payload_on = payload_on
|
||||
self._payload_off = payload_off
|
||||
self._optimistic = optimistic
|
||||
self._template = value_template
|
||||
self._payload_available = payload_available
|
||||
self._payload_not_available = payload_not_available
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to MQTT events.
|
||||
"""Subscribe to MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def state_message_received(topic, payload, qos):
|
||||
"""Handle new MQTT state messages."""
|
||||
|
@ -113,16 +102,6 @@ class MqttSwitch(SwitchDevice):
|
|||
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
@callback
|
||||
def availability_message_received(topic, payload, qos):
|
||||
"""Handle new MQTT availability messages."""
|
||||
if payload == self._payload_available:
|
||||
self._available = True
|
||||
elif payload == self._payload_not_available:
|
||||
self._available = False
|
||||
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
if self._state_topic is None:
|
||||
# Force into optimistic mode.
|
||||
self._optimistic = True
|
||||
|
@ -131,11 +110,6 @@ class MqttSwitch(SwitchDevice):
|
|||
self.hass, self._state_topic, state_message_received,
|
||||
self._qos)
|
||||
|
||||
if self._availability_topic is not None:
|
||||
yield from mqtt.async_subscribe(
|
||||
self.hass, self._availability_topic,
|
||||
availability_message_received, self._qos)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return the polling state."""
|
||||
|
@ -146,11 +120,6 @@ class MqttSwitch(SwitchDevice):
|
|||
"""Return the name of the switch."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if switch is available."""
|
||||
return self._available
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if device is on."""
|
||||
|
|
|
@ -11,6 +11,7 @@ import voluptuous as vol
|
|||
|
||||
import homeassistant.components.mqtt as mqtt
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components.mqtt import MqttAvailability
|
||||
from homeassistant.components.vacuum import (
|
||||
DEFAULT_ICON, SUPPORT_BATTERY, SUPPORT_CLEAN_SPOT, SUPPORT_FAN_SPEED,
|
||||
SUPPORT_LOCATE, SUPPORT_PAUSE, SUPPORT_RETURN_HOME, SUPPORT_SEND_COMMAND,
|
||||
|
@ -135,7 +136,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_FAN_SPEED_LIST, default=[]):
|
||||
vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_SEND_COMMAND_TOPIC): mqtt.valid_publish_topic,
|
||||
})
|
||||
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -187,6 +188,10 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
|
||||
send_command_topic = config.get(CONF_SEND_COMMAND_TOPIC)
|
||||
|
||||
availability_topic = config.get(mqtt.CONF_AVAILABILITY_TOPIC)
|
||||
payload_available = config.get(mqtt.CONF_PAYLOAD_AVAILABLE)
|
||||
payload_not_available = config.get(mqtt.CONF_PAYLOAD_NOT_AVAILABLE)
|
||||
|
||||
async_add_devices([
|
||||
MqttVacuum(
|
||||
name, supported_features, qos, retain, command_topic,
|
||||
|
@ -196,12 +201,13 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
charging_topic, charging_template, cleaning_topic,
|
||||
cleaning_template, docked_topic, docked_template, fan_speed_topic,
|
||||
fan_speed_template, set_fan_speed_topic, fan_speed_list,
|
||||
send_command_topic
|
||||
send_command_topic, availability_topic, payload_available,
|
||||
payload_not_available
|
||||
),
|
||||
])
|
||||
|
||||
|
||||
class MqttVacuum(VacuumDevice):
|
||||
class MqttVacuum(MqttAvailability, VacuumDevice):
|
||||
"""Representation of a MQTT-controlled vacuum."""
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
|
@ -213,8 +219,12 @@ class MqttVacuum(VacuumDevice):
|
|||
charging_topic, charging_template, cleaning_topic,
|
||||
cleaning_template, docked_topic, docked_template, fan_speed_topic,
|
||||
fan_speed_template, set_fan_speed_topic, fan_speed_list,
|
||||
send_command_topic):
|
||||
send_command_topic, availability_topic, payload_available,
|
||||
payload_not_available):
|
||||
"""Initialize the vacuum."""
|
||||
super().__init__(availability_topic, qos, payload_available,
|
||||
payload_not_available)
|
||||
|
||||
self._name = name
|
||||
self._supported_features = supported_features
|
||||
self._qos = qos
|
||||
|
@ -257,10 +267,9 @@ class MqttVacuum(VacuumDevice):
|
|||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe MQTT events.
|
||||
"""Subscribe MQTT events."""
|
||||
yield from super().async_added_to_hass()
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def message_received(topic, payload, qos):
|
||||
"""Handle new MQTT message."""
|
||||
|
|
|
@ -4,7 +4,8 @@ import unittest
|
|||
from homeassistant.setup import setup_component
|
||||
from homeassistant.const import (
|
||||
STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY,
|
||||
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN)
|
||||
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN)
|
||||
from homeassistant.components import alarm_control_panel
|
||||
|
||||
from tests.common import (
|
||||
|
@ -190,3 +191,33 @@ class TestAlarmControlPanelMQTT(unittest.TestCase):
|
|||
alarm_control_panel.alarm_disarm(self.hass, 'abcd')
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(call_count, self.mock_publish.call_count)
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test availability by custom payload with defined topic."""
|
||||
assert setup_component(self.hass, alarm_control_panel.DOMAIN, {
|
||||
alarm_control_panel.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
'state_topic': 'alarm/state',
|
||||
'command_topic': 'alarm/command',
|
||||
'code': '1234',
|
||||
'availability_topic': 'availability-topic',
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
}
|
||||
})
|
||||
|
||||
state = self.hass.states.get('alarm_control_panel.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('alarm_control_panel.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('alarm_control_panel.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
|
|
@ -7,7 +7,7 @@ from homeassistant.util.unit_system import (
|
|||
)
|
||||
from homeassistant.setup import setup_component
|
||||
from homeassistant.components import climate
|
||||
from homeassistant.const import STATE_OFF
|
||||
from homeassistant.const import STATE_OFF, STATE_UNAVAILABLE
|
||||
from homeassistant.components.climate import (
|
||||
SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE,
|
||||
SUPPORT_FAN_MODE, SUPPORT_SWING_MODE, SUPPORT_HOLD_MODE,
|
||||
|
@ -432,3 +432,27 @@ class TestMQTTClimate(unittest.TestCase):
|
|||
self.mock_publish.mock_calls[-2][1])
|
||||
state = self.hass.states.get(ENTITY_CLIMATE)
|
||||
self.assertEqual('off', state.attributes.get('aux_heat'))
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test availability by custom payload with defined topic."""
|
||||
config = copy.deepcopy(DEFAULT_CONFIG)
|
||||
config['climate']['availability_topic'] = 'availability-topic'
|
||||
config['climate']['payload_available'] = 'good'
|
||||
config['climate']['payload_not_available'] = 'nogood'
|
||||
|
||||
assert setup_component(self.hass, climate.DOMAIN, config)
|
||||
|
||||
state = self.hass.states.get('climate.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('climate.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('climate.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
"""Test MQTT fans."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.setup import setup_component
|
||||
from homeassistant.components import fan
|
||||
from homeassistant.const import ATTR_ASSUMED_STATE, STATE_UNAVAILABLE
|
||||
|
||||
from tests.common import (
|
||||
mock_mqtt_component, fire_mqtt_message, get_test_home_assistant)
|
||||
|
||||
|
||||
class TestMqttFan(unittest.TestCase):
|
||||
"""Test the MQTT fan platform."""
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.mock_publish = mock_mqtt_component(self.hass)
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
""""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test the availability payload."""
|
||||
assert setup_component(self.hass, fan.DOMAIN, {
|
||||
fan.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
'state_topic': 'state-topic',
|
||||
'command_topic': 'command-topic',
|
||||
'availability_topic': 'availability_topic',
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
}
|
||||
})
|
||||
|
||||
state = self.hass.states.get('fan.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('fan.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
self.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE))
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('fan.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'state-topic', '1')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('fan.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('fan.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
|
@ -142,7 +142,8 @@ import unittest
|
|||
from unittest import mock
|
||||
|
||||
from homeassistant.setup import setup_component
|
||||
from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE
|
||||
from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, STATE_UNAVAILABLE, ATTR_ASSUMED_STATE)
|
||||
import homeassistant.components.light as light
|
||||
from tests.common import (
|
||||
assert_setup_component, get_test_home_assistant, mock_mqtt_component,
|
||||
|
@ -794,3 +795,33 @@ class TestLightMQTT(unittest.TestCase):
|
|||
self.mock_publish.mock_calls[-4][1])
|
||||
self.assertEqual(('test_light/bright', 50, 0, False),
|
||||
self.mock_publish.mock_calls[-2][1])
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test availability by custom payload with defined topic."""
|
||||
self.assertTrue(setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
'command_topic': 'test_light/set',
|
||||
'brightness_command_topic': 'test_light/bright',
|
||||
'rgb_command_topic': "test_light/rgb",
|
||||
'availability_topic': 'availability-topic',
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
}
|
||||
}))
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
|
|
@ -82,7 +82,8 @@ import unittest
|
|||
|
||||
from homeassistant.setup import setup_component
|
||||
from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE, ATTR_SUPPORTED_FEATURES)
|
||||
STATE_ON, STATE_OFF, STATE_UNAVAILABLE, ATTR_ASSUMED_STATE,
|
||||
ATTR_SUPPORTED_FEATURES)
|
||||
import homeassistant.components.light as light
|
||||
from tests.common import (
|
||||
get_test_home_assistant, mock_mqtt_component, fire_mqtt_message,
|
||||
|
@ -472,3 +473,32 @@ class TestLightMQTTJSON(unittest.TestCase):
|
|||
state = self.hass.states.get('light.test')
|
||||
self.assertEqual(STATE_ON, state.state)
|
||||
self.assertEqual(255, state.attributes.get('white_value'))
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test availability by custom payload with defined topic."""
|
||||
self.assertTrue(setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt_json',
|
||||
'name': 'test',
|
||||
'state_topic': 'test_light_rgb',
|
||||
'command_topic': 'test_light_rgb/set',
|
||||
'availability_topic': 'availability-topic',
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
}
|
||||
}))
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
|
|
@ -29,7 +29,8 @@ If your light doesn't support RGB feature, omit `(red|green|blue)_template`.
|
|||
import unittest
|
||||
|
||||
from homeassistant.setup import setup_component
|
||||
from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE
|
||||
from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, STATE_UNAVAILABLE, ATTR_ASSUMED_STATE)
|
||||
import homeassistant.components.light as light
|
||||
from tests.common import (
|
||||
get_test_home_assistant, mock_mqtt_component, fire_mqtt_message,
|
||||
|
@ -463,3 +464,33 @@ class TestLightMQTTTemplate(unittest.TestCase):
|
|||
# effect should not have changed
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertEqual('rainbow', state.attributes.get('effect'))
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test availability by custom payload with defined topic."""
|
||||
self.assertTrue(setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt_template',
|
||||
'name': 'test',
|
||||
'command_topic': 'test_light_rgb/set',
|
||||
'command_on_template': 'on,{{ transition }}',
|
||||
'command_off_template': 'off,{{ transition|d }}',
|
||||
'availability_topic': 'availability-topic',
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
}
|
||||
}))
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('light.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
import unittest
|
||||
|
||||
from homeassistant.setup import setup_component
|
||||
from homeassistant.const import (STATE_LOCKED, STATE_UNLOCKED,
|
||||
ATTR_ASSUMED_STATE)
|
||||
from homeassistant.const import (
|
||||
STATE_LOCKED, STATE_UNLOCKED, STATE_UNAVAILABLE, ATTR_ASSUMED_STATE)
|
||||
import homeassistant.components.lock as lock
|
||||
from tests.common import (
|
||||
mock_mqtt_component, fire_mqtt_message, get_test_home_assistant)
|
||||
|
@ -111,3 +111,34 @@ class TestLockMQTT(unittest.TestCase):
|
|||
|
||||
state = self.hass.states.get('lock.test')
|
||||
self.assertEqual(STATE_UNLOCKED, state.state)
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test availability by custom payload with defined topic."""
|
||||
self.assertTrue(setup_component(self.hass, lock.DOMAIN, {
|
||||
lock.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
'state_topic': 'state-topic',
|
||||
'command_topic': 'command-topic',
|
||||
'payload_lock': 'LOCK',
|
||||
'payload_unlock': 'UNLOCK',
|
||||
'availability_topic': 'availability-topic',
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
}
|
||||
}))
|
||||
|
||||
state = self.hass.states.get('lock.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('lock.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('lock.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
|
|
@ -7,7 +7,7 @@ from unittest.mock import patch
|
|||
import homeassistant.core as ha
|
||||
from homeassistant.setup import setup_component
|
||||
import homeassistant.components.sensor as sensor
|
||||
from homeassistant.const import EVENT_STATE_CHANGED
|
||||
from homeassistant.const import EVENT_STATE_CHANGED, STATE_UNAVAILABLE
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import mock_mqtt_component, fire_mqtt_message
|
||||
|
@ -185,6 +185,34 @@ class TestSensorMQTT(unittest.TestCase):
|
|||
self.hass.block_till_done()
|
||||
self.assertEqual(2, len(events))
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test availability by custom payload with defined topic."""
|
||||
self.assertTrue(setup_component(self.hass, sensor.DOMAIN, {
|
||||
sensor.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
'state_topic': 'test-topic',
|
||||
'availability_topic': 'availability-topic',
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
}
|
||||
}))
|
||||
|
||||
state = self.hass.states.get('sensor.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('sensor.test')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('sensor.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
def _send_time_changed(self, now):
|
||||
"""Send a time changed event."""
|
||||
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: now})
|
||||
|
|
|
@ -167,22 +167,22 @@ class TestSwitchMQTT(unittest.TestCase):
|
|||
'availability_topic': 'availability_topic',
|
||||
'payload_on': 1,
|
||||
'payload_off': 0,
|
||||
'payload_available': 'online',
|
||||
'payload_not_available': 'offline'
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
}
|
||||
})
|
||||
|
||||
state = self.hass.states.get('switch.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'online')
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('switch.test')
|
||||
self.assertEqual(STATE_OFF, state.state)
|
||||
self.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE))
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'offline')
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('switch.test')
|
||||
|
@ -194,7 +194,7 @@ class TestSwitchMQTT(unittest.TestCase):
|
|||
state = self.hass.states.get('switch.test')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'online')
|
||||
fire_mqtt_message(self.hass, 'availability_topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('switch.test')
|
||||
|
|
|
@ -6,7 +6,8 @@ from homeassistant.components.vacuum import (
|
|||
ATTR_BATTERY_LEVEL, ATTR_BATTERY_ICON, ATTR_STATUS,
|
||||
ATTR_FAN_SPEED, mqtt)
|
||||
from homeassistant.components.mqtt import CONF_COMMAND_TOPIC
|
||||
from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, CONF_NAME
|
||||
from homeassistant.const import (
|
||||
CONF_PLATFORM, STATE_OFF, STATE_ON, STATE_UNAVAILABLE, CONF_NAME)
|
||||
from homeassistant.setup import setup_component
|
||||
from tests.common import (
|
||||
fire_mqtt_message, get_test_home_assistant, mock_mqtt_component)
|
||||
|
@ -197,3 +198,30 @@ class TestVacuumMQTT(unittest.TestCase):
|
|||
state = self.hass.states.get('vacuum.mqtttest')
|
||||
self.assertEqual(STATE_OFF, state.state)
|
||||
self.assertEqual("Stopped", state.attributes.get(ATTR_STATUS))
|
||||
|
||||
def test_custom_availability_payload(self):
|
||||
"""Test availability by custom payload with defined topic."""
|
||||
self.default_config.update({
|
||||
'availability_topic': 'availability-topic',
|
||||
'payload_available': 'good',
|
||||
'payload_not_available': 'nogood'
|
||||
})
|
||||
|
||||
self.assertTrue(setup_component(self.hass, vacuum.DOMAIN, {
|
||||
vacuum.DOMAIN: self.default_config,
|
||||
}))
|
||||
|
||||
state = self.hass.states.get('vacuum.mqtttest')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'good')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('vacuum.mqtttest')
|
||||
self.assertNotEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
||||
fire_mqtt_message(self.hass, 'availability-topic', 'nogood')
|
||||
self.hass.block_till_done()
|
||||
|
||||
state = self.hass.states.get('vacuum.mqtttest')
|
||||
self.assertEqual(STATE_UNAVAILABLE, state.state)
|
||||
|
|
Loading…
Reference in New Issue