Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small refactoring of MQTT binary_sensor #18674

Merged
merged 1 commit into from
Nov 25, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 29 additions & 59 deletions homeassistant/components/binary_sensor/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
vol.Optional(CONF_OFF_DELAY):
vol.All(vol.Coerce(int), vol.Range(min=0)),
# Integrations shouldn't never expose unique_id through configuration
# this here is an exception because MQTT is a msg transport, not a protocol
# Integrations should never expose unique_id through configuration.
# This is an exception because MQTT is a message transport, not a protocol
vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA,
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
Expand All @@ -55,33 +55,25 @@
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
async_add_entities, discovery_info=None):
"""Set up MQTT binary sensor through configuration.yaml."""
await _async_setup_entity(hass, config, async_add_entities)
await _async_setup_entity(config, async_add_entities)


async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up MQTT binary sensor dynamically through MQTT discovery."""
async def async_discover(discovery_payload):
"""Discover and add a MQTT binary sensor."""
config = PLATFORM_SCHEMA(discovery_payload)
await _async_setup_entity(hass, config, async_add_entities,
await _async_setup_entity(config, async_add_entities,
discovery_payload[ATTR_DISCOVERY_HASH])

async_dispatcher_connect(
hass, MQTT_DISCOVERY_NEW.format(binary_sensor.DOMAIN, 'mqtt'),
async_discover)


async def _async_setup_entity(hass, config, async_add_entities,
discovery_hash=None):
async def _async_setup_entity(config, async_add_entities, discovery_hash=None):
"""Set up the MQTT binary sensor."""
value_template = config.get(CONF_VALUE_TEMPLATE)
if value_template is not None:
value_template.hass = hass

async_add_entities([MqttBinarySensor(
config,
discovery_hash
)])
async_add_entities([MqttBinarySensor(config, discovery_hash)])


class MqttBinarySensor(MqttAvailability, MqttDiscoveryUpdate,
Expand All @@ -91,30 +83,18 @@ class MqttBinarySensor(MqttAvailability, MqttDiscoveryUpdate,
def __init__(self, config, discovery_hash):
"""Initialize the MQTT binary sensor."""
self._config = config
self._unique_id = config.get(CONF_UNIQUE_ID)
self._state = None
self._sub_state = None
self._delay_listener = None

self._name = None
self._state_topic = None
self._device_class = None
self._payload_on = None
self._payload_off = None
self._qos = None
self._force_update = None
self._off_delay = None
self._template = None
self._unique_id = None

# Load config
self._setup_from_config(config)

availability_topic = config.get(CONF_AVAILABILITY_TOPIC)
payload_available = config.get(CONF_PAYLOAD_AVAILABLE)
payload_not_available = config.get(CONF_PAYLOAD_NOT_AVAILABLE)
qos = config.get(CONF_QOS)
device_config = config.get(CONF_DEVICE)

MqttAvailability.__init__(self, availability_topic, self._qos,
MqttAvailability.__init__(self, availability_topic, qos,
payload_available, payload_not_available)
MqttDiscoveryUpdate.__init__(self, discovery_hash,
self.discovery_update)
Expand All @@ -129,30 +109,17 @@ async def async_added_to_hass(self):
async def discovery_update(self, discovery_payload):
"""Handle updated discovery message."""
config = PLATFORM_SCHEMA(discovery_payload)
self._setup_from_config(config)
self._config = config
await self.availability_discovery_update(config)
await self._subscribe_topics()
self.async_schedule_update_ha_state()

def _setup_from_config(self, config):
"""(Re)Setup the entity."""
self._name = config.get(CONF_NAME)
self._state_topic = config.get(CONF_STATE_TOPIC)
self._device_class = config.get(CONF_DEVICE_CLASS)
self._qos = config.get(CONF_QOS)
self._force_update = config.get(CONF_FORCE_UPDATE)
self._off_delay = config.get(CONF_OFF_DELAY)
self._payload_on = config.get(CONF_PAYLOAD_ON)
self._payload_off = config.get(CONF_PAYLOAD_OFF)
value_template = config.get(CONF_VALUE_TEMPLATE)
if value_template is not None and value_template.hass is None:
value_template.hass = self.hass
self._template = value_template

self._unique_id = config.get(CONF_UNIQUE_ID)

async def _subscribe_topics(self):
"""(Re)Subscribe to topics."""
value_template = self._config.get(CONF_VALUE_TEMPLATE)
if value_template is not None:
value_template.hass = self.hass

@callback
def off_delay_listener(now):
"""Switch device off after a delay."""
Expand All @@ -163,34 +130,37 @@ def off_delay_listener(now):
@callback
def state_message_received(_topic, payload, _qos):
"""Handle a new received MQTT state message."""
if self._template is not None:
payload = self._template.async_render_with_possible_json_value(
value_template = self._config.get(CONF_VALUE_TEMPLATE)
if value_template is not None:
payload = value_template.async_render_with_possible_json_value(
payload)
if payload == self._payload_on:
if payload == self._config.get(CONF_PAYLOAD_ON):
self._state = True
elif payload == self._payload_off:
elif payload == self._config.get(CONF_PAYLOAD_OFF):
self._state = False
else: # Payload is not for this entity
_LOGGER.warning('No matching payload found'
' for entity: %s with state_topic: %s',
self._name, self._state_topic)
self._config.get(CONF_NAME),
self._config.get(CONF_STATE_TOPIC))
return

if self._delay_listener is not None:
self._delay_listener()
self._delay_listener = None

if (self._state and self._off_delay is not None):
off_delay = self._config.get(CONF_OFF_DELAY)
if (self._state and off_delay is not None):
self._delay_listener = evt.async_call_later(
self.hass, self._off_delay, off_delay_listener)
self.hass, off_delay, off_delay_listener)

self.async_schedule_update_ha_state()

self._sub_state = await subscription.async_subscribe_topics(
self.hass, self._sub_state,
{'state_topic': {'topic': self._state_topic,
{'state_topic': {'topic': self._config.get(CONF_STATE_TOPIC),
'msg_callback': state_message_received,
'qos': self._qos}})
'qos': self._config.get(CONF_QOS)}})

async def async_will_remove_from_hass(self):
"""Unsubscribe when removed."""
Expand All @@ -205,7 +175,7 @@ def should_poll(self):
@property
def name(self):
"""Return the name of the binary sensor."""
return self._name
return self._config.get(CONF_NAME)

@property
def is_on(self):
Expand All @@ -215,12 +185,12 @@ def is_on(self):
@property
def device_class(self):
"""Return the class of this sensor."""
return self._device_class
return self._config.get(CONF_DEVICE_CLASS)

@property
def force_update(self):
"""Force update."""
return self._force_update
return self._config.get(CONF_FORCE_UPDATE)

@property
def unique_id(self):
Expand Down