2016-01-10 04:18:46 +00:00
|
|
|
"""
|
2016-02-26 22:52:54 +00:00
|
|
|
Connect two Home Assistant instances via MQTT.
|
2016-01-10 04:18:46 +00:00
|
|
|
|
2016-01-27 08:08:04 +00:00
|
|
|
For more details about this component, please refer to the documentation at
|
2016-02-26 22:52:54 +00:00
|
|
|
https://home-assistant.io/components/mqtt_eventstream/
|
2016-01-10 04:18:46 +00:00
|
|
|
"""
|
2017-02-22 08:43:22 +00:00
|
|
|
import asyncio
|
2016-01-10 04:18:46 +00:00
|
|
|
import json
|
2016-02-19 05:27:50 +00:00
|
|
|
|
2016-04-07 03:25:28 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2017-02-22 08:43:22 +00:00
|
|
|
from homeassistant.core import callback
|
2016-04-07 03:25:28 +00:00
|
|
|
from homeassistant.components.mqtt import (
|
|
|
|
valid_publish_topic, valid_subscribe_topic)
|
2016-01-10 04:18:46 +00:00
|
|
|
from homeassistant.const import (
|
2018-11-30 20:28:35 +00:00
|
|
|
ATTR_SERVICE_DATA, EVENT_CALL_SERVICE,
|
2016-02-19 05:27:50 +00:00
|
|
|
EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL)
|
|
|
|
from homeassistant.core import EventOrigin, State
|
2017-02-02 05:00:05 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2018-08-21 13:49:58 +00:00
|
|
|
from homeassistant.helpers.json import JSONEncoder
|
2016-01-10 04:18:46 +00:00
|
|
|
|
2017-04-30 05:04:49 +00:00
|
|
|
DOMAIN = 'mqtt_eventstream'
|
2016-01-10 04:18:46 +00:00
|
|
|
DEPENDENCIES = ['mqtt']
|
|
|
|
|
2016-04-07 03:25:28 +00:00
|
|
|
CONF_PUBLISH_TOPIC = 'publish_topic'
|
|
|
|
CONF_SUBSCRIBE_TOPIC = 'subscribe_topic'
|
2017-02-02 05:00:05 +00:00
|
|
|
CONF_PUBLISH_EVENTSTREAM_RECEIVED = 'publish_eventstream_received'
|
2018-02-22 10:19:18 +00:00
|
|
|
CONF_IGNORE_EVENT = 'ignore_event'
|
2016-04-07 03:25:28 +00:00
|
|
|
|
|
|
|
CONFIG_SCHEMA = vol.Schema({
|
|
|
|
DOMAIN: vol.Schema({
|
|
|
|
vol.Optional(CONF_PUBLISH_TOPIC): valid_publish_topic,
|
|
|
|
vol.Optional(CONF_SUBSCRIBE_TOPIC): valid_subscribe_topic,
|
2017-02-02 05:00:05 +00:00
|
|
|
vol.Optional(CONF_PUBLISH_EVENTSTREAM_RECEIVED, default=False):
|
|
|
|
cv.boolean,
|
2018-02-22 10:19:18 +00:00
|
|
|
vol.Optional(CONF_IGNORE_EVENT, default=[]): cv.ensure_list
|
2016-04-07 03:25:28 +00:00
|
|
|
}),
|
2016-04-07 04:42:56 +00:00
|
|
|
}, extra=vol.ALLOW_EXTRA)
|
2016-04-07 03:25:28 +00:00
|
|
|
|
2016-01-10 04:18:46 +00:00
|
|
|
|
2017-02-22 08:43:22 +00:00
|
|
|
@asyncio.coroutine
|
|
|
|
def async_setup(hass, config):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Set up the MQTT eventstream component."""
|
2018-05-01 18:57:30 +00:00
|
|
|
mqtt = hass.components.mqtt
|
2016-04-07 03:25:28 +00:00
|
|
|
conf = config.get(DOMAIN, {})
|
|
|
|
pub_topic = conf.get(CONF_PUBLISH_TOPIC)
|
|
|
|
sub_topic = conf.get(CONF_SUBSCRIBE_TOPIC)
|
2018-02-22 10:19:18 +00:00
|
|
|
ignore_event = conf.get(CONF_IGNORE_EVENT)
|
2016-01-13 02:01:53 +00:00
|
|
|
|
2017-02-22 08:43:22 +00:00
|
|
|
@callback
|
2016-01-13 02:01:53 +00:00
|
|
|
def _event_publisher(event):
|
2016-02-26 22:52:54 +00:00
|
|
|
"""Handle events by publishing them on the MQTT queue."""
|
2016-01-10 04:18:46 +00:00
|
|
|
if event.origin != EventOrigin.local:
|
|
|
|
return
|
2016-01-13 02:01:53 +00:00
|
|
|
if event.event_type == EVENT_TIME_CHANGED:
|
2016-01-10 04:18:46 +00:00
|
|
|
return
|
|
|
|
|
2018-02-22 10:19:18 +00:00
|
|
|
# User-defined events to ignore
|
|
|
|
if event.event_type in ignore_event:
|
|
|
|
return
|
|
|
|
|
2016-01-13 02:01:53 +00:00
|
|
|
# Filter out the events that were triggered by publishing
|
|
|
|
# to the MQTT topic, or you will end up in an infinite loop.
|
|
|
|
if event.event_type == EVENT_CALL_SERVICE:
|
|
|
|
if (
|
2016-04-07 03:25:28 +00:00
|
|
|
event.data.get('domain') == mqtt.DOMAIN and
|
|
|
|
event.data.get('service') == mqtt.SERVICE_PUBLISH and
|
2016-01-30 23:16:31 +00:00
|
|
|
event.data[ATTR_SERVICE_DATA].get('topic') == pub_topic
|
2016-01-13 02:01:53 +00:00
|
|
|
):
|
|
|
|
return
|
|
|
|
|
|
|
|
event_info = {'event_type': event.event_type, 'event_data': event.data}
|
|
|
|
msg = json.dumps(event_info, cls=JSONEncoder)
|
2018-05-01 18:57:30 +00:00
|
|
|
mqtt.async_publish(pub_topic, msg)
|
2016-01-10 04:18:46 +00:00
|
|
|
|
2016-02-26 22:52:54 +00:00
|
|
|
# Only listen for local events if you are going to publish them.
|
2016-01-13 02:01:53 +00:00
|
|
|
if pub_topic:
|
2017-02-22 08:43:22 +00:00
|
|
|
hass.bus.async_listen(MATCH_ALL, _event_publisher)
|
2016-01-10 04:18:46 +00:00
|
|
|
|
2016-02-26 22:52:54 +00:00
|
|
|
# Process events from a remote server that are received on a queue.
|
2017-02-22 08:43:22 +00:00
|
|
|
@callback
|
2016-01-10 04:18:46 +00:00
|
|
|
def _event_receiver(topic, payload, qos):
|
2016-03-08 16:55:57 +00:00
|
|
|
"""Receive events published by and fire them on this hass instance."""
|
2016-01-10 04:18:46 +00:00
|
|
|
event = json.loads(payload)
|
|
|
|
event_type = event.get('event_type')
|
|
|
|
event_data = event.get('event_data')
|
|
|
|
|
|
|
|
# Special case handling for event STATE_CHANGED
|
|
|
|
# We will try to convert state dicts back to State objects
|
2016-01-13 02:01:53 +00:00
|
|
|
# Copied over from the _handle_api_post_events_event method
|
|
|
|
# of the api component.
|
2016-01-10 04:18:46 +00:00
|
|
|
if event_type == EVENT_STATE_CHANGED and event_data:
|
|
|
|
for key in ('old_state', 'new_state'):
|
|
|
|
state = State.from_dict(event_data.get(key))
|
|
|
|
|
|
|
|
if state:
|
|
|
|
event_data[key] = state
|
|
|
|
|
2017-02-22 08:43:22 +00:00
|
|
|
hass.bus.async_fire(
|
2016-01-10 04:18:46 +00:00
|
|
|
event_type,
|
|
|
|
event_data=event_data,
|
|
|
|
origin=EventOrigin.remote
|
|
|
|
)
|
|
|
|
|
2016-02-26 22:52:54 +00:00
|
|
|
# Only subscribe if you specified a topic.
|
2016-01-13 02:01:53 +00:00
|
|
|
if sub_topic:
|
2018-05-01 18:57:30 +00:00
|
|
|
yield from mqtt.async_subscribe(sub_topic, _event_receiver)
|
2016-02-26 22:52:54 +00:00
|
|
|
|
2016-01-10 04:18:46 +00:00
|
|
|
return True
|