Merge pull request #3 from home-assistant/dev

Get latest
This commit is contained in:
jbarrancos 2017-10-11 16:04:37 +02:00 committed by GitHub
commit 2c9010d661
197 changed files with 7332 additions and 1468 deletions

View file

@ -149,6 +149,9 @@ omit =
homeassistant/components/rachio.py homeassistant/components/rachio.py
homeassistant/components/*/rachio.py homeassistant/components/*/rachio.py
homeassistant/components/raincloud.py
homeassistant/components/*/raincloud.py
homeassistant/components/raspihats.py homeassistant/components/raspihats.py
homeassistant/components/*/raspihats.py homeassistant/components/*/raspihats.py
@ -166,6 +169,9 @@ omit =
homeassistant/components/scsgate.py homeassistant/components/scsgate.py
homeassistant/components/*/scsgate.py homeassistant/components/*/scsgate.py
homeassistant/components/skybell.py
homeassistant/components/*/skybell.py
homeassistant/components/tado.py homeassistant/components/tado.py
homeassistant/components/*/tado.py homeassistant/components/*/tado.py
@ -179,6 +185,9 @@ omit =
homeassistant/components/tesla.py homeassistant/components/tesla.py
homeassistant/components/*/tesla.py homeassistant/components/*/tesla.py
homeassistant/components/thethingsnetwork.py
homeassistant/components/*/thethingsnetwork.py
homeassistant/components/*/thinkingcleaner.py homeassistant/components/*/thinkingcleaner.py
homeassistant/components/tradfri.py homeassistant/components/tradfri.py
@ -399,6 +408,7 @@ omit =
homeassistant/components/notify/aws_sqs.py homeassistant/components/notify/aws_sqs.py
homeassistant/components/notify/ciscospark.py homeassistant/components/notify/ciscospark.py
homeassistant/components/notify/clicksend.py homeassistant/components/notify/clicksend.py
homeassistant/components/notify/clicksendaudio.py
homeassistant/components/notify/discord.py homeassistant/components/notify/discord.py
homeassistant/components/notify/facebook.py homeassistant/components/notify/facebook.py
homeassistant/components/notify/free_mobile.py homeassistant/components/notify/free_mobile.py
@ -420,6 +430,7 @@ omit =
homeassistant/components/notify/pushover.py homeassistant/components/notify/pushover.py
homeassistant/components/notify/pushsafer.py homeassistant/components/notify/pushsafer.py
homeassistant/components/notify/rest.py homeassistant/components/notify/rest.py
homeassistant/components/notify/rocketchat.py
homeassistant/components/notify/sendgrid.py homeassistant/components/notify/sendgrid.py
homeassistant/components/notify/simplepush.py homeassistant/components/notify/simplepush.py
homeassistant/components/notify/slack.py homeassistant/components/notify/slack.py
@ -538,9 +549,11 @@ omit =
homeassistant/components/sensor/tank_utility.py homeassistant/components/sensor/tank_utility.py
homeassistant/components/sensor/ted5000.py homeassistant/components/sensor/ted5000.py
homeassistant/components/sensor/temper.py homeassistant/components/sensor/temper.py
homeassistant/components/sensor/tibber.py
homeassistant/components/sensor/time_date.py homeassistant/components/sensor/time_date.py
homeassistant/components/sensor/torque.py homeassistant/components/sensor/torque.py
homeassistant/components/sensor/transmission.py homeassistant/components/sensor/transmission.py
homeassistant/components/sensor/travisci.py
homeassistant/components/sensor/twitch.py homeassistant/components/sensor/twitch.py
homeassistant/components/sensor/uber.py homeassistant/components/sensor/uber.py
homeassistant/components/sensor/upnp.py homeassistant/components/sensor/upnp.py
@ -578,6 +591,7 @@ omit =
homeassistant/components/switch/telnet.py homeassistant/components/switch/telnet.py
homeassistant/components/switch/transmission.py homeassistant/components/switch/transmission.py
homeassistant/components/switch/wake_on_lan.py homeassistant/components/switch/wake_on_lan.py
homeassistant/components/switch/xiaomi_miio.py
homeassistant/components/telegram_bot/* homeassistant/components/telegram_bot/*
homeassistant/components/thingspeak.py homeassistant/components/thingspeak.py
homeassistant/components/tts/amazon_polly.py homeassistant/components/tts/amazon_polly.py

View file

@ -29,6 +29,9 @@ homeassistant/components/weblink.py @home-assistant/core
homeassistant/components/websocket_api.py @home-assistant/core homeassistant/components/websocket_api.py @home-assistant/core
homeassistant/components/zone.py @home-assistant/core homeassistant/components/zone.py @home-assistant/core
# To monitor non-pypi additions
requirements_all.txt @andrey-git
Dockerfile @home-assistant/docker Dockerfile @home-assistant/docker
virtualization/Docker/* @home-assistant/docker virtualization/Docker/* @home-assistant/docker
@ -36,6 +39,25 @@ homeassistant/components/zwave/* @home-assistant/z-wave
homeassistant/components/*/zwave.py @home-assistant/z-wave homeassistant/components/*/zwave.py @home-assistant/z-wave
# Indiviudal components # Indiviudal components
homeassistant/components/alarm_control_panel/egardia.py @jeroenterheerdt
homeassistant/components/climate/eq3btsmart.py @rytilahti
homeassistant/components/climate/sensibo.py @andrey-git
homeassistant/components/cover/template.py @PhracturedBlue homeassistant/components/cover/template.py @PhracturedBlue
homeassistant/components/device_tracker/automatic.py @armills homeassistant/components/device_tracker/automatic.py @armills
homeassistant/components/history_graph.py @andrey-git
homeassistant/components/light/tplink.py @rytilahti
homeassistant/components/light/yeelight.py @rytilahti
homeassistant/components/media_player/kodi.py @armills homeassistant/components/media_player/kodi.py @armills
homeassistant/components/sensor/airvisual.py @bachya
homeassistant/components/sensor/miflora.py @danielhiversen
homeassistant/components/sensor/tibber.py @danielhiversen
homeassistant/components/sensor/waqi.py @andrey-git
homeassistant/components/switch/rainmachine.py @bachya
homeassistant/components/switch/tplink.py @rytilahti
homeassistant/components/*/broadlink.py @danielhiversen
homeassistant/components/*/rfxtrx.py @danielhiversen
homeassistant/components/tesla.py @zabuldon
homeassistant/components/*/tesla.py @zabuldon
homeassistant/components/*/xiaomi_aqara.py @danielhiversen
homeassistant/components/*/xiaomi_miio.py @rytilahti

View file

@ -11,9 +11,10 @@ MAINTAINER Paulus Schoutsen <Paulus@PaulusSchoutsen.nl>
#ENV INSTALL_FFMPEG no #ENV INSTALL_FFMPEG no
#ENV INSTALL_LIBCEC no #ENV INSTALL_LIBCEC no
#ENV INSTALL_PHANTOMJS no #ENV INSTALL_PHANTOMJS no
#ENV INSTALL_COAP_CLIENT no #ENV INSTALL_COAP no
#ENV INSTALL_SSOCR no #ENV INSTALL_SSOCR no
VOLUME /config VOLUME /config
RUN mkdir -p /usr/src/app RUN mkdir -p /usr/src/app
@ -25,7 +26,6 @@ RUN virtualization/Docker/setup_docker_prereqs
# Install hass component dependencies # Install hass component dependencies
COPY requirements_all.txt requirements_all.txt COPY requirements_all.txt requirements_all.txt
# Uninstall enum34 because some depenndecies install it but breaks Python 3.4+. # Uninstall enum34 because some depenndecies install it but breaks Python 3.4+.
# See PR #8103 for more info. # See PR #8103 for more info.
RUN pip3 install --no-cache-dir -r requirements_all.txt && \ RUN pip3 install --no-cache-dir -r requirements_all.txt && \

View file

@ -117,7 +117,11 @@ def linkcode_resolve(domain, info):
linespec = "#L%d" % (lineno + 1) linespec = "#L%d" % (lineno + 1)
else: else:
linespec = "" linespec = ""
fn = relpath(fn, start='../') index = fn.find("/homeassistant/")
if index == -1:
index = 0
fn = fn[index:]
return '{}/blob/{}/{}{}'.format(GITHUB_URL, code_branch, fn, linespec) return '{}/blob/{}/{}{}'.format(GITHUB_URL, code_branch, fn, linespec)

View file

@ -11,13 +11,11 @@ from typing import Any, Optional, Dict
import voluptuous as vol import voluptuous as vol
import homeassistant.components as core_components from homeassistant import (
core, config as conf_util, loader, components as core_components)
from homeassistant.components import persistent_notification from homeassistant.components import persistent_notification
import homeassistant.config as conf_util
import homeassistant.core as core
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
import homeassistant.loader as loader
from homeassistant.util.logging import AsyncHandler from homeassistant.util.logging import AsyncHandler
from homeassistant.util.package import async_get_user_site, get_user_site from homeassistant.util.package import async_get_user_site, get_user_site
from homeassistant.util.yaml import clear_secret_cache from homeassistant.util.yaml import clear_secret_cache
@ -83,6 +81,18 @@ def async_from_config_dict(config: Dict[str, Any],
This method is a coroutine. This method is a coroutine.
""" """
start = time() start = time()
if enable_log:
async_enable_logging(hass, verbose, log_rotate_days, log_file)
if sys.version_info[:2] < (3, 5):
_LOGGER.warning(
'Python 3.4 support has been deprecated and will be removed in '
'the begining of 2018. Please upgrade Python or your operating '
'system. More info: https://home-assistant.io/blog/2017/10/06/'
'deprecating-python-3.4-support/'
)
core_config = config.get(core.DOMAIN, {}) core_config = config.get(core.DOMAIN, {})
try: try:
@ -93,9 +103,6 @@ def async_from_config_dict(config: Dict[str, Any],
yield from hass.async_add_job(conf_util.process_ha_config_upgrade, hass) yield from hass.async_add_job(conf_util.process_ha_config_upgrade, hass)
if enable_log:
async_enable_logging(hass, verbose, log_rotate_days, log_file)
hass.config.skip_pip = skip_pip hass.config.skip_pip = skip_pip
if skip_pip: if skip_pip:
_LOGGER.warning("Skipping pip installation of required modules. " _LOGGER.warning("Skipping pip installation of required modules. "

View file

@ -21,7 +21,7 @@ from homeassistant.const import (ATTR_ATTRIBUTION, ATTR_DATE, ATTR_TIME,
EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_STOP,
EVENT_HOMEASSISTANT_START) EVENT_HOMEASSISTANT_START)
REQUIREMENTS = ['abodepy==0.11.8'] REQUIREMENTS = ['abodepy==0.12.1']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -0,0 +1,121 @@
"""
Support for Arlo Alarm Control Panels.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.arlo/
"""
import asyncio
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.alarm_control_panel import (
AlarmControlPanel, PLATFORM_SCHEMA)
from homeassistant.components.arlo import (DATA_ARLO, CONF_ATTRIBUTION)
from homeassistant.const import (
ATTR_ATTRIBUTION, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED)
_LOGGER = logging.getLogger(__name__)
ARMED = 'armed'
CONF_HOME_MODE_NAME = 'home_mode_name'
DEPENDENCIES = ['arlo']
DISARMED = 'disarmed'
ICON = 'mdi:security'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_HOME_MODE_NAME, default=ARMED): cv.string,
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up the Arlo Alarm Control Panels."""
data = hass.data[DATA_ARLO]
if not data.base_stations:
return
home_mode_name = config.get(CONF_HOME_MODE_NAME)
base_stations = []
for base_station in data.base_stations:
base_stations.append(ArloBaseStation(base_station, home_mode_name))
async_add_devices(base_stations, True)
class ArloBaseStation(AlarmControlPanel):
"""Representation of an Arlo Alarm Control Panel."""
def __init__(self, data, home_mode_name):
"""Initialize the alarm control panel."""
self._base_station = data
self._home_mode_name = home_mode_name
self._state = None
@property
def icon(self):
"""Return icon."""
return ICON
@property
def state(self):
"""Return the state of the device."""
return self._state
def update(self):
"""Update the state of the device."""
# PyArlo sometimes returns None for mode. So retry 3 times before
# returning None.
num_retries = 3
i = 0
while i < num_retries:
mode = self._base_station.mode
if mode:
self._state = self._get_state_from_mode(mode)
return
i += 1
self._state = None
@asyncio.coroutine
def async_alarm_disarm(self, code=None):
"""Send disarm command."""
self._base_station.mode = DISARMED
@asyncio.coroutine
def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
self._base_station.mode = ARMED
@asyncio.coroutine
def async_alarm_arm_home(self, code=None):
"""Send arm home command. Uses custom mode."""
self._base_station.mode = self._home_mode_name
@property
def name(self):
"""Return the name of the base station."""
return self._base_station.name
@property
def device_state_attributes(self):
"""Return the state attributes."""
return {
ATTR_ATTRIBUTION: CONF_ATTRIBUTION,
'device_id': self._base_station.device_id
}
def _get_state_from_mode(self, mode):
"""Convert Arlo mode to Home Assistant state."""
if mode == ARMED:
return STATE_ALARM_ARMED_AWAY
elif mode == DISARMED:
return STATE_ALARM_DISARMED
elif mode == self._home_mode_name:
return STATE_ALARM_ARMED_HOME
return None

View file

@ -18,13 +18,14 @@ from homeassistant.const import (
CONF_NAME, STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, CONF_NAME, STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_AWAY, STATE_ALARM_TRIGGERED) STATE_ALARM_ARMED_AWAY, STATE_ALARM_TRIGGERED)
REQUIREMENTS = ['pythonegardia==1.0.20'] REQUIREMENTS = ['pythonegardia==1.0.22']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_REPORT_SERVER_CODES = 'report_server_codes' CONF_REPORT_SERVER_CODES = 'report_server_codes'
CONF_REPORT_SERVER_ENABLED = 'report_server_enabled' CONF_REPORT_SERVER_ENABLED = 'report_server_enabled'
CONF_REPORT_SERVER_PORT = 'report_server_port' CONF_REPORT_SERVER_PORT = 'report_server_port'
CONF_REPORT_SERVER_CODES_IGNORE = 'ignore'
DEFAULT_NAME = 'Egardia' DEFAULT_NAME = 'Egardia'
DEFAULT_PORT = 80 DEFAULT_PORT = 80
@ -148,9 +149,15 @@ class EgardiaAlarm(alarm.AlarmControlPanel):
def parsestatus(self, status): def parsestatus(self, status):
"""Parse the status.""" """Parse the status."""
newstatus = ([v for k, v in STATES.items() _LOGGER.debug("Parsing status %s", status)
if status.upper() == k][0]) # Ignore the statuscode if it is IGNORE
self._status = newstatus if status.lower().strip() != CONF_REPORT_SERVER_CODES_IGNORE:
_LOGGER.debug("Not ignoring status")
newstatus = ([v for k, v in STATES.items()
if status.upper() == k][0])
self._status = newstatus
else:
_LOGGER.error("Ignoring status")
def update(self): def update(self):
"""Update the alarm status.""" """Update the alarm status."""

View file

@ -6,88 +6,100 @@ from uuid import uuid4
from homeassistant.const import ( from homeassistant.const import (
ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF) ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF)
from homeassistant.components import switch, light from homeassistant.components import switch, light
from homeassistant.util.decorator import Registry
HANDLERS = Registry()
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ATTR_HEADER = 'header' API_DIRECTIVE = 'directive'
ATTR_NAME = 'name' API_EVENT = 'event'
ATTR_NAMESPACE = 'namespace' API_HEADER = 'header'
ATTR_MESSAGE_ID = 'messageId' API_PAYLOAD = 'payload'
ATTR_PAYLOAD = 'payload' API_ENDPOINT = 'endpoint'
ATTR_PAYLOAD_VERSION = 'payloadVersion'
MAPPING_COMPONENT = { MAPPING_COMPONENT = {
switch.DOMAIN: ['SWITCH', ('turnOff', 'turnOn'), None], switch.DOMAIN: ['SWITCH', ('Alexa.PowerController',), None],
light.DOMAIN: [ light.DOMAIN: [
'LIGHT', ('turnOff', 'turnOn'), { 'LIGHT', ('Alexa.PowerController',), {
light.SUPPORT_BRIGHTNESS: 'setPercentage' light.SUPPORT_BRIGHTNESS: 'Alexa.BrightnessController'
} }
], ],
} }
def mapping_api_function(name):
"""Return function pointer to api function for name.
Async friendly.
"""
mapping = {
'DiscoverAppliancesRequest': async_api_discovery,
'TurnOnRequest': async_api_turn_on,
'TurnOffRequest': async_api_turn_off,
'SetPercentageRequest': async_api_set_percentage,
}
return mapping.get(name, None)
@asyncio.coroutine @asyncio.coroutine
def async_handle_message(hass, message): def async_handle_message(hass, message):
"""Handle incoming API messages.""" """Handle incoming API messages."""
assert int(message[ATTR_HEADER][ATTR_PAYLOAD_VERSION]) == 2 assert message[API_DIRECTIVE][API_HEADER]['payloadVersion'] == '3'
# Read head data
message = message[API_DIRECTIVE]
namespace = message[API_HEADER]['namespace']
name = message[API_HEADER]['name']
# Do we support this API request? # Do we support this API request?
funct_ref = mapping_api_function(message[ATTR_HEADER][ATTR_NAME]) funct_ref = HANDLERS.get((namespace, name))
if not funct_ref: if not funct_ref:
_LOGGER.warning( _LOGGER.warning(
"Unsupported API request %s", message[ATTR_HEADER][ATTR_NAME]) "Unsupported API request %s/%s", namespace, name)
return api_error(message) return api_error(message)
return (yield from funct_ref(hass, message)) return (yield from funct_ref(hass, message))
def api_message(name, namespace, payload=None): def api_message(request, name='Response', namespace='Alexa', payload=None):
"""Create a API formatted response message. """Create a API formatted response message.
Async friendly. Async friendly.
""" """
payload = payload or {} payload = payload or {}
return {
ATTR_HEADER: { response = {
ATTR_MESSAGE_ID: uuid4(), API_EVENT: {
ATTR_NAME: name, API_HEADER: {
ATTR_NAMESPACE: namespace, 'namespace': namespace,
ATTR_PAYLOAD_VERSION: '2', 'name': name,
}, 'messageId': str(uuid4()),
ATTR_PAYLOAD: payload, 'payloadVersion': '3',
},
API_PAYLOAD: payload,
}
} }
# If a correlation token exsits, add it to header / Need by Async requests
token = request[API_HEADER].get('correlationToken')
if token:
response[API_EVENT][API_HEADER]['correlationToken'] = token
def api_error(request, exc='DriverInternalError'): # Extend event with endpoint object / Need by Async requests
if API_ENDPOINT in request:
response[API_EVENT][API_ENDPOINT] = request[API_ENDPOINT].copy()
return response
def api_error(request, error_type='INTERNAL_ERROR', error_message=""):
"""Create a API formatted error response. """Create a API formatted error response.
Async friendly. Async friendly.
""" """
return api_message(exc, request[ATTR_HEADER][ATTR_NAMESPACE]) payload = {
'type': error_type,
'message': error_message,
}
return api_message(request, name='ErrorResponse', payload=payload)
@HANDLERS.register(('Alexa.Discovery', 'Discover'))
@asyncio.coroutine @asyncio.coroutine
def async_api_discovery(hass, request): def async_api_discovery(hass, request):
"""Create a API formatted discovery response. """Create a API formatted discovery response.
Async friendly. Async friendly.
""" """
discovered_appliances = [] discovery_endpoints = []
for entity in hass.states.async_all(): for entity in hass.states.async_all():
class_data = MAPPING_COMPONENT.get(entity.domain) class_data = MAPPING_COMPONENT.get(entity.domain)
@ -95,35 +107,42 @@ def async_api_discovery(hass, request):
if not class_data: if not class_data:
continue continue
appliance = { endpoint = {
'actions': [], 'displayCategories': [class_data[0]],
'applianceTypes': [class_data[0]],
'additionalApplianceDetails': {}, 'additionalApplianceDetails': {},
'applianceId': entity.entity_id.replace('.', '#'), 'endpointId': entity.entity_id.replace('.', '#'),
'friendlyDescription': '',
'friendlyName': entity.name, 'friendlyName': entity.name,
'isReachable': True, 'description': '',
'manufacturerName': 'Unknown', 'manufacturerName': 'Unknown',
'modelName': 'Unknown',
'version': 'Unknown',
} }
actions = set()
# static actions # static actions
if class_data[1]: if class_data[1]:
appliance['actions'].extend(list(class_data[1])) actions |= set(class_data[1])
# dynamic actions # dynamic actions
if class_data[2]: if class_data[2]:
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
for feature, action_name in class_data[2].items(): for feature, action_name in class_data[2].items():
if feature & supported > 0: if feature & supported > 0:
appliance['actions'].append(action_name) actions.add(action_name)
discovered_appliances.append(appliance) # Write action into capabilities
capabilities = []
for action in actions:
capabilities.append({
'type': 'AlexaInterface',
'interface': action,
'version': 3,
})
endpoint['capabilities'] = capabilities
discovery_endpoints.append(endpoint)
return api_message( return api_message(
'DiscoverAppliancesResponse', 'Alexa.ConnectedHome.Discovery', request, name='Discover.Response', namespace='Alexa.Discovery',
payload={'discoveredAppliances': discovered_appliances}) payload={'endpoints': discovery_endpoints})
def extract_entity(funct): def extract_entity(funct):
@ -131,21 +150,21 @@ def extract_entity(funct):
@asyncio.coroutine @asyncio.coroutine
def async_api_entity_wrapper(hass, request): def async_api_entity_wrapper(hass, request):
"""Process a turn on request.""" """Process a turn on request."""
entity_id = \ entity_id = request[API_ENDPOINT]['endpointId'].replace('#', '.')
request[ATTR_PAYLOAD]['appliance']['applianceId'].replace('#', '.')
# extract state object # extract state object
entity = hass.states.get(entity_id) entity = hass.states.get(entity_id)
if not entity: if not entity:
_LOGGER.error("Can't process %s for %s", _LOGGER.error("Can't process %s for %s",
request[ATTR_HEADER][ATTR_NAME], entity_id) request[API_HEADER]['name'], entity_id)
return api_error(request) return api_error(request, error_type='NO_SUCH_ENDPOINT')
return (yield from funct(hass, request, entity)) return (yield from funct(hass, request, entity))
return async_api_entity_wrapper return async_api_entity_wrapper
@HANDLERS.register(('Alexa.PowerController', 'TurnOn'))
@extract_entity @extract_entity
@asyncio.coroutine @asyncio.coroutine
def async_api_turn_on(hass, request, entity): def async_api_turn_on(hass, request, entity):
@ -154,9 +173,10 @@ def async_api_turn_on(hass, request, entity):
ATTR_ENTITY_ID: entity.entity_id ATTR_ENTITY_ID: entity.entity_id
}, blocking=True) }, blocking=True)
return api_message('TurnOnConfirmation', 'Alexa.ConnectedHome.Control') return api_message(request)
@HANDLERS.register(('Alexa.PowerController', 'TurnOff'))
@extract_entity @extract_entity
@asyncio.coroutine @asyncio.coroutine
def async_api_turn_off(hass, request, entity): def async_api_turn_off(hass, request, entity):
@ -165,21 +185,19 @@ def async_api_turn_off(hass, request, entity):
ATTR_ENTITY_ID: entity.entity_id ATTR_ENTITY_ID: entity.entity_id
}, blocking=True) }, blocking=True)
return api_message('TurnOffConfirmation', 'Alexa.ConnectedHome.Control') return api_message(request)
@HANDLERS.register(('Alexa.BrightnessController', 'SetBrightness'))
@extract_entity @extract_entity
@asyncio.coroutine @asyncio.coroutine
def async_api_set_percentage(hass, request, entity): def async_api_set_brightness(hass, request, entity):
"""Process a set percentage request.""" """Process a set brightness request."""
if entity.domain == light.DOMAIN: brightness = request[API_PAYLOAD]['brightness']
brightness = request[ATTR_PAYLOAD]['percentageState']['value']
yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, {
ATTR_ENTITY_ID: entity.entity_id,
light.ATTR_BRIGHTNESS: brightness,
}, blocking=True)
else:
return api_error(request)
return api_message( yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, {
'SetPercentageConfirmation', 'Alexa.ConnectedHome.Control') ATTR_ENTITY_ID: entity.entity_id,
light.ATTR_BRIGHTNESS: brightness,
}, blocking=True)
return api_message(request)

View file

@ -1,5 +1,5 @@
""" """
This component provides basic support for Netgear Arlo IP cameras. This component provides support for Netgear Arlo IP cameras.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/arlo/ https://home-assistant.io/components/arlo/
@ -12,7 +12,7 @@ from requests.exceptions import HTTPError, ConnectTimeout
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD from homeassistant.const import CONF_USERNAME, CONF_PASSWORD
REQUIREMENTS = ['pyarlo==0.0.6'] REQUIREMENTS = ['pyarlo==0.0.7']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -23,7 +23,7 @@ DEFAULT_BRAND = 'Netgear Arlo'
DOMAIN = 'arlo' DOMAIN = 'arlo'
NOTIFICATION_ID = 'arlo_notification' NOTIFICATION_ID = 'arlo_notification'
NOTIFICATION_TITLE = 'Arlo Camera Setup' NOTIFICATION_TITLE = 'Arlo Component Setup'
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({

View file

@ -21,7 +21,7 @@ _LOGGER = logging.getLogger(__name__)
TRIGGER_SCHEMA = vol.Schema({ TRIGGER_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): 'event', vol.Required(CONF_PLATFORM): 'event',
vol.Required(CONF_EVENT_TYPE): cv.string, vol.Required(CONF_EVENT_TYPE): cv.string,
vol.Optional(CONF_EVENT_DATA): dict, vol.Optional(CONF_EVENT_DATA, default={}): dict,
}) })
@ -29,18 +29,24 @@ TRIGGER_SCHEMA = vol.Schema({
def async_trigger(hass, config, action): def async_trigger(hass, config, action):
"""Listen for events based on configuration.""" """Listen for events based on configuration."""
event_type = config.get(CONF_EVENT_TYPE) event_type = config.get(CONF_EVENT_TYPE)
event_data = config.get(CONF_EVENT_DATA) event_data_schema = vol.Schema(
config.get(CONF_EVENT_DATA),
extra=vol.ALLOW_EXTRA)
@callback @callback
def handle_event(event): def handle_event(event):
"""Listen for events and calls the action when data matches.""" """Listen for events and calls the action when data matches."""
if not event_data or all(val == event.data.get(key) for key, val try:
in event_data.items()): event_data_schema(event.data)
hass.async_run_job(action, { except vol.Invalid:
'trigger': { # If event data doesn't match requested schema, skip event
'platform': 'event', return
'event': event,
}, hass.async_run_job(action, {
}) 'trigger': {
'platform': 'event',
'event': event,
},
})
return hass.bus.async_listen(event_type, handle_event) return hass.bus.async_listen(event_type, handle_event)

View file

@ -99,8 +99,8 @@ def async_trigger(hass, config, action):
return return
async_remove_track_same = async_track_same_state( async_remove_track_same = async_track_same_state(
hass, True, time_delta, call_action, entity_ids=entity_id, hass, time_delta, call_action, entity_ids=entity_id,
async_check_func=check_numeric_state) async_check_same_func=check_numeric_state)
unsub = async_track_state_change( unsub = async_track_state_change(
hass, entity_id, state_automation_listener) hass, entity_id, state_automation_listener)

View file

@ -65,7 +65,9 @@ def async_trigger(hass, config, action):
return return
async_remove_track_same = async_track_same_state( async_remove_track_same = async_track_same_state(
hass, to_s.state, time_delta, call_action, entity_ids=entity_id) hass, time_delta, call_action,
lambda _, _2, to_state: to_state.state == to_s.state,
entity_ids=entity_id)
unsub = async_track_state_change( unsub = async_track_state_change(
hass, entity_id, state_automation_listener, from_state, to_state) hass, entity_id, state_automation_listener, from_state, to_state)

View file

@ -13,7 +13,8 @@ import voluptuous as vol
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA) BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.const import (CONF_NAME, ATTR_LONGITUDE, ATTR_LATITUDE) from homeassistant.const import (
CONF_NAME, ATTR_LONGITUDE, ATTR_LATITUDE, CONF_SHOW_ON_MAP)
from homeassistant.util import Throttle from homeassistant.util import Throttle
REQUIREMENTS = ['pyiss==1.0.1'] REQUIREMENTS = ['pyiss==1.0.1']
@ -23,8 +24,6 @@ _LOGGER = logging.getLogger(__name__)
ATTR_ISS_NEXT_RISE = 'next_rise' ATTR_ISS_NEXT_RISE = 'next_rise'
ATTR_ISS_NUMBER_PEOPLE_SPACE = 'number_of_people_in_space' ATTR_ISS_NUMBER_PEOPLE_SPACE = 'number_of_people_in_space'
CONF_SHOW_ON_MAP = 'show_on_map'
DEFAULT_NAME = 'ISS' DEFAULT_NAME = 'ISS'
DEFAULT_DEVICE_CLASS = 'visible' DEFAULT_DEVICE_CLASS = 'visible'

View file

@ -0,0 +1,72 @@
"""
Support for Melnor RainCloud sprinkler water timer.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.raincloud/
"""
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.raincloud import (
BINARY_SENSORS, DATA_RAINCLOUD, ICON_MAP, RainCloudEntity)
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.const import CONF_MONITORED_CONDITIONS
DEPENDENCIES = ['raincloud']
_LOGGER = logging.getLogger(__name__)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_MONITORED_CONDITIONS, default=list(BINARY_SENSORS)):
vol.All(cv.ensure_list, [vol.In(BINARY_SENSORS)]),
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up a sensor for a raincloud device."""
raincloud = hass.data[DATA_RAINCLOUD].data
sensors = []
for sensor_type in config.get(CONF_MONITORED_CONDITIONS):
if sensor_type == 'status':
sensors.append(
RainCloudBinarySensor(raincloud.controller, sensor_type))
sensors.append(
RainCloudBinarySensor(raincloud.controller.faucet,
sensor_type))
else:
# create an sensor for each zone managed by faucet
for zone in raincloud.controller.faucet.zones:
sensors.append(RainCloudBinarySensor(zone, sensor_type))
add_devices(sensors, True)
return True
class RainCloudBinarySensor(RainCloudEntity, BinarySensorDevice):
"""A sensor implementation for raincloud device."""
@property
def is_on(self):
"""Return true if the binary sensor is on."""
return self._state
def update(self):
"""Get the latest data and updates the state."""
_LOGGER.debug("Updating RainCloud sensor: %s", self._name)
self._state = getattr(self.data, self._sensor_type)
if self._sensor_type == 'status':
self._state = self._state == 'Online'
@property
def icon(self):
"""Return the icon of this device."""
if self._sensor_type == 'is_watering':
return 'mdi:water' if self.is_on else 'mdi:water-off'
elif self._sensor_type == 'status':
return 'mdi:pipe' if self.is_on else 'mdi:pipe-disconnected'
return ICON_MAP.get(self._sensor_type)

View file

@ -0,0 +1,97 @@
"""
Binary sensor support for the Skybell HD Doorbell.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.skybell/
"""
from datetime import timedelta
import logging
import voluptuous as vol
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.components.skybell import (
DEFAULT_ENTITY_NAMESPACE, DOMAIN as SKYBELL_DOMAIN, SkybellDevice)
from homeassistant.const import (
CONF_ENTITY_NAMESPACE, CONF_MONITORED_CONDITIONS)
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['skybell']
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=5)
# Sensor types: Name, device_class, event
SENSOR_TYPES = {
'button': ['Button', 'occupancy', 'device:sensor:button'],
'motion': ['Motion', 'motion', 'device:sensor:motion'],
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_ENTITY_NAMESPACE, default=DEFAULT_ENTITY_NAMESPACE):
cv.string,
vol.Required(CONF_MONITORED_CONDITIONS, default=[]):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the platform for a Skybell device."""
skybell = hass.data.get(SKYBELL_DOMAIN)
sensors = []
for sensor_type in config.get(CONF_MONITORED_CONDITIONS):
for device in skybell.get_devices():
sensors.append(SkybellBinarySensor(device, sensor_type))
add_devices(sensors, True)
class SkybellBinarySensor(SkybellDevice, BinarySensorDevice):
"""A binary sensor implementation for Skybell devices."""
def __init__(self, device, sensor_type):
"""Initialize a binary sensor for a Skybell device."""
super().__init__(device)
self._sensor_type = sensor_type
self._name = "{0} {1}".format(self._device.name,
SENSOR_TYPES[self._sensor_type][0])
self._device_class = SENSOR_TYPES[self._sensor_type][1]
self._event = {}
self._state = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def is_on(self):
"""Return True if the binary sensor is on."""
return self._state
@property
def device_class(self):
"""Return the class of the binary sensor."""
return self._device_class
@property
def device_state_attributes(self):
"""Return the state attributes."""
attrs = super().device_state_attributes
attrs['event_date'] = self._event.get('createdAt')
return attrs
def update(self):
"""Get the latest data and updates the state."""
super().update()
event = self._device.latest(SENSOR_TYPES[self._sensor_type][2])
self._state = bool(event and event.get('id') != self._event.get('id'))
self._event = event

View file

@ -135,7 +135,7 @@ class BinarySensorTemplate(BinarySensorDevice):
return False return False
@callback @callback
def _async_render(self, *args): def _async_render(self):
"""Get the state of template.""" """Get the state of template."""
try: try:
return self._template.async_render().lower() == 'true' return self._template.async_render().lower() == 'true'
@ -171,5 +171,5 @@ class BinarySensorTemplate(BinarySensorDevice):
period = self._delay_on if state else self._delay_off period = self._delay_on if state else self._delay_off
async_track_same_state( async_track_same_state(
self.hass, state, period, set_state, entity_ids=self._entities, self.hass, period, set_state, entity_ids=self._entities,
async_check_func=self._async_render) async_check_same_func=lambda *args: self._async_render() == state)

View file

@ -30,7 +30,6 @@ class TeslaBinarySensor(TeslaDevice, BinarySensorDevice):
def __init__(self, tesla_device, controller, sensor_type): def __init__(self, tesla_device, controller, sensor_type):
"""Initialisation of binary sensor.""" """Initialisation of binary sensor."""
super().__init__(tesla_device, controller) super().__init__(tesla_device, controller)
self._name = self.tesla_device.name
self._state = False self._state = False
self.entity_id = ENTITY_ID_FORMAT.format(self.tesla_id) self.entity_id = ENTITY_ID_FORMAT.format(self.tesla_id)
self._sensor_type = sensor_type self._sensor_type = sensor_type

View file

@ -20,15 +20,18 @@ from homeassistant.helpers.event import async_track_state_change
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ATTR_HYSTERESIS = 'hysteresis'
ATTR_SENSOR_VALUE = 'sensor_value' ATTR_SENSOR_VALUE = 'sensor_value'
ATTR_THRESHOLD = 'threshold' ATTR_THRESHOLD = 'threshold'
ATTR_TYPE = 'type' ATTR_TYPE = 'type'
CONF_HYSTERESIS = 'hysteresis'
CONF_LOWER = 'lower' CONF_LOWER = 'lower'
CONF_THRESHOLD = 'threshold' CONF_THRESHOLD = 'threshold'
CONF_UPPER = 'upper' CONF_UPPER = 'upper'
DEFAULT_NAME = 'Threshold' DEFAULT_NAME = 'Threshold'
DEFAULT_HYSTERESIS = 0.0
SENSOR_TYPES = [CONF_LOWER, CONF_UPPER] SENSOR_TYPES = [CONF_LOWER, CONF_UPPER]
@ -36,6 +39,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ENTITY_ID): cv.entity_id, vol.Required(CONF_ENTITY_ID): cv.entity_id,
vol.Required(CONF_THRESHOLD): vol.Coerce(float), vol.Required(CONF_THRESHOLD): vol.Coerce(float),
vol.Required(CONF_TYPE): vol.In(SENSOR_TYPES), vol.Required(CONF_TYPE): vol.In(SENSOR_TYPES),
vol.Optional(
CONF_HYSTERESIS, default=DEFAULT_HYSTERESIS): vol.Coerce(float),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
}) })
@ -47,28 +52,32 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
entity_id = config.get(CONF_ENTITY_ID) entity_id = config.get(CONF_ENTITY_ID)
name = config.get(CONF_NAME) name = config.get(CONF_NAME)
threshold = config.get(CONF_THRESHOLD) threshold = config.get(CONF_THRESHOLD)
hysteresis = config.get(CONF_HYSTERESIS)
limit_type = config.get(CONF_TYPE) limit_type = config.get(CONF_TYPE)
device_class = config.get(CONF_DEVICE_CLASS) device_class = config.get(CONF_DEVICE_CLASS)
async_add_devices( async_add_devices([ThresholdSensor(
[ThresholdSensor(hass, entity_id, name, threshold, limit_type, hass, entity_id, name, threshold,
device_class)], True) hysteresis, limit_type, device_class)
], True)
return True return True
class ThresholdSensor(BinarySensorDevice): class ThresholdSensor(BinarySensorDevice):
"""Representation of a Threshold sensor.""" """Representation of a Threshold sensor."""
def __init__(self, hass, entity_id, name, threshold, limit_type, def __init__(self, hass, entity_id, name, threshold,
device_class): hysteresis, limit_type, device_class):
"""Initialize the Threshold sensor.""" """Initialize the Threshold sensor."""
self._hass = hass self._hass = hass
self._entity_id = entity_id self._entity_id = entity_id
self.is_upper = limit_type == 'upper' self.is_upper = limit_type == 'upper'
self._name = name self._name = name
self._threshold = threshold self._threshold = threshold
self._hysteresis = hysteresis
self._device_class = device_class self._device_class = device_class
self._deviation = False self._state = False
self.sensor_value = 0 self.sensor_value = 0
@callback @callback
@ -97,7 +106,7 @@ class ThresholdSensor(BinarySensorDevice):
@property @property
def is_on(self): def is_on(self):
"""Return true if sensor is on.""" """Return true if sensor is on."""
return self._deviation return self._state
@property @property
def should_poll(self): def should_poll(self):
@ -116,13 +125,16 @@ class ThresholdSensor(BinarySensorDevice):
ATTR_ENTITY_ID: self._entity_id, ATTR_ENTITY_ID: self._entity_id,
ATTR_SENSOR_VALUE: self.sensor_value, ATTR_SENSOR_VALUE: self.sensor_value,
ATTR_THRESHOLD: self._threshold, ATTR_THRESHOLD: self._threshold,
ATTR_HYSTERESIS: self._hysteresis,
ATTR_TYPE: CONF_UPPER if self.is_upper else CONF_LOWER, ATTR_TYPE: CONF_UPPER if self.is_upper else CONF_LOWER,
} }
@asyncio.coroutine @asyncio.coroutine
def async_update(self): def async_update(self):
"""Get the latest data and updates the states.""" """Get the latest data and updates the states."""
if self.is_upper: if self._hysteresis == 0 and self.sensor_value == self._threshold:
self._deviation = bool(self.sensor_value > self._threshold) self._state = False
else: elif self.sensor_value > (self._threshold + self._hysteresis):
self._deviation = bool(self.sensor_value < self._threshold) self._state = self.is_upper
elif self.sensor_value < (self._threshold - self._hysteresis):
self._state = not self.is_upper

View file

@ -1,37 +1,40 @@
""" """
This component provides basic support for Netgear Arlo IP cameras. Support for Netgear Arlo IP cameras.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.arlo/ https://home-assistant.io/components/camera.arlo/
""" """
import asyncio import asyncio
import logging import logging
from datetime import timedelta
import voluptuous as vol import voluptuous as vol
from homeassistant.helpers import config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream
from homeassistant.components.arlo import DEFAULT_BRAND, DATA_ARLO from homeassistant.components.arlo import DEFAULT_BRAND, DATA_ARLO
from homeassistant.components.camera import Camera, PLATFORM_SCHEMA from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
from homeassistant.components.ffmpeg import DATA_FFMPEG from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.const import ATTR_BATTERY_LEVEL
from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream
DEPENDENCIES = ['arlo', 'ffmpeg']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(minutes=10)
ARLO_MODE_ARMED = 'armed'
ARLO_MODE_DISARMED = 'disarmed'
ATTR_BRIGHTNESS = 'brightness' ATTR_BRIGHTNESS = 'brightness'
ATTR_FLIPPED = 'flipped' ATTR_FLIPPED = 'flipped'
ATTR_MIRRORED = 'mirrored' ATTR_MIRRORED = 'mirrored'
ATTR_MOTION_SENSITIVITY = 'motion_detection_sensitivity' ATTR_MOTION = 'motion_detection_sensitivity'
ATTR_POWER_SAVE_MODE = 'power_save_mode' ATTR_POWERSAVE = 'power_save_mode'
ATTR_SIGNAL_STRENGTH = 'signal_strength' ATTR_SIGNAL_STRENGTH = 'signal_strength'
ATTR_UNSEEN_VIDEOS = 'unseen_videos' ATTR_UNSEEN_VIDEOS = 'unseen_videos'
CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments' CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments'
ARLO_MODE_ARMED = 'armed' DEPENDENCIES = ['arlo', 'ffmpeg']
ARLO_MODE_DISARMED = 'disarmed'
POWERSAVE_MODE_MAPPING = { POWERSAVE_MODE_MAPPING = {
1: 'best_battery_life', 1: 'best_battery_life',
@ -40,7 +43,8 @@ POWERSAVE_MODE_MAPPING = {
} }
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string, vol.Optional(CONF_FFMPEG_ARGUMENTS):
cv.string,
}) })
@ -69,6 +73,7 @@ class ArloCam(Camera):
self._motion_status = False self._motion_status = False
self._ffmpeg = hass.data[DATA_FFMPEG] self._ffmpeg = hass.data[DATA_FFMPEG]
self._ffmpeg_arguments = device_info.get(CONF_FFMPEG_ARGUMENTS) self._ffmpeg_arguments = device_info.get(CONF_FFMPEG_ARGUMENTS)
self.attrs = {}
def camera_image(self): def camera_image(self):
"""Return a still image response from the camera.""" """Return a still image response from the camera."""
@ -100,32 +105,24 @@ class ArloCam(Camera):
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
return { return {
ATTR_BATTERY_LEVEL: ATTR_BATTERY_LEVEL: self.attrs.get(ATTR_BATTERY_LEVEL),
self._camera.get_battery_level, ATTR_BRIGHTNESS: self.attrs.get(ATTR_BRIGHTNESS),
ATTR_BRIGHTNESS: ATTR_FLIPPED: self.attrs.get(ATTR_FLIPPED),
self._camera.get_brightness, ATTR_MIRRORED: self.attrs.get(ATTR_MIRRORED),
ATTR_FLIPPED: ATTR_MOTION: self.attrs.get(ATTR_MOTION),
self._camera.get_flip_state, ATTR_POWERSAVE: self.attrs.get(ATTR_POWERSAVE),
ATTR_MIRRORED: ATTR_SIGNAL_STRENGTH: self.attrs.get(ATTR_SIGNAL_STRENGTH),
self._camera.get_mirror_state, ATTR_UNSEEN_VIDEOS: self.attrs.get(ATTR_UNSEEN_VIDEOS),
ATTR_MOTION_SENSITIVITY:
self._camera.get_motion_detection_sensitivity,
ATTR_POWER_SAVE_MODE:
POWERSAVE_MODE_MAPPING[self._camera.get_powersave_mode],
ATTR_SIGNAL_STRENGTH:
self._camera.get_signal_strength,
ATTR_UNSEEN_VIDEOS:
self._camera.unseen_videos
} }
@property @property
def model(self): def model(self):
"""Camera model.""" """Return the camera model."""
return self._camera.model_id return self._camera.model_id
@property @property
def brand(self): def brand(self):
"""Camera brand.""" """Return the camera brand."""
return DEFAULT_BRAND return DEFAULT_BRAND
@property @property
@ -135,7 +132,7 @@ class ArloCam(Camera):
@property @property
def motion_detection_enabled(self): def motion_detection_enabled(self):
"""Camera Motion Detection Status.""" """Return the camera motion detection status."""
return self._motion_status return self._motion_status
def set_base_station_mode(self, mode): def set_base_station_mode(self, mode):
@ -143,7 +140,7 @@ class ArloCam(Camera):
# Get the list of base stations identified by library # Get the list of base stations identified by library
base_stations = self.hass.data[DATA_ARLO].base_stations base_stations = self.hass.data[DATA_ARLO].base_stations
# Some Arlo cameras does not have basestation # Some Arlo cameras does not have base station
# So check if there is base station detected first # So check if there is base station detected first
# if yes, then choose the primary base station # if yes, then choose the primary base station
# Set the mode on the chosen base station # Set the mode on the chosen base station
@ -160,3 +157,16 @@ class ArloCam(Camera):
"""Disable the motion detection in base station (Disarm).""" """Disable the motion detection in base station (Disarm)."""
self._motion_status = False self._motion_status = False
self.set_base_station_mode(ARLO_MODE_DISARMED) self.set_base_station_mode(ARLO_MODE_DISARMED)
def update(self):
"""Add an attribute-update task to the executor pool."""
self.attrs[ATTR_BATTERY_LEVEL] = self._camera.get_battery_level
self.attrs[ATTR_BRIGHTNESS] = self._camera.get_battery_level
self.attrs[ATTR_FLIPPED] = self._camera.get_flip_state,
self.attrs[ATTR_MIRRORED] = self._camera.get_mirror_state,
self.attrs[
ATTR_MOTION] = self._camera.get_motion_detection_sensitivity,
self.attrs[ATTR_POWERSAVE] = POWERSAVE_MODE_MAPPING[
self._camera.get_powersave_mode],
self.attrs[ATTR_SIGNAL_STRENGTH] = self._camera.get_signal_strength,
self.attrs[ATTR_UNSEEN_VIDEOS] = self._camera.unseen_videos

View file

@ -0,0 +1,67 @@
"""
Camera support for the Skybell HD Doorbell.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.skybell/
"""
from datetime import timedelta
import logging
import requests
from homeassistant.components.camera import Camera
from homeassistant.components.skybell import (
DOMAIN as SKYBELL_DOMAIN, SkybellDevice)
DEPENDENCIES = ['skybell']
_LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=90)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the platform for a Skybell device."""
skybell = hass.data.get(SKYBELL_DOMAIN)
sensors = []
for device in skybell.get_devices():
sensors.append(SkybellCamera(device))
add_devices(sensors, True)
class SkybellCamera(SkybellDevice, Camera):
"""A camera implementation for Skybell devices."""
def __init__(self, device):
"""Initialize a camera for a Skybell device."""
SkybellDevice.__init__(self, device)
Camera.__init__(self)
self._name = self._device.name
self._url = None
self._response = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
def camera_image(self):
"""Get the latest camera image."""
super().update()
if self._url != self._device.image:
self._url = self._device.image
try:
self._response = requests.get(
self._url, stream=True, timeout=10)
except requests.HTTPError as err:
_LOGGER.warning("Failed to get camera image: %s", err)
self._response = None
if not self._response:
return None
return self._response.content

View file

@ -7,44 +7,25 @@ https://home-assistant.io/components/camera.synology/
import asyncio import asyncio
import logging import logging
import requests
import voluptuous as vol import voluptuous as vol
import aiohttp
import async_timeout
from homeassistant.const import ( from homeassistant.const import (
CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_NAME, CONF_USERNAME, CONF_PASSWORD,
CONF_URL, CONF_WHITELIST, CONF_VERIFY_SSL, CONF_TIMEOUT) CONF_URL, CONF_WHITELIST, CONF_VERIFY_SSL, CONF_TIMEOUT)
from homeassistant.components.camera import ( from homeassistant.components.camera import (
Camera, PLATFORM_SCHEMA) Camera, PLATFORM_SCHEMA)
from homeassistant.helpers.aiohttp_client import ( from homeassistant.helpers.aiohttp_client import (
async_get_clientsession, async_create_clientsession, async_create_clientsession,
async_aiohttp_proxy_web) async_aiohttp_proxy_web)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util.async import run_coroutine_threadsafe
REQUIREMENTS = ['py-synology==0.1.3']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Synology Camera' DEFAULT_NAME = 'Synology Camera'
DEFAULT_STREAM_ID = '0'
DEFAULT_TIMEOUT = 5 DEFAULT_TIMEOUT = 5
CONF_CAMERA_NAME = 'camera_name'
CONF_STREAM_ID = 'stream_id'
QUERY_CGI = 'query.cgi'
QUERY_API = 'SYNO.API.Info'
AUTH_API = 'SYNO.API.Auth'
CAMERA_API = 'SYNO.SurveillanceStation.Camera'
STREAMING_API = 'SYNO.SurveillanceStation.VideoStream'
SESSION_ID = '0'
WEBAPI_PATH = '/webapi/'
AUTH_PATH = 'auth.cgi'
CAMERA_PATH = 'camera.cgi'
STREAMING_PATH = 'SurveillanceStation/videoStreaming.cgi'
CONTENT_TYPE_HEADER = 'Content-Type'
SYNO_API_URL = '{0}{1}{2}'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
@ -62,189 +43,89 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up a Synology IP Camera.""" """Set up a Synology IP Camera."""
verify_ssl = config.get(CONF_VERIFY_SSL) verify_ssl = config.get(CONF_VERIFY_SSL)
timeout = config.get(CONF_TIMEOUT) timeout = config.get(CONF_TIMEOUT)
websession_init = async_get_clientsession(hass, verify_ssl)
# Determine API to use for authentication
syno_api_url = SYNO_API_URL.format(
config.get(CONF_URL), WEBAPI_PATH, QUERY_CGI)
query_payload = {
'api': QUERY_API,
'method': 'Query',
'version': '1',
'query': 'SYNO.'
}
try: try:
with async_timeout.timeout(timeout, loop=hass.loop): from synology.surveillance_station import SurveillanceStation
query_req = yield from websession_init.get( surveillance = SurveillanceStation(
syno_api_url, config.get(CONF_URL),
params=query_payload config.get(CONF_USERNAME),
) config.get(CONF_PASSWORD),
verify_ssl=verify_ssl,
# Skip content type check because Synology doesn't return JSON with timeout=timeout
# right content type )
query_resp = yield from query_req.json(content_type=None) except (requests.exceptions.RequestException, ValueError):
auth_path = query_resp['data'][AUTH_API]['path'] _LOGGER.exception("Error when initializing SurveillanceStation")
camera_api = query_resp['data'][CAMERA_API]['path']
camera_path = query_resp['data'][CAMERA_API]['path']
streaming_path = query_resp['data'][STREAMING_API]['path']
except (asyncio.TimeoutError, aiohttp.ClientError):
_LOGGER.exception("Error on %s", syno_api_url)
return False return False
# Authticate to NAS to get a session id cameras = surveillance.get_all_cameras()
syno_auth_url = SYNO_API_URL.format( websession = async_create_clientsession(hass, verify_ssl)
config.get(CONF_URL), WEBAPI_PATH, auth_path)
session_id = yield from get_session_id(
hass,
websession_init,
config.get(CONF_USERNAME),
config.get(CONF_PASSWORD),
syno_auth_url,
timeout
)
# init websession
websession = async_create_clientsession(
hass, verify_ssl, cookies={'id': session_id})
# Use SessionID to get cameras in system
syno_camera_url = SYNO_API_URL.format(
config.get(CONF_URL), WEBAPI_PATH, camera_api)
camera_payload = {
'api': CAMERA_API,
'method': 'List',
'version': '1'
}
try:
with async_timeout.timeout(timeout, loop=hass.loop):
camera_req = yield from websession.get(
syno_camera_url,
params=camera_payload
)
except (asyncio.TimeoutError, aiohttp.ClientError):
_LOGGER.exception("Error on %s", syno_camera_url)
return False
camera_resp = yield from camera_req.json(content_type=None)
cameras = camera_resp['data']['cameras']
# add cameras # add cameras
devices = [] devices = []
for camera in cameras: for camera in cameras:
if not config.get(CONF_WHITELIST): if not config.get(CONF_WHITELIST):
camera_id = camera['id'] device = SynologyCamera(websession, surveillance, camera.camera_id)
snapshot_path = camera['snapshot_path']
device = SynologyCamera(
hass, websession, config, camera_id, camera['name'],
snapshot_path, streaming_path, camera_path, auth_path, timeout
)
devices.append(device) devices.append(device)
async_add_devices(devices) async_add_devices(devices)
@asyncio.coroutine
def get_session_id(hass, websession, username, password, login_url, timeout):
"""Get a session id."""
auth_payload = {
'api': AUTH_API,
'method': 'Login',
'version': '2',
'account': username,
'passwd': password,
'session': 'SurveillanceStation',
'format': 'sid'
}
try:
with async_timeout.timeout(timeout, loop=hass.loop):
auth_req = yield from websession.get(
login_url,
params=auth_payload
)
auth_resp = yield from auth_req.json(content_type=None)
return auth_resp['data']['sid']
except (asyncio.TimeoutError, aiohttp.ClientError):
_LOGGER.exception("Error on %s", login_url)
return False
class SynologyCamera(Camera): class SynologyCamera(Camera):
"""An implementation of a Synology NAS based IP camera.""" """An implementation of a Synology NAS based IP camera."""
def __init__(self, hass, websession, config, camera_id, def __init__(self, websession, surveillance, camera_id):
camera_name, snapshot_path, streaming_path, camera_path,
auth_path, timeout):
"""Initialize a Synology Surveillance Station camera.""" """Initialize a Synology Surveillance Station camera."""
super().__init__() super().__init__()
self.hass = hass
self._websession = websession self._websession = websession
self._name = camera_name self._surveillance = surveillance
self._synology_url = config.get(CONF_URL)
self._camera_name = config.get(CONF_CAMERA_NAME)
self._stream_id = config.get(CONF_STREAM_ID)
self._camera_id = camera_id self._camera_id = camera_id
self._snapshot_path = snapshot_path self._camera = self._surveillance.get_camera(camera_id)
self._streaming_path = streaming_path self._motion_setting = self._surveillance.get_motion_setting(camera_id)
self._camera_path = camera_path self.is_streaming = self._camera.is_enabled
self._auth_path = auth_path
self._timeout = timeout
def camera_image(self): def camera_image(self):
"""Return bytes of camera image.""" """Return bytes of camera image."""
return run_coroutine_threadsafe( return self._surveillance.get_camera_image(self._camera_id)
self.async_camera_image(), self.hass.loop).result()
@asyncio.coroutine
def async_camera_image(self):
"""Return a still image response from the camera."""
image_url = SYNO_API_URL.format(
self._synology_url, WEBAPI_PATH, self._camera_path)
image_payload = {
'api': CAMERA_API,
'method': 'GetSnapshot',
'version': '1',
'cameraId': self._camera_id
}
try:
with async_timeout.timeout(self._timeout, loop=self.hass.loop):
response = yield from self._websession.get(
image_url,
params=image_payload
)
except (asyncio.TimeoutError, aiohttp.ClientError):
_LOGGER.error("Error fetching %s", image_url)
return None
image = yield from response.read()
return image
@asyncio.coroutine @asyncio.coroutine
def handle_async_mjpeg_stream(self, request): def handle_async_mjpeg_stream(self, request):
"""Return a MJPEG stream image response directly from the camera.""" """Return a MJPEG stream image response directly from the camera."""
streaming_url = SYNO_API_URL.format( streaming_url = self._camera.video_stream_url
self._synology_url, WEBAPI_PATH, self._streaming_path) stream_coro = self._websession.get(streaming_url)
streaming_payload = {
'api': STREAMING_API,
'method': 'Stream',
'version': '1',
'cameraId': self._camera_id,
'format': 'mjpeg'
}
stream_coro = self._websession.get(
streaming_url, params=streaming_payload)
yield from async_aiohttp_proxy_web(self.hass, request, stream_coro) yield from async_aiohttp_proxy_web(self.hass, request, stream_coro)
@property @property
def name(self): def name(self):
"""Return the name of this device.""" """Return the name of this device."""
return self._name return self._camera.name
@property
def is_recording(self):
"""Return true if the device is recording."""
return self._camera.is_recording
def should_poll(self):
"""Update the recording state periodically."""
return True
def update(self):
"""Update the status of the camera."""
self._surveillance.update()
self._camera = self._surveillance.get_camera(self._camera.camera_id)
self._motion_setting = self._surveillance.get_motion_setting(
self._camera.camera_id)
self.is_streaming = self._camera.is_enabled
@property
def motion_detection_enabled(self):
"""Return the camera motion detection status."""
return self._motion_setting.is_enabled
def enable_motion_detection(self):
"""Enable motion detection in the camera."""
self._surveillance.enable_motion_detection(self._camera_id)
def disable_motion_detection(self):
"""Disable motion detection in camera."""
self._surveillance.disable_motion_detection(self._camera_id)

View file

@ -27,6 +27,7 @@ ATTR_RESUME_ALL = 'resume_all'
DEFAULT_RESUME_ALL = False DEFAULT_RESUME_ALL = False
TEMPERATURE_HOLD = 'temp' TEMPERATURE_HOLD = 'temp'
VACATION_HOLD = 'vacation' VACATION_HOLD = 'vacation'
AWAY_MODE = 'awayMode'
DEPENDENCIES = ['ecobee'] DEPENDENCIES = ['ecobee']
@ -144,20 +145,20 @@ class Thermostat(ClimateDevice):
@property @property
def current_temperature(self): def current_temperature(self):
"""Return the current temperature.""" """Return the current temperature."""
return self.thermostat['runtime']['actualTemperature'] / 10 return self.thermostat['runtime']['actualTemperature'] / 10.0
@property @property
def target_temperature_low(self): def target_temperature_low(self):
"""Return the lower bound temperature we try to reach.""" """Return the lower bound temperature we try to reach."""
if self.current_operation == STATE_AUTO: if self.current_operation == STATE_AUTO:
return int(self.thermostat['runtime']['desiredHeat'] / 10) return self.thermostat['runtime']['desiredHeat'] / 10.0
return None return None
@property @property
def target_temperature_high(self): def target_temperature_high(self):
"""Return the upper bound temperature we try to reach.""" """Return the upper bound temperature we try to reach."""
if self.current_operation == STATE_AUTO: if self.current_operation == STATE_AUTO:
return int(self.thermostat['runtime']['desiredCool'] / 10) return self.thermostat['runtime']['desiredCool'] / 10.0
return None return None
@property @property
@ -166,9 +167,9 @@ class Thermostat(ClimateDevice):
if self.current_operation == STATE_AUTO: if self.current_operation == STATE_AUTO:
return None return None
if self.current_operation == STATE_HEAT: if self.current_operation == STATE_HEAT:
return int(self.thermostat['runtime']['desiredHeat'] / 10) return self.thermostat['runtime']['desiredHeat'] / 10.0
elif self.current_operation == STATE_COOL: elif self.current_operation == STATE_COOL:
return int(self.thermostat['runtime']['desiredCool'] / 10) return self.thermostat['runtime']['desiredCool'] / 10.0
return None return None
@property @property
@ -186,6 +187,11 @@ class Thermostat(ClimateDevice):
@property @property
def current_hold_mode(self): def current_hold_mode(self):
"""Return current hold mode.""" """Return current hold mode."""
mode = self._current_hold_mode
return None if mode == AWAY_MODE else mode
@property
def _current_hold_mode(self):
events = self.thermostat['events'] events = self.thermostat['events']
for event in events: for event in events:
if event['running']: if event['running']:
@ -195,8 +201,8 @@ class Thermostat(ClimateDevice):
int(event['startDate'][0:4]) <= 1: int(event['startDate'][0:4]) <= 1:
# A temporary hold from away climate is a hold # A temporary hold from away climate is a hold
return 'away' return 'away'
# A permanent hold from away climate is away_mode # A permanent hold from away climate
return None return AWAY_MODE
elif event['holdClimateRef'] != "": elif event['holdClimateRef'] != "":
# Any other hold based on climate # Any other hold based on climate
return event['holdClimateRef'] return event['holdClimateRef']
@ -269,7 +275,7 @@ class Thermostat(ClimateDevice):
@property @property
def is_away_mode_on(self): def is_away_mode_on(self):
"""Return true if away mode is on.""" """Return true if away mode is on."""
return self.current_hold_mode == 'away' return self._current_hold_mode == AWAY_MODE
@property @property
def is_aux_heat_on(self): def is_aux_heat_on(self):
@ -277,12 +283,17 @@ class Thermostat(ClimateDevice):
return 'auxHeat' in self.thermostat['equipmentStatus'] return 'auxHeat' in self.thermostat['equipmentStatus']
def turn_away_mode_on(self): def turn_away_mode_on(self):
"""Turn away on.""" """Turn away mode on by setting it on away hold indefinitely."""
self.set_hold_mode('away') if self._current_hold_mode != AWAY_MODE:
self.data.ecobee.set_climate_hold(self.thermostat_index, 'away',
'indefinite')
self.update_without_throttle = True
def turn_away_mode_off(self): def turn_away_mode_off(self):
"""Turn away off.""" """Turn away off."""
self.set_hold_mode(None) if self._current_hold_mode == AWAY_MODE:
self.data.ecobee.resume_program(self.thermostat_index)
self.update_without_throttle = True
def set_hold_mode(self, hold_mode): def set_hold_mode(self, hold_mode):
"""Set hold mode (away, home, temp, sleep, etc.).""" """Set hold mode (away, home, temp, sleep, etc.)."""
@ -299,7 +310,7 @@ class Thermostat(ClimateDevice):
self.data.ecobee.resume_program(self.thermostat_index) self.data.ecobee.resume_program(self.thermostat_index)
else: else:
if hold_mode == TEMPERATURE_HOLD: if hold_mode == TEMPERATURE_HOLD:
self.set_temp_hold(int(self.current_temperature)) self.set_temp_hold(self.current_temperature)
else: else:
self.data.ecobee.set_climate_hold( self.data.ecobee.set_climate_hold(
self.thermostat_index, hold_mode, self.hold_preference()) self.thermostat_index, hold_mode, self.hold_preference())
@ -325,15 +336,11 @@ class Thermostat(ClimateDevice):
elif self.current_operation == STATE_COOL: elif self.current_operation == STATE_COOL:
heat_temp = temp - 20 heat_temp = temp - 20
cool_temp = temp cool_temp = temp
else:
self.data.ecobee.set_hold_temp(self.thermostat_index, cool_temp, # In auto mode set temperature between
heat_temp, self.hold_preference()) heat_temp = temp - 10
_LOGGER.debug("Setting ecobee hold_temp to: low=%s, is=%s, " cool_temp = temp + 10
"cool=%s, is=%s", heat_temp, isinstance( self.set_auto_temp_hold(heat_temp, cool_temp)
heat_temp, (int, float)), cool_temp,
isinstance(cool_temp, (int, float)))
self.update_without_throttle = True
def set_temperature(self, **kwargs): def set_temperature(self, **kwargs):
"""Set new target temperature.""" """Set new target temperature."""
@ -343,9 +350,9 @@ class Thermostat(ClimateDevice):
if self.current_operation == STATE_AUTO and low_temp is not None \ if self.current_operation == STATE_AUTO and low_temp is not None \
and high_temp is not None: and high_temp is not None:
self.set_auto_temp_hold(int(low_temp), int(high_temp)) self.set_auto_temp_hold(low_temp, high_temp)
elif temp is not None: elif temp is not None:
self.set_temp_hold(int(temp)) self.set_temp_hold(temp)
else: else:
_LOGGER.error( _LOGGER.error(
"Missing valid arguments for set_temperature in %s", kwargs) "Missing valid arguments for set_temperature in %s", kwargs)
@ -364,7 +371,7 @@ class Thermostat(ClimateDevice):
def resume_program(self, resume_all): def resume_program(self, resume_all):
"""Resume the thermostat schedule program.""" """Resume the thermostat schedule program."""
self.data.ecobee.resume_program( self.data.ecobee.resume_program(
self.thermostat_index, str(resume_all).lower()) self.thermostat_index, 'true' if resume_all else 'false')
self.update_without_throttle = True self.update_without_throttle = True
def hold_preference(self): def hold_preference(self):

View file

@ -17,7 +17,7 @@ from homeassistant.const import (
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['python-eq3bt==0.1.5'] REQUIREMENTS = ['python-eq3bt==0.1.6']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -164,4 +164,8 @@ class EQ3BTSmartThermostat(ClimateDevice):
def update(self): def update(self):
"""Update the data from the thermostat.""" """Update the data from the thermostat."""
self._thermostat.update() from bluepy.btle import BTLEException
try:
self._thermostat.update()
except BTLEException as ex:
_LOGGER.warning("Updating the state failed: %s", ex)

View file

@ -0,0 +1,483 @@
"""
Support for MQTT climate devices.
For more details about this platform, please refer to the documentation
https://home-assistant.io/components/climate.mqtt/
"""
import asyncio
import logging
import voluptuous as vol
from homeassistant.core import callback
import homeassistant.components.mqtt as mqtt
from homeassistant.components.climate import (
STATE_HEAT, STATE_COOL, STATE_DRY, STATE_FAN_ONLY, ClimateDevice,
PLATFORM_SCHEMA as CLIMATE_PLATFORM_SCHEMA, STATE_AUTO,
ATTR_OPERATION_MODE)
from homeassistant.const import (
STATE_ON, STATE_OFF, ATTR_TEMPERATURE, CONF_NAME)
from homeassistant.components.mqtt import (CONF_QOS, CONF_RETAIN)
import homeassistant.helpers.config_validation as cv
from homeassistant.components.fan import (SPEED_LOW, SPEED_MEDIUM,
SPEED_HIGH)
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['mqtt']
DEFAULT_NAME = 'MQTT HVAC'
CONF_POWER_COMMAND_TOPIC = 'power_command_topic'
CONF_POWER_STATE_TOPIC = 'power_state_topic'
CONF_MODE_COMMAND_TOPIC = 'mode_command_topic'
CONF_MODE_STATE_TOPIC = 'mode_state_topic'
CONF_TEMPERATURE_COMMAND_TOPIC = 'temperature_command_topic'
CONF_TEMPERATURE_STATE_TOPIC = 'temperature_state_topic'
CONF_FAN_MODE_COMMAND_TOPIC = 'fan_mode_command_topic'
CONF_FAN_MODE_STATE_TOPIC = 'fan_mode_state_topic'
CONF_SWING_MODE_COMMAND_TOPIC = 'swing_mode_command_topic'
CONF_SWING_MODE_STATE_TOPIC = 'swing_mode_state_topic'
CONF_AWAY_MODE_COMMAND_TOPIC = 'away_mode_command_topic'
CONF_AWAY_MODE_STATE_TOPIC = 'away_mode_state_topic'
CONF_HOLD_COMMAND_TOPIC = 'hold_command_topic'
CONF_HOLD_STATE_TOPIC = 'hold_state_topic'
CONF_AUX_COMMAND_TOPIC = 'aux_command_topic'
CONF_AUX_STATE_TOPIC = 'aux_state_topic'
CONF_CURRENT_TEMPERATURE_TOPIC = 'current_temperature_topic'
CONF_PAYLOAD_ON = 'payload_on'
CONF_PAYLOAD_OFF = 'payload_off'
CONF_FAN_MODE_LIST = 'fan_modes'
CONF_MODE_LIST = 'modes'
CONF_SWING_MODE_LIST = 'swing_modes'
CONF_INITIAL = 'initial'
CONF_SEND_IF_OFF = 'send_if_off'
PLATFORM_SCHEMA = CLIMATE_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_POWER_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_TEMPERATURE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_FAN_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SWING_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_AWAY_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_HOLD_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_AUX_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_POWER_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_TEMPERATURE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_FAN_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_SWING_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_AWAY_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_HOLD_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_AUX_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_CURRENT_TEMPERATURE_TOPIC):
mqtt.valid_subscribe_topic,
vol.Optional(CONF_FAN_MODE_LIST,
default=[STATE_AUTO, SPEED_LOW,
SPEED_MEDIUM, SPEED_HIGH]): cv.ensure_list,
vol.Optional(CONF_SWING_MODE_LIST,
default=[STATE_ON, STATE_OFF]): cv.ensure_list,
vol.Optional(CONF_MODE_LIST,
default=[STATE_AUTO, STATE_OFF, STATE_COOL, STATE_HEAT,
STATE_DRY, STATE_FAN_ONLY]): cv.ensure_list,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_INITIAL, default=21): cv.positive_int,
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,
})
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up the MQTT climate devices."""
async_add_devices([
MqttClimate(
hass,
config.get(CONF_NAME),
{
key: config.get(key) for key in (
CONF_POWER_COMMAND_TOPIC,
CONF_MODE_COMMAND_TOPIC,
CONF_TEMPERATURE_COMMAND_TOPIC,
CONF_FAN_MODE_COMMAND_TOPIC,
CONF_SWING_MODE_COMMAND_TOPIC,
CONF_AWAY_MODE_COMMAND_TOPIC,
CONF_HOLD_COMMAND_TOPIC,
CONF_AUX_COMMAND_TOPIC,
CONF_POWER_STATE_TOPIC,
CONF_MODE_STATE_TOPIC,
CONF_TEMPERATURE_STATE_TOPIC,
CONF_FAN_MODE_STATE_TOPIC,
CONF_SWING_MODE_STATE_TOPIC,
CONF_AWAY_MODE_STATE_TOPIC,
CONF_HOLD_STATE_TOPIC,
CONF_AUX_STATE_TOPIC,
CONF_CURRENT_TEMPERATURE_TOPIC
)
},
config.get(CONF_QOS),
config.get(CONF_RETAIN),
config.get(CONF_MODE_LIST),
config.get(CONF_FAN_MODE_LIST),
config.get(CONF_SWING_MODE_LIST),
config.get(CONF_INITIAL),
False, None, SPEED_LOW,
STATE_OFF, STATE_OFF, False,
config.get(CONF_SEND_IF_OFF),
config.get(CONF_PAYLOAD_ON),
config.get(CONF_PAYLOAD_OFF))
])
class MqttClimate(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):
"""Initialize the climate device."""
self.hass = hass
self._name = name
self._topic = topic
self._qos = qos
self._retain = retain
self._target_temperature = target_temperature
self._unit_of_measurement = hass.config.units.temperature_unit
self._away = away
self._hold = hold
self._current_temperature = None
self._current_fan_mode = current_fan_mode
self._current_operation = current_operation
self._aux = aux
self._current_swing_mode = current_swing_mode
self._fan_list = fan_mode_list
self._operation_list = mode_list
self._swing_list = swing_mode_list
self._target_temperature_step = 1
self._send_if_off = send_if_off
self._payload_on = payload_on
self._payload_off = payload_off
def async_added_to_hass(self):
"""Handle being added to home assistant."""
@callback
def handle_current_temp_received(topic, payload, qos):
"""Handle current temperature coming via MQTT."""
try:
self._current_temperature = float(payload)
self.async_schedule_update_ha_state()
except ValueError:
_LOGGER.error("Could not parse temperature from %s", payload)
if self._topic[CONF_CURRENT_TEMPERATURE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_CURRENT_TEMPERATURE_TOPIC],
handle_current_temp_received, self._qos)
@callback
def handle_mode_received(topic, payload, qos):
"""Handle receiving mode via MQTT."""
if payload not in self._operation_list:
_LOGGER.error("Invalid mode: %s", payload)
else:
self._current_operation = payload
self.async_schedule_update_ha_state()
if self._topic[CONF_MODE_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_MODE_STATE_TOPIC],
handle_mode_received, self._qos)
@callback
def handle_temperature_received(topic, payload, qos):
"""Handle target temperature coming via MQTT."""
try:
self._target_temperature = float(payload)
self.async_schedule_update_ha_state()
except ValueError:
_LOGGER.error("Could not parse temperature from %s", payload)
if self._topic[CONF_TEMPERATURE_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_TEMPERATURE_STATE_TOPIC],
handle_temperature_received, self._qos)
@callback
def handle_fan_mode_received(topic, payload, qos):
"""Handle receiving fan mode via MQTT."""
if payload not in self._fan_list:
_LOGGER.error("Invalid fan mode: %s", payload)
else:
self._current_fan_mode = payload
self.async_schedule_update_ha_state()
if self._topic[CONF_FAN_MODE_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_FAN_MODE_STATE_TOPIC],
handle_fan_mode_received, self._qos)
@callback
def handle_swing_mode_received(topic, payload, qos):
"""Handle receiving swing mode via MQTT."""
if payload not in self._swing_list:
_LOGGER.error("Invalid swing mode: %s", payload)
else:
self._current_swing_mode = payload
self.async_schedule_update_ha_state()
if self._topic[CONF_SWING_MODE_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_SWING_MODE_STATE_TOPIC],
handle_swing_mode_received, self._qos)
@callback
def handle_away_mode_received(topic, payload, qos):
"""Handle receiving away mode via MQTT."""
if payload == self._payload_on:
self._away = True
elif payload == self._payload_off:
self._away = False
else:
_LOGGER.error("Invalid away mode: %s", payload)
self.async_schedule_update_ha_state()
if self._topic[CONF_AWAY_MODE_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_AWAY_MODE_STATE_TOPIC],
handle_away_mode_received, self._qos)
@callback
def handle_aux_mode_received(topic, payload, qos):
"""Handle receiving aux mode via MQTT."""
if payload == self._payload_on:
self._aux = True
elif payload == self._payload_off:
self._aux = False
else:
_LOGGER.error("Invalid aux mode: %s", payload)
self.async_schedule_update_ha_state()
if self._topic[CONF_AUX_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_AUX_STATE_TOPIC],
handle_aux_mode_received, self._qos)
@callback
def handle_hold_mode_received(topic, payload, qos):
"""Handle receiving hold mode via MQTT."""
self._hold = payload
self.async_schedule_update_ha_state()
if self._topic[CONF_HOLD_STATE_TOPIC] is not None:
yield from mqtt.async_subscribe(
self.hass, self._topic[CONF_HOLD_STATE_TOPIC],
handle_hold_mode_received, self._qos)
@property
def should_poll(self):
"""Return the polling state."""
return False
@property
def name(self):
"""Return the name of the climate device."""
return self._name
@property
def temperature_unit(self):
"""Return the unit of measurement."""
return self._unit_of_measurement
@property
def current_temperature(self):
"""Return the current temperature."""
return self._current_temperature
@property
def target_temperature(self):
"""Return the temperature we try to reach."""
return self._target_temperature
@property
def current_operation(self):
"""Return current operation ie. heat, cool, idle."""
return self._current_operation
@property
def operation_list(self):
"""Return the list of available operation modes."""
return self._operation_list
@property
def target_temperature_step(self):
"""Return the supported step of target temperature."""
return self._target_temperature_step
@property
def is_away_mode_on(self):
"""Return if away mode is on."""
return self._away
@property
def current_hold_mode(self):
"""Return hold mode setting."""
return self._hold
@property
def is_aux_heat_on(self):
"""Return true if away mode is on."""
return self._aux
@property
def current_fan_mode(self):
"""Return the fan setting."""
return self._current_fan_mode
@property
def fan_list(self):
"""Return the list of available fan modes."""
return self._fan_list
@asyncio.coroutine
def async_set_temperature(self, **kwargs):
"""Set new target temperatures."""
if kwargs.get(ATTR_OPERATION_MODE) is not None:
operation_mode = kwargs.get(ATTR_OPERATION_MODE)
yield from self.async_set_operation_mode(operation_mode)
if kwargs.get(ATTR_TEMPERATURE) is not None:
if self._topic[CONF_TEMPERATURE_STATE_TOPIC] is None:
# optimistic mode
self._target_temperature = kwargs.get(ATTR_TEMPERATURE)
if self._send_if_off or self._current_operation != STATE_OFF:
mqtt.async_publish(
self.hass, self._topic[CONF_TEMPERATURE_COMMAND_TOPIC],
kwargs.get(ATTR_TEMPERATURE), self._qos, self._retain)
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_set_swing_mode(self, swing_mode):
"""Set new swing mode."""
if self._send_if_off or self._current_operation != STATE_OFF:
mqtt.async_publish(
self.hass, self._topic[CONF_SWING_MODE_COMMAND_TOPIC],
swing_mode, self._qos, self._retain)
if self._topic[CONF_SWING_MODE_STATE_TOPIC] is None:
self._current_swing_mode = swing_mode
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_set_fan_mode(self, fan):
"""Set new target temperature."""
if self._send_if_off or self._current_operation != STATE_OFF:
mqtt.async_publish(
self.hass, self._topic[CONF_FAN_MODE_COMMAND_TOPIC],
fan, self._qos, self._retain)
if self._topic[CONF_FAN_MODE_STATE_TOPIC] is None:
self._current_fan_mode = fan
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_set_operation_mode(self, operation_mode) -> None:
"""Set new operation mode."""
if self._topic[CONF_POWER_COMMAND_TOPIC] is not None:
if (self._current_operation == STATE_OFF and
operation_mode != STATE_OFF):
mqtt.async_publish(
self.hass, self._topic[CONF_POWER_COMMAND_TOPIC],
self._payload_on, self._qos, self._retain)
elif (self._current_operation != STATE_OFF and
operation_mode == STATE_OFF):
mqtt.async_publish(
self.hass, self._topic[CONF_POWER_COMMAND_TOPIC],
self._payload_off, self._qos, self._retain)
if self._topic[CONF_MODE_COMMAND_TOPIC] is not None:
mqtt.async_publish(
self.hass, self._topic[CONF_MODE_COMMAND_TOPIC],
operation_mode, self._qos, self._retain)
if self._topic[CONF_MODE_STATE_TOPIC] is None:
self._current_operation = operation_mode
self.async_schedule_update_ha_state()
@property
def current_swing_mode(self):
"""Return the swing setting."""
return self._current_swing_mode
@property
def swing_list(self):
"""List of available swing modes."""
return self._swing_list
@asyncio.coroutine
def async_turn_away_mode_on(self):
"""Turn away mode on."""
if self._topic[CONF_AWAY_MODE_COMMAND_TOPIC] is not None:
mqtt.async_publish(self.hass,
self._topic[CONF_AWAY_MODE_COMMAND_TOPIC],
self._payload_on, self._qos, self._retain)
if self._topic[CONF_AWAY_MODE_STATE_TOPIC] is None:
self._away = True
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_away_mode_off(self):
"""Turn away mode off."""
if self._topic[CONF_AWAY_MODE_COMMAND_TOPIC] is not None:
mqtt.async_publish(self.hass,
self._topic[CONF_AWAY_MODE_COMMAND_TOPIC],
self._payload_off, self._qos, self._retain)
if self._topic[CONF_AWAY_MODE_STATE_TOPIC] is None:
self._away = False
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_set_hold_mode(self, hold):
"""Update hold mode on."""
if self._topic[CONF_HOLD_COMMAND_TOPIC] is not None:
mqtt.async_publish(self.hass,
self._topic[CONF_HOLD_COMMAND_TOPIC],
hold, self._qos, self._retain)
if self._topic[CONF_HOLD_STATE_TOPIC] is None:
self._hold = hold
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_aux_heat_on(self):
"""Turn auxillary heater on."""
if self._topic[CONF_AUX_COMMAND_TOPIC] is not None:
mqtt.async_publish(self.hass, self._topic[CONF_AUX_COMMAND_TOPIC],
self._payload_on, self._qos, self._retain)
if self._topic[CONF_AUX_STATE_TOPIC] is None:
self._aux = True
self.async_schedule_update_ha_state()
@asyncio.coroutine
def async_turn_aux_heat_off(self):
"""Turn auxillary heater off."""
if self._topic[CONF_AUX_COMMAND_TOPIC] is not None:
mqtt.async_publish(self.hass, self._topic[CONF_AUX_COMMAND_TOPIC],
self._payload_off, self._qos, self._retain)
if self._topic[CONF_AUX_STATE_TOPIC] is None:
self._aux = False
self.async_schedule_update_ha_state()

View file

@ -35,7 +35,6 @@ class TeslaThermostat(TeslaDevice, ClimateDevice):
self.entity_id = ENTITY_ID_FORMAT.format(self.tesla_id) self.entity_id = ENTITY_ID_FORMAT.format(self.tesla_id)
self._target_temperature = None self._target_temperature = None
self._temperature = None self._temperature = None
self._name = self.tesla_device.name
@property @property
def current_operation(self): def current_operation(self):

View file

@ -0,0 +1,121 @@
"""
Support for Rflink Cover devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/cover.rflink/
"""
import asyncio
import logging
import voluptuous as vol
from homeassistant.components.rflink import (
DATA_ENTITY_GROUP_LOOKUP, DATA_ENTITY_LOOKUP,
DEVICE_DEFAULTS_SCHEMA, EVENT_KEY_COMMAND, RflinkCommand)
from homeassistant.components.cover import (
CoverDevice, PLATFORM_SCHEMA)
import homeassistant.helpers.config_validation as cv
from homeassistant.const import CONF_NAME
DEPENDENCIES = ['rflink']
_LOGGER = logging.getLogger(__name__)
CONF_ALIASES = 'aliases'
CONF_GROUP_ALIASES = 'group_aliases'
CONF_GROUP = 'group'
CONF_NOGROUP_ALIASES = 'nogroup_aliases'
CONF_DEVICE_DEFAULTS = 'device_defaults'
CONF_DEVICES = 'devices'
CONF_AUTOMATIC_ADD = 'automatic_add'
CONF_FIRE_EVENT = 'fire_event'
CONF_IGNORE_DEVICES = 'ignore_devices'
CONF_RECONNECT_INTERVAL = 'reconnect_interval'
CONF_SIGNAL_REPETITIONS = 'signal_repetitions'
CONF_WAIT_FOR_ACK = 'wait_for_ack'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_DEVICE_DEFAULTS, default=DEVICE_DEFAULTS_SCHEMA({})):
DEVICE_DEFAULTS_SCHEMA,
vol.Optional(CONF_DEVICES, default={}): vol.Schema({
cv.string: {
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_ALIASES, default=[]):
vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_GROUP_ALIASES, default=[]):
vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_NOGROUP_ALIASES, default=[]):
vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
vol.Optional(CONF_SIGNAL_REPETITIONS): vol.Coerce(int),
vol.Optional(CONF_GROUP, default=True): cv.boolean,
},
}),
})
def devices_from_config(domain_config, hass=None):
"""Parse configuration and add Rflink cover devices."""
devices = []
for device_id, config in domain_config[CONF_DEVICES].items():
device_config = dict(domain_config[CONF_DEVICE_DEFAULTS], **config)
device = RflinkCover(device_id, hass, **device_config)
devices.append(device)
# Register entity (and aliases) to listen to incoming rflink events
# Device id and normal aliases respond to normal and group command
hass.data[DATA_ENTITY_LOOKUP][
EVENT_KEY_COMMAND][device_id].append(device)
if config[CONF_GROUP]:
hass.data[DATA_ENTITY_GROUP_LOOKUP][
EVENT_KEY_COMMAND][device_id].append(device)
for _id in config[CONF_ALIASES]:
hass.data[DATA_ENTITY_LOOKUP][
EVENT_KEY_COMMAND][_id].append(device)
hass.data[DATA_ENTITY_GROUP_LOOKUP][
EVENT_KEY_COMMAND][_id].append(device)
return devices
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up the Rflink cover platform."""
async_add_devices(devices_from_config(config, hass))
class RflinkCover(RflinkCommand, CoverDevice):
"""Rflink entity which can switch on/stop/off (eg: cover)."""
def _handle_event(self, event):
"""Adjust state if Rflink picks up a remote command for this device."""
self.cancel_queued_send_commands()
command = event['command']
if command in ['on', 'allon']:
self._state = True
elif command in ['off', 'alloff']:
self._state = False
@property
def should_poll(self):
"""No polling available in RFlink cover."""
return False
@property
def is_closed(self):
"""Return if the cover is closed."""
return None
def async_close_cover(self, **kwargs):
"""Turn the device close."""
return self._async_handle_command("close_cover")
def async_open_cover(self, **kwargs):
"""Turn the device open."""
return self._async_handle_command("open_cover")
def async_stop_cover(self, **kwargs):
"""Turn the device stop."""
return self._async_handle_command("stop_cover")

View file

@ -87,8 +87,8 @@ def async_setup(hass, config):
# Set up input boolean # Set up input boolean
tasks.append(bootstrap.async_setup_component( tasks.append(bootstrap.async_setup_component(
hass, 'input_slider', hass, 'input_number',
{'input_slider': { {'input_number': {
'noise_allowance': {'icon': 'mdi:bell-ring', 'noise_allowance': {'icon': 'mdi:bell-ring',
'min': 0, 'min': 0,
'max': 10, 'max': 10,
@ -163,7 +163,7 @@ def async_setup(hass, config):
'scene.romantic_lights'])) 'scene.romantic_lights']))
tasks2.append(group.Group.async_create_group(hass, 'Bedroom', [ tasks2.append(group.Group.async_create_group(hass, 'Bedroom', [
lights[0], switches[1], media_players[0], lights[0], switches[1], media_players[0],
'input_slider.noise_allowance'])) 'input_number.noise_allowance']))
tasks2.append(group.Group.async_create_group(hass, 'Kitchen', [ tasks2.append(group.Group.async_create_group(hass, 'Kitchen', [
lights[2], 'cover.kitchen_window', 'lock.kitchen_door'])) lights[2], 'cover.kitchen_window', 'lock.kitchen_door']))
tasks2.append(group.Group.async_create_group(hass, 'Doors', [ tasks2.append(group.Group.async_create_group(hass, 'Doors', [

View file

@ -18,11 +18,10 @@ from homeassistant.setup import async_prepare_setup_platform
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
from homeassistant.components import group, zone from homeassistant.components import group, zone
from homeassistant.components.discovery import SERVICE_NETGEAR
from homeassistant.config import load_yaml_config_file, async_log_exception from homeassistant.config import load_yaml_config_file, async_log_exception
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers import config_per_platform, discovery from homeassistant.helpers import config_per_platform
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.restore_state import async_get_last_state from homeassistant.helpers.restore_state import async_get_last_state
@ -89,10 +88,6 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
cv.time_period, cv.positive_timedelta) cv.time_period, cv.positive_timedelta)
}) })
DISCOVERY_PLATFORMS = {
SERVICE_NETGEAR: 'netgear',
}
@bind_hass @bind_hass
def is_on(hass: HomeAssistantType, entity_id: str=None): def is_on(hass: HomeAssistantType, entity_id: str=None):
@ -180,22 +175,6 @@ def async_setup(hass: HomeAssistantType, config: ConfigType):
tracker.async_setup_group() tracker.async_setup_group()
@callback
def async_device_tracker_discovered(service, info):
"""Handle the discovery of device tracker platforms."""
hass.async_add_job(
async_setup_platform(DISCOVERY_PLATFORMS[service], {}, info))
discovery.async_listen(
hass, DISCOVERY_PLATFORMS.keys(), async_device_tracker_discovered)
@asyncio.coroutine
def async_platform_discovered(platform, info):
"""Load a platform."""
yield from async_setup_platform(platform, {}, disc_info=info)
discovery.async_listen_platform(hass, DOMAIN, async_platform_discovered)
# Clean up stale devices # Clean up stale devices
async_track_utc_time_change( async_track_utc_time_change(
hass, tracker.async_update_stale, second=range(0, 60, 5)) hass, tracker.async_update_stale, second=range(0, 60, 5))

View file

@ -1,5 +1,5 @@
""" """
Support the OwnTracks platform. Device tracker platform that adds support for OwnTracks over MQTT.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.owntracks/ https://home-assistant.io/components/device_tracker.owntracks/
@ -64,13 +64,7 @@ def get_cipher():
@asyncio.coroutine @asyncio.coroutine
def async_setup_scanner(hass, config, async_see, discovery_info=None): def async_setup_scanner(hass, config, async_see, discovery_info=None):
"""Set up an OwnTracks tracker.""" """Set up an OwnTracks tracker."""
max_gps_accuracy = config.get(CONF_MAX_GPS_ACCURACY) context = context_from_config(async_see, config)
waypoint_import = config.get(CONF_WAYPOINT_IMPORT)
waypoint_whitelist = config.get(CONF_WAYPOINT_WHITELIST)
secret = config.get(CONF_SECRET)
context = OwnTracksContext(async_see, secret, max_gps_accuracy,
waypoint_import, waypoint_whitelist)
@asyncio.coroutine @asyncio.coroutine
def async_handle_mqtt_message(topic, payload, qos): def async_handle_mqtt_message(topic, payload, qos):
@ -179,6 +173,17 @@ def _decrypt_payload(secret, topic, ciphertext):
return None return None
def context_from_config(async_see, config):
"""Create an async context from Home Assistant config."""
max_gps_accuracy = config.get(CONF_MAX_GPS_ACCURACY)
waypoint_import = config.get(CONF_WAYPOINT_IMPORT)
waypoint_whitelist = config.get(CONF_WAYPOINT_WHITELIST)
secret = config.get(CONF_SECRET)
return OwnTracksContext(async_see, secret, max_gps_accuracy,
waypoint_import, waypoint_whitelist)
class OwnTracksContext: class OwnTracksContext:
"""Hold the current OwnTracks context.""" """Hold the current OwnTracks context."""
@ -402,7 +407,8 @@ def async_handle_message(hass, context, message):
handler = HANDLERS.get(msgtype) handler = HANDLERS.get(msgtype)
if handler is None: if handler is None:
error = 'Received unsupported message type: {}.'.format(msgtype) _LOGGER.warning(
_LOGGER.warning(error) 'Received unsupported message type: %s.', msgtype)
return
yield from handler(hass, context, message) yield from handler(hass, context, message)

View file

@ -0,0 +1,54 @@
"""
Device tracker platform that adds support for OwnTracks over HTTP.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.owntracks_http/
"""
import asyncio
from aiohttp.web_exceptions import HTTPInternalServerError
from homeassistant.components.http import HomeAssistantView
# pylint: disable=unused-import
from .owntracks import ( # NOQA
REQUIREMENTS, PLATFORM_SCHEMA, context_from_config, async_handle_message)
DEPENDENCIES = ['http']
@asyncio.coroutine
def async_setup_scanner(hass, config, async_see, discovery_info=None):
"""Set up an OwnTracks tracker."""
context = context_from_config(async_see, config)
hass.http.register_view(OwnTracksView(context))
return True
class OwnTracksView(HomeAssistantView):
"""View to handle OwnTracks HTTP requests."""
url = '/api/owntracks/{user}/{device}'
name = 'api:owntracks'
def __init__(self, context):
"""Initialize OwnTracks URL endpoints."""
self.context = context
@asyncio.coroutine
def post(self, request, user, device):
"""Handle an OwnTracks message."""
hass = request.app['hass']
message = yield from request.json()
message['topic'] = 'owntracks/{}/{}'.format(user, device)
try:
yield from async_handle_message(hass, self.context, message)
return self.json([])
except ValueError:
raise HTTPInternalServerError

View file

@ -16,7 +16,7 @@ from homeassistant.const import CONF_HOST
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['pysnmp==4.3.9'] REQUIREMENTS = ['pysnmp==4.3.10']
CONF_COMMUNITY = 'community' CONF_COMMUNITY = 'community'
CONF_AUTHKEY = 'authkey' CONF_AUTHKEY = 'authkey'
@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument # pylint: disable=unused-argument
def get_scanner(hass, config): def get_scanner(hass, config):
"""Validate the configuration and return an snmp scanner.""" """Validate the configuration and return an SNMP scanner."""
scanner = SnmpScanner(config[DOMAIN]) scanner = SnmpScanner(config[DOMAIN])
return scanner if scanner.success_init else None return scanner if scanner.success_init else None

View file

@ -32,7 +32,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean, vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): vol.Any(
cv.boolean, cv.isfile)
}) })

View file

@ -21,7 +21,7 @@ from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.discovery import async_load_platform, async_discover from homeassistant.helpers.discovery import async_load_platform, async_discover
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
REQUIREMENTS = ['netdisco==1.2.0'] REQUIREMENTS = ['netdisco==1.2.2']
DOMAIN = 'discovery' DOMAIN = 'discovery'

View file

@ -15,7 +15,7 @@ from homeassistant.helpers import discovery
from homeassistant.const import CONF_API_KEY from homeassistant.const import CONF_API_KEY
from homeassistant.util import Throttle from homeassistant.util import Throttle
REQUIREMENTS = ['python-ecobee-api==0.0.9'] REQUIREMENTS = ['python-ecobee-api==0.0.10']
_CONFIGURING = {} _CONFIGURING = {}
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -3,10 +3,10 @@
FINGERPRINTS = { FINGERPRINTS = {
"compatibility.js": "1686167ff210e001f063f5c606b2e74b", "compatibility.js": "1686167ff210e001f063f5c606b2e74b",
"core.js": "2a7d01e45187c7d4635da05065b5e54e", "core.js": "2a7d01e45187c7d4635da05065b5e54e",
"frontend.html": "7e13ce36d3141182a62a5b061e87e77a", "frontend.html": "2de1bde3b4a6c6c47dd95504fc098906",
"mdi.html": "89074face5529f5fe6fbae49ecb3e88b", "mdi.html": "2e848b4da029bf73d426d5ba058a088d",
"micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a",
"panels/ha-panel-config.html": "61f65e75e39368e07441d7d6a4e36ae3", "panels/ha-panel-config.html": "52e2e1d477bfd6dc3708d65b8337f0af",
"panels/ha-panel-dev-event.html": "d409e7ab537d9fe629126d122345279c", "panels/ha-panel-dev-event.html": "d409e7ab537d9fe629126d122345279c",
"panels/ha-panel-dev-info.html": "b0e55eb657fd75f21aba2426ac0cedc0", "panels/ha-panel-dev-info.html": "b0e55eb657fd75f21aba2426ac0cedc0",
"panels/ha-panel-dev-mqtt.html": "94b222b013a98583842de3e72d5888c6", "panels/ha-panel-dev-mqtt.html": "94b222b013a98583842de3e72d5888c6",

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit a46e6b4cfa24d99011a9755e2588d761d78af152 Subproject commit 3092a4c08473df6b8643221e2740791fc6c8b03d

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -37,7 +37,7 @@
/* eslint-disable indent, no-unused-vars, no-multiple-empty-lines, max-nested-callbacks, space-before-function-paren, quotes, comma-spacing */ /* eslint-disable indent, no-unused-vars, no-multiple-empty-lines, max-nested-callbacks, space-before-function-paren, quotes, comma-spacing */
'use strict'; 'use strict';
var precacheConfig = [["/","da6c72cc82251a0456b2e678ebb6795c"],["/frontend/panels/dev-event-d409e7ab537d9fe629126d122345279c.html","936814991f2a5e23d61d29f0d40f81b8"],["/frontend/panels/dev-info-b0e55eb657fd75f21aba2426ac0cedc0.html","1fa953b0224470f70d4e87bbe4dff191"],["/frontend/panels/dev-mqtt-94b222b013a98583842de3e72d5888c6.html","dc3ddfac58397feda97317358f0aecbb"],["/frontend/panels/dev-service-422b2c181ee0713fa31d45a64e605baf.html","ae7d26b1c8c3309fd3c65944f89ea03f"],["/frontend/panels/dev-state-7948d3dba058f31517d880df8ed0e857.html","ff8156bb1a52490fcc07466556fce0e1"],["/frontend/panels/dev-template-928e7b81b9c113b70edc9f4a1d051827.html","312c8313800b44c83bcb8dc2df30c759"],["/frontend/panels/map-565db019147162080c21af962afc097f.html","a1a360042395682335e2f471dddad309"],["/static/compatibility-1686167ff210e001f063f5c606b2e74b.js","6ee7b5e2dd82b510c3bd92f7e215988e"],["/static/core-2a7d01e45187c7d4635da05065b5e54e.js","90a0a8a6a6dd0ca41b16f40e7d23924d"],["/static/frontend-7e13ce36d3141182a62a5b061e87e77a.html","73f53a9b597e1e69e0b3e56f4fc8f020"],["/static/mdi-89074face5529f5fe6fbae49ecb3e88b.html","97754e463f9e56a95c813d4d8e792347"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"]]; var precacheConfig = [["/","517bbe13d945f188a0896870cd3055d0"],["/frontend/panels/dev-event-d409e7ab537d9fe629126d122345279c.html","936814991f2a5e23d61d29f0d40f81b8"],["/frontend/panels/dev-info-b0e55eb657fd75f21aba2426ac0cedc0.html","1fa953b0224470f70d4e87bbe4dff191"],["/frontend/panels/dev-mqtt-94b222b013a98583842de3e72d5888c6.html","dc3ddfac58397feda97317358f0aecbb"],["/frontend/panels/dev-service-422b2c181ee0713fa31d45a64e605baf.html","ae7d26b1c8c3309fd3c65944f89ea03f"],["/frontend/panels/dev-state-7948d3dba058f31517d880df8ed0e857.html","ff8156bb1a52490fcc07466556fce0e1"],["/frontend/panels/dev-template-928e7b81b9c113b70edc9f4a1d051827.html","312c8313800b44c83bcb8dc2df30c759"],["/frontend/panels/map-565db019147162080c21af962afc097f.html","a1a360042395682335e2f471dddad309"],["/static/compatibility-1686167ff210e001f063f5c606b2e74b.js","6ee7b5e2dd82b510c3bd92f7e215988e"],["/static/core-2a7d01e45187c7d4635da05065b5e54e.js","90a0a8a6a6dd0ca41b16f40e7d23924d"],["/static/frontend-2de1bde3b4a6c6c47dd95504fc098906.html","51faf83c8a2d86529bc76a67fe6b5234"],["/static/mdi-89074face5529f5fe6fbae49ecb3e88b.html","97754e463f9e56a95c813d4d8e792347"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"]];
var cacheName = 'sw-precache-v3--' + (self.registration ? self.registration.scope : ''); var cacheName = 'sw-precache-v3--' + (self.registration ? self.registration.scope : '');

View file

@ -7,6 +7,13 @@
Code distributed by Google as part of the polymer project is also Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
Copyright (c) 2014 The Polymer Project Authors. All rights reserved. Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
@ -20,174 +27,170 @@ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/ */
'use strict';var Jb="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this; 'use strict';var N="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this,Oa="function"==typeof Object.defineProperties?Object.defineProperty:function(g,t,R){g!=Array.prototype&&g!=Object.prototype&&(g[t]=R.value)};function Pb(){Pb=function(){};N.Symbol||(N.Symbol=Qb)}var Qb=function(){var g=0;return function(t){return"jscomp_symbol_"+(t||"")+g++}}();
(function(){function k(){var a=this;this.s={};this.g=document.documentElement;var b=new Ka;b.rules=[];this.h=t.set(this.g,new t(b));this.i=!1;this.b=this.a=null;Kb(function(){a.c()})}function F(){this.customStyles=[];this.enqueued=!1}function Lb(){}function pa(a){this.cache={};this.c=void 0===a?100:a}function p(){}function t(a,b,c,d,e){this.G=a||null;this.b=b||null;this.ra=c||[];this.P=null;this.Z=e||"";this.a=this.B=this.K=null}function r(){}function Ka(){this.end=this.start=0;this.rules=this.parent= function Od(){Pb();var g=N.Symbol.iterator;g||(g=N.Symbol.iterator=N.Symbol("iterator"));"function"!=typeof Array.prototype[g]&&Oa(Array.prototype,g,{configurable:!0,writable:!0,value:function(){return Pd(this)}});Od=function(){}}function Pd(g){var t=0;return Qd(function(){return t<g.length?{done:!1,value:g[t++]}:{done:!0}})}function Qd(g){Od();g={next:g};g[N.Symbol.iterator]=function(){return this};return g}function Rd(g){Od();var t=g[Symbol.iterator];return t?t.call(g):Pd(g)}
this.previous=null;this.cssText=this.parsedCssText="";this.atRule=!1;this.type=0;this.parsedSelector=this.selector=this.keyframesName=""}function Id(a){function b(b,c){Object.defineProperty(b,"innerHTML",{enumerable:c.enumerable,configurable:!0,get:c.get,set:function(b){var d=this,e=void 0;n(this)&&(e=[],P(this,function(a){a!==d&&e.push(a)}));c.set.call(this,b);if(e)for(var f=0;f<e.length;f++){var g=e[f];1===g.__CE_state&&a.disconnectedCallback(g)}this.ownerDocument.__CE_hasRegistry?a.f(this):a.l(this); function Sd(g){for(var t,R=[];!(t=g.next()).done;)R.push(t.value);return R}
return b}})}function c(b,c){u(b,"insertAdjacentElement",function(b,d){var e=n(d);b=c.call(this,b,d);e&&a.a(d);n(b)&&a.b(d);return b})}Mb?u(Element.prototype,"attachShadow",function(a){return this.__CE_shadowRoot=a=Mb.call(this,a)}):console.warn("Custom Elements: `Element#attachShadow` was not patched.");if(La&&La.get)b(Element.prototype,La);else if(Ma&&Ma.get)b(HTMLElement.prototype,Ma);else{var d=Na.call(document,"div");a.v(function(a){b(a,{enumerable:!0,configurable:!0,get:function(){return Nb.call(this, (function(){function g(){var a=this;this.s={};this.g=document.documentElement;var b=new Pa;b.rules=[];this.h=w.set(this.g,new w(b));this.i=!1;this.b=this.a=null;Rb(function(){a.c()})}function t(){this.customStyles=[];this.enqueued=!1}function R(){}function ta(a){this.cache={};this.c=void 0===a?100:a}function p(){}function w(a,b,c,d,e){this.G=a||null;this.b=b||null;this.ua=c||[];this.S=null;this.$=e||"";this.a=this.C=this.M=null}function v(){}function Pa(){this.end=this.start=0;this.rules=this.parent=
!0).innerHTML},set:function(a){var b="template"===this.localName?this.content:this;for(d.innerHTML=a;0<b.childNodes.length;)Oa.call(b,b.childNodes[0]);for(;0<d.childNodes.length;)qa.call(b,d.childNodes[0])}})})}u(Element.prototype,"setAttribute",function(b,c){if(1!==this.__CE_state)return Ob.call(this,b,c);var d=Pa.call(this,b);Ob.call(this,b,c);c=Pa.call(this,b);a.attributeChangedCallback(this,b,d,c,null)});u(Element.prototype,"setAttributeNS",function(b,c,d){if(1!==this.__CE_state)return Pb.call(this, this.previous=null;this.cssText=this.parsedCssText="";this.atRule=!1;this.type=0;this.parsedSelector=this.selector=this.keyframesName=""}function Td(a){function b(b,c){Object.defineProperty(b,"innerHTML",{enumerable:c.enumerable,configurable:!0,get:c.get,set:function(b){var d=this,e=void 0;u(this)&&(e=[],S(this,function(a){a!==d&&e.push(a)}));c.set.call(this,b);if(e)for(var f=0;f<e.length;f++){var h=e[f];1===h.__CE_state&&a.disconnectedCallback(h)}this.ownerDocument.__CE_hasRegistry?a.f(this):a.l(this);
b,c,d);var e=ra.call(this,b,c);Pb.call(this,b,c,d);d=ra.call(this,b,c);a.attributeChangedCallback(this,c,e,d,b)});u(Element.prototype,"removeAttribute",function(b){if(1!==this.__CE_state)return Qb.call(this,b);var c=Pa.call(this,b);Qb.call(this,b);null!==c&&a.attributeChangedCallback(this,b,c,null,null)});u(Element.prototype,"removeAttributeNS",function(b,c){if(1!==this.__CE_state)return Rb.call(this,b,c);var d=ra.call(this,b,c);Rb.call(this,b,c);var e=ra.call(this,b,c);d!==e&&a.attributeChangedCallback(this, return b}})}function c(b,c){x(b,"insertAdjacentElement",function(b,d){var e=u(d);b=c.call(this,b,d);e&&a.a(d);u(b)&&a.b(d);return b})}Sb&&x(Element.prototype,"attachShadow",function(a){return this.__CE_shadowRoot=a=Sb.call(this,a)});if(Qa&&Qa.get)b(Element.prototype,Qa);else if(Ra&&Ra.get)b(HTMLElement.prototype,Ra);else{var d=Sa.call(document,"div");a.v(function(a){b(a,{enumerable:!0,configurable:!0,get:function(){return Tb.call(this,!0).innerHTML},set:function(a){var b="template"===this.localName?
c,d,e,b)});Sb?c(HTMLElement.prototype,Sb):Tb?c(Element.prototype,Tb):console.warn("Custom Elements: `Element#insertAdjacentElement` was not patched.");Ub(a,Element.prototype,{Ka:Jd,append:Kd});Ld(a,{kb:Md,jb:Nd,replaceWith:Od,remove:Pd})}function Ld(a,b){var c=Element.prototype;c.before=function(c){for(var d=[],f=0;f<arguments.length;++f)d[f-0]=arguments[f];f=d.filter(function(a){return a instanceof Node&&n(a)});b.kb.apply(this,d);for(var g=0;g<f.length;g++)a.a(f[g]);if(n(this))for(f=0;f<d.length;f++)g= this.content:this;for(d.innerHTML=a;0<b.childNodes.length;)Ta.call(b,b.childNodes[0]);for(;0<d.childNodes.length;)ua.call(b,d.childNodes[0])}})})}x(Element.prototype,"setAttribute",function(b,c){if(1!==this.__CE_state)return Ub.call(this,b,c);var d=Ua.call(this,b);Ub.call(this,b,c);c=Ua.call(this,b);a.attributeChangedCallback(this,b,d,c,null)});x(Element.prototype,"setAttributeNS",function(b,c,d){if(1!==this.__CE_state)return Vb.call(this,b,c,d);var e=va.call(this,b,c);Vb.call(this,b,c,d);d=va.call(this,
d[f],g instanceof Element&&a.b(g)};c.after=function(c){for(var d=[],f=0;f<arguments.length;++f)d[f-0]=arguments[f];f=d.filter(function(a){return a instanceof Node&&n(a)});b.jb.apply(this,d);for(var g=0;g<f.length;g++)a.a(f[g]);if(n(this))for(f=0;f<d.length;f++)g=d[f],g instanceof Element&&a.b(g)};c.replaceWith=function(c){for(var d=[],f=0;f<arguments.length;++f)d[f-0]=arguments[f];f=d.filter(function(a){return a instanceof Node&&n(a)});var g=n(this);b.replaceWith.apply(this,d);for(var h=0;h<f.length;h++)a.a(f[h]); b,c);a.attributeChangedCallback(this,c,e,d,b)});x(Element.prototype,"removeAttribute",function(b){if(1!==this.__CE_state)return Wb.call(this,b);var c=Ua.call(this,b);Wb.call(this,b);null!==c&&a.attributeChangedCallback(this,b,c,null,null)});x(Element.prototype,"removeAttributeNS",function(b,c){if(1!==this.__CE_state)return Xb.call(this,b,c);var d=va.call(this,b,c);Xb.call(this,b,c);var e=va.call(this,b,c);d!==e&&a.attributeChangedCallback(this,c,d,e,b)});Yb?c(HTMLElement.prototype,Yb):Zb?c(Element.prototype,
if(g)for(a.a(this),f=0;f<d.length;f++)g=d[f],g instanceof Element&&a.b(g)};c.remove=function(){var c=n(this);b.remove.call(this);c&&a.a(this)}}function Qd(a){function b(b,d){Object.defineProperty(b,"textContent",{enumerable:d.enumerable,configurable:!0,get:d.get,set:function(b){if(this.nodeType===Node.TEXT_NODE)d.set.call(this,b);else{var c=void 0;if(this.firstChild){var e=this.childNodes,h=e.length;if(0<h&&n(this)){c=Array(h);for(var m=0;m<h;m++)c[m]=e[m]}}d.set.call(this,b);if(c)for(b=0;b<c.length;b++)a.a(c[b])}}})} Zb):console.warn("Custom Elements: `Element#insertAdjacentElement` was not patched.");Va(a,Element.prototype,{ea:Ud,append:Vd});Wd(a,{ra:Xd,jb:Yd,replaceWith:Zd,remove:$d})}function Wd(a,b){var c=Element.prototype;function d(b){return function(c){for(var d=[],e=0;e<arguments.length;++e)d[e-0]=arguments[e];e=[];for(var f=[],q=0;q<d.length;q++){var g=d[q];g instanceof Element&&u(g)&&f.push(g);if(g instanceof DocumentFragment)for(g=g.firstChild;g;g=g.nextSibling)e.push(g);else e.push(g)}b.apply(this,
u(Node.prototype,"insertBefore",function(b,d){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=Vb.call(this,b,d);if(n(this))for(d=0;d<c.length;d++)a.b(c[d]);return b}c=n(b);d=Vb.call(this,b,d);c&&a.a(b);n(this)&&a.b(b);return d});u(Node.prototype,"appendChild",function(b){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=qa.call(this,b);if(n(this))for(var e=0;e<c.length;e++)a.b(c[e]);return b}c=n(b);e=qa.call(this,b);c&&a.a(b);n(this)&& d);for(d=0;d<f.length;d++)a.a(f[d]);if(u(this))for(d=0;d<e.length;d++)f=e[d],f instanceof Element&&a.b(f)}}void 0!==b.ra&&(c.before=d(b.ra));void 0!==b.ra&&(c.after=d(b.jb));void 0!==b.replaceWith&&x(c,"replaceWith",function(c){for(var d=[],e=0;e<arguments.length;++e)d[e-0]=arguments[e];e=[];for(var k=[],m=0;m<d.length;m++){var g=d[m];g instanceof Element&&u(g)&&k.push(g);if(g instanceof DocumentFragment)for(g=g.firstChild;g;g=g.nextSibling)e.push(g);else e.push(g)}m=u(this);b.replaceWith.apply(this,
a.b(b);return e});u(Node.prototype,"cloneNode",function(b){b=Nb.call(this,b);this.ownerDocument.__CE_hasRegistry?a.f(b):a.l(b);return b});u(Node.prototype,"removeChild",function(b){var c=n(b),e=Oa.call(this,b);c&&a.a(b);return e});u(Node.prototype,"replaceChild",function(b,d){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=Wb.call(this,b,d);if(n(this))for(a.a(d),d=0;d<c.length;d++)a.b(c[d]);return b}c=n(b);var f=Wb.call(this,b,d),g=n(this);g&&a.a(d);c&&a.a(b);g&& d);for(d=0;d<k.length;d++)a.a(k[d]);if(m)for(a.a(this),d=0;d<e.length;d++)k=e[d],k instanceof Element&&a.b(k)});void 0!==b.remove&&x(c,"remove",function(){var c=u(this);b.remove.call(this);c&&a.a(this)})}function ae(a){function b(b,d){Object.defineProperty(b,"textContent",{enumerable:d.enumerable,configurable:!0,get:d.get,set:function(b){if(this.nodeType===Node.TEXT_NODE)d.set.call(this,b);else{var c=void 0;if(this.firstChild){var e=this.childNodes,k=e.length;if(0<k&&u(this)){c=Array(k);for(var m=
a.b(b);return f});Qa&&Qa.get?b(Node.prototype,Qa):a.v(function(a){b(a,{enumerable:!0,configurable:!0,get:function(){for(var a=[],b=0;b<this.childNodes.length;b++)a.push(this.childNodes[b].textContent);return a.join("")},set:function(a){for(;this.firstChild;)Oa.call(this,this.firstChild);qa.call(this,document.createTextNode(a))}})})}function Rd(a){u(Document.prototype,"createElement",function(b){if(this.__CE_hasRegistry){var c=a.c(b);if(c)return new c.constructor}b=Na.call(this,b);a.g(b);return b}); 0;m<k;m++)c[m]=e[m]}}d.set.call(this,b);if(c)for(b=0;b<c.length;b++)a.a(c[b])}}})}x(Node.prototype,"insertBefore",function(b,d){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=$b.call(this,b,d);if(u(this))for(d=0;d<c.length;d++)a.b(c[d]);return b}c=u(b);d=$b.call(this,b,d);c&&a.a(b);u(this)&&a.b(b);return d});x(Node.prototype,"appendChild",function(b){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=ua.call(this,b);if(u(this))for(var e=
u(Document.prototype,"importNode",function(b,c){b=Sd.call(this,b,c);this.__CE_hasRegistry?a.f(b):a.l(b);return b});u(Document.prototype,"createElementNS",function(b,c){if(this.__CE_hasRegistry&&(null===b||"http://www.w3.org/1999/xhtml"===b)){var d=a.c(c);if(d)return new d.constructor}b=Td.call(this,b,c);a.g(b);return b});Ub(a,Document.prototype,{Ka:Ud,append:Vd})}function Ub(a,b,c){b.prepend=function(b){for(var d=[],f=0;f<arguments.length;++f)d[f-0]=arguments[f];f=d.filter(function(a){return a instanceof 0;e<c.length;e++)a.b(c[e]);return b}c=u(b);e=ua.call(this,b);c&&a.a(b);u(this)&&a.b(b);return e});x(Node.prototype,"cloneNode",function(b){b=Tb.call(this,b);this.ownerDocument.__CE_hasRegistry?a.f(b):a.l(b);return b});x(Node.prototype,"removeChild",function(b){var c=u(b),e=Ta.call(this,b);c&&a.a(b);return e});x(Node.prototype,"replaceChild",function(b,d){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=ac.call(this,b,d);if(u(this))for(a.a(d),d=0;d<c.length;d++)a.b(c[d]);
Node&&n(a)});c.Ka.apply(this,d);for(var g=0;g<f.length;g++)a.a(f[g]);if(n(this))for(f=0;f<d.length;f++)g=d[f],g instanceof Element&&a.b(g)};b.append=function(b){for(var d=[],f=0;f<arguments.length;++f)d[f-0]=arguments[f];f=d.filter(function(a){return a instanceof Node&&n(a)});c.append.apply(this,d);for(var g=0;g<f.length;g++)a.a(f[g]);if(n(this))for(f=0;f<d.length;f++)g=d[f],g instanceof Element&&a.b(g)}}function Wd(a){window.HTMLElement=function(){function b(){var b=this.constructor,d=a.C(b);if(!d)throw Error("The custom element being constructed was not registered with `customElements`."); return b}c=u(b);var f=ac.call(this,b,d),h=u(this);h&&a.a(d);c&&a.a(b);h&&a.b(b);return f});Wa&&Wa.get?b(Node.prototype,Wa):a.v(function(a){b(a,{enumerable:!0,configurable:!0,get:function(){for(var a=[],b=0;b<this.childNodes.length;b++)a.push(this.childNodes[b].textContent);return a.join("")},set:function(a){for(;this.firstChild;)Ta.call(this,this.firstChild);ua.call(this,document.createTextNode(a))}})})}function be(a){x(Document.prototype,"createElement",function(b){if(this.__CE_hasRegistry){var c=
var e=d.constructionStack;if(0===e.length)return e=Na.call(document,d.localName),Object.setPrototypeOf(e,b.prototype),e.__CE_state=1,e.__CE_definition=d,a.g(e),e;d=e.length-1;var f=e[d];if(f===Xb)throw Error("The HTMLElement constructor was either called reentrantly for this constructor or called multiple times.");e[d]=Xb;Object.setPrototypeOf(f,b.prototype);a.g(f);return f}b.prototype=Xd.prototype;return b}()}function x(a){this.c=!1;this.a=a;this.h=new Map;this.f=function(a){return a()};this.b=!1; a.c(b);if(c)return new c.constructor}b=Sa.call(this,b);a.g(b);return b});x(Document.prototype,"importNode",function(b,c){b=ce.call(this,b,c);this.__CE_hasRegistry?a.f(b):a.l(b);return b});x(Document.prototype,"createElementNS",function(b,c){if(this.__CE_hasRegistry&&(null===b||"http://www.w3.org/1999/xhtml"===b)){var d=a.c(c);if(d)return new d.constructor}b=de.call(this,b,c);a.g(b);return b});Va(a,Document.prototype,{ea:ee,append:fe})}function Va(a,b,c){function d(b){return function(c){for(var d=
this.g=[];this.i=new Ra(a,document)}function Yb(){var a=this;this.b=this.a=void 0;this.c=new Promise(function(b){a.b=b;a.a&&b(a.a)})}function Ra(a,b){this.b=a;this.a=b;this.N=void 0;this.b.f(this.a);"loading"===this.a.readyState&&(this.N=new MutationObserver(this.f.bind(this)),this.N.observe(this.a,{childList:!0,subtree:!0}))}function z(){this.u=new Map;this.s=new Map;this.j=[];this.h=!1}function l(a,b,c){if(a!==Zb)throw new TypeError("Illegal constructor");a=document.createDocumentFragment();a.__proto__= [],e=0;e<arguments.length;++e)d[e-0]=arguments[e];e=[];for(var f=[],g=0;g<d.length;g++){var n=d[g];n instanceof Element&&u(n)&&f.push(n);if(n instanceof DocumentFragment)for(n=n.firstChild;n;n=n.nextSibling)e.push(n);else e.push(n)}b.apply(this,d);for(d=0;d<f.length;d++)a.a(f[d]);if(u(this))for(d=0;d<e.length;d++)f=e[d],f instanceof Element&&a.b(f)}}void 0!==c.ea&&(b.prepend=d(c.ea));void 0!==c.append&&(b.append=d(c.append))}function ge(a){window.HTMLElement=function(){function b(){var b=this.constructor,
l.prototype;a.D(b,c);return a}function sa(a){if(!a.__shady||void 0===a.__shady.firstChild){a.__shady=a.__shady||{};a.__shady.firstChild=Sa(a);a.__shady.lastChild=Ta(a);$b(a);for(var b=a.__shady.childNodes=U(a),c=0,d;c<b.length&&(d=b[c]);c++)d.__shady=d.__shady||{},d.__shady.parentNode=a,d.__shady.nextSibling=b[c+1]||null,d.__shady.previousSibling=b[c-1]||null,ac(d)}}function Yd(a){var b=a&&a.N;b&&(b.ba.delete(a.ab),b.ba.size||(a.fb.__shady.X=null))}function Zd(a,b){a.__shady=a.__shady||{};a.__shady.X|| d=a.B(b);if(!d)throw Error("The custom element being constructed was not registered with `customElements`.");var e=d.constructionStack;if(0===e.length)return e=Sa.call(document,d.localName),Object.setPrototypeOf(e,b.prototype),e.__CE_state=1,e.__CE_definition=d,a.g(e),e;d=e.length-1;var f=e[d];if(f===bc)throw Error("The HTMLElement constructor was either called reentrantly for this constructor or called multiple times.");e[d]=bc;Object.setPrototypeOf(f,b.prototype);a.g(f);return f}b.prototype=he.prototype;
(a.__shady.X=new ta);a.__shady.X.ba.add(b);var c=a.__shady.X;return{ab:b,N:c,fb:a,takeRecords:function(){return c.takeRecords()}}}function ta(){this.a=!1;this.addedNodes=[];this.removedNodes=[];this.ba=new Set}function Q(a,b){V[W]=a;V[W+1]=b;W+=2;2===W&&(Ua?Ua(X):$d())}function ae(){return function(){return process.Gb(X)}}function be(){return"undefined"!==typeof Va?function(){Va(X)}:Wa()}function ce(){var a=0,b=new bc(X),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data= return b}()}function y(a){this.c=!1;this.a=a;this.h=new Map;this.f=function(a){return a()};this.b=!1;this.g=[];this.i=new Xa(a,document)}function cc(){var a=this;this.b=this.a=void 0;this.c=new Promise(function(b){a.b=b;a.a&&b(a.a)})}function Xa(a,b){this.b=a;this.a=b;this.P=void 0;this.b.f(this.a);"loading"===this.a.readyState&&(this.P=new MutationObserver(this.f.bind(this)),this.P.observe(this.a,{childList:!0,subtree:!0}))}function B(){this.u=new Map;this.s=new Map;this.j=[];this.h=!1}function l(a,
a=++a%2}}function de(){var a=new MessageChannel;a.port1.onmessage=X;return function(){return a.port2.postMessage(0)}}function Wa(){var a=setTimeout;return function(){return a(X,1)}}function X(){for(var a=0;a<W;a+=2)(0,V[a])(V[a+1]),V[a]=void 0,V[a+1]=void 0;W=0}function ee(){try{var a=require("vertx");Va=a.Ib||a.Hb;return be()}catch(b){return Wa()}}function Xa(a,b){var c=this,d=new this.constructor(Y);void 0===d[ua]&&cc(d);var e=c.o;if(e){var f=arguments[e-1];Q(function(){return dc(e,d,f,c.m)})}else Ya(c, b,c){if(a!==dc)throw new TypeError("Illegal constructor");a=document.createDocumentFragment();a.__proto__=l.prototype;a.H(b,c);return a}function wa(a){if(!a.__shady||void 0===a.__shady.firstChild){a.__shady=a.__shady||{};a.__shady.firstChild=Ya(a);a.__shady.lastChild=Za(a);ec(a);for(var b=a.__shady.childNodes=X(a),c=0,d;c<b.length&&(d=b[c]);c++)d.__shady=d.__shady||{},d.__shady.parentNode=a,d.__shady.nextSibling=b[c+1]||null,d.__shady.previousSibling=b[c-1]||null,fc(d)}}function ie(a){var b=a&&a.P;
d,a,b);return d}function Za(a){if(a&&"object"===typeof a&&a.constructor===this)return a;var b=new this(Y);ea(b,a);return b}function Y(){}function ec(a){try{return a.then}catch(b){return fa.error=b,fa}}function fe(a,b,c,d){try{a.call(b,c,d)}catch(e){return e}}function ge(a,b,c){Q(function(a){var d=!1,f=fe(c,b,function(c){d||(d=!0,b!==c?ea(a,c):K(a,c))},function(b){d||(d=!0,A(a,b))});!d&&f&&(d=!0,A(a,f))},a)}function he(a,b){1===b.o?K(a,b.m):2===b.o?A(a,b.m):Ya(b,void 0,function(b){return ea(a,b)}, b&&(b.ca.delete(a.ab),b.ca.size||(a.fb.__shady.Y=null))}function je(a,b){a.__shady=a.__shady||{};a.__shady.Y||(a.__shady.Y=new xa);a.__shady.Y.ca.add(b);var c=a.__shady.Y;return{ab:b,P:c,fb:a,takeRecords:function(){return c.takeRecords()}}}function xa(){this.a=!1;this.addedNodes=[];this.removedNodes=[];this.ca=new Set}function T(a,b){Y[Z]=a;Y[Z+1]=b;Z+=2;2===Z&&($a?$a(aa):ke())}function le(){return function(){return process.Hb(aa)}}function me(){return"undefined"!==typeof ab?function(){ab(aa)}:bb()}
function(b){return A(a,b)})}function fc(a,b,c){b.constructor===a.constructor&&c===Xa&&b.constructor.resolve===Za?he(a,b):c===fa?(A(a,fa.error),fa.error=null):void 0===c?K(a,b):"function"===typeof c?ge(a,b,c):K(a,b)}function ea(a,b){if(a===b)A(a,new TypeError("You cannot resolve a promise with itself"));else{var c=typeof b;null===b||"object"!==c&&"function"!==c?K(a,b):fc(a,b,ec(b))}}function ie(a){a.Ba&&a.Ba(a.m);$a(a)}function K(a,b){void 0===a.o&&(a.m=b,a.o=1,0!==a.U.length&&Q($a,a))}function A(a, function ne(){var a=0,b=new gc(aa),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data=a=++a%2}}function oe(){var a=new MessageChannel;a.port1.onmessage=aa;return function(){return a.port2.postMessage(0)}}function bb(){var a=setTimeout;return function(){return a(aa,1)}}function aa(){for(var a=0;a<Z;a+=2)(0,Y[a])(Y[a+1]),Y[a]=void 0,Y[a+1]=void 0;Z=0}function pe(){try{var a=require("vertx");ab=a.Jb||a.Ib;return me()}catch(b){return bb()}}function cb(a,b){var c=this,
b){void 0===a.o&&(a.o=2,a.m=b,Q(ie,a))}function Ya(a,b,c,d){var e=a.U,f=e.length;a.Ba=null;e[f]=b;e[f+1]=c;e[f+2]=d;0===f&&a.o&&Q($a,a)}function $a(a){var b=a.U,c=a.o;if(0!==b.length){for(var d,e,f=a.m,g=0;g<b.length;g+=3)d=b[g],e=b[g+c],d?dc(c,d,e,f):e(f);a.U.length=0}}function gc(){this.error=null}function dc(a,b,c,d){var e="function"===typeof c;if(e){try{var f=c(d)}catch(H){ab.error=H,f=ab}if(f===ab){var g=!0;var h=f.error;f.error=null}else var m=!0;if(b===f){A(b,new TypeError("A promises callback cannot return that same promise.")); d=new this.constructor(ba);void 0===d[ya]&&hc(d);var e=c.o;if(e){var f=arguments[e-1];T(function(){return ic(e,d,f,c.m)})}else db(c,d,a,b);return d}function eb(a){if(a&&"object"===typeof a&&a.constructor===this)return a;var b=new this(ba);ja(b,a);return b}function ba(){}function jc(a){try{return a.then}catch(b){return ka.error=b,ka}}function qe(a,b,c,d){try{a.call(b,c,d)}catch(e){return e}}function re(a,b,c){T(function(a){var d=!1,f=qe(c,b,function(c){d||(d=!0,b!==c?ja(a,c):L(a,c))},function(b){d||
return}}else f=d,m=!0;void 0===b.o&&(e&&m?ea(b,f):g?A(b,h):1===a?K(b,f):2===a&&A(b,f))}function je(a,b){try{b(function(b){ea(a,b)},function(b){A(a,b)})}catch(c){A(a,c)}}function cc(a){a[ua]=hc++;a.o=void 0;a.m=void 0;a.U=[]}function ha(a,b){this.eb=a;this.J=new a(Y);this.J[ua]||cc(this.J);ic(b)?(this.$=this.length=b.length,this.m=Array(this.length),0===this.length?K(this.J,this.m):(this.length=this.length||0,this.cb(b),0===this.$&&K(this.J,this.m))):A(this.J,Error("Array Methods must be provided an Array"))} (d=!0,C(a,b))});!d&&f&&(d=!0,C(a,f))},a)}function se(a,b){1===b.o?L(a,b.m):2===b.o?C(a,b.m):db(b,void 0,function(b){return ja(a,b)},function(b){return C(a,b)})}function kc(a,b,c){b.constructor===a.constructor&&c===cb&&b.constructor.resolve===eb?se(a,b):c===ka?(C(a,ka.error),ka.error=null):void 0===c?L(a,b):"function"===typeof c?re(a,b,c):L(a,b)}function ja(a,b){if(a===b)C(a,new TypeError("You cannot resolve a promise with itself"));else{var c=typeof b;null===b||"object"!==c&&"function"!==c?L(a,b):
function y(a){this[ua]=hc++;this.m=this.o=void 0;this.U=[];if(Y!==a){if("function"!==typeof a)throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(this instanceof y)je(this,a);else throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");}}function Z(a){return a.__shady&&void 0!==a.__shady.firstChild}function I(a){return"ShadyRoot"===a.Wa}function ia(a){a=a.getRootNode(); kc(a,b,jc(b))}}function te(a){a.Da&&a.Da(a.m);fb(a)}function L(a,b){void 0===a.o&&(a.m=b,a.o=1,0!==a.V.length&&T(fb,a))}function C(a,b){void 0===a.o&&(a.o=2,a.m=b,T(te,a))}function db(a,b,c,d){var e=a.V,f=e.length;a.Da=null;e[f]=b;e[f+1]=c;e[f+2]=d;0===f&&a.o&&T(fb,a)}function fb(a){var b=a.V,c=a.o;if(0!==b.length){for(var d,e,f=a.m,h=0;h<b.length;h+=3)d=b[h],e=b[h+c],d?ic(c,d,e,f):e(f);a.V.length=0}}function lc(){this.error=null}function ic(a,b,c,d){var e="function"===typeof c;if(e){try{var f=c(d)}catch(q){gb.error=
if(I(a))return a}function bb(a,b){if(a&&b)for(var c=Object.getOwnPropertyNames(b),d=0,e;d<c.length&&(e=c[d]);d++){var f=Object.getOwnPropertyDescriptor(b,e);f&&Object.defineProperty(a,e,f)}}function cb(a,b){for(var c=[],d=1;d<arguments.length;++d)c[d-1]=arguments[d];for(d=0;d<c.length;d++)bb(a,c[d]);return a}function ke(a,b){for(var c in b)a[c]=b[c]}function jc(a){db.push(a);eb.textContent=kc++}function lc(a){fb||(fb=!0,jc(va));ja.push(a)}function va(){fb=!1;for(var a=!!ja.length;ja.length;)ja.shift()(); q,f=gb}if(f===gb){var h=!0;var k=f.error;f.error=null}else var m=!0;if(b===f){C(b,new TypeError("A promises callback cannot return that same promise."));return}}else f=d,m=!0;void 0===b.o&&(e&&m?ja(b,f):h?C(b,k):1===a?L(b,f):2===a&&C(b,f))}function ue(a,b){try{b(function(b){ja(a,b)},function(b){C(a,b)})}catch(c){C(a,c)}}function hc(a){a[ya]=mc++;a.o=void 0;a.m=void 0;a.V=[]}function la(a,b){this.eb=a;this.L=new a(ba);this.L[ya]||hc(this.L);nc(b)?(this.aa=this.length=b.length,this.m=Array(this.length),
return a}function le(a,b){var c=b.getRootNode();return a.map(function(a){var b=c===a.target.getRootNode();if(b&&a.addedNodes){if(b=Array.from(a.addedNodes).filter(function(a){return c===a.getRootNode()}),b.length)return a=Object.create(a),Object.defineProperty(a,"addedNodes",{value:b,configurable:!0}),a}else if(b)return a}).filter(function(a){return a})}function mc(a){switch(a){case "&":return"&amp;";case "<":return"&lt;";case ">":return"&gt;";case '"':return"&quot;";case "\u00a0":return"&nbsp;"}} 0===this.length?L(this.L,this.m):(this.length=this.length||0,this.cb(b),0===this.aa&&L(this.L,this.m))):C(this.L,Error("Array Methods must be provided an Array"))}function D(a){this[ya]=mc++;this.m=this.o=void 0;this.V=[];if(ba!==a){if("function"!==typeof a)throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(this instanceof D)ue(this,a);else throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
function nc(a){for(var b={},c=0;c<a.length;c++)b[a[c]]=!0;return b}function gb(a,b){"template"===a.localName&&(a=a.content);for(var c="",d=b?b(a):a.childNodes,e=0,f=d.length,g;e<f&&(g=d[e]);e++){a:{var h=g;var m=a;var H=b;switch(h.nodeType){case Node.ELEMENT_NODE:for(var k=h.localName,l="<"+k,n=h.attributes,p=0;m=n[p];p++)l+=" "+m.name+'="'+m.value.replace(me,mc)+'"';l+=">";h=ne[k]?l:l+gb(h,H)+"</"+k+">";break a;case Node.TEXT_NODE:h=h.data;h=m&&oe[m.localName]?h:h.replace(pe,mc);break a;case Node.COMMENT_NODE:h= }}function ca(a){return a.__shady&&void 0!==a.__shady.firstChild}function J(a){return"ShadyRoot"===a.Wa}function ma(a){a=a.getRootNode();if(J(a))return a}function hb(a,b){if(a&&b)for(var c=Object.getOwnPropertyNames(b),d=0,e;d<c.length&&(e=c[d]);d++){var f=Object.getOwnPropertyDescriptor(b,e);f&&Object.defineProperty(a,e,f)}}function ib(a,b){for(var c=[],d=1;d<arguments.length;++d)c[d-1]=arguments[d];for(d=0;d<c.length;d++)hb(a,c[d]);return a}function ve(a,b){for(var c in b)a[c]=b[c]}function oc(a){jb.push(a);
"\x3c!--"+h.data+"--\x3e";break a;default:throw window.console.error(h),Error("not implemented");}}c+=h}return c}function aa(a){B.currentNode=a;return B.parentNode()}function Sa(a){B.currentNode=a;return B.firstChild()}function Ta(a){B.currentNode=a;return B.lastChild()}function oc(a){B.currentNode=a;return B.previousSibling()}function pc(a){B.currentNode=a;return B.nextSibling()}function U(a){var b=[];B.currentNode=a;for(a=B.firstChild();a;)b.push(a),a=B.nextSibling();return b}function qc(a){C.currentNode= kb.textContent=pc++}function qc(a,b){for(;b;){if(b==a)return!0;b=b.parentNode}return!1}function rc(a){lb||(lb=!0,oc(za));na.push(a)}function za(){lb=!1;for(var a=!!na.length;na.length;)na.shift()();return a}function we(a,b){var c=b.getRootNode();return a.map(function(a){var b=c===a.target.getRootNode();if(b&&a.addedNodes){if(b=Array.from(a.addedNodes).filter(function(a){return c===a.getRootNode()}),b.length)return a=Object.create(a),Object.defineProperty(a,"addedNodes",{value:b,configurable:!0}),
a;return C.parentNode()}function rc(a){C.currentNode=a;return C.firstChild()}function sc(a){C.currentNode=a;return C.lastChild()}function tc(a){C.currentNode=a;return C.previousSibling()}function uc(a){C.currentNode=a;return C.nextSibling()}function vc(a){var b=[];C.currentNode=a;for(a=C.firstChild();a;)b.push(a),a=C.nextSibling();return b}function wc(a){return gb(a,function(a){return U(a)})}function xc(a){switch(a.nodeType){case Node.ELEMENT_NODE:case Node.DOCUMENT_FRAGMENT_NODE:a=document.createTreeWalker(a, a}else if(b)return a}).filter(function(a){return a})}function sc(a){switch(a){case "&":return"&amp;";case "<":return"&lt;";case ">":return"&gt;";case '"':return"&quot;";case "\u00a0":return"&nbsp;"}}function tc(a){for(var b={},c=0;c<a.length;c++)b[a[c]]=!0;return b}function mb(a,b){"template"===a.localName&&(a=a.content);for(var c="",d=b?b(a):a.childNodes,e=0,f=d.length,h;e<f&&(h=d[e]);e++){a:{var k=h;var m=a;var g=b;switch(k.nodeType){case Node.ELEMENT_NODE:for(var n=k.localName,l="<"+n,t=k.attributes,
NodeFilter.SHOW_TEXT,null,!1);for(var b="",c;c=a.nextNode();)b+=c.nodeValue;return b;default:return a.nodeValue}}function M(a,b,c){for(var d in b){var e=Object.getOwnPropertyDescriptor(a,d);e&&e.configurable||!e&&c?Object.defineProperty(a,d,b[d]):c&&console.warn("Could not define",d,"on",a)}}function R(a){M(a,yc);M(a,hb);M(a,ib)}function zc(a,b,c){ac(a);c=c||null;a.__shady=a.__shady||{};b.__shady=b.__shady||{};c&&(c.__shady=c.__shady||{});a.__shady.previousSibling=c?c.__shady.previousSibling:b.lastChild; p=0;m=t[p];p++)l+=" "+m.name+'="'+m.value.replace(xe,sc)+'"';l+=">";k=ye[n]?l:l+mb(k,g)+"</"+n+">";break a;case Node.TEXT_NODE:k=k.data;k=m&&ze[m.localName]?k:k.replace(Ae,sc);break a;case Node.COMMENT_NODE:k="\x3c!--"+k.data+"--\x3e";break a;default:throw window.console.error(k),Error("not implemented");}}c+=k}return c}function da(a){E.currentNode=a;return E.parentNode()}function Ya(a){E.currentNode=a;return E.firstChild()}function Za(a){E.currentNode=a;return E.lastChild()}function uc(a){E.currentNode=
var d=a.__shady.previousSibling;d&&d.__shady&&(d.__shady.nextSibling=a);(d=a.__shady.nextSibling=c)&&d.__shady&&(d.__shady.previousSibling=a);a.__shady.parentNode=b;c?c===b.__shady.firstChild&&(b.__shady.firstChild=a):(b.__shady.lastChild=a,b.__shady.firstChild||(b.__shady.firstChild=a));b.__shady.childNodes=null}function jb(a,b,c){if(b===a)throw Error("Failed to execute 'appendChild' on 'Node': The new child element contains the parent.");if(c){var d=c.__shady&&c.__shady.parentNode;if(void 0!==d&& a;return E.previousSibling()}function vc(a){E.currentNode=a;return E.nextSibling()}function X(a){var b=[];E.currentNode=a;for(a=E.firstChild();a;)b.push(a),a=E.nextSibling();return b}function wc(a){F.currentNode=a;return F.parentNode()}function xc(a){F.currentNode=a;return F.firstChild()}function yc(a){F.currentNode=a;return F.lastChild()}function zc(a){F.currentNode=a;return F.previousSibling()}function Ac(a){F.currentNode=a;return F.nextSibling()}function Bc(a){var b=[];F.currentNode=a;for(a=F.firstChild();a;)b.push(a),
d!==a||void 0===d&&aa(c)!==a)throw Error("Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.");}if(c===b)return b;b.parentNode&&kb(b.parentNode,b);d=ia(a);var e;if(e=d)a:{if(!b.__noInsertionPoint){var f;"slot"===b.localName?f=[b]:b.querySelectorAll&&(f=b.querySelectorAll("slot"));if(f&&f.length){e=f;break a}}e=void 0}f=e;d&&("slot"===a.localName||f)&&d.M();if(Z(a)){e=c;$b(a);a.__shady=a.__shady||{};void 0!==a.__shady.firstChild&& a=F.nextSibling();return b}function Cc(a){return mb(a,function(a){return X(a)})}function Dc(a){switch(a.nodeType){case Node.ELEMENT_NODE:case Node.DOCUMENT_FRAGMENT_NODE:a=document.createTreeWalker(a,NodeFilter.SHOW_TEXT,null,!1);for(var b="",c;c=a.nextNode();)b+=c.nodeValue;return b;default:return a.nodeValue}}function O(a,b,c){for(var d in b){var e=Object.getOwnPropertyDescriptor(a,d);e&&e.configurable||!e&&c?Object.defineProperty(a,d,b[d]):c&&console.warn("Could not define",d,"on",a)}}function U(a){O(a,
(a.__shady.childNodes=null);if(b.nodeType===Node.DOCUMENT_FRAGMENT_NODE){for(var g=b.childNodes,h=0;h<g.length;h++)zc(g[h],a,e);b.__shady=b.__shady||{};e=void 0!==b.__shady.firstChild?null:void 0;b.__shady.firstChild=b.__shady.lastChild=e;b.__shady.childNodes=e}else zc(b,a,e);if(lb(a)){a.__shady.root.M();var m=!0}else a.__shady.root&&(m=!0)}m||(m=I(a)?a.host:a,c?(c=Ac(c),mb.call(m,b,c)):Bc.call(m,b));Cc(a,b);f&&d.$a(f);return b}function kb(a,b){if(b.parentNode!==a)throw Error("The node to be removed is not a child of this node: "+ Ec);O(a,nb);O(a,ob)}function Fc(a,b,c){fc(a);c=c||null;a.__shady=a.__shady||{};b.__shady=b.__shady||{};c&&(c.__shady=c.__shady||{});a.__shady.previousSibling=c?c.__shady.previousSibling:b.lastChild;var d=a.__shady.previousSibling;d&&d.__shady&&(d.__shady.nextSibling=a);(d=a.__shady.nextSibling=c)&&d.__shady&&(d.__shady.previousSibling=a);a.__shady.parentNode=b;c?c===b.__shady.firstChild&&(b.__shady.firstChild=a):(b.__shady.lastChild=a,b.__shady.firstChild||(b.__shady.firstChild=a));b.__shady.childNodes=
b);var c=ia(b);if(Z(a)){b.__shady=b.__shady||{};a.__shady=a.__shady||{};b===a.__shady.firstChild&&(a.__shady.firstChild=b.__shady.nextSibling);b===a.__shady.lastChild&&(a.__shady.lastChild=b.__shady.previousSibling);var d=b.__shady.previousSibling;var e=b.__shady.nextSibling;d&&(d.__shady=d.__shady||{},d.__shady.nextSibling=e);e&&(e.__shady=e.__shady||{},e.__shady.previousSibling=d);b.__shady.parentNode=b.__shady.previousSibling=b.__shady.nextSibling=void 0;void 0!==a.__shady.childNodes&&(a.__shady.childNodes= null}function pb(a,b,c){if(b===a)throw Error("Failed to execute 'appendChild' on 'Node': The new child element contains the parent.");if(c){var d=c.__shady&&c.__shady.parentNode;if(void 0!==d&&d!==a||void 0===d&&da(c)!==a)throw Error("Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.");}if(c===b)return b;b.parentNode&&qb(b.parentNode,b);d=ma(a);var e;if(e=d)a:{if(!b.__noInsertionPoint){var f;"slot"===b.localName?f=[b]:b.querySelectorAll&&
null);if(lb(a)){a.__shady.root.M();var f=!0}}Dc(b);c&&((e=a&&"slot"===a.localName)&&(f=!0),((d=c.gb(b))||e)&&c.M());f||(f=I(a)?a.host:a,(!a.__shady.root&&"slot"!==b.localName||f===aa(b))&&ka.call(f,b));Cc(a,null,b);return b}function Dc(a){if(a.__shady&&void 0!==a.__shady.sa)for(var b=a.childNodes,c=0,d=b.length,e;c<d&&(e=b[c]);c++)Dc(e);a.__shady&&(a.__shady.sa=void 0)}function Ac(a){var b=a;a&&"slot"===a.localName&&(b=(b=a.__shady&&a.__shady.V)&&b.length?b[0]:Ac(a.nextSibling));return b}function lb(a){return(a= (f=b.querySelectorAll("slot"));if(f&&f.length){e=f;break a}}e=void 0}(f=e)&&d.$a(f);d&&("slot"===a.localName||f)&&d.O();if(ca(a)){d=c;ec(a);a.__shady=a.__shady||{};void 0!==a.__shady.firstChild&&(a.__shady.childNodes=null);if(b.nodeType===Node.DOCUMENT_FRAGMENT_NODE){f=b.childNodes;for(e=0;e<f.length;e++)Fc(f[e],a,d);b.__shady=b.__shady||{};d=void 0!==b.__shady.firstChild?null:void 0;b.__shady.firstChild=b.__shady.lastChild=d;b.__shady.childNodes=d}else Fc(b,a,d);if(rb(a)){a.__shady.root.O();var h=
a&&a.__shady&&a.__shady.root)&&a.Aa()}function Ec(a,b){"slot"===b?(a=a.parentNode,lb(a)&&a.__shady.root.M()):"slot"===a.localName&&"name"===b&&(b=ia(a))&&(b.ib(a),b.M())}function Cc(a,b,c){if(a=a.__shady&&a.__shady.X)b&&a.addedNodes.push(b),c&&a.removedNodes.push(c),a.vb()}function Fc(a){if(a&&a.nodeType){a.__shady=a.__shady||{};var b=a.__shady.sa;void 0===b&&(I(a)?b=a:b=(b=a.parentNode)?Fc(b):a,document.documentElement.contains(a)&&(a.__shady.sa=b));return b}}function wa(a,b,c){var d=[];Gc(a.childNodes, !0}else a.__shady.root&&(h=!0)}h||(h=J(a)?a.host:a,c?(c=Gc(c),sb.call(h,b,c)):Hc.call(h,b));Ic(a,b);return b}function qb(a,b){if(b.parentNode!==a)throw Error("The node to be removed is not a child of this node: "+b);var c=ma(b);if(ca(a)){b.__shady=b.__shady||{};a.__shady=a.__shady||{};b===a.__shady.firstChild&&(a.__shady.firstChild=b.__shady.nextSibling);b===a.__shady.lastChild&&(a.__shady.lastChild=b.__shady.previousSibling);var d=b.__shady.previousSibling;var e=b.__shady.nextSibling;d&&(d.__shady=
b,c,d);return d}function Gc(a,b,c,d){for(var e=0,f=a.length,g;e<f&&(g=a[e]);e++){var h;if(h=g.nodeType===Node.ELEMENT_NODE){h=g;var m=b,H=c,k=d,l=m(h);l&&k.push(h);H&&H(l)?h=l:(Gc(h.childNodes,m,H,k),h=void 0)}if(h)break}}function Hc(a){a=a.getRootNode();I(a)&&a.Da()}function Ic(a,b,c){xa||(xa=window.ShadyCSS&&window.ShadyCSS.ScopingShim);xa&&"class"===b?xa.setElementClass(a,c):(Jc.call(a,b,c),Ec(a,b))}function Kc(a,b){if(a.ownerDocument!==document)return nb.call(document,a,b);var c=nb.call(document, d.__shady||{},d.__shady.nextSibling=e);e&&(e.__shady=e.__shady||{},e.__shady.previousSibling=d);b.__shady.parentNode=b.__shady.previousSibling=b.__shady.nextSibling=void 0;void 0!==a.__shady.childNodes&&(a.__shady.childNodes=null);if(rb(a)){a.__shady.root.O();var f=!0}}Jc(b);c&&((e=a&&"slot"===a.localName)&&(f=!0),((d=c.gb(b))||e)&&c.O());f||(f=J(a)?a.host:a,(!a.__shady.root&&"slot"!==b.localName||f===da(b))&&oa.call(f,b));Ic(a,null,b);return b}function Jc(a){if(a.__shady&&void 0!==a.__shady.va)for(var b=
a,!1);if(b){a=a.childNodes;b=0;for(var d;b<a.length;b++)d=Kc(a[b],!0),c.appendChild(d)}return c}function ob(a,b){var c=[],d=a;for(a=a===window?window:a.getRootNode();d;)c.push(d),d=d.assignedSlot?d.assignedSlot:d.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&d.host&&(b||d!==a)?d.host:d.parentNode;c[c.length-1]===document&&c.push(window);return c}function Lc(a,b){if(!I)return a;a=ob(a,!0);for(var c=0,d,e,f,g;c<b.length;c++)if(d=b[c],f=d===window?window:d.getRootNode(),f!==e&&(g=a.indexOf(f),e=f),!I(f)|| a.childNodes,c=0,d=b.length,e;c<d&&(e=b[c]);c++)Jc(e);a.__shady&&(a.__shady.va=void 0)}function Gc(a){var b=a;a&&"slot"===a.localName&&(b=(b=a.__shady&&a.__shady.W)&&b.length?b[0]:Gc(a.nextSibling));return b}function rb(a){return(a=a&&a.__shady&&a.__shady.root)&&a.Ca()}function Kc(a,b){"slot"===b?(a=a.parentNode,rb(a)&&a.__shady.root.O()):"slot"===a.localName&&"name"===b&&(b=ma(a))&&(b.ib(a),b.O())}function Ic(a,b,c){if(a=a.__shady&&a.__shady.Y)b&&a.addedNodes.push(b),c&&a.removedNodes.push(c),a.ub()}
-1<g)return d}function pb(a){function b(b,d){b=new a(b,d);b.ia=d&&!!d.composed;return b}ke(b,a);b.prototype=a.prototype;return b}function Mc(a,b,c){if(c=b.__handlers&&b.__handlers[a.type]&&b.__handlers[a.type][c])for(var d=0,e;(e=c[d])&&a.target!==a.relatedTarget&&(e.call(b,a),!a.Ua);d++);}function qe(a){var b=a.composedPath();Object.defineProperty(a,"currentTarget",{get:function(){return d},configurable:!0});for(var c=b.length-1;0<=c;c--){var d=b[c];Mc(a,d,"capture");if(a.ja)return}Object.defineProperty(a, function Lc(a){if(a&&a.nodeType){a.__shady=a.__shady||{};var b=a.__shady.va;void 0===b&&(J(a)?b=a:b=(b=a.parentNode)?Lc(b):a,pa.call(document.documentElement,a)&&(a.__shady.va=b));return b}}function Aa(a,b,c){var d=[];Mc(a.childNodes,b,c,d);return d}function Mc(a,b,c,d){for(var e=0,f=a.length,h;e<f&&(h=a[e]);e++){var k;if(k=h.nodeType===Node.ELEMENT_NODE){k=h;var m=b,g=c,n=d,l=m(k);l&&n.push(k);g&&g(l)?k=l:(Mc(k.childNodes,m,g,n),k=void 0)}if(k)break}}function Nc(a){a=a.getRootNode();J(a)&&a.Fa()}
"eventPhase",{get:function(){return Event.AT_TARGET}});var e;for(c=0;c<b.length;c++){d=b[c];var f=d.__shady&&d.__shady.root;if(0===c||f&&f===e)if(Mc(a,d,"bubble"),d!==window&&(e=d.getRootNode()),a.ja)break}}function Nc(a,b,c,d,e,f){for(var g=0;g<a.length;g++){var h=a[g],m=h.type,H=h.capture,k=h.once,l=h.passive;if(b===h.node&&c===m&&d===H&&e===k&&f===l)return g}return-1}function Oc(a,b,c){if(b){if("object"===typeof c){var d=!!c.capture;var e=!!c.once;var f=!!c.passive}else d=!!c,f=e=!1;var g=c&&c.ka|| function Oc(a,b,c){Ba||(Ba=window.ShadyCSS&&window.ShadyCSS.ScopingShim);Ba&&"class"===b?Ba.setElementClass(a,c):(Pc.call(a,b,c),Kc(a,b))}function Qc(a,b){if(a.ownerDocument!==document)return tb.call(document,a,b);var c=tb.call(document,a,!1);if(b){a=a.childNodes;b=0;for(var d;b<a.length;b++)d=Qc(a[b],!0),c.appendChild(d)}return c}function ub(a,b){var c=[],d=a;for(a=a===window?window:a.getRootNode();d;)c.push(d),d=d.assignedSlot?d.assignedSlot:d.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&d.host&&(b||
this,h=b[la];if(h){if(-1<Nc(h,g,a,d,e,f))return}else b[la]=[];h=function(d){e&&this.removeEventListener(a,b,c);d.__target||Pc(d);if(g!==this){var f=Object.getOwnPropertyDescriptor(d,"currentTarget");Object.defineProperty(d,"currentTarget",{get:function(){return g},configurable:!0})}if(d.composed||-1<d.composedPath().indexOf(g))if(d.target===d.relatedTarget)d.eventPhase===Event.BUBBLING_PHASE&&d.stopImmediatePropagation();else if(d.eventPhase===Event.CAPTURING_PHASE||d.bubbles||d.target===g){var h= d!==a)?d.host:d.parentNode;c[c.length-1]===document&&c.push(window);return c}function Rc(a,b){if(!J)return a;a=ub(a,!0);for(var c=0,d,e,f,h;c<b.length;c++)if(d=b[c],f=d===window?window:d.getRootNode(),f!==e&&(h=a.indexOf(f),e=f),!J(f)||-1<h)return d}function vb(a){function b(b,d){b=new a(b,d);b.ka=d&&!!d.composed;return b}ve(b,a);b.prototype=a.prototype;return b}function Sc(a,b,c){if(c=b.__handlers&&b.__handlers[a.type]&&b.__handlers[a.type][c])for(var d=0,e;(e=c[d])&&a.target!==a.relatedTarget&&
"object"===typeof b&&b.handleEvent?b.handleEvent(d):b.call(g,d);g!==this&&(f?(Object.defineProperty(d,"currentTarget",f),f=null):delete d.currentTarget);return h}};b[la].push({node:this,type:a,capture:d,once:e,passive:f,zb:h});qb[a]?(this.__handlers=this.__handlers||{},this.__handlers[a]=this.__handlers[a]||{capture:[],bubble:[]},this.__handlers[a][d?"capture":"bubble"].push(h)):(this instanceof Window?Qc:Rc).call(this,a,h,c)}}function Sc(a,b,c){if(b){if("object"===typeof c){var d=!!c.capture;var e= (e.call(b,a),!a.Ua);d++);}function Be(a){var b=a.composedPath();Object.defineProperty(a,"currentTarget",{get:function(){return d},configurable:!0});for(var c=b.length-1;0<=c;c--){var d=b[c];Sc(a,d,"capture");if(a.la)return}Object.defineProperty(a,"eventPhase",{get:function(){return Event.AT_TARGET}});var e;for(c=0;c<b.length;c++){d=b[c];var f=d.__shady&&d.__shady.root;if(0===c||f&&f===e)if(Sc(a,d,"bubble"),d!==window&&(e=d.getRootNode()),a.la)break}}function Tc(a,b,c,d,e,f){for(var h=0;h<a.length;h++){var k=
!!c.once;var f=!!c.passive}else d=!!c,f=e=!1;var g=c&&c.ka||this,h=void 0;var m=null;try{m=b[la]}catch(H){}m&&(e=Nc(m,g,a,d,e,f),-1<e&&(h=m.splice(e,1)[0].zb,m.length||(b[la]=void 0)));(this instanceof Window?Tc:Uc).call(this,a,h||b,c);h&&qb[a]&&this.__handlers&&this.__handlers[a]&&(a=this.__handlers[a][d?"capture":"bubble"],h=a.indexOf(h),-1<h&&a.splice(h,1))}}function re(){for(var a in qb)window.addEventListener(a,function(a){a.__target||(Pc(a),qe(a))},!0)}function Pc(a){a.__target=a.target;a.ya= a[h],m=k.type,g=k.capture,n=k.once,l=k.passive;if(b===k.node&&c===m&&d===g&&e===n&&f===l)return h}return-1}function Uc(a,b,c){if(b){if("object"===typeof c){var d=!!c.capture;var e=!!c.once;var f=!!c.passive}else d=!!c,f=e=!1;var h=c&&c.ma||this,k=b[qa];if(k){if(-1<Tc(k,h,a,d,e,f))return}else b[qa]=[];k=function(d){e&&this.removeEventListener(a,b,c);d.__target||Vc(d);if(h!==this){var f=Object.getOwnPropertyDescriptor(d,"currentTarget");Object.defineProperty(d,"currentTarget",{get:function(){return h},
a.relatedTarget;if(D.W){var b=Vc,c=Object.getPrototypeOf(a);if(!c.hasOwnProperty("__patchProto")){var d=Object.create(c);d.Bb=c;bb(d,b);c.__patchProto=d}a.__proto__=c.__patchProto}else bb(a,Vc)}function ma(a,b){return{index:a,Y:[],aa:b}}function se(a,b,c,d){var e=0,f=0,g=0,h=0,m=Math.min(b-e,d-f);if(0==e&&0==f)a:{for(g=0;g<m;g++)if(a[g]!==c[g])break a;g=m}if(b==a.length&&d==c.length){h=a.length;for(var k=c.length,l=0;l<m-g&&te(a[--h],c[--k]);)l++;h=l}e+=g;f+=g;b-=h;d-=h;if(0==b-e&&0==d-f)return[]; configurable:!0})}if(d.composed||-1<d.composedPath().indexOf(h))if(d.target===d.relatedTarget)d.eventPhase===Event.BUBBLING_PHASE&&d.stopImmediatePropagation();else if(d.eventPhase===Event.CAPTURING_PHASE||d.bubbles||d.target===h){var k="object"===typeof b&&b.handleEvent?b.handleEvent(d):b.call(h,d);h!==this&&(f?(Object.defineProperty(d,"currentTarget",f),f=null):delete d.currentTarget);return k}};b[qa].push({node:this,type:a,capture:d,once:e,passive:f,yb:k});wb[a]?(this.__handlers=this.__handlers||
if(e==b){for(b=ma(e,0);f<d;)b.Y.push(c[f++]);return[b]}if(f==d)return[ma(e,b-e)];m=e;g=f;d=d-g+1;h=b-m+1;b=Array(d);for(k=0;k<d;k++)b[k]=Array(h),b[k][0]=k;for(k=0;k<h;k++)b[0][k]=k;for(k=1;k<d;k++)for(l=1;l<h;l++)if(a[m+l-1]===c[g+k-1])b[k][l]=b[k-1][l-1];else{var n=b[k-1][l]+1,p=b[k][l-1]+1;b[k][l]=n<p?n:p}m=b.length-1;g=b[0].length-1;d=b[m][g];for(a=[];0<m||0<g;)0==m?(a.push(2),g--):0==g?(a.push(3),m--):(h=b[m-1][g-1],k=b[m-1][g],l=b[m][g-1],n=k<l?k<h?k:h:l<h?l:h,n==h?(h==d?a.push(0):(a.push(1), {},this.__handlers[a]=this.__handlers[a]||{capture:[],bubble:[]},this.__handlers[a][d?"capture":"bubble"].push(k)):(this instanceof Window?Wc:Xc).call(this,a,k,c)}}function Yc(a,b,c){if(b){if("object"===typeof c){var d=!!c.capture;var e=!!c.once;var f=!!c.passive}else d=!!c,f=e=!1;var h=c&&c.ma||this,k=void 0;var g=null;try{g=b[qa]}catch(q){}g&&(e=Tc(g,h,a,d,e,f),-1<e&&(k=g.splice(e,1)[0].yb,g.length||(b[qa]=void 0)));(this instanceof Window?Zc:$c).call(this,a,k||b,c);k&&wb[a]&&this.__handlers&&this.__handlers[a]&&
d=h),m--,g--):n==k?(a.push(3),m--,d=k):(a.push(2),g--,d=l));a.reverse();b=void 0;m=[];for(g=0;g<a.length;g++)switch(a[g]){case 0:b&&(m.push(b),b=void 0);e++;f++;break;case 1:b||(b=ma(e,0));b.aa++;e++;b.Y.push(c[f]);f++;break;case 2:b||(b=ma(e,0));b.aa++;e++;break;case 3:b||(b=ma(e,0)),b.Y.push(c[f]),f++}b&&m.push(b);return m}function te(a,b){return a===b}function Wc(a){var b=[];do b.unshift(a);while(a=a.parentNode);return b}function Xc(a){Hc(a);return a.__shady&&a.__shady.assignedSlot||null}function N(a, (a=this.__handlers[a][d?"capture":"bubble"],k=a.indexOf(k),-1<k&&a.splice(k,1))}}function Ce(){for(var a in wb)window.addEventListener(a,function(a){a.__target||(Vc(a),Be(a))},!0)}function Vc(a){a.__target=a.target;a.Aa=a.relatedTarget;if(G.X){var b=ad,c=Object.getPrototypeOf(a);if(!c.hasOwnProperty("__patchProto")){var d=Object.create(c);d.Ab=c;hb(d,b);c.__patchProto=d}a.__proto__=c.__patchProto}else hb(a,ad)}function ra(a,b){return{index:a,Z:[],ba:b}}function De(a,b,c,d){var e=0,f=0,h=0,k=0,g=Math.min(b-
b){for(var c=Object.getOwnPropertyNames(b),d=0;d<c.length;d++){var e=c[d],f=Object.getOwnPropertyDescriptor(b,e);f.value?a[e]=f.value:Object.defineProperty(a,e,f)}}function ue(){var a=window.customElements&&window.customElements.nativeHTMLElement||HTMLElement;N(window.Node.prototype,ve);N(window.Window.prototype,we);N(window.Text.prototype,xe);N(window.DocumentFragment.prototype,rb);N(window.Element.prototype,Yc);N(window.Document.prototype,Zc);window.HTMLSlotElement&&N(window.HTMLSlotElement.prototype, e,d-f);if(0==e&&0==f)a:{for(h=0;h<g;h++)if(a[h]!==c[h])break a;h=g}if(b==a.length&&d==c.length){k=a.length;for(var q=c.length,n=0;n<g-h&&Ee(a[--k],c[--q]);)n++;k=n}e+=h;f+=h;b-=k;d-=k;if(0==b-e&&0==d-f)return[];if(e==b){for(b=ra(e,0);f<d;)b.Z.push(c[f++]);return[b]}if(f==d)return[ra(e,b-e)];g=e;h=f;d=d-h+1;k=b-g+1;b=Array(d);for(q=0;q<d;q++)b[q]=Array(k),b[q][0]=q;for(q=0;q<k;q++)b[0][q]=q;for(q=1;q<d;q++)for(n=1;n<k;n++)if(a[g+n-1]===c[h+q-1])b[q][n]=b[q-1][n-1];else{var l=b[q-1][n]+1,p=b[q][n-1]+
$c);N(a.prototype,ye);D.W&&(R(window.Node.prototype),R(window.Text.prototype),R(window.DocumentFragment.prototype),R(window.Element.prototype),R(a.prototype),R(window.Document.prototype),window.HTMLSlotElement&&R(window.HTMLSlotElement.prototype))}function ad(a){var b=ze.has(a);a=/^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/.test(a);return!b&&a}function n(a){var b=a.isConnected;if(void 0!==b)return b;for(;a&&!(a.__CE_isImportDocument||a instanceof Document);)a=a.parentNode||(window.ShadowRoot&&a instanceof ShadowRoot? 1;b[q][n]=l<p?l:p}g=b.length-1;h=b[0].length-1;d=b[g][h];for(a=[];0<g||0<h;)0==g?(a.push(2),h--):0==h?(a.push(3),g--):(k=b[g-1][h-1],q=b[g-1][h],n=b[g][h-1],l=q<n?q<k?q:k:n<k?n:k,l==k?(k==d?a.push(0):(a.push(1),d=k),g--,h--):l==q?(a.push(3),g--,d=q):(a.push(2),h--,d=n));a.reverse();b=void 0;g=[];for(h=0;h<a.length;h++)switch(a[h]){case 0:b&&(g.push(b),b=void 0);e++;f++;break;case 1:b||(b=ra(e,0));b.ba++;e++;b.Z.push(c[f]);f++;break;case 2:b||(b=ra(e,0));b.ba++;e++;break;case 3:b||(b=ra(e,0)),b.Z.push(c[f]),
a.host:void 0);return!(!a||!(a.__CE_isImportDocument||a instanceof Document))}function sb(a,b){for(;b&&b!==a&&!b.nextSibling;)b=b.parentNode;return b&&b!==a?b.nextSibling:null}function P(a,b,c){c=c?c:new Set;for(var d=a;d;){if(d.nodeType===Node.ELEMENT_NODE){var e=d;b(e);var f=e.localName;if("link"===f&&"import"===e.getAttribute("rel")){d=e.import;if(d instanceof Node&&!c.has(d))for(c.add(d),d=d.firstChild;d;d=d.nextSibling)P(d,b,c);d=sb(a,e);continue}else if("template"===f){d=sb(a,e);continue}if(e= f++}b&&g.push(b);return g}function Ee(a,b){return a===b}function bd(a){var b=[];do b.unshift(a);while(a=a.parentNode);return b}function cd(a){Nc(a);return a.__shady&&a.__shady.assignedSlot||null}function P(a,b){for(var c=Object.getOwnPropertyNames(b),d=0;d<c.length;d++){var e=c[d],f=Object.getOwnPropertyDescriptor(b,e);f.value?a[e]=f.value:Object.defineProperty(a,e,f)}}function Fe(){var a=window.customElements&&window.customElements.nativeHTMLElement||HTMLElement;P(window.Node.prototype,Ge);P(window.Window.prototype,
e.__CE_shadowRoot)for(e=e.firstChild;e;e=e.nextSibling)P(e,b,c)}d=d.firstChild?d.firstChild:sb(a,d)}}function u(a,b,c){a[b]=c}function tb(a){a=a.replace(G.mb,"").replace(G.port,"");var b=bd,c=a,d=new Ka;d.start=0;d.end=c.length;for(var e=d,f=0,g=c.length;f<g;f++)if("{"===c[f]){e.rules||(e.rules=[]);var h=e,m=h.rules[h.rules.length-1]||null;e=new Ka;e.start=f+1;e.parent=h;e.previous=m;h.rules.push(e)}else"}"===c[f]&&(e.end=f+1,e=e.parent||d);return b(d,a)}function bd(a,b){var c=b.substring(a.start, He);P(window.Text.prototype,Ie);P(window.DocumentFragment.prototype,xb);P(window.Element.prototype,dd);P(window.Document.prototype,ed);window.HTMLSlotElement&&P(window.HTMLSlotElement.prototype,fd);P(a.prototype,Je);G.X&&(U(window.Node.prototype),U(window.Text.prototype),U(window.DocumentFragment.prototype),U(window.Element.prototype),U(a.prototype),U(window.Document.prototype),window.HTMLSlotElement&&U(window.HTMLSlotElement.prototype))}function gd(a){var b=Ke.has(a);a=/^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/.test(a);
a.end-1);a.parsedCssText=a.cssText=c.trim();a.parent&&(c=b.substring(a.previous?a.previous.end:a.parent.start,a.start-1),c=Ae(c),c=c.replace(G.Ja," "),c=c.substring(c.lastIndexOf(";")+1),c=a.parsedSelector=a.selector=c.trim(),a.atRule=0===c.indexOf("@"),a.atRule?0===c.indexOf("@media")?a.type=L.MEDIA_RULE:c.match(G.rb)&&(a.type=L.ha,a.keyframesName=a.selector.split(G.Ja).pop()):a.type=0===c.indexOf("--")?L.ua:L.STYLE_RULE);if(c=a.rules)for(var d=0,e=c.length,f;d<e&&(f=c[d]);d++)bd(f,b);return a}function Ae(a){return a.replace(/\\([0-9a-f]{1,6})\s/gi, return!b&&a}function u(a){var b=a.isConnected;if(void 0!==b)return b;for(;a&&!(a.__CE_isImportDocument||a instanceof Document);)a=a.parentNode||(window.ShadowRoot&&a instanceof ShadowRoot?a.host:void 0);return!(!a||!(a.__CE_isImportDocument||a instanceof Document))}function yb(a,b){for(;b&&b!==a&&!b.nextSibling;)b=b.parentNode;return b&&b!==a?b.nextSibling:null}function S(a,b,c){c=c?c:new Set;for(var d=a;d;){if(d.nodeType===Node.ELEMENT_NODE){var e=d;b(e);var f=e.localName;if("link"===f&&"import"===
function(a,c){a=c;for(c=6-a.length;c--;)a="0"+a;return"\\"+a})}function cd(a,b,c){c=void 0===c?"":c;var d="";if(a.cssText||a.rules){var e=a.rules,f;if(f=e)f=e[0],f=!(f&&f.selector&&0===f.selector.indexOf("--"));if(f){f=0;for(var g=e.length,h;f<g&&(h=e[f]);f++)d=cd(h,b,d)}else b?b=a.cssText:(b=a.cssText,b=b.replace(G.Ea,"").replace(G.Ia,""),b=b.replace(G.sb,"").replace(G.xb,"")),(d=b.trim())&&(d=" "+d+"\n")}d&&(a.selector&&(c+=a.selector+" {\n"),c+=d,a.selector&&(c+="}\n\n"));return c}function dd(a){v= e.getAttribute("rel")){d=e.import;if(d instanceof Node&&!c.has(d))for(c.add(d),d=d.firstChild;d;d=d.nextSibling)S(d,b,c);d=yb(a,e);continue}else if("template"===f){d=yb(a,e);continue}if(e=e.__CE_shadowRoot)for(e=e.firstChild;e;e=e.nextSibling)S(e,b,c)}d=d.firstChild?d.firstChild:yb(a,d)}}function x(a,b,c){a[b]=c}function zb(a){a=a.replace(I.lb,"").replace(I.port,"");var b=hd,c=a,d=new Pa;d.start=0;d.end=c.length;for(var e=d,f=0,h=c.length;f<h;f++)if("{"===c[f]){e.rules||(e.rules=[]);var k=e,g=k.rules[k.rules.length-
a&&a.shimcssproperties?!1:q||!(navigator.userAgent.match(/AppleWebKit\/601|Edge\/15/)||!window.CSS||!CSS.supports||!CSS.supports("box-shadow","0 0 0 var(--foo)"))}function ba(a,b){if(!a)return"";"string"===typeof a&&(a=tb(a));b&&ca(a,b);return cd(a,v)}function ya(a){!a.__cssRules&&a.textContent&&(a.__cssRules=tb(a.textContent));return a.__cssRules||null}function ed(a){return!!a.parent&&a.parent.type===L.ha}function ca(a,b,c,d){if(a){var e=!1,f=a.type;if(d&&f===L.MEDIA_RULE){var g=a.selector.match(Be); 1]||null;e=new Pa;e.start=f+1;e.parent=k;e.previous=g;k.rules.push(e)}else"}"===c[f]&&(e.end=f+1,e=e.parent||d);return b(d,a)}function hd(a,b){var c=b.substring(a.start,a.end-1);a.parsedCssText=a.cssText=c.trim();a.parent&&(c=b.substring(a.previous?a.previous.end:a.parent.start,a.start-1),c=Le(c),c=c.replace(I.La," "),c=c.substring(c.lastIndexOf(";")+1),c=a.parsedSelector=a.selector=c.trim(),a.atRule=0===c.indexOf("@"),a.atRule?0===c.indexOf("@media")?a.type=M.MEDIA_RULE:c.match(I.qb)&&(a.type=M.ja,
g&&(window.matchMedia(g[1]).matches||(e=!0))}f===L.STYLE_RULE?b(a):c&&f===L.ha?c(a):f===L.ua&&(e=!0);if((a=a.rules)&&!e){e=0;f=a.length;for(var h;e<f&&(h=a[e]);e++)ca(h,b,c,d)}}}function ub(a,b,c,d){var e=document.createElement("style");b&&e.setAttribute("scope",b);e.textContent=a;fd(e,c,d);return e}function fd(a,b,c){b=b||document.head;b.insertBefore(a,c&&c.nextSibling||b.firstChild);S?a.compareDocumentPosition(S)===Node.DOCUMENT_POSITION_PRECEDING&&(S=a):S=a}function gd(a,b){var c=a.indexOf("var("); a.keyframesName=a.selector.split(I.La).pop()):a.type=0===c.indexOf("--")?M.wa:M.STYLE_RULE);if(c=a.rules)for(var d=0,e=c.length,f;d<e&&(f=c[d]);d++)hd(f,b);return a}function Le(a){return a.replace(/\\([0-9a-f]{1,6})\s/gi,function(a,c){a=c;for(c=6-a.length;c--;)a="0"+a;return"\\"+a})}function id(a,b,c){c=void 0===c?"":c;var d="";if(a.cssText||a.rules){var e=a.rules,f;if(f=e)f=e[0],f=!(f&&f.selector&&0===f.selector.indexOf("--"));if(f){f=0;for(var h=e.length,k;f<h&&(k=e[f]);f++)d=id(k,b,d)}else b?b=
if(-1===c)return b(a,"","","");a:{var d=0;var e=c+3;for(var f=a.length;e<f;e++)if("("===a[e])d++;else if(")"===a[e]&&0===--d)break a;e=-1}d=a.substring(c+4,e);c=a.substring(0,c);a=gd(a.substring(e+1),b);e=d.indexOf(",");return-1===e?b(c,d.trim(),"",a):b(c,d.substring(0,e).trim(),d.substring(e+1).trim(),a)}function za(a,b){q?a.setAttribute("class",b):window.ShadyDOM.nativeMethods.setAttribute.call(a,"class",b)}function T(a){var b=a.localName,c="";b?-1<b.indexOf("-")||(c=b,b=a.getAttribute&&a.getAttribute("is")|| a.cssText:(b=a.cssText,b=b.replace(I.Ga,"").replace(I.Ka,""),b=b.replace(I.rb,"").replace(I.wb,"")),(d=b.trim())&&(d=" "+d+"\n")}d&&(a.selector&&(c+=a.selector+" {\n"),c+=d,a.selector&&(c+="}\n\n"));return c}function jd(a){A=a&&a.shimcssproperties?!1:z||!(navigator.userAgent.match(/AppleWebKit\/601|Edge\/15/)||!window.CSS||!CSS.supports||!CSS.supports("box-shadow","0 0 0 var(--foo)"))}function ea(a,b){if(!a)return"";"string"===typeof a&&(a=zb(a));b&&fa(a,b);return id(a,A)}function Ca(a){!a.__cssRules&&
""):(b=a.is,c=a.extends);return{is:b,Z:c}}function hd(a){for(var b=0;b<a.length;b++){var c=a[b];if(c.target!==document.documentElement&&c.target!==document.head)for(var d=0;d<c.addedNodes.length;d++){var e=c.addedNodes[d];if(e.nodeType===Node.ELEMENT_NODE){var f=e.getRootNode();var g=e;var h=[];g.classList?h=Array.from(g.classList):g instanceof window.SVGElement&&g.hasAttribute("class")&&(h=g.getAttribute("class").split(/\s+/));g=h;h=g.indexOf(w.c);(g=-1<h?g[h+1]:"")&&f===e.ownerDocument?w.a(e,g, a.textContent&&(a.__cssRules=zb(a.textContent));return a.__cssRules||null}function kd(a){return!!a.parent&&a.parent.type===M.ja}function fa(a,b,c,d){if(a){var e=!1,f=a.type;if(d&&f===M.MEDIA_RULE){var h=a.selector.match(Me);h&&(window.matchMedia(h[1]).matches||(e=!0))}f===M.STYLE_RULE?b(a):c&&f===M.ja?c(a):f===M.wa&&(e=!0);if((a=a.rules)&&!e){e=0;f=a.length;for(var k;e<f&&(k=a[e]);e++)fa(k,b,c,d)}}}function Ab(a,b,c,d){var e=document.createElement("style");b&&e.setAttribute("scope",b);e.textContent=
!0):f.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&(f=f.host)&&(f=T(f).is,g!==f&&(g&&w.a(e,g,!0),w.a(e,f)))}}}}function Ce(a){if(a=Aa[a])a._applyShimCurrentVersion=a._applyShimCurrentVersion||0,a._applyShimValidatingVersion=a._applyShimValidatingVersion||0,a._applyShimNextVersion=(a._applyShimNextVersion||0)+1}function id(a){return a._applyShimCurrentVersion===a._applyShimNextVersion}function De(a){a._applyShimValidatingVersion=a._applyShimNextVersion;a.b||(a.b=!0,Ee.then(function(){a._applyShimCurrentVersion= a;ld(e,c,d);return e}function ld(a,b,c){b=b||document.head;b.insertBefore(a,c&&c.nextSibling||b.firstChild);V?a.compareDocumentPosition(V)===Node.DOCUMENT_POSITION_PRECEDING&&(V=a):V=a}function md(a,b){var c=a.indexOf("var(");if(-1===c)return b(a,"","","");a:{var d=0;var e=c+3;for(var f=a.length;e<f;e++)if("("===a[e])d++;else if(")"===a[e]&&0===--d)break a;e=-1}d=a.substring(c+4,e);c=a.substring(0,c);a=md(a.substring(e+1),b);e=d.indexOf(",");return-1===e?b(c,d.trim(),"",a):b(c,d.substring(0,e).trim(),
a._applyShimNextVersion;a.b=!1}))}function Kb(a){requestAnimationFrame(function(){jd?jd(a):(vb||(vb=new Promise(function(a){wb=a}),"complete"===document.readyState?wb():document.addEventListener("readystatechange",function(){"complete"===document.readyState&&wb()})),vb.then(function(){a&&a()}))})}(function(){if(!function(){var a=document.createEvent("Event");a.initEvent("foo",!0,!0);a.preventDefault();return a.defaultPrevented}()){var a=Event.prototype.preventDefault;Event.prototype.preventDefault= d.substring(e+1).trim(),a)}function Da(a,b){z?a.setAttribute("class",b):window.ShadyDOM.nativeMethods.setAttribute.call(a,"class",b)}function W(a){var b=a.localName,c="";b?-1<b.indexOf("-")||(c=b,b=a.getAttribute&&a.getAttribute("is")||""):(b=a.is,c=a.extends);return{is:b,$:c}}function nd(a){for(var b=0;b<a.length;b++){var c=a[b];if(c.target!==document.documentElement&&c.target!==document.head)for(var d=0;d<c.addedNodes.length;d++){var e=c.addedNodes[d];if(e.nodeType===Node.ELEMENT_NODE){var f=e.getRootNode();
function(){this.cancelable&&(a.call(this),Object.defineProperty(this,"defaultPrevented",{get:function(){return!0},configurable:!0}))}}var b=/Trident/.test(navigator.userAgent);if(!window.CustomEvent||b&&"function"!==typeof window.CustomEvent)window.CustomEvent=function(a,b){b=b||{};var c=document.createEvent("CustomEvent");c.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail);return c},window.CustomEvent.prototype=window.Event.prototype;if(!window.Event||b&&"function"!==typeof window.Event){var c= var h=e;var k=[];h.classList?k=Array.from(h.classList):h instanceof window.SVGElement&&h.hasAttribute("class")&&(k=h.getAttribute("class").split(/\s+/));h=k;k=h.indexOf(r.a);if((h=-1<k?h[k+1]:"")&&f===e.ownerDocument)r.b(e,h,!0);else if(f.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&(f=f.host))if(f=W(f).is,h===f)for(e=window.ShadyDOM.nativeMethods.querySelectorAll.call(e,":not(."+r.a+")"),f=0;f<e.length;f++)r.h(e[f],h);else h&&r.b(e,h,!0),r.b(e,f)}}}}function Ne(a){if(a=Ea[a])a._applyShimCurrentVersion=
window.Event;window.Event=function(a,b){b=b||{};var c=document.createEvent("Event");c.initEvent(a,!!b.bubbles,!!b.cancelable);return c};if(c)for(var d in c)window.Event[d]=c[d];window.Event.prototype=c.prototype}if(!window.MouseEvent||b&&"function"!==typeof window.MouseEvent){b=window.MouseEvent;window.MouseEvent=function(a,b){b=b||{};var c=document.createEvent("MouseEvent");c.initMouseEvent(a,!!b.bubbles,!!b.cancelable,b.view||window,b.detail,b.screenX,b.screenY,b.clientX,b.clientY,b.ctrlKey,b.altKey, a._applyShimCurrentVersion||0,a._applyShimValidatingVersion=a._applyShimValidatingVersion||0,a._applyShimNextVersion=(a._applyShimNextVersion||0)+1}function od(a){return a._applyShimCurrentVersion===a._applyShimNextVersion}function Oe(a){a._applyShimValidatingVersion=a._applyShimNextVersion;a.b||(a.b=!0,Pe.then(function(){a._applyShimCurrentVersion=a._applyShimNextVersion;a.b=!1}))}function Rb(a){requestAnimationFrame(function(){pd?pd(a):(Bb||(Bb=new Promise(function(a){Cb=a}),"complete"===document.readyState?
b.shiftKey,b.metaKey,b.button,b.relatedTarget);return c};if(b)for(d in b)window.MouseEvent[d]=b[d];window.MouseEvent.prototype=b.prototype}Array.from||(Array.from=function(a){return[].slice.call(a)});Object.assign||(Object.assign=function(a,b){for(var c=[].slice.call(arguments,1),d=0,e;d<c.length;d++)if(e=c[d])for(var f=a,k=e,l=Object.getOwnPropertyNames(k),n=0;n<l.length;n++)e=l[n],f[e]=k[e];return a})})(window.WebComponents);(function(){function a(){}var b="undefined"===typeof HTMLTemplateElement; Cb():document.addEventListener("readystatechange",function(){"complete"===document.readyState&&Cb()})),Bb.then(function(){a&&a()}))})}(function(){if(!function(){var a=document.createEvent("Event");a.initEvent("foo",!0,!0);a.preventDefault();return a.defaultPrevented}()){var a=Event.prototype.preventDefault;Event.prototype.preventDefault=function(){this.cancelable&&(a.call(this),Object.defineProperty(this,"defaultPrevented",{get:function(){return!0},configurable:!0}))}}var b=/Trident/.test(navigator.userAgent);
/Trident/.test(navigator.userAgent)&&function(){var a=Document.prototype.importNode;Document.prototype.importNode=function(){var b=a.apply(this,arguments);if(b.nodeType===Node.DOCUMENT_FRAGMENT_NODE){var c=this.createDocumentFragment();c.appendChild(b);return c}return b}}();var c=Node.prototype.cloneNode,d=Document.prototype.createElement,e=Document.prototype.importNode,f=function(){if(!b){var a=document.createElement("template"),c=document.createElement("template");c.content.appendChild(document.createElement("div")); if(!window.CustomEvent||b&&"function"!==typeof window.CustomEvent)window.CustomEvent=function(a,b){b=b||{};var c=document.createEvent("CustomEvent");c.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail);return c},window.CustomEvent.prototype=window.Event.prototype;if(!window.Event||b&&"function"!==typeof window.Event){var c=window.Event;window.Event=function(a,b){b=b||{};var c=document.createEvent("Event");c.initEvent(a,!!b.bubbles,!!b.cancelable);return c};if(c)for(var d in c)window.Event[d]=
a.content.appendChild(c);a=a.cloneNode(!0);return 0===a.content.childNodes.length||0===a.content.firstChild.content.childNodes.length||!(document.createDocumentFragment().cloneNode()instanceof DocumentFragment)}}();if(b){var g=function(a){switch(a){case "&":return"&amp;";case "<":return"&lt;";case ">":return"&gt;";case "\u00a0":return"&nbsp;"}},h=function(b){Object.defineProperty(b,"innerHTML",{get:function(){for(var a="",b=this.content.firstChild;b;b=b.nextSibling)a+=b.outerHTML||b.data.replace(r, c[d];window.Event.prototype=c.prototype}if(!window.MouseEvent||b&&"function"!==typeof window.MouseEvent){b=window.MouseEvent;window.MouseEvent=function(a,b){b=b||{};var c=document.createEvent("MouseEvent");c.initMouseEvent(a,!!b.bubbles,!!b.cancelable,b.view||window,b.detail,b.screenX,b.screenY,b.clientX,b.clientY,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,b.button,b.relatedTarget);return c};if(b)for(d in b)window.MouseEvent[d]=b[d];window.MouseEvent.prototype=b.prototype}Array.from||(Array.from=function(a){return[].slice.call(a)});
g);return a},set:function(b){m.body.innerHTML=b;for(a.b(m);this.content.firstChild;)this.content.removeChild(this.content.firstChild);for(;m.body.firstChild;)this.content.appendChild(m.body.firstChild)},configurable:!0})},m=document.implementation.createHTMLDocument("template"),k=!0,l=document.createElement("style");l.textContent="template{display:none;}";var n=document.head;n.insertBefore(l,n.firstElementChild);a.prototype=Object.create(HTMLElement.prototype);var p=!document.createElement("div").hasOwnProperty("innerHTML"); Object.assign||(Object.assign=function(a,b){for(var c=[].slice.call(arguments,1),d=0,e;d<c.length;d++)if(e=c[d])for(var f=a,g=e,l=Object.getOwnPropertyNames(g),p=0;p<l.length;p++)e=l[p],f[e]=g[e];return a})})(window.WebComponents);(function(){function a(){}var b="undefined"===typeof HTMLTemplateElement;/Trident/.test(navigator.userAgent)&&function(){var a=Document.prototype.importNode;Document.prototype.importNode=function(){var b=a.apply(this,arguments);if(b.nodeType===Node.DOCUMENT_FRAGMENT_NODE){var c=
a.O=function(b){if(!b.content){b.content=m.createDocumentFragment();for(var c;c=b.firstChild;)b.content.appendChild(c);if(p)b.__proto__=a.prototype;else if(b.cloneNode=function(b){return a.a(this,b)},k)try{h(b)}catch(df){k=!1}a.b(b.content)}};h(a.prototype);a.b=function(b){b=b.querySelectorAll("template");for(var c=0,d=b.length,e;c<d&&(e=b[c]);c++)a.O(e)};document.addEventListener("DOMContentLoaded",function(){a.b(document)});Document.prototype.createElement=function(){var b=d.apply(this,arguments); this.createDocumentFragment();c.appendChild(b);return c}return b}}();var c=Node.prototype.cloneNode,d=Document.prototype.createElement,e=Document.prototype.importNode,f=function(){if(!b){var a=document.createElement("template"),c=document.createElement("template");c.content.appendChild(document.createElement("div"));a.content.appendChild(c);a=a.cloneNode(!0);return 0===a.content.childNodes.length||0===a.content.firstChild.content.childNodes.length||!(document.createDocumentFragment().cloneNode()instanceof
"template"===b.localName&&a.O(b);return b};var r=/[&\u00A0<>]/g}if(b||f)a.a=function(a,b){var d=c.call(a,!1);this.O&&this.O(d);b&&(d.content.appendChild(c.call(a.content,!0)),this.qa(d.content,a.content));return d},a.prototype.cloneNode=function(b){return a.a(this,b)},a.qa=function(a,b){if(b.querySelectorAll){b=b.querySelectorAll("template");a=a.querySelectorAll("template");for(var c=0,d=a.length,e,f;c<d;c++)f=b[c],e=a[c],this.O&&this.O(f),e.parentNode.replaceChild(f.cloneNode(!0),e)}},Node.prototype.cloneNode= DocumentFragment)}}();if(b){var h=function(a){switch(a){case "&":return"&amp;";case "<":return"&lt;";case ">":return"&gt;";case "\u00a0":return"&nbsp;"}},k=function(b){Object.defineProperty(b,"innerHTML",{get:function(){for(var a="",b=this.content.firstChild;b;b=b.nextSibling)a+=b.outerHTML||b.data.replace(u,h);return a},set:function(b){g.body.innerHTML=b;for(a.b(g);this.content.firstChild;)this.content.removeChild(this.content.firstChild);for(;g.body.firstChild;)this.content.appendChild(g.body.firstChild)},
function(b){if(this instanceof DocumentFragment)if(b)var d=this.ownerDocument.importNode(this,!0);else return this.ownerDocument.createDocumentFragment();else d=c.call(this,b);b&&a.qa(d,this);return d},Document.prototype.importNode=function(b,c){if("template"===b.localName)return a.a(b,c);var d=e.call(this,b,c);c&&a.qa(d,b);return d},f&&(window.HTMLTemplateElement.prototype.cloneNode=function(b){return a.a(this,b)});b&&(window.HTMLTemplateElement=a)})();var xb;Array.isArray?xb=Array.isArray:xb=function(a){return"[object Array]"=== configurable:!0})},g=document.implementation.createHTMLDocument("template"),q=!0,l=document.createElement("style");l.textContent="template{display:none;}";var p=document.head;p.insertBefore(l,p.firstElementChild);a.prototype=Object.create(HTMLElement.prototype);var t=!document.createElement("div").hasOwnProperty("innerHTML");a.R=function(b){if(!b.content){b.content=g.createDocumentFragment();for(var c;c=b.firstChild;)b.content.appendChild(c);if(t)b.__proto__=a.prototype;else if(b.cloneNode=function(b){return a.a(this,
Object.prototype.toString.call(a)};var ic=xb,W=0,Va,Ua,kd="undefined"!==typeof window?window:void 0,ld=kd||{},bc=ld.MutationObserver||ld.WebKitMutationObserver,Fe="undefined"!==typeof Uint8ClampedArray&&"undefined"!==typeof importScripts&&"undefined"!==typeof MessageChannel,V=Array(1E3);var $d="undefined"===typeof self&&"undefined"!==typeof process&&"[object process]"==={}.toString.call(process)?ae():bc?ce():Fe?de():kd||"function"!==typeof require?Wa():ee();var ua=Math.random().toString(36).substring(16), b)},q)try{k(b)}catch(rf){q=!1}a.b(b.content)}};k(a.prototype);a.b=function(b){b=b.querySelectorAll("template");for(var c=0,d=b.length,e;c<d&&(e=b[c]);c++)a.R(e)};document.addEventListener("DOMContentLoaded",function(){a.b(document)});Document.prototype.createElement=function(){var b=d.apply(this,arguments);"template"===b.localName&&a.R(b);return b};var u=/[&\u00A0<>]/g}if(b||f)a.a=function(a,b){var d=c.call(a,!1);this.R&&this.R(d);b&&(d.content.appendChild(c.call(a.content,!0)),this.ta(d.content,
fa=new gc,ab=new gc,hc=0;ha.prototype.cb=function(a){for(var b=0;void 0===this.o&&b<a.length;b++)this.bb(a[b],b)};ha.prototype.bb=function(a,b){var c=this.eb,d=c.resolve;d===Za?(d=ec(a),d===Xa&&void 0!==a.o?this.na(a.o,b,a.m):"function"!==typeof d?(this.$--,this.m[b]=a):c===y?(c=new c(Y),fc(c,a,d),this.oa(c,b)):this.oa(new c(function(b){return b(a)}),b)):this.oa(d(a),b)};ha.prototype.na=function(a,b,c){var d=this.J;void 0===d.o&&(this.$--,2===a?A(d,c):this.m[b]=c);0===this.$&&K(d,this.m)};ha.prototype.oa= a.content));return d},a.prototype.cloneNode=function(b){return a.a(this,b)},a.ta=function(a,b){if(b.querySelectorAll){b=b.querySelectorAll("template");a=a.querySelectorAll("template");for(var c=0,d=a.length,e,f;c<d;c++)f=b[c],e=a[c],this.R&&this.R(f),e.parentNode.replaceChild(f.cloneNode(!0),e)}},Node.prototype.cloneNode=function(b){if(this instanceof DocumentFragment)if(b)var d=this.ownerDocument.importNode(this,!0);else return this.ownerDocument.createDocumentFragment();else d=c.call(this,b);b&&
function(a,b){var c=this;Ya(a,void 0,function(a){return c.na(1,b,a)},function(a){return c.na(2,b,a)})};y.g=function(a){return(new ha(this,a)).J};y.h=function(a){var b=this;return ic(a)?new b(function(c,d){for(var e=a.length,f=0;f<e;f++)b.resolve(a[f]).then(c,d)}):new b(function(a,b){return b(new TypeError("You must pass an array to race."))})};y.resolve=Za;y.i=function(a){var b=new this(Y);A(b,a);return b};y.f=function(a){Ua=a};y.c=function(a){Q=a};y.b=Q;y.prototype={constructor:y,then:Xa};y.a=function(){if("undefined"!== a.ta(d,this);return d},Document.prototype.importNode=function(b,c){if("template"===b.localName)return a.a(b,c);var d=e.call(this,b,c);c&&a.ta(d,b);return d},f&&(window.HTMLTemplateElement.prototype.cloneNode=function(b){return a.a(this,b)});b&&(window.HTMLTemplateElement=a)})();var Db;Array.isArray?Db=Array.isArray:Db=function(a){return"[object Array]"===Object.prototype.toString.call(a)};var nc=Db,Z=0,ab,$a,qd="undefined"!==typeof window?window:void 0,rd=qd||{},gc=rd.MutationObserver||rd.WebKitMutationObserver,
typeof global)var a=global;else if("undefined"!==typeof self)a=self;else try{a=Function("return this")()}catch(d){throw Error("polyfill failed because global object is unavailable in this environment");}var b=a.Promise;if(b){var c=null;try{c=Object.prototype.toString.call(b.resolve())}catch(d){}if("[object Promise]"===c&&!b.Eb)return}a.Promise=y};y.Promise=y;y.a();(function(a){function b(a,b){if("function"===typeof window.CustomEvent)return new CustomEvent(a,b);var c=document.createEvent("CustomEvent"); Qe="undefined"!==typeof Uint8ClampedArray&&"undefined"!==typeof importScripts&&"undefined"!==typeof MessageChannel,Y=Array(1E3);var ke="undefined"===typeof self&&"undefined"!==typeof process&&"[object process]"==={}.toString.call(process)?le():gc?ne():Qe?oe():qd||"function"!==typeof require?bb():pe();var ya=Math.random().toString(36).substring(16),ka=new lc,gb=new lc,mc=0;la.prototype.cb=function(a){for(var b=0;void 0===this.o&&b<a.length;b++)this.bb(a[b],b)};la.prototype.bb=function(a,b){var c=this.eb,
c.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail);return c}function c(a){if(l)return a.ownerDocument!==document?a.ownerDocument:null;var b=a.__importDoc;if(!b&&a.parentNode){b=a.parentNode;if("function"===typeof b.closest)b=b.closest("link[rel=import]");else for(;!h(b)&&(b=b.parentNode););a.__importDoc=b}return b}function d(a){var b=document.querySelectorAll("link[rel=import]:not(import-dependency)"),c=b.length;c?k(b,function(b){return g(b,function(){0===--c&&a()})}):a()}function e(a){function b(){"loading"!== d=c.resolve;d===eb?(d=jc(a),d===cb&&void 0!==a.o?this.pa(a.o,b,a.m):"function"!==typeof d?(this.aa--,this.m[b]=a):c===D?(c=new c(ba),kc(c,a,d),this.qa(c,b)):this.qa(new c(function(b){return b(a)}),b)):this.qa(d(a),b)};la.prototype.pa=function(a,b,c){var d=this.L;void 0===d.o&&(this.aa--,2===a?C(d,c):this.m[b]=c);0===this.aa&&L(d,this.m)};la.prototype.qa=function(a,b){var c=this;db(a,void 0,function(a){return c.pa(1,b,a)},function(a){return c.pa(2,b,a)})};D.all=function(a){return(new la(this,a)).L};
document.readyState&&document.body&&(document.removeEventListener("readystatechange",b),a())}document.addEventListener("readystatechange",b);b()}function f(a){e(function(){return d(function(){return a&&a()})})}function g(a,b){if(a.__loaded)b&&b();else if("script"===a.localName&&!a.src||"style"===a.localName&&!a.firstChild)a.__loaded=!0,b&&b();else{var c=function(d){a.removeEventListener(d.type,c);a.__loaded=!0;b&&b()};a.addEventListener("load",c);x&&"style"===a.localName||a.addEventListener("error", D.race=function(a){var b=this;return nc(a)?new b(function(c,d){for(var e=a.length,f=0;f<e;f++)b.resolve(a[f]).then(c,d)}):new b(function(a,b){return b(new TypeError("You must pass an array to race."))})};D.resolve=eb;D.reject=function(a){var b=new this(ba);C(b,a);return b};D.Fb=function(a){$a=a};D.Eb=function(a){T=a};D.Bb=T;D.prototype={constructor:D,then:cb,a:function(a){return this.then(null,a)}};window.Promise||(window.Promise=D,D.prototype["catch"]=D.prototype.a);(function(a){function b(a,b){if("function"===
c)}}function h(a){return a.nodeType===Node.ELEMENT_NODE&&"link"===a.localName&&"import"===a.rel}function m(){var a=this;this.a={};this.b=0;this.f=new MutationObserver(function(b){return a.l(b)});this.f.observe(document.head,{childList:!0,subtree:!0});this.c(document)}function k(a,b,c){var d=a?a.length:0,e=c?-1:1;for(c=c?d-1:0;c<d&&0<=c;c+=e)b(a[c],c)}var l="import"in document.createElement("link"),n=null;!1==="currentScript"in document&&Object.defineProperty(document,"currentScript",{get:function(){return n|| typeof window.CustomEvent)return new CustomEvent(a,b);var c=document.createEvent("CustomEvent");c.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail);return c}function c(a){if(n)return a.ownerDocument!==document?a.ownerDocument:null;var b=a.__importDoc;if(!b&&a.parentNode){b=a.parentNode;if("function"===typeof b.closest)b=b.closest("link[rel=import]");else for(;!g(b)&&(b=b.parentNode););a.__importDoc=b}return b}function d(a){var b=document.querySelectorAll("link[rel=import]:not([import-dependency])"),
("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null)},configurable:!0});var p=/(^\/)|(^#)|(^[\w-\d]*:)/,r=/(url\()([^)]*)(\))/g,t=/(@import[\s]+(?!url\())([^;]*)(;)/g,w=/(<link[^>]*)(rel=['|"]?stylesheet['|"]?[^>]*>)/g,q={nb:function(a,b){a.href&&a.setAttribute("href",q.ta(a.getAttribute("href"),b));a.src&&a.setAttribute("src",q.ta(a.getAttribute("src"),b));if("style"===a.localName){var c=q.La(a.textContent,b,r);a.textContent=q.La(c,b,t)}},La:function(a,b,c){return a.replace(c, c=b.length;c?l(b,function(b){return h(b,function(){0===--c&&a()})}):a()}function e(a){function b(){"loading"!==document.readyState&&document.body&&(document.removeEventListener("readystatechange",b),a())}document.addEventListener("readystatechange",b);b()}function f(a){e(function(){return d(function(){return a&&a()})})}function h(a,b){if(a.__loaded)b&&b();else if("script"===a.localName&&!a.src||"style"===a.localName&&!a.firstChild)a.__loaded=!0,b&&b();else{var c=function(d){a.removeEventListener(d.type,
function(a,c,d,e){a=d.replace(/["']/g,"");b&&(a=q.Ma(a,b));return c+"'"+a+"'"+e})},ta:function(a,b){return a&&p.test(a)?a:q.Ma(a,b)},Ma:function(a,b){if(void 0===q.la){q.la=!1;try{var c=new URL("b","http://a");c.pathname="c%20d";q.la="http://a/c%20d"===c.href}catch(ef){}}if(q.la)return(new URL(a,b)).href;c=q.Za;c||(c=document.implementation.createHTMLDocument("temp"),q.Za=c,c.wa=c.createElement("base"),c.head.appendChild(c.wa),c.va=c.createElement("a"));c.wa.href=b;c.va.href=a;return c.va.href||a}}, c);a.__loaded=!0;b&&b()};a.addEventListener("load",c);z&&"style"===a.localName||a.addEventListener("error",c)}}function g(a){return a.nodeType===Node.ELEMENT_NODE&&"link"===a.localName&&"import"===a.rel}function m(){var a=this;this.a={};this.b=0;this.f=new MutationObserver(function(b){return a.l(b)});this.f.observe(document.head,{childList:!0,subtree:!0});this.c(document)}function l(a,b,c){var d=a?a.length:0,e=c?-1:1;for(c=c?d-1:0;c<d&&0<=c;c+=e)b(a[c],c)}var n="import"in document.createElement("link"),
y={async:!0,load:function(a,b,c){if(a)if(a.match(/^data:/)){a=a.split(",");var d=a[1];d=-1<a[0].indexOf(";base64")?atob(d):decodeURIComponent(d);b(d)}else{var e=new XMLHttpRequest;e.open("GET",a,y.async);e.onload=function(){var a=e.responseURL||e.getResponseHeader("Location");a&&0===a.indexOf("/")&&(a=(location.origin||location.protocol+"//"+location.host)+a);var d=e.response||e.responseText;304===e.status||0===e.status||200<=e.status&&300>e.status?b(d,a):c(d)};e.send()}else c("error: href must be specified")}}, p=null;!1==="currentScript"in document&&Object.defineProperty(document,"currentScript",{get:function(){return p||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null)},configurable:!0});var t=/(url\()([^)]*)(\))/g,u=/(@import[\s]+(?!url\())([^;]*)(;)/g,v=/(<link[^>]*)(rel=['|"]?stylesheet['|"]?[^>]*>)/g,r={mb:function(a,b){a.href&&a.setAttribute("href",r.fa(a.getAttribute("href"),b));a.src&&a.setAttribute("src",r.fa(a.getAttribute("src"),b));if("style"===a.localName){var c=
x=/Trident/.test(navigator.userAgent)||/Edge\/\d./i.test(navigator.userAgent);m.prototype.c=function(a){var b=this;a=a.querySelectorAll("link[rel=import]");k(a,function(a){return b.h(a)})};m.prototype.h=function(a){var b=this,c=a.href;if(void 0!==this.a[c]){var d=this.a[c];d&&d.__loaded&&(a.import=d,this.g(a))}else this.b++,this.a[c]="pending",y.load(c,function(a,d){a=b.s(a,d||c);b.a[c]=a;b.b--;b.c(a);b.i()},function(){b.a[c]=null;b.b--;b.i()})};m.prototype.s=function(a,b){if(!a)return document.createDocumentFragment(); r.Ma(a.textContent,b,t);a.textContent=r.Ma(c,b,u)}},Ma:function(a,b,c){return a.replace(c,function(a,c,d,e){a=d.replace(/["']/g,"");b&&(a=r.fa(a,b));return c+"'"+a+"'"+e})},fa:function(a,b){if(void 0===r.na){r.na=!1;try{var c=new URL("b","http://a");c.pathname="c%20d";r.na="http://a/c%20d"===c.href}catch(sf){}}if(r.na)return(new URL(a,b)).href;c=r.Za;c||(c=document.implementation.createHTMLDocument("temp"),r.Za=c,c.ya=c.createElement("base"),c.head.appendChild(c.ya),c.xa=c.createElement("a"));c.ya.href=
x&&(a=a.replace(w,function(a,b,c){return-1===a.indexOf("type=")?b+" type=import-disable "+c:a}));var c=document.createElement("template");c.innerHTML=a;if(c.content)a=c.content;else for(a=document.createDocumentFragment();c.firstChild;)a.appendChild(c.firstChild);if(c=a.querySelector("base"))b=q.ta(c.getAttribute("href"),b),c.removeAttribute("href");c=a.querySelectorAll('link[rel=import], link[rel=stylesheet][href][type=import-disable],\n style:not([type]), link[rel=stylesheet][href]:not([type]),\n script:not([type]), script[type="application/javascript"],\n script[type="text/javascript"]'); b;c.xa.href=a;return c.xa.href||a}},w={async:!0,load:function(a,b,c){if(a)if(a.match(/^data:/)){a=a.split(",");var d=a[1];d=-1<a[0].indexOf(";base64")?atob(d):decodeURIComponent(d);b(d)}else{var e=new XMLHttpRequest;e.open("GET",a,w.async);e.onload=function(){var a=e.responseURL||e.getResponseHeader("Location");a&&0===a.indexOf("/")&&(a=(location.origin||location.protocol+"//"+location.host)+a);var d=e.response||e.responseText;304===e.status||0===e.status||200<=e.status&&300>e.status?b(d,a):c(d)};
var d=0;k(c,function(a){g(a);q.nb(a,b);a.setAttribute("import-dependency","");"script"===a.localName&&!a.src&&a.textContent&&(a.setAttribute("src","data:text/javascript;charset=utf-8,"+encodeURIComponent(a.textContent+("\n//# sourceURL="+b+(d?"-"+d:"")+".js\n"))),a.textContent="",d++)});return a};m.prototype.i=function(){var a=this;if(!this.b){this.f.disconnect();this.flatten(document);var b=!1,c=!1,d=function(){c&&b&&(a.c(document),a.b||(a.f.observe(document.head,{childList:!0,subtree:!0}),a.j()))}; e.send()}else c("error: href must be specified")}},z=/Trident/.test(navigator.userAgent)||/Edge\/\d./i.test(navigator.userAgent);m.prototype.c=function(a){var b=this;a=a.querySelectorAll("link[rel=import]");l(a,function(a){return b.h(a)})};m.prototype.h=function(a){var b=this,c=a.href;if(void 0!==this.a[c]){var d=this.a[c];d&&d.__loaded&&(a.import=d,this.g(a))}else this.b++,this.a[c]="pending",w.load(c,function(a,d){a=b.s(a,d||c);b.a[c]=a;b.b--;b.c(a);b.i()},function(){b.a[c]=null;b.b--;b.i()})};
this.v(function(){c=!0;d()});this.u(function(){b=!0;d()})}};m.prototype.flatten=function(a){var b=this;a=a.querySelectorAll("link[rel=import]");k(a,function(a){var c=b.a[a.href];(a.import=c)&&c.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&(b.a[a.href]=a,a.readyState="loading",a.import=a,b.flatten(c),a.appendChild(c))})};m.prototype.u=function(a){function b(e){if(e<d){var f=c[e],h=document.createElement("script");f.removeAttribute("import-dependency");k(f.attributes,function(a){return h.setAttribute(a.name, m.prototype.s=function(a,b){if(!a)return document.createDocumentFragment();z&&(a=a.replace(v,function(a,b,c){return-1===a.indexOf("type=")?b+" type=import-disable "+c:a}));var c=document.createElement("template");c.innerHTML=a;if(c.content)a=c.content;else for(a=document.createDocumentFragment();c.firstChild;)a.appendChild(c.firstChild);if(c=a.querySelector("base"))b=r.fa(c.getAttribute("href"),b),c.removeAttribute("href");c=a.querySelectorAll('link[rel=import], link[rel=stylesheet][href][type=import-disable],\n style:not([type]), link[rel=stylesheet][href]:not([type]),\n script:not([type]), script[type="application/javascript"],\n script[type="text/javascript"]');
a.value)});n=h;f.parentNode.replaceChild(h,f);g(h,function(){n=null;b(e+1)})}else a()}var c=document.querySelectorAll("script[import-dependency]"),d=c.length;b(0)};m.prototype.v=function(a){var b=document.querySelectorAll("style[import-dependency],\n link[rel=stylesheet][import-dependency]"),d=b.length;if(d){var e=x&&!!document.querySelector("link[rel=stylesheet][href][type=import-disable]");k(b,function(b){g(b,function(){b.removeAttribute("import-dependency");0===--d&&a()});if(e&&b.parentNode!== var d=0;l(c,function(a){h(a);r.mb(a,b);a.setAttribute("import-dependency","");"script"===a.localName&&!a.src&&a.textContent&&(a.setAttribute("src","data:text/javascript;charset=utf-8,"+encodeURIComponent(a.textContent+("\n//# sourceURL="+b+(d?"-"+d:"")+".js\n"))),a.textContent="",d++)});return a};m.prototype.i=function(){var a=this;if(!this.b){this.f.disconnect();this.flatten(document);var b=!1,c=!1,d=function(){c&&b&&(a.c(document),a.b||(a.f.observe(document.head,{childList:!0,subtree:!0}),a.j()))};
document.head){var f=document.createElement(b.localName);f.__appliedElement=b;f.setAttribute("type","import-placeholder");b.parentNode.insertBefore(f,b.nextSibling);for(f=c(b);f&&c(f);)f=c(f);f.parentNode!==document.head&&(f=null);document.head.insertBefore(b,f);b.removeAttribute("type")}})}else a()};m.prototype.j=function(){var a=this,b=document.querySelectorAll("link[rel=import]");k(b,function(b){return a.g(b)},!0)};m.prototype.g=function(a){a.__loaded||(a.__loaded=!0,a.import&&(a.import.readyState= this.v(function(){c=!0;d()});this.u(function(){b=!0;d()})}};m.prototype.flatten=function(a){var b=this;a=a.querySelectorAll("link[rel=import]");l(a,function(a){var c=b.a[a.href];(a.import=c)&&c.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&(b.a[a.href]=a,a.readyState="loading",a.import=a,b.flatten(c),a.appendChild(c))})};m.prototype.u=function(a){function b(e){if(e<d){var f=c[e],g=document.createElement("script");f.removeAttribute("import-dependency");l(f.attributes,function(a){return g.setAttribute(a.name,
"complete"),a.dispatchEvent(b(a.import?"load":"error",{bubbles:!1,cancelable:!1,detail:void 0})))};m.prototype.l=function(a){var b=this;k(a,function(a){return k(a.addedNodes,function(a){a&&a.nodeType===Node.ELEMENT_NODE&&(h(a)?b.h(a):b.c(a))})})};if(l){var v=document.querySelectorAll("link[rel=import]");k(v,function(a){a.import&&"loading"===a.import.readyState||(a.__loaded=!0)});v=function(a){a=a.target;h(a)&&(a.__loaded=!0)};document.addEventListener("load",v,!0);document.addEventListener("error", a.value)});p=g;f.parentNode.replaceChild(g,f);h(g,function(){p=null;b(e+1)})}else a()}var c=document.querySelectorAll("script[import-dependency]"),d=c.length;b(0)};m.prototype.v=function(a){var b=document.querySelectorAll("style[import-dependency],\n link[rel=stylesheet][import-dependency]"),d=b.length;if(d){var e=z&&!!document.querySelector("link[rel=stylesheet][href][type=import-disable]");l(b,function(b){h(b,function(){b.removeAttribute("import-dependency");0===--d&&a()});if(e&&b.parentNode!==
v,!0)}else{var u=Object.getOwnPropertyDescriptor(Node.prototype,"baseURI");Object.defineProperty((!u||u.configurable?Node:Element).prototype,"baseURI",{get:function(){var a=h(this)?this:c(this);return a?a.href:u&&u.get?u.get.call(this):(document.querySelector("base")||window.location).href},configurable:!0,enumerable:!0});e(function(){return new m})}f(function(){return document.dispatchEvent(b("HTMLImportsLoaded",{cancelable:!0,bubbles:!0,detail:void 0}))});a.useNative=l;a.whenReady=f;a.importForElement= document.head){var f=document.createElement(b.localName);f.__appliedElement=b;f.setAttribute("type","import-placeholder");b.parentNode.insertBefore(f,b.nextSibling);for(f=c(b);f&&c(f);)f=c(f);f.parentNode!==document.head&&(f=null);document.head.insertBefore(b,f);b.removeAttribute("type")}})}else a()};m.prototype.j=function(){var a=this,b=document.querySelectorAll("link[rel=import]");l(b,function(b){return a.g(b)},!0)};m.prototype.g=function(a){a.__loaded||(a.__loaded=!0,a.import&&(a.import.readyState=
c})(window.HTMLImports=window.HTMLImports||{});window.WebComponents=window.WebComponents||{flags:{}};var md=document.querySelector('script[src*="webcomponents-lite.js"]'),Ge=/wc-(.+)/,E={};if(!E.noOpts){location.search.slice(1).split("&").forEach(function(a){a=a.split("=");var b;a[0]&&(b=a[0].match(Ge))&&(E[b[1]]=a[1]||!0)});if(md)for(var nd=0,Ba;Ba=md.attributes[nd];nd++)"src"!==Ba.name&&(E[Ba.name]=Ba.value||!0);if(E.log&&E.log.split){var He=E.log.split(",");E.log={};He.forEach(function(a){E.log[a]= "complete"),a.dispatchEvent(b(a.import?"load":"error",{bubbles:!1,cancelable:!1,detail:void 0})))};m.prototype.l=function(a){var b=this;l(a,function(a){return l(a.addedNodes,function(a){a&&a.nodeType===Node.ELEMENT_NODE&&(g(a)?b.h(a):b.c(a))})})};if(n){var x=document.querySelectorAll("link[rel=import]");l(x,function(a){a.import&&"loading"===a.import.readyState||(a.__loaded=!0)});x=function(a){a=a.target;g(a)&&(a.__loaded=!0)};document.addEventListener("load",x,!0);document.addEventListener("error",
!0})}else E.log={}}window.WebComponents.flags=E;var od=E.shadydom;od&&(window.ShadyDOM=window.ShadyDOM||{},window.ShadyDOM.force=od);var pd=E.register||E.ce;pd&&window.customElements&&(window.customElements.forcePolyfill=pd);var D=window.ShadyDOM||{};D.ob=!(!Element.prototype.attachShadow||!Node.prototype.getRootNode);var yb=Object.getOwnPropertyDescriptor(Node.prototype,"firstChild");D.W=!!(yb&&yb.configurable&&yb.get);D.Ha=D.force||!D.ob;var da=Element.prototype,qd=da.matches||da.matchesSelector|| x,!0)}else{var y=Object.getOwnPropertyDescriptor(Node.prototype,"baseURI");Object.defineProperty((!y||y.configurable?Node:Element).prototype,"baseURI",{get:function(){var a=g(this)?this:c(this);return a?a.href:y&&y.get?y.get.call(this):(document.querySelector("base")||window.location).href},configurable:!0,enumerable:!0});e(function(){return new m})}f(function(){return document.dispatchEvent(b("HTMLImportsLoaded",{cancelable:!0,bubbles:!0,detail:void 0}))});a.useNative=n;a.whenReady=f;a.importForElement=
da.mozMatchesSelector||da.msMatchesSelector||da.oMatchesSelector||da.webkitMatchesSelector,eb=document.createTextNode(""),kc=0,db=[];(new MutationObserver(function(){for(;db.length;)try{db.shift()()}catch(a){throw eb.textContent=kc++,a;}})).observe(eb,{characterData:!0});var ja=[],fb;va.list=ja;ta.prototype.vb=function(){var a=this;this.a||(this.a=!0,jc(function(){a.b()}))};ta.prototype.b=function(){if(this.a){this.a=!1;var a=this.takeRecords();a.length&&this.ba.forEach(function(b){b(a)})}};ta.prototype.takeRecords= c})(window.HTMLImports=window.HTMLImports||{});window.WebComponents=window.WebComponents||{flags:{}};var sd=document.querySelector('script[src*="webcomponents-lite.js"]'),Re=/wc-(.+)/,H={};if(!H.noOpts){location.search.slice(1).split("&").forEach(function(a){a=a.split("=");var b;a[0]&&(b=a[0].match(Re))&&(H[b[1]]=a[1]||!0)});if(sd)for(var td=0,Fa;Fa=sd.attributes[td];td++)"src"!==Fa.name&&(H[Fa.name]=Fa.value||!0);if(H.log&&H.log.split){var Se=H.log.split(",");H.log={};Se.forEach(function(a){H.log[a]=
function(){if(this.addedNodes.length||this.removedNodes.length){var a=[{addedNodes:this.addedNodes,removedNodes:this.removedNodes}];this.addedNodes=[];this.removedNodes=[];return a}return[]};var Bc=Element.prototype.appendChild,mb=Element.prototype.insertBefore,ka=Element.prototype.removeChild,Jc=Element.prototype.setAttribute,rd=Element.prototype.removeAttribute,zb=Element.prototype.cloneNode,nb=Document.prototype.importNode,Rc=Element.prototype.addEventListener,Uc=Element.prototype.removeEventListener, !0})}else H.log={}}window.WebComponents.flags=H;var ud=H.shadydom;ud&&(window.ShadyDOM=window.ShadyDOM||{},window.ShadyDOM.force=ud);var vd=H.register||H.ce;vd&&window.customElements&&(window.customElements.forcePolyfill=vd);var G=window.ShadyDOM||{};G.nb=!(!Element.prototype.attachShadow||!Node.prototype.getRootNode);var Eb=Object.getOwnPropertyDescriptor(Node.prototype,"firstChild");G.X=!!(Eb&&Eb.configurable&&Eb.get);G.Ja=G.force||!G.nb;var ha=Element.prototype,wd=ha.matches||ha.matchesSelector||
Qc=Window.prototype.addEventListener,Tc=Window.prototype.removeEventListener,Ab=Element.prototype.dispatchEvent,Ie=Object.freeze({appendChild:Bc,insertBefore:mb,removeChild:ka,setAttribute:Jc,removeAttribute:rd,cloneNode:zb,importNode:nb,addEventListener:Rc,removeEventListener:Uc,Jb:Qc,Kb:Tc,dispatchEvent:Ab,querySelector:Element.prototype.querySelector,querySelectorAll:Element.prototype.querySelectorAll}),me=/[&\u00A0"]/g,pe=/[&\u00A0<>]/g,ne=nc("area base br col command embed hr img input keygen link meta param source track wbr".split(" ")), ha.mozMatchesSelector||ha.msMatchesSelector||ha.oMatchesSelector||ha.webkitMatchesSelector,kb=document.createTextNode(""),pc=0,jb=[];(new MutationObserver(function(){for(;jb.length;)try{jb.shift()()}catch(a){throw kb.textContent=pc++,a;}})).observe(kb,{characterData:!0});var Te=!!document.contains,na=[],lb;za.list=na;xa.prototype.ub=function(){var a=this;this.a||(this.a=!0,oc(function(){a.b()}))};xa.prototype.b=function(){if(this.a){this.a=!1;var a=this.takeRecords();a.length&&this.ca.forEach(function(b){b(a)})}};
oe=nc("style script xmp iframe noembed noframes plaintext noscript".split(" ")),B=document.createTreeWalker(document,NodeFilter.SHOW_ALL,null,!1),C=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT,null,!1),Je=Object.freeze({parentNode:aa,firstChild:Sa,lastChild:Ta,previousSibling:oc,nextSibling:pc,childNodes:U,parentElement:qc,firstElementChild:rc,lastElementChild:sc,previousElementSibling:tc,nextElementSibling:uc,children:vc,innerHTML:wc,textContent:xc}),Bb=Object.getOwnPropertyDescriptor(Element.prototype, xa.prototype.takeRecords=function(){if(this.addedNodes.length||this.removedNodes.length){var a=[{addedNodes:this.addedNodes,removedNodes:this.removedNodes}];this.addedNodes=[];this.removedNodes=[];return a}return[]};var Hc=Element.prototype.appendChild,sb=Element.prototype.insertBefore,oa=Element.prototype.removeChild,Pc=Element.prototype.setAttribute,xd=Element.prototype.removeAttribute,Fb=Element.prototype.cloneNode,tb=Document.prototype.importNode,Xc=Element.prototype.addEventListener,$c=Element.prototype.removeEventListener,
"innerHTML")||Object.getOwnPropertyDescriptor(HTMLElement.prototype,"innerHTML"),Ca=document.implementation.createHTMLDocument("inert").createElement("div"),Cb=Object.getOwnPropertyDescriptor(Document.prototype,"activeElement"),yc={parentElement:{get:function(){var a=this.__shady&&this.__shady.parentNode;a&&a.nodeType!==Node.ELEMENT_NODE&&(a=null);return void 0!==a?a:qc(this)},configurable:!0},parentNode:{get:function(){var a=this.__shady&&this.__shady.parentNode;return void 0!==a?a:aa(this)},configurable:!0}, Wc=Window.prototype.addEventListener,Zc=Window.prototype.removeEventListener,Gb=Element.prototype.dispatchEvent,pa=Node.prototype.contains||HTMLElement.prototype.contains,Ue=Object.freeze({appendChild:Hc,insertBefore:sb,removeChild:oa,setAttribute:Pc,removeAttribute:xd,cloneNode:Fb,importNode:tb,addEventListener:Xc,removeEventListener:$c,Kb:Wc,Lb:Zc,dispatchEvent:Gb,querySelector:Element.prototype.querySelector,querySelectorAll:Element.prototype.querySelectorAll,contains:pa}),xe=/[&\u00A0"]/g,Ae=
nextSibling:{get:function(){var a=this.__shady&&this.__shady.nextSibling;return void 0!==a?a:pc(this)},configurable:!0},previousSibling:{get:function(){var a=this.__shady&&this.__shady.previousSibling;return void 0!==a?a:oc(this)},configurable:!0},className:{get:function(){return this.getAttribute("class")||""},set:function(a){this.setAttribute("class",a)},configurable:!0},nextElementSibling:{get:function(){if(this.__shady&&void 0!==this.__shady.nextSibling){for(var a=this.nextSibling;a&&a.nodeType!== /[&\u00A0<>]/g,ye=tc("area base br col command embed hr img input keygen link meta param source track wbr".split(" ")),ze=tc("style script xmp iframe noembed noframes plaintext noscript".split(" ")),E=document.createTreeWalker(document,NodeFilter.SHOW_ALL,null,!1),F=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT,null,!1),Ve=Object.freeze({parentNode:da,firstChild:Ya,lastChild:Za,previousSibling:uc,nextSibling:vc,childNodes:X,parentElement:wc,firstElementChild:xc,lastElementChild:yc,previousElementSibling:zc,
Node.ELEMENT_NODE;)a=a.nextSibling;return a}return uc(this)},configurable:!0},previousElementSibling:{get:function(){if(this.__shady&&void 0!==this.__shady.previousSibling){for(var a=this.previousSibling;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}return tc(this)},configurable:!0}},hb={childNodes:{get:function(){if(Z(this)){if(!this.__shady.childNodes){this.__shady.childNodes=[];for(var a=this.firstChild;a;a=a.nextSibling)this.__shady.childNodes.push(a)}var b=this.__shady.childNodes}else b= nextElementSibling:Ac,children:Bc,innerHTML:Cc,textContent:Dc}),Hb=Object.getOwnPropertyDescriptor(Element.prototype,"innerHTML")||Object.getOwnPropertyDescriptor(HTMLElement.prototype,"innerHTML"),Ga=document.implementation.createHTMLDocument("inert").createElement("div"),Ib=Object.getOwnPropertyDescriptor(Document.prototype,"activeElement"),Ec={parentElement:{get:function(){var a=this.__shady&&this.__shady.parentNode;a&&a.nodeType!==Node.ELEMENT_NODE&&(a=null);return void 0!==a?a:wc(this)},configurable:!0},
U(this);b.item=function(a){return b[a]};return b},configurable:!0},childElementCount:{get:function(){return this.children.length},configurable:!0},firstChild:{get:function(){var a=this.__shady&&this.__shady.firstChild;return void 0!==a?a:Sa(this)},configurable:!0},lastChild:{get:function(){var a=this.__shady&&this.__shady.lastChild;return void 0!==a?a:Ta(this)},configurable:!0},textContent:{get:function(){if(Z(this)){for(var a=[],b=0,c=this.childNodes,d;d=c[b];b++)d.nodeType!==Node.COMMENT_NODE&& parentNode:{get:function(){var a=this.__shady&&this.__shady.parentNode;return void 0!==a?a:da(this)},configurable:!0},nextSibling:{get:function(){var a=this.__shady&&this.__shady.nextSibling;return void 0!==a?a:vc(this)},configurable:!0},previousSibling:{get:function(){var a=this.__shady&&this.__shady.previousSibling;return void 0!==a?a:uc(this)},configurable:!0},className:{get:function(){return this.getAttribute("class")||""},set:function(a){this.setAttribute("class",a)},configurable:!0},nextElementSibling:{get:function(){if(this.__shady&&
a.push(d.textContent);return a.join("")}return xc(this)},set:function(a){switch(this.nodeType){case Node.ELEMENT_NODE:case Node.DOCUMENT_FRAGMENT_NODE:for(;this.firstChild;)this.removeChild(this.firstChild);(0<a.length||this.nodeType===Node.ELEMENT_NODE)&&this.appendChild(document.createTextNode(a));break;default:this.nodeValue=a}},configurable:!0},firstElementChild:{get:function(){if(this.__shady&&void 0!==this.__shady.firstChild){for(var a=this.firstChild;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling; void 0!==this.__shady.nextSibling){for(var a=this.nextSibling;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}return Ac(this)},configurable:!0},previousElementSibling:{get:function(){if(this.__shady&&void 0!==this.__shady.previousSibling){for(var a=this.previousSibling;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}return zc(this)},configurable:!0}},nb={childNodes:{get:function(){if(ca(this)){if(!this.__shady.childNodes){this.__shady.childNodes=[];for(var a=this.firstChild;a;a=
return a}return rc(this)},configurable:!0},lastElementChild:{get:function(){if(this.__shady&&void 0!==this.__shady.lastChild){for(var a=this.lastChild;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}return sc(this)},configurable:!0},children:{get:function(){var a;Z(this)?a=Array.prototype.filter.call(this.childNodes,function(a){return a.nodeType===Node.ELEMENT_NODE}):a=vc(this);a.item=function(b){return a[b]};return a},configurable:!0},innerHTML:{get:function(){var a="template"=== a.nextSibling)this.__shady.childNodes.push(a)}var b=this.__shady.childNodes}else b=X(this);b.item=function(a){return b[a]};return b},configurable:!0},childElementCount:{get:function(){return this.children.length},configurable:!0},firstChild:{get:function(){var a=this.__shady&&this.__shady.firstChild;return void 0!==a?a:Ya(this)},configurable:!0},lastChild:{get:function(){var a=this.__shady&&this.__shady.lastChild;return void 0!==a?a:Za(this)},configurable:!0},textContent:{get:function(){if(ca(this)){for(var a=
this.localName?this.content:this;return Z(this)?gb(a):wc(a)},set:function(a){for(var b="template"===this.localName?this.content:this;b.firstChild;)b.removeChild(b.firstChild);for(Bb&&Bb.set?Bb.set.call(Ca,a):Ca.innerHTML=a;Ca.firstChild;)b.appendChild(Ca.firstChild)},configurable:!0}},sd={shadowRoot:{get:function(){return this.__shady&&this.__shady.tb||null},configurable:!0}},ib={activeElement:{get:function(){var a=Cb&&Cb.get?Cb.get.call(document):D.W?void 0:document.activeElement;if(a&&a.nodeType){var b= [],b=0,c=this.childNodes,d;d=c[b];b++)d.nodeType!==Node.COMMENT_NODE&&a.push(d.textContent);return a.join("")}return Dc(this)},set:function(a){switch(this.nodeType){case Node.ELEMENT_NODE:case Node.DOCUMENT_FRAGMENT_NODE:for(;this.firstChild;)this.removeChild(this.firstChild);(0<a.length||this.nodeType===Node.ELEMENT_NODE)&&this.appendChild(document.createTextNode(a));break;default:this.nodeValue=a}},configurable:!0},firstElementChild:{get:function(){if(this.__shady&&void 0!==this.__shady.firstChild){for(var a=
!!I(this);if(this===document||b&&this.host!==a&&this.host.contains(a)){for(b=ia(a);b&&b!==this;)a=b.host,b=ia(a);a=this===document?b?null:a:b===this?a:null}else a=null}else a=null;return a},set:function(){},configurable:!0}},ac=D.W?function(){}:function(a){a.__shady&&a.__shady.Xa||(a.__shady=a.__shady||{},a.__shady.Xa=!0,M(a,yc,!0))},$b=D.W?function(){}:function(a){a.__shady&&a.__shady.Va||(a.__shady=a.__shady||{},a.__shady.Va=!0,M(a,hb,!0),M(a,sd,!0))},xa=null,la="__eventWrappers"+Date.now(),Ke= this.firstChild;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}return xc(this)},configurable:!0},lastElementChild:{get:function(){if(this.__shady&&void 0!==this.__shady.lastChild){for(var a=this.lastChild;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}return yc(this)},configurable:!0},children:{get:function(){var a;ca(this)?a=Array.prototype.filter.call(this.childNodes,function(a){return a.nodeType===Node.ELEMENT_NODE}):a=Bc(this);a.item=function(b){return a[b]};return a},
{blur:!0,focus:!0,focusin:!0,focusout:!0,click:!0,dblclick:!0,mousedown:!0,mouseenter:!0,mouseleave:!0,mousemove:!0,mouseout:!0,mouseover:!0,mouseup:!0,wheel:!0,beforeinput:!0,input:!0,keydown:!0,keyup:!0,compositionstart:!0,compositionupdate:!0,compositionend:!0,touchstart:!0,touchend:!0,touchmove:!0,touchcancel:!0,pointerover:!0,pointerenter:!0,pointerdown:!0,pointermove:!0,pointerup:!0,pointercancel:!0,pointerout:!0,pointerleave:!0,gotpointercapture:!0,lostpointercapture:!0,dragstart:!0,drag:!0, configurable:!0},innerHTML:{get:function(){var a="template"===this.localName?this.content:this;return ca(this)?mb(a):Cc(a)},set:function(a){for(var b="template"===this.localName?this.content:this;b.firstChild;)b.removeChild(b.firstChild);for(Hb&&Hb.set?Hb.set.call(Ga,a):Ga.innerHTML=a;Ga.firstChild;)b.appendChild(Ga.firstChild)},configurable:!0}},yd={shadowRoot:{get:function(){return this.__shady&&this.__shady.sb||null},configurable:!0}},ob={activeElement:{get:function(){var a=Ib&&Ib.get?Ib.get.call(document):
dragenter:!0,dragleave:!0,dragover:!0,drop:!0,dragend:!0,DOMActivate:!0,DOMFocusIn:!0,DOMFocusOut:!0,keypress:!0},Vc={get composed(){!1!==this.isTrusted&&void 0===this.ia&&(this.ia=Ke[this.type]);return this.ia||!1},composedPath:function(){this.xa||(this.xa=ob(this.__target,this.composed));return this.xa},get target(){return Lc(this.currentTarget,this.composedPath())},get relatedTarget(){if(!this.ya)return null;this.za||(this.za=ob(this.ya,!0));return Lc(this.currentTarget,this.za)},stopPropagation:function(){Event.prototype.stopPropagation.call(this); G.X?void 0:document.activeElement;if(a&&a.nodeType){var b=!!J(this);if(this===document||b&&this.host!==a&&pa.call(this.host,a)){for(b=ma(a);b&&b!==this;)a=b.host,b=ma(a);a=this===document?b?null:a:b===this?a:null}else a=null}else a=null;return a},set:function(){},configurable:!0}},fc=G.X?function(){}:function(a){a.__shady&&a.__shady.Xa||(a.__shady=a.__shady||{},a.__shady.Xa=!0,O(a,Ec,!0))},ec=G.X?function(){}:function(a){a.__shady&&a.__shady.Va||(a.__shady=a.__shady||{},a.__shady.Va=!0,O(a,nb,!0),
this.ja=!0},stopImmediatePropagation:function(){Event.prototype.stopImmediatePropagation.call(this);this.ja=this.Ua=!0}},qb={focus:!0,blur:!0},Le=pb(window.Event),Me=pb(window.CustomEvent),Ne=pb(window.MouseEvent),Zb={};l.prototype=Object.create(DocumentFragment.prototype);l.prototype.D=function(a,b){this.Wa="ShadyRoot";sa(a);sa(this);this.host=a;this.L=b&&b.mode;a.__shady=a.__shady||{};a.__shady.root=this;a.__shady.tb="closed"!==this.L?this:null;this.T=!1;this.b=[];this.a=null;b=U(a);for(var c=0, O(a,yd,!0))},Ba=null,qa="__eventWrappers"+Date.now(),We={blur:!0,focus:!0,focusin:!0,focusout:!0,click:!0,dblclick:!0,mousedown:!0,mouseenter:!0,mouseleave:!0,mousemove:!0,mouseout:!0,mouseover:!0,mouseup:!0,wheel:!0,beforeinput:!0,input:!0,keydown:!0,keyup:!0,compositionstart:!0,compositionupdate:!0,compositionend:!0,touchstart:!0,touchend:!0,touchmove:!0,touchcancel:!0,pointerover:!0,pointerenter:!0,pointerdown:!0,pointermove:!0,pointerup:!0,pointercancel:!0,pointerout:!0,pointerleave:!0,gotpointercapture:!0,
d=b.length;c<d;c++)ka.call(a,b[c])};l.prototype.M=function(){var a=this;this.T||(this.T=!0,lc(function(){return a.Da()}))};l.prototype.C=function(){for(var a=this,b=this;b;)b.T&&(a=b),b=b.hb();return a};l.prototype.hb=function(){var a=this.host.getRootNode();if(I(a))for(var b=this.host.childNodes,c=0,d;c<b.length;c++)if(d=b[c],this.h(d))return a};l.prototype.Da=function(){this.T&&this.C()._renderRoot()};l.prototype._renderRoot=function(){this.T=!1;this.v();this.s()};l.prototype.v=function(){for(var a= lostpointercapture:!0,dragstart:!0,drag:!0,dragenter:!0,dragleave:!0,dragover:!0,drop:!0,dragend:!0,DOMActivate:!0,DOMFocusIn:!0,DOMFocusOut:!0,keypress:!0},ad={get composed(){!1!==this.isTrusted&&void 0===this.ka&&(this.ka=We[this.type]);return this.ka||!1},composedPath:function(){this.za||(this.za=ub(this.__target,this.composed));return this.za},get target(){return Rc(this.currentTarget,this.composedPath())},get relatedTarget(){if(!this.Aa)return null;this.Ba||(this.Ba=ub(this.Aa,!0));return Rc(this.currentTarget,
0,b;a<this.b.length;a++)b=this.b[a],this.l(b);for(b=this.host.firstChild;b;b=b.nextSibling)this.f(b);for(a=0;a<this.b.length;a++){b=this.b[a];if(!b.__shady.assignedNodes.length)for(var c=b.firstChild;c;c=c.nextSibling)this.f(c,b);c=b.parentNode;(c=c.__shady&&c.__shady.root)&&c.Aa()&&c._renderRoot();this.c(b.__shady.V,b.__shady.assignedNodes);if(c=b.__shady.Ca){for(var d=0;d<c.length;d++)c[d].__shady.ma=null;b.__shady.Ca=null;c.length>b.__shady.assignedNodes.length&&(b.__shady.pa=!0)}b.__shady.pa&& this.Ba)},stopPropagation:function(){Event.prototype.stopPropagation.call(this);this.la=!0},stopImmediatePropagation:function(){Event.prototype.stopImmediatePropagation.call(this);this.la=this.Ua=!0}},wb={focus:!0,blur:!0},Xe=vb(window.Event),Ye=vb(window.CustomEvent),Ze=vb(window.MouseEvent),dc={};l.prototype=Object.create(DocumentFragment.prototype);l.prototype.H=function(a,b){this.Wa="ShadyRoot";wa(a);wa(this);this.host=a;this.J=b&&b.mode;a.__shady=a.__shady||{};a.__shady.root=this;a.__shady.sb=
(b.__shady.pa=!1,this.g(b))}};l.prototype.f=function(a,b){a.__shady=a.__shady||{};var c=a.__shady.ma;a.__shady.ma=null;b||(b=(b=this.a[a.slot||"__catchall"])&&b[0]);b?(b.__shady.assignedNodes.push(a),a.__shady.assignedSlot=b):a.__shady.assignedSlot=void 0;c!==a.__shady.assignedSlot&&a.__shady.assignedSlot&&(a.__shady.assignedSlot.__shady.pa=!0)};l.prototype.l=function(a){var b=a.__shady.assignedNodes;a.__shady.assignedNodes=[];a.__shady.V=[];if(a.__shady.Ca=b)for(var c=0;c<b.length;c++){var d=b[c]; "closed"!==this.J?this:null;this.U=!1;this.b=[];this.a={};this.c=[];b=X(a);for(var c=0,d=b.length;c<d;c++)oa.call(a,b[c])};l.prototype.O=function(){var a=this;this.U||(this.U=!0,rc(function(){return a.Fa()}))};l.prototype.N=function(){for(var a=this,b=this;b;)b.U&&(a=b),b=b.hb();return a};l.prototype.hb=function(){var a=this.host.getRootNode();if(J(a))for(var b=this.host.childNodes,c=0,d;c<b.length;c++)if(d=b[c],this.j(d))return a};l.prototype.Fa=function(){this.U&&this.N()._renderRoot()};l.prototype._renderRoot=
d.__shady.ma=d.__shady.assignedSlot;d.__shady.assignedSlot===a&&(d.__shady.assignedSlot=null)}};l.prototype.c=function(a,b){for(var c=0,d;c<b.length&&(d=b[c]);c++)"slot"==d.localName?this.c(a,d.__shady.assignedNodes):a.push(b[c])};l.prototype.g=function(a){Ab.call(a,new Event("slotchange"));a.__shady.assignedSlot&&this.g(a.__shady.assignedSlot)};l.prototype.s=function(){for(var a=this.b,b=[],c=0;c<a.length;c++){var d=a[c].parentNode;d.__shady&&d.__shady.root||!(0>b.indexOf(d))||b.push(d)}for(a=0;a< function(){this.U=!1;this.D();this.v()};l.prototype.D=function(){this.f();for(var a=0,b;a<this.b.length;a++)b=this.b[a],this.u(b);for(b=this.host.firstChild;b;b=b.nextSibling)this.h(b);for(a=0;a<this.b.length;a++){b=this.b[a];if(!b.__shady.assignedNodes.length)for(var c=b.firstChild;c;c=c.nextSibling)this.h(c,b);c=b.parentNode;(c=c.__shady&&c.__shady.root)&&c.Ca()&&c._renderRoot();this.g(b.__shady.W,b.__shady.assignedNodes);if(c=b.__shady.Ea){for(var d=0;d<c.length;d++)c[d].__shady.oa=null;b.__shady.Ea=
b.length;a++)c=b[a],this.I(c===this?this.host:c,this.u(c))};l.prototype.u=function(a){var b=[];a=a.childNodes;for(var c=0;c<a.length;c++){var d=a[c];if(this.h(d)){d=d.__shady.V;for(var e=0;e<d.length;e++)b.push(d[e])}else b.push(d)}return b};l.prototype.h=function(a){return"slot"==a.localName};l.prototype.I=function(a,b){for(var c=U(a),d=se(b,b.length,c,c.length),e=0,f=0,g;e<d.length&&(g=d[e]);e++){for(var h=0,k;h<g.Y.length&&(k=g.Y[h]);h++)aa(k)===a&&ka.call(a,k),c.splice(g.index+f,1);f-=g.aa}for(e= null;c.length>b.__shady.assignedNodes.length&&(b.__shady.sa=!0)}b.__shady.sa&&(b.__shady.sa=!1,this.i(b))}};l.prototype.h=function(a,b){a.__shady=a.__shady||{};var c=a.__shady.oa;a.__shady.oa=null;b||(b=(b=this.a[a.slot||"__catchall"])&&b[0]);b?(b.__shady.assignedNodes.push(a),a.__shady.assignedSlot=b):a.__shady.assignedSlot=void 0;c!==a.__shady.assignedSlot&&a.__shady.assignedSlot&&(a.__shady.assignedSlot.__shady.sa=!0)};l.prototype.u=function(a){var b=a.__shady.assignedNodes;a.__shady.assignedNodes=
0;e<d.length&&(g=d[e]);e++)for(f=c[g.index],h=g.index;h<g.index+g.aa;h++)k=b[h],mb.call(a,k,f),c.splice(h,0,k)};l.prototype.$a=function(a){this.a=this.a||{};this.b=this.b||[];for(var b=0;b<a.length;b++){var c=a[b];c.__shady=c.__shady||{};sa(c);sa(c.parentNode);var d=this.i(c);if(this.a[d]){var e=e||{};e[d]=!0;this.a[d].push(c)}else this.a[d]=[c];this.b.push(c)}if(e)for(var f in e)this.a[f]=this.j(this.a[f])};l.prototype.i=function(a){var b=a.name||a.getAttribute("name")||"__catchall";return a.Ya= [];a.__shady.W=[];if(a.__shady.Ea=b)for(var c=0;c<b.length;c++){var d=b[c];d.__shady.oa=d.__shady.assignedSlot;d.__shady.assignedSlot===a&&(d.__shady.assignedSlot=null)}};l.prototype.g=function(a,b){for(var c=0,d;c<b.length&&(d=b[c]);c++)"slot"==d.localName?this.g(a,d.__shady.assignedNodes):a.push(b[c])};l.prototype.i=function(a){Gb.call(a,new Event("slotchange"));a.__shady.assignedSlot&&this.i(a.__shady.assignedSlot)};l.prototype.v=function(){for(var a=this.b,b=[],c=0;c<a.length;c++){var d=a[c].parentNode;
b};l.prototype.j=function(a){return a.sort(function(a,c){a=Wc(a);for(var b=Wc(c),e=0;e<a.length;e++){c=a[e];var f=b[e];if(c!==f)return a=Array.from(c.parentNode.childNodes),a.indexOf(c)-a.indexOf(f)}})};l.prototype.gb=function(a){this.a=this.a||{};this.b=this.b||[];var b=this.a,c;for(c in b)for(var d=b[c],e=0;e<d.length;e++){var f=d[e],g;a:{for(g=f;g;){if(g==a){g=!0;break a}g=g.parentNode}g=void 0}if(g){d.splice(e,1);var h=this.b.indexOf(f);0<=h&&this.b.splice(h,1);e--;this.H(f);h=!0}}return h};l.prototype.ib= d.__shady&&d.__shady.root||!(0>b.indexOf(d))||b.push(d)}for(a=0;a<b.length;a++)c=b[a],this.T(c===this?this.host:c,this.B(c))};l.prototype.B=function(a){var b=[];a=a.childNodes;for(var c=0;c<a.length;c++){var d=a[c];if(this.j(d)){d=d.__shady.W;for(var e=0;e<d.length;e++)b.push(d[e])}else b.push(d)}return b};l.prototype.j=function(a){return"slot"==a.localName};l.prototype.T=function(a,b){for(var c=X(a),d=De(b,b.length,c,c.length),e=0,f=0,h;e<d.length&&(h=d[e]);e++){for(var g=0,m;g<h.Z.length&&(m=h.Z[g]);g++)da(m)===
function(a){var b=a.Ya,c=this.i(a);if(c!==b){b=this.a[b];var d=b.indexOf(a);0<=d&&b.splice(d,1);b=this.a[c]||(this.a[c]=[]);b.push(a);1<b.length&&(this.a[c]=this.j(b))}};l.prototype.H=function(a){if(a=a.__shady.V)for(var b=0;b<a.length;b++){var c=a[b],d=aa(c);d&&ka.call(d,c)}};l.prototype.Aa=function(){return!!this.b.length};l.prototype.addEventListener=function(a,b,c){"object"!==typeof c&&(c={capture:!!c});c.ka=this;this.host.addEventListener(a,b,c)};l.prototype.removeEventListener=function(a,b, a&&oa.call(a,m),c.splice(h.index+f,1);f-=h.ba}for(e=0;e<d.length&&(h=d[e]);e++)for(f=c[h.index],g=h.index;g<h.index+h.ba;g++)m=b[g],sb.call(a,m,f),c.splice(g,0,m)};l.prototype.$a=function(a){this.c.push.apply(this.c,[].concat(a instanceof Array?a:Sd(Rd(a))))};l.prototype.f=function(){this.c.length&&(this.I(this.c),this.c=[])};l.prototype.I=function(a){for(var b,c=0;c<a.length;c++){var d=a[c];d.__shady=d.__shady||{};wa(d);wa(d.parentNode);var e=this.l(d);this.a[e]?(b=b||{},b[e]=!0,this.a[e].push(d)):
c){"object"!==typeof c&&(c={capture:!!c});c.ka=this;this.host.removeEventListener(a,b,c)};l.prototype.getElementById=function(a){return wa(this,function(b){return b.id==a},function(a){return!!a})[0]||null};(function(a){M(a,hb,!0);M(a,ib,!0)})(l.prototype);var we={addEventListener:Oc.bind(window),removeEventListener:Sc.bind(window)},ve={addEventListener:Oc,removeEventListener:Sc,appendChild:function(a){return jb(this,a)},insertBefore:function(a,b){return jb(this,a,b)},removeChild:function(a){return kb(this, this.a[e]=[d];this.b.push(d)}if(b)for(var f in b)this.a[f]=this.s(this.a[f])};l.prototype.l=function(a){var b=a.name||a.getAttribute("name")||"__catchall";return a.Ya=b};l.prototype.s=function(a){return a.sort(function(a,c){a=bd(a);for(var b=bd(c),e=0;e<a.length;e++){c=a[e];var f=b[e];if(c!==f)return a=Array.from(c.parentNode.childNodes),a.indexOf(c)-a.indexOf(f)}})};l.prototype.gb=function(a){this.f();var b=this.a,c;for(c in b)for(var d=b[c],e=0;e<d.length;e++){var f=d[e];if(qc(a,f)){d.splice(e,
a)},replaceChild:function(a,b){jb(this,a,b);kb(this,b);return a},cloneNode:function(a){if("template"==this.localName)var b=zb.call(this,a);else if(b=zb.call(this,!1),a){a=this.childNodes;for(var c=0,d;c<a.length;c++)d=a[c].cloneNode(!0),b.appendChild(d)}return b},getRootNode:function(){return Fc(this)},get isConnected(){var a=this.ownerDocument;if(a&&a.contains&&a.contains(this)||(a=a.documentElement)&&a.contains&&a.contains(this))return!0;for(a=this;a&&!(a instanceof Document);)a=a.parentNode||(a instanceof 1);var h=this.b.indexOf(f);0<=h&&this.b.splice(h,1);e--;this.K(f);h=!0}}return h};l.prototype.ib=function(a){var b=a.Ya,c=this.l(a);if(c!==b){b=this.a[b];var d=b.indexOf(a);0<=d&&b.splice(d,1);b=this.a[c]||(this.a[c]=[]);b.push(a);1<b.length&&(this.a[c]=this.s(b))}};l.prototype.K=function(a){if(a=a.__shady.W)for(var b=0;b<a.length;b++){var c=a[b],d=da(c);d&&oa.call(d,c)}};l.prototype.Ca=function(){this.f();return!!this.b.length};l.prototype.addEventListener=function(a,b,c){"object"!==typeof c&&(c=
l?a.host:void 0);return!!(a&&a instanceof Document)},dispatchEvent:function(a){va();return Ab.call(this,a)}},xe={get assignedSlot(){return Xc(this)}},rb={querySelector:function(a){return wa(this,function(b){return qd.call(b,a)},function(a){return!!a})[0]||null},querySelectorAll:function(a){return wa(this,function(b){return qd.call(b,a)})}},$c={assignedNodes:function(a){if("slot"===this.localName)return Hc(this),this.__shady?(a&&a.flatten?this.__shady.V:this.__shady.assignedNodes)||[]:[]}},Yc=cb({setAttribute:function(a, {capture:!!c});c.ma=this;this.host.addEventListener(a,b,c)};l.prototype.removeEventListener=function(a,b,c){"object"!==typeof c&&(c={capture:!!c});c.ma=this;this.host.removeEventListener(a,b,c)};l.prototype.getElementById=function(a){return Aa(this,function(b){return b.id==a},function(a){return!!a})[0]||null};(function(a){O(a,nb,!0);O(a,ob,!0)})(l.prototype);var He={addEventListener:Uc.bind(window),removeEventListener:Yc.bind(window)},Ge={addEventListener:Uc,removeEventListener:Yc,appendChild:function(a){return pb(this,
b){Ic(this,a,b)},removeAttribute:function(a){rd.call(this,a);Ec(this,a)},attachShadow:function(a){if(!this)throw"Must provide a host.";if(!a)throw"Not enough arguments.";return new l(Zb,this,a)},get slot(){return this.getAttribute("slot")},set slot(a){Ic(this,"slot",a)},get assignedSlot(){return Xc(this)}},rb,$c);Object.defineProperties(Yc,sd);var Zc=cb({importNode:function(a,b){return Kc(a,b)},getElementById:function(a){return wa(this,function(b){return b.id==a},function(a){return!!a})[0]||null}}, a)},insertBefore:function(a,b){return pb(this,a,b)},removeChild:function(a){return qb(this,a)},replaceChild:function(a,b){pb(this,a,b);qb(this,b);return a},cloneNode:function(a){if("template"==this.localName)var b=Fb.call(this,a);else if(b=Fb.call(this,!1),a){a=this.childNodes;for(var c=0,d;c<a.length;c++)d=a[c].cloneNode(!0),b.appendChild(d)}return b},getRootNode:function(){return Lc(this)},contains:function(a){return qc(this,a)},get isConnected(){var a=this.ownerDocument;if(Te&&pa.call(a,this)||
rb);Object.defineProperties(Zc,{_activeElement:ib.activeElement});var Oe=HTMLElement.prototype.blur,ye=cb({blur:function(){var a=this.__shady&&this.__shady.root;(a=a&&a.activeElement)?a.blur():Oe.call(this)}});D.Ha&&(window.ShadyDOM={inUse:D.Ha,patch:function(a){return a},isShadyRoot:I,enqueue:lc,flush:va,settings:D,filterMutations:le,observeChildren:Zd,unobserveChildren:Yd,nativeMethods:Ie,nativeTree:Je},window.Event=Le,window.CustomEvent=Me,window.MouseEvent=Ne,re(),ue(),window.ShadowRoot=l);var ze= a.documentElement&&pa.call(a.documentElement,this))return!0;for(a=this;a&&!(a instanceof Document);)a=a.parentNode||(a instanceof l?a.host:void 0);return!!(a&&a instanceof Document)},dispatchEvent:function(a){za();return Gb.call(this,a)}},Ie={get assignedSlot(){return cd(this)}},xb={querySelector:function(a){return Aa(this,function(b){return wd.call(b,a)},function(a){return!!a})[0]||null},querySelectorAll:function(a){return Aa(this,function(b){return wd.call(b,a)})}},fd={assignedNodes:function(a){if("slot"===
new Set("annotation-xml color-profile font-face font-face-src font-face-uri font-face-format font-face-name missing-glyph".split(" "));z.prototype.D=function(a,b){this.u.set(a,b);this.s.set(b.constructor,b)};z.prototype.c=function(a){return this.u.get(a)};z.prototype.C=function(a){return this.s.get(a)};z.prototype.v=function(a){this.h=!0;this.j.push(a)};z.prototype.l=function(a){var b=this;this.h&&P(a,function(a){return b.g(a)})};z.prototype.g=function(a){if(this.h&&!a.__CE_patched){a.__CE_patched= this.localName)return Nc(this),this.__shady?(a&&a.flatten?this.__shady.W:this.__shady.assignedNodes)||[]:[]}},dd=ib({setAttribute:function(a,b){Oc(this,a,b)},removeAttribute:function(a){xd.call(this,a);Kc(this,a)},attachShadow:function(a){if(!this)throw"Must provide a host.";if(!a)throw"Not enough arguments.";return new l(dc,this,a)},get slot(){return this.getAttribute("slot")},set slot(a){Oc(this,"slot",a)},get assignedSlot(){return cd(this)}},xb,fd);Object.defineProperties(dd,yd);var ed=ib({importNode:function(a,
!0;for(var b=0;b<this.j.length;b++)this.j[b](a)}};z.prototype.b=function(a){var b=[];P(a,function(a){return b.push(a)});for(a=0;a<b.length;a++){var c=b[a];1===c.__CE_state?this.connectedCallback(c):this.i(c)}};z.prototype.a=function(a){var b=[];P(a,function(a){return b.push(a)});for(a=0;a<b.length;a++){var c=b[a];1===c.__CE_state&&this.disconnectedCallback(c)}};z.prototype.f=function(a,b){var c=this;b=b?b:{};var d=b.yb||new Set,e=b.Na||function(a){return c.i(a)},f=[];P(a,function(a){if("link"===a.localName&& b){return Qc(a,b)},getElementById:function(a){return Aa(this,function(b){return b.id==a},function(a){return!!a})[0]||null}},xb);Object.defineProperties(ed,{_activeElement:ob.activeElement});var $e=HTMLElement.prototype.blur,Je=ib({blur:function(){var a=this.__shady&&this.__shady.root;(a=a&&a.activeElement)?a.blur():$e.call(this)}});G.Ja&&(window.ShadyDOM={inUse:G.Ja,patch:function(a){return a},isShadyRoot:J,enqueue:rc,flush:za,settings:G,filterMutations:we,observeChildren:je,unobserveChildren:ie,
"import"===a.getAttribute("rel")){var b=a.import;b instanceof Node&&"complete"===b.readyState?(b.__CE_isImportDocument=!0,b.__CE_hasRegistry=!0):a.addEventListener("load",function(){var b=a.import;b.__CE_documentLoadHandled||(b.__CE_documentLoadHandled=!0,b.__CE_isImportDocument=!0,b.__CE_hasRegistry=!0,d.delete(b),c.f(b,{yb:d,Na:e}))})}else f.push(a)},d);if(this.h)for(a=0;a<f.length;a++)this.g(f[a]);for(a=0;a<f.length;a++)e(f[a])};z.prototype.i=function(a){if(void 0===a.__CE_state){var b=this.c(a.localName); nativeMethods:Ue,nativeTree:Ve},window.Event=Xe,window.CustomEvent=Ye,window.MouseEvent=Ze,Ce(),Fe(),window.ShadowRoot=l);var Ke=new Set("annotation-xml color-profile font-face font-face-src font-face-uri font-face-format font-face-name missing-glyph".split(" "));B.prototype.D=function(a,b){this.u.set(a,b);this.s.set(b.constructor,b)};B.prototype.c=function(a){return this.u.get(a)};B.prototype.B=function(a){return this.s.get(a)};B.prototype.v=function(a){this.h=!0;this.j.push(a)};B.prototype.l=function(a){var b=
if(b){b.constructionStack.push(a);var c=b.constructor;try{try{if(new c!==a)throw Error("The custom element constructor did not produce the element being upgraded.");}finally{b.constructionStack.pop()}}catch(f){throw a.__CE_state=2,f;}a.__CE_state=1;a.__CE_definition=b;if(b.attributeChangedCallback)for(b=b.observedAttributes,c=0;c<b.length;c++){var d=b[c],e=a.getAttribute(d);null!==e&&this.attributeChangedCallback(a,d,null,e,null)}n(a)&&this.connectedCallback(a)}}};z.prototype.connectedCallback=function(a){var b= this;this.h&&S(a,function(a){return b.g(a)})};B.prototype.g=function(a){if(this.h&&!a.__CE_patched){a.__CE_patched=!0;for(var b=0;b<this.j.length;b++)this.j[b](a)}};B.prototype.b=function(a){var b=[];S(a,function(a){return b.push(a)});for(a=0;a<b.length;a++){var c=b[a];1===c.__CE_state?this.connectedCallback(c):this.i(c)}};B.prototype.a=function(a){var b=[];S(a,function(a){return b.push(a)});for(a=0;a<b.length;a++){var c=b[a];1===c.__CE_state&&this.disconnectedCallback(c)}};B.prototype.f=function(a,
a.__CE_definition;b.connectedCallback&&b.connectedCallback.call(a)};z.prototype.disconnectedCallback=function(a){var b=a.__CE_definition;b.disconnectedCallback&&b.disconnectedCallback.call(a)};z.prototype.attributeChangedCallback=function(a,b,c,d,e){var f=a.__CE_definition;f.attributeChangedCallback&&-1<f.observedAttributes.indexOf(b)&&f.attributeChangedCallback.call(a,b,c,d,e)};Ra.prototype.c=function(){this.N&&this.N.disconnect()};Ra.prototype.f=function(a){var b=this.a.readyState;"interactive"!== b){var c=this;b=b?b:{};var d=b.xb||new Set,e=b.Na||function(a){return c.i(a)},f=[];S(a,function(a){if("link"===a.localName&&"import"===a.getAttribute("rel")){var b=a.import;b instanceof Node&&"complete"===b.readyState?(b.__CE_isImportDocument=!0,b.__CE_hasRegistry=!0):a.addEventListener("load",function(){var b=a.import;if(!b.__CE_documentLoadHandled){b.__CE_documentLoadHandled=!0;b.__CE_isImportDocument=!0;b.__CE_hasRegistry=!0;var f=new Set(d);f.delete(b);c.f(b,{xb:f,Na:e})}})}else f.push(a)},d);
b&&"complete"!==b||this.c();for(b=0;b<a.length;b++)for(var c=a[b].addedNodes,d=0;d<c.length;d++)this.b.f(c[d])};Yb.prototype.resolve=function(a){if(this.a)throw Error("Already resolved.");this.a=a;this.b&&this.b(a)};x.prototype.define=function(a,b){var c=this;if(!(b instanceof Function))throw new TypeError("Custom element constructors must be functions.");if(!ad(a))throw new SyntaxError("The element name '"+a+"' is not valid.");if(this.a.c(a))throw Error("A custom element with name '"+a+"' has already been defined."); if(this.h)for(a=0;a<f.length;a++)this.g(f[a]);for(a=0;a<f.length;a++)e(f[a])};B.prototype.i=function(a){if(void 0===a.__CE_state){var b=this.c(a.localName);if(b){b.constructionStack.push(a);var c=b.constructor;try{try{if(new c!==a)throw Error("The custom element constructor did not produce the element being upgraded.");}finally{b.constructionStack.pop()}}catch(f){throw a.__CE_state=2,f;}a.__CE_state=1;a.__CE_definition=b;if(b.attributeChangedCallback)for(b=b.observedAttributes,c=0;c<b.length;c++){var d=
if(this.c)throw Error("A custom element is already being defined.");this.c=!0;try{var d=function(a){var b=e[a];if(void 0!==b&&!(b instanceof Function))throw Error("The '"+a+"' callback must be a function.");return b},e=b.prototype;if(!(e instanceof Object))throw new TypeError("The custom element constructor's prototype is not an object.");var f=d("connectedCallback");var g=d("disconnectedCallback");var h=d("adoptedCallback");var k=d("attributeChangedCallback");var l=b.observedAttributes||[]}catch(cf){return}finally{this.c= b[c],e=a.getAttribute(d);null!==e&&this.attributeChangedCallback(a,d,null,e,null)}u(a)&&this.connectedCallback(a)}}};B.prototype.connectedCallback=function(a){var b=a.__CE_definition;b.connectedCallback&&b.connectedCallback.call(a)};B.prototype.disconnectedCallback=function(a){var b=a.__CE_definition;b.disconnectedCallback&&b.disconnectedCallback.call(a)};B.prototype.attributeChangedCallback=function(a,b,c,d,e){var f=a.__CE_definition;f.attributeChangedCallback&&-1<f.observedAttributes.indexOf(b)&&
!1}b={localName:a,constructor:b,connectedCallback:f,disconnectedCallback:g,adoptedCallback:h,attributeChangedCallback:k,observedAttributes:l,constructionStack:[]};this.a.D(a,b);this.g.push(b);this.b||(this.b=!0,this.f(function(){return c.j()}))};x.prototype.j=function(){var a=this;if(!1!==this.b){this.b=!1;for(var b=this.g,c=[],d=new Map,e=0;e<b.length;e++)d.set(b[e].localName,[]);this.a.f(document,{Na:function(b){if(void 0===b.__CE_state){var e=b.localName,f=d.get(e);f?f.push(b):a.a.c(e)&&c.push(b)}}}); f.attributeChangedCallback.call(a,b,c,d,e)};Xa.prototype.c=function(){this.P&&this.P.disconnect()};Xa.prototype.f=function(a){var b=this.a.readyState;"interactive"!==b&&"complete"!==b||this.c();for(b=0;b<a.length;b++)for(var c=a[b].addedNodes,d=0;d<c.length;d++)this.b.f(c[d])};cc.prototype.resolve=function(a){if(this.a)throw Error("Already resolved.");this.a=a;this.b&&this.b(a)};y.prototype.define=function(a,b){var c=this;if(!(b instanceof Function))throw new TypeError("Custom element constructors must be functions.");
for(e=0;e<c.length;e++)this.a.i(c[e]);for(;0<b.length;){var f=b.shift();e=f.localName;f=d.get(f.localName);for(var g=0;g<f.length;g++)this.a.i(f[g]);(e=this.h.get(e))&&e.resolve(void 0)}}};x.prototype.get=function(a){if(a=this.a.c(a))return a.constructor};x.prototype.whenDefined=function(a){if(!ad(a))return Promise.reject(new SyntaxError("'"+a+"' is not a valid custom element name."));var b=this.h.get(a);if(b)return b.c;b=new Yb;this.h.set(a,b);this.a.c(a)&&!this.g.some(function(b){return b.localName=== if(!gd(a))throw new SyntaxError("The element name '"+a+"' is not valid.");if(this.a.c(a))throw Error("A custom element with name '"+a+"' has already been defined.");if(this.c)throw Error("A custom element is already being defined.");this.c=!0;try{var d=function(a){var b=e[a];if(void 0!==b&&!(b instanceof Function))throw Error("The '"+a+"' callback must be a function.");return b},e=b.prototype;if(!(e instanceof Object))throw new TypeError("The custom element constructor's prototype is not an object.");
a})&&b.resolve(void 0);return b.c};x.prototype.l=function(a){this.i.c();var b=this.f;this.f=function(c){return a(function(){return b(c)})}};window.CustomElementRegistry=x;x.prototype.define=x.prototype.define;x.prototype.get=x.prototype.get;x.prototype.whenDefined=x.prototype.whenDefined;x.prototype.polyfillWrapFlushCallback=x.prototype.l;var Na=window.Document.prototype.createElement,Td=window.Document.prototype.createElementNS,Sd=window.Document.prototype.importNode,Ud=window.Document.prototype.prepend, var f=d("connectedCallback");var g=d("disconnectedCallback");var k=d("adoptedCallback");var l=d("attributeChangedCallback");var q=b.observedAttributes||[]}catch(n){return}finally{this.c=!1}b={localName:a,constructor:b,connectedCallback:f,disconnectedCallback:g,adoptedCallback:k,attributeChangedCallback:l,observedAttributes:q,constructionStack:[]};this.a.D(a,b);this.g.push(b);this.b||(this.b=!0,this.f(function(){return c.j()}))};y.prototype.j=function(){var a=this;if(!1!==this.b){this.b=!1;for(var b=
Vd=window.Document.prototype.append,Nb=window.Node.prototype.cloneNode,qa=window.Node.prototype.appendChild,Vb=window.Node.prototype.insertBefore,Oa=window.Node.prototype.removeChild,Wb=window.Node.prototype.replaceChild,Qa=Object.getOwnPropertyDescriptor(window.Node.prototype,"textContent"),Mb=window.Element.prototype.attachShadow,La=Object.getOwnPropertyDescriptor(window.Element.prototype,"innerHTML"),Pa=window.Element.prototype.getAttribute,Ob=window.Element.prototype.setAttribute,Qb=window.Element.prototype.removeAttribute, this.g,c=[],d=new Map,e=0;e<b.length;e++)d.set(b[e].localName,[]);this.a.f(document,{Na:function(b){if(void 0===b.__CE_state){var e=b.localName,f=d.get(e);f?f.push(b):a.a.c(e)&&c.push(b)}}});for(e=0;e<c.length;e++)this.a.i(c[e]);for(;0<b.length;){var f=b.shift();e=f.localName;f=d.get(f.localName);for(var g=0;g<f.length;g++)this.a.i(f[g]);(e=this.h.get(e))&&e.resolve(void 0)}}};y.prototype.get=function(a){if(a=this.a.c(a))return a.constructor};y.prototype.whenDefined=function(a){if(!gd(a))return Promise.reject(new SyntaxError("'"+
ra=window.Element.prototype.getAttributeNS,Pb=window.Element.prototype.setAttributeNS,Rb=window.Element.prototype.removeAttributeNS,Tb=window.Element.prototype.insertAdjacentElement,Jd=window.Element.prototype.prepend,Kd=window.Element.prototype.append,Md=window.Element.prototype.before,Nd=window.Element.prototype.after,Od=window.Element.prototype.replaceWith,Pd=window.Element.prototype.remove,Xd=window.HTMLElement,Ma=Object.getOwnPropertyDescriptor(window.HTMLElement.prototype,"innerHTML"),Sb=window.HTMLElement.prototype.insertAdjacentElement, a+"' is not a valid custom element name."));var b=this.h.get(a);if(b)return b.c;b=new cc;this.h.set(a,b);this.a.c(a)&&!this.g.some(function(b){return b.localName===a})&&b.resolve(void 0);return b.c};y.prototype.l=function(a){this.i.c();var b=this.f;this.f=function(c){return a(function(){return b(c)})}};window.CustomElementRegistry=y;y.prototype.define=y.prototype.define;y.prototype.get=y.prototype.get;y.prototype.whenDefined=y.prototype.whenDefined;y.prototype.polyfillWrapFlushCallback=y.prototype.l;
Xb=new function(){},Da=window.customElements;if(!Da||Da.forcePolyfill||"function"!=typeof Da.define||"function"!=typeof Da.get){var na=new z;Wd(na);Rd(na);Qd(na);Id(na);document.__CE_hasRegistry=!0;var Pe=new x(na);Object.defineProperty(window,"customElements",{configurable:!0,enumerable:!0,value:Pe})}var L={STYLE_RULE:1,ha:7,MEDIA_RULE:4,ua:1E3},G={mb:/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,port:/@import[^;]*;/gim,Ea:/(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,Ia:/(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim, var Sa=window.Document.prototype.createElement,de=window.Document.prototype.createElementNS,ce=window.Document.prototype.importNode,ee=window.Document.prototype.prepend,fe=window.Document.prototype.append,af=window.DocumentFragment.prototype.prepend,bf=window.DocumentFragment.prototype.append,Tb=window.Node.prototype.cloneNode,ua=window.Node.prototype.appendChild,$b=window.Node.prototype.insertBefore,Ta=window.Node.prototype.removeChild,ac=window.Node.prototype.replaceChild,Wa=Object.getOwnPropertyDescriptor(window.Node.prototype,
sb:/@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,xb:/[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,rb:/^@[^\s]*keyframes/,Ja:/\s+/g},q=!(window.ShadyDOM&&window.ShadyDOM.inUse);if(window.ShadyCSS&&void 0!==window.ShadyCSS.nativeCss)var v=window.ShadyCSS.nativeCss;else window.ShadyCSS?(dd(window.ShadyCSS),window.ShadyCSS=void 0):dd(window.WebComponents&&window.WebComponents.flags);var Ea=/(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};{])+)|\{([^}]*)\}(?:(?=[;\s}])|$))/gi, "textContent"),Sb=window.Element.prototype.attachShadow,Qa=Object.getOwnPropertyDescriptor(window.Element.prototype,"innerHTML"),Ua=window.Element.prototype.getAttribute,Ub=window.Element.prototype.setAttribute,Wb=window.Element.prototype.removeAttribute,va=window.Element.prototype.getAttributeNS,Vb=window.Element.prototype.setAttributeNS,Xb=window.Element.prototype.removeAttributeNS,Zb=window.Element.prototype.insertAdjacentElement,Ud=window.Element.prototype.prepend,Vd=window.Element.prototype.append,
Fa=/(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,Qe=/(--[\w-]+)\s*([:,;)]|$)/gi,Re=/(animation\s*:)|(animation-name\s*:)/,Be=/@media\s(.*)/,Se=/\{[^}]*\}/g,S=null;r.prototype.a=function(a,b,c){a.__styleScoped?a.__styleScoped=null:this.i(a,b||"",c)};r.prototype.i=function(a,b,c){a.nodeType===Node.ELEMENT_NODE&&this.C(a,b,c);if(a="template"===a.localName?(a.content||a.Cb).childNodes:a.children||a.childNodes)for(var d=0;d<a.length;d++)this.i(a[d],b,c)};r.prototype.C=function(a,b,c){if(b)if(a.classList)c?(a.classList.remove("style-scope"), Xd=window.Element.prototype.before,Yd=window.Element.prototype.after,Zd=window.Element.prototype.replaceWith,$d=window.Element.prototype.remove,he=window.HTMLElement,Ra=Object.getOwnPropertyDescriptor(window.HTMLElement.prototype,"innerHTML"),Yb=window.HTMLElement.prototype.insertAdjacentElement,bc=new function(){},Ha=window.customElements;if(!Ha||Ha.forcePolyfill||"function"!=typeof Ha.define||"function"!=typeof Ha.get){var ia=new B;ge(ia);be(ia);Va(ia,DocumentFragment.prototype,{ea:af,append:bf});
a.classList.remove(b)):(a.classList.add("style-scope"),a.classList.add(b));else if(a.getAttribute){var d=a.getAttribute(Te);c?d&&(b=d.replace("style-scope","").replace(b,""),za(a,b)):za(a,(d?d+" ":"")+"style-scope "+b)}};r.prototype.b=function(a,b,c){var d=a.__cssBuild;q||"shady"===d?b=ba(b,c):(a=T(a),b=this.I(b,a.is,a.Z,c)+"\n\n");return b.trim()};r.prototype.I=function(a,b,c,d){var e=this.f(b,c);b=this.h(b);var f=this;return ba(a,function(a){a.c||(f.S(a,b,e),a.c=!0);d&&d(a,b,e)})};r.prototype.h= ae(ia);Td(ia);document.__CE_hasRegistry=!0;var cf=new y(ia);Object.defineProperty(window,"customElements",{configurable:!0,enumerable:!0,value:cf})}var M={STYLE_RULE:1,ja:7,MEDIA_RULE:4,wa:1E3},I={lb:/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,port:/@import[^;]*;/gim,Ga:/(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,Ka:/(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,rb:/@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,wb:/[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,qb:/^@[^\s]*keyframes/,La:/\s+/g},
function(a){return a?Ue+a:""};r.prototype.f=function(a,b){return b?"[is="+a+"]":a};r.prototype.S=function(a,b,c){this.j(a,this.g,b,c)};r.prototype.j=function(a,b,c,d){a.selector=a.A=this.l(a,b,c,d)};r.prototype.l=function(a,b,c,d){var e=a.selector.split(td);if(!ed(a)){a=0;for(var f=e.length,g;a<f&&(g=e[a]);a++)e[a]=b.call(this,g,c,d)}return e.join(td)};r.prototype.u=function(a){return a.replace(Db,function(a,c,d){-1<d.indexOf("+")?d=d.replace(/\+/g,"___"):-1<d.indexOf("___")&&(d=d.replace(/___/g, z=!(window.ShadyDOM&&window.ShadyDOM.inUse);if(window.ShadyCSS&&void 0!==window.ShadyCSS.nativeCss)var A=window.ShadyCSS.nativeCss;else window.ShadyCSS?(jd(window.ShadyCSS),window.ShadyCSS=void 0):jd(window.WebComponents&&window.WebComponents.flags);var Ia=/(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};{])+)|\{([^}]*)\}(?:(?=[;\s}])|$))/gi,Ja=/(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,df=/(--[\w-]+)\s*([:,;)]|$)/gi,ef=/(animation\s*:)|(animation-name\s*:)/,Me=/@media\s(.*)/,
"+"));return":"+c+"("+d+")"})};r.prototype.g=function(a,b,c){var d=this,e=!1;a=a.trim();var f=Db.test(a);f&&(a=a.replace(Db,function(a,b,c){return":"+b+"("+c.replace(/\s/g,"")+")"}),a=this.u(a));a=a.replace(Ve,Eb+" $1");a=a.replace(We,function(a,f,k){e||(a=d.D(k,f,b,c),e=e||a.stop,f=a.lb,k=a.value);return f+k});f&&(a=this.u(a));return a};r.prototype.D=function(a,b,c,d){var e=a.indexOf(Fb);0<=a.indexOf(Eb)?a=this.H(a,d):0!==e&&(a=c?this.s(a,c):a);c=!1;0<=e&&(b="",c=!0);if(c){var f=!0;c&&(a=a.replace(Xe, ff=/\{[^}]*\}/g,V=null;v.prototype.b=function(a,b,c){a.__styleScoped?a.__styleScoped=null:this.j(a,b||"",c)};v.prototype.j=function(a,b,c){a.nodeType===Node.ELEMENT_NODE&&this.h(a,b,c);if(a="template"===a.localName?(a.content||a.Cb).childNodes:a.children||a.childNodes)for(var d=0;d<a.length;d++)this.j(a[d],b,c)};v.prototype.h=function(a,b,c){if(b)if(a.classList)c?(a.classList.remove("style-scope"),a.classList.remove(b)):(a.classList.add("style-scope"),a.classList.add(b));else if(a.getAttribute){var d=
function(a,b){return" > "+b}))}a=a.replace(Ye,function(a,b,c){return'[dir="'+c+'"] '+b+", "+b+'[dir="'+c+'"]'});return{value:a,lb:b,stop:f}};r.prototype.s=function(a,b){a=a.split(ud);a[0]+=b;return a.join(ud)};r.prototype.H=function(a,b){var c=a.match(vd);return(c=c&&c[2].trim()||"")?c[0].match(wd)?a.replace(vd,function(a,c,f){return b+f}):c.split(wd)[0]===b?c:Ze:a.replace(Eb,b)};r.prototype.R=function(a){a.selector=a.parsedSelector;this.v(a);this.j(a,this.L)};r.prototype.v=function(a){a.selector=== a.getAttribute(gf);c?d&&(b=d.replace("style-scope","").replace(b,""),Da(a,b)):Da(a,(d?d+" ":"")+"style-scope "+b)}};v.prototype.c=function(a,b,c){var d=a.__cssBuild;z||"shady"===d?b=ea(b,c):(a=W(a),b=this.I(b,a.is,a.$,c)+"\n\n");return b.trim()};v.prototype.I=function(a,b,c,d){var e=this.f(b,c);b=this.i(b);var f=this;return ea(a,function(a){a.c||(f.K(a,b,e),a.c=!0);d&&d(a,b,e)})};v.prototype.i=function(a){return a?hf+a:""};v.prototype.f=function(a,b){return b?"[is="+a+"]":a};v.prototype.K=function(a,
$e&&(a.selector="html")};r.prototype.L=function(a){return a.match(Fb)?this.g(a,xd):this.s(a.trim(),xd)};Jb.Object.defineProperties(r.prototype,{c:{configurable:!0,enumerable:!0,get:function(){return"style-scope"}}});var Db=/:(nth[-\w]+)\(([^)]+)\)/,xd=":not(.style-scope)",td=",",We=/(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=[])+)/g,wd=/[[.:#*]/,Eb=":host",$e=":root",Fb="::slotted",Ve=new RegExp("^("+Fb+")"),vd=/(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,Xe=/(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,Ye= b,c){this.l(a,this.g,b,c)};v.prototype.l=function(a,b,c,d){a.selector=a.A=this.s(a,b,c,d)};v.prototype.s=function(a,b,c,d){var e=a.selector.split(zd);if(!kd(a)){a=0;for(var f=e.length,g;a<f&&(g=e[a]);a++)e[a]=b.call(this,g,c,d)}return e.join(zd)};v.prototype.v=function(a){return a.replace(Jb,function(a,c,d){-1<d.indexOf("+")?d=d.replace(/\+/g,"___"):-1<d.indexOf("___")&&(d=d.replace(/___/g,"+"));return":"+c+"("+d+")"})};v.prototype.g=function(a,b,c){var d=this,e=!1;a=a.trim();var f=Jb.test(a);f&&
/(.*):dir\((?:(ltr|rtl))\)/,Ue=".",ud=":",Te="class",Ze="should_not_match",w=new r;t.get=function(a){return a?a.__styleInfo:null};t.set=function(a,b){return a.__styleInfo=b};t.prototype.c=function(){return this.G};t.prototype._getStyleRules=t.prototype.c;var yd=function(a){return a.matches||a.matchesSelector||a.mozMatchesSelector||a.msMatchesSelector||a.oMatchesSelector||a.webkitMatchesSelector}(window.Element.prototype),af=navigator.userAgent.match("Trident");p.prototype.R=function(a){var b=this, (a=a.replace(Jb,function(a,b,c){return":"+b+"("+c.replace(/\s/g,"")+")"}),a=this.v(a));a=a.replace(jf,Kb+" $1");a=a.replace(kf,function(a,f,g){e||(a=d.D(g,f,b,c),e=e||a.stop,f=a.kb,g=a.value);return f+g});f&&(a=this.v(a));return a};v.prototype.D=function(a,b,c,d){var e=a.indexOf(Lb);0<=a.indexOf(Kb)?a=this.H(a,d):0!==e&&(a=c?this.u(a,c):a);c=!1;0<=e&&(b="",c=!0);if(c){var f=!0;c&&(a=a.replace(lf,function(a,b){return" > "+b}))}a=a.replace(mf,function(a,b,c){return'[dir="'+c+'"] '+b+", "+b+'[dir="'+
c={},d=[],e=0;ca(a,function(a){b.c(a);a.index=e++;b.I(a.w.cssText,c)},function(a){d.push(a)});a.b=d;a=[];for(var f in c)a.push(f);return a};p.prototype.c=function(a){if(!a.w){var b={},c={};this.b(a,c)&&(b.F=c,a.rules=null);b.cssText=this.H(a);a.w=b}};p.prototype.b=function(a,b){var c=a.w;if(c){if(c.F)return Object.assign(b,c.F),!0}else{c=a.parsedCssText;for(var d;a=Ea.exec(c);){d=(a[2]||a[3]).trim();if("inherit"!==d||"unset"!==d)b[a[1].trim()]=d;d=!0}return d}};p.prototype.H=function(a){return this.L(a.parsedCssText)}; c+'"]'});return{value:a,kb:b,stop:f}};v.prototype.u=function(a,b){a=a.split(Ad);a[0]+=b;return a.join(Ad)};v.prototype.H=function(a,b){var c=a.match(Bd);return(c=c&&c[2].trim()||"")?c[0].match(Cd)?a.replace(Bd,function(a,c,f){return b+f}):c.split(Cd)[0]===b?c:nf:a.replace(Kb,b)};v.prototype.J=function(a){a.selector=a.parsedSelector;this.B(a);this.l(a,this.N)};v.prototype.B=function(a){a.selector===of&&(a.selector="html")};v.prototype.N=function(a){return a.match(Lb)?this.g(a,Dd):this.u(a.trim(),Dd)};
p.prototype.L=function(a){return a.replace(Se,"").replace(Ea,"")};p.prototype.I=function(a,b){for(var c;c=Qe.exec(a);){var d=c[1];":"!==c[2]&&(b[d]=!0)}};p.prototype.ea=function(a){for(var b=Object.getOwnPropertyNames(a),c=0,d;c<b.length;c++)d=b[c],a[d]=this.a(a[d],a)};p.prototype.a=function(a,b){if(a)if(0<=a.indexOf(";"))a=this.f(a,b);else{var c=this;a=gd(a,function(a,e,f,g){if(!e)return a+g;(e=c.a(b[e],b))&&"initial"!==e?"apply-shim-inherit"===e&&(e="inherit"):e=c.a(b[f]||f,b)||f;return a+(e||"")+ N.Object.defineProperties(v.prototype,{a:{configurable:!0,enumerable:!0,get:function(){return"style-scope"}}});var Jb=/:(nth[-\w]+)\(([^)]+)\)/,Dd=":not(.style-scope)",zd=",",kf=/(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=[])+)/g,Cd=/[[.:#*]/,Kb=":host",of=":root",Lb="::slotted",jf=new RegExp("^("+Lb+")"),Bd=/(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,lf=/(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,mf=/(.*):dir\((?:(ltr|rtl))\)/,hf=".",Ad=":",gf="class",nf="should_not_match",r=new v;w.get=function(a){return a?
g})}return a&&a.trim()||""};p.prototype.f=function(a,b){a=a.split(";");for(var c=0,d,e;c<a.length;c++)if(d=a[c]){Fa.lastIndex=0;if(e=Fa.exec(d))d=this.a(b[e[1]],b);else if(e=d.indexOf(":"),-1!==e){var f=d.substring(e);f=f.trim();f=this.a(f,b)||f;d=d.substring(0,e)+f}a[c]=d&&d.lastIndexOf(";")===d.length-1?d.slice(0,-1):d||""}return a.join(";")};p.prototype.D=function(a,b){var c="";a.w||this.c(a);a.w.cssText&&(c=this.f(a.w.cssText,b));a.cssText=c};p.prototype.C=function(a,b){var c=a.cssText,d=a.cssText; a.__styleInfo:null};w.set=function(a,b){return a.__styleInfo=b};w.prototype.c=function(){return this.G};w.prototype._getStyleRules=w.prototype.c;var Ed=function(a){return a.matches||a.matchesSelector||a.mozMatchesSelector||a.msMatchesSelector||a.oMatchesSelector||a.webkitMatchesSelector}(window.Element.prototype),pf=navigator.userAgent.match("Trident");p.prototype.J=function(a){var b=this,c={},d=[],e=0;fa(a,function(a){b.c(a);a.index=e++;b.I(a.w.cssText,c)},function(a){d.push(a)});a.b=d;a=[];for(var f in c)a.push(f);
null==a.Ga&&(a.Ga=Re.test(c));if(a.Ga)if(null==a.ca){a.ca=[];for(var e in b)d=b[e],d=d(c),c!==d&&(c=d,a.ca.push(e))}else{for(e=0;e<a.ca.length;++e)d=b[a.ca[e]],c=d(c);d=c}a.cssText=d};p.prototype.da=function(a,b){var c={},d=this,e=[];ca(a,function(a){a.w||d.c(a);var f=a.A||a.parsedSelector;b&&a.w.F&&f&&yd.call(b,f)&&(d.b(a,c),a=a.index,f=parseInt(a/32,10),e[f]=(e[f]||0)|1<<a%32)},null,!0);return{F:c,key:e}};p.prototype.ga=function(a,b,c,d){b.w||this.c(b);if(b.w.F){var e=T(a);a=e.is;e=e.Z;e=a?w.f(a, return a};p.prototype.c=function(a){if(!a.w){var b={},c={};this.b(a,c)&&(b.F=c,a.rules=null);b.cssText=this.H(a);a.w=b}};p.prototype.b=function(a,b){var c=a.w;if(c){if(c.F)return Object.assign(b,c.F),!0}else{c=a.parsedCssText;for(var d;a=Ia.exec(c);){d=(a[2]||a[3]).trim();if("inherit"!==d||"unset"!==d)b[a[1].trim()]=d;d=!0}return d}};p.prototype.H=function(a){return this.N(a.parsedCssText)};p.prototype.N=function(a){return a.replace(ff,"").replace(Ia,"")};p.prototype.I=function(a,b){for(var c;c=df.exec(a);){var d=
e):"html";var f=b.parsedSelector,g=":host > *"===f||"html"===f,h=0===f.indexOf(":host")&&!g;"shady"===c&&(g=f===e+" > *."+e||-1!==f.indexOf("html"),h=!g&&0===f.indexOf(e));"shadow"===c&&(g=":host > *"===f||"html"===f,h=h&&!g);if(g||h)c=e,h&&(q&&!b.A&&(b.A=w.l(b,w.g,w.h(a),e)),c=b.A||e),d({wb:c,qb:h,Fb:g})}};p.prototype.S=function(a,b){var c={},d={},e=this,f=b&&b.__cssBuild;ca(b,function(b){e.ga(a,b,f,function(f){yd.call(a.Db||a,f.wb)&&(f.qb?e.b(b,c):e.b(b,d))})},null,!0);return{ub:d,pb:c}};p.prototype.fa= c[1];":"!==c[2]&&(b[d]=!0)}};p.prototype.ga=function(a){for(var b=Object.getOwnPropertyNames(a),c=0,d;c<b.length;c++)d=b[c],a[d]=this.a(a[d],a)};p.prototype.a=function(a,b){if(a)if(0<=a.indexOf(";"))a=this.f(a,b);else{var c=this;a=md(a,function(a,e,f,g){if(!e)return a+g;(e=c.a(b[e],b))&&"initial"!==e?"apply-shim-inherit"===e&&(e="inherit"):e=c.a(b[f]||f,b)||f;return a+(e||"")+g})}return a&&a.trim()||""};p.prototype.f=function(a,b){a=a.split(";");for(var c=0,d,e;c<a.length;c++)if(d=a[c]){Ja.lastIndex=
function(a,b,c){var d=this,e=T(a),f=w.f(e.is,e.Z),g=new RegExp("(?:^|[^.#[:])"+(a.extends?"\\"+f.slice(0,-1)+"\\]":f)+"($|[.:[\\s>+~])");e=t.get(a).G;var h=this.h(e,c);return w.b(a,e,function(a){d.D(a,b);q||ed(a)||!a.cssText||(d.C(a,h),d.l(a,g,f,c))})};p.prototype.h=function(a,b){a=a.b;var c={};if(!q&&a)for(var d=0,e=a[d];d<a.length;e=a[++d])this.j(e,b),c[e.keyframesName]=this.i(e);return c};p.prototype.i=function(a){return function(b){return b.replace(a.f,a.a)}};p.prototype.j=function(a,b){a.f=new RegExp(a.keyframesName, 0;if(e=Ja.exec(d))d=this.a(b[e[1]],b);else if(e=d.indexOf(":"),-1!==e){var f=d.substring(e);f=f.trim();f=this.a(f,b)||f;d=d.substring(0,e)+f}a[c]=d&&d.lastIndexOf(";")===d.length-1?d.slice(0,-1):d||""}return a.join(";")};p.prototype.D=function(a,b){var c="";a.w||this.c(a);a.w.cssText&&(c=this.f(a.w.cssText,b));a.cssText=c};p.prototype.B=function(a,b){var c=a.cssText,d=a.cssText;null==a.Ia&&(a.Ia=ef.test(c));if(a.Ia)if(null==a.da){a.da=[];for(var e in b)d=b[e],d=d(c),c!==d&&(c=d,a.da.push(e))}else{for(e=
"g");a.a=a.keyframesName+"-"+b;a.A=a.A||a.selector;a.selector=a.A.replace(a.keyframesName,a.a)};p.prototype.l=function(a,b,c,d){a.A=a.A||a.selector;d="."+d;for(var e=a.A.split(","),f=0,g=e.length,h;f<g&&(h=e[f]);f++)e[f]=h.match(b)?h.replace(c,d):d+" "+h;a.selector=e.join(",")};p.prototype.u=function(a,b,c){var d=a.getAttribute("class")||"",e=d;c&&(e=d.replace(new RegExp("\\s*x-scope\\s*"+c+"\\s*","g")," "));e+=(e?" ":"")+"x-scope "+b;d!==e&&za(a,e)};p.prototype.v=function(a,b,c,d){b=d?d.textContent|| 0;e<a.da.length;++e)d=b[a.da[e]],c=d(c);d=c}a.cssText=d};p.prototype.T=function(a,b){var c={},d=this,e=[];fa(a,function(a){a.w||d.c(a);var f=a.A||a.parsedSelector;b&&a.w.F&&f&&Ed.call(b,f)&&(d.b(a,c),a=a.index,f=parseInt(a/32,10),e[f]=(e[f]||0)|1<<a%32)},null,!0);return{F:c,key:e}};p.prototype.ia=function(a,b,c,d){b.w||this.c(b);if(b.w.F){var e=W(a);a=e.is;e=e.$;e=a?r.f(a,e):"html";var f=b.parsedSelector,g=":host > *"===f||"html"===f,k=0===f.indexOf(":host")&&!g;"shady"===c&&(g=f===e+" > *."+e||-1!==
"":this.fa(a,b,c);var e=t.get(a),f=e.a;f&&!q&&f!==d&&(f._useCount--,0>=f._useCount&&f.parentNode&&f.parentNode.removeChild(f));q?e.a?(e.a.textContent=b,d=e.a):b&&(d=ub(b,c,a.shadowRoot,e.b)):d?d.parentNode||(af&&-1<b.indexOf("@media")&&(d.textContent=b),fd(d,null,e.b)):b&&(d=ub(b,c,null,e.b));d&&(d._useCount=d._useCount||0,e.a!=d&&d._useCount++,e.a=d);return d};p.prototype.s=function(a,b){var c=ya(a),d=this;a.textContent=ba(c,function(a){var c=a.cssText=a.parsedCssText;a.w&&a.w.cssText&&(c=c.replace(G.Ea, f.indexOf("html"),k=!g&&0===f.indexOf(e));"shadow"===c&&(g=":host > *"===f||"html"===f,k=k&&!g);if(g||k)c=e,k&&(z&&!b.A&&(b.A=r.s(b,r.g,r.i(a),e)),c=b.A||e),d({vb:c,pb:k,Gb:g})}};p.prototype.K=function(a,b){var c={},d={},e=this,f=b&&b.__cssBuild;fa(b,function(b){e.ia(a,b,f,function(f){Ed.call(a.Db||a,f.vb)&&(f.pb?e.b(b,c):e.b(b,d))})},null,!0);return{tb:d,ob:c}};p.prototype.ha=function(a,b,c){var d=this,e=W(a),f=r.f(e.is,e.$),g=new RegExp("(?:^|[^.#[:])"+(a.extends?"\\"+f.slice(0,-1)+"\\]":f)+"($|[.:[\\s>+~])");
"").replace(G.Ia,""),a.cssText=d.f(c,b))})};Jb.Object.defineProperties(p.prototype,{g:{configurable:!0,enumerable:!0,get:function(){return"x-scope"}}});var O=new p,Gb={},Ga=window.customElements;if(Ga&&!q){var bf=Ga.define;Ga.define=function(a,b,c){var d=document.createComment(" Shady DOM styles for "+a+" "),e=document.head;e.insertBefore(d,(S?S.nextSibling:null)||e.firstChild);S=d;Gb[a]=d;return bf.call(Ga,a,b,c)}}pa.prototype.a=function(a,b,c){for(var d=0;d<c.length;d++){var e=c[d];if(a.F[e]!== e=w.get(a).G;var k=this.h(e,c);return r.c(a,e,function(a){d.D(a,b);z||kd(a)||!a.cssText||(d.B(a,k),d.l(a,g,f,c))})};p.prototype.h=function(a,b){a=a.b;var c={};if(!z&&a)for(var d=0,e=a[d];d<a.length;e=a[++d])this.j(e,b),c[e.keyframesName]=this.i(e);return c};p.prototype.i=function(a){return function(b){return b.replace(a.f,a.a)}};p.prototype.j=function(a,b){a.f=new RegExp(a.keyframesName,"g");a.a=a.keyframesName+"-"+b;a.A=a.A||a.selector;a.selector=a.A.replace(a.keyframesName,a.a)};p.prototype.l=function(a,
b[e])return!1}return!0};pa.prototype.b=function(a,b,c,d){var e=this.cache[a]||[];e.push({F:b,styleElement:c,B:d});e.length>this.c&&e.shift();this.cache[a]=e};pa.prototype.fetch=function(a,b,c){if(a=this.cache[a])for(var d=a.length-1;0<=d;d--){var e=a[d];if(this.a(e,b,c))return e}};if(!q){var zd=new MutationObserver(hd),Ad=function(a){zd.observe(a,{childList:!0,subtree:!0})};if(window.customElements&&!window.customElements.polyfillWrapFlushCallback)Ad(document);else{var Hb=function(){Ad(document.body)}; b,c,d){a.A=a.A||a.selector;d="."+d;for(var e=a.A.split(","),f=0,g=e.length,k;f<g&&(k=e[f]);f++)e[f]=k.match(b)?k.replace(c,d):d+" "+k;a.selector=e.join(",")};p.prototype.u=function(a,b,c){var d=a.getAttribute("class")||"",e=d;c&&(e=d.replace(new RegExp("\\s*x-scope\\s*"+c+"\\s*","g")," "));e+=(e?" ":"")+"x-scope "+b;d!==e&&Da(a,e)};p.prototype.v=function(a,b,c,d){b=d?d.textContent||"":this.ha(a,b,c);var e=w.get(a),f=e.a;f&&!z&&f!==d&&(f._useCount--,0>=f._useCount&&f.parentNode&&f.parentNode.removeChild(f));
window.HTMLImports?window.HTMLImports.whenReady(Hb):requestAnimationFrame(function(){if("loading"===document.readyState){var a=function(){Hb();document.removeEventListener("readystatechange",a)};document.addEventListener("readystatechange",a)}else Hb()})}Lb=function(){hd(zd.takeRecords())}}var Aa={},Ee=Promise.resolve(),vb=null,jd=window.HTMLImports&&window.HTMLImports.whenReady||null,wb,Ha=null,oa=null;F.prototype.Fa=function(){!this.enqueued&&oa&&(this.enqueued=!0,Kb(oa))};F.prototype.b=function(a){a.__seenByShadyCSS|| z?e.a?(e.a.textContent=b,d=e.a):b&&(d=Ab(b,c,a.shadowRoot,e.b)):d?d.parentNode||(pf&&-1<b.indexOf("@media")&&(d.textContent=b),ld(d,null,e.b)):b&&(d=Ab(b,c,null,e.b));d&&(d._useCount=d._useCount||0,e.a!=d&&d._useCount++,e.a=d);return d};p.prototype.s=function(a,b){var c=Ca(a),d=this;a.textContent=ea(c,function(a){var c=a.cssText=a.parsedCssText;a.w&&a.w.cssText&&(c=c.replace(I.Ga,"").replace(I.Ka,""),a.cssText=d.f(c,b))})};N.Object.defineProperties(p.prototype,{g:{configurable:!0,enumerable:!0,get:function(){return"x-scope"}}});
(a.__seenByShadyCSS=!0,this.customStyles.push(a),this.Fa())};F.prototype.a=function(a){return a.__shadyCSSCachedStyle?a.__shadyCSSCachedStyle:a.getStyle?a.getStyle():a};F.prototype.c=function(){for(var a=this.customStyles,b=0;b<a.length;b++){var c=a[b];if(!c.__shadyCSSCachedStyle){var d=this.a(c);d&&(d=d.__appliedElement||d,Ha&&Ha(d),c.__shadyCSSCachedStyle=d)}}return a};F.prototype.addCustomStyle=F.prototype.b;F.prototype.getStyleForCustomStyle=F.prototype.a;F.prototype.processStyles=F.prototype.c; var Q=new p,Mb={},Ka=window.customElements;if(Ka&&!z){var qf=Ka.define;Ka.define=function(a,b,c){var d=document.createComment(" Shady DOM styles for "+a+" "),e=document.head;e.insertBefore(d,(V?V.nextSibling:null)||e.firstChild);V=d;Mb[a]=d;return qf.call(Ka,a,b,c)}}ta.prototype.a=function(a,b,c){for(var d=0;d<c.length;d++){var e=c[d];if(a.F[e]!==b[e])return!1}return!0};ta.prototype.b=function(a,b,c,d){var e=this.cache[a]||[];e.push({F:b,styleElement:c,C:d});e.length>this.c&&e.shift();this.cache[a]=
Object.defineProperties(F.prototype,{transformCallback:{get:function(){return Ha},set:function(a){Ha=a}},validateCallback:{get:function(){return oa},set:function(a){var b=!1;oa||(b=!0);oa=a;b&&this.Fa()}}});var Bd=new pa;k.prototype.C=function(){Lb()};k.prototype.S=function(a){var b=this.s[a]=(this.s[a]||0)+1;return a+"-"+b};k.prototype.Ra=function(a){return ya(a)};k.prototype.Ta=function(a){return ba(a)};k.prototype.R=function(a){a=a.content.querySelectorAll("style");for(var b=[],c=0;c<a.length;c++){var d= e};ta.prototype.fetch=function(a,b,c){if(a=this.cache[a])for(var d=a.length-1;0<=d;d--){var e=a[d];if(this.a(e,b,c))return e}};if(!z){var Fd=new MutationObserver(nd),Gd=function(a){Fd.observe(a,{childList:!0,subtree:!0})};if(window.customElements&&!window.customElements.polyfillWrapFlushCallback)Gd(document);else{var Nb=function(){Gd(document.body)};window.HTMLImports?window.HTMLImports.whenReady(Nb):requestAnimationFrame(function(){if("loading"===document.readyState){var a=function(){Nb();document.removeEventListener("readystatechange",
a[c];b.push(d.textContent);d.parentNode.removeChild(d)}return b.join("").trim()};k.prototype.ea=function(a){return(a=a.content.querySelector("style"))?a.getAttribute("css-build")||"":""};k.prototype.prepareTemplate=function(a,b,c){if(!a.f){a.f=!0;a.name=b;a.extends=c;Aa[b]=a;var d=this.ea(a),e=this.R(a);c={is:b,extends:c,Ab:d};q||w.a(a.content,b);this.c();var f=Fa.test(e)||Ea.test(e);Fa.lastIndex=0;Ea.lastIndex=0;e=tb(e);f&&v&&this.a&&this.a.transformRules(e,b);a._styleAst=e;a.g=d;d=[];v||(d=O.R(a._styleAst)); a)};document.addEventListener("readystatechange",a)}else Nb()})}R=function(){nd(Fd.takeRecords())}}var Ea={},Pe=Promise.resolve(),Bb=null,pd=window.HTMLImports&&window.HTMLImports.whenReady||null,Cb,La=null,sa=null;t.prototype.Ha=function(){!this.enqueued&&sa&&(this.enqueued=!0,Rb(sa))};t.prototype.b=function(a){a.__seenByShadyCSS||(a.__seenByShadyCSS=!0,this.customStyles.push(a),this.Ha())};t.prototype.a=function(a){return a.__shadyCSSCachedStyle?a.__shadyCSSCachedStyle:a.getStyle?a.getStyle():a};
if(!d.length||v)b=this.da(c,a._styleAst,q?a.content:null,Gb[b]),a.a=b;a.c=d}};k.prototype.da=function(a,b,c,d){b=w.b(a,b);if(b.length)return ub(b,a.is,c,d)};k.prototype.ga=function(a){var b=T(a),c=b.is;b=b.Z;var d=Gb[c];c=Aa[c];if(c){var e=c._styleAst;var f=c.c}return t.set(a,new t(e,d,f,0,b))};k.prototype.H=function(){!this.a&&window.ShadyCSS&&window.ShadyCSS.ApplyShim&&(this.a=window.ShadyCSS.ApplyShim,this.a.invalidCallback=Ce)};k.prototype.I=function(){var a=this;!this.b&&window.ShadyCSS&&window.ShadyCSS.CustomStyleInterface&& t.prototype.c=function(){for(var a=this.customStyles,b=0;b<a.length;b++){var c=a[b];if(!c.__shadyCSSCachedStyle){var d=this.a(c);d&&(d=d.__appliedElement||d,La&&La(d),c.__shadyCSSCachedStyle=d)}}return a};t.prototype.addCustomStyle=t.prototype.b;t.prototype.getStyleForCustomStyle=t.prototype.a;t.prototype.processStyles=t.prototype.c;Object.defineProperties(t.prototype,{transformCallback:{get:function(){return La},set:function(a){La=a}},validateCallback:{get:function(){return sa},set:function(a){var b=
(this.b=window.ShadyCSS.CustomStyleInterface,this.b.transformCallback=function(b){a.v(b)},this.b.validateCallback=function(){requestAnimationFrame(function(){(a.b.enqueued||a.i)&&a.f()})})};k.prototype.c=function(){this.H();this.I()};k.prototype.f=function(){this.c();if(this.b){var a=this.b.processStyles();this.b.enqueued&&(v?this.Pa(a):(this.u(this.g,this.h),this.D(a)),this.b.enqueued=!1,this.i&&!v&&this.styleDocument())}};k.prototype.styleElement=function(a,b){var c=T(a).is,d=t.get(a);d||(d=this.ga(a)); !1;sa||(b=!0);sa=a;b&&this.Ha()}}});var Hd=new ta;g.prototype.B=function(){R()};g.prototype.K=function(a){var b=this.s[a]=(this.s[a]||0)+1;return a+"-"+b};g.prototype.Ra=function(a){return Ca(a)};g.prototype.Ta=function(a){return ea(a)};g.prototype.J=function(a){a=a.content.querySelectorAll("style");for(var b=[],c=0;c<a.length;c++){var d=a[c];b.push(d.textContent);d.parentNode.removeChild(d)}return b.join("").trim()};g.prototype.ga=function(a){return(a=a.content.querySelector("style"))?a.getAttribute("css-build")||
this.j(a)||(this.i=!0);b&&(d.P=d.P||{},Object.assign(d.P,b));if(v){if(d.P){b=d.P;for(var e in b)null===e?a.style.removeProperty(e):a.style.setProperty(e,b[e])}if(((e=Aa[c])||this.j(a))&&e&&e.a&&!id(e)){if(id(e)||e._applyShimValidatingVersion!==e._applyShimNextVersion)this.c(),this.a&&this.a.transformRules(e._styleAst,c),e.a.textContent=w.b(a,d.G),De(e);q&&(c=a.shadowRoot)&&(c.querySelector("style").textContent=w.b(a,d.G));d.G=e._styleAst}}else this.u(a,d),d.ra&&d.ra.length&&this.L(a,d)};k.prototype.l= "":""};g.prototype.prepareTemplate=function(a,b,c){if(!a.f){a.f=!0;a.name=b;a.extends=c;Ea[b]=a;var d=this.ga(a),e=this.J(a);c={is:b,extends:c,zb:d};z||r.b(a.content,b);this.c();var f=Ja.test(e)||Ia.test(e);Ja.lastIndex=0;Ia.lastIndex=0;e=zb(e);f&&A&&this.a&&this.a.transformRules(e,b);a._styleAst=e;a.g=d;d=[];A||(d=Q.J(a._styleAst));if(!d.length||A)b=this.T(c,a._styleAst,z?a.content:null,Mb[b]),a.a=b;a.c=d}};g.prototype.T=function(a,b,c,d){b=r.c(a,b);if(b.length)return Ab(b,a.is,c,d)};g.prototype.ia=
function(a){return(a=a.getRootNode().host)?t.get(a)?a:this.l(a):this.g};k.prototype.j=function(a){return a===this.g};k.prototype.L=function(a,b){var c=T(a).is,d=Bd.fetch(c,b.K,b.ra),e=d?d.styleElement:null,f=b.B;b.B=d&&d.B||this.S(c);e=O.v(a,b.K,b.B,e);q||O.u(a,b.B,f);d||Bd.b(c,b.K,e,b.B)};k.prototype.u=function(a,b){var c=this.l(a),d=t.get(c);c=Object.create(d.K||null);var e=O.S(a,b.G);a=O.da(d.G,a).F;Object.assign(c,e.pb,a,e.ub);this.fa(c,b.P);O.ea(c);b.K=c};k.prototype.fa=function(a,b){for(var c in b){var d= function(a){var b=W(a),c=b.is;b=b.$;var d=Mb[c];c=Ea[c];if(c){var e=c._styleAst;var f=c.c}return w.set(a,new w(e,d,f,0,b))};g.prototype.H=function(){!this.a&&window.ShadyCSS&&window.ShadyCSS.ApplyShim&&(this.a=window.ShadyCSS.ApplyShim,this.a.invalidCallback=Ne)};g.prototype.I=function(){var a=this;!this.b&&window.ShadyCSS&&window.ShadyCSS.CustomStyleInterface&&(this.b=window.ShadyCSS.CustomStyleInterface,this.b.transformCallback=function(b){a.v(b)},this.b.validateCallback=function(){requestAnimationFrame(function(){(a.b.enqueued||
b[c];if(d||0===d)a[c]=d}};k.prototype.styleDocument=function(a){this.styleSubtree(this.g,a)};k.prototype.styleSubtree=function(a,b){var c=a.shadowRoot;(c||this.j(a))&&this.styleElement(a,b);if(b=c&&(c.children||c.childNodes))for(a=0;a<b.length;a++)this.styleSubtree(b[a]);else if(a=a.children||a.childNodes)for(b=0;b<a.length;b++)this.styleSubtree(a[b])};k.prototype.Pa=function(a){for(var b=0;b<a.length;b++){var c=this.b.getStyleForCustomStyle(a[b]);c&&this.Oa(c)}};k.prototype.D=function(a){for(var b= a.i)&&a.f()})})};g.prototype.c=function(){this.H();this.I()};g.prototype.f=function(){this.c();if(this.b){var a=this.b.processStyles();this.b.enqueued&&(A?this.Pa(a):(this.u(this.g,this.h),this.D(a)),this.b.enqueued=!1,this.i&&!A&&this.styleDocument())}};g.prototype.styleElement=function(a,b){var c=W(a).is,d=w.get(a);d||(d=this.ia(a));this.j(a)||(this.i=!0);b&&(d.S=d.S||{},Object.assign(d.S,b));if(A){if(d.S){b=d.S;for(var e in b)null===e?a.style.removeProperty(e):a.style.setProperty(e,b[e])}if(((e=
0;b<a.length;b++){var c=this.b.getStyleForCustomStyle(a[b]);c&&O.s(c,this.h.K)}};k.prototype.v=function(a){var b=this,c=ya(a);ca(c,function(a){q?w.v(a):w.R(a);v&&(b.c(),b.a&&b.a.transformRule(a))});v?a.textContent=ba(c):this.h.G.rules.push(c)};k.prototype.Oa=function(a){if(v&&this.a){var b=ya(a);this.c();this.a.transformRules(b);a.textContent=ba(b)}};k.prototype.getComputedStyleValue=function(a,b){var c;v||(c=(t.get(a)||t.get(this.l(a))).K[b]);return(c=c||window.getComputedStyle(a).getPropertyValue(b))? Ea[c])||this.j(a))&&e&&e.a&&!od(e)){if(od(e)||e._applyShimValidatingVersion!==e._applyShimNextVersion)this.c(),this.a&&this.a.transformRules(e._styleAst,c),e.a.textContent=r.c(a,d.G),Oe(e);z&&(c=a.shadowRoot)&&(c.querySelector("style").textContent=r.c(a,d.G));d.G=e._styleAst}}else this.u(a,d),d.ua&&d.ua.length&&this.N(a,d)};g.prototype.l=function(a){return(a=a.getRootNode().host)?w.get(a)?a:this.l(a):this.g};g.prototype.j=function(a){return a===this.g};g.prototype.N=function(a,b){var c=W(a).is,d=
c.trim():""};k.prototype.Sa=function(a,b){var c=a.getRootNode();b=b?b.split(/\s/):[];c=c.host&&c.host.localName;if(!c){var d=a.getAttribute("class");if(d){d=d.split(/\s/);for(var e=0;e<d.length;e++)if(d[e]===w.c){c=d[e+1];break}}}c&&b.push(w.c,c);v||(c=t.get(a))&&c.B&&b.push(O.g,c.B);za(a,b.join(" "))};k.prototype.Qa=function(a){return t.get(a)};k.prototype.flush=k.prototype.C;k.prototype.prepareTemplate=k.prototype.prepareTemplate;k.prototype.styleElement=k.prototype.styleElement;k.prototype.styleDocument= Hd.fetch(c,b.M,b.ua),e=d?d.styleElement:null,f=b.C;b.C=d&&d.C||this.K(c);e=Q.v(a,b.M,b.C,e);z||Q.u(a,b.C,f);d||Hd.b(c,b.M,e,b.C)};g.prototype.u=function(a,b){var c=this.l(a),d=w.get(c);c=Object.create(d.M||null);var e=Q.K(a,b.G);a=Q.T(d.G,a).F;Object.assign(c,e.ob,a,e.tb);this.ha(c,b.S);Q.ga(c);b.M=c};g.prototype.ha=function(a,b){for(var c in b){var d=b[c];if(d||0===d)a[c]=d}};g.prototype.styleDocument=function(a){this.styleSubtree(this.g,a)};g.prototype.styleSubtree=function(a,b){var c=a.shadowRoot;
k.prototype.styleDocument;k.prototype.styleSubtree=k.prototype.styleSubtree;k.prototype.getComputedStyleValue=k.prototype.getComputedStyleValue;k.prototype.setElementClass=k.prototype.Sa;k.prototype._styleInfoForNode=k.prototype.Qa;k.prototype.transformCustomStyleForDocument=k.prototype.v;k.prototype.getStyleAst=k.prototype.Ra;k.prototype.styleAstToString=k.prototype.Ta;k.prototype.flushCustomStyles=k.prototype.f;Object.defineProperties(k.prototype,{nativeShadow:{get:function(){return q}},nativeCss:{get:function(){return v}}}); (c||this.j(a))&&this.styleElement(a,b);if(b=c&&(c.children||c.childNodes))for(a=0;a<b.length;a++)this.styleSubtree(b[a]);else if(a=a.children||a.childNodes)for(b=0;b<a.length;b++)this.styleSubtree(a[b])};g.prototype.Pa=function(a){for(var b=0;b<a.length;b++){var c=this.b.getStyleForCustomStyle(a[b]);c&&this.Oa(c)}};g.prototype.D=function(a){for(var b=0;b<a.length;b++){var c=this.b.getStyleForCustomStyle(a[b]);c&&Q.s(c,this.h.M)}};g.prototype.v=function(a){var b=this,c=Ca(a);fa(c,function(a){z?r.B(a):
var J=new k;if(window.ShadyCSS){var Cd=window.ShadyCSS.ApplyShim;var Dd=window.ShadyCSS.CustomStyleInterface}window.ShadyCSS={ScopingShim:J,prepareTemplate:function(a,b,c){J.f();J.prepareTemplate(a,b,c)},styleSubtree:function(a,b){J.f();J.styleSubtree(a,b)},styleElement:function(a){J.f();J.styleElement(a)},styleDocument:function(a){J.f();J.styleDocument(a)},getComputedStyleValue:function(a,b){return J.getComputedStyleValue(a,b)},nativeCss:v,nativeShadow:q};Cd&&(window.ShadyCSS.ApplyShim=Cd);Dd&&(window.ShadyCSS.CustomStyleInterface= r.J(a);A&&(b.c(),b.a&&b.a.transformRule(a))});A?a.textContent=ea(c):this.h.G.rules.push(c)};g.prototype.Oa=function(a){if(A&&this.a){var b=Ca(a);this.c();this.a.transformRules(b);a.textContent=ea(b)}};g.prototype.getComputedStyleValue=function(a,b){var c;A||(c=(w.get(a)||w.get(this.l(a))).M[b]);return(c=c||window.getComputedStyle(a).getPropertyValue(b))?c.trim():""};g.prototype.Sa=function(a,b){var c=a.getRootNode();b=b?b.split(/\s/):[];c=c.host&&c.host.localName;if(!c){var d=a.getAttribute("class");
Dd);var Ib=window.customElements,Ia=window.HTMLImports;window.WebComponents=window.WebComponents||{};if(Ib&&Ib.polyfillWrapFlushCallback){var Ja,Ed=function(){if(Ja){var a=Ja;Ja=null;a();return!0}},Fd=Ia.whenReady;Ib.polyfillWrapFlushCallback(function(a){Ja=a;Fd(Ed)});Ia.whenReady=function(a){Fd(function(){Ed()?Ia.whenReady(a):a()})}}Ia.whenReady(function(){requestAnimationFrame(function(){window.WebComponents.ready=!0;document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}); if(d){d=d.split(/\s/);for(var e=0;e<d.length;e++)if(d[e]===r.a){c=d[e+1];break}}}c&&b.push(r.a,c);A||(c=w.get(a))&&c.C&&b.push(Q.g,c.C);Da(a,b.join(" "))};g.prototype.Qa=function(a){return w.get(a)};g.prototype.flush=g.prototype.B;g.prototype.prepareTemplate=g.prototype.prepareTemplate;g.prototype.styleElement=g.prototype.styleElement;g.prototype.styleDocument=g.prototype.styleDocument;g.prototype.styleSubtree=g.prototype.styleSubtree;g.prototype.getComputedStyleValue=g.prototype.getComputedStyleValue;
var Gd=document.createElement("style");Gd.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var Hd=document.querySelector("head");Hd.insertBefore(Gd,Hd.firstChild)})();}).call(this); g.prototype.setElementClass=g.prototype.Sa;g.prototype._styleInfoForNode=g.prototype.Qa;g.prototype.transformCustomStyleForDocument=g.prototype.v;g.prototype.getStyleAst=g.prototype.Ra;g.prototype.styleAstToString=g.prototype.Ta;g.prototype.flushCustomStyles=g.prototype.f;Object.defineProperties(g.prototype,{nativeShadow:{get:function(){return z}},nativeCss:{get:function(){return A}}});var K=new g;if(window.ShadyCSS){var Id=window.ShadyCSS.ApplyShim;var Jd=window.ShadyCSS.CustomStyleInterface}window.ShadyCSS=
{ScopingShim:K,prepareTemplate:function(a,b,c){K.f();K.prepareTemplate(a,b,c)},styleSubtree:function(a,b){K.f();K.styleSubtree(a,b)},styleElement:function(a){K.f();K.styleElement(a)},styleDocument:function(a){K.f();K.styleDocument(a)},getComputedStyleValue:function(a,b){return K.getComputedStyleValue(a,b)},nativeCss:A,nativeShadow:z};Id&&(window.ShadyCSS.ApplyShim=Id);Jd&&(window.ShadyCSS.CustomStyleInterface=Jd);var Ob=window.customElements,Ma=window.HTMLImports;window.WebComponents=window.WebComponents||
{};if(Ob&&Ob.polyfillWrapFlushCallback){var Na,Kd=function(){if(Na){var a=Na;Na=null;a();return!0}},Ld=Ma.whenReady;Ob.polyfillWrapFlushCallback(function(a){Na=a;Ld(Kd)});Ma.whenReady=function(a){Ld(function(){Kd()?Ma.whenReady(a):a()})}}Ma.whenReady(function(){requestAnimationFrame(function(){window.WebComponents.ready=!0;document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})});var Md=document.createElement("style");Md.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";
var Nd=document.querySelector("head");Nd.insertBefore(Md,Nd.firstChild)})();}).call(this);
//# sourceMappingURL=webcomponents-lite.js.map //# sourceMappingURL=webcomponents-lite.js.map

View file

@ -24,7 +24,7 @@ from homeassistant.helpers.event import track_time_change
from homeassistant.util import convert, dt from homeassistant.util import convert, dt
REQUIREMENTS = [ REQUIREMENTS = [
'google-api-python-client==1.6.2', 'google-api-python-client==1.6.4',
'oauth2client==4.0.0', 'oauth2client==4.0.0',
] ]
@ -99,10 +99,10 @@ def do_authentication(hass, config):
from oauth2client.file import Storage from oauth2client.file import Storage
oauth = OAuth2WebServerFlow( oauth = OAuth2WebServerFlow(
config[CONF_CLIENT_ID], client_id=config[CONF_CLIENT_ID],
config[CONF_CLIENT_SECRET], client_secret=config[CONF_CLIENT_SECRET],
'https://www.googleapis.com/auth/calendar.readonly', scope='https://www.googleapis.com/auth/calendar.readonly',
'Home-Assistant.io', redirect_uri='Home-Assistant.io',
) )
try: try:

View file

@ -269,7 +269,7 @@ def async_setup(hass, config):
hass.services.async_register( hass.services.async_register(
DOMAIN, SERVICE_RELOAD, reload_service_handler, DOMAIN, SERVICE_RELOAD, reload_service_handler,
descriptions[DOMAIN][SERVICE_RELOAD], schema=RELOAD_SERVICE_SCHEMA) descriptions[SERVICE_RELOAD], schema=RELOAD_SERVICE_SCHEMA)
@asyncio.coroutine @asyncio.coroutine
def groups_service_handler(service): def groups_service_handler(service):
@ -346,11 +346,11 @@ def async_setup(hass, config):
hass.services.async_register( hass.services.async_register(
DOMAIN, SERVICE_SET, groups_service_handler, DOMAIN, SERVICE_SET, groups_service_handler,
descriptions[DOMAIN][SERVICE_SET], schema=SET_SERVICE_SCHEMA) descriptions[SERVICE_SET], schema=SET_SERVICE_SCHEMA)
hass.services.async_register( hass.services.async_register(
DOMAIN, SERVICE_REMOVE, groups_service_handler, DOMAIN, SERVICE_REMOVE, groups_service_handler,
descriptions[DOMAIN][SERVICE_REMOVE], schema=REMOVE_SERVICE_SCHEMA) descriptions[SERVICE_REMOVE], schema=REMOVE_SERVICE_SCHEMA)
@asyncio.coroutine @asyncio.coroutine
def visibility_service_handler(service): def visibility_service_handler(service):
@ -368,7 +368,7 @@ def async_setup(hass, config):
hass.services.async_register( hass.services.async_register(
DOMAIN, SERVICE_SET_VISIBILITY, visibility_service_handler, DOMAIN, SERVICE_SET_VISIBILITY, visibility_service_handler,
descriptions[DOMAIN][SERVICE_SET_VISIBILITY], descriptions[SERVICE_SET_VISIBILITY],
schema=SET_VISIBILITY_SERVICE_SCHEMA) schema=SET_VISIBILITY_SERVICE_SCHEMA)
return True return True

View file

@ -0,0 +1,59 @@
reload:
description: "Reload group configuration."
set_visibility:
description: Hide or show a group
fields:
entity_id:
description: Name(s) of entities to set value
example: 'group.travel'
visible:
description: True if group should be shown or False if it should be hidden.
example: True
set:
description: Create/Update a user group
fields:
object_id:
description: Group id and part of entity id
example: 'test_group'
name:
description: Name of group
example: 'My test group'
view:
description: Boolean for if the group is a view
example: True
icon:
description: Name of icon for the group
example: 'mdi:camera'
control:
description: Value for control the group control
example: 'hidden'
visible:
description: If the group is visible on UI
example: True
entities:
description: List of all members in the group. Not compatible with 'delta'
example: domain.entity_id1, domain.entity_id2
add_entities:
description: List of members they will change on group listening.
example: domain.entity_id1, domain.entity_id2
remove:
description: Remove a user group
fields:
object_id:
description: Group id and part of entity id
example: 'test_group'

View file

@ -14,9 +14,13 @@ from aiohttp import web
from aiohttp.web_exceptions import HTTPBadGateway from aiohttp.web_exceptions import HTTPBadGateway
from aiohttp.hdrs import CONTENT_TYPE from aiohttp.hdrs import CONTENT_TYPE
import async_timeout import async_timeout
import voluptuous as vol
from homeassistant.const import CONTENT_TYPE_TEXT_PLAIN import homeassistant.helpers.config_validation as cv
from homeassistant.components.http import HomeAssistantView, KEY_AUTHENTICATED from homeassistant.const import CONTENT_TYPE_TEXT_PLAIN, SERVER_PORT
from homeassistant.components.http import (
HomeAssistantView, KEY_AUTHENTICATED, CONF_API_PASSWORD, CONF_SERVER_PORT,
CONF_SSL_CERTIFICATE)
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.components.frontend import register_built_in_panel from homeassistant.components.frontend import register_built_in_panel
@ -25,16 +29,42 @@ _LOGGER = logging.getLogger(__name__)
DOMAIN = 'hassio' DOMAIN = 'hassio'
DEPENDENCIES = ['http'] DEPENDENCIES = ['http']
SERVICE_ADDON_START = 'addon_start'
SERVICE_ADDON_STOP = 'addon_stop'
SERVICE_ADDON_RESTART = 'addon_restart'
SERVICE_ADDON_STDIN = 'addon_stdin'
ATTR_ADDON = 'addon'
ATTR_INPUT = 'input'
NO_TIMEOUT = { NO_TIMEOUT = {
re.compile(r'^homeassistant/update$'), re.compile(r'^host/update$'), re.compile(r'^homeassistant/update$'),
re.compile(r'^supervisor/update$'), re.compile(r'^addons/[^/]*/update$'), re.compile(r'^host/update$'),
re.compile(r'^addons/[^/]*/install$') re.compile(r'^supervisor/update$'),
re.compile(r'^addons/[^/]*/update$'),
re.compile(r'^addons/[^/]*/install$'),
re.compile(r'^addons/[^/]*/rebuild$')
} }
NO_AUTH = { NO_AUTH = {
re.compile(r'^panel$'), re.compile(r'^addons/[^/]*/logo$') re.compile(r'^panel$'), re.compile(r'^addons/[^/]*/logo$')
} }
SCHEMA_ADDON = vol.Schema({
vol.Required(ATTR_ADDON): cv.slug,
})
SCHEMA_ADDON_STDIN = SCHEMA_ADDON.extend({
vol.Required(ATTR_INPUT): vol.Any(dict, cv.string)
})
MAP_SERVICE_API = {
SERVICE_ADDON_START: ('/addons/{addon}/start', SCHEMA_ADDON),
SERVICE_ADDON_STOP: ('/addons/{addon}/stop', SCHEMA_ADDON),
SERVICE_ADDON_RESTART: ('/addons/{addon}/restart', SCHEMA_ADDON),
SERVICE_ADDON_STDIN: ('/addons/{addon}/stdin', SCHEMA_ADDON_STDIN),
}
@asyncio.coroutine @asyncio.coroutine
def async_setup(hass, config): def async_setup(hass, config):
@ -48,8 +78,7 @@ def async_setup(hass, config):
websession = async_get_clientsession(hass) websession = async_get_clientsession(hass)
hassio = HassIO(hass.loop, websession, host) hassio = HassIO(hass.loop, websession, host)
api_ok = yield from hassio.is_connected() if not (yield from hassio.is_connected()):
if not api_ok:
_LOGGER.error("Not connected with HassIO!") _LOGGER.error("Not connected with HassIO!")
return False return False
@ -59,6 +88,23 @@ def async_setup(hass, config):
register_built_in_panel(hass, 'hassio', 'Hass.io', register_built_in_panel(hass, 'hassio', 'Hass.io',
'mdi:access-point-network') 'mdi:access-point-network')
if 'http' in config:
yield from hassio.update_hass_api(config.get('http'))
@asyncio.coroutine
def async_service_handler(service):
"""Handle service calls for HassIO."""
api_command = MAP_SERVICE_API[service.service][0]
addon = service.data[ATTR_ADDON]
data = service.data[ATTR_INPUT] if ATTR_INPUT in service.data else None
yield from hassio.send_command(
api_command.format(addon=addon), payload=data, timeout=60)
for service, settings in MAP_SERVICE_API.items():
hass.services.async_register(
DOMAIN, service, async_service_handler, schema=settings[1])
return True return True
@ -71,30 +117,52 @@ class HassIO(object):
self.websession = websession self.websession = websession
self._ip = ip self._ip = ip
@asyncio.coroutine
def is_connected(self): def is_connected(self):
"""Return True if it connected to HassIO supervisor. """Return True if it connected to HassIO supervisor.
This method return a coroutine.
"""
return self.send_command("/supervisor/ping", method="get")
def update_hass_api(self, http_config):
"""Update Home-Assistant API data on HassIO.
This method return a coroutine.
"""
port = http_config.get(CONF_SERVER_PORT) or SERVER_PORT
options = {
'ssl': CONF_SSL_CERTIFICATE in http_config,
'port': port,
'password': http_config.get(CONF_API_PASSWORD),
}
return self.send_command("/homeassistant/options", payload=options)
@asyncio.coroutine
def send_command(self, command, method="post", payload=None, timeout=10):
"""Send API command to HassIO.
This method is a coroutine. This method is a coroutine.
""" """
try: try:
with async_timeout.timeout(10, loop=self.loop): with async_timeout.timeout(timeout, loop=self.loop):
request = yield from self.websession.get( request = yield from self.websession.request(
"http://{}{}".format(self._ip, "/supervisor/ping") method, "http://{}{}".format(self._ip, command),
) json=payload)
if request.status != 200: if request.status != 200:
_LOGGER.error("Ping return code %d.", request.status) _LOGGER.error(
"%s return code %d.", command, request.status)
return False return False
answer = yield from request.json() answer = yield from request.json()
return answer and answer['result'] == 'ok' return answer and answer['result'] == 'ok'
except asyncio.TimeoutError: except asyncio.TimeoutError:
_LOGGER.error("Timeout on ping request") _LOGGER.error("Timeout on %s request", command)
except aiohttp.ClientError as err: except aiohttp.ClientError as err:
_LOGGER.error("Client error on ping request %s", err) _LOGGER.error("Client error on %s request %s", command, err)
return False return False

View file

@ -41,6 +41,7 @@ def last_recorder_run(hass):
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
res = (session.query(RecorderRuns) res = (session.query(RecorderRuns)
.filter(RecorderRuns.end.isnot(None))
.order_by(RecorderRuns.end.desc()).first()) .order_by(RecorderRuns.end.desc()).first())
if res is None: if res is None:
return None return None
@ -283,9 +284,10 @@ class HistoryPeriodView(HomeAssistantView):
end_time = request.query.get('end_time') end_time = request.query.get('end_time')
if end_time: if end_time:
end_time = dt_util.as_utc( end_time = dt_util.parse_datetime(end_time)
dt_util.parse_datetime(end_time)) if end_time:
if end_time is None: end_time = dt_util.as_utc(end_time)
else:
return self.json_message('Invalid end_time', HTTP_BAD_REQUEST) return self.json_message('Invalid end_time', HTTP_BAD_REQUEST)
else: else:
end_time = start_time + one_day end_time = start_time + one_day

View file

@ -21,7 +21,7 @@ from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import track_time_interval from homeassistant.helpers.event import track_time_interval
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
REQUIREMENTS = ['pyhomematic==0.1.32'] REQUIREMENTS = ['pyhomematic==0.1.33']
DOMAIN = 'homematic' DOMAIN = 'homematic'
@ -69,7 +69,8 @@ HM_DEVICE_TYPES = {
'IPSmoke'], 'IPSmoke'],
DISCOVER_CLIMATE: [ DISCOVER_CLIMATE: [
'Thermostat', 'ThermostatWall', 'MAXThermostat', 'ThermostatWall2', 'Thermostat', 'ThermostatWall', 'MAXThermostat', 'ThermostatWall2',
'MAXWallThermostat', 'IPThermostat', 'IPThermostatWall'], 'MAXWallThermostat', 'IPThermostat', 'IPThermostatWall',
'ThermostatGroup'],
DISCOVER_BINARY_SENSORS: [ DISCOVER_BINARY_SENSORS: [
'ShutterContact', 'Smoke', 'SmokeV2', 'Motion', 'MotionV2', 'ShutterContact', 'Smoke', 'SmokeV2', 'Motion', 'MotionV2',
'RemoteMotion', 'WeatherSensor', 'TiltSensor', 'IPShutterContact', 'RemoteMotion', 'WeatherSensor', 'TiltSensor', 'IPShutterContact',
@ -129,6 +130,7 @@ CONF_LOCAL_IP = 'local_ip'
CONF_LOCAL_PORT = 'local_port' CONF_LOCAL_PORT = 'local_port'
CONF_IP = 'ip' CONF_IP = 'ip'
CONF_PORT = 'port' CONF_PORT = 'port'
CONF_PATH = 'path'
CONF_CALLBACK_IP = 'callback_ip' CONF_CALLBACK_IP = 'callback_ip'
CONF_CALLBACK_PORT = 'callback_port' CONF_CALLBACK_PORT = 'callback_port'
CONF_RESOLVENAMES = 'resolvenames' CONF_RESOLVENAMES = 'resolvenames'
@ -140,6 +142,7 @@ DEFAULT_LOCAL_IP = '0.0.0.0'
DEFAULT_LOCAL_PORT = 0 DEFAULT_LOCAL_PORT = 0
DEFAULT_RESOLVENAMES = False DEFAULT_RESOLVENAMES = False
DEFAULT_PORT = 2001 DEFAULT_PORT = 2001
DEFAULT_PATH = ''
DEFAULT_USERNAME = 'Admin' DEFAULT_USERNAME = 'Admin'
DEFAULT_PASSWORD = '' DEFAULT_PASSWORD = ''
DEFAULT_VARIABLES = False DEFAULT_VARIABLES = False
@ -160,8 +163,8 @@ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
vol.Required(CONF_HOSTS): {cv.match_all: { vol.Required(CONF_HOSTS): {cv.match_all: {
vol.Required(CONF_IP): cv.string, vol.Required(CONF_IP): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
cv.port, vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string,
vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string, vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD, default=DEFAULT_PASSWORD): cv.string, vol.Optional(CONF_PASSWORD, default=DEFAULT_PASSWORD): cv.string,
vol.Optional(CONF_VARIABLES, default=DEFAULT_VARIABLES): vol.Optional(CONF_VARIABLES, default=DEFAULT_VARIABLES):
@ -258,6 +261,7 @@ def setup(hass, config):
remotes[rname] = {} remotes[rname] = {}
remotes[rname][CONF_IP] = server remotes[rname][CONF_IP] = server
remotes[rname][CONF_PORT] = rconfig.get(CONF_PORT) remotes[rname][CONF_PORT] = rconfig.get(CONF_PORT)
remotes[rname][CONF_PATH] = rconfig.get(CONF_PATH)
remotes[rname][CONF_RESOLVENAMES] = rconfig.get(CONF_RESOLVENAMES) remotes[rname][CONF_RESOLVENAMES] = rconfig.get(CONF_RESOLVENAMES)
remotes[rname][CONF_USERNAME] = rconfig.get(CONF_USERNAME) remotes[rname][CONF_USERNAME] = rconfig.get(CONF_USERNAME)
remotes[rname][CONF_PASSWORD] = rconfig.get(CONF_PASSWORD) remotes[rname][CONF_PASSWORD] = rconfig.get(CONF_PASSWORD)

View file

@ -1,8 +1,11 @@
"""Authentication for HTTP component.""" """Authentication for HTTP component."""
import asyncio import asyncio
import base64
import hmac import hmac
import logging import logging
from aiohttp import hdrs
from homeassistant.const import HTTP_HEADER_HA_AUTH from homeassistant.const import HTTP_HEADER_HA_AUTH
from .util import get_real_ip from .util import get_real_ip
from .const import KEY_TRUSTED_NETWORKS, KEY_AUTHENTICATED from .const import KEY_TRUSTED_NETWORKS, KEY_AUTHENTICATED
@ -41,6 +44,10 @@ def auth_middleware(app, handler):
validate_password(request, request.query[DATA_API_PASSWORD])): validate_password(request, request.query[DATA_API_PASSWORD])):
authenticated = True authenticated = True
elif (hdrs.AUTHORIZATION in request.headers and
validate_authorization_header(request)):
authenticated = True
elif is_trusted_ip(request): elif is_trusted_ip(request):
authenticated = True authenticated = True
@ -64,3 +71,22 @@ def validate_password(request, api_password):
"""Test if password is valid.""" """Test if password is valid."""
return hmac.compare_digest( return hmac.compare_digest(
api_password, request.app['hass'].http.api_password) api_password, request.app['hass'].http.api_password)
def validate_authorization_header(request):
"""Test an authorization header if valid password."""
if hdrs.AUTHORIZATION not in request.headers:
return False
auth_type, auth = request.headers.get(hdrs.AUTHORIZATION).split(' ', 1)
if auth_type != 'Basic':
return False
decoded = base64.b64decode(auth).decode('utf-8')
username, password = decoded.split(':', 1)
if username != 'homeassistant':
return False
return validate_password(request, password)

View file

@ -17,7 +17,7 @@ from homeassistant.components.image_processing import (
ImageProcessingEntity) ImageProcessingEntity)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['numpy==1.13.1'] REQUIREMENTS = ['numpy==1.13.3']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -28,7 +28,7 @@ CASCADE_URL = \
'https://raw.githubusercontent.com/opencv/opencv/master/data/' + \ 'https://raw.githubusercontent.com/opencv/opencv/master/data/' + \
'lbpcascades/lbpcascade_frontalface.xml' 'lbpcascades/lbpcascade_frontalface.xml'
CONF_CLASSIFIER = 'classifer' CONF_CLASSIFIER = 'classifier'
CONF_FILE = 'file' CONF_FILE = 'file'
CONF_MIN_SIZE = 'min_size' CONF_MIN_SIZE = 'min_size'
CONF_NEIGHBORS = 'neighbors' CONF_NEIGHBORS = 'neighbors'

View file

@ -18,7 +18,7 @@ from homeassistant.helpers import state as state_helper
from homeassistant.helpers.entity_values import EntityValues from homeassistant.helpers.entity_values import EntityValues
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['influxdb==3.0.0'] REQUIREMENTS = ['influxdb==4.1.1']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -0,0 +1,227 @@
"""
Component to offer a way to select a date and / or a time.
For more details about this component, please refer to the documentation
at https://home-assistant.io/components/input_datetime/
"""
import asyncio
import logging
import datetime
import voluptuous as vol
from homeassistant.const import (
ATTR_ENTITY_ID, CONF_ICON, CONF_NAME, STATE_UNKNOWN)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.util import dt as dt_util
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'input_datetime'
ENTITY_ID_FORMAT = DOMAIN + '.{}'
CONF_HAS_DATE = 'has_date'
CONF_HAS_TIME = 'has_time'
CONF_INITIAL = 'initial'
ATTR_DATE = 'date'
ATTR_TIME = 'time'
SERVICE_SET_DATETIME = 'set_datetime'
SERVICE_SET_DATETIME_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Optional(ATTR_DATE): cv.date,
vol.Optional(ATTR_TIME): cv.time,
})
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
cv.slug: vol.All({
vol.Optional(CONF_NAME): cv.string,
vol.Required(CONF_HAS_DATE): cv.boolean,
vol.Required(CONF_HAS_TIME): cv.boolean,
vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INITIAL): cv.datetime,
}, cv.has_at_least_one_key_value((CONF_HAS_DATE, True),
(CONF_HAS_TIME, True)))})
}, extra=vol.ALLOW_EXTRA)
@asyncio.coroutine
def async_set_datetime(hass, entity_id, dt_value):
"""Set date and / or time of input_datetime."""
yield from hass.services.async_call(DOMAIN, SERVICE_SET_DATETIME, {
ATTR_ENTITY_ID: entity_id,
ATTR_DATE: dt_value.date(),
ATTR_TIME: dt_value.time()
})
@asyncio.coroutine
def async_setup(hass, config):
"""Set up an input datetime."""
component = EntityComponent(_LOGGER, DOMAIN, hass)
entities = []
for object_id, cfg in config[DOMAIN].items():
name = cfg.get(CONF_NAME)
has_time = cfg.get(CONF_HAS_TIME)
has_date = cfg.get(CONF_HAS_DATE)
icon = cfg.get(CONF_ICON)
initial = cfg.get(CONF_INITIAL)
entities.append(InputDatetime(object_id, name,
has_date, has_time, icon, initial))
if not entities:
return False
@asyncio.coroutine
def async_set_datetime_service(call):
"""Handle a call to the input datetime 'set datetime' service."""
target_inputs = component.async_extract_from_service(call)
tasks = []
for input_datetime in target_inputs:
time = call.data.get(ATTR_TIME)
date = call.data.get(ATTR_DATE)
if (input_datetime.has_date() and not date) or \
(input_datetime.has_time() and not time):
_LOGGER.error("Invalid service data for "
"input_datetime.set_datetime: %s",
str(call.data))
continue
tasks.append(input_datetime.async_set_datetime(date, time))
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_SET_DATETIME, async_set_datetime_service,
schema=SERVICE_SET_DATETIME_SCHEMA)
yield from component.async_add_entities(entities)
return True
class InputDatetime(Entity):
"""Representation of a datetime input."""
def __init__(self, object_id, name, has_date, has_time, icon, initial):
"""Initialize a select input."""
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
self._name = name
self._has_date = has_date
self._has_time = has_time
self._icon = icon
self._initial = initial
self._current_datetime = None
@asyncio.coroutine
def async_added_to_hass(self):
"""Run when entity about to be added."""
restore_val = None
# Priority 1: Initial State
if self._initial is not None:
restore_val = self._initial
# Priority 2: Old state
if restore_val is None:
old_state = yield from async_get_last_state(self.hass,
self.entity_id)
if old_state is not None:
restore_val = dt_util.parse_datetime(old_state.state)
if restore_val is not None:
if not self._has_date:
self._current_datetime = restore_val.time()
elif not self._has_time:
self._current_datetime = restore_val.date()
else:
self._current_datetime = restore_val
def has_date(self):
"""Return whether the input datetime carries a date."""
return self._has_date
def has_time(self):
"""Return whether the input datetime carries a time."""
return self._has_time
@property
def should_poll(self):
"""If entity should be polled."""
return False
@property
def name(self):
"""Return the name of the select input."""
return self._name
@property
def icon(self):
"""Return the icon to be used for this entity."""
return self._icon
@property
def state(self):
"""Return the state of the component."""
if self._current_datetime is None:
return STATE_UNKNOWN
return self._current_datetime
@property
def state_attributes(self):
"""Return the state attributes."""
attrs = {
'has_date': self._has_date,
'has_time': self._has_time,
}
if self._current_datetime is None:
return attrs
if self._has_date and self._current_datetime is not None:
attrs['year'] = self._current_datetime.year
attrs['month'] = self._current_datetime.month
attrs['day'] = self._current_datetime.day
if self._has_time and self._current_datetime is not None:
attrs['hour'] = self._current_datetime.hour
attrs['minute'] = self._current_datetime.minute
attrs['second'] = self._current_datetime.second
if self._current_datetime is not None:
if not self._has_date:
attrs['timestamp'] = self._current_datetime.hour * 3600 + \
self._current_datetime.minute * 60 + \
self._current_datetime.second
elif not self._has_time:
extended = datetime.datetime.combine(self._current_datetime,
datetime.time(0, 0))
attrs['timestamp'] = extended.timestamp()
else:
attrs['timestamp'] = self._current_datetime.timestamp()
return attrs
@asyncio.coroutine
def async_set_datetime(self, date_val, time_val):
"""Set a new date / time."""
if self._has_date and self._has_time and date_val and time_val:
self._current_datetime = datetime.datetime.combine(date_val,
time_val)
elif self._has_date and not self._has_time and date_val:
self._current_datetime = date_val
if self._has_time and not self._has_date and time_val:
self._current_datetime = time_val
yield from self.async_update_ha_state()

View file

@ -1,8 +1,8 @@
""" """
Component to offer a way to select a value from a slider. Component to offer a way to set a numeric value from a slider or text box.
For more details about this component, please refer to the documentation For more details about this component, please refer to the documentation
at https://home-assistant.io/components/input_slider/ at https://home-assistant.io/components/input_number/
""" """
import asyncio import asyncio
import logging import logging
@ -19,29 +19,34 @@ from homeassistant.helpers.restore_state import async_get_last_state
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = 'input_slider' DOMAIN = 'input_number'
ENTITY_ID_FORMAT = DOMAIN + '.{}' ENTITY_ID_FORMAT = DOMAIN + '.{}'
CONF_INITIAL = 'initial' CONF_INITIAL = 'initial'
CONF_MIN = 'min' CONF_MIN = 'min'
CONF_MAX = 'max' CONF_MAX = 'max'
CONF_MODE = 'mode'
CONF_STEP = 'step' CONF_STEP = 'step'
MODE_SLIDER = 'slider'
MODE_BOX = 'box'
ATTR_VALUE = 'value' ATTR_VALUE = 'value'
ATTR_MIN = 'min' ATTR_MIN = 'min'
ATTR_MAX = 'max' ATTR_MAX = 'max'
ATTR_STEP = 'step' ATTR_STEP = 'step'
ATTR_MODE = 'mode'
SERVICE_SELECT_VALUE = 'select_value' SERVICE_SET_VALUE = 'set_value'
SERVICE_SELECT_VALUE_SCHEMA = vol.Schema({ SERVICE_SET_VALUE_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Required(ATTR_VALUE): vol.Coerce(float), vol.Required(ATTR_VALUE): vol.Coerce(float),
}) })
def _cv_input_slider(cfg): def _cv_input_number(cfg):
"""Configure validation helper for input slider (voluptuous).""" """Configure validation helper for input number (voluptuous)."""
minimum = cfg.get(CONF_MIN) minimum = cfg.get(CONF_MIN)
maximum = cfg.get(CONF_MAX) maximum = cfg.get(CONF_MAX)
if minimum >= maximum: if minimum >= maximum:
@ -64,16 +69,18 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_STEP, default=1): vol.Optional(CONF_STEP, default=1):
vol.All(vol.Coerce(float), vol.Range(min=1e-3)), vol.All(vol.Coerce(float), vol.Range(min=1e-3)),
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
vol.Optional(ATTR_UNIT_OF_MEASUREMENT): cv.string vol.Optional(ATTR_UNIT_OF_MEASUREMENT): cv.string,
}, _cv_input_slider) vol.Optional(CONF_MODE, default=MODE_SLIDER):
vol.In([MODE_BOX, MODE_SLIDER]),
}, _cv_input_number)
}) })
}, required=True, extra=vol.ALLOW_EXTRA) }, required=True, extra=vol.ALLOW_EXTRA)
@bind_hass @bind_hass
def select_value(hass, entity_id, value): def set_value(hass, entity_id, value):
"""Set input_slider to value.""" """Set input_number to value."""
hass.services.call(DOMAIN, SERVICE_SELECT_VALUE, { hass.services.call(DOMAIN, SERVICE_SET_VALUE, {
ATTR_ENTITY_ID: entity_id, ATTR_ENTITY_ID: entity_id,
ATTR_VALUE: value, ATTR_VALUE: value,
}) })
@ -94,37 +101,39 @@ def async_setup(hass, config):
step = cfg.get(CONF_STEP) step = cfg.get(CONF_STEP)
icon = cfg.get(CONF_ICON) icon = cfg.get(CONF_ICON)
unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT) unit = cfg.get(ATTR_UNIT_OF_MEASUREMENT)
mode = cfg.get(CONF_MODE)
entities.append(InputSlider( entities.append(InputNumber(
object_id, name, initial, minimum, maximum, step, icon, unit)) object_id, name, initial, minimum, maximum, step, icon, unit,
mode))
if not entities: if not entities:
return False return False
@asyncio.coroutine @asyncio.coroutine
def async_select_value_service(call): def async_set_value_service(call):
"""Handle a calls to the input slider services.""" """Handle a calls to the input slider services."""
target_inputs = component.async_extract_from_service(call) target_inputs = component.async_extract_from_service(call)
tasks = [input_slider.async_select_value(call.data[ATTR_VALUE]) tasks = [input_number.async_set_value(call.data[ATTR_VALUE])
for input_slider in target_inputs] for input_number in target_inputs]
if tasks: if tasks:
yield from asyncio.wait(tasks, loop=hass.loop) yield from asyncio.wait(tasks, loop=hass.loop)
hass.services.async_register( hass.services.async_register(
DOMAIN, SERVICE_SELECT_VALUE, async_select_value_service, DOMAIN, SERVICE_SET_VALUE, async_set_value_service,
schema=SERVICE_SELECT_VALUE_SCHEMA) schema=SERVICE_SET_VALUE_SCHEMA)
yield from component.async_add_entities(entities) yield from component.async_add_entities(entities)
return True return True
class InputSlider(Entity): class InputNumber(Entity):
"""Represent an slider.""" """Represent an slider."""
def __init__(self, object_id, name, initial, minimum, maximum, step, icon, def __init__(self, object_id, name, initial, minimum, maximum, step, icon,
unit): unit, mode):
"""Initialize a select input.""" """Initialize an input number."""
self.entity_id = ENTITY_ID_FORMAT.format(object_id) self.entity_id = ENTITY_ID_FORMAT.format(object_id)
self._name = name self._name = name
self._current_value = initial self._current_value = initial
@ -133,6 +142,7 @@ class InputSlider(Entity):
self._step = step self._step = step
self._icon = icon self._icon = icon
self._unit = unit self._unit = unit
self._mode = mode
@property @property
def should_poll(self): def should_poll(self):
@ -141,7 +151,7 @@ class InputSlider(Entity):
@property @property
def name(self): def name(self):
"""Return the name of the select input slider.""" """Return the name of the input slider."""
return self._name return self._name
@property @property
@ -165,7 +175,8 @@ class InputSlider(Entity):
return { return {
ATTR_MIN: self._minimum, ATTR_MIN: self._minimum,
ATTR_MAX: self._maximum, ATTR_MAX: self._maximum,
ATTR_STEP: self._step ATTR_STEP: self._step,
ATTR_MODE: self._mode,
} }
@asyncio.coroutine @asyncio.coroutine
@ -184,8 +195,8 @@ class InputSlider(Entity):
self._current_value = self._minimum self._current_value = self._minimum
@asyncio.coroutine @asyncio.coroutine
def async_select_value(self, value): def async_set_value(self, value):
"""Select new value.""" """Set new value."""
num_value = float(value) num_value = float(value)
if num_value < self._minimum or num_value > self._maximum: if num_value < self._minimum or num_value > self._maximum:
_LOGGER.warning("Invalid value: %s (range %s - %s)", _LOGGER.warning("Invalid value: %s (range %s - %s)",

View file

@ -263,7 +263,7 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable,
# create a service for calling run_scene directly on the bridge, # create a service for calling run_scene directly on the bridge,
# used to simplify automation rules. # used to simplify automation rules.
def hue_activate_scene(call): def hue_activate_scene(call):
"""Service to call directly directly into bridge to set scenes.""" """Service to call directly into bridge to set scenes."""
group_name = call.data[ATTR_GROUP_NAME] group_name = call.data[ATTR_GROUP_NAME]
scene_name = call.data[ATTR_SCENE_NAME] scene_name = call.data[ATTR_SCENE_NAME]
bridge.run_scene(group_name, scene_name) bridge.run_scene(group_name, scene_name)

View file

@ -213,7 +213,7 @@ class MqttJson(Light):
except KeyError: except KeyError:
pass pass
except ValueError: except ValueError:
_LOGGER.warning("Invalid white value value received") _LOGGER.warning("Invalid white value received")
if self._xy is not None: if self._xy is not None:
try: try:

View file

@ -0,0 +1,87 @@
"""
Light/LED support for the Skybell HD Doorbell.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.skybell/
"""
import logging
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_RGB_COLOR,
SUPPORT_BRIGHTNESS, SUPPORT_RGB_COLOR, Light)
from homeassistant.components.skybell import (
DOMAIN as SKYBELL_DOMAIN, SkybellDevice)
DEPENDENCIES = ['skybell']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the platform for a Skybell device."""
skybell = hass.data.get(SKYBELL_DOMAIN)
sensors = []
for device in skybell.get_devices():
sensors.append(SkybellLight(device))
add_devices(sensors, True)
def _to_skybell_level(level):
"""Convert the given HASS light level (0-255) to Skybell (0-100)."""
return int((level * 100) / 255)
def _to_hass_level(level):
"""Convert the given Skybell (0-100) light level to HASS (0-255)."""
return int((level * 255) / 100)
class SkybellLight(SkybellDevice, Light):
"""A binary sensor implementation for Skybell devices."""
def __init__(self, device):
"""Initialize a light for a Skybell device."""
super().__init__(device)
self._name = self._device.name
@property
def name(self):
"""Return the name of the sensor."""
return self._name
def turn_on(self, **kwargs):
"""Turn on the light."""
if ATTR_RGB_COLOR in kwargs:
self._device.led_rgb = kwargs[ATTR_RGB_COLOR]
elif ATTR_BRIGHTNESS in kwargs:
self._device.led_intensity = _to_skybell_level(
kwargs[ATTR_BRIGHTNESS])
else:
self._device.led_intensity = _to_skybell_level(255)
def turn_off(self, **kwargs):
"""Turn off the light."""
self._device.led_intensity = 0
@property
def is_on(self):
"""Return true if device is on."""
return self._device.led_intensity > 0
@property
def brightness(self):
"""Return the brightness of the light."""
return _to_hass_level(self._device.led_intensity)
@property
def rgb_color(self):
"""Return the color of the light."""
return self._device.led_rgb
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR

View file

@ -17,7 +17,7 @@ from homeassistant.util.color import (
from typing import Tuple from typing import Tuple
REQUIREMENTS = ['pyHS100==0.2.4.2'] REQUIREMENTS = ['pyHS100==0.3.0']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -124,7 +124,7 @@ class TPLinkSmartBulb(Light):
def update(self): def update(self):
"""Update the TP-Link Bulb's state.""" """Update the TP-Link Bulb's state."""
from pyHS100 import SmartPlugException from pyHS100 import SmartDeviceException
try: try:
self._state = ( self._state = (
self.smartbulb.state == self.smartbulb.BULB_STATE_ON) self.smartbulb.state == self.smartbulb.BULB_STATE_ON)
@ -136,7 +136,7 @@ class TPLinkSmartBulb(Light):
self._color_temp = kelvin_to_mired( self._color_temp = kelvin_to_mired(
self.smartbulb.color_temp) self.smartbulb.color_temp)
self._rgb = hsv_to_rgb(self.smartbulb.hsv) self._rgb = hsv_to_rgb(self.smartbulb.hsv)
except (SmartPlugException, OSError) as ex: except (SmartDeviceException, OSError) as ex:
_LOGGER.warning('Could not read state for %s: %s', self.name, ex) _LOGGER.warning('Could not read state for %s: %s', self.name, ex)
@property @property

View file

@ -4,15 +4,18 @@ Support for the IKEA Tradfri platform.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.tradfri/ https://home-assistant.io/components/light.tradfri/
""" """
import asyncio
import logging import logging
from homeassistant.core import callback
from homeassistant.components.light import ( from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_RGB_COLOR, SUPPORT_BRIGHTNESS, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_RGB_COLOR, ATTR_TRANSITION,
SUPPORT_COLOR_TEMP, SUPPORT_RGB_COLOR, Light) SUPPORT_BRIGHTNESS, SUPPORT_TRANSITION, SUPPORT_COLOR_TEMP,
from homeassistant.components.light import ( SUPPORT_RGB_COLOR, Light)
PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA) from homeassistant.components.light import \
from homeassistant.components.tradfri import ( PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA
KEY_GATEWAY, KEY_TRADFRI_GROUPS, KEY_API) from homeassistant.components.tradfri import KEY_GATEWAY, KEY_TRADFRI_GROUPS, \
KEY_API
from homeassistant.util import color as color_util from homeassistant.util import color as color_util
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -20,10 +23,13 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['tradfri'] DEPENDENCIES = ['tradfri']
PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA
IKEA = 'IKEA of Sweden' IKEA = 'IKEA of Sweden'
TRADFRI_LIGHT_MANAGER = 'Tradfri Light Manager'
SUPPORTED_FEATURES = (SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION)
ALLOWED_TEMPERATURES = {IKEA} ALLOWED_TEMPERATURES = {IKEA}
def setup_platform(hass, config, add_devices, discovery_info=None): @asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up the IKEA Tradfri Light platform.""" """Set up the IKEA Tradfri Light platform."""
if discovery_info is None: if discovery_info is None:
return return
@ -31,14 +37,21 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
gateway_id = discovery_info['gateway'] gateway_id = discovery_info['gateway']
api = hass.data[KEY_API][gateway_id] api = hass.data[KEY_API][gateway_id]
gateway = hass.data[KEY_GATEWAY][gateway_id] gateway = hass.data[KEY_GATEWAY][gateway_id]
devices = api(gateway.get_devices())
lights = [dev for dev in devices if api(dev).has_light_control] devices_command = gateway.get_devices()
add_devices(Tradfri(light, api) for light in lights) devices_commands = yield from api(devices_command)
devices = yield from api(*devices_commands)
lights = [dev for dev in devices if dev.has_light_control]
if lights:
async_add_devices(TradfriLight(light, api) for light in lights)
allow_tradfri_groups = hass.data[KEY_TRADFRI_GROUPS][gateway_id] allow_tradfri_groups = hass.data[KEY_TRADFRI_GROUPS][gateway_id]
if allow_tradfri_groups: if allow_tradfri_groups:
groups = api(gateway.get_groups()) groups_command = gateway.get_groups()
add_devices(TradfriGroup(group, api) for group in groups) groups_commands = yield from api(groups_command)
groups = yield from api(*groups_commands)
if groups:
async_add_devices(TradfriGroup(group, api) for group in groups)
class TradfriGroup(Light): class TradfriGroup(Light):
@ -46,14 +59,26 @@ class TradfriGroup(Light):
def __init__(self, light, api): def __init__(self, light, api):
"""Initialize a Group.""" """Initialize a Group."""
self._group = api(light)
self._api = api self._api = api
self._name = self._group.name self._group = light
self._name = light.name
self._refresh(light)
@asyncio.coroutine
def async_added_to_hass(self):
"""Start thread when added to hass."""
self._async_start_observe()
@property
def should_poll(self):
"""No polling needed for tradfri group."""
return False
@property @property
def supported_features(self): def supported_features(self):
"""Flag supported features.""" """Flag supported features."""
return SUPPORT_BRIGHTNESS return SUPPORTED_FEATURES
@property @property
def name(self): def name(self):
@ -70,49 +95,68 @@ class TradfriGroup(Light):
"""Return the brightness of the group lights.""" """Return the brightness of the group lights."""
return self._group.dimmer return self._group.dimmer
def turn_off(self, **kwargs): @asyncio.coroutine
def async_turn_off(self, **kwargs):
"""Instruct the group lights to turn off.""" """Instruct the group lights to turn off."""
self._api(self._group.set_state(0)) self.hass.async_add_job(self._api(self._group.set_state(0)))
def turn_on(self, **kwargs): @asyncio.coroutine
def async_turn_on(self, **kwargs):
"""Instruct the group lights to turn on, or dim.""" """Instruct the group lights to turn on, or dim."""
keys = {}
if ATTR_TRANSITION in kwargs:
keys['transition_time'] = int(kwargs[ATTR_TRANSITION]) * 10
if ATTR_BRIGHTNESS in kwargs: if ATTR_BRIGHTNESS in kwargs:
self._api(self._group.set_dimmer(kwargs[ATTR_BRIGHTNESS])) self.hass.async_add_job(self._api(
self._group.set_dimmer(kwargs[ATTR_BRIGHTNESS], **keys)))
else: else:
self._api(self._group.set_state(1)) self.hass.async_add_job(self._api(self._group.set_state(1)))
@callback
def _async_start_observe(self, exc=None):
"""Start observation of light."""
from pytradfri.error import PyTradFriError
if exc:
_LOGGER.warning("Observation failed for %s", self._name,
exc_info=exc)
def update(self):
"""Fetch new state data for this group."""
from pytradfri import RequestTimeout
try: try:
self._api(self._group.update()) cmd = self._group.observe(callback=self._observe_update,
except RequestTimeout: err_callback=self._async_start_observe,
_LOGGER.warning("Tradfri update request timed out") duration=0)
self.hass.async_add_job(self._api(cmd))
except PyTradFriError as err:
_LOGGER.warning("Observation failed, trying again", exc_info=err)
self._async_start_observe()
def _refresh(self, group):
"""Refresh the light data."""
self._group = group
self._name = group.name
def _observe_update(self, tradfri_device):
"""Receive new state data for this light."""
self._refresh(tradfri_device)
self.hass.async_add_job(self.async_update_ha_state())
class Tradfri(Light): class TradfriLight(Light):
"""The platform class required by Home Asisstant.""" """The platform class required by Home Assistant."""
def __init__(self, light, api): def __init__(self, light, api):
"""Initialize a Light.""" """Initialize a Light."""
self._light = api(light)
self._api = api self._api = api
self._light = None
# Caching of LightControl and light object self._light_control = None
self._light_control = self._light.light_control self._light_data = None
self._light_data = self._light_control.lights[0] self._name = None
self._name = self._light.name
self._rgb_color = None self._rgb_color = None
self._features = SUPPORT_BRIGHTNESS self._features = SUPPORTED_FEATURES
self._temp_supported = False
if self._light_data.hex_color is not None: self._refresh(light)
if self._light.device_info.manufacturer == IKEA:
self._features |= SUPPORT_COLOR_TEMP
else:
self._features |= SUPPORT_RGB_COLOR
self._ok_temps = \
self._light.device_info.manufacturer in ALLOWED_TEMPERATURES
@property @property
def min_mireds(self): def min_mireds(self):
@ -126,6 +170,30 @@ class Tradfri(Light):
from pytradfri.color import MIN_KELVIN_WS from pytradfri.color import MIN_KELVIN_WS
return color_util.color_temperature_kelvin_to_mired(MIN_KELVIN_WS) return color_util.color_temperature_kelvin_to_mired(MIN_KELVIN_WS)
@property
def device_state_attributes(self):
"""Return the devices' state attributes."""
info = self._light.device_info
attrs = {
'manufacturer': info.manufacturer,
'model_number': info.model_number,
'serial': info.serial,
'firmware_version': info.firmware_version,
'power_source': info.power_source_str,
'battery_level': info.battery_level
}
return attrs
@asyncio.coroutine
def async_added_to_hass(self):
"""Start thread when added to hass."""
self._async_start_observe()
@property
def should_poll(self):
"""No polling needed for tradfri light."""
return False
@property @property
def supported_features(self): def supported_features(self):
"""Flag supported features.""" """Flag supported features."""
@ -151,7 +219,7 @@ class Tradfri(Light):
"""Return the CT color value in mireds.""" """Return the CT color value in mireds."""
if (self._light_data.kelvin_color is None or if (self._light_data.kelvin_color is None or
self.supported_features & SUPPORT_COLOR_TEMP == 0 or self.supported_features & SUPPORT_COLOR_TEMP == 0 or
not self._ok_temps): not self._temp_supported):
return None return None
return color_util.color_temperature_kelvin_to_mired( return color_util.color_temperature_kelvin_to_mired(
self._light_data.kelvin_color self._light_data.kelvin_color
@ -162,42 +230,90 @@ class Tradfri(Light):
"""RGB color of the light.""" """RGB color of the light."""
return self._rgb_color return self._rgb_color
def turn_off(self, **kwargs): @asyncio.coroutine
def async_turn_off(self, **kwargs):
"""Instruct the light to turn off.""" """Instruct the light to turn off."""
self._api(self._light_control.set_state(False)) self.hass.async_add_job(self._api(
self._light_control.set_state(False)))
def turn_on(self, **kwargs): @asyncio.coroutine
def async_turn_on(self, **kwargs):
""" """
Instruct the light to turn on. Instruct the light to turn on.
After adding "self._light_data.hexcolor is not None" After adding "self._light_data.hexcolor is not None"
for ATTR_RGB_COLOR, this also supports Philips Hue bulbs. for ATTR_RGB_COLOR, this also supports Philips Hue bulbs.
""" """
if ATTR_BRIGHTNESS in kwargs:
self._api(self._light_control.set_dimmer(kwargs[ATTR_BRIGHTNESS]))
else:
self._api(self._light_control.set_state(True))
if ATTR_RGB_COLOR in kwargs and self._light_data.hex_color is not None: if ATTR_RGB_COLOR in kwargs and self._light_data.hex_color is not None:
self._api(self._light.light_control.set_rgb_color( self.hass.async_add_job(self._api(
*kwargs[ATTR_RGB_COLOR])) self._light.light_control.set_rgb_color(
*kwargs[ATTR_RGB_COLOR])))
elif ATTR_COLOR_TEMP in kwargs and \ elif ATTR_COLOR_TEMP in kwargs and \
self._light_data.hex_color is not None and self._ok_temps: self._light_data.hex_color is not None and \
self._temp_supported:
kelvin = color_util.color_temperature_mired_to_kelvin( kelvin = color_util.color_temperature_mired_to_kelvin(
kwargs[ATTR_COLOR_TEMP]) kwargs[ATTR_COLOR_TEMP])
self._api(self._light_control.set_kelvin_color(kelvin)) self.hass.async_add_job(self._api(
self._light_control.set_kelvin_color(kelvin)))
keys = {}
if ATTR_TRANSITION in kwargs:
keys['transition_time'] = int(kwargs[ATTR_TRANSITION]) * 10
if ATTR_BRIGHTNESS in kwargs:
self.hass.async_add_job(self._api(
self._light_control.set_dimmer(kwargs[ATTR_BRIGHTNESS],
**keys)))
else:
self.hass.async_add_job(self._api(
self._light_control.set_state(True)))
@callback
def _async_start_observe(self, exc=None):
"""Start observation of light."""
from pytradfri.error import PyTradFriError
if exc:
_LOGGER.warning("Observation failed for %s", self._name,
exc_info=exc)
def update(self):
"""Fetch new state data for this light."""
from pytradfri import RequestTimeout
try: try:
self._api(self._light.update()) cmd = self._light.observe(callback=self._observe_update,
except RequestTimeout as exception: err_callback=self._async_start_observe,
_LOGGER.warning("Tradfri update request timed out: %s", exception) duration=0)
self.hass.async_add_job(self._api(cmd))
except PyTradFriError as err:
_LOGGER.warning("Observation failed, trying again", exc_info=err)
self._async_start_observe()
def _refresh(self, light):
"""Refresh the light data."""
self._light = light
# Caching of LightControl and light object
self._light_control = light.light_control
self._light_data = light.light_control.lights[0]
self._name = light.name
self._rgb_color = None
self._features = SUPPORTED_FEATURES
if self._light_data.hex_color is not None:
if self._light.device_info.manufacturer == IKEA:
self._features |= SUPPORT_COLOR_TEMP
else:
self._features |= SUPPORT_RGB_COLOR
self._temp_supported = self._light.device_info.manufacturer \
in ALLOWED_TEMPERATURES
def _observe_update(self, tradfri_device):
"""Receive new state data for this light."""
self._refresh(tradfri_device)
# Handle Hue lights paired with the gateway # Handle Hue lights paired with the gateway
# hex_color is 0 when bulb is unreachable # hex_color is 0 when bulb is unreachable
if self._light_data.hex_color not in (None, '0'): if self._light_data.hex_color not in (None, '0'):
self._rgb_color = color_util.rgb_hex_to_rgb_list( self._rgb_color = color_util.rgb_hex_to_rgb_list(
self._light_data.hex_color) self._light_data.hex_color)
self.hass.async_add_job(self.async_update_ha_state())

View file

@ -54,6 +54,10 @@ SUPPORT_YEELIGHT_RGB = (SUPPORT_YEELIGHT |
SUPPORT_EFFECT | SUPPORT_EFFECT |
SUPPORT_COLOR_TEMP) SUPPORT_COLOR_TEMP)
YEELIGHT_MIN_KELVIN = YEELIGHT_MAX_KELVIN = 2700
YEELIGHT_RGB_MIN_KELVIN = 1700
YEELIGHT_RGB_MAX_KELVIN = 6500
EFFECT_DISCO = "Disco" EFFECT_DISCO = "Disco"
EFFECT_TEMP = "Slow Temp" EFFECT_TEMP = "Slow Temp"
EFFECT_STROBE = "Strobe epilepsy!" EFFECT_STROBE = "Strobe epilepsy!"
@ -191,6 +195,20 @@ class YeelightLight(Light):
"""Return the brightness of this light between 1..255.""" """Return the brightness of this light between 1..255."""
return self._brightness return self._brightness
@property
def min_mireds(self):
"""Return minimum supported color temperature."""
if self.supported_features & SUPPORT_COLOR_TEMP:
return kelvin_to_mired(YEELIGHT_RGB_MAX_KELVIN)
return kelvin_to_mired(YEELIGHT_MAX_KELVIN)
@property
def max_mireds(self):
"""Return maximum supported color temperature."""
if self.supported_features & SUPPORT_COLOR_TEMP:
return kelvin_to_mired(YEELIGHT_RGB_MIN_KELVIN)
return kelvin_to_mired(YEELIGHT_MIN_KELVIN)
def _get_rgb_from_properties(self): def _get_rgb_from_properties(self):
rgb = self._properties.get('rgb', None) rgb = self._properties.get('rgb', None)
color_mode = self._properties.get('color_mode', None) color_mode = self._properties.get('color_mode', None)
@ -434,7 +452,10 @@ class YeelightLight(Light):
def turn_off(self, **kwargs) -> None: def turn_off(self, **kwargs) -> None:
"""Turn off.""" """Turn off."""
import yeelight import yeelight
duration = int(self.config[CONF_TRANSITION]) # in ms
if ATTR_TRANSITION in kwargs: # passed kwarg overrides config
duration = int(kwargs.get(ATTR_TRANSITION) * 1000) # kwarg in s
try: try:
self._bulb.turn_off() self._bulb.turn_off(duration=duration)
except yeelight.BulbException as ex: except yeelight.BulbException as ex:
_LOGGER.error("Unable to turn the bulb off: %s", ex) _LOGGER.error("Unable to turn the bulb off: %s", ex)

View file

@ -29,20 +29,17 @@ class TeslaLock(TeslaDevice, LockDevice):
"""Initialisation of the lock.""" """Initialisation of the lock."""
self._state = None self._state = None
super().__init__(tesla_device, controller) super().__init__(tesla_device, controller)
self._name = self.tesla_device.name
self.entity_id = ENTITY_ID_FORMAT.format(self.tesla_id) self.entity_id = ENTITY_ID_FORMAT.format(self.tesla_id)
def lock(self, **kwargs): def lock(self, **kwargs):
"""Send the lock command.""" """Send the lock command."""
_LOGGER.debug("Locking doors for: %s", self._name) _LOGGER.debug("Locking doors for: %s", self._name)
self.tesla_device.lock() self.tesla_device.lock()
self._state = STATE_LOCKED
def unlock(self, **kwargs): def unlock(self, **kwargs):
"""Send the unlock command.""" """Send the unlock command."""
_LOGGER.debug("Unlocking doors for: %s", self._name) _LOGGER.debug("Unlocking doors for: %s", self._name)
self.tesla_device.unlock() self.tesla_device.unlock()
self._state = STATE_UNLOCKED
@property @property
def is_locked(self): def is_locked(self):

View file

@ -15,7 +15,7 @@ from homeassistant.components.media_player import (
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
REQUIREMENTS = ['youtube_dl==2017.9.24'] REQUIREMENTS = ['youtube_dl==2017.10.01']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -225,7 +225,7 @@ class DenonDevice(MediaPlayerDevice):
self.telnet_command('MU' + ('ON' if mute else 'OFF')) self.telnet_command('MU' + ('ON' if mute else 'OFF'))
def media_play(self): def media_play(self):
"""Play media media player.""" """Play media player."""
self.telnet_command('NS9A') self.telnet_command('NS9A')
def media_pause(self): def media_pause(self):

View file

@ -124,7 +124,7 @@ class DuneHDPlayerEntity(MediaPlayerDevice):
self.schedule_update_ha_state() self.schedule_update_ha_state()
def media_play(self): def media_play(self):
"""Play media media player.""" """Play media player."""
self._state = self._player.play() self._state = self._player.play()
self.schedule_update_ha_state() self.schedule_update_ha_state()

View file

@ -287,12 +287,6 @@ class PlexClient(MediaPlayerDevice):
self._is_player_available = False self._is_player_available = False
self._machine_identifier = None self._machine_identifier = None
self._make = '' self._make = ''
self._media_content_id = None
self._media_content_rating = None
self._media_content_type = None
self._media_duration = None
self._media_image_url = None
self._media_title = None
self._name = None self._name = None
self._player_state = 'idle' self._player_state = 'idle'
self._previous_volume_level = 1 # Used in fake muting self._previous_volume_level = 1 # Used in fake muting
@ -308,16 +302,7 @@ class PlexClient(MediaPlayerDevice):
self.update_devices = update_devices self.update_devices = update_devices
self.update_sessions = update_sessions self.update_sessions = update_sessions
# Music self._clear_media()
self._media_album_artist = None
self._media_album_name = None
self._media_artist = None
self._media_track = None
# TV Show
self._media_episode = None
self._media_season = None
self._media_series_title = None
self.refresh(device, session) self.refresh(device, session)
@ -339,10 +324,32 @@ class PlexClient(MediaPlayerDevice):
'media_player', prefix, 'media_player', prefix,
self.name.lower().replace('-', '_')) self.name.lower().replace('-', '_'))
def _clear_media(self):
"""Set all Media Items to None."""
# General
self._media_content_id = None
self._media_content_rating = None
self._media_content_type = None
self._media_duration = None
self._media_image_url = None
self._media_title = None
self._media_position = None
# Music
self._media_album_artist = None
self._media_album_name = None
self._media_artist = None
self._media_track = None
# TV Show
self._media_episode = None
self._media_season = None
self._media_series_title = None
def refresh(self, device, session): def refresh(self, device, session):
"""Refresh key device data.""" """Refresh key device data."""
# new data refresh # new data refresh
if session: self._clear_media()
if session: # Not being triggered by Chrome or FireTablet Plex App
self._session = session self._session = session
if device: if device:
self._device = device self._device = device
@ -369,9 +376,6 @@ class PlexClient(MediaPlayerDevice):
self._session.ratingKey) self._session.ratingKey)
self._media_content_rating = self._convert_na_to_none( self._media_content_rating = self._convert_na_to_none(
self._session.contentRating) self._session.contentRating)
else:
self._media_position = None
self._media_content_id = None
# player dependent data # player dependent data
if self._session and self._session.player: if self._session and self._session.player:
@ -405,7 +409,6 @@ class PlexClient(MediaPlayerDevice):
self._session.duration) self._session.duration)
else: else:
self._session_type = None self._session_type = None
self._media_duration = None
# media type # media type
if self._session_type == 'clip': if self._session_type == 'clip':
@ -418,11 +421,9 @@ class PlexClient(MediaPlayerDevice):
self._media_content_type = MEDIA_TYPE_VIDEO self._media_content_type = MEDIA_TYPE_VIDEO
elif self._session_type == 'track': elif self._session_type == 'track':
self._media_content_type = MEDIA_TYPE_MUSIC self._media_content_type = MEDIA_TYPE_MUSIC
else:
self._media_content_type = None
# title (movie name, tv episode name, music song name) # title (movie name, tv episode name, music song name)
if self._session: if self._session and self._is_player_active:
self._media_title = self._convert_na_to_none(self._session.title) self._media_title = self._convert_na_to_none(self._session.title)
# Movies # Movies
@ -431,9 +432,7 @@ class PlexClient(MediaPlayerDevice):
self._media_title += ' (' + str(self._session.year) + ')' self._media_title += ' (' + str(self._session.year) + ')'
# TV Show # TV Show
if (self._is_player_active and if self._media_content_type is MEDIA_TYPE_TVSHOW:
self._media_content_type is MEDIA_TYPE_TVSHOW):
# season number (00) # season number (00)
if callable(self._convert_na_to_none(self._session.seasons)): if callable(self._convert_na_to_none(self._session.seasons)):
self._media_season = self._convert_na_to_none( self._media_season = self._convert_na_to_none(
@ -443,23 +442,15 @@ class PlexClient(MediaPlayerDevice):
self._media_season = self._session.parentIndex.zfill(2) self._media_season = self._session.parentIndex.zfill(2)
else: else:
self._media_season = None self._media_season = None
# show name # show name
self._media_series_title = self._convert_na_to_none( self._media_series_title = self._convert_na_to_none(
self._session.grandparentTitle) self._session.grandparentTitle)
# episode number (00) # episode number (00)
if self._convert_na_to_none( if self._convert_na_to_none(self._session.index) is not None:
self._session.index) is not None:
self._media_episode = str(self._session.index).zfill(2) self._media_episode = str(self._session.index).zfill(2)
else:
self._media_season = None
self._media_series_title = None
self._media_episode = None
# Music # Music
if (self._is_player_active and if self._media_content_type == MEDIA_TYPE_MUSIC:
self._media_content_type == MEDIA_TYPE_MUSIC):
self._media_album_name = self._convert_na_to_none( self._media_album_name = self._convert_na_to_none(
self._session.parentTitle) self._session.parentTitle)
self._media_album_artist = self._convert_na_to_none( self._media_album_artist = self._convert_na_to_none(
@ -469,14 +460,9 @@ class PlexClient(MediaPlayerDevice):
self._session.originalTitle) self._session.originalTitle)
# use album artist if track artist is missing # use album artist if track artist is missing
if self._media_artist is None: if self._media_artist is None:
_LOGGER.debug("Using album artist because track artist was " _LOGGER.debug("Using album artist because track artist "
"not found: %s", self.entity_id) "was not found: %s", self.entity_id)
self._media_artist = self._media_album_artist self._media_artist = self._media_album_artist
else:
self._media_album_name = None
self._media_album_artist = None
self._media_track = None
self._media_artist = None
# set app name to library name # set app name to library name
if (self._session is not None if (self._session is not None
@ -501,8 +487,6 @@ class PlexClient(MediaPlayerDevice):
thumb_url = self._get_thumbnail_url(self._session.art) thumb_url = self._get_thumbnail_url(self._session.art)
self._media_image_url = thumb_url self._media_image_url = thumb_url
else:
self._media_image_url = None
def _get_thumbnail_url(self, property_value): def _get_thumbnail_url(self, property_value):
"""Return full URL (if exists) for a thumbnail property.""" """Return full URL (if exists) for a thumbnail property."""
@ -521,6 +505,7 @@ class PlexClient(MediaPlayerDevice):
"""Force client to idle.""" """Force client to idle."""
self._state = STATE_IDLE self._state = STATE_IDLE
self._session = None self._session = None
self._clear_media()
@property @property
def unique_id(self): def unique_id(self):

View file

@ -18,7 +18,7 @@ from homeassistant.const import (CONF_NAME, CONF_HOST, STATE_OFF, STATE_ON,
STATE_PLAYING, STATE_IDLE) STATE_PLAYING, STATE_IDLE)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['rxv==0.4.0'] REQUIREMENTS = ['rxv==0.5.1']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -33,7 +33,9 @@ SUPPORTED_FEATURES = (
SUPPORT_SELECT_SOURCE SUPPORT_SELECT_SOURCE
) )
REQUIREMENTS = ['pymusiccast==0.1.0'] KNOWN_HOSTS_KEY = 'data_yamaha_musiccast'
REQUIREMENTS = ['pymusiccast==0.1.2']
DEFAULT_NAME = "Yamaha Receiver" DEFAULT_NAME = "Yamaha Receiver"
DEFAULT_PORT = 5005 DEFAULT_PORT = 5005
@ -47,16 +49,48 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Yamaha MusicCast platform.""" """Set up the Yamaha MusicCast platform."""
import socket
import pymusiccast import pymusiccast
known_hosts = hass.data.get(KNOWN_HOSTS_KEY)
if known_hosts is None:
known_hosts = hass.data[KNOWN_HOSTS_KEY] = []
_LOGGER.debug("known_hosts: %s", known_hosts)
name = config.get(CONF_NAME) name = config.get(CONF_NAME)
host = config.get(CONF_HOST) host = config.get(CONF_HOST)
port = config.get(CONF_PORT) port = config.get(CONF_PORT)
receiver = pymusiccast.McDevice(host, udp_port=port) # Get IP of host to prevent duplicates
_LOGGER.debug("receiver: %s / Port: %d", receiver, port) try:
ipaddr = socket.gethostbyname(host)
except (OSError) as error:
_LOGGER.error(
"Could not communicate with %s:%d: %s", host, port, error)
return
add_devices([YamahaDevice(receiver, name)], True) if [item for item in known_hosts if item[0] == ipaddr]:
_LOGGER.warning("Host %s:%d already registered.", host, port)
return
if [item for item in known_hosts if item[1] == port]:
_LOGGER.warning("Port %s:%d already registered.", host, port)
return
reg_host = (ipaddr, port)
known_hosts.append(reg_host)
try:
receiver = pymusiccast.McDevice(ipaddr, udp_port=port)
except pymusiccast.exceptions.YMCInitError as err:
_LOGGER.error(err)
receiver = None
if receiver:
_LOGGER.debug("receiver: %s / Port: %d", receiver, port)
add_devices([YamahaDevice(receiver, name)], True)
else:
known_hosts.remove(reg_host)
class YamahaDevice(MediaPlayerDevice): class YamahaDevice(MediaPlayerDevice):

View file

@ -14,7 +14,7 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
from homeassistant.const import ( from homeassistant.const import (
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
CONF_HOST, CONF_METHOD, CONF_PORT, ATTR_STATE) CONF_HOST, CONF_METHOD, CONF_PORT, CONF_TYPE, CONF_TIMEOUT, ATTR_STATE)
DOMAIN = 'modbus' DOMAIN = 'modbus'
@ -24,7 +24,6 @@ REQUIREMENTS = ['pymodbus==1.3.1']
CONF_BAUDRATE = 'baudrate' CONF_BAUDRATE = 'baudrate'
CONF_BYTESIZE = 'bytesize' CONF_BYTESIZE = 'bytesize'
CONF_STOPBITS = 'stopbits' CONF_STOPBITS = 'stopbits'
CONF_TYPE = 'type'
CONF_PARITY = 'parity' CONF_PARITY = 'parity'
SERIAL_SCHEMA = { SERIAL_SCHEMA = {
@ -35,12 +34,14 @@ SERIAL_SCHEMA = {
vol.Required(CONF_PARITY): vol.Any('E', 'O', 'N'), vol.Required(CONF_PARITY): vol.Any('E', 'O', 'N'),
vol.Required(CONF_STOPBITS): vol.Any(1, 2), vol.Required(CONF_STOPBITS): vol.Any(1, 2),
vol.Required(CONF_TYPE): 'serial', vol.Required(CONF_TYPE): 'serial',
vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout,
} }
ETHERNET_SCHEMA = { ETHERNET_SCHEMA = {
vol.Required(CONF_HOST): cv.string, vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_PORT): cv.positive_int, vol.Required(CONF_PORT): cv.positive_int,
vol.Required(CONF_TYPE): vol.Any('tcp', 'udp'), vol.Required(CONF_TYPE): vol.Any('tcp', 'udp'),
vol.Optional(CONF_TIMEOUT, default=3): cv.socket_timeout,
} }
@ -89,15 +90,18 @@ def setup(hass, config):
baudrate=config[DOMAIN][CONF_BAUDRATE], baudrate=config[DOMAIN][CONF_BAUDRATE],
stopbits=config[DOMAIN][CONF_STOPBITS], stopbits=config[DOMAIN][CONF_STOPBITS],
bytesize=config[DOMAIN][CONF_BYTESIZE], bytesize=config[DOMAIN][CONF_BYTESIZE],
parity=config[DOMAIN][CONF_PARITY]) parity=config[DOMAIN][CONF_PARITY],
timeout=config[DOMAIN][CONF_TIMEOUT])
elif client_type == 'tcp': elif client_type == 'tcp':
from pymodbus.client.sync import ModbusTcpClient as ModbusClient from pymodbus.client.sync import ModbusTcpClient as ModbusClient
client = ModbusClient(host=config[DOMAIN][CONF_HOST], client = ModbusClient(host=config[DOMAIN][CONF_HOST],
port=config[DOMAIN][CONF_PORT]) port=config[DOMAIN][CONF_PORT],
timeout=config[DOMAIN][CONF_TIMEOUT])
elif client_type == 'udp': elif client_type == 'udp':
from pymodbus.client.sync import ModbusUdpClient as ModbusClient from pymodbus.client.sync import ModbusUdpClient as ModbusClient
client = ModbusClient(host=config[DOMAIN][CONF_HOST], client = ModbusClient(host=config[DOMAIN][CONF_HOST],
port=config[DOMAIN][CONF_PORT]) port=config[DOMAIN][CONF_PORT],
timeout=config[DOMAIN][CONF_TIMEOUT])
else: else:
return False return False

View file

@ -12,14 +12,19 @@ from homeassistant.const import MATCH_ALL
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.components.mqtt import valid_publish_topic from homeassistant.components.mqtt import valid_publish_topic
from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.event import async_track_state_change
import homeassistant.helpers.config_validation as cv
CONF_BASE_TOPIC = 'base_topic' CONF_BASE_TOPIC = 'base_topic'
CONF_PUBLISH_ATTRIBUTES = 'publish_attributes'
CONF_PUBLISH_TIMESTAMPS = 'publish_timestamps'
DEPENDENCIES = ['mqtt'] DEPENDENCIES = ['mqtt']
DOMAIN = 'mqtt_statestream' DOMAIN = 'mqtt_statestream'
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
vol.Required(CONF_BASE_TOPIC): valid_publish_topic vol.Required(CONF_BASE_TOPIC): valid_publish_topic,
vol.Optional(CONF_PUBLISH_ATTRIBUTES, default=False): cv.boolean,
vol.Optional(CONF_PUBLISH_TIMESTAMPS, default=False): cv.boolean
}) })
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
@ -29,6 +34,8 @@ def async_setup(hass, config):
"""Set up the MQTT state feed.""" """Set up the MQTT state feed."""
conf = config.get(DOMAIN, {}) conf = config.get(DOMAIN, {})
base_topic = conf.get(CONF_BASE_TOPIC) base_topic = conf.get(CONF_BASE_TOPIC)
publish_attributes = conf.get(CONF_PUBLISH_ATTRIBUTES)
publish_timestamps = conf.get(CONF_PUBLISH_TIMESTAMPS)
if not base_topic.endswith('/'): if not base_topic.endswith('/'):
base_topic = base_topic + '/' base_topic = base_topic + '/'
@ -38,8 +45,28 @@ def async_setup(hass, config):
return return
payload = new_state.state payload = new_state.state
topic = base_topic + entity_id.replace('.', '/') + '/state' mybase = base_topic + entity_id.replace('.', '/') + '/'
hass.components.mqtt.async_publish(topic, payload, 1, True) hass.components.mqtt.async_publish(mybase + 'state', payload, 1, True)
if publish_timestamps:
if new_state.last_updated:
hass.components.mqtt.async_publish(
mybase + 'last_updated',
new_state.last_updated.isoformat(),
1,
True)
if new_state.last_changed:
hass.components.mqtt.async_publish(
mybase + 'last_changed',
new_state.last_changed.isoformat(),
1,
True)
if publish_attributes:
for key, val in new_state.attributes.items():
if val:
hass.components.mqtt.async_publish(mybase + key,
val, 1, True)
async_track_state_change(hass, MATCH_ALL, _state_publisher) async_track_state_change(hass, MATCH_ALL, _state_publisher)
return True return True

View file

@ -0,0 +1,90 @@
"""
Clicksend audio platform for notify component.
This platform sends text to speech audio messages through clicksend
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.clicksendaudio/
"""
import json
import logging
import requests
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
CONF_USERNAME, CONF_API_KEY, CONF_RECIPIENT, HTTP_HEADER_CONTENT_TYPE,
CONTENT_TYPE_JSON)
from homeassistant.components.notify import (
PLATFORM_SCHEMA, BaseNotificationService)
_LOGGER = logging.getLogger(__name__)
BASE_API_URL = 'https://rest.clicksend.com/v3'
HEADERS = {HTTP_HEADER_CONTENT_TYPE: CONTENT_TYPE_JSON}
CONF_LANGUAGE = 'language'
CONF_VOICE = 'voice'
DEFAULT_LANGUAGE = 'en-us'
DEFAULT_VOICE = 'female'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_API_KEY): cv.string,
vol.Required(CONF_RECIPIENT): cv.string,
vol.Optional(CONF_LANGUAGE, default=DEFAULT_LANGUAGE): cv.string,
vol.Optional(CONF_VOICE, default=DEFAULT_VOICE): cv.string,
})
def get_service(hass, config, discovery_info=None):
"""Get the ClickSend notification service."""
if _authenticate(config) is False:
_LOGGER.error("You are not authorized to access ClickSend")
return None
return ClicksendNotificationService(config)
class ClicksendNotificationService(BaseNotificationService):
"""Implementation of a notification service for the ClickSend service."""
def __init__(self, config):
"""Initialize the service."""
self.username = config.get(CONF_USERNAME)
self.api_key = config.get(CONF_API_KEY)
self.recipient = config.get(CONF_RECIPIENT)
self.language = config.get(CONF_LANGUAGE)
self.voice = config.get(CONF_VOICE)
def send_message(self, message="", **kwargs):
"""Send a voice call to a user."""
data = ({'messages': [{'source': 'hass.notify', 'from': self.recipient,
'to': self.recipient, 'body': message,
'lang': self.language, 'voice': self.voice}]})
api_url = "{}/voice/send".format(BASE_API_URL)
resp = requests.post(api_url, data=json.dumps(data), headers=HEADERS,
auth=(self.username, self.api_key), timeout=5)
obj = json.loads(resp.text)
response_msg = obj['response_msg']
response_code = obj['response_code']
if resp.status_code != 200:
_LOGGER.error("Error %s : %s (Code %s)", resp.status_code,
response_msg, response_code)
def _authenticate(config):
"""Authenticate with ClickSend."""
api_url = '{}/account'.format(BASE_API_URL)
resp = requests.get(api_url, headers=HEADERS,
auth=(config.get(CONF_USERNAME),
config.get(CONF_API_KEY)), timeout=5)
if resp.status_code != 200:
return False
return True

View file

@ -15,7 +15,7 @@ from homeassistant.components.notify import (
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['discord.py==0.16.11'] REQUIREMENTS = ['discord.py==0.16.12']
CONF_TOKEN = 'token' CONF_TOKEN = 'token'

View file

@ -56,8 +56,15 @@ class FacebookNotificationService(BaseNotificationService):
return return
for target in targets: for target in targets:
# If the target starts with a "+", we suppose it's a phone number,
# otherwise it's a user id.
if target.startswith('+'):
recipient = {"phone_number": target}
else:
recipient = {"id": target}
body = { body = {
"recipient": {"phone_number": target}, "recipient": recipient,
"message": body_message "message": body_message
} }
import json import json

View file

@ -0,0 +1,76 @@
"""
Rocket.Chat notification service.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.rocketchat/
"""
import logging
import voluptuous as vol
from homeassistant.const import (
CONF_URL, CONF_USERNAME, CONF_PASSWORD)
from homeassistant.components.notify import (
ATTR_DATA, PLATFORM_SCHEMA,
BaseNotificationService)
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['rocketchat-API==0.6.1']
CONF_ROOM = 'room'
_LOGGER = logging.getLogger(__name__)
# pylint: disable=no-value-for-parameter
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_URL): vol.Url(),
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_ROOM): cv.string,
})
def get_service(hass, config, discovery_info=None):
"""Return the notify service."""
from rocketchat_API.APIExceptions.RocketExceptions import (
RocketConnectionException, RocketAuthenticationException)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
url = config.get(CONF_URL)
room = config.get(CONF_ROOM)
try:
return RocketChatNotificationService(url, username, password, room)
except RocketConnectionException:
_LOGGER.warning(
"Unable to connect to Rocket.Chat server at %s.", url)
except RocketAuthenticationException:
_LOGGER.warning(
"Rocket.Chat authentication failed for user %s.", username)
_LOGGER.info("Please check your username/password.")
return None
class RocketChatNotificationService(BaseNotificationService):
"""Implement the notification service for Rocket.Chat."""
def __init__(self, url, username, password, room):
"""Initialize the service."""
from rocketchat_API.rocketchat import RocketChat
self._room = room
self._server = RocketChat(username, password, server_url=url)
def send_message(self, message="", **kwargs):
"""Send a message to Rocket.Chat."""
data = kwargs.get(ATTR_DATA) or {}
resp = self._server.chat_post_message(message, channel=self._room,
**data)
if resp.status_code == 200:
success = resp.json()["success"]
if not success:
_LOGGER.error("Unable to post Rocket.Chat message")
else:
_LOGGER.error("Incorrect status code when posting message: %d",
resp.status_code)

View file

@ -15,8 +15,8 @@ from homeassistant.const import CONF_PASSWORD, CONF_SENDER, CONF_RECIPIENT
REQUIREMENTS = ['sleekxmpp==1.3.2', REQUIREMENTS = ['sleekxmpp==1.3.2',
'dnspython3==1.15.0', 'dnspython3==1.15.0',
'pyasn1==0.3.6', 'pyasn1==0.3.7',
'pyasn1-modules==0.1.4'] 'pyasn1-modules==0.1.5']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -129,11 +129,11 @@ def async_setup(hass, config):
) )
hass.services.async_register(DOMAIN, SERVICE_CREATE, create_service, hass.services.async_register(DOMAIN, SERVICE_CREATE, create_service,
descriptions[DOMAIN][SERVICE_CREATE], descriptions[SERVICE_CREATE],
SCHEMA_SERVICE_CREATE) SCHEMA_SERVICE_CREATE)
hass.services.async_register(DOMAIN, SERVICE_DISMISS, dismiss_service, hass.services.async_register(DOMAIN, SERVICE_DISMISS, dismiss_service,
descriptions[DOMAIN][SERVICE_DISMISS], descriptions[SERVICE_DISMISS],
SCHEMA_SERVICE_DISMISS) SCHEMA_SERVICE_DISMISS)
return True return True

View file

@ -0,0 +1,23 @@
create:
description: Show a notification in the frontend
fields:
message:
description: Message body of the notification. [Templates accepted]
example: Please check your configuration.yaml.
title:
description: Optional title for your notification. [Optional, Templates accepted]
example: Test notification
notification_id:
description: Target ID of the notification, will replace a notification with the same Id. [Optional]
example: 1234
dismiss:
description: Remove a notification from the frontend
fields:
notification_id:
description: Target ID of the notification, which should be removed. [Required]
example: 1234

View file

@ -1,8 +1,9 @@
"""Component to allow running Python scripts.""" """Component to allow running Python scripts."""
import glob
import os
import logging
import datetime import datetime
import glob
import logging
import os
import time
import voluptuous as vol import voluptuous as vol
@ -10,6 +11,7 @@ from homeassistant.const import SERVICE_RELOAD
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
from homeassistant.util import sanitize_filename from homeassistant.util import sanitize_filename
import homeassistant.util.dt as dt_util
DOMAIN = 'python_script' DOMAIN = 'python_script'
REQUIREMENTS = ['restrictedpython==4.0a3'] REQUIREMENTS = ['restrictedpython==4.0a3']
@ -25,6 +27,13 @@ ALLOWED_EVENTBUS = set(['fire'])
ALLOWED_STATEMACHINE = set(['entity_ids', 'all', 'get', 'is_state', ALLOWED_STATEMACHINE = set(['entity_ids', 'all', 'get', 'is_state',
'is_state_attr', 'remove', 'set']) 'is_state_attr', 'remove', 'set'])
ALLOWED_SERVICEREGISTRY = set(['services', 'has_service', 'call']) ALLOWED_SERVICEREGISTRY = set(['services', 'has_service', 'call'])
ALLOWED_TIME = set(['sleep', 'strftime', 'strptime', 'gmtime', 'localtime',
'ctime', 'time', 'mktime'])
ALLOWED_DATETIME = set(['date', 'time', 'datetime', 'timedelta', 'tzinfo'])
ALLOWED_DT_UTIL = set([
'utcnow', 'now', 'as_utc', 'as_timestamp', 'as_local',
'utc_from_timestamp', 'start_of_local_day', 'parse_datetime', 'parse_date',
'get_age'])
class ScriptError(HomeAssistantError): class ScriptError(HomeAssistantError):
@ -111,7 +120,10 @@ def execute(hass, filename, source, data=None):
elif (obj is hass and name not in ALLOWED_HASS or elif (obj is hass and name not in ALLOWED_HASS or
obj is hass.bus and name not in ALLOWED_EVENTBUS or obj is hass.bus and name not in ALLOWED_EVENTBUS or
obj is hass.states and name not in ALLOWED_STATEMACHINE or obj is hass.states and name not in ALLOWED_STATEMACHINE or
obj is hass.services and name not in ALLOWED_SERVICEREGISTRY): obj is hass.services and name not in ALLOWED_SERVICEREGISTRY or
obj is dt_util and name not in ALLOWED_DT_UTIL or
obj is datetime and name not in ALLOWED_DATETIME or
isinstance(obj, TimeWrapper) and name not in ALLOWED_TIME):
raise ScriptError('Not allowed to access {}.{}'.format( raise ScriptError('Not allowed to access {}.{}'.format(
obj.__class__.__name__, name)) obj.__class__.__name__, name))
@ -120,6 +132,8 @@ def execute(hass, filename, source, data=None):
builtins = safe_builtins.copy() builtins = safe_builtins.copy()
builtins.update(utility_builtins) builtins.update(utility_builtins)
builtins['datetime'] = datetime builtins['datetime'] = datetime
builtins['time'] = TimeWrapper()
builtins['dt_util'] = dt_util
restricted_globals = { restricted_globals = {
'__builtins__': builtins, '__builtins__': builtins,
'_print_': StubPrinter, '_print_': StubPrinter,
@ -159,3 +173,24 @@ class StubPrinter:
# pylint: disable=no-self-use # pylint: disable=no-self-use
_LOGGER.warning( _LOGGER.warning(
"Don't use print() inside scripts. Use logger.info() instead.") "Don't use print() inside scripts. Use logger.info() instead.")
class TimeWrapper:
"""Wrapper of the time module."""
# Class variable, only going to warn once per Home Assistant run
warned = False
# pylint: disable=no-self-use
def sleep(self, *args, **kwargs):
"""Sleep method that warns once."""
if not TimeWrapper.warned:
TimeWrapper.warned = True
_LOGGER.warning('Using time.sleep can reduce the performance of '
'Home Assistant')
time.sleep(*args, **kwargs)
def __getattr__(self, attr):
"""Fetch an attribute from Time module."""
return getattr(time, attr)

View file

@ -0,0 +1,179 @@
"""
Support for Melnor RainCloud sprinkler water timer.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/raincloud/
"""
import asyncio
import logging
from datetime import timedelta
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
ATTR_ATTRIBUTION, CONF_USERNAME, CONF_PASSWORD, CONF_SCAN_INTERVAL)
from homeassistant.helpers.event import track_time_interval
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect, dispatcher_send)
from requests.exceptions import HTTPError, ConnectTimeout
REQUIREMENTS = ['raincloudy==0.0.3']
_LOGGER = logging.getLogger(__name__)
ALLOWED_WATERING_TIME = [5, 10, 15, 30, 45, 60]
CONF_ATTRIBUTION = "Data provided by Melnor Aquatimer.com"
CONF_WATERING_TIME = 'watering_minutes'
NOTIFICATION_ID = 'raincloud_notification'
NOTIFICATION_TITLE = 'Rain Cloud Setup'
DATA_RAINCLOUD = 'raincloud'
DOMAIN = 'raincloud'
DEFAULT_WATERING_TIME = 15
KEY_MAP = {
'auto_watering': 'Automatic Watering',
'battery': 'Battery',
'is_watering': 'Watering',
'manual_watering': 'Manual Watering',
'next_cycle': 'Next Cycle',
'rain_delay': 'Rain Delay',
'status': 'Status',
'watering_time': 'Remaining Watering Time',
}
ICON_MAP = {
'auto_watering': 'mdi:autorenew',
'battery': '',
'is_watering': '',
'manual_watering': 'mdi:water-pump',
'next_cycle': 'mdi:calendar-clock',
'rain_delay': 'mdi:weather-rainy',
'status': '',
'watering_time': 'mdi:water-pump',
}
UNIT_OF_MEASUREMENT_MAP = {
'auto_watering': '',
'battery': '%',
'is_watering': '',
'manual_watering': '',
'next_cycle': '',
'rain_delay': 'days',
'status': '',
'watering_time': 'min',
}
BINARY_SENSORS = ['is_watering', 'status']
SENSORS = ['battery', 'next_cycle', 'rain_delay', 'watering_time']
SWITCHES = ['auto_watering', 'manual_watering']
SCAN_INTERVAL = timedelta(seconds=20)
SIGNAL_UPDATE_RAINCLOUD = "raincloud_update"
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL):
cv.time_period,
}),
}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):
"""Set up the Melnor RainCloud component."""
conf = config[DOMAIN]
username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD)
scan_interval = conf.get(CONF_SCAN_INTERVAL)
try:
from raincloudy.core import RainCloudy
raincloud = RainCloudy(username=username, password=password)
if not raincloud.is_connected:
raise HTTPError
hass.data[DATA_RAINCLOUD] = RainCloudHub(raincloud)
except (ConnectTimeout, HTTPError) as ex:
_LOGGER.error("Unable to connect to Rain Cloud service: %s", str(ex))
hass.components.persistent_notification.create(
'Error: {}<br />'
'You will need to restart hass after fixing.'
''.format(ex),
title=NOTIFICATION_TITLE,
notification_id=NOTIFICATION_ID)
return False
def hub_refresh(event_time):
"""Call Raincloud hub to refresh information."""
_LOGGER.debug("Updating RainCloud Hub component.")
hass.data[DATA_RAINCLOUD].data.update()
dispatcher_send(hass, SIGNAL_UPDATE_RAINCLOUD)
# Call the Raincloud API to refresh updates
track_time_interval(hass, hub_refresh, scan_interval)
return True
class RainCloudHub(object):
"""Representation of a base RainCloud device."""
def __init__(self, data):
"""Initialize the entity."""
self.data = data
class RainCloudEntity(Entity):
"""Entity class for RainCloud devices."""
def __init__(self, data, sensor_type):
"""Initialize the RainCloud entity."""
self.data = data
self._sensor_type = sensor_type
self._name = "{0} {1}".format(
self.data.name, KEY_MAP.get(self._sensor_type))
self._state = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@asyncio.coroutine
def async_added_to_hass(self):
"""Register callbacks."""
async_dispatcher_connect(
self.hass, SIGNAL_UPDATE_RAINCLOUD, self._update_callback)
def _update_callback(self):
"""Callback update method."""
self.schedule_update_ha_state(True)
@property
def unit_of_measurement(self):
"""Return the units of measurement."""
return UNIT_OF_MEASUREMENT_MAP.get(self._sensor_type)
@property
def device_state_attributes(self):
"""Return the state attributes."""
return {
ATTR_ATTRIBUTION: CONF_ATTRIBUTION,
'current_time': self.data.current_time,
'identifier': self.data.serial,
}
@property
def icon(self):
"""Icon to use in the frontend, if any."""
return ICON_MAP.get(self._sensor_type)

View file

@ -12,7 +12,8 @@ from homeassistant.const import (
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP
) )
REQUIREMENTS = ['raspihats==2.2.1'] REQUIREMENTS = ['raspihats==2.2.3',
'smbus-cffi==0.5.1']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -10,10 +10,11 @@ https://home-assistant.io/components/recorder/
import asyncio import asyncio
import concurrent.futures import concurrent.futures
import logging import logging
from os import path
import queue import queue
import threading import threading
import time import time
from datetime import timedelta, datetime from datetime import datetime, timedelta
from typing import Optional, Dict from typing import Optional, Dict
import voluptuous as vol import voluptuous as vol
@ -28,6 +29,7 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from homeassistant import config as conf_util
from . import purge, migration from . import purge, migration
from .const import DATA_INSTANCE from .const import DATA_INSTANCE
@ -39,11 +41,21 @@ _LOGGER = logging.getLogger(__name__)
DOMAIN = 'recorder' DOMAIN = 'recorder'
SERVICE_PURGE = 'purge'
ATTR_KEEP_DAYS = 'keep_days'
SERVICE_PURGE_SCHEMA = vol.Schema({
vol.Required(ATTR_KEEP_DAYS):
vol.All(vol.Coerce(int), vol.Range(min=0))
})
DEFAULT_URL = 'sqlite:///{hass_config_path}' DEFAULT_URL = 'sqlite:///{hass_config_path}'
DEFAULT_DB_FILE = 'home-assistant_v2.db' DEFAULT_DB_FILE = 'home-assistant_v2.db'
CONF_DB_URL = 'db_url' CONF_DB_URL = 'db_url'
CONF_PURGE_DAYS = 'purge_days' CONF_PURGE_KEEP_DAYS = 'purge_keep_days'
CONF_PURGE_INTERVAL = 'purge_interval'
CONF_EVENT_TYPES = 'event_types' CONF_EVENT_TYPES = 'event_types'
CONNECT_RETRY_WAIT = 3 CONNECT_RETRY_WAIT = 3
@ -65,7 +77,9 @@ FILTER_SCHEMA = vol.Schema({
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: FILTER_SCHEMA.extend({ DOMAIN: FILTER_SCHEMA.extend({
vol.Optional(CONF_PURGE_DAYS): vol.Inclusive(CONF_PURGE_KEEP_DAYS, 'purge'):
vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Inclusive(CONF_PURGE_INTERVAL, 'purge'):
vol.All(vol.Coerce(int), vol.Range(min=1)), vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Optional(CONF_DB_URL): cv.string, vol.Optional(CONF_DB_URL): cv.string,
}) })
@ -106,7 +120,8 @@ def run_information(hass, point_in_time: Optional[datetime]=None):
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the recorder.""" """Set up the recorder."""
conf = config.get(DOMAIN, {}) conf = config.get(DOMAIN, {})
purge_days = conf.get(CONF_PURGE_DAYS) purge_days = conf.get(CONF_PURGE_KEEP_DAYS)
purge_interval = conf.get(CONF_PURGE_INTERVAL)
db_url = conf.get(CONF_DB_URL, None) db_url = conf.get(CONF_DB_URL, None)
if not db_url: if not db_url:
@ -116,24 +131,46 @@ def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
include = conf.get(CONF_INCLUDE, {}) include = conf.get(CONF_INCLUDE, {})
exclude = conf.get(CONF_EXCLUDE, {}) exclude = conf.get(CONF_EXCLUDE, {})
instance = hass.data[DATA_INSTANCE] = Recorder( instance = hass.data[DATA_INSTANCE] = Recorder(
hass, purge_days=purge_days, uri=db_url, include=include, hass, uri=db_url, include=include, exclude=exclude)
exclude=exclude)
instance.async_initialize() instance.async_initialize()
instance.start() instance.start()
@asyncio.coroutine
def async_handle_purge_interval(now):
"""Handle purge interval."""
instance.do_purge(purge_days)
@asyncio.coroutine
def async_handle_purge_service(service):
"""Handle calls to the purge service."""
instance.do_purge(service.data[ATTR_KEEP_DAYS])
descriptions = yield from hass.async_add_job(
conf_util.load_yaml_config_file, path.join(
path.dirname(__file__), 'services.yaml'))
if purge_interval and purge_days:
async_track_time_interval(hass, async_handle_purge_interval,
timedelta(days=purge_interval))
hass.services.async_register(DOMAIN, SERVICE_PURGE,
async_handle_purge_service,
descriptions.get(SERVICE_PURGE),
schema=SERVICE_PURGE_SCHEMA)
return (yield from instance.async_db_ready) return (yield from instance.async_db_ready)
class Recorder(threading.Thread): class Recorder(threading.Thread):
"""A threaded recorder class.""" """A threaded recorder class."""
def __init__(self, hass: HomeAssistant, purge_days: int, uri: str, def __init__(self, hass: HomeAssistant, uri: str,
include: Dict, exclude: Dict) -> None: include: Dict, exclude: Dict) -> None:
"""Initialize the recorder.""" """Initialize the recorder."""
threading.Thread.__init__(self, name='Recorder') threading.Thread.__init__(self, name='Recorder')
self.hass = hass self.hass = hass
self.purge_days = purge_days self.purge_days = None
self.queue = queue.Queue() # type: Any self.queue = queue.Queue() # type: Any
self.recording_start = dt_util.utcnow() self.recording_start = dt_util.utcnow()
self.db_url = uri self.db_url = uri
@ -148,12 +185,19 @@ class Recorder(threading.Thread):
self.exclude_t = exclude.get(CONF_EVENT_TYPES, []) self.exclude_t = exclude.get(CONF_EVENT_TYPES, [])
self.get_session = None self.get_session = None
self.purge_task = object()
@callback @callback
def async_initialize(self): def async_initialize(self):
"""Initialize the recorder.""" """Initialize the recorder."""
self.hass.bus.async_listen(MATCH_ALL, self.event_listener) self.hass.bus.async_listen(MATCH_ALL, self.event_listener)
def do_purge(self, purge_days=None):
"""Event listener for purging data."""
if purge_days is not None:
self.purge_days = purge_days
self.queue.put(self.purge_task)
def run(self): def run(self):
"""Start processing events to save.""" """Start processing events to save."""
from .models import States, Events from .models import States, Events
@ -190,7 +234,6 @@ class Recorder(threading.Thread):
self.hass.add_job(connection_failed) self.hass.add_job(connection_failed)
return return
purge_task = object()
shutdown_task = object() shutdown_task = object()
hass_started = concurrent.futures.Future() hass_started = concurrent.futures.Future()
@ -220,15 +263,6 @@ class Recorder(threading.Thread):
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START,
notify_hass_started) notify_hass_started)
if self.purge_days is not None:
@callback
def do_purge(now):
"""Event listener for purging data."""
self.queue.put(purge_task)
async_track_time_interval(self.hass, do_purge,
timedelta(days=2))
self.hass.add_job(register) self.hass.add_job(register)
result = hass_started.result() result = hass_started.result()
@ -244,7 +278,7 @@ class Recorder(threading.Thread):
self._close_connection() self._close_connection()
self.queue.task_done() self.queue.task_done()
return return
elif event is purge_task: elif event is self.purge_task:
purge.purge_old_data(self, self.purge_days) purge.purge_old_data(self, self.purge_days)
continue continue
elif event.event_type == EVENT_TIME_CHANGED: elif event.event_type == EVENT_TIME_CHANGED:

View file

@ -0,0 +1,9 @@
# Describes the format for available recorder services
purge:
description: Start purge task - delete events and states older than x days, according to keep_days service data.
fields:
keep_days:
description: Number of history days to keep in database after purge. Value >= 0
example: 2

View file

@ -16,7 +16,7 @@ from homeassistant.const import (
CONF_DEVICES) CONF_DEVICES)
from homeassistant.components.remote import PLATFORM_SCHEMA from homeassistant.components.remote import PLATFORM_SCHEMA
REQUIREMENTS = ['pyitachip2ir==0.0.6'] REQUIREMENTS = ['pyitachip2ir==0.0.7']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -11,6 +11,7 @@ import logging
import os import os
import async_timeout import async_timeout
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, CONF_COMMAND, CONF_HOST, CONF_PORT, ATTR_ENTITY_ID, CONF_COMMAND, CONF_HOST, CONF_PORT,
@ -22,6 +23,7 @@ from homeassistant.helpers.deprecation import get_deprecated
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
import voluptuous as vol import voluptuous as vol
REQUIREMENTS = ['rflink==0.0.34'] REQUIREMENTS = ['rflink==0.0.34']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -370,6 +372,19 @@ class RflinkCommand(RflinkDevice):
# if the state is true, it gets set as false # if the state is true, it gets set as false
self._state = self._state in [STATE_UNKNOWN, False] self._state = self._state in [STATE_UNKNOWN, False]
# Cover options for RFlink
elif command == 'close_cover':
cmd = 'DOWN'
self._state = False
elif command == 'open_cover':
cmd = 'UP'
self._state = True
elif command == 'stop_cover':
cmd = 'STOP'
self._state = True
# Send initial command and queue repetitions. # Send initial command and queue repetitions.
# This allows the entity state to be updated quickly and not having to # This allows the entity state to be updated quickly and not having to
# wait for all repetitions to be sent # wait for all repetitions to be sent

View file

@ -0,0 +1,81 @@
"""
Support for Abode Security System sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.abode/
"""
import logging
from homeassistant.components.abode import AbodeDevice, DOMAIN as ABODE_DOMAIN
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['abode']
# Sensor types: Name, icon
SENSOR_TYPES = {
'temp': ['Temperature', 'thermometer'],
'humidity': ['Humidity', 'water-percent'],
'lux': ['Lux', 'lightbulb'],
}
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up a sensor for an Abode device."""
import abodepy.helpers.constants as CONST
data = hass.data[ABODE_DOMAIN]
devices = []
for device in data.abode.get_devices(generic_type=CONST.TYPE_SENSOR):
if data.is_excluded(device):
continue
for sensor_type in SENSOR_TYPES:
devices.append(AbodeSensor(data, device, sensor_type))
data.devices.extend(devices)
add_devices(devices)
class AbodeSensor(AbodeDevice):
"""A sensor implementation for Abode devices."""
def __init__(self, data, device, sensor_type):
"""Initialize a sensor for an Abode device."""
super().__init__(data, device)
self._sensor_type = sensor_type
self._icon = 'mdi:{}'.format(SENSOR_TYPES[self._sensor_type][1])
self._name = '{0} {1}'.format(self._device.name,
SENSOR_TYPES[self._sensor_type][0])
@property
def icon(self):
"""Icon to use in the frontend, if any."""
return self._icon
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
if self._sensor_type == 'temp':
return self._device.temp
elif self._sensor_type == 'humidity':
return self._device.humidity
elif self._sensor_type == 'lux':
return self._device.lux
@property
def unit_of_measurement(self):
"""Return the units of measurement."""
if self._sensor_type == 'temp':
return self._device.temp_unit
elif self._sensor_type == 'humidity':
return self._device.humidity_unit
elif self._sensor_type == 'lux':
return self._device.lux_unit

View file

@ -4,7 +4,6 @@ Support for AirVisual air quality sensors.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.airvisual/ https://home-assistant.io/components/sensor.airvisual/
""" """
import asyncio import asyncio
from logging import getLogger from logging import getLogger
from datetime import timedelta from datetime import timedelta
@ -15,13 +14,15 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_API_KEY, ATTR_ATTRIBUTION, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_API_KEY,
CONF_LATITUDE, CONF_LONGITUDE, CONF_MONITORED_CONDITIONS, CONF_STATE) CONF_LATITUDE, CONF_LONGITUDE, CONF_MONITORED_CONDITIONS, CONF_STATE,
CONF_SHOW_ON_MAP)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle from homeassistant.util import Throttle
_LOGGER = getLogger(__name__)
REQUIREMENTS = ['pyairvisual==1.0.0'] REQUIREMENTS = ['pyairvisual==1.0.0']
_LOGGER = getLogger(__name__)
ATTR_CITY = 'city' ATTR_CITY = 'city'
ATTR_COUNTRY = 'country' ATTR_COUNTRY = 'country'
ATTR_POLLUTANT_SYMBOL = 'pollutant_symbol' ATTR_POLLUTANT_SYMBOL = 'pollutant_symbol'
@ -32,6 +33,7 @@ ATTR_TIMESTAMP = 'timestamp'
CONF_CITY = 'city' CONF_CITY = 'city'
CONF_COUNTRY = 'country' CONF_COUNTRY = 'country'
CONF_RADIUS = 'radius' CONF_RADIUS = 'radius'
CONF_ATTRIBUTION = "Data provided by AirVisual"
MASS_PARTS_PER_MILLION = 'ppm' MASS_PARTS_PER_MILLION = 'ppm'
MASS_PARTS_PER_BILLION = 'ppb' MASS_PARTS_PER_BILLION = 'ppb'
@ -39,56 +41,22 @@ VOLUME_MICROGRAMS_PER_CUBIC_METER = 'µg/m3'
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10) MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
POLLUTANT_LEVEL_MAPPING = [{ POLLUTANT_LEVEL_MAPPING = [
'label': 'Good', {'label': 'Good', 'minimum': 0, 'maximum': 50},
'minimum': 0, {'label': 'Moderate', 'minimum': 51, 'maximum': 100},
'maximum': 50 {'label': 'Unhealthy for sensitive group', 'minimum': 101, 'maximum': 150},
}, { {'label': 'Unhealthy', 'minimum': 151, 'maximum': 200},
'label': 'Moderate', {'label': 'Very Unhealthy', 'minimum': 201, 'maximum': 300},
'minimum': 51, {'label': 'Hazardous', 'minimum': 301, 'maximum': 10000}
'maximum': 100 ]
}, {
'label': 'Unhealthy for Sensitive Groups',
'minimum': 101,
'maximum': 150
}, {
'label': 'Unhealthy',
'minimum': 151,
'maximum': 200
}, {
'label': 'Very Unhealthy',
'minimum': 201,
'maximum': 300
}, {
'label': 'Hazardous',
'minimum': 301,
'maximum': 10000
}]
POLLUTANT_MAPPING = { POLLUTANT_MAPPING = {
'co': { 'co': {'label': 'Carbon Monoxide', 'unit': MASS_PARTS_PER_MILLION},
'label': 'Carbon Monoxide', 'n2': {'label': 'Nitrogen Dioxide', 'unit': MASS_PARTS_PER_BILLION},
'unit': MASS_PARTS_PER_MILLION 'o3': {'label': 'Ozone', 'unit': MASS_PARTS_PER_BILLION},
}, 'p1': {'label': 'PM10', 'unit': VOLUME_MICROGRAMS_PER_CUBIC_METER},
'n2': { 'p2': {'label': 'PM2.5', 'unit': VOLUME_MICROGRAMS_PER_CUBIC_METER},
'label': 'Nitrogen Dioxide', 's2': {'label': 'Sulfur Dioxide', 'unit': MASS_PARTS_PER_BILLION},
'unit': MASS_PARTS_PER_BILLION
},
'o3': {
'label': 'Ozone',
'unit': MASS_PARTS_PER_BILLION
},
'p1': {
'label': 'PM10',
'unit': VOLUME_MICROGRAMS_PER_CUBIC_METER
},
'p2': {
'label': 'PM2.5',
'unit': VOLUME_MICROGRAMS_PER_CUBIC_METER
},
's2': {
'label': 'Sulfur Dioxide',
'unit': MASS_PARTS_PER_BILLION
}
} }
SENSOR_LOCALES = {'cn': 'Chinese', 'us': 'U.S.'} SENSOR_LOCALES = {'cn': 'Chinese', 'us': 'U.S.'}
@ -99,22 +67,16 @@ SENSOR_TYPES = [
] ]
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_API_KEY): vol.Required(CONF_API_KEY): cv.string,
cv.string,
vol.Required(CONF_MONITORED_CONDITIONS): vol.Required(CONF_MONITORED_CONDITIONS):
vol.All(cv.ensure_list, [vol.In(SENSOR_LOCALES)]), vol.All(cv.ensure_list, [vol.In(SENSOR_LOCALES)]),
vol.Optional(CONF_LATITUDE): vol.Optional(CONF_CITY): cv.string,
cv.latitude, vol.Optional(CONF_COUNTRY): cv.string,
vol.Optional(CONF_LONGITUDE): vol.Optional(CONF_LATITUDE): cv.latitude,
cv.longitude, vol.Optional(CONF_LONGITUDE): cv.longitude,
vol.Optional(CONF_RADIUS, default=1000): vol.Optional(CONF_RADIUS, default=1000): cv.positive_int,
cv.positive_int, vol.Optional(CONF_SHOW_ON_MAP, default=True): cv.boolean,
vol.Optional(CONF_CITY): vol.Optional(CONF_STATE): cv.string,
cv.string,
vol.Optional(CONF_STATE):
cv.string,
vol.Optional(CONF_COUNTRY):
cv.string
}) })
@ -123,8 +85,6 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Configure the platform and add the sensors.""" """Configure the platform and add the sensors."""
import pyairvisual as pav import pyairvisual as pav
_LOGGER.debug('Received configuration: %s', config)
api_key = config.get(CONF_API_KEY) api_key = config.get(CONF_API_KEY)
monitored_locales = config.get(CONF_MONITORED_CONDITIONS) monitored_locales = config.get(CONF_MONITORED_CONDITIONS)
latitude = config.get(CONF_LATITUDE, hass.config.latitude) latitude = config.get(CONF_LATITUDE, hass.config.latitude)
@ -133,20 +93,20 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
city = config.get(CONF_CITY) city = config.get(CONF_CITY)
state = config.get(CONF_STATE) state = config.get(CONF_STATE)
country = config.get(CONF_COUNTRY) country = config.get(CONF_COUNTRY)
show_on_map = config.get(CONF_SHOW_ON_MAP)
if city and state and country: if city and state and country:
_LOGGER.debug('Using city, state, and country: %s, %s, %s', city, _LOGGER.debug(
state, country) "Using city, state, and country: %s, %s, %s", city, state, country)
data = AirVisualData( data = AirVisualData(
pav.Client(api_key), city=city, state=state, country=country) pav.Client(api_key), city=city, state=state, country=country,
show_on_map=show_on_map)
else: else:
_LOGGER.debug('Using latitude and longitude: %s, %s', latitude, _LOGGER.debug(
longitude) "Using latitude and longitude: %s, %s", latitude, longitude)
data = AirVisualData( data = AirVisualData(
pav.Client(api_key), pav.Client(api_key), latitude=latitude, longitude=longitude,
latitude=latitude, radius=radius, show_on_map=show_on_map)
longitude=longitude,
radius=radius)
sensors = [] sensors = []
for locale in monitored_locales: for locale in monitored_locales:
@ -167,7 +127,7 @@ class AirVisualBaseSensor(Entity):
"""Define a base class for all of our sensors.""" """Define a base class for all of our sensors."""
def __init__(self, data, name, icon, locale): def __init__(self, data, name, icon, locale):
"""Initialize.""" """Initialize the sensor."""
self._data = data self._data = data
self._icon = icon self._icon = icon
self._locale = locale self._locale = locale
@ -177,17 +137,24 @@ class AirVisualBaseSensor(Entity):
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes.""" """Return the device state attributes."""
return { attrs = {
ATTR_ATTRIBUTION: 'AirVisual©', ATTR_ATTRIBUTION: CONF_ATTRIBUTION,
ATTR_CITY: self._data.city, ATTR_CITY: self._data.city,
ATTR_COUNTRY: self._data.country, ATTR_COUNTRY: self._data.country,
ATTR_REGION: self._data.state, ATTR_REGION: self._data.state,
ATTR_LATITUDE: self._data.latitude,
ATTR_LONGITUDE: self._data.longitude,
ATTR_TIMESTAMP: self._data.pollution_info.get('ts') ATTR_TIMESTAMP: self._data.pollution_info.get('ts')
} }
if self._data.show_on_map:
attrs[ATTR_LATITUDE] = self._data.latitude
attrs[ATTR_LONGITUDE] = self._data.longitude
else:
attrs['lati'] = self._data.latitude
attrs['long'] = self._data.longitude
return attrs
@property @property
def icon(self): def icon(self):
"""Return the icon.""" """Return the icon."""
@ -206,7 +173,7 @@ class AirVisualBaseSensor(Entity):
@asyncio.coroutine @asyncio.coroutine
def async_update(self): def async_update(self):
"""Update the status of the sensor.""" """Update the status of the sensor."""
_LOGGER.debug('Updating sensor: %s', self._name) _LOGGER.debug("Updating sensor: %s", self._name)
self._data.update() self._data.update()
@ -251,14 +218,14 @@ class MainPollutantSensor(AirVisualBaseSensor):
"""Define a sensor to the main pollutant of an area.""" """Define a sensor to the main pollutant of an area."""
def __init__(self, data, name, icon, locale): def __init__(self, data, name, icon, locale):
"""Initialize.""" """Initialize the sensor."""
super().__init__(data, name, icon, locale) super().__init__(data, name, icon, locale)
self._symbol = None self._symbol = None
self._unit = None self._unit = None
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes.""" """Return the device state attributes."""
return merge_two_dicts(super().device_state_attributes, { return merge_two_dicts(super().device_state_attributes, {
ATTR_POLLUTANT_SYMBOL: self._symbol, ATTR_POLLUTANT_SYMBOL: self._symbol,
ATTR_POLLUTANT_UNIT: self._unit ATTR_POLLUTANT_UNIT: self._unit
@ -279,7 +246,7 @@ class AirVisualData(object):
"""Define an object to hold sensor data.""" """Define an object to hold sensor data."""
def __init__(self, client, **kwargs): def __init__(self, client, **kwargs):
"""Initialize.""" """Initialize the AirVisual data element."""
self._client = client self._client = client
self.pollution_info = None self.pollution_info = None
@ -291,6 +258,8 @@ class AirVisualData(object):
self.longitude = kwargs.get(CONF_LONGITUDE) self.longitude = kwargs.get(CONF_LONGITUDE)
self._radius = kwargs.get(CONF_RADIUS) self._radius = kwargs.get(CONF_RADIUS)
self.show_on_map = kwargs.get(CONF_SHOW_ON_MAP)
@Throttle(MIN_TIME_BETWEEN_UPDATES) @Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self): def update(self):
"""Update with new AirVisual data.""" """Update with new AirVisual data."""
@ -298,21 +267,21 @@ class AirVisualData(object):
try: try:
if self.city and self.state and self.country: if self.city and self.state and self.country:
resp = self._client.city(self.city, self.state, resp = self._client.city(
self.country).get('data') self.city, self.state, self.country).get('data')
self.longitude, self.latitude = resp.get('location').get(
'coordinates')
else: else:
resp = self._client.nearest_city(self.latitude, self.longitude, resp = self._client.nearest_city(
self._radius).get('data') self.latitude, self.longitude, self._radius).get('data')
_LOGGER.debug('New data retrieved: %s', resp) _LOGGER.debug("New data retrieved: %s", resp)
self.city = resp.get('city') self.city = resp.get('city')
self.state = resp.get('state') self.state = resp.get('state')
self.country = resp.get('country') self.country = resp.get('country')
self.longitude, self.latitude = resp.get('location').get(
'coordinates')
self.pollution_info = resp.get('current', {}).get('pollution', {}) self.pollution_info = resp.get('current', {}).get('pollution', {})
except exceptions.HTTPError as exc_info: except exceptions.HTTPError as exc_info:
_LOGGER.error('Unable to retrieve data on this location: %s', _LOGGER.error("Unable to retrieve data on this location: %s",
self.__dict__) self.__dict__)
_LOGGER.debug(exc_info) _LOGGER.debug(exc_info)
self.pollution_info = {} self.pollution_info = {}

View file

@ -9,6 +9,7 @@ import asyncio
from homeassistant.components.android_ip_webcam import ( from homeassistant.components.android_ip_webcam import (
KEY_MAP, ICON_MAP, DATA_IP_WEBCAM, AndroidIPCamEntity, CONF_HOST, KEY_MAP, ICON_MAP, DATA_IP_WEBCAM, AndroidIPCamEntity, CONF_HOST,
CONF_NAME, CONF_SENSORS) CONF_NAME, CONF_SENSORS)
from homeassistant.helpers.icon import icon_for_battery_level
DEPENDENCIES = ['android_ip_webcam'] DEPENDENCIES = ['android_ip_webcam']
@ -75,14 +76,5 @@ class IPWebcamSensor(AndroidIPCamEntity):
def icon(self): def icon(self):
"""Return the icon for the sensor.""" """Return the icon for the sensor."""
if self._sensor == 'battery_level' and self._state is not None: if self._sensor == 'battery_level' and self._state is not None:
rounded_level = round(int(self._state), -1) return icon_for_battery_level(int(self._state))
returning_icon = 'mdi:battery'
if rounded_level < 10:
returning_icon = 'mdi:battery-outline'
elif self._state == 100:
returning_icon = 'mdi:battery'
else:
returning_icon = 'mdi:battery-{}'.format(str(rounded_level))
return returning_icon
return ICON_MAP.get(self._sensor, 'mdi:eye') return ICON_MAP.get(self._sensor, 'mdi:eye')

View file

@ -7,26 +7,29 @@ https://home-assistant.io/components/sensor.arlo/
import asyncio import asyncio
import logging import logging
from datetime import timedelta from datetime import timedelta
import voluptuous as vol import voluptuous as vol
from homeassistant.helpers import config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.components.arlo import ( from homeassistant.components.arlo import (
CONF_ATTRIBUTION, DEFAULT_BRAND, DATA_ARLO) CONF_ATTRIBUTION, DEFAULT_BRAND, DATA_ARLO)
from homeassistant.const import (
ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS, STATE_UNKNOWN)
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.icon import icon_for_battery_level
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['arlo'] DEPENDENCIES = ['arlo']
_LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=90)
# sensor_type [ description, unit, icon ] # sensor_type [ description, unit, icon ]
SENSOR_TYPES = { SENSOR_TYPES = {
'last_capture': ['Last', None, 'run-fast'], 'last_capture': ['Last', None, 'run-fast'],
'total_cameras': ['Arlo Cameras', None, 'video'], 'total_cameras': ['Arlo Cameras', None, 'video'],
'captured_today': ['Captured Today', None, 'file-video'], 'captured_today': ['Captured Today', None, 'file-video'],
'battery_level': ['Battery Level', '%', 'battery-50']
} }
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
@ -34,8 +37,6 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
}) })
SCAN_INTERVAL = timedelta(seconds=90)
@asyncio.coroutine @asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
@ -47,18 +48,15 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
sensors = [] sensors = []
for sensor_type in config.get(CONF_MONITORED_CONDITIONS): for sensor_type in config.get(CONF_MONITORED_CONDITIONS):
if sensor_type == 'total_cameras': if sensor_type == 'total_cameras':
sensors.append(ArloSensor(hass, sensors.append(ArloSensor(
SENSOR_TYPES[sensor_type][0], hass, SENSOR_TYPES[sensor_type][0], arlo, sensor_type))
arlo,
sensor_type))
else: else:
for camera in arlo.cameras: for camera in arlo.cameras:
name = '{0} {1}'.format(SENSOR_TYPES[sensor_type][0], name = '{0} {1}'.format(
camera.name) SENSOR_TYPES[sensor_type][0], camera.name)
sensors.append(ArloSensor(hass, name, camera, sensor_type)) sensors.append(ArloSensor(hass, name, camera, sensor_type))
async_add_devices(sensors, True) async_add_devices(sensors, True)
return True
class ArloSensor(Entity): class ArloSensor(Entity):
@ -87,6 +85,9 @@ class ArloSensor(Entity):
@property @property
def icon(self): def icon(self):
"""Icon to use in the frontend, if any.""" """Icon to use in the frontend, if any."""
if self._sensor_type == 'battery_level' and self._state is not None:
return icon_for_battery_level(battery_level=int(self._state),
charging=False)
return self._icon return self._icon
@property @property
@ -109,18 +110,25 @@ class ArloSensor(Entity):
video = self._data.videos()[0] video = self._data.videos()[0]
self._state = video.created_at_pretty("%m-%d-%Y %H:%M:%S") self._state = video.created_at_pretty("%m-%d-%Y %H:%M:%S")
except (AttributeError, IndexError): except (AttributeError, IndexError):
self._state = STATE_UNKNOWN self._state = None
elif self._sensor_type == 'battery_level':
try:
self._state = self._data.get_battery_level
except TypeError:
self._state = None
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes.""" """Return the device state attributes."""
attrs = {} attrs = {}
attrs[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION attrs[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION
attrs['brand'] = DEFAULT_BRAND attrs['brand'] = DEFAULT_BRAND
if self._sensor_type == 'last_capture' or \ if self._sensor_type == 'last_capture' or \
self._sensor_type == 'captured_today': self._sensor_type == 'captured_today' or \
self._sensor_type == 'battery_level':
attrs['model'] = self._data.model_id attrs['model'] = self._data.model_id
return attrs return attrs

View file

@ -42,7 +42,7 @@ def discover_sensors(topic, payload):
name = parts[2] + " Moisture" name = parts[2] + " Moisture"
return ArwnSensor(name, 'moisture', unit, "mdi:water-percent") return ArwnSensor(name, 'moisture', unit, "mdi:water-percent")
if domain == "rain": if domain == "rain":
if len(parts) >= 2 and parts[2] == "today": if len(parts) >= 3 and parts[2] == "today":
return ArwnSensor("Rain Since Midnight", 'since_midnight', return ArwnSensor("Rain Since Midnight", 'since_midnight',
"in", "mdi:water") "in", "mdi:water")
if domain == 'barometer': if domain == 'barometer':

View file

@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.string,
vol.Optional(CONF_HOST, default=None): cv.string, vol.Optional(CONF_HOST, default=None): cv.string,
vol.Optional(CONF_DSMR_VERSION, default=DEFAULT_DSMR_VERSION): vol.All( vol.Optional(CONF_DSMR_VERSION, default=DEFAULT_DSMR_VERSION): vol.All(
cv.string, vol.In(['4', '2.2'])), cv.string, vol.In(['5', '4', '2.2'])),
vol.Optional(CONF_RECONNECT_INTERVAL, default=30): int, vol.Optional(CONF_RECONNECT_INTERVAL, default=30): int,
}) })
@ -73,7 +73,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
devices = [DSMREntity(name, obis) for name, obis in obis_mapping] devices = [DSMREntity(name, obis) for name, obis in obis_mapping]
# Protocol version specific obis # Protocol version specific obis
if dsmr_version == '4': if dsmr_version in ('4', '5'):
gas_obis = obis_ref.HOURLY_GAS_METER_READING gas_obis = obis_ref.HOURLY_GAS_METER_READING
else: else:
gas_obis = obis_ref.GAS_METER_READING gas_obis = obis_ref.GAS_METER_READING

View file

@ -82,6 +82,11 @@ class FedexSensor(Entity):
"""Return the state of the sensor.""" """Return the state of the sensor."""
return self._state return self._state
@property
def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return 'packages'
def _update(self): def _update(self):
"""Update device state.""" """Update device state."""
import fedexdeliverymanager import fedexdeliverymanager

View file

@ -17,7 +17,7 @@ from homeassistant.components.http import HomeAssistantView
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import ATTR_ATTRIBUTION from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util.icon import icon_for_battery_level from homeassistant.helpers.icon import icon_for_battery_level
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['fitbit==0.3.0'] REQUIREMENTS = ['fitbit==0.3.0']

View file

@ -20,7 +20,7 @@ import homeassistant.helpers.config_validation as cv
import homeassistant.helpers.location as location import homeassistant.helpers.location as location
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
REQUIREMENTS = ['googlemaps==2.4.6'] REQUIREMENTS = ['googlemaps==2.5.1']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -22,6 +22,8 @@ import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['influxdb==4.1.1']
DEFAULT_HOST = 'localhost' DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 8086 DEFAULT_PORT = 8086
DEFAULT_DATABASE = 'home_assistant' DEFAULT_DATABASE = 'home_assistant'
@ -37,7 +39,6 @@ CONF_FIELD = 'field'
CONF_MEASUREMENT_NAME = 'measurement' CONF_MEASUREMENT_NAME = 'measurement'
CONF_WHERE = 'where' CONF_WHERE = 'where'
REQUIREMENTS = ['influxdb==3.0.0']
_QUERY_SCHEME = vol.Schema({ _QUERY_SCHEME = vol.Schema({
vol.Required(CONF_NAME): cv.string, vol.Required(CONF_NAME): cv.string,

View file

@ -6,7 +6,7 @@ https://home-assistant.io/ecosystem/ios/
""" """
from homeassistant.components import ios from homeassistant.components import ios
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util.icon import icon_for_battery_level from homeassistant.helpers.icon import icon_for_battery_level
DEPENDENCIES = ['ios'] DEPENDENCIES = ['ios']

View file

@ -44,6 +44,18 @@ SENSOR_TYPES = {
'ipv4_in': ['IPv4 In', 'kb/s', 'system.ipv4', 'received', 0], 'ipv4_in': ['IPv4 In', 'kb/s', 'system.ipv4', 'received', 0],
'ipv4_out': ['IPv4 Out', 'kb/s', 'system.ipv4', 'sent', 0], 'ipv4_out': ['IPv4 Out', 'kb/s', 'system.ipv4', 'sent', 0],
'disk_free': ['Disk Free', 'GiB', 'disk_space._', 'avail', 2], 'disk_free': ['Disk Free', 'GiB', 'disk_space._', 'avail', 2],
'cpu_iowait': ['CPU IOWait', '%', 'system.cpu', 'iowait', 1],
'cpu_user': ['CPU User', '%', 'system.cpu', 'user', 1],
'cpu_system': ['CPU System', '%', 'system.cpu', 'system', 1],
'cpu_softirq': ['CPU SoftIRQ', '%', 'system.cpu', 'softirq', 1],
'cpu_guest': ['CPU Guest', '%', 'system.cpu', 'guest', 1],
'uptime': ['Uptime', 's', 'system.uptime', 'uptime', 0],
'packets_received': ['Packets Received', 'packets/s', 'ipv4.packets',
'received', 0],
'packets_sent': ['Packets Sent', 'packets/s', 'ipv4.packets',
'sent', 0],
'connections': ['Active Connections', 'Count',
'netfilter.conntrack_sockets', 'connections', 0]
} }
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({

View file

@ -61,8 +61,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
'[.-]*')): '[.-]*')):
sensor_id = os.path.split(device_folder)[1] sensor_id = os.path.split(device_folder)[1]
device_file = os.path.join(device_folder, 'w1_slave') device_file = os.path.join(device_folder, 'w1_slave')
devs.append(OneWire(device_names.get(sensor_id, sensor_id), devs.append(OneWireDirect(device_names.get(sensor_id,
device_file, 'temperature')) sensor_id),
device_file, 'temperature'))
else: else:
for family_file_path in glob(os.path.join(base_dir, '*', 'family')): for family_file_path in glob(os.path.join(base_dir, '*', 'family')):
family_file = open(family_file_path, "r") family_file = open(family_file_path, "r")
@ -73,8 +74,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
os.path.split(family_file_path)[0])[1] os.path.split(family_file_path)[0])[1]
device_file = os.path.join( device_file = os.path.join(
os.path.split(family_file_path)[0], sensor_value) os.path.split(family_file_path)[0], sensor_value)
devs.append(OneWire(device_names.get(sensor_id, sensor_id), devs.append(OneWireOWFS(device_names.get(sensor_id,
device_file, sensor_key)) sensor_id),
device_file, sensor_key))
if devs == []: if devs == []:
_LOGGER.error("No onewire sensor found. Check if dtoverlay=w1-gpio " _LOGGER.error("No onewire sensor found. Check if dtoverlay=w1-gpio "
@ -97,9 +99,8 @@ class OneWire(Entity):
def _read_value_raw(self): def _read_value_raw(self):
"""Read the value as it is returned by the sensor.""" """Read the value as it is returned by the sensor."""
ds_device_file = open(self._device_file, 'r') with open(self._device_file, 'r') as ds_device_file:
lines = ds_device_file.readlines() lines = ds_device_file.readlines()
ds_device_file.close()
return lines return lines
@property @property
@ -117,30 +118,37 @@ class OneWire(Entity):
"""Return the unit the value is expressed in.""" """Return the unit the value is expressed in."""
return self._unit_of_measurement return self._unit_of_measurement
class OneWireDirect(OneWire):
"""Implementation of an One wire Sensor directly connected to RPI GPIO."""
def update(self): def update(self):
"""Get the latest data from the device.""" """Get the latest data from the device."""
value = None value = None
if self._device_file.startswith(DEFAULT_MOUNT_DIR): lines = self._read_value_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = self._read_value_raw() lines = self._read_value_raw()
while lines[0].strip()[-3:] != 'YES': equals_pos = lines[1].find('t=')
time.sleep(0.2) if equals_pos != -1:
lines = self._read_value_raw() value_string = lines[1][equals_pos + 2:]
equals_pos = lines[1].find('t=') value = round(float(value_string) / 1000.0, 1)
if equals_pos != -1: self._state = value
value_string = lines[1][equals_pos+2:]
value = round(float(value_string) / 1000.0, 1)
else: class OneWireOWFS(OneWire):
try: """Implementation of an One wire Sensor through owfs."""
ds_device_file = open(self._device_file, 'r')
value_read = ds_device_file.readlines() def update(self):
ds_device_file.close() """Get the latest data from the device."""
if len(value_read) == 1: value = None
value = round(float(value_read[0]), 1) try:
except ValueError: value_read = self._read_value_raw()
_LOGGER.warning("Invalid value read from %s", if len(value_read) == 1:
self._device_file) value = round(float(value_read[0]), 1)
except FileNotFoundError: except ValueError:
_LOGGER.warning( _LOGGER.warning("Invalid value read from %s", self._device_file)
"Cannot read from sensor: %s", self._device_file) except FileNotFoundError:
_LOGGER.warning("Cannot read from sensor: %s", self._device_file)
self._state = value self._state = value

Some files were not shown because too many files have changed in this diff Show more