hass-core/homeassistant/components/mqtt/discovery.py
Paulus Schoutsen 5a9013cda5
Refactor Hue: phue -> aiohue (#13043)
* phue -> aiohue

* Clean up

* Fix config

* Address comments

* Typo

* Fix rebase error

* Mark light as unavailable when bridge is disconnected

* Tests

* Make Throttle work with double delay and async

* Rework update logic

* Don't resolve host to IP

* Clarify comment

* No longer do unnecessary updates

* Add more doc

* Another comment update

* Wrap up tests

* Lint

* Fix tests

* PyLint does not like mix 'n match async and coroutine

* Lint

* Update aiohue to 1.2

* Lint

* Fix await MagicMock
2018-03-16 20:27:05 -07:00

93 lines
3 KiB
Python

"""
Support for MQTT discovery.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/mqtt/#discovery
"""
import json
import logging
import re
import homeassistant.components.mqtt as mqtt
from homeassistant.helpers.discovery import async_load_platform
from homeassistant.const import CONF_PLATFORM
from homeassistant.components.mqtt import CONF_STATE_TOPIC
_LOGGER = logging.getLogger(__name__)
TOPIC_MATCHER = re.compile(
r'(?P<prefix_topic>\w+)/(?P<component>\w+)/'
r'(?:(?P<node_id>[a-zA-Z0-9_-]+)/)?(?P<object_id>[a-zA-Z0-9_-]+)/config')
SUPPORTED_COMPONENTS = [
'binary_sensor', 'cover', 'fan', 'light', 'sensor', 'switch']
ALLOWED_PLATFORMS = {
'binary_sensor': ['mqtt'],
'cover': ['mqtt'],
'fan': ['mqtt'],
'light': ['mqtt', 'mqtt_json', 'mqtt_template'],
'sensor': ['mqtt'],
'switch': ['mqtt'],
}
ALREADY_DISCOVERED = 'mqtt_discovered_components'
async def async_start(hass, discovery_topic, hass_config):
"""Initialize of MQTT Discovery."""
async def async_device_message_received(topic, payload, qos):
"""Process the received message."""
match = TOPIC_MATCHER.match(topic)
if not match:
return
_prefix_topic, component, node_id, object_id = match.groups()
try:
payload = json.loads(payload)
except ValueError:
_LOGGER.warning("Unable to parse JSON %s: %s", object_id, payload)
return
if component not in SUPPORTED_COMPONENTS:
_LOGGER.warning("Component %s is not supported", component)
return
payload = dict(payload)
platform = payload.get(CONF_PLATFORM, 'mqtt')
if platform not in ALLOWED_PLATFORMS.get(component, []):
_LOGGER.warning("Platform %s (component %s) is not allowed",
platform, component)
return
payload[CONF_PLATFORM] = platform
if CONF_STATE_TOPIC not in payload:
payload[CONF_STATE_TOPIC] = '{}/{}/{}{}/state'.format(
discovery_topic, component, '%s/' % node_id if node_id else '',
object_id)
if ALREADY_DISCOVERED not in hass.data:
hass.data[ALREADY_DISCOVERED] = set()
# If present, the node_id will be included in the discovered object id
discovery_id = '_'.join((node_id, object_id)) if node_id else object_id
discovery_hash = (component, discovery_id)
if discovery_hash in hass.data[ALREADY_DISCOVERED]:
_LOGGER.info("Component has already been discovered: %s %s",
component, discovery_id)
return
hass.data[ALREADY_DISCOVERED].add(discovery_hash)
_LOGGER.info("Found new component: %s %s", component, discovery_id)
await async_load_platform(
hass, component, platform, payload, hass_config)
await mqtt.async_subscribe(
hass, discovery_topic + '/#', async_device_message_received, 0)
return True