From 54777a81bca5a099d1d56e25e30118dace054db7 Mon Sep 17 00:00:00 2001 From: emontnemery Date: Sun, 31 Mar 2019 05:07:01 +0200 Subject: [PATCH 001/167] Forward media control to playing group (#22566) * Forward media control to playing group * Fix forwarding control to dynamic group * Fix, add tests --- homeassistant/components/cast/media_player.py | 53 +++++++-- tests/components/cast/test_media_player.py | 106 ++++++++++++++++++ 2 files changed, 150 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index 12f524f2121..cb60cdc2967 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -508,11 +508,12 @@ class CastDevice(MediaPlayerDevice): self.mz_cast_status = {} self.mz_media_status = {} self.mz_media_status_received = {} + self.mz_mgr = None self._available = False # type: bool self._dynamic_group_available = False # type: bool self._status_listener = None # type: Optional[CastStatusListener] self._dynamic_group_status_listener = None \ - # type: Optional[CastStatusListener] + # type: Optional[DynamicGroupCastStatusListener] self._add_remove_handler = None self._del_remove_handler = None @@ -638,10 +639,10 @@ class CastDevice(MediaPlayerDevice): if CAST_MULTIZONE_MANAGER_KEY not in self.hass.data: from pychromecast.controllers.multizone import MultizoneManager self.hass.data[CAST_MULTIZONE_MANAGER_KEY] = MultizoneManager() - mz_mgr = self.hass.data[CAST_MULTIZONE_MANAGER_KEY] + self.mz_mgr = self.hass.data[CAST_MULTIZONE_MANAGER_KEY] self._status_listener = CastStatusListener( - self, chromecast, mz_mgr) + self, chromecast, self.mz_mgr) self._available = False self.cast_status = chromecast.status self.media_status = chromecast.media_controller.status @@ -736,6 +737,7 @@ class CastDevice(MediaPlayerDevice): self.mz_cast_status = {} self.mz_media_status = {} self.mz_media_status_received = {} + self.mz_mgr = None if self._status_listener is not None: self._status_listener.invalidate() self._status_listener = None @@ -857,6 +859,32 @@ class CastDevice(MediaPlayerDevice): self.schedule_update_ha_state() # ========== Service Calls ========== + def _media_controller(self): + """ + Return media status. + + First try from our own cast, then dynamic groups and finally + groups which our cast is a member in. + """ + media_status = self.media_status + media_controller = self._chromecast.media_controller + + if ((media_status is None or media_status.player_state == "UNKNOWN") + and self._dynamic_group_cast is not None): + media_status = self.dynamic_group_media_status + media_controller = \ + self._dynamic_group_cast.media_controller + + if media_status is None or media_status.player_state == "UNKNOWN": + groups = self.mz_media_status + for k, val in groups.items(): + if val and val.player_state != "UNKNOWN": + media_controller = \ + self.mz_mgr.get_multizone_mediacontroller(k) + break + + return media_controller + def turn_on(self): """Turn on the cast device.""" import pychromecast @@ -887,30 +915,37 @@ class CastDevice(MediaPlayerDevice): def media_play(self): """Send play command.""" - self._chromecast.media_controller.play() + media_controller = self._media_controller() + media_controller.play() def media_pause(self): """Send pause command.""" - self._chromecast.media_controller.pause() + media_controller = self._media_controller() + media_controller.pause() def media_stop(self): """Send stop command.""" - self._chromecast.media_controller.stop() + media_controller = self._media_controller() + media_controller.stop() def media_previous_track(self): """Send previous track command.""" - self._chromecast.media_controller.rewind() + media_controller = self._media_controller() + media_controller.rewind() def media_next_track(self): """Send next track command.""" - self._chromecast.media_controller.skip() + media_controller = self._media_controller() + media_controller.skip() def media_seek(self, position): """Seek the media to a specific location.""" - self._chromecast.media_controller.seek(position) + media_controller = self._media_controller() + media_controller.seek(position) def play_media(self, media_type, media_id, **kwargs): """Play media from a URL.""" + # We do not want this to be forwarded to a group / dynamic group self._chromecast.media_controller.play_media(media_id, media_type) # ========== Properties ========== diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index 85012a4a710..7c40b09d03e 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -397,6 +397,112 @@ async def test_dynamic_group_media_states(hass: HomeAssistantType): assert state.state == 'playing' +async def test_group_media_control(hass: HomeAssistantType): + """Test media states are read from group if entity has no state.""" + info = get_fake_chromecast_info() + full_info = attr.evolve(info, model_name='google home', + friendly_name='Speaker', uuid=FakeUUID) + + with patch('pychromecast.dial.get_device_status', + return_value=full_info): + chromecast, entity = await async_setup_media_player_cast(hass, info) + + entity._available = True + entity.schedule_update_ha_state() + await hass.async_block_till_done() + + state = hass.states.get('media_player.speaker') + assert state is not None + assert state.name == 'Speaker' + assert state.state == 'unknown' + assert entity.unique_id == full_info.uuid + + group_media_status = MagicMock(images=None) + player_media_status = MagicMock(images=None) + + # Player has no state, group is playing -> Should forward calls to group + group_media_status.player_is_playing = True + entity.multizone_new_media_status(str(FakeGroupUUID), group_media_status) + entity.media_play() + grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + assert grp_media.play.called + assert not chromecast.media_controller.play.called + + # Player is paused, group is playing -> Should not forward + player_media_status.player_is_playing = False + player_media_status.player_is_paused = True + entity.new_media_status(player_media_status) + entity.media_pause() + grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + assert not grp_media.pause.called + assert chromecast.media_controller.pause.called + + # Player is in unknown state, group is playing -> Should forward to group + player_media_status.player_state = "UNKNOWN" + entity.new_media_status(player_media_status) + entity.media_stop() + grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + assert grp_media.stop.called + assert not chromecast.media_controller.stop.called + + # Verify play_media is not forwarded + entity.play_media(None, None) + assert not grp_media.play_media.called + assert chromecast.media_controller.play_media.called + + +async def test_dynamic_group_media_control(hass: HomeAssistantType): + """Test media states are read from group if entity has no state.""" + info = get_fake_chromecast_info() + full_info = attr.evolve(info, model_name='google home', + friendly_name='Speaker', uuid=FakeUUID) + + with patch('pychromecast.dial.get_device_status', + return_value=full_info): + chromecast, entity = await async_setup_media_player_cast(hass, info) + + entity._available = True + entity.schedule_update_ha_state() + entity._dynamic_group_cast = MagicMock() + await hass.async_block_till_done() + + state = hass.states.get('media_player.speaker') + assert state is not None + assert state.name == 'Speaker' + assert state.state == 'unknown' + assert entity.unique_id == full_info.uuid + + group_media_status = MagicMock(images=None) + player_media_status = MagicMock(images=None) + + # Player has no state, dynamic group is playing -> Should forward + group_media_status.player_is_playing = True + entity.new_dynamic_group_media_status(group_media_status) + entity.media_previous_track() + assert entity._dynamic_group_cast.media_controller.rewind.called + assert not chromecast.media_controller.rewind.called + + # Player is paused, dynamic group is playing -> Should not forward + player_media_status.player_is_playing = False + player_media_status.player_is_paused = True + entity.new_media_status(player_media_status) + entity.media_next_track() + assert not entity._dynamic_group_cast.media_controller.skip.called + assert chromecast.media_controller.skip.called + + # Player is in unknown state, dynamic group is playing -> Should forward + player_media_status.player_state = "UNKNOWN" + entity.new_media_status(player_media_status) + entity.media_seek(None) + assert entity._dynamic_group_cast.media_controller.seek.called + assert not chromecast.media_controller.seek.called + + # Verify play_media is not forwarded + entity.play_media(None, None) + assert not entity._dynamic_group_cast.media_controller.play_media.called + assert chromecast.media_controller.play_media.called + + async def test_disconnect_on_stop(hass: HomeAssistantType): """Test cast device disconnects socket on stop.""" info = get_fake_chromecast_info() From f6e9dd48323769a0cff8986ae51016408c0aa6f1 Mon Sep 17 00:00:00 2001 From: Chris Helming Date: Sun, 31 Mar 2019 00:01:58 -0400 Subject: [PATCH 002/167] Update Foscam component to support stream source (#22568) * Update Foscam to support stream source * Removing spaces and tabs * Changing to Python3-style string formatting * Adding '_media_port' to hopefully cover other models --- homeassistant/components/foscam/camera.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/foscam/camera.py b/homeassistant/components/foscam/camera.py index ceec57f7755..a11d2f48f62 100644 --- a/homeassistant/components/foscam/camera.py +++ b/homeassistant/components/foscam/camera.py @@ -8,7 +8,8 @@ import logging import voluptuous as vol -from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA) +from homeassistant.components.camera import ( + Camera, PLATFORM_SCHEMA, SUPPORT_STREAM) from homeassistant.const import ( CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_PORT) from homeassistant.helpers import config_validation as cv @@ -57,6 +58,8 @@ class FoscamCam(Camera): self._foscam_session = FoscamCamera( ip_address, port, self._username, self._password, verbose=False) + self._media_port = self._foscam_session.get_port_info()[1]['mediaPort'] + def camera_image(self): """Return a still image response from the camera.""" # Send the request to snap a picture and return raw jpg data @@ -67,6 +70,20 @@ class FoscamCam(Camera): return response + @property + def supported_features(self): + """Return supported features.""" + return SUPPORT_STREAM + + @property + def stream_source(self): + """Return the stream source.""" + return 'rtsp://{}:{}@{}:{}/videoMain'.format( + self._username, + self._password, + self._foscam_session.host, + self._media_port) + @property def motion_detection_enabled(self): """Camera Motion Detection Status.""" From 4d1633807c700ca528e79f7a1a676e0d1dc76e1e Mon Sep 17 00:00:00 2001 From: emontnemery Date: Sun, 31 Mar 2019 06:04:32 +0200 Subject: [PATCH 003/167] Turn light off if brightness is 0 (#22400) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Turn light off if brightness is 0 * Lint * Review comments * Lint * Fixup, add tests * Fix trådfri light + test --- homeassistant/components/light/__init__.py | 20 ++++++++- homeassistant/components/tradfri/light.py | 2 - tests/components/light/test_init.py | 50 ++++++++++++++++++++++ tests/components/light/test_tradfri.py | 14 ++---- 4 files changed, 72 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index acf95a3c081..7fe7ae343f9 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -175,6 +175,17 @@ def preprocess_turn_on_alternatives(params): params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color) +def preprocess_turn_off(params): + """Process data for turning light off if brightness is 0.""" + if ATTR_BRIGHTNESS in params and params[ATTR_BRIGHTNESS] == 0: + # Zero brightness: Light will be turned off + params = {k: v for k, v in params.items() if k in [ATTR_TRANSITION, + ATTR_FLASH]} + return (True, params) # Light should be turned off + + return (False, None) # Light should be turned on + + class SetIntentHandler(intent.IntentHandler): """Handle set color intents.""" @@ -272,17 +283,24 @@ async def async_setup(hass, config): ) preprocess_turn_on_alternatives(params) + turn_lights_off, off_params = preprocess_turn_off(params) update_tasks = [] for light in target_lights: light.async_set_context(service.context) pars = params + off_pars = off_params + turn_light_off = turn_lights_off if not pars: pars = params.copy() pars[ATTR_PROFILE] = Profiles.get_default(light.entity_id) preprocess_turn_on_alternatives(pars) - await light.async_turn_on(**pars) + turn_light_off, off_pars = preprocess_turn_off(pars) + if turn_light_off: + await light.async_turn_off(**off_pars) + else: + await light.async_turn_on(**pars) if not light.should_poll: continue diff --git a/homeassistant/components/tradfri/light.py b/homeassistant/components/tradfri/light.py index 38ce428b51b..07ab4806dfc 100644 --- a/homeassistant/components/tradfri/light.py +++ b/homeassistant/components/tradfri/light.py @@ -263,8 +263,6 @@ class TradfriLight(Light): brightness = kwargs[ATTR_BRIGHTNESS] if brightness > 254: brightness = 254 - elif brightness < 0: - brightness = 0 dimmer_data = {ATTR_DIMMER: brightness, ATTR_TRANSITION_TIME: transition_time} dimmer_command = self._light_control.set_dimmer(**dimmer_data) diff --git a/tests/components/light/test_init.py b/tests/components/light/test_init.py index 28d688b2080..0025e9bce66 100644 --- a/tests/components/light/test_init.py +++ b/tests/components/light/test_init.py @@ -161,6 +161,19 @@ class TestLight(unittest.TestCase): assert not light.is_on(self.hass, dev2.entity_id) assert not light.is_on(self.hass, dev3.entity_id) + # turn off all lights by setting brightness to 0 + common.turn_on(self.hass) + + self.hass.block_till_done() + + common.turn_on(self.hass, brightness=0) + + self.hass.block_till_done() + + assert not light.is_on(self.hass, dev1.entity_id) + assert not light.is_on(self.hass, dev2.entity_id) + assert not light.is_on(self.hass, dev3.entity_id) + # toggle all lights common.toggle(self.hass) @@ -207,6 +220,32 @@ class TestLight(unittest.TestCase): light.ATTR_HS_COLOR: (71.059, 100), } == data + # Ensure attributes are filtered when light is turned off + common.turn_on(self.hass, dev1.entity_id, + transition=10, brightness=0, color_name='blue') + common.turn_on( + self.hass, dev2.entity_id, brightness=0, rgb_color=(255, 255, 255), + white_value=0) + common.turn_on(self.hass, dev3.entity_id, brightness=0, + xy_color=(.4, .6)) + + self.hass.block_till_done() + + assert not light.is_on(self.hass, dev1.entity_id) + assert not light.is_on(self.hass, dev2.entity_id) + assert not light.is_on(self.hass, dev3.entity_id) + + _, data = dev1.last_call('turn_off') + assert { + light.ATTR_TRANSITION: 10, + } == data + + _, data = dev2.last_call('turn_off') + assert {} == data + + _, data = dev3.last_call('turn_off') + assert {} == data + # One of the light profiles prof_name, prof_h, prof_s, prof_bri = 'relax', 35.932, 69.412, 144 @@ -292,6 +331,7 @@ class TestLight(unittest.TestCase): with open(user_light_file, 'w') as user_file: user_file.write('id,x,y,brightness\n') user_file.write('test,.4,.6,100\n') + user_file.write('test_off,0,0,0\n') assert setup_component( self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}} @@ -305,11 +345,21 @@ class TestLight(unittest.TestCase): _, data = dev1.last_call('turn_on') + assert light.is_on(self.hass, dev1.entity_id) assert { light.ATTR_HS_COLOR: (71.059, 100), light.ATTR_BRIGHTNESS: 100 } == data + common.turn_on(self.hass, dev1.entity_id, profile='test_off') + + self.hass.block_till_done() + + _, data = dev1.last_call('turn_off') + + assert not light.is_on(self.hass, dev1.entity_id) + assert {} == data + def test_default_profiles_group(self): """Test default turn-on light profile for all lights.""" platform = loader.get_component(self.hass, 'light.test') diff --git a/tests/components/light/test_tradfri.py b/tests/components/light/test_tradfri.py index 337031cf92c..37d3ec322ff 100644 --- a/tests/components/light/test_tradfri.py +++ b/tests/components/light/test_tradfri.py @@ -35,20 +35,12 @@ TURN_ON_TEST_CASES = [ 'brightness': 100 } ], - # Brightness == 0 + # Brightness == 1 [ {'can_set_dimmer': True}, - {'brightness': 0}, + {'brightness': 1}, { - 'brightness': 0 - } - ], - # Brightness < 0 - [ - {'can_set_dimmer': True}, - {'brightness': -1}, - { - 'brightness': 0 + 'brightness': 1 } ], # Brightness > 254 From 388d614e30a97d6d2302134d8f600ffe3d01df07 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sat, 30 Mar 2019 21:10:32 -0700 Subject: [PATCH 004/167] Ignore flaky test (#22563) --- tests/components/statistics/test_sensor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/components/statistics/test_sensor.py b/tests/components/statistics/test_sensor.py index 580b11f5ccd..c558c476ca1 100644 --- a/tests/components/statistics/test_sensor.py +++ b/tests/components/statistics/test_sensor.py @@ -230,7 +230,7 @@ class TestStatisticsSensor(unittest.TestCase): state.attributes.get('max_age') assert self.change_rate == state.attributes.get('change_rate') - @pytest.mark.skip + @pytest.mark.skip("Flaky in CI") def test_initialize_from_database(self): """Test initializing the statistics from the database.""" # enable the recorder @@ -260,6 +260,7 @@ class TestStatisticsSensor(unittest.TestCase): state = self.hass.states.get('sensor.test_mean') assert str(self.mean) == state.state + @pytest.mark.skip("Flaky in CI") def test_initialize_from_database_with_maxage(self): """Test initializing the statistics from the database.""" mock_data = { From 800b1c7fe65fc4938273a16b923fb2ff4ec3f5da Mon Sep 17 00:00:00 2001 From: OleksandrBerchenko Date: Sun, 31 Mar 2019 14:43:54 +0300 Subject: [PATCH 005/167] Fix typo in light/__init__.py (#22581) --- homeassistant/components/light/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 7fe7ae343f9..e3971cd8e42 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -465,7 +465,7 @@ class Light(ToggleEntity): if supported_features & SUPPORT_COLOR_TEMP: data[ATTR_COLOR_TEMP] = self.color_temp - if self.supported_features & SUPPORT_COLOR and self.hs_color: + if supported_features & SUPPORT_COLOR and self.hs_color: # pylint: disable=unsubscriptable-object,not-an-iterable hs_color = self.hs_color data[ATTR_HS_COLOR] = ( From 1b0b5b4b8c830165d57cbf9c938ed20138265939 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Sun, 31 Mar 2019 16:19:39 +0200 Subject: [PATCH 006/167] Fix lightwave config validation (#22576) --- homeassistant/components/lightwave/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/lightwave/__init__.py b/homeassistant/components/lightwave/__init__.py index a9e5dcf9823..f6e11352265 100644 --- a/homeassistant/components/lightwave/__init__.py +++ b/homeassistant/components/lightwave/__init__.py @@ -14,7 +14,7 @@ DOMAIN = 'lightwave' CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema( - cv.has_at_least_one_key(CONF_LIGHTS, CONF_SWITCHES), { + vol.All(cv.has_at_least_one_key(CONF_LIGHTS, CONF_SWITCHES), { vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_LIGHTS, default={}): { cv.string: vol.Schema({vol.Required(CONF_NAME): cv.string}), @@ -23,6 +23,7 @@ CONFIG_SCHEMA = vol.Schema({ cv.string: vol.Schema({vol.Required(CONF_NAME): cv.string}), } }) + ) }, extra=vol.ALLOW_EXTRA) From 842a36dc9ee5f4a1d27fdc8bb62cdeb8a2d8a9ae Mon Sep 17 00:00:00 2001 From: OleksandrBerchenko Date: Sun, 31 Mar 2019 22:02:45 +0300 Subject: [PATCH 007/167] Rewrite Osram Lightify component (#22184) * Rewrite Osram Lightify component * Update python-lightify version to 1.0.7.2 * Remove unneeded code * 1. Remove changes in light/__init__.py, 2. Set properties to None by default * Fix typo --- .../components/osramlightify/light.py | 414 +++++++++++------- requirements_all.txt | 2 +- 2 files changed, 246 insertions(+), 170 deletions(-) diff --git a/homeassistant/components/osramlightify/light.py b/homeassistant/components/osramlightify/light.py index a49e12c76a6..59cc2bac5d6 100644 --- a/homeassistant/components/osramlightify/light.py +++ b/homeassistant/components/osramlightify/light.py @@ -4,41 +4,35 @@ Support for Osram Lightify. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.osramlightify/ """ -from datetime import timedelta import logging import random import socket import voluptuous as vol -from homeassistant import util from homeassistant.components.light import ( - ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_HS_COLOR, - ATTR_TRANSITION, EFFECT_RANDOM, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, + ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_TRANSITION, + ATTR_EFFECT, EFFECT_RANDOM, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, SUPPORT_EFFECT, SUPPORT_TRANSITION, Light) + from homeassistant.const import CONF_HOST import homeassistant.helpers.config_validation as cv -from homeassistant.util.color import ( - color_temperature_kelvin_to_mired, color_temperature_mired_to_kelvin) import homeassistant.util.color as color_util -REQUIREMENTS = ['lightify==1.0.6.1'] +REQUIREMENTS = ['lightify==1.0.7.2'] _LOGGER = logging.getLogger(__name__) CONF_ALLOW_LIGHTIFY_NODES = 'allow_lightify_nodes' CONF_ALLOW_LIGHTIFY_GROUPS = 'allow_lightify_groups' +CONF_INTERVAL_LIGHTIFY_STATUS = 'interval_lightify_status' +CONF_INTERVAL_LIGHTIFY_CONF = 'interval_lightify_conf' DEFAULT_ALLOW_LIGHTIFY_NODES = True DEFAULT_ALLOW_LIGHTIFY_GROUPS = True - -MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - -SUPPORT_OSRAMLIGHTIFY = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | - SUPPORT_EFFECT | SUPPORT_COLOR | - SUPPORT_TRANSITION) +DEFAULT_INTERVAL_LIGHTIFY_STATUS = 5 +DEFAULT_INTERVAL_LIGHTIFY_CONF = 3600 PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, @@ -46,228 +40,310 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ default=DEFAULT_ALLOW_LIGHTIFY_NODES): cv.boolean, vol.Optional(CONF_ALLOW_LIGHTIFY_GROUPS, default=DEFAULT_ALLOW_LIGHTIFY_GROUPS): cv.boolean, + vol.Optional(CONF_INTERVAL_LIGHTIFY_STATUS, + default=DEFAULT_INTERVAL_LIGHTIFY_STATUS): cv.positive_int, + vol.Optional(CONF_INTERVAL_LIGHTIFY_CONF, + default=DEFAULT_INTERVAL_LIGHTIFY_CONF): cv.positive_int }) +DEFAULT_BRIGHTNESS = 2 +DEFAULT_KELVIN = 2700 -def setup_platform(hass, config, add_entities, discovery_info=None): + +def setup_platform(_hass, config, add_entities, _discovery_info=None): """Set up the Osram Lightify lights.""" import lightify - host = config.get(CONF_HOST) - add_nodes = config.get(CONF_ALLOW_LIGHTIFY_NODES) - add_groups = config.get(CONF_ALLOW_LIGHTIFY_GROUPS) - + host = config[CONF_HOST] try: - bridge = lightify.Lightify(host) + bridge = lightify.Lightify(host, log_level=logging.NOTSET) except socket.error as err: msg = "Error connecting to bridge: {} due to: {}".format( host, str(err)) _LOGGER.exception(msg) return - setup_bridge(bridge, add_entities, add_nodes, add_groups) + setup_bridge(bridge, add_entities, config) -def setup_bridge(bridge, add_entities, add_nodes, add_groups): +def setup_bridge(bridge, add_entities, config): """Set up the Lightify bridge.""" lights = {} + groups = {} + groups_last_updated = [0] - @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update_lights(): - """Update the lights objects with latest info from bridge.""" + """Update the lights objects with the latest info from the bridge.""" try: - bridge.update_all_light_status() - bridge.update_group_list() + new_lights = bridge.update_all_light_status( + config[CONF_INTERVAL_LIGHTIFY_STATUS]) + lights_changed = bridge.lights_changed() except TimeoutError: _LOGGER.error("Timeout during updating of lights") + return 0 except OSError: _LOGGER.error("OSError during updating of lights") + return 0 - new_lights = [] - - if add_nodes: - for (light_id, light) in bridge.lights().items(): - if light_id not in lights: - osram_light = OsramLightifyLight( - light_id, light, update_lights) - lights[light_id] = osram_light - new_lights.append(osram_light) + if new_lights and config[CONF_ALLOW_LIGHTIFY_NODES]: + new_entities = [] + for addr, light in new_lights.items(): + if addr not in lights: + osram_light = OsramLightifyLight(light, update_lights, + lights_changed) + lights[addr] = osram_light + new_entities.append(osram_light) else: - lights[light_id].light = light + lights[addr].update_luminary(light) - if add_groups: - for (group_name, group) in bridge.groups().items(): - if group_name not in lights: - osram_group = OsramLightifyGroup( - group, bridge, update_lights) - lights[group_name] = osram_group - new_lights.append(osram_group) + add_entities(new_entities) + + return lights_changed + + def update_groups(): + """Update the groups objects with the latest info from the bridge.""" + lights_changed = update_lights() + + try: + new_groups = bridge.update_group_list( + config[CONF_INTERVAL_LIGHTIFY_CONF]) + groups_updated = bridge.groups_updated() + except TimeoutError: + _LOGGER.error("Timeout during updating of groups") + return 0 + except OSError: + _LOGGER.error("OSError during updating of groups") + return 0 + + if new_groups: + new_groups = {group.idx(): group for group in new_groups.values()} + new_entities = [] + for idx, group in new_groups.items(): + if idx not in groups: + osram_group = OsramLightifyGroup(group, update_groups, + groups_updated) + groups[idx] = osram_group + new_entities.append(osram_group) else: - lights[group_name].group = group + groups[idx].update_luminary(group) - if new_lights: - add_entities(new_lights) + add_entities(new_entities) + + if groups_updated > groups_last_updated[0]: + groups_last_updated[0] = groups_updated + for idx, osram_group in groups.items(): + if idx not in new_groups: + osram_group.update_static_attributes() + + return max(lights_changed, groups_updated) update_lights() + if config[CONF_ALLOW_LIGHTIFY_GROUPS]: + update_groups() class Luminary(Light): """Representation of Luminary Lights and Groups.""" - def __init__(self, luminary, update_lights): - """Initialize a Luminary light.""" - self.update_lights = update_lights + def __init__(self, luminary, update_func, changed): + """Initialize a Luminary Light.""" + self.update_func = update_func self._luminary = luminary + self._changed = changed + + self._unique_id = None + self._supported_features = [] + self._effect_list = [] + self._is_on = False + self._min_mireds = None + self._max_mireds = None self._brightness = None - self._hs = None - self._name = None - self._temperature = None - self._state = False - self.update() + self._color_temp = None + self._rgb_color = None + + self.update_static_attributes() + self.update_dynamic_attributes() + + def _get_unique_id(self): + """Get a unique ID (not implemented).""" + raise NotImplementedError + + def _get_supported_features(self): + """Get list of supported features.""" + features = 0 + if 'lum' in self._luminary.supported_features(): + features = features | SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION + + if 'temp' in self._luminary.supported_features(): + features = features | SUPPORT_COLOR_TEMP | SUPPORT_TRANSITION + + if 'rgb' in self._luminary.supported_features(): + features = (features | SUPPORT_COLOR | SUPPORT_TRANSITION | + SUPPORT_EFFECT) + + return features + + def _get_effect_list(self): + """Get list of supported effects.""" + effects = [] + if 'rgb' in self._luminary.supported_features(): + effects.append(EFFECT_RANDOM) + + return effects @property def name(self): - """Return the name of the device if any.""" - return self._name + """Return the name of the luminary.""" + return self._luminary.name() @property def hs_color(self): - """Last hs color value set.""" - return self._hs + """Return last hs color value set.""" + return color_util.color_RGB_to_hs(*self._rgb_color) @property def color_temp(self): """Return the color temperature.""" - return self._temperature + return self._color_temp @property def brightness(self): - """Brightness of this light between 0..255.""" + """Return brightness of the luminary (0..255).""" return self._brightness @property def is_on(self): - """Update status to True if device is on.""" - return self._state + """Return True if the device is on.""" + return self._is_on @property def supported_features(self): - """Flag supported features.""" - return SUPPORT_OSRAMLIGHTIFY + """List of supported features.""" + return self._supported_features @property def effect_list(self): """List of supported effects.""" - return [EFFECT_RANDOM] - - def turn_on(self, **kwargs): - """Turn the device on.""" - if ATTR_TRANSITION in kwargs: - transition = int(kwargs[ATTR_TRANSITION] * 10) - else: - transition = 0 - - if ATTR_BRIGHTNESS in kwargs: - self._brightness = kwargs[ATTR_BRIGHTNESS] - self._luminary.set_luminance( - int(self._brightness / 2.55), transition) - else: - self._luminary.set_onoff(1) - - if ATTR_HS_COLOR in kwargs: - red, green, blue = \ - color_util.color_hs_to_RGB(*kwargs[ATTR_HS_COLOR]) - self._luminary.set_rgb(red, green, blue, transition) - - if ATTR_COLOR_TEMP in kwargs: - color_t = kwargs[ATTR_COLOR_TEMP] - kelvin = int(color_temperature_mired_to_kelvin(color_t)) - self._luminary.set_temperature(kelvin, transition) - - if ATTR_EFFECT in kwargs: - effect = kwargs.get(ATTR_EFFECT) - if effect == EFFECT_RANDOM: - self._luminary.set_rgb( - random.randrange(0, 255), random.randrange(0, 255), - random.randrange(0, 255), transition) - - self.schedule_update_ha_state() - - def turn_off(self, **kwargs): - """Turn the device off.""" - if ATTR_TRANSITION in kwargs: - transition = int(kwargs[ATTR_TRANSITION] * 10) - self._luminary.set_luminance(0, transition) - else: - transition = 0 - self._luminary.set_onoff(0) - self.schedule_update_ha_state() - - def update(self): - """Synchronize state with bridge.""" - self.update_lights(no_throttle=True) - self._name = self._luminary.name() - - -class OsramLightifyLight(Luminary): - """Representation of an Osram Lightify Light.""" - - def __init__(self, light_id, light, update_lights): - """Initialize the Lightify light.""" - self._light_id = light_id - super().__init__(light, update_lights) - - def update(self): - """Update status of a light.""" - super().update() - self._state = self._luminary.on() - rgb = self._luminary.rgb() - self._hs = color_util.color_RGB_to_hs(*rgb) - o_temp = self._luminary.temp() - if o_temp == 0: - self._temperature = None - else: - self._temperature = color_temperature_kelvin_to_mired( - self._luminary.temp()) - self._brightness = int(self._luminary.lum() * 2.55) + return self._effect_list @property - def unique_id(self): - """Return a unique ID.""" - return self._light_id + def min_mireds(self): + """Return the coldest color_temp that this light supports.""" + return self._min_mireds - -class OsramLightifyGroup(Luminary): - """Representation of an Osram Lightify Group.""" - - def __init__(self, group, bridge, update_lights): - """Initialize the Lightify light group.""" - self._bridge = bridge - self._light_ids = [] - super().__init__(group, update_lights) - self._unique_id = '{}'.format(self._light_ids) - - def _get_state(self): - """Get state of group.""" - lights = self._bridge.lights() - return any(lights[light_id].on() for light_id in self._light_ids) - - def update(self): - """Update group status.""" - super().update() - self._light_ids = self._luminary.lights() - light = self._bridge.lights()[self._light_ids[0]] - self._brightness = int(light.lum() * 2.55) - rgb = light.rgb() - self._hs = color_util.color_RGB_to_hs(*rgb) - o_temp = light.temp() - if o_temp == 0: - self._temperature = None - else: - self._temperature = color_temperature_kelvin_to_mired(o_temp) - self._state = light.on() + @property + def max_mireds(self): + """Return the warmest color_temp that this light supports.""" + return self._max_mireds @property def unique_id(self): """Return a unique ID.""" return self._unique_id + + def play_effect(self, effect, transition): + """Play selected effect.""" + if effect == EFFECT_RANDOM: + self._rgb_color = (random.randrange(0, 256), + random.randrange(0, 256), + random.randrange(0, 256)) + self._luminary.set_rgb(*self._rgb_color, transition) + self._luminary.set_onoff(True) + return True + + return False + + def turn_on(self, **kwargs): + """Turn the device on.""" + transition = int(kwargs.get(ATTR_TRANSITION, 0) * 10) + if ATTR_EFFECT in kwargs: + self.play_effect(kwargs[ATTR_EFFECT], transition) + return + + if ATTR_HS_COLOR in kwargs: + self._rgb_color = color_util.color_hs_to_RGB( + *kwargs[ATTR_HS_COLOR]) + self._luminary.set_rgb(*self._rgb_color, transition) + + if ATTR_COLOR_TEMP in kwargs: + self._color_temp = kwargs[ATTR_COLOR_TEMP] + self._luminary.set_temperature( + int(color_util.color_temperature_mired_to_kelvin( + self._color_temp)), transition) + + self._is_on = True + if ATTR_BRIGHTNESS in kwargs: + self._brightness = kwargs[ATTR_BRIGHTNESS] + self._luminary.set_luminance(int(self._brightness / 2.55), + transition) + else: + self._luminary.set_onoff(True) + + def turn_off(self, **kwargs): + """Turn the device off.""" + self._is_on = False + if ATTR_TRANSITION in kwargs: + transition = int(kwargs[ATTR_TRANSITION] * 10) + self._brightness = DEFAULT_BRIGHTNESS + self._luminary.set_luminance(0, transition) + else: + self._luminary.set_onoff(False) + + def update_luminary(self, luminary): + """Update internal luminary object.""" + self._luminary = luminary + self.update_static_attributes() + + def update_static_attributes(self): + """Update static attributes of the luminary.""" + self._unique_id = self._get_unique_id() + self._supported_features = self._get_supported_features() + self._effect_list = self._get_effect_list() + if self._supported_features & SUPPORT_COLOR_TEMP: + self._min_mireds = color_util.color_temperature_kelvin_to_mired( + self._luminary.max_temp() or DEFAULT_KELVIN) + self._max_mireds = color_util.color_temperature_kelvin_to_mired( + self._luminary.min_temp() or DEFAULT_KELVIN) + + def update_dynamic_attributes(self): + """Update dynamic attributes of the luminary.""" + self._is_on = self._luminary.on() + if self._supported_features & SUPPORT_BRIGHTNESS: + self._brightness = int(self._luminary.lum() * 2.55) + + if self._supported_features & SUPPORT_COLOR_TEMP: + self._color_temp = color_util.color_temperature_kelvin_to_mired( + self._luminary.temp() or DEFAULT_KELVIN) + + if self._supported_features & SUPPORT_COLOR: + self._rgb_color = self._luminary.rgb() + + def update(self): + """Synchronize state with bridge.""" + changed = self.update_func() + if changed > self._changed: + self._changed = changed + self.update_dynamic_attributes() + + +class OsramLightifyLight(Luminary): + """Representation of an Osram Lightify Light.""" + + def _get_unique_id(self): + """Get a unique ID.""" + return self._luminary.addr() + + +class OsramLightifyGroup(Luminary): + """Representation of an Osram Lightify Group.""" + + def _get_unique_id(self): + """Get a unique ID for the group.""" +# Actually, it's a wrong choice for a unique ID, because a combination of +# lights is NOT unique (Osram Lightify allows to create different groups +# with the same lights). Also a combination of lights may easily change, +# but the group remains the same from the user's perspective. +# It should be something like "-" +# For now keeping it as is for backward compatibility with existing +# users. + return '{}'.format(self._luminary.lights()) diff --git a/requirements_all.txt b/requirements_all.txt index ec4c6028356..18f9098a2e4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -643,7 +643,7 @@ libsoundtouch==0.7.2 liffylights==0.9.4 # homeassistant.components.osramlightify.light -lightify==1.0.6.1 +lightify==1.0.7.2 # homeassistant.components.lightwave lightwave==0.15 From 5abfc8438280c85eeeddc93819cf2488aa6d5967 Mon Sep 17 00:00:00 2001 From: Markus Jankowski Date: Sun, 31 Mar 2019 21:18:45 +0200 Subject: [PATCH 008/167] Clean up homematicip cloud (#22589) * Code Cleanup - removed unused constants - more icons on binary_sensor groups - alligned code for device_state_attributes - fixed temperature unit origin for weather * removed icons --- .../homematicip_cloud/alarm_control_panel.py | 3 --- .../components/homematicip_cloud/climate.py | 2 -- .../components/homematicip_cloud/light.py | 16 ++++------------ .../components/homematicip_cloud/sensor.py | 2 -- .../components/homematicip_cloud/switch.py | 4 ---- .../components/homematicip_cloud/weather.py | 3 ++- 6 files changed, 6 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/alarm_control_panel.py b/homeassistant/components/homematicip_cloud/alarm_control_panel.py index eb5855bb980..df0201340ed 100644 --- a/homeassistant/components/homematicip_cloud/alarm_control_panel.py +++ b/homeassistant/components/homematicip_cloud/alarm_control_panel.py @@ -12,9 +12,6 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['homematicip_cloud'] -HMIP_ZONE_AWAY = 'EXTERNAL' -HMIP_ZONE_HOME = 'INTERNAL' - async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): diff --git a/homeassistant/components/homematicip_cloud/climate.py b/homeassistant/components/homematicip_cloud/climate.py index 955f3e5baa7..5055858e9c7 100644 --- a/homeassistant/components/homematicip_cloud/climate.py +++ b/homeassistant/components/homematicip_cloud/climate.py @@ -10,8 +10,6 @@ from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice _LOGGER = logging.getLogger(__name__) -STATE_BOOST = 'Boost' - HA_STATE_TO_HMIP = { STATE_AUTO: 'AUTOMATIC', STATE_MANUAL: 'MANUAL', diff --git a/homeassistant/components/homematicip_cloud/light.py b/homeassistant/components/homematicip_cloud/light.py index f8b19b5bb1e..f5bac66388c 100644 --- a/homeassistant/components/homematicip_cloud/light.py +++ b/homeassistant/components/homematicip_cloud/light.py @@ -13,7 +13,6 @@ _LOGGER = logging.getLogger(__name__) ATTR_ENERGY_COUNTER = 'energy_counter_kwh' ATTR_POWER_CONSUMPTION = 'power_consumption' -ATTR_PROFILE_MODE = 'profile_mode' async def async_setup_platform( @@ -77,13 +76,9 @@ class HomematicipLightMeasuring(HomematicipLight): """Return the state attributes of the generic device.""" attr = super().device_state_attributes if self._device.currentPowerConsumption > 0.05: - attr.update({ - ATTR_POWER_CONSUMPTION: - round(self._device.currentPowerConsumption, 2) - }) - attr.update({ - ATTR_ENERGY_COUNTER: round(self._device.energyCounter, 2) - }) + attr[ATTR_POWER_CONSUMPTION] = \ + round(self._device.currentPowerConsumption, 2) + attr[ATTR_ENERGY_COUNTER] = round(self._device.energyCounter, 2) return attr @@ -168,10 +163,7 @@ class HomematicipNotificationLight(HomematicipGenericDevice, Light): """Return the state attributes of the generic device.""" attr = super().device_state_attributes if self.is_on: - attr.update({ - ATTR_COLOR_NAME: - self._channel.simpleRGBColorState - }) + attr[ATTR_COLOR_NAME] = self._channel.simpleRGBColorState return attr @property diff --git a/homeassistant/components/homematicip_cloud/sensor.py b/homeassistant/components/homematicip_cloud/sensor.py index 39758739400..e053c191c6b 100644 --- a/homeassistant/components/homematicip_cloud/sensor.py +++ b/homeassistant/components/homematicip_cloud/sensor.py @@ -12,8 +12,6 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['homematicip_cloud'] ATTR_TEMPERATURE_OFFSET = 'temperature_offset' -ATTR_VALVE_STATE = 'valve_state' -ATTR_VALVE_POSITION = 'valve_position' ATTR_WIND_DIRECTION = 'wind_direction' ATTR_WIND_DIRECTION_VARIATION = 'wind_direction_variation_in_degree' diff --git a/homeassistant/components/homematicip_cloud/switch.py b/homeassistant/components/homematicip_cloud/switch.py index 62e72f0ade7..2199b867002 100644 --- a/homeassistant/components/homematicip_cloud/switch.py +++ b/homeassistant/components/homematicip_cloud/switch.py @@ -10,10 +10,6 @@ DEPENDENCIES = ['homematicip_cloud'] _LOGGER = logging.getLogger(__name__) -ATTR_POWER_CONSUMPTION = 'power_consumption' -ATTR_ENERGIE_COUNTER = 'energie_counter' -ATTR_PROFILE_MODE = 'profile_mode' - async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): diff --git a/homeassistant/components/homematicip_cloud/weather.py b/homeassistant/components/homematicip_cloud/weather.py index 101adcdeaaa..ba3157471f9 100644 --- a/homeassistant/components/homematicip_cloud/weather.py +++ b/homeassistant/components/homematicip_cloud/weather.py @@ -3,6 +3,7 @@ import logging from homeassistant.components.weather import WeatherEntity +from homeassistant.const import TEMP_CELSIUS from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice @@ -55,7 +56,7 @@ class HomematicipWeatherSensor(HomematicipGenericDevice, WeatherEntity): @property def temperature_unit(self): """Return the unit of measurement.""" - return self.hass.config.units.temperature_unit + return TEMP_CELSIUS @property def humidity(self): From 7d7b931163636d1b778b64e52cfed60b85f76087 Mon Sep 17 00:00:00 2001 From: Sander Cornelissen Date: Sun, 31 Mar 2019 22:00:48 +0200 Subject: [PATCH 009/167] Retrying connecting Influxdb at setup (#22567) * Also retry Influxdb at setup() * Use event.call_later() for retry setup Influxdb * Fix max line length in setup() in Influxdb * Add extra space before comment * Fix sec -> seconds and add return True --- homeassistant/components/influxdb/__init__.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/influxdb/__init__.py b/homeassistant/components/influxdb/__init__.py index b421960b51f..551996983c8 100644 --- a/homeassistant/components/influxdb/__init__.py +++ b/homeassistant/components/influxdb/__init__.py @@ -14,7 +14,7 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_PORT, CONF_SSL, CONF_USERNAME, CONF_VERIFY_SSL, EVENT_STATE_CHANGED, EVENT_HOMEASSISTANT_STOP, STATE_UNAVAILABLE, STATE_UNKNOWN) -from homeassistant.helpers import state as state_helper +from homeassistant.helpers import state as state_helper, event as event_helper import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_values import EntityValues @@ -39,6 +39,7 @@ DOMAIN = 'influxdb' TIMEOUT = 5 RETRY_DELAY = 20 QUEUE_BACKLOG_SECONDS = 30 +RETRY_INTERVAL = 60 # seconds BATCH_TIMEOUT = 1 BATCH_BUFFER_SIZE = 100 @@ -134,11 +135,16 @@ def setup(hass, config): influx.write_points([]) except (exceptions.InfluxDBClientError, requests.exceptions.ConnectionError) as exc: - _LOGGER.error("Database host is not accessible due to '%s', please " - "check your entries in the configuration file (host, " - "port, etc.) and verify that the database exists and is " - "READ/WRITE", exc) - return False + _LOGGER.warning( + "Database host is not accessible due to '%s', please " + "check your entries in the configuration file (host, " + "port, etc.) and verify that the database exists and is " + "READ/WRITE. Retrying again in %s seconds.", exc, RETRY_INTERVAL + ) + event_helper.call_later( + hass, RETRY_INTERVAL, lambda _: setup(hass, config) + ) + return True def event_to_json(event): """Add an event to the outgoing Influx list.""" From 755571abe3946a58a48832dd1d7c63db03df9acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9-Marc=20Simard?= Date: Sun, 31 Mar 2019 17:21:45 -0400 Subject: [PATCH 010/167] Fix gtfs typing and logger issues (#22572) ## Description: Some code cleanup requests where raised in the [latest merged GTFS commit](https://github.com/home-assistant/home-assistant/pull/20966/commits/9153e3b671990d3c33f59b8cde5506b30fcaaa65). This new PR aims to address them, including: - Clear all typing issues. - Respect logger levels and format. - Simplify some non-pythonic lines. This sensor now passes `mypy` testing, but does so by ignoring two lines with `# type: ignore`. **Related issue (if applicable):** fixes issues raised by @MartinHjelmare in #20966 ## Checklist: - [x] The code change is tested and works locally. - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass** - [x] There is no commented out code in this PR. [ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14 [ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23 --- homeassistant/components/gtfs/sensor.py | 70 ++++++++++++------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/gtfs/sensor.py b/homeassistant/components/gtfs/sensor.py index 5555459aa16..85f2651d1f6 100644 --- a/homeassistant/components/gtfs/sensor.py +++ b/homeassistant/components/gtfs/sensor.py @@ -130,7 +130,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # type: ignore def get_next_departure(schedule: Any, start_station_id: Any, end_station_id: Any, offset: cv.time_period, - include_tomorrow: cv.boolean = False) -> dict: + include_tomorrow: bool = False) -> dict: """Get the next departure for the given schedule.""" now = datetime.datetime.now() + offset now_date = now.strftime(dt_util.DATE_STR_FORMAT) @@ -147,7 +147,7 @@ def get_next_departure(schedule: Any, start_station_id: Any, limit = 24 * 60 * 60 * 2 tomorrow_select = tomorrow_where = tomorrow_order = '' if include_tomorrow: - limit = limit / 2 * 3 + limit = int(limit / 2 * 3) tomorrow_name = tomorrow.strftime('%A').lower() tomorrow_select = "calendar.{} AS tomorrow,".format(tomorrow_name) tomorrow_where = "OR calendar.{} = 1".format(tomorrow_name) @@ -218,7 +218,7 @@ def get_next_departure(schedule: Any, start_station_id: Any, # as long as all departures are within the calendar date range. timetable = {} yesterday_start = today_start = tomorrow_start = None - yesterday_last = today_last = None + yesterday_last = today_last = '' for row in result: if row['yesterday'] == 1 and yesterday_date >= row['start_date']: @@ -274,7 +274,7 @@ def get_next_departure(schedule: Any, start_station_id: Any, _LOGGER.debug("Timetable: %s", sorted(timetable.keys())) - item = {} + item = {} # type: dict for key in sorted(timetable.keys()): if dt_util.parse_datetime(key) > now: item = timetable[key] @@ -350,22 +350,22 @@ def get_next_departure(schedule: Any, start_station_id: Any, def setup_platform(hass: HomeAssistantType, config: ConfigType, add_entities: Callable[[list], None], - discovery_info: Optional[dict] = None) -> bool: + discovery_info: Optional[dict] = None) -> None: """Set up the GTFS sensor.""" gtfs_dir = hass.config.path(DEFAULT_PATH) - data = str(config.get(CONF_DATA)) + data = config[CONF_DATA] origin = config.get(CONF_ORIGIN) destination = config.get(CONF_DESTINATION) name = config.get(CONF_NAME) offset = config.get(CONF_OFFSET) - include_tomorrow = config.get(CONF_TOMORROW) + include_tomorrow = config[CONF_TOMORROW] if not os.path.exists(gtfs_dir): os.makedirs(gtfs_dir) if not os.path.exists(os.path.join(gtfs_dir, data)): _LOGGER.error("The given GTFS data file/folder was not found") - return False + return import pygtfs @@ -382,7 +382,6 @@ def setup_platform(hass: HomeAssistantType, config: ConfigType, add_entities([ GTFSDepartureSensor(gtfs, name, origin, destination, offset, include_tomorrow)]) - return True class GTFSDepartureSensor(Entity): @@ -390,7 +389,7 @@ class GTFSDepartureSensor(Entity): def __init__(self, pygtfs: Any, name: Optional[Any], origin: Any, destination: Any, offset: cv.time_period, - include_tomorrow: cv.boolean) -> None: + include_tomorrow: bool) -> None: """Initialize the sensor.""" self._pygtfs = pygtfs self.origin = origin @@ -402,7 +401,7 @@ class GTFSDepartureSensor(Entity): self._available = False self._icon = ICON self._name = '' - self._state = None + self._state = None # type: Optional[str] self._attributes = {} # type: dict self._agency = None @@ -421,10 +420,8 @@ class GTFSDepartureSensor(Entity): return self._name @property - def state(self) -> str: + def state(self) -> Optional[str]: # type: ignore """Return the state of the sensor.""" - if self._state is None: - return STATE_UNKNOWN return self._state @property @@ -488,26 +485,27 @@ class GTFSDepartureSensor(Entity): else: trip_id = self._departure['trip_id'] if not self._trip or self._trip.trip_id != trip_id: - _LOGGER.info("Fetching trip details for %s", trip_id) + _LOGGER.debug("Fetching trip details for %s", trip_id) self._trip = self._pygtfs.trips_by_id(trip_id)[0] route_id = self._departure['route_id'] if not self._route or self._route.route_id != route_id: - _LOGGER.info("Fetching route details for %s", route_id) + _LOGGER.debug("Fetching route details for %s", route_id) self._route = self._pygtfs.routes_by_id(route_id)[0] # Fetch agency details exactly once if self._agency is None and self._route: + _LOGGER.debug("Fetching agency details for %s", + self._route.agency_id) try: - _LOGGER.info("Fetching agency details for %s", - self._route.agency_id) self._agency = self._pygtfs.agencies_by_id( self._route.agency_id)[0] except IndexError: _LOGGER.warning( - "Agency ID '%s' not found in agency table. You may " - "want to update the agency database table to fix this " - "missing reference.", self._route.agency_id) + "Agency ID '%s' was not found in agency table, " + "you may want to update the routes database table " + "to fix this missing reference", + self._route.agency_id) self._agency = False # Assign attributes, icon and name @@ -540,21 +538,21 @@ class GTFSDepartureSensor(Entity): if self._departure[ATTR_FIRST] is not None: self._attributes[ATTR_FIRST] = self._departure['first'] - elif ATTR_FIRST in self._attributes.keys(): + elif ATTR_FIRST in self._attributes: del self._attributes[ATTR_FIRST] if self._departure[ATTR_LAST] is not None: self._attributes[ATTR_LAST] = self._departure['last'] - elif ATTR_LAST in self._attributes.keys(): + elif ATTR_LAST in self._attributes: del self._attributes[ATTR_LAST] else: - if ATTR_ARRIVAL in self._attributes.keys(): + if ATTR_ARRIVAL in self._attributes: del self._attributes[ATTR_ARRIVAL] - if ATTR_DAY in self._attributes.keys(): + if ATTR_DAY in self._attributes: del self._attributes[ATTR_DAY] - if ATTR_FIRST in self._attributes.keys(): + if ATTR_FIRST in self._attributes: del self._attributes[ATTR_FIRST] - if ATTR_LAST in self._attributes.keys(): + if ATTR_LAST in self._attributes: del self._attributes[ATTR_LAST] # Add contextual information @@ -563,21 +561,21 @@ class GTFSDepartureSensor(Entity): if self._state is None: self._attributes[ATTR_INFO] = "No more departures" if \ self._include_tomorrow else "No more departures today" - elif ATTR_INFO in self._attributes.keys(): + elif ATTR_INFO in self._attributes: del self._attributes[ATTR_INFO] if self._agency: self._attributes[ATTR_ATTRIBUTION] = self._agency.agency_name - elif ATTR_ATTRIBUTION in self._attributes.keys(): + elif ATTR_ATTRIBUTION in self._attributes: del self._attributes[ATTR_ATTRIBUTION] # Add extra metadata key = 'agency_id' - if self._agency and key not in self._attributes.keys(): + if self._agency and key not in self._attributes: self.append_keys(self.dict_for_table(self._agency), 'Agency') key = 'origin_station_stop_id' - if self._origin and key not in self._attributes.keys(): + if self._origin and key not in self._attributes: self.append_keys(self.dict_for_table(self._origin), "Origin Station") self._attributes[ATTR_LOCATION_ORIGIN] = \ @@ -590,7 +588,7 @@ class GTFSDepartureSensor(Entity): WHEELCHAIR_BOARDING_DEFAULT) key = 'destination_station_stop_id' - if self._destination and key not in self._attributes.keys(): + if self._destination and key not in self._attributes: self.append_keys(self.dict_for_table(self._destination), "Destination Station") self._attributes[ATTR_LOCATION_DESTINATION] = \ @@ -604,9 +602,9 @@ class GTFSDepartureSensor(Entity): # Manage Route metadata key = 'route_id' - if not self._route and key in self._attributes.keys(): + if not self._route and key in self._attributes: self.remove_keys('Route') - elif self._route and (key not in self._attributes.keys() or + elif self._route and (key not in self._attributes or self._attributes[key] != self._route.route_id): self.append_keys(self.dict_for_table(self._route), 'Route') self._attributes[ATTR_ROUTE_TYPE] = \ @@ -614,9 +612,9 @@ class GTFSDepartureSensor(Entity): # Manage Trip metadata key = 'trip_id' - if not self._trip and key in self._attributes.keys(): + if not self._trip and key in self._attributes: self.remove_keys('Trip') - elif self._trip and (key not in self._attributes.keys() or + elif self._trip and (key not in self._attributes or self._attributes[key] != self._trip.trip_id): self.append_keys(self.dict_for_table(self._trip), 'Trip') self._attributes[ATTR_BICYCLE] = BICYCLE_ALLOWED_OPTIONS.get( From e085383d2dc5fd57c502cbf6b0c02bfad8271967 Mon Sep 17 00:00:00 2001 From: drjared88 Date: Sun, 31 Mar 2019 16:12:55 -0600 Subject: [PATCH 011/167] Update ONVIF component to SUPPORT_STREAM (#22569) * Update Onvif component to SUPPORT_STREAM * Update camera.py * Update camera.py * Update camera.py Remove extra spaces. * lookup URL when camera is added to hass and add extra guards --- homeassistant/components/onvif/camera.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/onvif/camera.py b/homeassistant/components/onvif/camera.py index 36f1b18eebf..09d47c3c0c9 100644 --- a/homeassistant/components/onvif/camera.py +++ b/homeassistant/components/onvif/camera.py @@ -13,7 +13,8 @@ import voluptuous as vol from homeassistant.const import ( CONF_NAME, CONF_HOST, CONF_USERNAME, CONF_PASSWORD, CONF_PORT, ATTR_ENTITY_ID) -from homeassistant.components.camera import Camera, PLATFORM_SCHEMA +from homeassistant.components.camera import ( + Camera, PLATFORM_SCHEMA, SUPPORT_STREAM) from homeassistant.components.camera.const import DOMAIN from homeassistant.components.ffmpeg import ( DATA_FFMPEG, CONF_EXTRA_ARGUMENTS) @@ -187,13 +188,14 @@ class ONVIFHassCamera(Camera): self.hass.data[ONVIF_DATA] = {} self.hass.data[ONVIF_DATA][ENTITIES] = [] self.hass.data[ONVIF_DATA][ENTITIES].append(self) + await self.hass.async_add_executor_job(self.obtain_input_uri) async def async_camera_image(self): """Return a still image response from the camera.""" from haffmpeg.tools import ImageFrame, IMAGE_JPEG if not self._input: - await self.hass.async_add_job(self.obtain_input_uri) + await self.hass.async_add_executor_job(self.obtain_input_uri) if not self._input: return None @@ -210,7 +212,7 @@ class ONVIFHassCamera(Camera): from haffmpeg.camera import CameraMjpeg if not self._input: - await self.hass.async_add_job(self.obtain_input_uri) + await self.hass.async_add_executor_job(self.obtain_input_uri) if not self._input: return None @@ -228,6 +230,18 @@ class ONVIFHassCamera(Camera): finally: await stream.close() + @property + def supported_features(self): + """Return supported features.""" + if self._input: + return SUPPORT_STREAM + return 0 + + @property + def stream_source(self): + """Return the stream source.""" + return self._input + @property def name(self): """Return the name of this camera.""" From 50a0504e07c971874a1bedf99ebd17a5383c88b1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 31 Mar 2019 17:14:19 -0700 Subject: [PATCH 012/167] Add stream to the default config (#22602) --- homeassistant/components/default_config/__init__.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/default_config/__init__.py b/homeassistant/components/default_config/__init__.py index 888a4d51c95..6743893888d 100644 --- a/homeassistant/components/default_config/__init__.py +++ b/homeassistant/components/default_config/__init__.py @@ -1,7 +1,11 @@ """Component providing default configuration for new users.""" +try: + import av +except ImportError: + av = None DOMAIN = 'default_config' -DEPENDENCIES = ( +DEPENDENCIES = [ 'automation', 'cloud', 'config', @@ -17,7 +21,10 @@ DEPENDENCIES = ( 'system_health', 'updater', 'zeroconf', -) +] +# Only automatically set up the stream component when dependency installed +if av is not None: + DEPENDENCIES.append('stream') async def async_setup(hass, config): From 3d8efd42006a5a25ccc3393d843d7de30ecbce98 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Sun, 31 Mar 2019 20:32:55 -0600 Subject: [PATCH 013/167] Add permission checking to all RainMachine services (#22399) * Add permission checking to all RainMachine services * Linting * Some initial work * Owner comments * Test in place (I think) * Linting * Update conftest.py --- .../components/rainmachine/__init__.py | 94 ++++++++++++++----- tests/components/rainmachine/conftest.py | 23 +++++ .../rainmachine/test_service_permissions.py | 41 ++++++++ 3 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 tests/components/rainmachine/conftest.py create mode 100644 tests/components/rainmachine/test_service_permissions.py diff --git a/homeassistant/components/rainmachine/__init__.py b/homeassistant/components/rainmachine/__init__.py index 6d986fa5c67..2ff5ddcd4aa 100644 --- a/homeassistant/components/rainmachine/__init__.py +++ b/homeassistant/components/rainmachine/__init__.py @@ -1,15 +1,18 @@ """Support for RainMachine devices.""" import logging from datetime import timedelta +from functools import wraps import voluptuous as vol +from homeassistant.auth.permissions.const import POLICY_CONTROL from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import ( ATTR_ATTRIBUTION, CONF_BINARY_SENSORS, CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL, CONF_SENSORS, CONF_SSL, CONF_MONITORED_CONDITIONS, CONF_SWITCHES) -from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.exceptions import ( + ConfigEntryNotReady, Unauthorized, UnknownUser) from homeassistant.helpers import aiohttp_client, config_validation as cv from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.entity import Entity @@ -128,6 +131,44 @@ CONFIG_SCHEMA = vol.Schema({ }, extra=vol.ALLOW_EXTRA) +def _check_valid_user(hass): + """Ensure the user of a service call has proper permissions.""" + def decorator(service): + """Decorate.""" + @wraps(service) + async def check_permissions(call): + """Check user permission and raise before call if unauthorized.""" + if not call.context.user_id: + return + + user = await hass.auth.async_get_user(call.context.user_id) + if user is None: + raise UnknownUser( + context=call.context, + permission=POLICY_CONTROL + ) + + # RainMachine services don't interact with specific entities. + # Therefore, we examine _all_ RainMachine entities and if the user + # has permission to control _any_ of them, the user has permission + # to call the service: + en_reg = await hass.helpers.entity_registry.async_get_registry() + rainmachine_entities = [ + entity.entity_id for entity in en_reg.entities.values() + if entity.platform == DOMAIN + ] + for entity_id in rainmachine_entities: + if user.permissions.check_entity(entity_id, POLICY_CONTROL): + return await service(call) + + raise Unauthorized( + context=call.context, + permission=POLICY_CONTROL, + ) + return check_permissions + return decorator + + async def async_setup(hass, config): """Set up the RainMachine component.""" hass.data[DOMAIN] = {} @@ -197,59 +238,70 @@ async def async_setup_entry(hass, config_entry): refresh, timedelta(seconds=config_entry.data[CONF_SCAN_INTERVAL])) - async def disable_program(service): + @_check_valid_user(hass) + async def disable_program(call): """Disable a program.""" await rainmachine.client.programs.disable( - service.data[CONF_PROGRAM_ID]) + call.data[CONF_PROGRAM_ID]) async_dispatcher_send(hass, PROGRAM_UPDATE_TOPIC) - async def disable_zone(service): + @_check_valid_user(hass) + async def disable_zone(call): """Disable a zone.""" - await rainmachine.client.zones.disable(service.data[CONF_ZONE_ID]) + await rainmachine.client.zones.disable(call.data[CONF_ZONE_ID]) async_dispatcher_send(hass, ZONE_UPDATE_TOPIC) - async def enable_program(service): + @_check_valid_user(hass) + async def enable_program(call): """Enable a program.""" - await rainmachine.client.programs.enable(service.data[CONF_PROGRAM_ID]) + await rainmachine.client.programs.enable(call.data[CONF_PROGRAM_ID]) async_dispatcher_send(hass, PROGRAM_UPDATE_TOPIC) - async def enable_zone(service): + @_check_valid_user(hass) + async def enable_zone(call): """Enable a zone.""" - await rainmachine.client.zones.enable(service.data[CONF_ZONE_ID]) + await rainmachine.client.zones.enable(call.data[CONF_ZONE_ID]) async_dispatcher_send(hass, ZONE_UPDATE_TOPIC) - async def pause_watering(service): + @_check_valid_user(hass) + async def pause_watering(call): """Pause watering for a set number of seconds.""" - await rainmachine.client.watering.pause_all(service.data[CONF_SECONDS]) + await rainmachine.client.watering.pause_all(call.data[CONF_SECONDS]) async_dispatcher_send(hass, PROGRAM_UPDATE_TOPIC) - async def start_program(service): + @_check_valid_user(hass) + async def start_program(call): """Start a particular program.""" - await rainmachine.client.programs.start(service.data[CONF_PROGRAM_ID]) + await rainmachine.client.programs.start(call.data[CONF_PROGRAM_ID]) async_dispatcher_send(hass, PROGRAM_UPDATE_TOPIC) - async def start_zone(service): + @_check_valid_user(hass) + async def start_zone(call): """Start a particular zone for a certain amount of time.""" await rainmachine.client.zones.start( - service.data[CONF_ZONE_ID], service.data[CONF_ZONE_RUN_TIME]) + call.data[CONF_ZONE_ID], call.data[CONF_ZONE_RUN_TIME]) async_dispatcher_send(hass, ZONE_UPDATE_TOPIC) - async def stop_all(service): + @_check_valid_user(hass) + async def stop_all(call): """Stop all watering.""" await rainmachine.client.watering.stop_all() async_dispatcher_send(hass, PROGRAM_UPDATE_TOPIC) - async def stop_program(service): + @_check_valid_user(hass) + async def stop_program(call): """Stop a program.""" - await rainmachine.client.programs.stop(service.data[CONF_PROGRAM_ID]) + await rainmachine.client.programs.stop(call.data[CONF_PROGRAM_ID]) async_dispatcher_send(hass, PROGRAM_UPDATE_TOPIC) - async def stop_zone(service): + @_check_valid_user(hass) + async def stop_zone(call): """Stop a zone.""" - await rainmachine.client.zones.stop(service.data[CONF_ZONE_ID]) + await rainmachine.client.zones.stop(call.data[CONF_ZONE_ID]) async_dispatcher_send(hass, ZONE_UPDATE_TOPIC) - async def unpause_watering(service): + @_check_valid_user(hass) + async def unpause_watering(call): """Unpause watering.""" await rainmachine.client.watering.unpause_all() async_dispatcher_send(hass, PROGRAM_UPDATE_TOPIC) diff --git a/tests/components/rainmachine/conftest.py b/tests/components/rainmachine/conftest.py new file mode 100644 index 00000000000..fdc81151995 --- /dev/null +++ b/tests/components/rainmachine/conftest.py @@ -0,0 +1,23 @@ +"""Configuration for Rainmachine tests.""" +import pytest + +from homeassistant.components.rainmachine.const import DOMAIN +from homeassistant.const import ( + CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL, CONF_SSL) + +from tests.common import MockConfigEntry + + +@pytest.fixture(name="config_entry") +def config_entry_fixture(): + """Create a mock RainMachine config entry.""" + return MockConfigEntry( + domain=DOMAIN, + title='192.168.1.101', + data={ + CONF_IP_ADDRESS: '192.168.1.101', + CONF_PASSWORD: '12345', + CONF_PORT: 8080, + CONF_SSL: True, + CONF_SCAN_INTERVAL: 60, + }) diff --git a/tests/components/rainmachine/test_service_permissions.py b/tests/components/rainmachine/test_service_permissions.py new file mode 100644 index 00000000000..caa84337517 --- /dev/null +++ b/tests/components/rainmachine/test_service_permissions.py @@ -0,0 +1,41 @@ +"""Define tests for permissions on RainMachine service calls.""" +import asynctest +import pytest + +from homeassistant.components.rainmachine.const import DOMAIN +from homeassistant.core import Context +from homeassistant.exceptions import Unauthorized, UnknownUser +from homeassistant.setup import async_setup_component + +from tests.common import mock_coro + + +async def setup_platform(hass, config_entry): + """Set up the media player platform for testing.""" + with asynctest.mock.patch('regenmaschine.login') as mock_login: + mock_client = mock_login.return_value + mock_client.restrictions.current.return_value = mock_coro() + mock_client.restrictions.universal.return_value = mock_coro() + config_entry.add_to_hass(hass) + assert await async_setup_component(hass, DOMAIN) + await hass.async_block_till_done() + + +async def test_services_authorization( + hass, config_entry, hass_read_only_user): + """Test that a RainMachine service is halted on incorrect permissions.""" + await setup_platform(hass, config_entry) + + with pytest.raises(UnknownUser): + await hass.services.async_call( + 'rainmachine', + 'unpause_watering', {}, + blocking=True, + context=Context(user_id='fake_user_id')) + + with pytest.raises(Unauthorized): + await hass.services.async_call( + 'rainmachine', + 'unpause_watering', {}, + blocking=True, + context=Context(user_id=hass_read_only_user.id)) From 9a4b0cfb9b51400980ee5b797f3301e4861ac8dd Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 31 Mar 2019 19:52:44 -0700 Subject: [PATCH 014/167] Updated frontend to 20190331.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 3baea2008b1..f0358dbd6cc 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -21,7 +21,7 @@ from homeassistant.loader import bind_hass from .storage import async_setup_frontend_storage -REQUIREMENTS = ['home-assistant-frontend==20190329.0'] +REQUIREMENTS = ['home-assistant-frontend==20190331.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 18f9098a2e4..e3cc4a34954 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -551,7 +551,7 @@ hole==0.3.0 holidays==0.9.10 # homeassistant.components.frontend -home-assistant-frontend==20190329.0 +home-assistant-frontend==20190331.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 6c7f5b6a5a7..85b49f71ce7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -129,7 +129,7 @@ hdate==0.8.7 holidays==0.9.10 # homeassistant.components.frontend -home-assistant-frontend==20190329.0 +home-assistant-frontend==20190331.0 # homeassistant.components.homekit_controller homekit[IP]==0.13.0 From 804f1d1cc8fc031e30383135b1dcd1cbfb9dc638 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 31 Mar 2019 20:01:23 -0700 Subject: [PATCH 015/167] Update translations --- .../components/axis/.translations/no.json | 26 ++++++++++++++ .../components/axis/.translations/pt.json | 12 +++++++ .../components/deconz/.translations/pt.json | 4 +-- .../components/esphome/.translations/no.json | 2 +- .../components/esphome/.translations/pt.json | 2 +- .../components/heos/.translations/ca.json | 20 +++++++++++ .../components/heos/.translations/en.json | 34 +++++++++---------- .../components/heos/.translations/no.json | 5 +++ .../components/heos/.translations/ru.json | 20 +++++++++++ .../homematicip_cloud/.translations/pt.json | 2 +- .../components/ps4/.translations/da.json | 3 ++ .../components/ps4/.translations/no.json | 9 +++++ .../components/ps4/.translations/pl.json | 9 +++++ .../components/ps4/.translations/ru.json | 4 +-- .../components/ps4/.translations/zh-Hant.json | 9 +++++ 15 files changed, 137 insertions(+), 24 deletions(-) create mode 100644 homeassistant/components/axis/.translations/no.json create mode 100644 homeassistant/components/axis/.translations/pt.json create mode 100644 homeassistant/components/heos/.translations/ca.json create mode 100644 homeassistant/components/heos/.translations/no.json create mode 100644 homeassistant/components/heos/.translations/ru.json diff --git a/homeassistant/components/axis/.translations/no.json b/homeassistant/components/axis/.translations/no.json new file mode 100644 index 00000000000..94b5a1680b7 --- /dev/null +++ b/homeassistant/components/axis/.translations/no.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "Enheten er allerede konfigurert", + "bad_config_file": "D\u00e5rlig data fra konfigurasjonsfilen", + "link_local_address": "Linking av lokale adresser st\u00f8ttes ikke" + }, + "error": { + "already_configured": "Enheten er allerede konfigurert", + "device_unavailable": "Enheten er ikke tilgjengelig", + "faulty_credentials": "Ugyldig brukerlegitimasjon" + }, + "step": { + "user": { + "data": { + "host": "Vert", + "password": "Passord", + "port": "Port", + "username": "Brukernavn" + }, + "title": "Sett opp Axis enhet" + } + }, + "title": "Axis enhet" + } +} \ No newline at end of file diff --git a/homeassistant/components/axis/.translations/pt.json b/homeassistant/components/axis/.translations/pt.json new file mode 100644 index 00000000000..e71b890506d --- /dev/null +++ b/homeassistant/components/axis/.translations/pt.json @@ -0,0 +1,12 @@ +{ + "config": { + "step": { + "user": { + "data": { + "password": "Palavra-passe", + "port": "Porta" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/pt.json b/homeassistant/components/deconz/.translations/pt.json index a0419b8baa4..47f5bb7db59 100644 --- a/homeassistant/components/deconz/.translations/pt.json +++ b/homeassistant/components/deconz/.translations/pt.json @@ -12,13 +12,13 @@ "init": { "data": { "host": "Servidor", - "port": "Porta (por omiss\u00e3o: '80')" + "port": "Porta" }, "title": "Defina o gateway deCONZ" }, "link": { "description": "Desbloqueie o seu gateway deCONZ para se registar no Home Assistant. \n\n 1. V\u00e1 para as configura\u00e7\u00f5es do sistema deCONZ \n 2. Pressione o bot\u00e3o \"Desbloquear Gateway\"", - "title": "Link com deCONZ" + "title": "Liga\u00e7\u00e3o com deCONZ" }, "options": { "data": { diff --git a/homeassistant/components/esphome/.translations/no.json b/homeassistant/components/esphome/.translations/no.json index 095e8825fbd..c71424b6f00 100644 --- a/homeassistant/components/esphome/.translations/no.json +++ b/homeassistant/components/esphome/.translations/no.json @@ -13,7 +13,7 @@ "data": { "password": "Passord" }, - "description": "Vennligst skriv inn passordet du har angitt i din konfigurasjon.", + "description": "Vennligst skriv inn passordet du har angitt i din konfigurasjon for {name}.", "title": "Skriv Inn Passord" }, "discovery_confirm": { diff --git a/homeassistant/components/esphome/.translations/pt.json b/homeassistant/components/esphome/.translations/pt.json index ea1e25c3024..7e4a85f3514 100644 --- a/homeassistant/components/esphome/.translations/pt.json +++ b/homeassistant/components/esphome/.translations/pt.json @@ -13,7 +13,7 @@ "data": { "password": "Palavra-passe" }, - "description": "Por favor, insira a palavra-passe que colocou na configura\u00e7\u00e3o", + "description": "Por favor, insira a palavra-passe que colocou na configura\u00e7\u00e3o para {name}", "title": "Palavra-passe" }, "user": { diff --git a/homeassistant/components/heos/.translations/ca.json b/homeassistant/components/heos/.translations/ca.json new file mode 100644 index 00000000000..1336d487953 --- /dev/null +++ b/homeassistant/components/heos/.translations/ca.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_setup": "Nom\u00e9s pots configurar una \u00fanica connexi\u00f3 de Heos tot i que aquesta ja pot controlar tots els dispositius de la xarxa." + }, + "error": { + "connection_failure": "No es pot connectar amb l'amfitri\u00f3 especificat." + }, + "step": { + "user": { + "data": { + "access_token": "Amfitri\u00f3" + }, + "description": "Introdueix el nom d'amfitri\u00f3 o l'adre\u00e7a IP d'un dispositiu Heos (preferiblement un connectat a la xarxa per cable).", + "title": "Connexi\u00f3 amb Heos" + } + }, + "title": "Heos" + } +} \ No newline at end of file diff --git a/homeassistant/components/heos/.translations/en.json b/homeassistant/components/heos/.translations/en.json index a272c0a2a0f..c38b69ea1c2 100644 --- a/homeassistant/components/heos/.translations/en.json +++ b/homeassistant/components/heos/.translations/en.json @@ -1,20 +1,20 @@ { - "config": { - "title": "Heos", - "step": { - "user": { - "title": "Connect to Heos", - "description": "Please enter the host name or IP address of a Heos device (preferably one connected via wire to the network).", - "data": { - "access_token": "Host" - } - } - }, - "error": { - "connection_failure": "Unable to connect to the specified host." - }, - "abort": { - "already_setup": "You can only configure a single Heos connection as it will support all devices on the network." + "config": { + "abort": { + "already_setup": "You can only configure a single Heos connection as it will support all devices on the network." + }, + "error": { + "connection_failure": "Unable to connect to the specified host." + }, + "step": { + "user": { + "data": { + "access_token": "Host" + }, + "description": "Please enter the host name or IP address of a Heos device (preferably one connected via wire to the network).", + "title": "Connect to Heos" + } + }, + "title": "Heos" } - } } \ No newline at end of file diff --git a/homeassistant/components/heos/.translations/no.json b/homeassistant/components/heos/.translations/no.json new file mode 100644 index 00000000000..12ed8cc457a --- /dev/null +++ b/homeassistant/components/heos/.translations/no.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Heos" + } +} \ No newline at end of file diff --git a/homeassistant/components/heos/.translations/ru.json b/homeassistant/components/heos/.translations/ru.json new file mode 100644 index 00000000000..e78b9e4083b --- /dev/null +++ b/homeassistant/components/heos/.translations/ru.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_setup": "\u041d\u0443\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Heos \u0432 \u0441\u0435\u0442\u0438." + }, + "error": { + "connection_failure": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c\u0443 \u0445\u043e\u0441\u0442\u0443" + }, + "step": { + "user": { + "data": { + "access_token": "\u0425\u043e\u0441\u0442" + }, + "description": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0438\u043c\u044f \u0445\u043e\u0441\u0442\u0430 \u0438\u043b\u0438 IP-\u0430\u0434\u0440\u0435\u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Heos (\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0441\u0435\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 \u043a\u0430\u0431\u0435\u043b\u044c).", + "title": "Heos" + } + }, + "title": "Heos" + } +} \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/.translations/pt.json b/homeassistant/components/homematicip_cloud/.translations/pt.json index 8b431125ef0..0954f3ff4f9 100644 --- a/homeassistant/components/homematicip_cloud/.translations/pt.json +++ b/homeassistant/components/homematicip_cloud/.translations/pt.json @@ -21,7 +21,7 @@ "title": "Escolher ponto de acesso HomematicIP" }, "link": { - "description": "Pressione o bot\u00e3o azul no ponto de acesso e o bot\u00e3o enviar para registrar HomematicIP com o Home Assistant.\n\n![Localiza\u00e7\u00e3o do bot\u00e3o na ponte](/ static/images/config_flows/config_homematicip_cloud.png)", + "description": "Pressione o bot\u00e3o azul no ponto de acesso e o bot\u00e3o enviar para registrar HomematicIP com o Home Assistant.\n\n![Localiza\u00e7\u00e3o do bot\u00e3o na bridge](/ static/images/config_flows/config_homematicip_cloud.png)", "title": "Associar ponto de acesso" } }, diff --git a/homeassistant/components/ps4/.translations/da.json b/homeassistant/components/ps4/.translations/da.json index 7c5f9e7621c..801317a9e7f 100644 --- a/homeassistant/components/ps4/.translations/da.json +++ b/homeassistant/components/ps4/.translations/da.json @@ -25,6 +25,9 @@ }, "description": "Indtast dine PlayStation 4 oplysninger. For 'PIN' skal du navigere til 'Indstillinger' p\u00e5 din PlayStation 4 konsol. G\u00e5 derefter til 'Indstillinger for mobilapp-forbindelse' og v\u00e6lg 'Tilf\u00f8j enhed'. Indtast den PIN der vises.", "title": "PlayStation 4" + }, + "mode": { + "title": "PlayStation 4" } }, "title": "PlayStation 4" diff --git a/homeassistant/components/ps4/.translations/no.json b/homeassistant/components/ps4/.translations/no.json index 32687882da2..8907032d83e 100644 --- a/homeassistant/components/ps4/.translations/no.json +++ b/homeassistant/components/ps4/.translations/no.json @@ -9,6 +9,7 @@ }, "error": { "login_failed": "Klarte ikke \u00e5 koble til PlayStation 4. Bekreft at PIN koden er riktig.", + "no_ipaddress": "Angi IP adressen til din PlayStation 4 som du \u00f8nsker konfigurere.", "not_ready": "PlayStation 4 er ikke p\u00e5sl\u00e5tt eller koblet til nettverk." }, "step": { @@ -25,6 +26,14 @@ }, "description": "Skriv inn PlayStation 4 informasjonen din. For 'PIN', naviger til 'Innstillinger' p\u00e5 PlayStation 4 konsollen, deretter navigerer du til 'Innstillinger for mobilapp forbindelse' og velger 'Legg til enhet'. Skriv inn PIN-koden som vises.", "title": "PlayStation 4" + }, + "mode": { + "data": { + "ip_address": "IP- adresse (Ikke fyll ut hvis du bruker Auto Discovery).", + "mode": "Konfigureringsmodus" + }, + "description": "Velg modus for konfigurasjon. Feltet IP-adresse kan st\u00e5 tomt dersom du velger Auto Discovery, da enheter vil bli oppdaget automatisk.", + "title": "PlayStation 4" } }, "title": "PlayStation 4" diff --git a/homeassistant/components/ps4/.translations/pl.json b/homeassistant/components/ps4/.translations/pl.json index eea4eda0810..d38dabe3188 100644 --- a/homeassistant/components/ps4/.translations/pl.json +++ b/homeassistant/components/ps4/.translations/pl.json @@ -9,6 +9,7 @@ }, "error": { "login_failed": "Nie uda\u0142o si\u0119 sparowa\u0107 z PlayStation 4. Sprawd\u017a, czy PIN jest poprawny.", + "no_ipaddress": "Wprowad\u017a adres IP PlayStation 4, kt\u00f3ry chcesz skonfigurowa\u0107.", "not_ready": "PlayStation 4 nie jest w\u0142\u0105czona lub po\u0142\u0105czona z sieci\u0105." }, "step": { @@ -25,6 +26,14 @@ }, "description": "Wprowad\u017a informacje o PlayStation 4. Aby uzyska\u0107 'PIN', przejd\u017a do 'Ustawienia' na konsoli PlayStation 4. Nast\u0119pnie przejd\u017a do 'Ustawienia po\u0142\u0105czenia aplikacji mobilnej' i wybierz 'Dodaj urz\u0105dzenie'. Wprowad\u017a wy\u015bwietlony kod PIN.", "title": "PlayStation 4" + }, + "mode": { + "data": { + "ip_address": "Adres IP (pozostaw puste, je\u015bli u\u017cywasz funkcji Auto Discovery).", + "mode": "Tryb konfiguracji" + }, + "description": "Wybierz tryb konfiguracji. Pole adresu IP mo\u017cna pozostawi\u0107 puste, je\u015bli wybierzesz opcj\u0119 Auto Discovery, poniewa\u017c urz\u0105dzenia zostan\u0105 automatycznie wykryte.", + "title": "PlayStation 4" } }, "title": "PlayStation 4" diff --git a/homeassistant/components/ps4/.translations/ru.json b/homeassistant/components/ps4/.translations/ru.json index 424d0964729..a784a607ac3 100644 --- a/homeassistant/components/ps4/.translations/ru.json +++ b/homeassistant/components/ps4/.translations/ru.json @@ -8,13 +8,13 @@ "port_997_bind_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043f\u043e\u0440\u0442\u0443 997. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/ps4/)." }, "error": { - "login_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u0441 PlayStation 4. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e PIN-\u043a\u043e\u0434 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439.", + "login_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043e\u043f\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u0441 PlayStation 4. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e PIN-\u043a\u043e\u0434 \u0432\u0432\u0435\u0434\u0435\u043d \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e.", "no_ipaddress": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 IP-\u0430\u0434\u0440\u0435\u0441 PlayStation 4.", "not_ready": "PlayStation 4 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u043a \u0441\u0435\u0442\u0438." }, "step": { "creds": { - "description": "\u041d\u0430\u0436\u043c\u0438\u0442\u0435 **\u041f\u041e\u0414\u0422\u0412\u0415\u0420\u0414\u0418\u0422\u042c**, \u0430 \u0437\u0430\u0442\u0435\u043c \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 'PS4 Second Screen' \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e 'Home-Assistant', \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c.", + "description": "\u041d\u0430\u0436\u043c\u0438\u0442\u0435 **\u041f\u041e\u0414\u0422\u0412\u0415\u0420\u0414\u0418\u0422\u042c**, \u0430 \u0437\u0430\u0442\u0435\u043c \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 'PS4 Second Screen' \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0435 \u0441\u043f\u0438\u0441\u043e\u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e 'Home-Assistant'.", "title": "PlayStation 4" }, "link": { diff --git a/homeassistant/components/ps4/.translations/zh-Hant.json b/homeassistant/components/ps4/.translations/zh-Hant.json index b4f45986c1e..54740e2c727 100644 --- a/homeassistant/components/ps4/.translations/zh-Hant.json +++ b/homeassistant/components/ps4/.translations/zh-Hant.json @@ -9,6 +9,7 @@ }, "error": { "login_failed": "PlayStation 4 \u914d\u5c0d\u5931\u6557\uff0c\u8acb\u78ba\u8a8d PIN \u78bc\u3002", + "no_ipaddress": "\u8f38\u5165\u6240\u8981\u8a2d\u5b9a\u7684 PlayStation 4 \u4e4b IP \u4f4d\u5740\u3002", "not_ready": "PlayStation 4 \u4e26\u672a\u958b\u555f\u6216\u672a\u9023\u7dda\u81f3\u7db2\u8def\u3002" }, "step": { @@ -25,6 +26,14 @@ }, "description": "\u8f38\u5165\u60a8\u7684 PlayStation 4 \u8cc7\u8a0a\uff0c\u300cPIN\u300d\u65bc PlayStation 4 \u4e3b\u6a5f\u7684\u300c\u8a2d\u5b9a\u300d\u5167\uff0c\u4e26\u65bc\u300c\u884c\u52d5\u7a0b\u5f0f\u9023\u7dda\u8a2d\u5b9a\uff08Mobile App Connection Settings\uff09\u300d\u4e2d\u9078\u64c7\u300c\u65b0\u589e\u88dd\u7f6e\u300d\u3002\u8f38\u5165\u6240\u986f\u793a\u7684 PIN \u78bc\u3002", "title": "PlayStation 4" + }, + "mode": { + "data": { + "ip_address": "IP \u4f4d\u5740\uff08\u5982\u679c\u4f7f\u7528\u81ea\u52d5\u63a2\u7d22\u65b9\u5f0f\uff0c\u8acb\u4fdd\u7559\u7a7a\u767d\uff09\u3002", + "mode": "\u8a2d\u5b9a\u6a21\u5f0f" + }, + "description": "\u9078\u64c7\u6a21\u5f0f\u4ee5\u9032\u884c\u8a2d\u5b9a\u3002\u5047\u5982\u9078\u64c7\u81ea\u52d5\u63a2\u7d22\u6a21\u5f0f\u7684\u8a71\uff0c\u7531\u65bc\u6703\u81ea\u52d5\u9032\u884c\u88dd\u7f6e\u641c\u5c0b\uff0cIP \u4f4d\u5740\u53ef\u4fdd\u7559\u70ba\u7a7a\u767d\u3002", + "title": "PlayStation 4" } }, "title": "PlayStation 4" From 734a67ede003b252639e4dcaf5a4df149ac2a6e3 Mon Sep 17 00:00:00 2001 From: carstenschroeder Date: Mon, 1 Apr 2019 05:28:43 +0200 Subject: [PATCH 016/167] Refactor of ADS integration and introduce ADSEntity (#22583) * Prevent toogle to false at restart * change to asyncio.run_coroutine_threadsafe * refactor ADS platforms; introduce AdsEntity * fix hound findings * some formatting * remove redundant def. * fix useless super delegation * fix inconsistent ADS data type for brightness * fix requested changes * fix comment --- homeassistant/components/ads/__init__.py | 71 ++++++++++++++ homeassistant/components/ads/binary_sensor.py | 63 ++---------- homeassistant/components/ads/light.py | 97 ++++--------------- homeassistant/components/ads/sensor.py | 53 +++------- homeassistant/components/ads/switch.py | 70 ++----------- 5 files changed, 121 insertions(+), 233 deletions(-) diff --git a/homeassistant/components/ads/__init__.py b/homeassistant/components/ads/__init__.py index 1b90e645af4..5ab53e3acd2 100644 --- a/homeassistant/components/ads/__init__.py +++ b/homeassistant/components/ads/__init__.py @@ -4,12 +4,15 @@ import struct import logging import ctypes from collections import namedtuple +import asyncio +import async_timeout import voluptuous as vol from homeassistant.const import ( CONF_DEVICE, CONF_IP_ADDRESS, CONF_PORT, EVENT_HOMEASSISTANT_STOP) import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import Entity REQUIREMENTS = ['pyads==3.0.7'] @@ -31,6 +34,9 @@ CONF_ADS_VALUE = 'value' CONF_ADS_VAR = 'adsvar' CONF_ADS_VAR_BRIGHTNESS = 'adsvar_brightness' +STATE_KEY_STATE = 'state' +STATE_KEY_BRIGHTNESS = 'brightness' + DOMAIN = 'ads' SERVICE_WRITE_DATA_BY_NAME = 'write_data_by_name' @@ -210,3 +216,68 @@ class AdsHub: _LOGGER.warning("No callback available for this datatype") notification_item.callback(notification_item.name, value) + + +class AdsEntity(Entity): + """Representation of ADS entity.""" + + def __init__(self, ads_hub, name, ads_var): + """Initialize ADS binary sensor.""" + self._name = name + self._unique_id = ads_var + self._state_dict = {} + self._state_dict[STATE_KEY_STATE] = None + self._ads_hub = ads_hub + self._ads_var = ads_var + self._event = None + + async def async_initialize_device( + self, ads_var, plctype, state_key=STATE_KEY_STATE, factor=None): + """Register device notification.""" + def update(name, value): + """Handle device notifications.""" + _LOGGER.debug('Variable %s changed its value to %d', name, value) + + if factor is None: + self._state_dict[state_key] = value + else: + self._state_dict[state_key] = value / factor + + asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop) + self.schedule_update_ha_state() + + async def async_event_set(): + """Set event in async context.""" + self._event.set() + + self._event = asyncio.Event() + + await self.hass.async_add_executor_job( + self._ads_hub.add_device_notification, + ads_var, plctype, update) + try: + with async_timeout.timeout(10): + await self._event.wait() + except asyncio.TimeoutError: + _LOGGER.debug('Variable %s: Timeout during first update', + ads_var) + + @property + def name(self): + """Return the default name of the binary sensor.""" + return self._name + + @property + def unique_id(self): + """Return an unique identifier for this entity.""" + return self._unique_id + + @property + def should_poll(self): + """Return False because entity pushes its state to HA.""" + return False + + @property + def available(self): + """Return False if state has not been updated yet.""" + return self._state_dict[STATE_KEY_STATE] is not None diff --git a/homeassistant/components/ads/binary_sensor.py b/homeassistant/components/ads/binary_sensor.py index 91cd60771d9..baa44cb498f 100644 --- a/homeassistant/components/ads/binary_sensor.py +++ b/homeassistant/components/ads/binary_sensor.py @@ -1,7 +1,5 @@ """Support for ADS binary sensors.""" import logging -import asyncio -import async_timeout import voluptuous as vol @@ -10,7 +8,7 @@ from homeassistant.components.binary_sensor import ( from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME import homeassistant.helpers.config_validation as cv -from . import CONF_ADS_VAR, DATA_ADS +from . import CONF_ADS_VAR, DATA_ADS, AdsEntity, STATE_KEY_STATE _LOGGER = logging.getLogger(__name__) @@ -36,70 +34,25 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities([ads_sensor]) -class AdsBinarySensor(BinarySensorDevice): +class AdsBinarySensor(AdsEntity, BinarySensorDevice): """Representation of ADS binary sensors.""" def __init__(self, ads_hub, name, ads_var, device_class): """Initialize ADS binary sensor.""" - self._name = name - self._unique_id = ads_var - self._state = None + super().__init__(ads_hub, name, ads_var) self._device_class = device_class or 'moving' - self._ads_hub = ads_hub - self.ads_var = ads_var - self._event = None async def async_added_to_hass(self): """Register device notification.""" - def update(name, value): - """Handle device notifications.""" - _LOGGER.debug('Variable %s changed its value to %d', name, value) - self._state = value - asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop) - self.schedule_update_ha_state() - - async def async_event_set(): - """Set event in async context.""" - self._event.set() - - self._event = asyncio.Event() - - await self.hass.async_add_executor_job( - self._ads_hub.add_device_notification, - self.ads_var, self._ads_hub.PLCTYPE_BOOL, update) - try: - with async_timeout.timeout(10): - await self._event.wait() - except asyncio.TimeoutError: - _LOGGER.debug('Variable %s: Timeout during first update', - self.ads_var) + await self.async_initialize_device(self._ads_var, + self._ads_hub.PLCTYPE_BOOL) @property - def name(self): - """Return the default name of the binary sensor.""" - return self._name - - @property - def unique_id(self): - """Return an unique identifier for this entity.""" - return self._unique_id + def is_on(self): + """Return True if the entity is on.""" + return self._state_dict[STATE_KEY_STATE] @property def device_class(self): """Return the device class.""" return self._device_class - - @property - def is_on(self): - """Return if the binary sensor is on.""" - return self._state - - @property - def should_poll(self): - """Return False because entity pushes its state to HA.""" - return False - - @property - def available(self): - """Return False if state has not been updated yet.""" - return self._state is not None diff --git a/homeassistant/components/ads/light.py b/homeassistant/components/ads/light.py index 2ece1402907..49961565dce 100644 --- a/homeassistant/components/ads/light.py +++ b/homeassistant/components/ads/light.py @@ -1,7 +1,5 @@ """Support for ADS light sources.""" import logging -import asyncio -import async_timeout import voluptuous as vol @@ -10,12 +8,12 @@ from homeassistant.components.light import ( from homeassistant.const import CONF_NAME import homeassistant.helpers.config_validation as cv -from . import CONF_ADS_VAR, CONF_ADS_VAR_BRIGHTNESS, DATA_ADS +from . import CONF_ADS_VAR, CONF_ADS_VAR_BRIGHTNESS, DATA_ADS, \ + AdsEntity, STATE_KEY_BRIGHTNESS, STATE_KEY_STATE _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['ads'] DEFAULT_NAME = 'ADS Light' -CONF_ADSVAR_BRIGHTNESS = 'adsvar_brightness' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_ADS_VAR): cv.string, vol.Optional(CONF_ADS_VAR_BRIGHTNESS): cv.string, @@ -35,107 +33,54 @@ def setup_platform(hass, config, add_entities, discovery_info=None): name)]) -class AdsLight(Light): +class AdsLight(AdsEntity, Light): """Representation of ADS light.""" def __init__(self, ads_hub, ads_var_enable, ads_var_brightness, name): """Initialize AdsLight entity.""" - self._ads_hub = ads_hub - self._on_state = None - self._brightness = None - self._name = name - self._unique_id = ads_var_enable - self.ads_var_enable = ads_var_enable - self.ads_var_brightness = ads_var_brightness - self._event = None + super().__init__(ads_hub, name, ads_var_enable) + self._state_dict[STATE_KEY_BRIGHTNESS] = None + self._ads_var_brightness = ads_var_brightness async def async_added_to_hass(self): """Register device notification.""" - def update_on_state(name, value): - """Handle device notifications for state.""" - _LOGGER.debug('Variable %s changed its value to %d', name, value) - self._on_state = value - asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop) - self.schedule_update_ha_state() + await self.async_initialize_device(self._ads_var, + self._ads_hub.PLCTYPE_BOOL) - async def async_event_set(): - """Set event in async context.""" - self._event.set() - - def update_brightness(name, value): - """Handle device notification for brightness.""" - _LOGGER.debug('Variable %s changed its value to %d', name, value) - self._brightness = value - self.schedule_update_ha_state() - - self._event = asyncio.Event() - - await self.hass.async_add_executor_job( - self._ads_hub.add_device_notification, - self.ads_var_enable, self._ads_hub.PLCTYPE_BOOL, update_on_state - ) - if self.ads_var_brightness is not None: - await self.hass.async_add_executor_job( - self._ads_hub.add_device_notification, - self.ads_var_brightness, self._ads_hub.PLCTYPE_INT, - update_brightness - ) - try: - with async_timeout.timeout(10): - await self._event.wait() - except asyncio.TimeoutError: - _LOGGER.debug('Variable %s: Timeout during first update', - self.ads_var_enable) - - @property - def name(self): - """Return the name of the device if any.""" - return self._name - - @property - def unique_id(self): - """Return an unique identifier for this entity.""" - return self._unique_id + if self._ads_var_brightness is not None: + await self.async_initialize_device(self._ads_var_brightness, + self._ads_hub.PLCTYPE_UINT, + STATE_KEY_BRIGHTNESS) @property def brightness(self): """Return the brightness of the light (0..255).""" - return self._brightness - - @property - def is_on(self): - """Return if light is on.""" - return self._on_state - - @property - def should_poll(self): - """Return False because entity pushes its state to HA.""" - return False + return self._state_dict[STATE_KEY_BRIGHTNESS] @property def supported_features(self): """Flag supported features.""" support = 0 - if self.ads_var_brightness is not None: + if self._ads_var_brightness is not None: support = SUPPORT_BRIGHTNESS return support @property - def available(self): - """Return False if state has not been updated yet.""" - return self._on_state is not None + def is_on(self): + """Return True if the entity is on.""" + return self._state_dict[STATE_KEY_STATE] def turn_on(self, **kwargs): """Turn the light on or set a specific dimmer value.""" brightness = kwargs.get(ATTR_BRIGHTNESS) - self._ads_hub.write_by_name(self.ads_var_enable, True, + self._ads_hub.write_by_name(self._ads_var, True, self._ads_hub.PLCTYPE_BOOL) - if self.ads_var_brightness is not None and brightness is not None: - self._ads_hub.write_by_name(self.ads_var_brightness, brightness, + if self._ads_var_brightness is not None and brightness is not None: + self._ads_hub.write_by_name(self._ads_var_brightness, brightness, self._ads_hub.PLCTYPE_UINT) def turn_off(self, **kwargs): """Turn the light off.""" - self._ads_hub.write_by_name(self.ads_var_enable, False, + self._ads_hub.write_by_name(self._ads_var, False, self._ads_hub.PLCTYPE_BOOL) diff --git a/homeassistant/components/ads/sensor.py b/homeassistant/components/ads/sensor.py index 118a669a7ad..e74b8753d4b 100644 --- a/homeassistant/components/ads/sensor.py +++ b/homeassistant/components/ads/sensor.py @@ -7,9 +7,9 @@ from homeassistant.components import ads from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.entity import Entity -from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR +from . import CONF_ADS_FACTOR, CONF_ADS_TYPE, CONF_ADS_VAR, \ + AdsEntity, STATE_KEY_STATE _LOGGER = logging.getLogger(__name__) @@ -43,60 +43,31 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities([entity]) -class AdsSensor(Entity): +class AdsSensor(AdsEntity): """Representation of an ADS sensor entity.""" def __init__(self, ads_hub, ads_var, ads_type, name, unit_of_measurement, factor): """Initialize AdsSensor entity.""" - self._ads_hub = ads_hub - self._name = name - self._unique_id = ads_var - self._value = None + super().__init__(ads_hub, name, ads_var) self._unit_of_measurement = unit_of_measurement - self.ads_var = ads_var - self.ads_type = ads_type - self.factor = factor + self._ads_type = ads_type + self._factor = factor async def async_added_to_hass(self): """Register device notification.""" - def update(name, value): - """Handle device notifications.""" - _LOGGER.debug("Variable %s changed its value to %d", name, value) - - # If factor is set use it otherwise not - if self.factor is None: - self._value = value - else: - self._value = value / self.factor - self.schedule_update_ha_state() - - self.hass.async_add_job( - self._ads_hub.add_device_notification, - self.ads_var, self._ads_hub.ADS_TYPEMAP[self.ads_type], update - ) - - @property - def name(self): - """Return the name of the entity.""" - return self._name - - @property - def unique_id(self): - """Return an unique identifier for this entity.""" - return self._unique_id + await self.async_initialize_device( + self._ads_var, + self._ads_hub.ADS_TYPEMAP[self._ads_type], + STATE_KEY_STATE, + self._factor) @property def state(self): """Return the state of the device.""" - return self._value + return self._state_dict[STATE_KEY_STATE] @property def unit_of_measurement(self): """Return the unit of measurement.""" return self._unit_of_measurement - - @property - def should_poll(self): - """Return False because entity pushes its state.""" - return False diff --git a/homeassistant/components/ads/switch.py b/homeassistant/components/ads/switch.py index 3d2189d2ede..0dfbeb811a0 100644 --- a/homeassistant/components/ads/switch.py +++ b/homeassistant/components/ads/switch.py @@ -1,16 +1,13 @@ """Support for ADS switch platform.""" import logging -import asyncio -import async_timeout import voluptuous as vol -from homeassistant.components.switch import PLATFORM_SCHEMA +from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA from homeassistant.const import CONF_NAME import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.entity import ToggleEntity -from . import CONF_ADS_VAR, DATA_ADS +from . import CONF_ADS_VAR, DATA_ADS, AdsEntity, STATE_KEY_STATE _LOGGER = logging.getLogger(__name__) @@ -34,74 +31,25 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities([AdsSwitch(ads_hub, name, ads_var)]) -class AdsSwitch(ToggleEntity): +class AdsSwitch(AdsEntity, SwitchDevice): """Representation of an ADS switch device.""" - def __init__(self, ads_hub, name, ads_var): - """Initialize the AdsSwitch entity.""" - self._ads_hub = ads_hub - self._on_state = None - self._name = name - self._unique_id = ads_var - self.ads_var = ads_var - self._event = None - async def async_added_to_hass(self): """Register device notification.""" - def update(name, value): - """Handle device notification.""" - _LOGGER.debug("Variable %s changed its value to %d", name, value) - self._on_state = value - asyncio.run_coroutine_threadsafe(async_event_set(), self.hass.loop) - self.schedule_update_ha_state() - - async def async_event_set(): - """Set event in async context.""" - self._event.set() - - self._event = asyncio.Event() - - await self.hass.async_add_executor_job( - self._ads_hub.add_device_notification, - self.ads_var, self._ads_hub.PLCTYPE_BOOL, update) - try: - with async_timeout.timeout(10): - await self._event.wait() - except asyncio.TimeoutError: - _LOGGER.debug('Variable %s: Timeout during first update', - self.ads_var) + await self.async_initialize_device(self._ads_var, + self._ads_hub.PLCTYPE_BOOL) @property def is_on(self): - """Return if the switch is turned on.""" - return self._on_state - - @property - def name(self): - """Return the name of the entity.""" - return self._name - - @property - def unique_id(self): - """Return an unique identifier for this entity.""" - return self._unique_id - - @property - def should_poll(self): - """Return False because entity pushes its state to HA.""" - return False - - @property - def available(self): - """Return False if state has not been updated yet.""" - return self._on_state is not None + """Return True if the entity is on.""" + return self._state_dict[STATE_KEY_STATE] def turn_on(self, **kwargs): """Turn the switch on.""" self._ads_hub.write_by_name( - self.ads_var, True, self._ads_hub.PLCTYPE_BOOL) + self._ads_var, True, self._ads_hub.PLCTYPE_BOOL) def turn_off(self, **kwargs): """Turn the switch off.""" self._ads_hub.write_by_name( - self.ads_var, False, self._ads_hub.PLCTYPE_BOOL) + self._ads_var, False, self._ads_hub.PLCTYPE_BOOL) From 7bd8c0d39a2ba847a8e3413896b42b21fc63c915 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Sun, 31 Mar 2019 21:30:45 -0700 Subject: [PATCH 017/167] Add new mobile_app webhook command: get_zones (#22604) ## Description: Adds a new `mobile_app` webhook command, `get_zones`, which just returns all zones. ## Checklist: - [x] The code change is tested and works locally. - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass** - [x] There is no commented out code in this PR. --- homeassistant/components/mobile_app/const.py | 5 +-- .../components/mobile_app/helpers.py | 5 +-- .../components/mobile_app/webhook.py | 32 +++++++++++++------ homeassistant/components/zone/config_flow.py | 2 +- tests/components/mobile_app/test_webhook.py | 26 +++++++++++++++ 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/mobile_app/const.py b/homeassistant/components/mobile_app/const.py index 3aa4626da29..38897056c11 100644 --- a/homeassistant/components/mobile_app/const.py +++ b/homeassistant/components/mobile_app/const.py @@ -65,6 +65,7 @@ ERR_SENSOR_DUPLICATE_UNIQUE_ID = 'duplicate_unique_id' WEBHOOK_TYPE_CALL_SERVICE = 'call_service' WEBHOOK_TYPE_FIRE_EVENT = 'fire_event' +WEBHOOK_TYPE_GET_ZONES = 'get_zones' WEBHOOK_TYPE_REGISTER_SENSOR = 'register_sensor' WEBHOOK_TYPE_RENDER_TEMPLATE = 'render_template' WEBHOOK_TYPE_UPDATE_LOCATION = 'update_location' @@ -72,8 +73,8 @@ WEBHOOK_TYPE_UPDATE_REGISTRATION = 'update_registration' WEBHOOK_TYPE_UPDATE_SENSOR_STATES = 'update_sensor_states' WEBHOOK_TYPES = [WEBHOOK_TYPE_CALL_SERVICE, WEBHOOK_TYPE_FIRE_EVENT, - WEBHOOK_TYPE_REGISTER_SENSOR, WEBHOOK_TYPE_RENDER_TEMPLATE, - WEBHOOK_TYPE_UPDATE_LOCATION, + WEBHOOK_TYPE_GET_ZONES, WEBHOOK_TYPE_REGISTER_SENSOR, + WEBHOOK_TYPE_RENDER_TEMPLATE, WEBHOOK_TYPE_UPDATE_LOCATION, WEBHOOK_TYPE_UPDATE_REGISTRATION, WEBHOOK_TYPE_UPDATE_SENSOR_STATES] diff --git a/homeassistant/components/mobile_app/helpers.py b/homeassistant/components/mobile_app/helpers.py index 60bd8b4e1d6..ee593588ef8 100644 --- a/homeassistant/components/mobile_app/helpers.py +++ b/homeassistant/components/mobile_app/helpers.py @@ -6,6 +6,7 @@ from typing import Callable, Dict, Tuple from aiohttp.web import json_response, Response from homeassistant.core import Context +from homeassistant.helpers.json import JSONEncoder from homeassistant.helpers.typing import HomeAssistantType from .const import (ATTR_APP_DATA, ATTR_APP_ID, ATTR_APP_NAME, @@ -133,9 +134,9 @@ def savable_state(hass: HomeAssistantType) -> Dict: def webhook_response(data, *, registration: Dict, status: int = 200, headers: Dict = None) -> Response: """Return a encrypted response if registration supports it.""" - data = json.dumps(data) + data = json.dumps(data, cls=JSONEncoder) - if CONF_SECRET in registration: + if registration[ATTR_SUPPORTS_ENCRYPTION]: keylen, encrypt = setup_encrypt() key = registration[CONF_SECRET].encode("utf-8") diff --git a/homeassistant/components/mobile_app/webhook.py b/homeassistant/components/mobile_app/webhook.py index aafa6046d11..71c6d0d6673 100644 --- a/homeassistant/components/mobile_app/webhook.py +++ b/homeassistant/components/mobile_app/webhook.py @@ -9,6 +9,8 @@ from homeassistant.components.device_tracker import (ATTR_ATTRIBUTES, DOMAIN as DT_DOMAIN, SERVICE_SEE as DT_SEE) +from homeassistant.components.zone.const import DOMAIN as ZONE_DOMAIN + from homeassistant.const import (ATTR_DOMAIN, ATTR_SERVICE, ATTR_SERVICE_DATA, CONF_WEBHOOK_ID, HTTP_BAD_REQUEST, HTTP_CREATED) @@ -33,9 +35,10 @@ from .const import (ATTR_ALTITUDE, ATTR_BATTERY, ATTR_COURSE, ATTR_DEVICE_ID, DATA_STORE, DOMAIN, ERR_ENCRYPTION_REQUIRED, ERR_SENSOR_DUPLICATE_UNIQUE_ID, ERR_SENSOR_NOT_REGISTERED, SIGNAL_SENSOR_UPDATE, WEBHOOK_PAYLOAD_SCHEMA, - WEBHOOK_SCHEMAS, WEBHOOK_TYPE_CALL_SERVICE, - WEBHOOK_TYPE_FIRE_EVENT, WEBHOOK_TYPE_REGISTER_SENSOR, - WEBHOOK_TYPE_RENDER_TEMPLATE, WEBHOOK_TYPE_UPDATE_LOCATION, + WEBHOOK_SCHEMAS, WEBHOOK_TYPES, WEBHOOK_TYPE_CALL_SERVICE, + WEBHOOK_TYPE_FIRE_EVENT, WEBHOOK_TYPE_GET_ZONES, + WEBHOOK_TYPE_REGISTER_SENSOR, WEBHOOK_TYPE_RENDER_TEMPLATE, + WEBHOOK_TYPE_UPDATE_LOCATION, WEBHOOK_TYPE_UPDATE_REGISTRATION, WEBHOOK_TYPE_UPDATE_SENSOR_STATES) @@ -87,16 +90,19 @@ async def handle_webhook(hass: HomeAssistantType, webhook_id: str, enc_data = req_data[ATTR_WEBHOOK_ENCRYPTED_DATA] webhook_payload = _decrypt_payload(registration[CONF_SECRET], enc_data) - if webhook_type not in WEBHOOK_SCHEMAS: + if webhook_type not in WEBHOOK_TYPES: _LOGGER.error('Received invalid webhook type: %s', webhook_type) return empty_okay_response() - try: - data = WEBHOOK_SCHEMAS[webhook_type](webhook_payload) - except vol.Invalid as ex: - err = vol.humanize.humanize_error(webhook_payload, ex) - _LOGGER.error('Received invalid webhook payload: %s', err) - return empty_okay_response(headers=headers) + data = webhook_payload + + if webhook_type in WEBHOOK_SCHEMAS: + try: + data = WEBHOOK_SCHEMAS[webhook_type](webhook_payload) + except vol.Invalid as ex: + err = vol.humanize.humanize_error(webhook_payload, ex) + _LOGGER.error('Received invalid webhook payload: %s', err) + return empty_okay_response(headers=headers) context = registration_context(registration) @@ -261,3 +267,9 @@ async def handle_webhook(hass: HomeAssistantType, webhook_id: str, return webhook_response(resp, registration=registration, headers=headers) + + if webhook_type == WEBHOOK_TYPE_GET_ZONES: + zones = (hass.states.get(entity_id) for entity_id + in sorted(hass.states.async_entity_ids(ZONE_DOMAIN))) + return webhook_response(list(zones), registration=registration, + headers=headers) diff --git a/homeassistant/components/zone/config_flow.py b/homeassistant/components/zone/config_flow.py index bf221a828ad..a7b968676d6 100644 --- a/homeassistant/components/zone/config_flow.py +++ b/homeassistant/components/zone/config_flow.py @@ -14,7 +14,7 @@ from .const import CONF_PASSIVE, DOMAIN, HOME_ZONE @callback def configured_zones(hass): - """Return a set of the configured hosts.""" + """Return a set of the configured zones.""" return set((slugify(entry.data[CONF_NAME])) for entry in hass.config_entries.async_entries(DOMAIN)) diff --git a/tests/components/mobile_app/test_webhook.py b/tests/components/mobile_app/test_webhook.py index a70e8ba1275..ad19a70a806 100644 --- a/tests/components/mobile_app/test_webhook.py +++ b/tests/components/mobile_app/test_webhook.py @@ -4,8 +4,10 @@ import logging import pytest from homeassistant.components.mobile_app.const import CONF_SECRET +from homeassistant.components.zone import DOMAIN as ZONE_DOMAIN from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.core import callback +from homeassistant.setup import async_setup_component from tests.common import async_mock_service @@ -100,6 +102,30 @@ async def test_webhook_update_registration(webhook_client, hass_client): # noqa assert CONF_SECRET not in update_json +async def test_webhook_handle_get_zones(hass, create_registrations, # noqa: F401, F811, E501 + webhook_client): # noqa: F811 + """Test that we can get zones properly.""" + await async_setup_component(hass, ZONE_DOMAIN, { + ZONE_DOMAIN: { + 'name': 'test', + 'latitude': 32.880837, + 'longitude': -117.237561, + 'radius': 250, + } + }) + + resp = await webhook_client.post( + '/api/webhook/{}'.format(create_registrations[1]['webhook_id']), + json={'type': 'get_zones'} + ) + + assert resp.status == 200 + + json = await resp.json() + assert len(json) == 1 + assert json[0]['entity_id'] == 'zone.home' + + async def test_webhook_returns_error_incorrect_json(webhook_client, # noqa: F401, F811, E501 create_registrations, # noqa: F401, F811, E501 caplog): # noqa: E501 F811 From a61181b10cca2f6517dac74f0f13465f1811afec Mon Sep 17 00:00:00 2001 From: N1nja98 <47512532+N1nja98@users.noreply.github.com> Date: Mon, 1 Apr 2019 01:27:47 -0500 Subject: [PATCH 018/167] Fixed brightness reducing after each light change (#22606) self._brightness max is 255 and hsv brightness max is 100. Assigning 255 based brightness value directly with 100 based hsv reduces brightness eventually to zero. --- homeassistant/components/zengge/light.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/zengge/light.py b/homeassistant/components/zengge/light.py index b283b8611dc..69ca3da0af9 100644 --- a/homeassistant/components/zengge/light.py +++ b/homeassistant/components/zengge/light.py @@ -157,6 +157,6 @@ class ZenggeLight(Light): rgb = self._bulb.get_colour() hsv = color_util.color_RGB_to_hsv(*rgb) self._hs_color = hsv[:2] - self._brightness = hsv[2] + self._brightness = (hsv[2] / 100) * 255 self._white = self._bulb.get_white() self._state = self._bulb.get_on() From 282fd225c9d621b773f289dc7acfc30ebd9639df Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Mon, 1 Apr 2019 08:47:29 +0200 Subject: [PATCH 019/167] Add netgear_lte connection sensors (#22558) --- homeassistant/components/netgear_lte/__init__.py | 2 +- homeassistant/components/netgear_lte/sensor.py | 11 +++++++++++ .../components/netgear_lte/sensor_types.py | 13 +++++++++++++ requirements_all.txt | 2 +- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/netgear_lte/__init__.py b/homeassistant/components/netgear_lte/__init__.py index a259a361be4..c611c65797d 100644 --- a/homeassistant/components/netgear_lte/__init__.py +++ b/homeassistant/components/netgear_lte/__init__.py @@ -20,7 +20,7 @@ from homeassistant.helpers.event import async_track_time_interval from . import sensor_types -REQUIREMENTS = ['eternalegypt==0.0.5'] +REQUIREMENTS = ['eternalegypt==0.0.6'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/netgear_lte/sensor.py b/homeassistant/components/netgear_lte/sensor.py index 42b0ddfa054..8141444bfc4 100644 --- a/homeassistant/components/netgear_lte/sensor.py +++ b/homeassistant/components/netgear_lte/sensor.py @@ -36,6 +36,8 @@ async def async_setup_platform( sensors.append(SMSSensor(modem_data, sensor_type)) elif sensor_type == SENSOR_USAGE: sensors.append(UsageSensor(modem_data, sensor_type)) + else: + sensors.append(GenericSensor(modem_data, sensor_type)) async_add_entities(sensors) @@ -106,3 +108,12 @@ class UsageSensor(LTESensor): def state(self): """Return the state of the sensor.""" return round(self.modem_data.data.usage / 1024**2, 1) + + +class GenericSensor(LTESensor): + """Sensor entity with raw state.""" + + @property + def state(self): + """Return the state of the sensor.""" + return getattr(self.modem_data.data, self.sensor_type) diff --git a/homeassistant/components/netgear_lte/sensor_types.py b/homeassistant/components/netgear_lte/sensor_types.py index 673f929d9ad..5a56404abda 100644 --- a/homeassistant/components/netgear_lte/sensor_types.py +++ b/homeassistant/components/netgear_lte/sensor_types.py @@ -6,6 +6,19 @@ SENSOR_USAGE = 'usage' SENSOR_UNITS = { SENSOR_SMS: 'unread', SENSOR_USAGE: 'MiB', + 'radio_quality': '%', + 'rx_level': 'dBm', + 'tx_level': 'dBm', + 'upstream': None, + 'wire_connected': None, + 'mobile_connected': None, + 'connection_text': None, + 'connection_type': None, + 'current_ps_service_type': None, + 'register_network_display': None, + 'roaming': None, + 'current_band': None, + 'cell_id': None, } ALL = list(SENSOR_UNITS) diff --git a/requirements_all.txt b/requirements_all.txt index e3cc4a34954..ef42a58e97c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -407,7 +407,7 @@ ephem==3.7.6.0 epson-projector==0.1.3 # homeassistant.components.netgear_lte -eternalegypt==0.0.5 +eternalegypt==0.0.6 # homeassistant.components.keyboard_remote # evdev==0.6.1 From c96804954cb4b6ecad77005b9194f236a16b79f6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 1 Apr 2019 01:22:51 -0700 Subject: [PATCH 020/167] Only allow admins to enable remote connection (#22609) * Only allow admins to enable remote connection * Protect WS API * Lint --- homeassistant/components/cloud/__init__.py | 9 ++++---- homeassistant/components/cloud/http_api.py | 2 ++ tests/components/cloud/test_init.py | 26 +++++++++++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/cloud/__init__.py b/homeassistant/components/cloud/__init__.py index 76a768385f8..fca5b292033 100644 --- a/homeassistant/components/cloud/__init__.py +++ b/homeassistant/components/cloud/__init__.py @@ -187,10 +187,11 @@ async def async_setup(hass, config): await cloud.remote.disconnect() await prefs.async_update(remote_enabled=False) - hass.services.async_register( - DOMAIN, SERVICE_REMOTE_CONNECT, _service_handler) - hass.services.async_register( - DOMAIN, SERVICE_REMOTE_DISCONNECT, _service_handler) + empty_schema = vol.Schema({}) + hass.helpers.service.async_register_admin_service( + DOMAIN, SERVICE_REMOTE_CONNECT, _service_handler, empty_schema) + hass.helpers.service.async_register_admin_service( + DOMAIN, SERVICE_REMOTE_DISCONNECT, _service_handler, empty_schema) await http_api.async_setup(hass) hass.async_create_task(hass.helpers.discovery.async_load_platform( diff --git a/homeassistant/components/cloud/http_api.py b/homeassistant/components/cloud/http_api.py index 212bdfb4bf8..d997d98d06e 100644 --- a/homeassistant/components/cloud/http_api.py +++ b/homeassistant/components/cloud/http_api.py @@ -422,6 +422,7 @@ def _account_data(cloud): } +@websocket_api.require_admin @_require_cloud_login @websocket_api.async_response @_ws_handle_cloud_errors @@ -436,6 +437,7 @@ async def websocket_remote_connect(hass, connection, msg): connection.send_result(msg['id'], _account_data(cloud)) +@websocket_api.require_admin @_require_cloud_login @websocket_api.async_response @_ws_handle_cloud_errors diff --git a/tests/components/cloud/test_init.py b/tests/components/cloud/test_init.py index 0de395c8bbc..ea611c29df1 100644 --- a/tests/components/cloud/test_init.py +++ b/tests/components/cloud/test_init.py @@ -1,6 +1,10 @@ """Test the cloud component.""" from unittest.mock import patch +import pytest + +from homeassistant.core import Context +from homeassistant.exceptions import Unauthorized from homeassistant.auth.const import GROUP_ID_ADMIN from homeassistant.components import cloud from homeassistant.components.cloud.const import DOMAIN @@ -34,7 +38,7 @@ async def test_constructor_loads_info_from_config(hass): assert cl.relayer == 'test-relayer' -async def test_remote_services(hass, mock_cloud_fixture): +async def test_remote_services(hass, mock_cloud_fixture, hass_read_only_user): """Setup cloud component and test services.""" cloud = hass.data[DOMAIN] @@ -58,6 +62,26 @@ async def test_remote_services(hass, mock_cloud_fixture): assert mock_disconnect.called assert not cloud.client.remote_autostart + # Test admin access required + non_admin_context = Context(user_id=hass_read_only_user.id) + + with patch( + "hass_nabucasa.remote.RemoteUI.connect", return_value=mock_coro() + ) as mock_connect, pytest.raises(Unauthorized): + await hass.services.async_call(DOMAIN, "remote_connect", blocking=True, + context=non_admin_context) + + assert mock_connect.called is False + + with patch( + "hass_nabucasa.remote.RemoteUI.disconnect", return_value=mock_coro() + ) as mock_disconnect, pytest.raises(Unauthorized): + await hass.services.async_call( + DOMAIN, "remote_disconnect", blocking=True, + context=non_admin_context) + + assert mock_disconnect.called is False + async def test_startup_shutdown_events(hass, mock_cloud_fixture): """Test if the cloud will start on startup event.""" From 42e3e878dfb43142c89046dc51ee939e32571621 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 1 Apr 2019 05:07:12 -0700 Subject: [PATCH 021/167] Cloudhooks for webhook config flows (#22611) --- .../components/dialogflow/__init__.py | 5 ++ homeassistant/components/geofency/__init__.py | 5 ++ .../components/gpslogger/__init__.py | 5 ++ homeassistant/components/ifttt/__init__.py | 5 ++ homeassistant/components/locative/__init__.py | 6 ++- homeassistant/components/mailgun/__init__.py | 5 ++ homeassistant/components/twilio/__init__.py | 5 ++ homeassistant/helpers/config_entry_flow.py | 26 ++++++++-- tests/helpers/test_config_entry_flow.py | 52 ++++++++++++++++++- 9 files changed, 108 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/dialogflow/__init__.py b/homeassistant/components/dialogflow/__init__.py index 210aebe80d5..1536fe3d236 100644 --- a/homeassistant/components/dialogflow/__init__.py +++ b/homeassistant/components/dialogflow/__init__.py @@ -79,6 +79,11 @@ async def async_unload_entry(hass, entry): hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID]) return True + +# pylint: disable=invalid-name +async_remove_entry = config_entry_flow.webhook_async_remove_entry + + config_entry_flow.register_webhook_flow( DOMAIN, 'Dialogflow Webhook', diff --git a/homeassistant/components/geofency/__init__.py b/homeassistant/components/geofency/__init__.py index f27798e9e0d..88b72f02cc2 100644 --- a/homeassistant/components/geofency/__init__.py +++ b/homeassistant/components/geofency/__init__.py @@ -133,6 +133,11 @@ async def async_unload_entry(hass, entry): await hass.config_entries.async_forward_entry_unload(entry, DEVICE_TRACKER) return True + +# pylint: disable=invalid-name +async_remove_entry = config_entry_flow.webhook_async_remove_entry + + config_entry_flow.register_webhook_flow( DOMAIN, 'Geofency Webhook', diff --git a/homeassistant/components/gpslogger/__init__.py b/homeassistant/components/gpslogger/__init__.py index 12da63d8ebb..6bc9d11a68e 100644 --- a/homeassistant/components/gpslogger/__init__.py +++ b/homeassistant/components/gpslogger/__init__.py @@ -104,6 +104,11 @@ async def async_unload_entry(hass, entry): await hass.config_entries.async_forward_entry_unload(entry, DEVICE_TRACKER) return True + +# pylint: disable=invalid-name +async_remove_entry = config_entry_flow.webhook_async_remove_entry + + config_entry_flow.register_webhook_flow( DOMAIN, 'GPSLogger Webhook', diff --git a/homeassistant/components/ifttt/__init__.py b/homeassistant/components/ifttt/__init__.py index 4ab361d41eb..bad3984ea5b 100644 --- a/homeassistant/components/ifttt/__init__.py +++ b/homeassistant/components/ifttt/__init__.py @@ -108,6 +108,11 @@ async def async_unload_entry(hass, entry): hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID]) return True + +# pylint: disable=invalid-name +async_remove_entry = config_entry_flow.webhook_async_remove_entry + + config_entry_flow.register_webhook_flow( DOMAIN, 'IFTTT Webhook', diff --git a/homeassistant/components/locative/__init__.py b/homeassistant/components/locative/__init__.py index e6a5b56ecda..335ae4cfe1e 100644 --- a/homeassistant/components/locative/__init__.py +++ b/homeassistant/components/locative/__init__.py @@ -141,10 +141,14 @@ async def async_setup_entry(hass, entry): async def async_unload_entry(hass, entry): """Unload a config entry.""" hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID]) - await hass.config_entries.async_forward_entry_unload(entry, DEVICE_TRACKER) return True + +# pylint: disable=invalid-name +async_remove_entry = config_entry_flow.webhook_async_remove_entry + + config_entry_flow.register_webhook_flow( DOMAIN, 'Locative Webhook', diff --git a/homeassistant/components/mailgun/__init__.py b/homeassistant/components/mailgun/__init__.py index 3903bd14e25..2a941d8bf50 100644 --- a/homeassistant/components/mailgun/__init__.py +++ b/homeassistant/components/mailgun/__init__.py @@ -88,6 +88,11 @@ async def async_unload_entry(hass, entry): hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID]) return True + +# pylint: disable=invalid-name +async_remove_entry = config_entry_flow.webhook_async_remove_entry + + config_entry_flow.register_webhook_flow( DOMAIN, 'Mailgun Webhook', diff --git a/homeassistant/components/twilio/__init__.py b/homeassistant/components/twilio/__init__.py index ce8c272165f..e7ba06a05f7 100644 --- a/homeassistant/components/twilio/__init__.py +++ b/homeassistant/components/twilio/__init__.py @@ -60,6 +60,11 @@ async def async_unload_entry(hass, entry): hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID]) return True + +# pylint: disable=invalid-name +async_remove_entry = config_entry_flow.webhook_async_remove_entry + + config_entry_flow.register_webhook_flow( DOMAIN, 'Twilio Webhook', diff --git a/homeassistant/helpers/config_entry_flow.py b/homeassistant/helpers/config_entry_flow.py index 8f5705bc67a..6d200a39c85 100644 --- a/homeassistant/helpers/config_entry_flow.py +++ b/homeassistant/helpers/config_entry_flow.py @@ -118,15 +118,35 @@ class WebhookFlowHandler(config_entries.ConfigFlow): ) webhook_id = self.hass.components.webhook.async_generate_id() - webhook_url = \ - self.hass.components.webhook.async_generate_url(webhook_id) + + if self.hass.components.cloud.async_active_subscription(): + webhook_url = \ + await self.hass.components.cloud.async_create_cloudhook( + webhook_id + ) + cloudhook = True + else: + webhook_url = \ + self.hass.components.webhook.async_generate_url(webhook_id) + cloudhook = False self._description_placeholder['webhook_url'] = webhook_url return self.async_create_entry( title=self._title, data={ - 'webhook_id': webhook_id + 'webhook_id': webhook_id, + 'cloudhook': cloudhook, }, description_placeholders=self._description_placeholder ) + + +async def webhook_async_remove_entry(hass, entry) -> None: + """Remove a webhook config entry.""" + if (not entry.data.get('cloudhook') or + 'cloud' not in hass.config.components): + return + + await hass.components.cloud.async_delete_cloudhook( + entry.data['webhook_id']) diff --git a/tests/helpers/test_config_entry_flow.py b/tests/helpers/test_config_entry_flow.py index 846c2cd1560..c198325b350 100644 --- a/tests/helpers/test_config_entry_flow.py +++ b/tests/helpers/test_config_entry_flow.py @@ -3,9 +3,9 @@ from unittest.mock import patch, Mock import pytest -from homeassistant import config_entries, data_entry_flow, loader +from homeassistant import config_entries, data_entry_flow, loader, setup from homeassistant.helpers import config_entry_flow -from tests.common import MockConfigEntry, MockModule +from tests.common import MockConfigEntry, MockModule, mock_coro @pytest.fixture @@ -193,3 +193,51 @@ async def test_webhook_config_flow_registers_webhook(hass, webhook_flow_conf): assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result['data']['webhook_id'] is not None + + +async def test_webhook_create_cloudhook(hass, webhook_flow_conf): + """Test only a single entry is allowed.""" + assert await setup.async_setup_component(hass, 'cloud', {}) + + async_setup_entry = Mock(return_value=mock_coro(True)) + async_unload_entry = Mock(return_value=mock_coro(True)) + + loader.set_component(hass, 'test_single', MockModule( + 'test_single', + async_setup_entry=async_setup_entry, + async_unload_entry=async_unload_entry, + async_remove_entry=config_entry_flow.webhook_async_remove_entry, + )) + + result = await hass.config_entries.flow.async_init( + 'test_single', context={'source': config_entries.SOURCE_USER}) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + + coro = mock_coro({ + 'cloudhook_url': 'https://example.com' + }) + + with patch('hass_nabucasa.cloudhooks.Cloudhooks.async_create', + return_value=coro) as mock_create, \ + patch('homeassistant.components.cloud.async_active_subscription', + return_value=True), \ + patch('homeassistant.components.cloud.async_is_logged_in', + return_value=True): + + result = await hass.config_entries.flow.async_configure( + result['flow_id'], {}) + + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['description_placeholders']['webhook_url'] == \ + 'https://example.com' + assert len(mock_create.mock_calls) == 1 + assert len(async_setup_entry.mock_calls) == 1 + + with patch('hass_nabucasa.cloudhooks.Cloudhooks.async_delete', + return_value=coro) as mock_delete: + + result = \ + await hass.config_entries.async_remove(result['result'].entry_id) + + assert len(mock_delete.mock_calls) == 1 + assert result['require_restart'] is False From 6829ecad9d044311dca8f1c02ebbad3e04e00320 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 1 Apr 2019 14:16:16 +0200 Subject: [PATCH 022/167] Hass.io ingress (#22505) * Fix API stream of snapshot / Add ingress * fix lint * Fix stream handling * Cleanup api handling * fix typing * Set proxy header * Use header constant * Enable the ingress setup * fix lint * Fix name * Fix tests * fix lint * forward params * Add tests for ingress * Cleanup cookie handling with aiohttp 3.5 * Add more tests * Fix tests * Fix lint * Fix header handling for steam * forward header too * fix lint * fix flake --- homeassistant/components/hassio/__init__.py | 4 + homeassistant/components/hassio/const.py | 7 +- homeassistant/components/hassio/http.py | 79 +++++--- homeassistant/components/hassio/ingress.py | 210 ++++++++++++++++++++ tests/components/hassio/test_http.py | 80 +++----- tests/components/hassio/test_ingress.py | 162 +++++++++++++++ tests/components/hassio/test_init.py | 2 +- tests/test_util/aiohttp.py | 2 +- 8 files changed, 458 insertions(+), 88 deletions(-) create mode 100644 homeassistant/components/hassio/ingress.py create mode 100644 tests/components/hassio/test_ingress.py diff --git a/homeassistant/components/hassio/__init__.py b/homeassistant/components/hassio/__init__.py index 073974200a0..e8d04b1596d 100644 --- a/homeassistant/components/hassio/__init__.py +++ b/homeassistant/components/hassio/__init__.py @@ -20,6 +20,7 @@ from .auth import async_setup_auth from .discovery import async_setup_discovery from .handler import HassIO, HassioAPIError from .http import HassIOView +from .ingress import async_setup_ingress _LOGGER = logging.getLogger(__name__) @@ -270,4 +271,7 @@ async def async_setup(hass, config): # Init auth Hass.io feature async_setup_auth(hass) + # Init ingress Hass.io feature + async_setup_ingress(hass, host) + return True diff --git a/homeassistant/components/hassio/const.py b/homeassistant/components/hassio/const.py index 964f94bfb41..e4132562c31 100644 --- a/homeassistant/components/hassio/const.py +++ b/homeassistant/components/hassio/const.py @@ -9,6 +9,7 @@ ATTR_UUID = 'uuid' ATTR_USERNAME = 'username' ATTR_PASSWORD = 'password' -X_HASSIO = 'X-HASSIO-KEY' -X_HASS_USER_ID = 'X-HASS-USER-ID' -X_HASS_IS_ADMIN = 'X-HASS-IS-ADMIN' +X_HASSIO = 'X-Hassio-Key' +X_INGRESS_PATH = "X-Ingress-Path" +X_HASS_USER_ID = 'X-Hass-User-ID' +X_HASS_IS_ADMIN = 'X-Hass-Is-Admin' diff --git a/homeassistant/components/hassio/http.py b/homeassistant/components/hassio/http.py index 01ded9ca11d..7284004d72f 100644 --- a/homeassistant/components/hassio/http.py +++ b/homeassistant/components/hassio/http.py @@ -3,10 +3,11 @@ import asyncio import logging import os import re +from typing import Dict, Union import aiohttp from aiohttp import web -from aiohttp.hdrs import CONTENT_TYPE +from aiohttp.hdrs import CONTENT_TYPE, CONTENT_LENGTH from aiohttp.web_exceptions import HTTPBadGateway import async_timeout @@ -20,7 +21,8 @@ _LOGGER = logging.getLogger(__name__) NO_TIMEOUT = re.compile( r'^(?:' r'|homeassistant/update' - r'|host/update' + r'|hassos/update' + r'|hassos/update/cli' r'|supervisor/update' r'|addons/[^/]+/(?:update|install|rebuild)' r'|snapshots/.+/full' @@ -44,25 +46,26 @@ class HassIOView(HomeAssistantView): url = "/api/hassio/{path:.+}" requires_auth = False - def __init__(self, host, websession): + def __init__(self, host: str, websession: aiohttp.ClientSession): """Initialize a Hass.io base view.""" self._host = host self._websession = websession - async def _handle(self, request, path): + async def _handle( + self, request: web.Request, path: str + ) -> Union[web.Response, web.StreamResponse]: """Route data to Hass.io.""" if _need_auth(path) and not request[KEY_AUTHENTICATED]: return web.Response(status=401) - client = await self._command_proxy(path, request) - - data = await client.read() - return _create_response(client, data) + return await self._command_proxy(path, request) get = _handle post = _handle - async def _command_proxy(self, path, request): + async def _command_proxy( + self, path: str, request: web.Request + ) -> Union[web.Response, web.StreamResponse]: """Return a client request with proxy origin for Hass.io supervisor. This method is a coroutine. @@ -71,29 +74,38 @@ class HassIOView(HomeAssistantView): hass = request.app['hass'] data = None - headers = { - X_HASSIO: os.environ.get('HASSIO_TOKEN', ""), - } - user = request.get('hass_user') - if user is not None: - headers[X_HASS_USER_ID] = request['hass_user'].id - headers[X_HASS_IS_ADMIN] = str(int(request['hass_user'].is_admin)) + headers = _init_header(request) try: with async_timeout.timeout(10, loop=hass.loop): data = await request.read() - if data: - headers[CONTENT_TYPE] = request.content_type - else: - data = None method = getattr(self._websession, request.method.lower()) client = await method( "http://{}/{}".format(self._host, path), data=data, headers=headers, timeout=read_timeout ) + print(client.headers) - return client + # Simple request + if int(client.headers.get(CONTENT_LENGTH, 0)) < 4194000: + # Return Response + body = await client.read() + return web.Response( + content_type=client.content_type, + status=client.status, + body=body, + ) + + # Stream response + response = web.StreamResponse(status=client.status) + response.content_type = client.content_type + + await response.prepare(request) + async for data in client.content.iter_chunked(4096): + await response.write(data) + + return response except aiohttp.ClientError as err: _LOGGER.error("Client error on api %s request %s", path, err) @@ -104,23 +116,30 @@ class HassIOView(HomeAssistantView): raise HTTPBadGateway() -def _create_response(client, data): - """Convert a response from client request.""" - return web.Response( - body=data, - status=client.status, - content_type=client.content_type, - ) +def _init_header(request: web.Request) -> Dict[str, str]: + """Create initial header.""" + headers = { + X_HASSIO: os.environ.get('HASSIO_TOKEN', ""), + CONTENT_TYPE: request.content_type, + } + + # Add user data + user = request.get('hass_user') + if user is not None: + headers[X_HASS_USER_ID] = request['hass_user'].id + headers[X_HASS_IS_ADMIN] = str(int(request['hass_user'].is_admin)) + + return headers -def _get_timeout(path): +def _get_timeout(path: str) -> int: """Return timeout for a URL path.""" if NO_TIMEOUT.match(path): return 0 return 300 -def _need_auth(path): +def _need_auth(path: str) -> bool: """Return if a path need authentication.""" if NO_AUTH.match(path): return False diff --git a/homeassistant/components/hassio/ingress.py b/homeassistant/components/hassio/ingress.py new file mode 100644 index 00000000000..6c1ef389712 --- /dev/null +++ b/homeassistant/components/hassio/ingress.py @@ -0,0 +1,210 @@ +"""Hass.io Add-on ingress service.""" +import asyncio +from ipaddress import ip_address +import os +from typing import Dict, Union + +import aiohttp +from aiohttp import web +from aiohttp import hdrs +from aiohttp.web_exceptions import HTTPBadGateway +from multidict import CIMultiDict + +from homeassistant.core import callback +from homeassistant.components.http import HomeAssistantView +from homeassistant.helpers.typing import HomeAssistantType + +from .const import X_HASSIO, X_INGRESS_PATH + + +@callback +def async_setup_ingress(hass: HomeAssistantType, host: str): + """Auth setup.""" + websession = hass.helpers.aiohttp_client.async_get_clientsession() + + hassio_ingress = HassIOIngress(host, websession) + hass.http.register_view(hassio_ingress) + + +class HassIOIngress(HomeAssistantView): + """Hass.io view to handle base part.""" + + name = "api:hassio:ingress" + url = "/api/hassio_ingress/{addon}/{path:.+}" + requires_auth = False + + def __init__(self, host: str, websession: aiohttp.ClientSession): + """Initialize a Hass.io ingress view.""" + self._host = host + self._websession = websession + + def _create_url(self, addon: str, path: str) -> str: + """Create URL to service.""" + return "http://{}/addons/{}/web/{}".format(self._host, addon, path) + + async def _handle( + self, request: web.Request, addon: str, path: str + ) -> Union[web.Response, web.StreamResponse, web.WebSocketResponse]: + """Route data to Hass.io ingress service.""" + try: + # Websocket + if _is_websocket(request): + return await self._handle_websocket(request, addon, path) + + # Request + return await self._handle_request(request, addon, path) + + except aiohttp.ClientError: + pass + + raise HTTPBadGateway() from None + + get = _handle + post = _handle + put = _handle + delete = _handle + + async def _handle_websocket( + self, request: web.Request, addon: str, path: str + ) -> web.WebSocketResponse: + """Ingress route for websocket.""" + ws_server = web.WebSocketResponse() + await ws_server.prepare(request) + + url = self._create_url(addon, path) + source_header = _init_header(request, addon) + + # Start proxy + async with self._websession.ws_connect( + url, headers=source_header + ) as ws_client: + # Proxy requests + await asyncio.wait( + [ + _websocket_forward(ws_server, ws_client), + _websocket_forward(ws_client, ws_server), + ], + return_when=asyncio.FIRST_COMPLETED + ) + + return ws_server + + async def _handle_request( + self, request: web.Request, addon: str, path: str + ) -> Union[web.Response, web.StreamResponse]: + """Ingress route for request.""" + url = self._create_url(addon, path) + data = await request.read() + source_header = _init_header(request, addon) + + async with self._websession.request( + request.method, url, headers=source_header, + params=request.query, data=data, cookies=request.cookies + ) as result: + headers = _response_header(result) + + # Simple request + if hdrs.CONTENT_LENGTH in result.headers and \ + int(result.headers.get(hdrs.CONTENT_LENGTH, 0)) < 4194000: + # Return Response + body = await result.read() + return web.Response( + headers=headers, + status=result.status, + body=body + ) + + # Stream response + response = web.StreamResponse( + status=result.status, headers=headers) + response.content_type = result.content_type + + try: + await response.prepare(request) + async for data in result.content: + await response.write(data) + + except (aiohttp.ClientError, aiohttp.ClientPayloadError): + pass + + return response + + +def _init_header( + request: web.Request, addon: str +) -> Union[CIMultiDict, Dict[str, str]]: + """Create initial header.""" + headers = {} + + # filter flags + for name, value in request.headers.items(): + if name in (hdrs.CONTENT_LENGTH, hdrs.CONTENT_TYPE): + continue + headers[name] = value + + # Inject token / cleanup later on Supervisor + headers[X_HASSIO] = os.environ.get('HASSIO_TOKEN', "") + + # Ingress information + headers[X_INGRESS_PATH] = "/api/hassio_ingress/{}".format(addon) + + # Set X-Forwarded-For + forward_for = request.headers.get(hdrs.X_FORWARDED_FOR) + connected_ip = ip_address(request.transport.get_extra_info('peername')[0]) + if forward_for: + forward_for = "{}, {!s}".format(forward_for, connected_ip) + else: + forward_for = "{!s}".format(connected_ip) + headers[hdrs.X_FORWARDED_FOR] = forward_for + + # Set X-Forwarded-Host + forward_host = request.headers.get(hdrs.X_FORWARDED_HOST) + if not forward_host: + forward_host = request.host + headers[hdrs.X_FORWARDED_HOST] = forward_host + + # Set X-Forwarded-Proto + forward_proto = request.headers.get(hdrs.X_FORWARDED_PROTO) + if not forward_proto: + forward_proto = request.url.scheme + headers[hdrs.X_FORWARDED_PROTO] = forward_proto + + return headers + + +def _response_header(response: aiohttp.ClientResponse) -> Dict[str, str]: + """Create response header.""" + headers = {} + + for name, value in response.headers.items(): + if name in (hdrs.TRANSFER_ENCODING, hdrs.CONTENT_LENGTH, + hdrs.CONTENT_TYPE): + continue + headers[name] = value + + return headers + + +def _is_websocket(request: web.Request) -> bool: + """Return True if request is a websocket.""" + headers = request.headers + + if headers.get(hdrs.CONNECTION) == "Upgrade" and \ + headers.get(hdrs.UPGRADE) == "websocket": + return True + return False + + +async def _websocket_forward(ws_from, ws_to): + """Handle websocket message directly.""" + async for msg in ws_from: + if msg.type == aiohttp.WSMsgType.TEXT: + await ws_to.send_str(msg.data) + elif msg.type == aiohttp.WSMsgType.BINARY: + await ws_to.send_bytes(msg.data) + elif msg.type == aiohttp.WSMsgType.PING: + await ws_to.ping() + elif msg.type == aiohttp.WSMsgType.PONG: + await ws_to.pong() + elif ws_to.closed: + await ws_to.close(code=ws_to.close_code, message=msg.extra) diff --git a/tests/components/hassio/test_http.py b/tests/components/hassio/test_http.py index 3f58c6e697e..3a58048735b 100644 --- a/tests/components/hassio/test_http.py +++ b/tests/components/hassio/test_http.py @@ -1,29 +1,22 @@ """The tests for the hassio component.""" import asyncio -from unittest.mock import patch, Mock, MagicMock +from unittest.mock import patch import pytest from homeassistant.const import HTTP_HEADER_HA_AUTH -from tests.common import mock_coro from . import API_PASSWORD @asyncio.coroutine -def test_forward_request(hassio_client): +def test_forward_request(hassio_client, aioclient_mock): """Test fetching normal path.""" - response = MagicMock() - response.read.return_value = mock_coro('data') + aioclient_mock.post("http://127.0.0.1/beer", text="response") - with patch('homeassistant.components.hassio.HassIOView._command_proxy', - Mock(return_value=mock_coro(response))), \ - patch('homeassistant.components.hassio.http' - '._create_response') as mresp: - mresp.return_value = 'response' - resp = yield from hassio_client.post('/api/hassio/beer', headers={ - HTTP_HEADER_HA_AUTH: API_PASSWORD - }) + resp = yield from hassio_client.post('/api/hassio/beer', headers={ + HTTP_HEADER_HA_AUTH: API_PASSWORD + }) # Check we got right response assert resp.status == 200 @@ -31,8 +24,7 @@ def test_forward_request(hassio_client): assert body == 'response' # Check we forwarded command - assert len(mresp.mock_calls) == 1 - assert mresp.mock_calls[0][1] == (response, 'data') + assert len(aioclient_mock.mock_calls) == 1 @asyncio.coroutine @@ -55,18 +47,13 @@ def test_auth_required_forward_request(hassio_noauth_client, build_type): 'app/index.html', 'app/hassio-app.html', 'app/index.html', 'app/hassio-app.html', 'app/some-chunk.js', 'app/app.js', ]) -def test_forward_request_no_auth_for_panel(hassio_client, build_type): +def test_forward_request_no_auth_for_panel( + hassio_client, build_type, aioclient_mock): """Test no auth needed for .""" - response = MagicMock() - response.read.return_value = mock_coro('data') + aioclient_mock.get( + "http://127.0.0.1/{}".format(build_type), text="response") - with patch('homeassistant.components.hassio.HassIOView._command_proxy', - Mock(return_value=mock_coro(response))), \ - patch('homeassistant.components.hassio.http.' - '_create_response') as mresp: - mresp.return_value = 'response' - resp = yield from hassio_client.get( - '/api/hassio/{}'.format(build_type)) + resp = yield from hassio_client.get('/api/hassio/{}'.format(build_type)) # Check we got right response assert resp.status == 200 @@ -74,22 +61,16 @@ def test_forward_request_no_auth_for_panel(hassio_client, build_type): assert body == 'response' # Check we forwarded command - assert len(mresp.mock_calls) == 1 - assert mresp.mock_calls[0][1] == (response, 'data') + assert len(aioclient_mock.mock_calls) == 1 @asyncio.coroutine -def test_forward_request_no_auth_for_logo(hassio_client): +def test_forward_request_no_auth_for_logo(hassio_client, aioclient_mock): """Test no auth needed for .""" - response = MagicMock() - response.read.return_value = mock_coro('data') + aioclient_mock.get( + "http://127.0.0.1/addons/bl_b392/logo", text="response") - with patch('homeassistant.components.hassio.HassIOView._command_proxy', - Mock(return_value=mock_coro(response))), \ - patch('homeassistant.components.hassio.http.' - '_create_response') as mresp: - mresp.return_value = 'response' - resp = yield from hassio_client.get('/api/hassio/addons/bl_b392/logo') + resp = yield from hassio_client.get('/api/hassio/addons/bl_b392/logo') # Check we got right response assert resp.status == 200 @@ -97,24 +78,18 @@ def test_forward_request_no_auth_for_logo(hassio_client): assert body == 'response' # Check we forwarded command - assert len(mresp.mock_calls) == 1 - assert mresp.mock_calls[0][1] == (response, 'data') + assert len(aioclient_mock.mock_calls) == 1 @asyncio.coroutine -def test_forward_log_request(hassio_client): +def test_forward_log_request(hassio_client, aioclient_mock): """Test fetching normal log path doesn't remove ANSI color escape codes.""" - response = MagicMock() - response.read.return_value = mock_coro('data') + aioclient_mock.get( + "http://127.0.0.1/beer/logs", text="\033[32mresponse\033[0m") - with patch('homeassistant.components.hassio.HassIOView._command_proxy', - Mock(return_value=mock_coro(response))), \ - patch('homeassistant.components.hassio.http.' - '_create_response') as mresp: - mresp.return_value = '\033[32mresponse\033[0m' - resp = yield from hassio_client.get('/api/hassio/beer/logs', headers={ - HTTP_HEADER_HA_AUTH: API_PASSWORD - }) + resp = yield from hassio_client.get('/api/hassio/beer/logs', headers={ + HTTP_HEADER_HA_AUTH: API_PASSWORD + }) # Check we got right response assert resp.status == 200 @@ -122,8 +97,7 @@ def test_forward_log_request(hassio_client): assert body == '\033[32mresponse\033[0m' # Check we forwarded command - assert len(mresp.mock_calls) == 1 - assert mresp.mock_calls[0][1] == (response, 'data') + assert len(aioclient_mock.mock_calls) == 1 @asyncio.coroutine @@ -151,5 +125,5 @@ async def test_forwarding_user_info(hassio_client, hass_admin_user, assert len(aioclient_mock.mock_calls) == 1 req_headers = aioclient_mock.mock_calls[0][-1] - req_headers['X-HASS-USER-ID'] == hass_admin_user.id - req_headers['X-HASS-IS-ADMIN'] == '1' + req_headers['X-Hass-User-ID'] == hass_admin_user.id + req_headers['X-Hass-Is-Admin'] == '1' diff --git a/tests/components/hassio/test_ingress.py b/tests/components/hassio/test_ingress.py new file mode 100644 index 00000000000..4e071ba24fd --- /dev/null +++ b/tests/components/hassio/test_ingress.py @@ -0,0 +1,162 @@ +"""The tests for the hassio component.""" + +from aiohttp.hdrs import X_FORWARDED_FOR, X_FORWARDED_HOST, X_FORWARDED_PROTO +from aiohttp.client_exceptions import WSServerHandshakeError +import pytest + + +@pytest.mark.parametrize( + 'build_type', [ + ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5") + ]) +async def test_ingress_request_get( + hassio_client, build_type, aioclient_mock): + """Test no auth needed for .""" + aioclient_mock.get("http://127.0.0.1/addons/{}/web/{}".format( + build_type[0], build_type[1]), text="test") + + resp = await hassio_client.get( + '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), + headers={"X-Test-Header": "beer"} + ) + + # Check we got right response + assert resp.status == 200 + body = await resp.text() + assert body == "test" + + # Check we forwarded command + assert len(aioclient_mock.mock_calls) == 1 + assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456" + assert aioclient_mock.mock_calls[-1][3]["X-Ingress-Path"] == \ + "/api/hassio_ingress/{}".format(build_type[0]) + assert aioclient_mock.mock_calls[-1][3]["X-Test-Header"] == "beer" + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_FOR] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_HOST] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] + + +@pytest.mark.parametrize( + 'build_type', [ + ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5") + ]) +async def test_ingress_request_post( + hassio_client, build_type, aioclient_mock): + """Test no auth needed for .""" + aioclient_mock.post("http://127.0.0.1/addons/{}/web/{}".format( + build_type[0], build_type[1]), text="test") + + resp = await hassio_client.post( + '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), + headers={"X-Test-Header": "beer"} + ) + + # Check we got right response + assert resp.status == 200 + body = await resp.text() + assert body == "test" + + # Check we forwarded command + assert len(aioclient_mock.mock_calls) == 1 + assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456" + assert aioclient_mock.mock_calls[-1][3]["X-Ingress-Path"] == \ + "/api/hassio_ingress/{}".format(build_type[0]) + assert aioclient_mock.mock_calls[-1][3]["X-Test-Header"] == "beer" + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_FOR] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_HOST] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] + + +@pytest.mark.parametrize( + 'build_type', [ + ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5") + ]) +async def test_ingress_request_put( + hassio_client, build_type, aioclient_mock): + """Test no auth needed for .""" + aioclient_mock.put("http://127.0.0.1/addons/{}/web/{}".format( + build_type[0], build_type[1]), text="test") + + resp = await hassio_client.put( + '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), + headers={"X-Test-Header": "beer"} + ) + + # Check we got right response + assert resp.status == 200 + body = await resp.text() + assert body == "test" + + # Check we forwarded command + assert len(aioclient_mock.mock_calls) == 1 + assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456" + assert aioclient_mock.mock_calls[-1][3]["X-Ingress-Path"] == \ + "/api/hassio_ingress/{}".format(build_type[0]) + assert aioclient_mock.mock_calls[-1][3]["X-Test-Header"] == "beer" + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_FOR] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_HOST] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] + + +@pytest.mark.parametrize( + 'build_type', [ + ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5") + ]) +async def test_ingress_request_delete( + hassio_client, build_type, aioclient_mock): + """Test no auth needed for .""" + aioclient_mock.delete("http://127.0.0.1/addons/{}/web/{}".format( + build_type[0], build_type[1]), text="test") + + resp = await hassio_client.delete( + '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), + headers={"X-Test-Header": "beer"} + ) + + # Check we got right response + assert resp.status == 200 + body = await resp.text() + assert body == "test" + + # Check we forwarded command + assert len(aioclient_mock.mock_calls) == 1 + assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456" + assert aioclient_mock.mock_calls[-1][3]["X-Ingress-Path"] == \ + "/api/hassio_ingress/{}".format(build_type[0]) + assert aioclient_mock.mock_calls[-1][3]["X-Test-Header"] == "beer" + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_FOR] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_HOST] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] + + +@pytest.mark.parametrize( + 'build_type', [ + ("a3_vl", "test/beer/ws"), ("core", "ws.php"), + ("local", "panel/config/stream"), ("jk_921", "hulk") + ]) +async def test_ingress_websocket( + hassio_client, build_type, aioclient_mock): + """Test no auth needed for .""" + aioclient_mock.get("http://127.0.0.1/addons/{}/web/{}".format( + build_type[0], build_type[1])) + + # Ignore error because we can setup a full IO infrastructure + with pytest.raises(WSServerHandshakeError): + await hassio_client.ws_connect( + '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), + headers={"X-Test-Header": "beer"} + ) + + # Check we forwarded command + assert len(aioclient_mock.mock_calls) == 1 + assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456" + assert aioclient_mock.mock_calls[-1][3]["X-Ingress-Path"] == \ + "/api/hassio_ingress/{}".format(build_type[0]) + assert aioclient_mock.mock_calls[-1][3]["X-Test-Header"] == "beer" + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_FOR] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_HOST] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] diff --git a/tests/components/hassio/test_init.py b/tests/components/hassio/test_init.py index fc4661e7544..f1f148f8495 100644 --- a/tests/components/hassio/test_init.py +++ b/tests/components/hassio/test_init.py @@ -207,7 +207,7 @@ def test_setup_hassio_no_additional_data(hass, aioclient_mock): assert result assert aioclient_mock.call_count == 3 - assert aioclient_mock.mock_calls[-1][3]['X-HASSIO-KEY'] == "123456" + assert aioclient_mock.mock_calls[-1][3]['X-Hassio-Key'] == "123456" @asyncio.coroutine diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index 8b3b057bfc0..ab759f03058 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -102,7 +102,7 @@ class AiohttpClientMocker: async def match_request(self, method, url, *, data=None, auth=None, params=None, headers=None, allow_redirects=None, - timeout=None, json=None): + timeout=None, json=None, cookies=None): """Match a request against pre-registered requests.""" data = data or json url = URL(url) From de4d1f2c19de6a6eb2375aaf708b45f0c7133e25 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 1 Apr 2019 07:12:59 -0700 Subject: [PATCH 023/167] Config CircleCI workflow (#22590) * Add mypyrc to control typing check, add mypy to circle * Add translation upload circlci job --- .circleci/config.yml | 47 ++++++++++++++++++++++++++++++-------- README.rst | 6 +++-- mypyrc | 21 +++++++++++++++++ script/translations_upload | 3 ++- tox.ini | 2 +- 5 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 mypyrc diff --git a/.circleci/config.yml b/.circleci/config.yml index f9eb28bdf4a..b4f22601bb5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,7 +52,7 @@ commands: command: | python3 -m venv venv . venv/bin/activate - pip install -U pip + pip install -q -U pip <<# parameters.all >>pip install -q --progress-bar off -r requirements_all.txt -c homeassistant/package_constraints.txt<> <<# parameters.test >>pip install -q --progress-bar off -r requirements_test.txt -c homeassistant/package_constraints.txt<> <<# parameters.test_all >>pip install -q --progress-bar off -r requirements_test_all.txt -c homeassistant/package_constraints.txt<> @@ -68,28 +68,35 @@ commands: name: install command: | . venv/bin/activate - pip install --progress-bar off -e . + pip install -q --progress-bar off -e . jobs: static-check: executor: name: python - tag: 3.7-stretch + tag: 3.5.5-stretch steps: - checkout - docker-prereqs + - install-requirements: + python: 3.5.5-stretch + test: true - run: name: run static check command: | - python3 -m venv venv . venv/bin/activate - pip install -U pip - pip install --progress-bar off flake8 flake8 + - run: + name: run static type check + command: | + . venv/bin/activate + TYPING_FILES=$(cat mypyrc) + mypy $TYPING_FILES + - install - run: name: run gen_requirements_all @@ -114,7 +121,7 @@ jobs: executor: name: python tag: 3.7-stretch - parallelism: 3 + parallelism: 2 steps: - checkout @@ -154,7 +161,7 @@ jobs: executor: name: python tag: << parameters.python >> - parallelism: 3 + parallelism: 2 steps: - checkout @@ -172,7 +179,6 @@ jobs: if [ -z "$CODE_COVERAGE" ]; then CC_SWITCH=""; else CC_SWITCH="--cov --cov-report html:htmlcov"; fi pytest --timeout=9 --duration=10 --junitxml=test-reports/homeassistant/results.xml -qq -o junit_family=xunit2 -o junit_suite_name=homeassistant -o console_output_style=count -p no:sugar $CC_SWITCH -- ${TESTFILES} script/check_dirty - when: always - store_test_results: path: test-reports @@ -185,6 +191,23 @@ jobs: path: test-reports destination: test-reports + # This job use machine executor, e.g. classic CircleCI VM because we need both lokalise-cli and a Python runtime. + # Classic CircleCI included python 2.7.12 and python 3.5.2 managed by pyenv, the Python version may need change if + # CircleCI changed its VM in future. + upload-translations: + machine: true + + steps: + - checkout + + - run: + name: upload english translations + command: | + pyenv versions + pyenv global 3.5.2 + docker pull lokalise/lokalise-cli@sha256:2198814ebddfda56ee041a4b427521757dd57f75415ea9693696a64c550cef21 + script/translations_upload + workflows: version: 2 build: @@ -222,3 +245,9 @@ workflows: # - test: # name: test 3.8 # python: 3.8-rc-stretch + - upload-translations: + requires: + - static-check + filters: + branches: + only: dev diff --git a/README.rst b/README.rst index f231d6c5514..941a463fb37 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -Home Assistant |Build Status| |Coverage Status| |Chat Status| +Home Assistant |Build Status| |CI Status| |Coverage Status| |Chat Status| ================================================================================= Home Assistant is a home automation platform running on Python 3. It is able to track and control all devices at home and offer a platform for automating control. @@ -27,8 +27,10 @@ components `__ of our website for further help and information. -.. |Build Status| image:: https://travis-ci.org/home-assistant/home-assistant.svg?branch=master +.. |Build Status| image:: https://travis-ci.org/home-assistant/home-assistant.svg?branch=dev :target: https://travis-ci.org/home-assistant/home-assistant +.. |CI Status| image:: https://circleci.com/gh/home-assistant/home-assistant.svg?style=shield + :target: https://circleci.com/gh/home-assistant/home-assistant .. |Coverage Status| image:: https://img.shields.io/coveralls/home-assistant/home-assistant.svg :target: https://coveralls.io/r/home-assistant/home-assistant?branch=master .. |Chat Status| image:: https://img.shields.io/discord/330944238910963714.svg diff --git a/mypyrc b/mypyrc new file mode 100644 index 00000000000..7c73d12e381 --- /dev/null +++ b/mypyrc @@ -0,0 +1,21 @@ +homeassistant/*.py +homeassistant/auth/ +homeassistant/util/ +homeassistant/helpers/__init__.py +homeassistant/helpers/aiohttp_client.py +homeassistant/helpers/area_registry.py +homeassistant/helpers/condition.py +homeassistant/helpers/deprecation.py +homeassistant/helpers/dispatcher.py +homeassistant/helpers/entity_values.py +homeassistant/helpers/entityfilter.py +homeassistant/helpers/icon.py +homeassistant/helpers/intent.py +homeassistant/helpers/json.py +homeassistant/helpers/location.py +homeassistant/helpers/signal.py +homeassistant/helpers/state.py +homeassistant/helpers/sun.py +homeassistant/helpers/temperature.py +homeassistant/helpers/translation.py +homeassistant/helpers/typing.py diff --git a/script/translations_upload b/script/translations_upload index 5bf9fe1e121..52045e41d60 100755 --- a/script/translations_upload +++ b/script/translations_upload @@ -26,7 +26,8 @@ LANG_ISO=en CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) -if [ "${CURRENT_BRANCH-}" != "dev" ] && [ "${TRAVIS_BRANCH-}" != "dev" ] ; then +# Check Travis and CircleCI environment as well +if [ "${CURRENT_BRANCH-}" != "dev" ] && [ "${TRAVIS_BRANCH-}" != "dev" ] && [ "${CIRCLE_BRANCH-}" != "dev" ]; then echo "Please only run the translations upload script from a clean checkout of dev." exit 1 fi diff --git a/tox.ini b/tox.ini index 8423141df60..b8995d9e877 100644 --- a/tox.ini +++ b/tox.ini @@ -42,4 +42,4 @@ deps = -r{toxinidir}/requirements_test.txt -c{toxinidir}/homeassistant/package_constraints.txt commands = - /bin/bash -c 'mypy homeassistant/*.py homeassistant/{auth,util}/ homeassistant/helpers/{__init__,aiohttp_client,area_registry,condition,deprecation,dispatcher,entity_values,entityfilter,icon,intent,json,location,signal,state,sun,temperature,translation,typing}.py' + /bin/bash -c 'TYPING_FILES=$(cat mypyrc); mypy $TYPING_FILES' From a5b03541e90a7ff7aff9f4b26573879c9c1de3fa Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 1 Apr 2019 17:16:56 +0200 Subject: [PATCH 024/167] Delete .travis.yml --- .travis.yml | 55 ----------------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0461d182232..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,55 +0,0 @@ -sudo: false -dist: xenial -addons: - apt: - sources: - - sourceline: "ppa:jonathonf/ffmpeg-4" - packages: - - libudev-dev - - libavformat-dev - - libavcodec-dev - - libavdevice-dev - - libavutil-dev - - libswscale-dev - - libswresample-dev - - libavfilter-dev -matrix: - fast_finish: true - include: - - python: "3.5.3" - env: TOXENV=lint - - python: "3.5.3" - env: TOXENV=pylint - - python: "3.5.3" - env: TOXENV=typing - - python: "3.5.3" - env: TOXENV=cov - after_success: coveralls - - python: "3.6" - env: TOXENV=py36 - - python: "3.7" - env: TOXENV=py37 - - python: "3.8-dev" - env: TOXENV=py38 - if: branch = dev AND type = push - allow_failures: - - python: "3.8-dev" - env: TOXENV=py38 - -cache: - directories: - - $HOME/.cache/pip -install: pip install -U tox coveralls -language: python -script: travis_wait 40 tox --develop -services: - - docker -before_deploy: - - docker pull lokalise/lokalise-cli@sha256:2198814ebddfda56ee041a4b427521757dd57f75415ea9693696a64c550cef21 -deploy: - skip_cleanup: true - provider: script - script: script/travis_deploy - on: - branch: dev - condition: $TOXENV = lint From 9f2c5b7231bcf26e4d5052d01187a65c08fcae19 Mon Sep 17 00:00:00 2001 From: Andrew Sayre <6730289+andrewsayre@users.noreply.github.com> Date: Mon, 1 Apr 2019 11:58:52 -0500 Subject: [PATCH 025/167] Add source selection to Heos component (#22592) * Add select source support * Review feedback changes * Removed unused import * Ignore 'umused' import used in typing * Only include trace back on useful errors * Remove return from play_source --- homeassistant/components/heos/__init__.py | 137 ++++++++++++++++-- homeassistant/components/heos/const.py | 4 + homeassistant/components/heos/media_player.py | 47 +++++- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/heos/conftest.py | 46 +++++- tests/components/heos/test_init.py | 55 +++++-- tests/components/heos/test_media_player.py | 120 +++++++++++++-- 8 files changed, 365 insertions(+), 48 deletions(-) diff --git a/homeassistant/components/heos/__init__.py b/homeassistant/components/heos/__init__.py index 2214a602ef3..dadd9f10464 100644 --- a/homeassistant/components/heos/__init__.py +++ b/homeassistant/components/heos/__init__.py @@ -1,5 +1,6 @@ """Denon HEOS Media Player.""" import asyncio +from datetime import timedelta import logging import voluptuous as vol @@ -8,13 +9,17 @@ from homeassistant.components.media_player.const import ( DOMAIN as MEDIA_PLAYER_DOMAIN) from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP +from homeassistant.exceptions import ConfigEntryNotReady import homeassistant.helpers.config_validation as cv from homeassistant.helpers.typing import ConfigType, HomeAssistantType +from homeassistant.util import Throttle from .config_flow import format_title -from .const import DATA_CONTROLLER, DOMAIN +from .const import ( + COMMAND_RETRY_ATTEMPTS, COMMAND_RETRY_DELAY, DATA_CONTROLLER, + DATA_SOURCE_MANAGER, DOMAIN, SIGNAL_HEOS_SOURCES_UPDATED) -REQUIREMENTS = ['pyheos==0.2.0'] +REQUIREMENTS = ['pyheos==0.3.0'] CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -22,6 +27,8 @@ CONFIG_SCHEMA = vol.Schema({ }) }, extra=vol.ALLOW_EXTRA) +MIN_UPDATE_SOURCES = timedelta(seconds=1) + _LOGGER = logging.getLogger(__name__) @@ -50,7 +57,7 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType): async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): """Initialize config entry which represents the HEOS controller.""" - from pyheos import Heos + from pyheos import Heos, CommandError host = entry.data[CONF_HOST] # Setting all_progress_events=False ensures that we only receive a # media position update upon start of playback or when media changes @@ -58,26 +65,34 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): try: await controller.connect(auto_reconnect=True) # Auto reconnect only operates if initial connection was successful. - except (asyncio.TimeoutError, ConnectionError) as error: + except (asyncio.TimeoutError, ConnectionError, CommandError) as error: await controller.disconnect() - _LOGGER.exception("Unable to connect to controller %s: %s", - host, type(error).__name__) - return False + _LOGGER.debug("Unable to connect to controller %s: %s", host, error) + raise ConfigEntryNotReady + # Disconnect when shutting down async def disconnect_controller(event): await controller.disconnect() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, disconnect_controller) try: - players = await controller.get_players() - except (asyncio.TimeoutError, ConnectionError) as error: + players, favorites, inputs = await asyncio.gather( + controller.get_players(), + controller.get_favorites(), + controller.get_input_sources() + ) + except (asyncio.TimeoutError, ConnectionError, CommandError) as error: await controller.disconnect() - _LOGGER.exception("Unable to retrieve players: %s", - type(error).__name__) - return False + _LOGGER.debug("Unable to retrieve players and sources: %s", error, + exc_info=isinstance(error, CommandError)) + raise ConfigEntryNotReady + + source_manager = SourceManager(favorites, inputs) + source_manager.connect_update(hass, controller) hass.data[DOMAIN] = { DATA_CONTROLLER: controller, + DATA_SOURCE_MANAGER: source_manager, MEDIA_PLAYER_DOMAIN: players } hass.async_create_task(hass.config_entries.async_forward_entry_setup( @@ -88,7 +103,105 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry): """Unload a config entry.""" controller = hass.data[DOMAIN][DATA_CONTROLLER] + controller.dispatcher.disconnect_all() await controller.disconnect() hass.data.pop(DOMAIN) return await hass.config_entries.async_forward_entry_unload( entry, MEDIA_PLAYER_DOMAIN) + + +class SourceManager: + """Class that manages sources for players.""" + + def __init__(self, favorites, inputs, *, + retry_delay: int = COMMAND_RETRY_DELAY, + max_retry_attempts: int = COMMAND_RETRY_ATTEMPTS): + """Init input manager.""" + self.retry_delay = retry_delay + self.max_retry_attempts = max_retry_attempts + self.favorites = favorites + self.inputs = inputs + self.source_list = self._build_source_list() + + def _build_source_list(self): + """Build a single list of inputs from various types.""" + source_list = [] + source_list.extend([favorite.name for favorite + in self.favorites.values()]) + source_list.extend([source.name for source in self.inputs]) + return source_list + + async def play_source(self, source: str, player): + """Determine type of source and play it.""" + index = next((index for index, favorite in self.favorites.items() + if favorite.name == source), None) + if index is not None: + await player.play_favorite(index) + return + + input_source = next((input_source for input_source in self.inputs + if input_source.name == source), None) + if input_source is not None: + await player.play_input_source(input_source) + return + + _LOGGER.error("Unknown source: %s", source) + + def get_current_source(self, now_playing_media): + """Determine current source from now playing media.""" + from pyheos import const + # Match input by input_name:media_id + if now_playing_media.source_id == const.MUSIC_SOURCE_AUX_INPUT: + return next((input_source.name for input_source in self.inputs + if input_source.input_name == + now_playing_media.media_id), None) + # Try matching favorite by name:station or media_id:album_id + return next((source.name for source in self.favorites.values() + if source.name == now_playing_media.station + or source.media_id == now_playing_media.album_id), None) + + def connect_update(self, hass, controller): + """ + Connect listener for when sources change and signal player update. + + EVENT_SOURCES_CHANGED is often raised multiple times in response to a + physical event therefore throttle it. Retrieving sources immediately + after the event may fail so retry. + """ + from pyheos import CommandError, const + + @Throttle(MIN_UPDATE_SOURCES) + async def get_sources(): + retry_attempts = 0 + while True: + try: + return await asyncio.gather( + controller.get_favorites(), + controller.get_input_sources()) + except (asyncio.TimeoutError, ConnectionError, CommandError) \ + as error: + if retry_attempts < self.max_retry_attempts: + retry_attempts += 1 + _LOGGER.debug("Error retrieving sources and will " + "retry: %s", error, + exc_info=isinstance(error, CommandError)) + await asyncio.sleep(self.retry_delay) + else: + _LOGGER.error("Unable to update sources: %s", error, + exc_info=isinstance(error, CommandError)) + return + + async def update_sources(event): + if event in const.EVENT_SOURCES_CHANGED: + sources = await get_sources() + # If throttled, it will return None + if sources: + self.favorites, self.inputs = sources + self.source_list = self._build_source_list() + _LOGGER.debug("Sources updated due to changed event") + # Let players know to update + hass.helpers.dispatcher.async_dispatcher_send( + SIGNAL_HEOS_SOURCES_UPDATED) + + controller.dispatcher.connect( + const.SIGNAL_CONTROLLER_EVENT, update_sources) diff --git a/homeassistant/components/heos/const.py b/homeassistant/components/heos/const.py index 65c452e4a71..9cb65589b43 100644 --- a/homeassistant/components/heos/const.py +++ b/homeassistant/components/heos/const.py @@ -1,4 +1,8 @@ """Const for the HEOS integration.""" +COMMAND_RETRY_ATTEMPTS = 2 +COMMAND_RETRY_DELAY = 1 DATA_CONTROLLER = "controller" +DATA_SOURCE_MANAGER = "source_manager" DOMAIN = 'heos' +SIGNAL_HEOS_SOURCES_UPDATED = "heos_sources_updated" diff --git a/homeassistant/components/heos/media_player.py b/homeassistant/components/heos/media_player.py index f96435dc713..466c9ae8faa 100644 --- a/homeassistant/components/heos/media_player.py +++ b/homeassistant/components/heos/media_player.py @@ -1,22 +1,27 @@ """Denon HEOS Media Player.""" from functools import reduce from operator import ior +from typing import Sequence from homeassistant.components.media_player import MediaPlayerDevice from homeassistant.components.media_player.const import ( DOMAIN, MEDIA_TYPE_MUSIC, SUPPORT_CLEAR_PLAYLIST, SUPPORT_NEXT_TRACK, - SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PREVIOUS_TRACK, SUPPORT_SHUFFLE_SET, - SUPPORT_STOP, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP) + SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PREVIOUS_TRACK, SUPPORT_SELECT_SOURCE, + SUPPORT_SHUFFLE_SET, SUPPORT_STOP, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, + SUPPORT_VOLUME_STEP) +from homeassistant.config_entries import ConfigEntry from homeassistant.const import STATE_IDLE, STATE_PAUSED, STATE_PLAYING +from homeassistant.helpers.typing import HomeAssistantType from homeassistant.util.dt import utcnow -from .const import DOMAIN as HEOS_DOMAIN +from .const import ( + DATA_SOURCE_MANAGER, DOMAIN as HEOS_DOMAIN, SIGNAL_HEOS_SOURCES_UPDATED) DEPENDENCIES = ['heos'] BASE_SUPPORTED_FEATURES = SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | \ SUPPORT_VOLUME_STEP | SUPPORT_CLEAR_PLAYLIST | \ - SUPPORT_SHUFFLE_SET + SUPPORT_SHUFFLE_SET | SUPPORT_SELECT_SOURCE async def async_setup_platform( @@ -25,8 +30,9 @@ async def async_setup_platform( pass -async def async_setup_entry(hass, config_entry, async_add_entities): - """Add binary sensors for a config entry.""" +async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry, + async_add_entities): + """Add media players for a config entry.""" players = hass.data[HEOS_DOMAIN][DOMAIN] devices = [HeosMediaPlayer(player) for player in players.values()] async_add_entities(devices, True) @@ -42,6 +48,7 @@ class HeosMediaPlayer(MediaPlayerDevice): self._player = player self._signals = [] self._supported_features = BASE_SUPPORTED_FEATURES + self._source_manager = None self._play_state_to_state = { const.PLAY_STATE_PLAY: STATE_PLAYING, const.PLAY_STATE_STOP: STATE_IDLE, @@ -74,9 +81,14 @@ class HeosMediaPlayer(MediaPlayerDevice): self._media_position_updated_at = utcnow() await self.async_update_ha_state(True) + async def _sources_updated(self): + """Handle sources changed.""" + await self.async_update_ha_state(True) + async def async_added_to_hass(self): """Device added to hass.""" from pyheos import const + self._source_manager = self.hass.data[HEOS_DOMAIN][DATA_SOURCE_MANAGER] # Update state when attributes of the player change self._signals.append(self._player.heos.dispatcher.connect( const.SIGNAL_PLAYER_EVENT, self._player_update)) @@ -86,6 +98,10 @@ class HeosMediaPlayer(MediaPlayerDevice): # Update state upon connect/disconnects self._signals.append(self._player.heos.dispatcher.connect( const.SIGNAL_HEOS_EVENT, self._heos_event)) + # Update state when sources change + self._signals.append( + self.hass.helpers.dispatcher.async_dispatcher_connect( + SIGNAL_HEOS_SOURCES_UPDATED, self._sources_updated)) async def async_clear_playlist(self): """Clear players playlist.""" @@ -115,6 +131,10 @@ class HeosMediaPlayer(MediaPlayerDevice): """Mute the volume.""" await self._player.set_mute(mute) + async def async_select_source(self, source): + """Select input source.""" + await self._source_manager.play_source(source, self._player) + async def async_set_shuffle(self, shuffle): """Enable/disable shuffle mode.""" await self._player.set_play_mode(self._player.repeat, shuffle) @@ -218,7 +238,9 @@ class HeosMediaPlayer(MediaPlayerDevice): @property def media_image_url(self) -> str: """Image url of current playing media.""" - return self._player.now_playing_media.image_url + # May be an empty string, if so, return None + image_url = self._player.now_playing_media.image_url + return image_url if image_url else None @property def media_title(self) -> str: @@ -240,6 +262,17 @@ class HeosMediaPlayer(MediaPlayerDevice): """Boolean if shuffle is enabled.""" return self._player.shuffle + @property + def source(self) -> str: + """Name of the current input source.""" + return self._source_manager.get_current_source( + self._player.now_playing_media) + + @property + def source_list(self) -> Sequence[str]: + """List of available input sources.""" + return self._source_manager.source_list + @property def state(self) -> str: """State of the player.""" diff --git a/requirements_all.txt b/requirements_all.txt index ef42a58e97c..5d9f175df5e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1077,7 +1077,7 @@ pygtt==1.1.2 pyhaversion==2.0.3 # homeassistant.components.heos -pyheos==0.2.0 +pyheos==0.3.0 # homeassistant.components.hikvision.binary_sensor pyhik==0.2.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 85b49f71ce7..bc51c45f849 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -206,7 +206,7 @@ pydeconz==54 pydispatcher==2.0.5 # homeassistant.components.heos -pyheos==0.2.0 +pyheos==0.3.0 # homeassistant.components.homematic pyhomematic==0.1.58 diff --git a/tests/components/heos/conftest.py b/tests/components/heos/conftest.py index 6aa2f316088..1b76db21187 100644 --- a/tests/components/heos/conftest.py +++ b/tests/components/heos/conftest.py @@ -1,6 +1,8 @@ """Configuration for HEOS tests.""" +from typing import Dict, Sequence + from asynctest.mock import Mock, patch as patch -from pyheos import Dispatcher, HeosPlayer, const +from pyheos import Dispatcher, HeosPlayer, HeosSource, InputSource, const import pytest from homeassistant.components.heos import DOMAIN @@ -17,12 +19,15 @@ def config_entry_fixture(): @pytest.fixture(name="controller") -def controller_fixture(players): +def controller_fixture(players, favorites, input_sources, dispatcher): """Create a mock Heos controller fixture.""" with patch("pyheos.Heos", autospec=True) as mock: mock_heos = mock.return_value + mock_heos.dispatcher = dispatcher mock_heos.get_players.return_value = players mock_heos.players = players + mock_heos.get_favorites.return_value = favorites + mock_heos.get_input_sources.return_value = input_sources yield mock_heos @@ -35,10 +40,10 @@ def config_fixture(): @pytest.fixture(name="players") -def player_fixture(): +def player_fixture(dispatcher): """Create a mock HeosPlayer.""" player = Mock(HeosPlayer, autospec=True) - player.heos.dispatcher = Dispatcher() + player.heos.dispatcher = dispatcher player.player_id = 1 player.name = "Test Player" player.model = "Test Model" @@ -65,3 +70,36 @@ def player_fixture(): player.now_playing_media.image_url = "http://" player.now_playing_media.song = "Song" return {player.player_id: player} + + +@pytest.fixture(name="favorites") +def favorites_fixture() -> Dict[int, HeosSource]: + """Create favorites fixture.""" + station = Mock(HeosSource, autospec=True) + station.type = const.TYPE_STATION + station.name = "Today's Hits Radio" + station.media_id = '123456789' + radio = Mock(HeosSource, autospec=True) + radio.type = const.TYPE_STATION + radio.name = "Classical MPR (Classical Music)" + radio.media_id = 's1234' + return { + 1: station, + 2: radio + } + + +@pytest.fixture(name="input_sources") +def input_sources_fixture() -> Sequence[InputSource]: + """Create a set of input sources for testing.""" + source = Mock(InputSource, autospec=True) + source.player_id = 1 + source.input_name = const.INPUT_AUX_IN_1 + source.name = "HEOS Drive - Line In 1" + return [source] + + +@pytest.fixture(name="dispatcher") +def dispatcher_fixture() -> Dispatcher: + """Create a dispatcher for testing.""" + return Dispatcher() diff --git a/tests/components/heos/test_init.py b/tests/components/heos/test_init.py index b89c39113e4..b6bc3e24e1a 100644 --- a/tests/components/heos/test_init.py +++ b/tests/components/heos/test_init.py @@ -2,12 +2,17 @@ import asyncio from asynctest import patch +from pyheos import CommandError, const +import pytest -from homeassistant.components.heos import async_setup_entry, async_unload_entry -from homeassistant.components.heos.const import DATA_CONTROLLER, DOMAIN +from homeassistant.components.heos import ( + SourceManager, async_setup_entry, async_unload_entry) +from homeassistant.components.heos.const import ( + DATA_CONTROLLER, DATA_SOURCE_MANAGER, DOMAIN) from homeassistant.components.media_player.const import ( DOMAIN as MEDIA_PLAYER_DOMAIN) from homeassistant.const import CONF_HOST +from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.setup import async_setup_component @@ -36,7 +41,7 @@ async def test_async_setup_updates_entry(hass, config_entry, config): async def test_async_setup_returns_true(hass, config_entry, config): - """Test component setup updates entry from config.""" + """Test component setup from config.""" config_entry.add_to_hass(hass) assert await async_setup_component(hass, DOMAIN, config) await hass.async_block_till_done() @@ -46,7 +51,7 @@ async def test_async_setup_returns_true(hass, config_entry, config): async def test_async_setup_no_config_returns_true(hass, config_entry): - """Test component setup updates entry from entry only.""" + """Test component setup from entry only.""" config_entry.add_to_hass(hass) assert await async_setup_component(hass, DOMAIN, {}) await hass.async_block_till_done() @@ -67,21 +72,21 @@ async def test_async_setup_entry_loads_platforms( assert forward_mock.call_count == 1 assert controller.connect.call_count == 1 controller.disconnect.assert_not_called() - assert hass.data[DOMAIN] == { - DATA_CONTROLLER: controller, - MEDIA_PLAYER_DOMAIN: controller.players - } + assert hass.data[DOMAIN][DATA_CONTROLLER] == controller + assert hass.data[DOMAIN][MEDIA_PLAYER_DOMAIN] == controller.players + assert isinstance(hass.data[DOMAIN][DATA_SOURCE_MANAGER], SourceManager) async def test_async_setup_entry_connect_failure( hass, config_entry, controller): - """Test failure to connect does not load entry.""" + """Connection failure raises ConfigEntryNotReady.""" config_entry.add_to_hass(hass) errors = [ConnectionError, asyncio.TimeoutError] for error in errors: controller.connect.side_effect = error - assert not await async_setup_entry(hass, config_entry) - await hass.async_block_till_done() + with pytest.raises(ConfigEntryNotReady): + await async_setup_entry(hass, config_entry) + await hass.async_block_till_done() assert controller.connect.call_count == 1 assert controller.disconnect.call_count == 1 controller.connect.reset_mock() @@ -90,13 +95,14 @@ async def test_async_setup_entry_connect_failure( async def test_async_setup_entry_player_failure( hass, config_entry, controller): - """Test failure to retrieve players does not load entry.""" + """Failure to retrieve players/sources raises ConfigEntryNotReady.""" config_entry.add_to_hass(hass) errors = [ConnectionError, asyncio.TimeoutError] for error in errors: controller.get_players.side_effect = error - assert not await async_setup_entry(hass, config_entry) - await hass.async_block_till_done() + with pytest.raises(ConfigEntryNotReady): + await async_setup_entry(hass, config_entry) + await hass.async_block_till_done() assert controller.connect.call_count == 1 assert controller.disconnect.call_count == 1 controller.connect.reset_mock() @@ -112,3 +118,24 @@ async def test_unload_entry(hass, config_entry, controller): await hass.async_block_till_done() assert controller.disconnect.call_count == 1 assert unload.call_count == 1 + assert DOMAIN not in hass.data + + +async def test_update_sources_retry(hass, config_entry, config, controller, + caplog): + """Test update sources retries on failures to max attempts.""" + config_entry.add_to_hass(hass) + assert await async_setup_component(hass, DOMAIN, config) + controller.get_favorites.reset_mock() + controller.get_input_sources.reset_mock() + source_manager = hass.data[DOMAIN][DATA_SOURCE_MANAGER] + source_manager.retry_delay = 0 + source_manager.max_retry_attempts = 1 + controller.get_favorites.side_effect = CommandError("Test", "test", 0) + controller.dispatcher.send( + const.SIGNAL_CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED) + # Wait until it's finished + while "Unable to update sources" not in caplog.text: + await asyncio.sleep(0.1) + assert controller.get_favorites.call_count == 2 + assert controller.get_input_sources.call_count == 2 diff --git a/tests/components/heos/test_media_player.py b/tests/components/heos/test_media_player.py index d065740f7c9..2f8d7dfc1e9 100644 --- a/tests/components/heos/test_media_player.py +++ b/tests/components/heos/test_media_player.py @@ -1,16 +1,19 @@ """Tests for the Heos Media Player platform.""" +import asyncio + from pyheos import const from homeassistant.components.heos import media_player -from homeassistant.components.heos.const import DOMAIN +from homeassistant.components.heos.const import ( + DATA_SOURCE_MANAGER, DOMAIN, SIGNAL_HEOS_SOURCES_UPDATED) from homeassistant.components.media_player.const import ( - ATTR_MEDIA_ALBUM_NAME, ATTR_MEDIA_ARTIST, ATTR_MEDIA_CONTENT_ID, - ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_DURATION, ATTR_MEDIA_POSITION, - ATTR_MEDIA_POSITION_UPDATED_AT, ATTR_MEDIA_SHUFFLE, ATTR_MEDIA_TITLE, - ATTR_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_MUTED, - DOMAIN as MEDIA_PLAYER_DOMAIN, MEDIA_TYPE_MUSIC, SERVICE_CLEAR_PLAYLIST, - SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PREVIOUS_TRACK, - SUPPORT_STOP) + ATTR_INPUT_SOURCE, ATTR_INPUT_SOURCE_LIST, ATTR_MEDIA_ALBUM_NAME, + ATTR_MEDIA_ARTIST, ATTR_MEDIA_CONTENT_ID, ATTR_MEDIA_CONTENT_TYPE, + ATTR_MEDIA_DURATION, ATTR_MEDIA_POSITION, ATTR_MEDIA_POSITION_UPDATED_AT, + ATTR_MEDIA_SHUFFLE, ATTR_MEDIA_TITLE, ATTR_MEDIA_VOLUME_LEVEL, + ATTR_MEDIA_VOLUME_MUTED, DOMAIN as MEDIA_PLAYER_DOMAIN, MEDIA_TYPE_MUSIC, + SERVICE_CLEAR_PLAYLIST, SERVICE_SELECT_SOURCE, SUPPORT_NEXT_TRACK, + SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PREVIOUS_TRACK, SUPPORT_STOP) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_SUPPORTED_FEATURES, SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, @@ -56,10 +59,13 @@ async def test_state_attributes(hass, config_entry, config, controller): assert state.attributes[ATTR_SUPPORTED_FEATURES] == \ SUPPORT_PLAY | SUPPORT_PAUSE | SUPPORT_STOP | SUPPORT_NEXT_TRACK | \ SUPPORT_PREVIOUS_TRACK | media_player.BASE_SUPPORTED_FEATURES + assert ATTR_INPUT_SOURCE not in state.attributes + assert state.attributes[ATTR_INPUT_SOURCE_LIST] == \ + hass.data[DOMAIN][DATA_SOURCE_MANAGER].source_list async def test_updates_start_from_signals( - hass, config_entry, config, controller): + hass, config_entry, config, controller, favorites): """Tests dispatched signals update player.""" await setup_platform(hass, config_entry, config) player = controller.players[1] @@ -110,6 +116,23 @@ async def test_updates_start_from_signals( state = hass.states.get('media_player.test_player') assert state.state == STATE_PLAYING + # Test sources event update + event = asyncio.Event() + + async def set_signal(): + event.set() + hass.helpers.dispatcher.async_dispatcher_connect( + SIGNAL_HEOS_SOURCES_UPDATED, set_signal) + + favorites.clear() + player.heos.dispatcher.send( + const.SIGNAL_CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED) + await event.wait() + source_list = hass.data[DOMAIN][DATA_SOURCE_MANAGER].source_list + assert len(source_list) == 1 + state = hass.states.get('media_player.test_player') + assert state.attributes[ATTR_INPUT_SOURCE_LIST] == source_list + async def test_services(hass, config_entry, config, controller): """Tests player commands.""" @@ -173,6 +196,85 @@ async def test_services(hass, config_entry, config, controller): player.set_volume.assert_called_once_with(100) +async def test_select_favorite( + hass, config_entry, config, controller, favorites): + """Tests selecting a music service favorite and state.""" + await setup_platform(hass, config_entry, config) + player = controller.players[1] + # Test set music service preset + favorite = favorites[1] + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, SERVICE_SELECT_SOURCE, + {ATTR_ENTITY_ID: 'media_player.test_player', + ATTR_INPUT_SOURCE: favorite.name}, blocking=True) + player.play_favorite.assert_called_once_with(1) + # Test state is matched by station name + player.now_playing_media.station = favorite.name + player.heos.dispatcher.send( + const.SIGNAL_PLAYER_EVENT, player.player_id, + const.EVENT_PLAYER_STATE_CHANGED) + await hass.async_block_till_done() + state = hass.states.get('media_player.test_player') + assert state.attributes[ATTR_INPUT_SOURCE] == favorite.name + + +async def test_select_radio_favorite( + hass, config_entry, config, controller, favorites): + """Tests selecting a radio favorite and state.""" + await setup_platform(hass, config_entry, config) + player = controller.players[1] + # Test set radio preset + favorite = favorites[2] + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, SERVICE_SELECT_SOURCE, + {ATTR_ENTITY_ID: 'media_player.test_player', + ATTR_INPUT_SOURCE: favorite.name}, blocking=True) + player.play_favorite.assert_called_once_with(2) + # Test state is matched by album id + player.now_playing_media.station = "Classical" + player.now_playing_media.album_id = favorite.media_id + player.heos.dispatcher.send( + const.SIGNAL_PLAYER_EVENT, player.player_id, + const.EVENT_PLAYER_STATE_CHANGED) + await hass.async_block_till_done() + state = hass.states.get('media_player.test_player') + assert state.attributes[ATTR_INPUT_SOURCE] == favorite.name + + +async def test_select_input_source( + hass, config_entry, config, controller, input_sources): + """Tests selecting input source and state.""" + await setup_platform(hass, config_entry, config) + player = controller.players[1] + # Test proper service called + input_source = input_sources[0] + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, SERVICE_SELECT_SOURCE, + {ATTR_ENTITY_ID: 'media_player.test_player', + ATTR_INPUT_SOURCE: input_source.name}, blocking=True) + player.play_input_source.assert_called_once_with(input_source) + # Test state is matched by media id + player.now_playing_media.source_id = const.MUSIC_SOURCE_AUX_INPUT + player.now_playing_media.media_id = const.INPUT_AUX_IN_1 + player.heos.dispatcher.send( + const.SIGNAL_PLAYER_EVENT, player.player_id, + const.EVENT_PLAYER_STATE_CHANGED) + await hass.async_block_till_done() + state = hass.states.get('media_player.test_player') + assert state.attributes[ATTR_INPUT_SOURCE] == input_source.name + + +async def test_select_input_unknown( + hass, config_entry, config, controller, caplog): + """Tests selecting an unknown input.""" + await setup_platform(hass, config_entry, config) + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, SERVICE_SELECT_SOURCE, + {ATTR_ENTITY_ID: 'media_player.test_player', + ATTR_INPUT_SOURCE: "Unknown"}, blocking=True) + assert "Unknown source: Unknown" in caplog.text + + async def test_unload_config_entry(hass, config_entry, config, controller): """Test the player is removed when the config entry is unloaded.""" await setup_platform(hass, config_entry, config) From 1e96d696887577e2317857115777146611335347 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 1 Apr 2019 19:00:25 +0200 Subject: [PATCH 026/167] Update face_recognition to 1.2.3 (#22622) --- homeassistant/components/dlib_face_detect/image_processing.py | 2 +- homeassistant/components/dlib_face_identify/image_processing.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/dlib_face_detect/image_processing.py b/homeassistant/components/dlib_face_detect/image_processing.py index cb9ea5ff5f9..fea756395e4 100644 --- a/homeassistant/components/dlib_face_detect/image_processing.py +++ b/homeassistant/components/dlib_face_detect/image_processing.py @@ -13,7 +13,7 @@ from homeassistant.components.image_processing import PLATFORM_SCHEMA # noqa from homeassistant.components.image_processing import ( ImageProcessingFaceEntity, CONF_SOURCE, CONF_ENTITY_ID, CONF_NAME) -REQUIREMENTS = ['face_recognition==1.0.0'] +REQUIREMENTS = ['face_recognition==1.2.3'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/dlib_face_identify/image_processing.py b/homeassistant/components/dlib_face_identify/image_processing.py index d8c3f5f621f..6611fb0edfb 100644 --- a/homeassistant/components/dlib_face_identify/image_processing.py +++ b/homeassistant/components/dlib_face_identify/image_processing.py @@ -15,7 +15,7 @@ from homeassistant.components.image_processing import ( CONF_NAME) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['face_recognition==1.0.0'] +REQUIREMENTS = ['face_recognition==1.2.3'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 5d9f175df5e..3868e744228 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -418,7 +418,7 @@ evohomeclient==0.2.8 # homeassistant.components.dlib_face_detect.image_processing # homeassistant.components.dlib_face_identify.image_processing -# face_recognition==1.0.0 +# face_recognition==1.2.3 # homeassistant.components.fastdotcom fastdotcom==0.0.3 From 0056fcf904a2f1f340ce65c01bd862a27d6c74f8 Mon Sep 17 00:00:00 2001 From: Fredrik Erlandsson Date: Mon, 1 Apr 2019 19:01:31 +0200 Subject: [PATCH 027/167] Make platform setup a coroutine (#22620) * make setup_platform a coroutine * Update homeassistant/components/tellduslive/sensor.py Co-Authored-By: fredrike --- homeassistant/components/daikin/climate.py | 3 ++- homeassistant/components/daikin/sensor.py | 3 ++- homeassistant/components/daikin/switch.py | 3 ++- homeassistant/components/tellduslive/binary_sensor.py | 3 ++- homeassistant/components/tellduslive/cover.py | 3 ++- homeassistant/components/tellduslive/light.py | 3 ++- homeassistant/components/tellduslive/sensor.py | 3 ++- homeassistant/components/tellduslive/switch.py | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/daikin/climate.py b/homeassistant/components/daikin/climate.py index c42f2785576..f348c88daac 100644 --- a/homeassistant/components/daikin/climate.py +++ b/homeassistant/components/daikin/climate.py @@ -53,7 +53,8 @@ HA_ATTR_TO_DAIKIN = { } -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): """Old way of setting up the Daikin HVAC platform. Can only be called when a user accidentally mentions the platform in their diff --git a/homeassistant/components/daikin/sensor.py b/homeassistant/components/daikin/sensor.py index 5a005e29989..c4f885f5081 100644 --- a/homeassistant/components/daikin/sensor.py +++ b/homeassistant/components/daikin/sensor.py @@ -13,7 +13,8 @@ from .const import ( _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): """Old way of setting up the Daikin sensors. Can only be called when a user accidentally mentions the platform in their diff --git a/homeassistant/components/daikin/switch.py b/homeassistant/components/daikin/switch.py index 29159c60fe9..74d03985478 100644 --- a/homeassistant/components/daikin/switch.py +++ b/homeassistant/components/daikin/switch.py @@ -10,7 +10,8 @@ _LOGGER = logging.getLogger(__name__) ZONE_ICON = 'mdi:home-circle' -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): """Old way of setting up the platform. Can only be called when a user accidentally mentions the platform in their diff --git a/homeassistant/components/tellduslive/binary_sensor.py b/homeassistant/components/tellduslive/binary_sensor.py index fc13f75838a..1e258b90463 100644 --- a/homeassistant/components/tellduslive/binary_sensor.py +++ b/homeassistant/components/tellduslive/binary_sensor.py @@ -10,7 +10,8 @@ from .entry import TelldusLiveEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): """Old way of setting up TelldusLive. Can only be called when a user accidentally mentions the platform in their diff --git a/homeassistant/components/tellduslive/cover.py b/homeassistant/components/tellduslive/cover.py index 6dac00ed7a2..b2cb5d9e62e 100644 --- a/homeassistant/components/tellduslive/cover.py +++ b/homeassistant/components/tellduslive/cover.py @@ -10,7 +10,8 @@ from .entry import TelldusLiveEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): """Old way of setting up TelldusLive. Can only be called when a user accidentally mentions the platform in their diff --git a/homeassistant/components/tellduslive/light.py b/homeassistant/components/tellduslive/light.py index 3847c66b6cb..abbfd8ac92e 100644 --- a/homeassistant/components/tellduslive/light.py +++ b/homeassistant/components/tellduslive/light.py @@ -11,7 +11,8 @@ from .entry import TelldusLiveEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): """Old way of setting up TelldusLive. Can only be called when a user accidentally mentions the platform in their diff --git a/homeassistant/components/tellduslive/sensor.py b/homeassistant/components/tellduslive/sensor.py index 156c11c95a7..8839337590b 100644 --- a/homeassistant/components/tellduslive/sensor.py +++ b/homeassistant/components/tellduslive/sensor.py @@ -42,7 +42,8 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): """Old way of setting up TelldusLive. Can only be called when a user accidentally mentions the platform in their diff --git a/homeassistant/components/tellduslive/switch.py b/homeassistant/components/tellduslive/switch.py index 55275b5b754..888feff41f8 100644 --- a/homeassistant/components/tellduslive/switch.py +++ b/homeassistant/components/tellduslive/switch.py @@ -10,7 +10,8 @@ from .entry import TelldusLiveEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): """Old way of setting up TelldusLive. Can only be called when a user accidentally mentions the platform in their From 431cc63aaf6e59024b8ff30d2448be9c048fa3be Mon Sep 17 00:00:00 2001 From: VDRainer <26381449+VDRainer@users.noreply.github.com> Date: Mon, 1 Apr 2019 19:03:18 +0200 Subject: [PATCH 028/167] Trend binary sensor check for state unavailable (#22621) * Trend binary sensor check for state unavailable Fixes: https://github.com/home-assistant/home-assistant/issues/20210 * Fix pylint --- homeassistant/components/trend/binary_sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/trend/binary_sensor.py b/homeassistant/components/trend/binary_sensor.py index fe3d10ab72c..2b1ae0e083a 100644 --- a/homeassistant/components/trend/binary_sensor.py +++ b/homeassistant/components/trend/binary_sensor.py @@ -10,7 +10,7 @@ from homeassistant.components.binary_sensor import ( BinarySensorDevice) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, CONF_DEVICE_CLASS, CONF_ENTITY_ID, - CONF_FRIENDLY_NAME, STATE_UNKNOWN, CONF_SENSORS) + CONF_FRIENDLY_NAME, STATE_UNKNOWN, STATE_UNAVAILABLE, CONF_SENSORS) from homeassistant.core import callback import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import generate_entity_id @@ -140,7 +140,7 @@ class SensorTrend(BinarySensorDevice): state = new_state.attributes.get(self._attribute) else: state = new_state.state - if state != STATE_UNKNOWN: + if state not in (STATE_UNKNOWN, STATE_UNAVAILABLE): sample = (utcnow().timestamp(), float(state)) self.samples.append(sample) self.async_schedule_update_ha_state(True) From bbc4775eab7ed3097bceff73d15b4c6195d590b9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 1 Apr 2019 10:20:13 -0700 Subject: [PATCH 029/167] Disable Z-Wave autoheal (#22628) --- homeassistant/components/zwave/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/zwave/const.py b/homeassistant/components/zwave/const.py index fece48655df..67b5341a4e6 100644 --- a/homeassistant/components/zwave/const.py +++ b/homeassistant/components/zwave/const.py @@ -29,7 +29,7 @@ CONF_USB_STICK_PATH = 'usb_path' CONF_CONFIG_PATH = 'config_path' CONF_NETWORK_KEY = 'network_key' -DEFAULT_CONF_AUTOHEAL = True +DEFAULT_CONF_AUTOHEAL = False DEFAULT_CONF_USB_STICK_PATH = '/zwaveusbstick' DEFAULT_POLLING_INTERVAL = 60000 DEFAULT_DEBUG = False From 2e02efed104af9fe2e22a78b66961c5d900f68e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Mon, 1 Apr 2019 19:33:38 +0200 Subject: [PATCH 030/167] Handle disonnect bug in Tibber library (#22629) --- homeassistant/components/tibber/__init__.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tibber/__init__.py b/homeassistant/components/tibber/__init__.py index 135437801d9..19cf6fe6525 100644 --- a/homeassistant/components/tibber/__init__.py +++ b/homeassistant/components/tibber/__init__.py @@ -11,7 +11,7 @@ from homeassistant.const import (EVENT_HOMEASSISTANT_STOP, CONF_ACCESS_TOKEN, from homeassistant.helpers import discovery from homeassistant.helpers.aiohttp_client import async_get_clientsession -REQUIREMENTS = ['pyTibber==0.10.0'] +REQUIREMENTS = ['pyTibber==0.10.1'] DOMAIN = 'tibber' diff --git a/requirements_all.txt b/requirements_all.txt index 3868e744228..3c3eabad553 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -925,7 +925,7 @@ pyRFXtrx==0.23 # pySwitchmate==0.4.5 # homeassistant.components.tibber -pyTibber==0.10.0 +pyTibber==0.10.1 # homeassistant.components.dlink.switch pyW215==0.6.0 From ab2ac60d123fb8c070a03a46e7b8f60a7b676b67 Mon Sep 17 00:00:00 2001 From: Anna Prosvetova Date: Mon, 1 Apr 2019 20:44:46 +0300 Subject: [PATCH 031/167] Fix xiaomi vacuum resume functionality (#22626) --- homeassistant/components/xiaomi_miio/vacuum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/xiaomi_miio/vacuum.py b/homeassistant/components/xiaomi_miio/vacuum.py index c7f69a40330..2673a5b897c 100644 --- a/homeassistant/components/xiaomi_miio/vacuum.py +++ b/homeassistant/components/xiaomi_miio/vacuum.py @@ -303,7 +303,7 @@ class MiroboVacuum(StateVacuumDevice): async def async_start(self): """Start or resume the cleaning task.""" await self._try_command( - "Unable to start the vacuum: %s", self._vacuum.start) + "Unable to start the vacuum: %s", self._vacuum.resume_or_start) async def async_pause(self): """Pause the cleaning task.""" From 1ce622469d878c8d1a527f7562eab455f4ce945a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9-Marc=20Simard?= Date: Mon, 1 Apr 2019 13:49:53 -0400 Subject: [PATCH 032/167] Fix GTFS variable type mismatch (#22624) --- homeassistant/components/gtfs/sensor.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/gtfs/sensor.py b/homeassistant/components/gtfs/sensor.py index 85f2651d1f6..c94f97d93dc 100644 --- a/homeassistant/components/gtfs/sensor.py +++ b/homeassistant/components/gtfs/sensor.py @@ -268,9 +268,8 @@ def get_next_departure(schedule: Any, start_station_id: Any, timetable[idx] = {**row, **extras} # Flag last departures. - for idx in [yesterday_last, today_last]: - if idx is not None: - timetable[idx]['last'] = True + for idx in filter(None, [yesterday_last, today_last]): + timetable[idx]['last'] = True _LOGGER.debug("Timetable: %s", sorted(timetable.keys())) From e78709c5f501592c630186d866268ac01d48f9ea Mon Sep 17 00:00:00 2001 From: etheralm <8655564+etheralm@users.noreply.github.com> Date: Mon, 1 Apr 2019 19:57:11 +0200 Subject: [PATCH 033/167] Add support for Dyson Purecool 2018 Air Purifiers models TP04 and DP04 (#22215) * initial commit initial commit rewrite tests fix merge issue with fan component fix merge issue with fan component * correct line length * change to sync_setup_component for tests * rename services and move services.yaml * move hepa and carbon filter state from sensor to fan * add test for duplicate entities * fix method call tests * fix docstring --- homeassistant/components/dyson/__init__.py | 6 +- homeassistant/components/dyson/climate.py | 15 +- homeassistant/components/dyson/fan.py | 409 ++++++++++++++-- homeassistant/components/dyson/sensor.py | 9 +- homeassistant/components/dyson/services.yaml | 64 +++ homeassistant/components/dyson/vacuum.py | 16 +- homeassistant/components/fan/services.yaml | 10 - requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- script/gen_requirements_all.py | 4 +- tests/components/dyson/test_climate.py | 15 +- tests/components/dyson/test_fan.py | 484 +++++++++++++++++-- tests/components/dyson/test_init.py | 30 +- tests/components/dyson/test_sensor.py | 9 +- tests/components/dyson/test_vacuum.py | 4 +- 15 files changed, 946 insertions(+), 133 deletions(-) create mode 100644 homeassistant/components/dyson/services.yaml diff --git a/homeassistant/components/dyson/__init__.py b/homeassistant/components/dyson/__init__.py index c2e56436bd8..eccf8aac364 100644 --- a/homeassistant/components/dyson/__init__.py +++ b/homeassistant/components/dyson/__init__.py @@ -3,12 +3,12 @@ import logging import voluptuous as vol +import homeassistant.helpers.config_validation as cv from homeassistant.const import ( CONF_DEVICES, CONF_PASSWORD, CONF_TIMEOUT, CONF_USERNAME) from homeassistant.helpers import discovery -import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['libpurecoollink==0.4.2'] +REQUIREMENTS = ['libpurecool==0.5.0'] _LOGGER = logging.getLogger(__name__) @@ -41,7 +41,7 @@ def setup(hass, config): if DYSON_DEVICES not in hass.data: hass.data[DYSON_DEVICES] = [] - from libpurecoollink.dyson import DysonAccount + from libpurecool.dyson import DysonAccount dyson_account = DysonAccount(config[DOMAIN].get(CONF_USERNAME), config[DOMAIN].get(CONF_PASSWORD), config[DOMAIN].get(CONF_LANGUAGE)) diff --git a/homeassistant/components/dyson/climate.py b/homeassistant/components/dyson/climate.py index 3e5c976b1f4..a24d011623b 100644 --- a/homeassistant/components/dyson/climate.py +++ b/homeassistant/components/dyson/climate.py @@ -11,7 +11,6 @@ from homeassistant.components.climate.const import ( STATE_COOL, STATE_HEAT, STATE_IDLE, SUPPORT_FAN_MODE, SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE) from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS - from . import DYSON_DEVICES _LOGGER = logging.getLogger(__name__) @@ -30,7 +29,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if discovery_info is None: return - from libpurecoollink.dyson_pure_hotcool_link import DysonPureHotCoolLink + from libpurecool.dyson_pure_hotcool_link import DysonPureHotCoolLink # Get Dyson Devices from parent component. add_devices( [DysonPureHotCoolLinkDevice(device) @@ -54,7 +53,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice): def on_message(self, message): """Call when new messages received from the climate.""" - from libpurecoollink.dyson_pure_state import DysonPureHotCoolState + from libpurecool.dyson_pure_state import DysonPureHotCoolState if isinstance(message, DysonPureHotCoolState): _LOGGER.debug("Message received for climate device %s : %s", @@ -109,7 +108,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice): @property def current_operation(self): """Return current operation ie. heat, cool, idle.""" - from libpurecoollink.const import HeatMode, HeatState + from libpurecool.const import HeatMode, HeatState if self._device.state.heat_mode == HeatMode.HEAT_ON.value: if self._device.state.heat_state == HeatState.HEAT_STATE_ON.value: return STATE_HEAT @@ -124,7 +123,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice): @property def current_fan_mode(self): """Return the fan setting.""" - from libpurecoollink.const import FocusMode + from libpurecool.const import FocusMode if self._device.state.focus_mode == FocusMode.FOCUS_ON.value: return STATE_FOCUS return STATE_DIFFUSE @@ -144,7 +143,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice): # Limit the target temperature into acceptable range. target_temp = min(self.max_temp, target_temp) target_temp = max(self.min_temp, target_temp) - from libpurecoollink.const import HeatTarget, HeatMode + from libpurecool.const import HeatTarget, HeatMode self._device.set_configuration( heat_target=HeatTarget.celsius(target_temp), heat_mode=HeatMode.HEAT_ON) @@ -152,7 +151,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice): def set_fan_mode(self, fan_mode): """Set new fan mode.""" _LOGGER.debug("Set %s focus mode %s", self.name, fan_mode) - from libpurecoollink.const import FocusMode + from libpurecool.const import FocusMode if fan_mode == STATE_FOCUS: self._device.set_configuration(focus_mode=FocusMode.FOCUS_ON) elif fan_mode == STATE_DIFFUSE: @@ -161,7 +160,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice): def set_operation_mode(self, operation_mode): """Set operation mode.""" _LOGGER.debug("Set %s heat mode %s", self.name, operation_mode) - from libpurecoollink.const import HeatMode + from libpurecool.const import HeatMode if operation_mode == STATE_HEAT: self._device.set_configuration(heat_mode=HeatMode.HEAT_ON) elif operation_mode == STATE_COOL: diff --git a/homeassistant/components/dyson/fan.py b/homeassistant/components/dyson/fan.py index 743d301df42..0140378968b 100644 --- a/homeassistant/components/dyson/fan.py +++ b/homeassistant/components/dyson/fan.py @@ -7,65 +7,150 @@ import logging import voluptuous as vol -from homeassistant.components.fan import ( - DOMAIN, SUPPORT_OSCILLATE, SUPPORT_SET_SPEED, FanEntity) -from homeassistant.const import CONF_ENTITY_ID import homeassistant.helpers.config_validation as cv - +from homeassistant.components.fan import ( + SUPPORT_OSCILLATE, SUPPORT_SET_SPEED, FanEntity, + SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH) +from homeassistant.const import ATTR_ENTITY_ID from . import DYSON_DEVICES _LOGGER = logging.getLogger(__name__) -CONF_NIGHT_MODE = 'night_mode' - -ATTR_IS_NIGHT_MODE = 'is_night_mode' -ATTR_IS_AUTO_MODE = 'is_auto_mode' +ATTR_NIGHT_MODE = 'night_mode' +ATTR_AUTO_MODE = 'auto_mode' +ATTR_ANGLE_LOW = 'angle_low' +ATTR_ANGLE_HIGH = 'angle_high' +ATTR_FLOW_DIRECTION_FRONT = 'flow_direction_front' +ATTR_TIMER = 'timer' +ATTR_HEPA_FILTER = 'hepa_filter' +ATTR_CARBON_FILTER = 'carbon_filter' +ATTR_DYSON_SPEED = 'dyson_speed' +ATTR_DYSON_SPEED_LIST = 'dyson_speed_list' DEPENDENCIES = ['dyson'] +DYSON_DOMAIN = 'dyson' DYSON_FAN_DEVICES = 'dyson_fan_devices' -SERVICE_SET_NIGHT_MODE = 'dyson_set_night_mode' +SERVICE_SET_NIGHT_MODE = 'set_night_mode' +SERVICE_SET_AUTO_MODE = 'set_auto_mode' +SERVICE_SET_ANGLE = 'set_angle' +SERVICE_SET_FLOW_DIRECTION_FRONT = 'set_flow_direction_front' +SERVICE_SET_TIMER = 'set_timer' +SERVICE_SET_DYSON_SPEED = 'set_speed' DYSON_SET_NIGHT_MODE_SCHEMA = vol.Schema({ - vol.Required(CONF_ENTITY_ID): cv.entity_id, - vol.Required(CONF_NIGHT_MODE): cv.boolean, + vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(ATTR_NIGHT_MODE): cv.boolean, +}) + +SET_AUTO_MODE_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(ATTR_AUTO_MODE): cv.boolean, +}) + +SET_ANGLE_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(ATTR_ANGLE_LOW): cv.positive_int, + vol.Required(ATTR_ANGLE_HIGH): cv.positive_int +}) + +SET_FLOW_DIRECTION_FRONT_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(ATTR_FLOW_DIRECTION_FRONT): cv.boolean +}) + +SET_TIMER_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(ATTR_TIMER): cv.positive_int +}) + +SET_DYSON_SPEED_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(ATTR_DYSON_SPEED): cv.positive_int }) def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dyson fan components.""" - from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink + from libpurecool.dyson_pure_cool_link import DysonPureCoolLink + from libpurecool.dyson_pure_cool import DysonPureCool + + if discovery_info is None: + return _LOGGER.debug("Creating new Dyson fans") if DYSON_FAN_DEVICES not in hass.data: hass.data[DYSON_FAN_DEVICES] = [] # Get Dyson Devices from parent component - for device in [d for d in hass.data[DYSON_DEVICES] if - isinstance(d, DysonPureCoolLink)]: - dyson_entity = DysonPureCoolLinkDevice(hass, device) - hass.data[DYSON_FAN_DEVICES].append(dyson_entity) + has_purecool_devices = False + device_serials = [device.serial for device in hass.data[DYSON_FAN_DEVICES]] + for device in hass.data[DYSON_DEVICES]: + if device.serial not in device_serials: + if isinstance(device, DysonPureCool): + has_purecool_devices = True + dyson_entity = DysonPureCoolDevice(device) + hass.data[DYSON_FAN_DEVICES].append(dyson_entity) + elif isinstance(device, DysonPureCoolLink): + dyson_entity = DysonPureCoolLinkDevice(hass, device) + hass.data[DYSON_FAN_DEVICES].append(dyson_entity) add_entities(hass.data[DYSON_FAN_DEVICES]) def service_handle(service): """Handle the Dyson services.""" - entity_id = service.data.get(CONF_ENTITY_ID) - night_mode = service.data.get(CONF_NIGHT_MODE) - fan_device = next([fan for fan in hass.data[DYSON_FAN_DEVICES] if - fan.entity_id == entity_id].__iter__(), None) + entity_id = service.data[ATTR_ENTITY_ID] + fan_device = next((fan for fan in hass.data[DYSON_FAN_DEVICES] if + fan.entity_id == entity_id), None) if fan_device is None: _LOGGER.warning("Unable to find Dyson fan device %s", str(entity_id)) return if service.service == SERVICE_SET_NIGHT_MODE: - fan_device.night_mode(night_mode) + fan_device.set_night_mode(service.data[ATTR_NIGHT_MODE]) + + if service.service == SERVICE_SET_AUTO_MODE: + fan_device.set_auto_mode(service.data[ATTR_AUTO_MODE]) + + if service.service == SERVICE_SET_ANGLE: + fan_device.set_angle(service.data[ATTR_ANGLE_LOW], + service.data[ATTR_ANGLE_HIGH]) + + if service.service == SERVICE_SET_FLOW_DIRECTION_FRONT: + fan_device.set_flow_direction_front( + service.data[ATTR_FLOW_DIRECTION_FRONT]) + + if service.service == SERVICE_SET_TIMER: + fan_device.set_timer(service.data[ATTR_TIMER]) + + if service.service == SERVICE_SET_DYSON_SPEED: + fan_device.set_dyson_speed(service.data[ATTR_DYSON_SPEED]) # Register dyson service(s) hass.services.register( - DOMAIN, SERVICE_SET_NIGHT_MODE, service_handle, + DYSON_DOMAIN, SERVICE_SET_NIGHT_MODE, service_handle, schema=DYSON_SET_NIGHT_MODE_SCHEMA) + if has_purecool_devices: + hass.services.register( + DYSON_DOMAIN, SERVICE_SET_AUTO_MODE, service_handle, + schema=SET_AUTO_MODE_SCHEMA) + + hass.services.register( + DYSON_DOMAIN, SERVICE_SET_ANGLE, service_handle, + schema=SET_ANGLE_SCHEMA) + + hass.services.register( + DYSON_DOMAIN, SERVICE_SET_FLOW_DIRECTION_FRONT, service_handle, + schema=SET_FLOW_DIRECTION_FRONT_SCHEMA) + + hass.services.register( + DYSON_DOMAIN, SERVICE_SET_TIMER, service_handle, + schema=SET_TIMER_SCHEMA) + + hass.services.register( + DYSON_DOMAIN, SERVICE_SET_DYSON_SPEED, service_handle, + schema=SET_DYSON_SPEED_SCHEMA) class DysonPureCoolLinkDevice(FanEntity): @@ -84,7 +169,7 @@ class DysonPureCoolLinkDevice(FanEntity): def on_message(self, message): """Call when new messages received from the fan.""" - from libpurecoollink.dyson_pure_state import DysonPureCoolState + from libpurecool.dyson_pure_state import DysonPureCoolState if isinstance(message, DysonPureCoolState): _LOGGER.debug("Message received for fan device %s: %s", self.name, @@ -103,7 +188,7 @@ class DysonPureCoolLinkDevice(FanEntity): def set_speed(self, speed: str) -> None: """Set the speed of the fan. Never called ??.""" - from libpurecoollink.const import FanSpeed, FanMode + from libpurecool.const import FanSpeed, FanMode _LOGGER.debug("Set fan speed to: %s", speed) @@ -116,7 +201,7 @@ class DysonPureCoolLinkDevice(FanEntity): def turn_on(self, speed: str = None, **kwargs) -> None: """Turn on the fan.""" - from libpurecoollink.const import FanSpeed, FanMode + from libpurecool.const import FanSpeed, FanMode _LOGGER.debug("Turn on fan %s with speed %s", self.name, speed) if speed: @@ -132,14 +217,14 @@ class DysonPureCoolLinkDevice(FanEntity): def turn_off(self, **kwargs) -> None: """Turn off the fan.""" - from libpurecoollink.const import FanMode + from libpurecool.const import FanMode _LOGGER.debug("Turn off fan %s", self.name) self._device.set_configuration(fan_mode=FanMode.OFF) def oscillate(self, oscillating: bool) -> None: """Turn on/off oscillating.""" - from libpurecoollink.const import Oscillation + from libpurecool.const import Oscillation _LOGGER.debug("Turn oscillation %s for device %s", oscillating, self.name) @@ -166,7 +251,7 @@ class DysonPureCoolLinkDevice(FanEntity): @property def speed(self) -> str: """Return the current speed.""" - from libpurecoollink.const import FanSpeed + from libpurecool.const import FanSpeed if self._device.state: if self._device.state.speed == FanSpeed.FAN_SPEED_AUTO.value: @@ -180,13 +265,13 @@ class DysonPureCoolLinkDevice(FanEntity): return None @property - def is_night_mode(self): + def night_mode(self): """Return Night mode.""" return self._device.state.night_mode == "ON" - def night_mode(self, night_mode: bool) -> None: + def set_night_mode(self, night_mode: bool) -> None: """Turn fan in night mode.""" - from libpurecoollink.const import NightMode + from libpurecool.const import NightMode _LOGGER.debug("Set %s night mode %s", self.name, night_mode) if night_mode: @@ -195,13 +280,13 @@ class DysonPureCoolLinkDevice(FanEntity): self._device.set_configuration(night_mode=NightMode.NIGHT_MODE_OFF) @property - def is_auto_mode(self): + def auto_mode(self): """Return auto mode.""" return self._device.state.fan_mode == "AUTO" - def auto_mode(self, auto_mode: bool) -> None: + def set_auto_mode(self, auto_mode: bool) -> None: """Turn fan in auto mode.""" - from libpurecoollink.const import FanMode + from libpurecool.const import FanMode _LOGGER.debug("Set %s auto mode %s", self.name, auto_mode) if auto_mode: @@ -212,7 +297,7 @@ class DysonPureCoolLinkDevice(FanEntity): @property def speed_list(self) -> list: """Get the list of available speeds.""" - from libpurecoollink.const import FanSpeed + from libpurecool.const import FanSpeed supported_speeds = [ FanSpeed.FAN_SPEED_AUTO.value, @@ -239,6 +324,256 @@ class DysonPureCoolLinkDevice(FanEntity): def device_state_attributes(self) -> dict: """Return optional state attributes.""" return { - ATTR_IS_NIGHT_MODE: self.is_night_mode, - ATTR_IS_AUTO_MODE: self.is_auto_mode + ATTR_NIGHT_MODE: self.night_mode, + ATTR_AUTO_MODE: self.auto_mode } + + +class DysonPureCoolDevice(FanEntity): + """Representation of a Dyson Purecool (TP04/DP04) fan.""" + + def __init__(self, device): + """Initialize the fan.""" + self._device = device + + async def async_added_to_hass(self): + """Call when entity is added to hass.""" + self.hass.async_add_executor_job( + self._device.add_message_listener, self.on_message) + + def on_message(self, message): + """Call when new messages received from the fan.""" + from libpurecool.dyson_pure_state_v2 import DysonPureCoolV2State + + if isinstance(message, DysonPureCoolV2State): + _LOGGER.debug("Message received for fan device %s: %s", self.name, + message) + self.schedule_update_ha_state() + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def name(self): + """Return the display name of this fan.""" + return self._device.name + + def turn_on(self, speed: str = None, **kwargs) -> None: + """Turn on the fan.""" + _LOGGER.debug("Turn on fan %s", self.name) + + if speed is not None: + self.set_speed(speed) + else: + self._device.turn_on() + + def set_speed(self, speed: str) -> None: + """Set the speed of the fan.""" + from libpurecool.const import FanSpeed + if speed == SPEED_LOW: + self._device.set_fan_speed(FanSpeed.FAN_SPEED_4) + elif speed == SPEED_MEDIUM: + self._device.set_fan_speed(FanSpeed.FAN_SPEED_7) + elif speed == SPEED_HIGH: + self._device.set_fan_speed(FanSpeed.FAN_SPEED_10) + + def turn_off(self, **kwargs): + """Turn off the fan.""" + _LOGGER.debug("Turn off fan %s", self.name) + self._device.turn_off() + + def set_dyson_speed(self, speed: str = None) -> None: + """Set the exact speed of the purecool fan.""" + from libpurecool.const import FanSpeed + + _LOGGER.debug("Set exact speed for fan %s", self.name) + + fan_speed = FanSpeed('{0:04d}'.format(int(speed))) + self._device.set_fan_speed(fan_speed) + + def oscillate(self, oscillating: bool) -> None: + """Turn on/off oscillating.""" + _LOGGER.debug("Turn oscillation %s for device %s", oscillating, + self.name) + + if oscillating: + self._device.enable_oscillation() + else: + self._device.disable_oscillation() + + def set_night_mode(self, night_mode: bool) -> None: + """Turn on/off night mode.""" + _LOGGER.debug("Turn night mode %s for device %s", night_mode, + self.name) + + if night_mode: + self._device.enable_night_mode() + else: + self._device.disable_night_mode() + + def set_auto_mode(self, auto_mode: bool) -> None: + """Turn auto mode on/off.""" + _LOGGER.debug("Turn auto mode %s for device %s", auto_mode, + self.name) + if auto_mode: + self._device.enable_auto_mode() + else: + self._device.disable_auto_mode() + + def set_angle(self, angle_low: int, angle_high: int) -> None: + """Set device angle.""" + _LOGGER.debug("set low %s and high angle %s for device %s", + angle_low, angle_high, self.name) + self._device.enable_oscillation(angle_low, angle_high) + + def set_flow_direction_front(self, + flow_direction_front: bool) -> None: + """Set frontal airflow direction.""" + _LOGGER.debug("Set frontal flow direction to %s for device %s", + flow_direction_front, + self.name) + + if flow_direction_front: + self._device.enable_frontal_direction() + else: + self._device.disable_frontal_direction() + + def set_timer(self, timer) -> None: + """Set timer.""" + _LOGGER.debug("Set timer to %s for device %s", timer, + self.name) + + if timer == 0: + self._device.disable_sleep_timer() + else: + self._device.enable_sleep_timer(timer) + + @property + def oscillating(self): + """Return the oscillation state.""" + return self._device.state and self._device.state.oscillation == "OION" + + @property + def is_on(self): + """Return true if the entity is on.""" + if self._device.state: + return self._device.state.fan_power == "ON" + + @property + def speed(self): + """Return the current speed.""" + from libpurecool.const import FanSpeed + + speed_map = {FanSpeed.FAN_SPEED_1.value: SPEED_LOW, + FanSpeed.FAN_SPEED_2.value: SPEED_LOW, + FanSpeed.FAN_SPEED_3.value: SPEED_LOW, + FanSpeed.FAN_SPEED_4.value: SPEED_LOW, + FanSpeed.FAN_SPEED_AUTO.value: SPEED_MEDIUM, + FanSpeed.FAN_SPEED_5.value: SPEED_MEDIUM, + FanSpeed.FAN_SPEED_6.value: SPEED_MEDIUM, + FanSpeed.FAN_SPEED_7.value: SPEED_MEDIUM, + FanSpeed.FAN_SPEED_8.value: SPEED_HIGH, + FanSpeed.FAN_SPEED_9.value: SPEED_HIGH} + + return speed_map[self._device.state.speed] + + @property + def dyson_speed(self): + """Return the current speed.""" + from libpurecool.const import FanSpeed + + if self._device.state: + if self._device.state.speed == FanSpeed.FAN_SPEED_AUTO.value: + return self._device.state.speed + return int(self._device.state.speed) + + @property + def night_mode(self): + """Return Night mode.""" + return self._device.state.night_mode == "ON" + + @property + def auto_mode(self): + """Return Auto mode.""" + return self._device.state.auto_mode == "ON" + + @property + def angle_low(self): + """Return angle high.""" + return int(self._device.state.oscillation_angle_low) + + @property + def angle_high(self): + """Return angle low.""" + return int(self._device.state.oscillation_angle_high) + + @property + def flow_direction_front(self): + """Return frontal flow direction.""" + return self._device.state.front_direction == 'ON' + + @property + def timer(self): + """Return timer.""" + return self._device.state.sleep_timer + + @property + def hepa_filter(self): + """Return the HEPA filter state.""" + return int(self._device.state.hepa_filter_state) + + @property + def carbon_filter(self): + """Return the carbon filter state.""" + return int(self._device.state.carbon_filter_state) + + @property + def speed_list(self) -> list: + """Get the list of available speeds.""" + return [SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] + + @property + def dyson_speed_list(self) -> list: + """Get the list of available dyson speeds.""" + from libpurecool.const import FanSpeed + return [ + int(FanSpeed.FAN_SPEED_1.value), + int(FanSpeed.FAN_SPEED_2.value), + int(FanSpeed.FAN_SPEED_3.value), + int(FanSpeed.FAN_SPEED_4.value), + int(FanSpeed.FAN_SPEED_5.value), + int(FanSpeed.FAN_SPEED_6.value), + int(FanSpeed.FAN_SPEED_7.value), + int(FanSpeed.FAN_SPEED_8.value), + int(FanSpeed.FAN_SPEED_9.value), + int(FanSpeed.FAN_SPEED_10.value), + ] + + @property + def device_serial(self): + """Return fan's serial number.""" + return self._device.serial + + @property + def supported_features(self) -> int: + """Flag supported features.""" + return SUPPORT_OSCILLATE | \ + SUPPORT_SET_SPEED + + @property + def device_state_attributes(self) -> dict: + """Return optional state attributes.""" + return { + ATTR_NIGHT_MODE: self.night_mode, + ATTR_AUTO_MODE: self.auto_mode, + ATTR_ANGLE_LOW: self.angle_low, + ATTR_ANGLE_HIGH: self.angle_high, + ATTR_FLOW_DIRECTION_FRONT: self.flow_direction_front, + ATTR_TIMER: self.timer, + ATTR_HEPA_FILTER: self.hepa_filter, + ATTR_CARBON_FILTER: self.carbon_filter, + ATTR_DYSON_SPEED: self.dyson_speed, + ATTR_DYSON_SPEED_LIST: self.dyson_speed_list + } diff --git a/homeassistant/components/dyson/sensor.py b/homeassistant/components/dyson/sensor.py index ed8987f75c2..abf06f15437 100644 --- a/homeassistant/components/dyson/sensor.py +++ b/homeassistant/components/dyson/sensor.py @@ -37,9 +37,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None): devices = [] unit = hass.config.units.temperature_unit # Get Dyson Devices from parent component - from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink - for device in [d for d in hass.data[DYSON_DEVICES] if - isinstance(d, DysonPureCoolLink)]: + from libpurecool.dyson_pure_cool import DysonPureCool + from libpurecool.dyson_pure_cool_link import DysonPureCoolLink + + for device in [d for d in hass.data[DYSON_DEVICES] + if isinstance(d, DysonPureCoolLink) and + not isinstance(d, DysonPureCool)]: devices.append(DysonFilterLifeSensor(device)) devices.append(DysonDustSensor(device)) devices.append(DysonHumiditySensor(device)) diff --git a/homeassistant/components/dyson/services.yaml b/homeassistant/components/dyson/services.yaml new file mode 100644 index 00000000000..a93b15b4304 --- /dev/null +++ b/homeassistant/components/dyson/services.yaml @@ -0,0 +1,64 @@ +# Describes the format for available fan services + +set_night_mode: + description: Set the fan in night mode. + fields: + entity_id: + description: Name(s) of the entities to enable/disable night mode + example: 'fan.living_room' + night_mode: + description: Night mode status + example: true + +set_auto_mode: + description: Set the fan in auto mode. + fields: + entity_id: + description: Name(s) of the entities to enable/disable auto mode + example: 'fan.living_room' + auto_mode: + description: Auto mode status + example: true + +set_angle: + description: Set the oscillation angle of the selected fan(s). + fields: + entity_id: + description: Name(s) of the entities for which to set the angle + example: 'fan.living_room' + angle_low: + description: The angle at which the oscillation should start + example: 1 + angle_high: + description: The angle at which the oscillation should end + example: 255 + +flow_direction_front: + description: Set the fan flow direction. + fields: + entity_id: + description: Name(s) of the entities to set frontal flow direction for + example: 'fan.living_room' + flow_direction_front: + description: Frontal flow direction + example: true + +set_timer: + description: Set the sleep timer. + fields: + entity_id: + description: Name(s) of the entities to set the sleep timer for + example: 'fan.living_room' + timer: + description: The value in minutes to set the timer to, 0 to disable it + example: 30 + +set_speed: + description: Set the exact speed of the fan. + fields: + entity_id: + description: Name(s) of the entities to set the speed for + example: 'fan.living_room' + timer: + description: Speed + example: 1 \ No newline at end of file diff --git a/homeassistant/components/dyson/vacuum.py b/homeassistant/components/dyson/vacuum.py index 7902cfa1585..72c7b95562f 100644 --- a/homeassistant/components/dyson/vacuum.py +++ b/homeassistant/components/dyson/vacuum.py @@ -31,7 +31,7 @@ SUPPORT_DYSON = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PAUSE | \ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dyson 360 Eye robot vacuum platform.""" - from libpurecoollink.dyson_360_eye import Dyson360Eye + from libpurecool.dyson_360_eye import Dyson360Eye _LOGGER.debug("Creating new Dyson 360 Eye robot vacuum") if DYSON_360_EYE_DEVICES not in hass.data: @@ -81,7 +81,7 @@ class Dyson360EyeDevice(VacuumDevice): @property def status(self): """Return the status of the vacuum cleaner.""" - from libpurecoollink.const import Dyson360EyeMode + from libpurecool.const import Dyson360EyeMode dyson_labels = { Dyson360EyeMode.INACTIVE_CHARGING: "Stopped - Charging", Dyson360EyeMode.INACTIVE_CHARGED: "Stopped - Charged", @@ -106,7 +106,7 @@ class Dyson360EyeDevice(VacuumDevice): @property def fan_speed(self): """Return the fan speed of the vacuum cleaner.""" - from libpurecoollink.const import PowerMode + from libpurecool.const import PowerMode speed_labels = { PowerMode.MAX: "Max", PowerMode.QUIET: "Quiet" @@ -128,7 +128,7 @@ class Dyson360EyeDevice(VacuumDevice): @property def is_on(self) -> bool: """Return True if entity is on.""" - from libpurecoollink.const import Dyson360EyeMode + from libpurecool.const import Dyson360EyeMode return self._device.state.state in [ Dyson360EyeMode.FULL_CLEAN_INITIATED, @@ -149,7 +149,7 @@ class Dyson360EyeDevice(VacuumDevice): @property def battery_icon(self): """Return the battery icon for the vacuum cleaner.""" - from libpurecoollink.const import Dyson360EyeMode + from libpurecool.const import Dyson360EyeMode charging = self._device.state.state in [ Dyson360EyeMode.INACTIVE_CHARGING] @@ -158,7 +158,7 @@ class Dyson360EyeDevice(VacuumDevice): def turn_on(self, **kwargs): """Turn the vacuum on.""" - from libpurecoollink.const import Dyson360EyeMode + from libpurecool.const import Dyson360EyeMode _LOGGER.debug("Turn on device %s", self.name) if self._device.state.state in [Dyson360EyeMode.FULL_CLEAN_PAUSED]: @@ -178,7 +178,7 @@ class Dyson360EyeDevice(VacuumDevice): def set_fan_speed(self, fan_speed, **kwargs): """Set fan speed.""" - from libpurecoollink.const import PowerMode + from libpurecool.const import PowerMode _LOGGER.debug("Set fan speed %s on device %s", fan_speed, self.name) power_modes = { @@ -189,7 +189,7 @@ class Dyson360EyeDevice(VacuumDevice): def start_pause(self, **kwargs): """Start, pause or resume the cleaning task.""" - from libpurecoollink.const import Dyson360EyeMode + from libpurecool.const import Dyson360EyeMode if self._device.state.state in [Dyson360EyeMode.FULL_CLEAN_PAUSED]: _LOGGER.debug("Resume device %s", self.name) diff --git a/homeassistant/components/fan/services.yaml b/homeassistant/components/fan/services.yaml index 35a81c7c934..16d3742d9ab 100644 --- a/homeassistant/components/fan/services.yaml +++ b/homeassistant/components/fan/services.yaml @@ -54,16 +54,6 @@ set_direction: description: The direction to rotate. Either 'forward' or 'reverse' example: 'forward' -dyson_set_night_mode: - description: Set the fan in night mode. - fields: - entity_id: - description: Name(s) of the entities to enable/disable night mode - example: 'fan.living_room' - night_mode: - description: Night mode status - example: true - xiaomi_miio_set_buzzer_on: description: Turn the buzzer on. fields: diff --git a/requirements_all.txt b/requirements_all.txt index 3c3eabad553..ea76277be4d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -628,7 +628,7 @@ konnected==0.1.5 lakeside==0.12 # homeassistant.components.dyson -libpurecoollink==0.4.2 +libpurecool==0.5.0 # homeassistant.components.foscam.camera libpyfoscam==1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index bc51c45f849..b18ee2b5261 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -145,7 +145,7 @@ influxdb==5.2.0 jsonpath==0.75 # homeassistant.components.dyson -libpurecoollink==0.4.2 +libpurecool==0.5.0 # homeassistant.components.soundtouch.media_player libsoundtouch==0.7.2 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 5cc347249f7..3180f7b8228 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 """Generate an updated requirements_all.txt.""" +import fnmatch import importlib import os import pkgutil import re import sys -import fnmatch COMMENT_REQUIREMENTS = ( 'Adafruit-DHT', @@ -74,7 +74,7 @@ TEST_REQUIREMENTS = ( 'homematicip', 'influxdb', 'jsonpath', - 'libpurecoollink', + 'libpurecool', 'libsoundtouch', 'luftdaten', 'mbddns', diff --git a/tests/components/dyson/test_climate.py b/tests/components/dyson/test_climate.py index 43ce6344ec4..778b3bdad49 100644 --- a/tests/components/dyson/test_climate.py +++ b/tests/components/dyson/test_climate.py @@ -2,12 +2,13 @@ import unittest from unittest import mock -from libpurecoollink.const import (FocusMode, HeatMode, HeatState, HeatTarget, - TiltState) -from libpurecoollink.dyson_pure_state import DysonPureHotCoolState -from libpurecoollink.dyson_pure_hotcool_link import DysonPureHotCoolLink -from homeassistant.components.dyson import climate as dyson +from libpurecool.const import (FocusMode, HeatMode, + HeatState, HeatTarget, TiltState) +from libpurecool.dyson_pure_hotcool_link import DysonPureHotCoolLink +from libpurecool.dyson_pure_state import DysonPureHotCoolState + from homeassistant.components import dyson as dyson_parent +from homeassistant.components.dyson import climate as dyson from homeassistant.const import TEMP_CELSIUS, ATTR_TEMPERATURE from homeassistant.setup import setup_component from tests.common import get_test_home_assistant @@ -110,9 +111,9 @@ class DysonTest(unittest.TestCase): """Stop everything that was started.""" self.hass.stop() - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_device_heat_on(), _get_device_cool()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_setup_component_with_parent_discovery(self, mocked_login, mocked_devices): """Test setup_component using discovery.""" diff --git a/tests/components/dyson/test_fan.py b/tests/components/dyson/test_fan.py index a04116f10f2..0a9469ae807 100644 --- a/tests/components/dyson/test_fan.py +++ b/tests/components/dyson/test_fan.py @@ -1,16 +1,28 @@ """Test the Dyson fan component.""" +import json import unittest from unittest import mock -from homeassistant.setup import setup_component +import asynctest +from libpurecool.const import FanSpeed, FanMode, NightMode, Oscillation +from libpurecool.dyson_pure_cool import DysonPureCool +from libpurecool.dyson_pure_cool_link import DysonPureCoolLink +from libpurecool.dyson_pure_state import DysonPureCoolState +from libpurecool.dyson_pure_state_v2 import DysonPureCoolV2State + +import homeassistant.components.dyson.fan as dyson from homeassistant.components import dyson as dyson_parent -from homeassistant.components.dyson import DYSON_DEVICES, fan as dyson -from homeassistant.components.fan import (ATTR_SPEED, ATTR_SPEED_LIST, - ATTR_OSCILLATING) +from homeassistant.components.dyson import DYSON_DEVICES +from homeassistant.components.fan import (DOMAIN, ATTR_SPEED, ATTR_SPEED_LIST, + ATTR_OSCILLATING, SPEED_LOW, + SPEED_MEDIUM, SPEED_HIGH, + SERVICE_OSCILLATE) +from homeassistant.const import (SERVICE_TURN_ON, + SERVICE_TURN_OFF, + ATTR_ENTITY_ID) +from homeassistant.helpers import discovery +from homeassistant.setup import setup_component, async_setup_component from tests.common import get_test_home_assistant -from libpurecoollink.const import FanSpeed, FanMode, NightMode, Oscillation -from libpurecoollink.dyson_pure_state import DysonPureCoolState -from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink class MockDysonState(DysonPureCoolState): @@ -21,6 +33,58 @@ class MockDysonState(DysonPureCoolState): pass +def _get_dyson_purecool_device(): + """Return a valid device as provided by the Dyson web services.""" + device = mock.Mock(spec=DysonPureCool) + device.serial = "XX-XXXXX-XX" + device.name = "Living room" + device.connect = mock.Mock(return_value=True) + device.auto_connect = mock.Mock(return_value=True) + device.state = mock.Mock() + device.state.oscillation = "OION" + device.state.fan_power = "ON" + device.state.speed = FanSpeed.FAN_SPEED_AUTO.value + device.state.night_mode = "OFF" + device.state.auto_mode = "ON" + device.state.oscillation_angle_low = "0090" + device.state.oscillation_angle_high = "0180" + device.state.front_direction = "ON" + device.state.sleep_timer = 60 + device.state.hepa_filter_state = "0090" + device.state.carbon_filter_state = "0080" + return device + + +def _get_supported_speeds(): + return [ + int(FanSpeed.FAN_SPEED_1.value), + int(FanSpeed.FAN_SPEED_2.value), + int(FanSpeed.FAN_SPEED_3.value), + int(FanSpeed.FAN_SPEED_4.value), + int(FanSpeed.FAN_SPEED_5.value), + int(FanSpeed.FAN_SPEED_6.value), + int(FanSpeed.FAN_SPEED_7.value), + int(FanSpeed.FAN_SPEED_8.value), + int(FanSpeed.FAN_SPEED_9.value), + int(FanSpeed.FAN_SPEED_10.value), + ] + + +def _get_config(): + """Return a config dictionary.""" + return {dyson_parent.DOMAIN: { + dyson_parent.CONF_USERNAME: "email", + dyson_parent.CONF_PASSWORD: "password", + dyson_parent.CONF_LANGUAGE: "GB", + dyson_parent.CONF_DEVICES: [ + { + "device_id": "XX-XXXXX-XX", + "device_ip": "192.168.0.1" + } + ] + }} + + def _get_device_with_no_state(): """Return a device with no state.""" device = mock.Mock() @@ -64,8 +128,8 @@ def _get_device_on(): return device -class DysonTest(unittest.TestCase): - """Dyson Sensor component test class.""" +class DysonSetupTest(unittest.TestCase): + """Dyson component setup tests.""" def setUp(self): # pylint: disable=invalid-name """Set up things to be run when tests are started.""" @@ -79,24 +143,39 @@ class DysonTest(unittest.TestCase): """Test setup component with no devices.""" self.hass.data[dyson.DYSON_DEVICES] = [] add_entities = mock.MagicMock() - dyson.setup_platform(self.hass, None, add_entities) + dyson.setup_platform(self.hass, None, add_entities, mock.Mock()) add_entities.assert_called_with([]) def test_setup_component(self): """Test setup component with devices.""" def _add_device(devices): - assert len(devices) == 1 + assert len(devices) == 2 assert devices[0].name == "Device_name" device_fan = _get_device_on() + device_purecool_fan = _get_dyson_purecool_device() device_non_fan = _get_device_off() - self.hass.data[dyson.DYSON_DEVICES] = [device_fan, device_non_fan] + self.hass.data[dyson.DYSON_DEVICES] = [device_fan, + device_purecool_fan, + device_non_fan] dyson.setup_platform(self.hass, None, _add_device) - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + +class DysonTest(unittest.TestCase): + """Dyson fan component test class.""" + + def setUp(self): # pylint: disable=invalid-name + """Set up things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + def tearDown(self): # pylint: disable=invalid-name + """Stop everything that was started.""" + self.hass.stop() + + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_device_on()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_get_state_attributes(self, mocked_login, mocked_devices): """Test async added to hass.""" setup_component(self.hass, dyson_parent.DOMAIN, { @@ -108,18 +187,18 @@ class DysonTest(unittest.TestCase): }) self.hass.block_till_done() state = self.hass.states.get("{}.{}".format( - dyson.DOMAIN, + DOMAIN, mocked_devices.return_value[0].name)) - assert dyson.ATTR_IS_NIGHT_MODE in state.attributes - assert dyson.ATTR_IS_AUTO_MODE in state.attributes + assert dyson.ATTR_NIGHT_MODE in state.attributes + assert dyson.ATTR_AUTO_MODE in state.attributes assert ATTR_SPEED in state.attributes assert ATTR_SPEED_LIST in state.attributes assert ATTR_OSCILLATING in state.attributes - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_device_on()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_async_added_to_hass(self, mocked_login, mocked_devices): """Test async added to hass.""" setup_component(self.hass, dyson_parent.DOMAIN, { @@ -161,11 +240,11 @@ class DysonTest(unittest.TestCase): device = _get_device_on() component = dyson.DysonPureCoolLinkDevice(self.hass, device) assert not component.should_poll - component.night_mode(True) + component.set_night_mode(True) set_config = device.set_configuration set_config.assert_called_with(night_mode=NightMode.NIGHT_MODE_ON) - component.night_mode(False) + component.set_night_mode(False) set_config = device.set_configuration set_config.assert_called_with(night_mode=NightMode.NIGHT_MODE_OFF) @@ -173,22 +252,22 @@ class DysonTest(unittest.TestCase): """Test night mode.""" device = _get_device_on() component = dyson.DysonPureCoolLinkDevice(self.hass, device) - assert not component.is_night_mode + assert not component.night_mode device = _get_device_off() component = dyson.DysonPureCoolLinkDevice(self.hass, device) - assert component.is_night_mode + assert component.night_mode def test_dyson_turn_auto_mode(self): """Test turn on/off fan with auto mode.""" device = _get_device_on() component = dyson.DysonPureCoolLinkDevice(self.hass, device) assert not component.should_poll - component.auto_mode(True) + component.set_auto_mode(True) set_config = device.set_configuration set_config.assert_called_with(fan_mode=FanMode.AUTO) - component.auto_mode(False) + component.set_auto_mode(False) set_config = device.set_configuration set_config.assert_called_with(fan_mode=FanMode.FAN) @@ -196,11 +275,11 @@ class DysonTest(unittest.TestCase): """Test auto mode.""" device = _get_device_on() component = dyson.DysonPureCoolLinkDevice(self.hass, device) - assert not component.is_auto_mode + assert not component.auto_mode device = _get_device_auto() component = dyson.DysonPureCoolLinkDevice(self.hass, device) - assert component.is_auto_mode + assert component.auto_mode def test_dyson_turn_on_speed(self): """Test turn on fan with specified speed.""" @@ -320,14 +399,355 @@ class DysonTest(unittest.TestCase): self.hass.data[DYSON_DEVICES] = [] dyson_device.entity_id = 'fan.living_room' self.hass.data[dyson.DYSON_FAN_DEVICES] = [dyson_device] - dyson.setup_platform(self.hass, None, mock.MagicMock()) + dyson.setup_platform(self.hass, None, + mock.MagicMock(), mock.MagicMock()) - self.hass.services.call(dyson.DOMAIN, dyson.SERVICE_SET_NIGHT_MODE, + self.hass.services.call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_NIGHT_MODE, {"entity_id": "fan.bed_room", "night_mode": True}, True) - assert not dyson_device.night_mode.called + assert dyson_device.set_night_mode.call_count == 0 - self.hass.services.call(dyson.DOMAIN, dyson.SERVICE_SET_NIGHT_MODE, + self.hass.services.call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_NIGHT_MODE, {"entity_id": "fan.living_room", "night_mode": True}, True) - dyson_device.night_mode.assert_called_with(True) + dyson_device.set_night_mode.assert_called_with(True) + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_turn_on(devices, login, hass): + """Test turn on.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "fan.bed_room"}, True) + assert device.turn_on.call_count == 0 + + await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "fan.living_room"}, True) + assert device.turn_on.call_count == 1 + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_set_speed(devices, login, hass): + """Test set speed.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "fan.bed_room", + ATTR_SPEED: SPEED_LOW}, True) + assert device.set_fan_speed.call_count == 0 + + await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "fan.living_room", + ATTR_SPEED: SPEED_LOW}, True) + device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_4) + + await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "fan.living_room", + ATTR_SPEED: SPEED_MEDIUM}, True) + device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_7) + + await hass.services.async_call(DOMAIN, SERVICE_TURN_ON, + {ATTR_ENTITY_ID: "fan.living_room", + ATTR_SPEED: SPEED_HIGH}, True) + device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_10) + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_turn_off(devices, login, hass): + """Test turn off.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "fan.bed_room"}, True) + assert device.turn_off.call_count == 0 + + await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "fan.living_room"}, True) + assert device.turn_off.call_count == 1 + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_set_dyson_speed(devices, login, hass): + """Test set exact dyson speed.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_DYSON_SPEED, + {ATTR_ENTITY_ID: "fan.bed_room", + dyson.ATTR_DYSON_SPEED: + int(FanSpeed.FAN_SPEED_2.value)}, + True) + assert device.set_fan_speed.call_count == 0 + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_DYSON_SPEED, + {ATTR_ENTITY_ID: "fan.living_room", + dyson.ATTR_DYSON_SPEED: + int(FanSpeed.FAN_SPEED_2.value)}, + True) + device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_2) + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_oscillate(devices, login, hass): + """Test set oscillation.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE, + {ATTR_ENTITY_ID: "fan.bed_room", + ATTR_OSCILLATING: True}, True) + assert device.enable_oscillation.call_count == 0 + + await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE, + {ATTR_ENTITY_ID: "fan.living_room", + ATTR_OSCILLATING: True}, True) + assert device.enable_oscillation.call_count == 1 + + await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE, + {ATTR_ENTITY_ID: "fan.living_room", + ATTR_OSCILLATING: False}, True) + assert device.disable_oscillation.call_count == 1 + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_set_night_mode(devices, login, hass): + """Test set night mode.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + + await hass.async_block_till_done() + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_NIGHT_MODE, + {"entity_id": "fan.bed_room", + "night_mode": True}, True) + assert device.enable_night_mode.call_count == 0 + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_NIGHT_MODE, + {"entity_id": "fan.living_room", + "night_mode": True}, True) + assert device.enable_night_mode.call_count == 1 + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_NIGHT_MODE, + {"entity_id": "fan.living_room", + "night_mode": False}, True) + assert device.disable_night_mode.call_count == 1 + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_set_auto_mode(devices, login, hass): + """Test set auto mode.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_AUTO_MODE, + {ATTR_ENTITY_ID: "fan.bed_room", + dyson.ATTR_AUTO_MODE: True}, True) + assert device.enable_auto_mode.call_count == 0 + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_AUTO_MODE, + {ATTR_ENTITY_ID: "fan.living_room", + dyson.ATTR_AUTO_MODE: True}, True) + assert device.enable_auto_mode.call_count == 1 + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_AUTO_MODE, + {ATTR_ENTITY_ID: "fan.living_room", + dyson.ATTR_AUTO_MODE: False}, True) + assert device.disable_auto_mode.call_count == 1 + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_set_angle(devices, login, hass): + """Test set angle.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_ANGLE, + {ATTR_ENTITY_ID: "fan.bed_room", + dyson.ATTR_ANGLE_LOW: 90, + dyson.ATTR_ANGLE_HIGH: 180}, True) + assert device.enable_oscillation.call_count == 0 + + await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_ANGLE, + {ATTR_ENTITY_ID: "fan.living_room", + dyson.ATTR_ANGLE_LOW: 90, + dyson.ATTR_ANGLE_HIGH: 180}, True) + device.enable_oscillation.assert_called_with(90, 180) + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_set_flow_direction_front(devices, login, hass): + """Test set frontal flow direction.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_FLOW_DIRECTION_FRONT, + {ATTR_ENTITY_ID: "fan.bed_room", + dyson.ATTR_FLOW_DIRECTION_FRONT: True}, + True) + assert device.enable_frontal_direction.call_count == 0 + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_FLOW_DIRECTION_FRONT, + {ATTR_ENTITY_ID: "fan.living_room", + dyson.ATTR_FLOW_DIRECTION_FRONT: True}, + True) + assert device.enable_frontal_direction.call_count == 1 + + await hass.services.async_call(dyson.DYSON_DOMAIN, + dyson.SERVICE_SET_FLOW_DIRECTION_FRONT, + {ATTR_ENTITY_ID: "fan.living_room", + dyson.ATTR_FLOW_DIRECTION_FRONT: False}, + True) + assert device.disable_frontal_direction.call_count == 1 + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_set_timer(devices, login, hass): + """Test set timer.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + + await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_TIMER, + {ATTR_ENTITY_ID: "fan.bed_room", + dyson.ATTR_TIMER: 60}, + True) + assert device.enable_frontal_direction.call_count == 0 + + await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_TIMER, + {ATTR_ENTITY_ID: "fan.living_room", + dyson.ATTR_TIMER: 60}, + True) + device.enable_sleep_timer.assert_called_with(60) + + await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_TIMER, + {ATTR_ENTITY_ID: "fan.living_room", + dyson.ATTR_TIMER: 0}, + True) + assert device.disable_sleep_timer.call_count == 1 + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_attributes(devices, login, hass): + """Test state attributes.""" + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + fan_state = hass.states.get("fan.living_room") + attributes = fan_state.attributes + + assert fan_state.state == "on" + assert attributes[dyson.ATTR_NIGHT_MODE] is False + assert attributes[dyson.ATTR_AUTO_MODE] is True + assert attributes[dyson.ATTR_ANGLE_LOW] == 90 + assert attributes[dyson.ATTR_ANGLE_HIGH] == 180 + assert attributes[dyson.ATTR_FLOW_DIRECTION_FRONT] is True + assert attributes[dyson.ATTR_TIMER] == 60 + assert attributes[dyson.ATTR_HEPA_FILTER] == 90 + assert attributes[dyson.ATTR_CARBON_FILTER] == 80 + assert attributes[dyson.ATTR_DYSON_SPEED] == FanSpeed.FAN_SPEED_AUTO.value + assert attributes[ATTR_SPEED] == SPEED_MEDIUM + assert attributes[ATTR_OSCILLATING] is True + assert attributes[dyson.ATTR_DYSON_SPEED_LIST] == _get_supported_speeds() + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_update_state(devices, login, hass): + """Test state update.""" + device = devices.return_value[0] + await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config()) + await hass.async_block_till_done() + event = {"msg": "CURRENT-STATE", + "product-state": {"fpwr": "OFF", "fdir": "OFF", "auto": "OFF", + "oscs": "ON", "oson": "ON", "nmod": "OFF", + "rhtm": "ON", "fnst": "FAN", "ercd": "11E1", + "wacd": "NONE", "nmdv": "0004", "fnsp": "0002", + "bril": "0002", "corf": "ON", "cflr": "0085", + "hflr": "0095", "sltm": "OFF", "osal": "0045", + "osau": "0095", "ancp": "CUST"}} + device.state = DysonPureCoolV2State(json.dumps(event)) + + callback = device.add_message_listener.call_args_list[0][0][0] + callback(device.state) + await hass.async_block_till_done() + fan_state = hass.states.get("fan.living_room") + attributes = fan_state.attributes + + assert fan_state.state == "off" + assert attributes[dyson.ATTR_NIGHT_MODE] is False + assert attributes[dyson.ATTR_AUTO_MODE] is False + assert attributes[dyson.ATTR_ANGLE_LOW] == 45 + assert attributes[dyson.ATTR_ANGLE_HIGH] == 95 + assert attributes[dyson.ATTR_FLOW_DIRECTION_FRONT] is False + assert attributes[dyson.ATTR_TIMER] == "OFF" + assert attributes[dyson.ATTR_HEPA_FILTER] == 95 + assert attributes[dyson.ATTR_CARBON_FILTER] == 85 + assert attributes[dyson.ATTR_DYSON_SPEED] == \ + int(FanSpeed.FAN_SPEED_2.value) + assert attributes[ATTR_SPEED] is SPEED_LOW + assert attributes[ATTR_OSCILLATING] is False + assert attributes[dyson.ATTR_DYSON_SPEED_LIST] == _get_supported_speeds() + + +@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True) +@asynctest.patch('libpurecool.dyson.DysonAccount.devices', + return_value=[_get_dyson_purecool_device()]) +async def test_purecool_component_setup_only_once(devices, login, hass): + """Test if entities are created only once.""" + config = _get_config() + await async_setup_component(hass, dyson_parent.DOMAIN, config) + await hass.async_block_till_done() + discovery.load_platform(hass, "fan", dyson_parent.DOMAIN, {}, config) + await hass.async_block_till_done() + + fans = [fan for fan in hass.data[DOMAIN].entities + if fan.platform.platform_name == dyson_parent.DOMAIN] + + assert len(fans) == 1 + assert fans[0].device_serial == "XX-XXXXX-XX" diff --git a/tests/components/dyson/test_init.py b/tests/components/dyson/test_init.py index 2e7b05b06cd..cc8c04a1559 100644 --- a/tests/components/dyson/test_init.py +++ b/tests/components/dyson/test_init.py @@ -43,7 +43,7 @@ class DysonTest(unittest.TestCase): """Stop everything that was started.""" self.hass.stop() - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=False) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=False) def test_dyson_login_failed(self, mocked_login): """Test if Dyson connection failed.""" dyson.setup(self.hass, {dyson.DOMAIN: { @@ -53,8 +53,8 @@ class DysonTest(unittest.TestCase): }}) assert mocked_login.call_count == 1 - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', return_value=[]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[]) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_dyson_login(self, mocked_login, mocked_devices): """Test valid connection to dyson web service.""" dyson.setup(self.hass, {dyson.DOMAIN: { @@ -67,9 +67,9 @@ class DysonTest(unittest.TestCase): assert len(self.hass.data[dyson.DYSON_DEVICES]) == 0 @mock.patch('homeassistant.helpers.discovery.load_platform') - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_dyson_account_device_available()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_dyson_custom_conf(self, mocked_login, mocked_devices, mocked_discovery): """Test device connection using custom configuration.""" @@ -89,9 +89,9 @@ class DysonTest(unittest.TestCase): assert len(self.hass.data[dyson.DYSON_DEVICES]) == 1 assert mocked_discovery.call_count == 4 - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_dyson_account_device_not_available()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_dyson_custom_conf_device_not_available(self, mocked_login, mocked_devices): """Test device connection with an invalid device.""" @@ -110,9 +110,9 @@ class DysonTest(unittest.TestCase): assert mocked_devices.call_count == 1 assert len(self.hass.data[dyson.DYSON_DEVICES]) == 0 - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_dyson_account_device_error()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_dyson_custom_conf_device_error(self, mocked_login, mocked_devices): """Test device connection with device raising an exception.""" @@ -132,9 +132,9 @@ class DysonTest(unittest.TestCase): assert len(self.hass.data[dyson.DYSON_DEVICES]) == 0 @mock.patch('homeassistant.helpers.discovery.load_platform') - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_dyson_account_device_available()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_dyson_custom_conf_with_unknown_device(self, mocked_login, mocked_devices, mocked_discovery): @@ -156,9 +156,9 @@ class DysonTest(unittest.TestCase): assert mocked_discovery.call_count == 0 @mock.patch('homeassistant.helpers.discovery.load_platform') - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_dyson_account_device_available()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_dyson_discovery(self, mocked_login, mocked_devices, mocked_discovery): """Test device connection using discovery.""" @@ -174,9 +174,9 @@ class DysonTest(unittest.TestCase): assert len(self.hass.data[dyson.DYSON_DEVICES]) == 1 assert mocked_discovery.call_count == 4 - @mock.patch('libpurecoollink.dyson.DysonAccount.devices', + @mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[_get_dyson_account_device_not_available()]) - @mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True) + @mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True) def test_dyson_discovery_device_not_available(self, mocked_login, mocked_devices): """Test device connection with discovery and invalid device.""" diff --git a/tests/components/dyson/test_sensor.py b/tests/components/dyson/test_sensor.py index 3218038c7e3..67c34d4d180 100644 --- a/tests/components/dyson/test_sensor.py +++ b/tests/components/dyson/test_sensor.py @@ -2,16 +2,17 @@ import unittest from unittest import mock +from libpurecool.dyson_pure_cool_link import DysonPureCoolLink + +from homeassistant.components.dyson import sensor as dyson from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, \ STATE_OFF -from homeassistant.components.dyson import sensor as dyson from tests.common import get_test_home_assistant -from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink def _get_device_without_state(): """Return a valid device provide by Dyson web services.""" - device = mock.Mock(spec=DysonPureCoolLink) + device = mock.Mock() device.name = "Device_name" device.state = None device.environmental_state = None @@ -20,7 +21,7 @@ def _get_device_without_state(): def _get_with_state(): """Return a valid device with state values.""" - device = mock.Mock() + device = mock.Mock(spec=DysonPureCoolLink) device.name = "Device_name" device.state = mock.Mock() device.state.filter_life = 100 diff --git a/tests/components/dyson/test_vacuum.py b/tests/components/dyson/test_vacuum.py index 05ad8cf0db7..cdf76c975ae 100644 --- a/tests/components/dyson/test_vacuum.py +++ b/tests/components/dyson/test_vacuum.py @@ -2,8 +2,8 @@ import unittest from unittest import mock -from libpurecoollink.dyson_360_eye import Dyson360Eye -from libpurecoollink.const import Dyson360EyeMode, PowerMode +from libpurecool.const import Dyson360EyeMode, PowerMode +from libpurecool.dyson_360_eye import Dyson360Eye from homeassistant.components.dyson import vacuum as dyson from homeassistant.components.dyson.vacuum import Dyson360EyeDevice From 82296aeb7127fa3532098ea7b53e2f33b54e7c42 Mon Sep 17 00:00:00 2001 From: Phil Bruckner Date: Mon, 1 Apr 2019 17:36:29 -0500 Subject: [PATCH 034/167] Amcrest: Add on/off support & attributes. Bump amcrest to 1.3.0 (#22418) * Amcrest: Add on/off support & attributes to camera entity. Bump amcrest package to 1.3.0. Add support for turn_on & turn_off services. Add implementation of is_recording method, as well as brand, model, hardware_version, machine_name, serial_number, software_build and software_version attributes. Bump amcrest package to 1.3.0 required for above changes and also handles errors in storage commands which resolves #19982. * Update per review Rebase to upstream/dev. Remove video_enabled property and setter and replace with _enable_video_stream method. Remove static attributes from camera and sensors. --- homeassistant/components/amcrest/__init__.py | 2 +- homeassistant/components/amcrest/camera.py | 87 +++++++++++++++++++- homeassistant/components/amcrest/sensor.py | 13 --- requirements_all.txt | 2 +- 4 files changed, 85 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/amcrest/__init__.py b/homeassistant/components/amcrest/__init__.py index 84dc0b5bb01..295b798c3b1 100644 --- a/homeassistant/components/amcrest/__init__.py +++ b/homeassistant/components/amcrest/__init__.py @@ -12,7 +12,7 @@ from homeassistant.helpers import discovery import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['amcrest==1.2.7'] +REQUIREMENTS = ['amcrest==1.3.0'] DEPENDENCIES = ['ffmpeg'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/amcrest/camera.py b/homeassistant/components/amcrest/camera.py index 63c2c720781..853d5404dab 100644 --- a/homeassistant/components/amcrest/camera.py +++ b/homeassistant/components/amcrest/camera.py @@ -3,7 +3,7 @@ import asyncio import logging from homeassistant.components.camera import ( - Camera, SUPPORT_STREAM) + Camera, SUPPORT_ON_OFF, SUPPORT_STREAM) from homeassistant.components.ffmpeg import DATA_FFMPEG from homeassistant.const import CONF_NAME from homeassistant.helpers.aiohttp_client import ( @@ -39,18 +39,23 @@ class AmcrestCam(Camera): super(AmcrestCam, self).__init__() self._name = amcrest.name self._camera = amcrest.device - self._base_url = self._camera.get_base_url() self._ffmpeg = hass.data[DATA_FFMPEG] self._ffmpeg_arguments = amcrest.ffmpeg_arguments self._stream_source = amcrest.stream_source self._resolution = amcrest.resolution self._token = self._auth = amcrest.authentication + self._is_recording = False + self._model = None self._snapshot_lock = asyncio.Lock() async def async_camera_image(self): """Return a still image response from the camera.""" from amcrest import AmcrestError + if not self.is_on: + _LOGGER.error( + 'Attempt to take snaphot when %s camera is off', self.name) + return None async with self._snapshot_lock: try: # Send the request to snap a picture and return raw jpg data @@ -59,7 +64,8 @@ class AmcrestCam(Camera): return response.data except AmcrestError as error: _LOGGER.error( - 'Could not get camera image due to error %s', error) + 'Could not get image from %s camera due to error: %s', + self.name, error) return None async def handle_async_mjpeg_stream(self, request): @@ -94,6 +100,8 @@ class AmcrestCam(Camera): finally: await stream.close() + # Entity property overrides + @property def name(self): """Return the name of this camera.""" @@ -102,9 +110,80 @@ class AmcrestCam(Camera): @property def supported_features(self): """Return supported features.""" - return SUPPORT_STREAM + return SUPPORT_ON_OFF | SUPPORT_STREAM + + # Camera property overrides + + @property + def is_recording(self): + """Return true if the device is recording.""" + return self._is_recording + + @property + def brand(self): + """Return the camera brand.""" + return 'Amcrest' + + @property + def model(self): + """Return the camera model.""" + return self._model @property def stream_source(self): """Return the source of the stream.""" return self._camera.rtsp_url(typeno=self._resolution) + + @property + def is_on(self): + """Return true if on.""" + return self.is_streaming + + # Other Entity method overrides + + def update(self): + """Update entity status.""" + from amcrest import AmcrestError + + _LOGGER.debug('Pulling data from %s camera', self.name) + if self._model is None: + try: + self._model = self._camera.device_type.split('=')[-1].strip() + except AmcrestError as error: + _LOGGER.error( + 'Could not get %s camera model due to error: %s', + self.name, error) + self._model = '' + try: + self.is_streaming = self._camera.video_enabled + self._is_recording = self._camera.record_mode == 'Manual' + except AmcrestError as error: + _LOGGER.error( + 'Could not get %s camera attributes due to error: %s', + self.name, error) + + # Other Camera method overrides + + def turn_off(self): + """Turn off camera.""" + self._enable_video_stream(False) + + def turn_on(self): + """Turn on camera.""" + self._enable_video_stream(True) + + # Utility methods + + def _enable_video_stream(self, enable): + """Enable or disable camera video stream.""" + from amcrest import AmcrestError + + try: + self._camera.video_enabled = enable + except AmcrestError as error: + _LOGGER.error( + 'Could not %s %s camera video stream due to error: %s', + 'enable' if enable else 'disable', self.name, error) + else: + self.is_streaming = enable + self.schedule_update_ha_state() diff --git a/homeassistant/components/amcrest/sensor.py b/homeassistant/components/amcrest/sensor.py index c721914c73c..68bc86da94c 100644 --- a/homeassistant/components/amcrest/sensor.py +++ b/homeassistant/components/amcrest/sensor.py @@ -75,19 +75,6 @@ class AmcrestSensor(Entity): """Get the latest data and updates the state.""" _LOGGER.debug("Pulling data from %s sensor.", self._name) - try: - version, build_date = self._camera.software_information - self._attrs['Build Date'] = build_date.split('=')[-1] - self._attrs['Version'] = version.split('=')[-1] - except ValueError: - self._attrs['Build Date'] = 'Not Available' - self._attrs['Version'] = 'Not Available' - - try: - self._attrs['Serial Number'] = self._camera.serial_number - except ValueError: - self._attrs['Serial Number'] = 'Not Available' - if self._sensor_type == 'motion_detector': self._state = self._camera.is_motion_detected self._attrs['Record Mode'] = self._camera.record_mode diff --git a/requirements_all.txt b/requirements_all.txt index ea76277be4d..4a67141d743 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -155,7 +155,7 @@ alarmdecoder==1.13.2 alpha_vantage==2.1.0 # homeassistant.components.amcrest -amcrest==1.2.7 +amcrest==1.3.0 # homeassistant.components.androidtv.media_player androidtv==0.0.14 From a7e613616c5d771f2c5fb9a39345fdfc7c48161c Mon Sep 17 00:00:00 2001 From: Malte Franken Date: Tue, 2 Apr 2019 10:27:58 +1100 Subject: [PATCH 035/167] change library to georss_generic_client (#22615) --- homeassistant/components/geo_rss_events/sensor.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- script/gen_requirements_all.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/geo_rss_events/sensor.py b/homeassistant/components/geo_rss_events/sensor.py index ab406f9241e..f71a60c2e83 100644 --- a/homeassistant/components/geo_rss_events/sensor.py +++ b/homeassistant/components/geo_rss_events/sensor.py @@ -20,7 +20,7 @@ from homeassistant.const import ( CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS, CONF_URL) from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['georss_client==0.5'] +REQUIREMENTS = ['georss_generic_client==0.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 4a67141d743..9f7ee3d3f3a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -473,7 +473,7 @@ geizhals==0.0.9 geojson_client==0.3 # homeassistant.components.geo_rss_events.sensor -georss_client==0.5 +georss_generic_client==0.2 # homeassistant.components.gitter.sensor gitterpy==0.1.7 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index b18ee2b5261..76ec85148e2 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -108,7 +108,7 @@ gTTS-token==1.1.3 geojson_client==0.3 # homeassistant.components.geo_rss_events.sensor -georss_client==0.5 +georss_generic_client==0.2 # homeassistant.components.ffmpeg ha-ffmpeg==2.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 3180f7b8228..33a7b4fd16f 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -59,7 +59,7 @@ TEST_REQUIREMENTS = ( 'feedparser-homeassistant', 'foobot_async', 'geojson_client', - 'georss_client', + 'georss_generic_client', 'gTTS-token', 'ha-ffmpeg', 'hangups', From e70803266923327f813ecc4bd142a9044171e1c1 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 2 Apr 2019 02:41:08 +0200 Subject: [PATCH 036/167] Support GET params for websocket ingress path (#22638) --- homeassistant/components/hassio/ingress.py | 5 +++++ tests/components/hassio/test_ingress.py | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/hassio/ingress.py b/homeassistant/components/hassio/ingress.py index 6c1ef389712..04241f53de9 100644 --- a/homeassistant/components/hassio/ingress.py +++ b/homeassistant/components/hassio/ingress.py @@ -71,9 +71,14 @@ class HassIOIngress(HomeAssistantView): ws_server = web.WebSocketResponse() await ws_server.prepare(request) + # Preparing url = self._create_url(addon, path) source_header = _init_header(request, addon) + # Support GET query + if request.query_string: + url = "{}?{}".format(url, request.query_string) + # Start proxy async with self._websession.ws_connect( url, headers=source_header diff --git a/tests/components/hassio/test_ingress.py b/tests/components/hassio/test_ingress.py index 4e071ba24fd..4b72eda4c25 100644 --- a/tests/components/hassio/test_ingress.py +++ b/tests/components/hassio/test_ingress.py @@ -136,7 +136,8 @@ async def test_ingress_request_delete( @pytest.mark.parametrize( 'build_type', [ ("a3_vl", "test/beer/ws"), ("core", "ws.php"), - ("local", "panel/config/stream"), ("jk_921", "hulk") + ("local", "panel/config/stream"), ("jk_921", "hulk"), + ("demo", "ws/connection?id=9&token=SJAKWS283") ]) async def test_ingress_websocket( hassio_client, build_type, aioclient_mock): From 1e26151069c7cefe1401d08ffc3e0a20271d7745 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 1 Apr 2019 17:42:04 -0700 Subject: [PATCH 037/167] Require static-check success first for rest of workflow (#22635) * Require static-check success first * Update config.yml --- .circleci/config.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b4f22601bb5..9c9d75d934b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -213,18 +213,26 @@ workflows: build: jobs: - static-check - - pre-install-all-requirements + - pre-install-all-requirements: + requires: + - static-check - pylint: requires: - pre-install-all-requirements - pre-test: name: pre-test 3.5.5 + requires: + - static-check python: 3.5.5-stretch - pre-test: name: pre-test 3.6 + requires: + - static-check python: 3.6-stretch - pre-test: name: pre-test 3.7 + requires: + - static-check python: 3.7-stretch - test: name: test 3.5.5 From 39eaa7fc8d71018fa5ec81b856ace7086e9260e1 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 1 Apr 2019 17:43:29 -0700 Subject: [PATCH 038/167] Add trusted networks deprecating warning (#22487) * Add trusted networks deprecating warning * Update auth.py * Update auth.py * Update auth.py * Update auth.py * Tweak --- homeassistant/components/http/auth.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/homeassistant/components/http/auth.py b/homeassistant/components/http/auth.py index 4736ef12391..7b8508894ce 100644 --- a/homeassistant/components/http/auth.py +++ b/homeassistant/components/http/auth.py @@ -190,6 +190,12 @@ def setup_auth(hass, app): elif (trusted_networks and await async_validate_trusted_networks(request)): + _LOGGER.warning( + 'Access from trusted networks without auth token is going to ' + 'be removed in Home Assistant 0.96. Configure the trusted ' + 'networks auth provider or use long-lived access tokens to ' + 'access %s from %s', + request.path, request[KEY_REAL_IP]) authenticated = True elif (support_legacy and HTTP_HEADER_HA_AUTH in request.headers and From 7646dc00e0a5d9f7f2ff7b3c5a8c62d1139c70a1 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 1 Apr 2019 20:31:05 -0700 Subject: [PATCH 039/167] Add codecov (#22649) --- .circleci/config.yml | 5 +++-- requirements_test.txt | 1 + requirements_test_all.txt | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9c9d75d934b..cde04d08e40 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -172,13 +172,14 @@ jobs: - install - run: - name: run tests + name: run tests with code coverage command: | . venv/bin/activate + CC_SWITCH="--cov --cov-report=" TESTFILES=$(circleci tests glob "tests/**/test_*.py" | circleci tests split --split-by=timings) - if [ -z "$CODE_COVERAGE" ]; then CC_SWITCH=""; else CC_SWITCH="--cov --cov-report html:htmlcov"; fi pytest --timeout=9 --duration=10 --junitxml=test-reports/homeassistant/results.xml -qq -o junit_family=xunit2 -o junit_suite_name=homeassistant -o console_output_style=count -p no:sugar $CC_SWITCH -- ${TESTFILES} script/check_dirty + codecov - store_test_results: path: test-reports diff --git a/requirements_test.txt b/requirements_test.txt index bf96353144c..0cd8c583f38 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -2,6 +2,7 @@ # make new things fail. Manually update these pins when pulling in a # new version asynctest==0.12.2 +codecov==2.0.15 coveralls==1.2.0 flake8-docstrings==1.3.0 flake8==3.7.7 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 76ec85148e2..974cfef9cd0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -3,6 +3,7 @@ # make new things fail. Manually update these pins when pulling in a # new version asynctest==0.12.2 +codecov==2.0.15 coveralls==1.2.0 flake8-docstrings==1.3.0 flake8==3.7.7 From 2578c8525bf59108edd81a1528f10e44edf19e5b Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Tue, 2 Apr 2019 05:57:25 +0200 Subject: [PATCH 040/167] Qwikswitch fix listen loop (#22600) * Qwikswitch fix listen loop * 0.93 fix qwikcord upstream --- homeassistant/components/qwikswitch/__init__.py | 5 +++-- .../components/qwikswitch/binary_sensor.py | 2 +- homeassistant/components/qwikswitch/sensor.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/qwikswitch/test_init.py | 17 ++++++++++------- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/qwikswitch/__init__.py b/homeassistant/components/qwikswitch/__init__.py index 63e30a9491e..23144ed82b8 100644 --- a/homeassistant/components/qwikswitch/__init__.py +++ b/homeassistant/components/qwikswitch/__init__.py @@ -19,7 +19,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.discovery import load_platform from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['pyqwikswitch==0.8'] +REQUIREMENTS = ['pyqwikswitch==0.93'] _LOGGER = logging.getLogger(__name__) @@ -119,7 +119,8 @@ class QSToggleEntity(QSEntity): async def async_setup(hass, config): """Qwiskswitch component setup.""" from pyqwikswitch.async_ import QSUsb - from pyqwikswitch import CMD_BUTTONS, QS_CMD, QS_ID, QSType, SENSORS + from pyqwikswitch.qwikswitch import ( + CMD_BUTTONS, QS_CMD, QS_ID, QSType, SENSORS) # Add cmd's to in /&listen packets will fire events # By default only buttons of type [TOGGLE,SCENE EXE,LEVEL] diff --git a/homeassistant/components/qwikswitch/binary_sensor.py b/homeassistant/components/qwikswitch/binary_sensor.py index 17021f7a9e9..6cdc29deae4 100644 --- a/homeassistant/components/qwikswitch/binary_sensor.py +++ b/homeassistant/components/qwikswitch/binary_sensor.py @@ -35,7 +35,7 @@ class QSBinarySensor(QSEntity, BinarySensorDevice): def __init__(self, sensor): """Initialize the sensor.""" - from pyqwikswitch import SENSORS + from pyqwikswitch.qwikswitch import SENSORS super().__init__(sensor['id'], sensor['name']) self.channel = sensor['channel'] diff --git a/homeassistant/components/qwikswitch/sensor.py b/homeassistant/components/qwikswitch/sensor.py index 07d0247e4f6..b9ccb3c3a7b 100644 --- a/homeassistant/components/qwikswitch/sensor.py +++ b/homeassistant/components/qwikswitch/sensor.py @@ -33,7 +33,7 @@ class QSSensor(QSEntity): def __init__(self, sensor): """Initialize the sensor.""" - from pyqwikswitch import SENSORS + from pyqwikswitch.qwikswitch import SENSORS super().__init__(sensor['id'], sensor['name']) self.channel = sensor['channel'] diff --git a/requirements_all.txt b/requirements_all.txt index 9f7ee3d3f3a..1ef9af9c970 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1238,7 +1238,7 @@ pypollencom==2.2.3 pyps4-homeassistant==0.5.2 # homeassistant.components.qwikswitch -pyqwikswitch==0.8 +pyqwikswitch==0.93 # homeassistant.components.nmbs.sensor pyrail==0.0.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 974cfef9cd0..5d58e42e8b2 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -234,7 +234,7 @@ pyotp==2.2.6 pyps4-homeassistant==0.5.2 # homeassistant.components.qwikswitch -pyqwikswitch==0.8 +pyqwikswitch==0.93 # homeassistant.components.smartthings pysmartapp==0.3.2 diff --git a/tests/components/qwikswitch/test_init.py b/tests/components/qwikswitch/test_init.py index 76655f32816..d6ad0607d42 100644 --- a/tests/components/qwikswitch/test_init.py +++ b/tests/components/qwikswitch/test_init.py @@ -7,6 +7,7 @@ from homeassistant.const import EVENT_HOMEASSISTANT_START from homeassistant.components.qwikswitch import DOMAIN as QWIKSWITCH from homeassistant.bootstrap import async_setup_component from tests.test_util.aiohttp import mock_aiohttp_client +from aiohttp.client_exceptions import ClientError _LOGGER = logging.getLogger(__name__) @@ -23,6 +24,8 @@ class AiohttpClientMockResponseList(list): try: res = list.pop(self, 0) _LOGGER.debug("MockResponseList popped %s: %s", res, self) + if isinstance(res, Exception): + raise res return res except IndexError: raise AssertionError("MockResponseList empty") @@ -54,7 +57,7 @@ def aioclient_mock(): yield mock_session -async def test_binary_sensor_device(hass, aioclient_mock): +async def test_binary_sensor_device(hass, aioclient_mock): # noqa """Test a binary sensor device.""" config = { 'qwikswitch': { @@ -75,7 +78,8 @@ async def test_binary_sensor_device(hass, aioclient_mock): hass.bus.async_fire(EVENT_HOMEASSISTANT_START) LISTEN.append('{"id":"@a00001","cmd":"","data":"4e0e1601","rssi":"61%"}') - LISTEN.append('') # Will cause a sleep + LISTEN.append(ClientError()) # Will cause a sleep + await hass.async_block_till_done() state_obj = hass.states.get('binary_sensor.s1') assert state_obj.state == 'on' @@ -87,7 +91,7 @@ async def test_binary_sensor_device(hass, aioclient_mock): assert state_obj.state == 'off' -async def test_sensor_device(hass, aioclient_mock): +async def test_sensor_device(hass, aioclient_mock): # noqa """Test a sensor device.""" config = { 'qwikswitch': { @@ -100,8 +104,8 @@ async def test_sensor_device(hass, aioclient_mock): } } await async_setup_component(hass, QWIKSWITCH, config) - await hass.async_block_till_done() + await hass.async_block_till_done() state_obj = hass.states.get('sensor.ss1') assert state_obj.state == 'None' @@ -110,8 +114,7 @@ async def test_sensor_device(hass, aioclient_mock): LISTEN.append( '{"id":"@a00001","name":"ss1","type":"rel",' '"val":"4733800001a00000"}') - LISTEN.append('') # Will cause a sleep - await LISTEN.wait_till_empty(hass) # await hass.async_block_till_done() + await hass.async_block_till_done() state_obj = hass.states.get('sensor.ss1') - assert state_obj.state == 'None' + assert state_obj.state == '416' From 48189dd15221bc1c088808750754f56d345e934f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 1 Apr 2019 21:51:43 -0700 Subject: [PATCH 041/167] Run PyLint under Python 3.5 (#22642) * Run PyLint under Python 3.5 * Remove -q from pip install to debug * Upgrade setuptools before install * Use correct cache key for pylint --- .circleci/config.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cde04d08e40..cfc968a1a6a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ executors: parameters: tag: type: string - default: latest + default: latest docker: - image: circleci/python:<< parameters.tag >> - image: circleci/buildpack-deps:stretch @@ -53,6 +53,7 @@ commands: python3 -m venv venv . venv/bin/activate pip install -q -U pip + pip install -q -U setuptools <<# parameters.all >>pip install -q --progress-bar off -r requirements_all.txt -c homeassistant/package_constraints.txt<> <<# parameters.test >>pip install -q --progress-bar off -r requirements_test.txt -c homeassistant/package_constraints.txt<> <<# parameters.test_all >>pip install -q --progress-bar off -r requirements_test_all.txt -c homeassistant/package_constraints.txt<> @@ -107,27 +108,27 @@ jobs: pre-install-all-requirements: executor: name: python - tag: 3.7-stretch + tag: 3.5.5-stretch steps: - checkout - docker-prereqs - install-requirements: - python: 3.7-stretch + python: 3.5.5-stretch all: true test: true pylint: executor: name: python - tag: 3.7-stretch + tag: 3.5.5-stretch parallelism: 2 steps: - checkout - docker-prereqs - install-requirements: - python: 3.7-stretch + python: 3.5.5-stretch all: true test: true - install From 16e0953f267f6b24cbbfebee282a48cb542f7bb4 Mon Sep 17 00:00:00 2001 From: Jc2k Date: Tue, 2 Apr 2019 08:57:58 +0100 Subject: [PATCH 042/167] Fix racy homekit_controller platform setup caused by #22368 (#22655) --- homeassistant/components/homekit_controller/__init__.py | 3 +-- homeassistant/components/homekit_controller/connection.py | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/homekit_controller/__init__.py b/homeassistant/components/homekit_controller/__init__.py index 44af8bffe26..2a43d0ac9ce 100644 --- a/homeassistant/components/homekit_controller/__init__.py +++ b/homeassistant/components/homekit_controller/__init__.py @@ -191,8 +191,7 @@ def setup(hass, config): return _LOGGER.debug('Discovered unique device %s', hkid) - device = HKDevice(hass, host, port, model, hkid, config_num, config) - hass.data[KNOWN_DEVICES][hkid] = device + HKDevice(hass, host, port, model, hkid, config_num, config) hass.data[KNOWN_DEVICES] = {} discovery.listen(hass, SERVICE_HOMEKIT, discovery_dispatch) diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py index d875b91eb2c..2ca568b547f 100644 --- a/homeassistant/components/homekit_controller/connection.py +++ b/homeassistant/components/homekit_controller/connection.py @@ -7,7 +7,8 @@ from homeassistant.helpers import discovery from homeassistant.helpers.event import call_later from .const import ( - CONTROLLER, DOMAIN, HOMEKIT_ACCESSORY_DISPATCH, PAIRING_FILE, HOMEKIT_DIR + CONTROLLER, DOMAIN, HOMEKIT_ACCESSORY_DISPATCH, KNOWN_DEVICES, + PAIRING_FILE, HOMEKIT_DIR ) @@ -76,6 +77,8 @@ class HKDevice(): self.pairing = self.controller.pairings.get(hkid) + hass.data[KNOWN_DEVICES][hkid] = self + if self.pairing is not None: self.accessory_setup() else: From 3bd37d6a657ff676c919515784cdb631c138e754 Mon Sep 17 00:00:00 2001 From: David Bonnes Date: Tue, 2 Apr 2019 14:11:26 +0100 Subject: [PATCH 043/167] Improve evohome exception handling and fix bugs (#22140) * Use latest client library, evohomeclient v0.3.1 * Fix issue #22097: Failed to call service climate/turn_on... * BUGFIX: handle case where a Zone doesn't have a temperature * BUGFIX: missing exception handler, and inappropriate delint hints * Improve exception handling, and also better messages * improve code (REDACT secrets); remove TODOs * minor refactor - improve error message * more refactoring - improve error message * remove TODOs * update to latest evohomeclient library * Use latest client library, evohomeclient v0.3.1 * Fix issue #22097: Failed to call service climate/turn_on... * BUGFIX: handle case where a Zone doesn't have a temperature * BUGFIX: missing exception handler, and inappropriate delint hints * Improve exception handling, and also better messages * improve code (REDACT secrets); remove TODOs * minor refactor - improve error message * more refactoring - improve error message * remove TODOs * update to latest evohomeclient library * fix requests for houndci-bot * Tidy up requests exception handling * Correct lint error * update to latest client library * minor de-lint * more cleanup of exceptions, messages * refactored for new exception * fix error in requirements*_all.txt * de-lint * delint unused import * import 3rd-party library only inside methods * change honeywell tests * delint, fix typo * we dont log usernames, passwords, etc. * de-lint --- homeassistant/components/evohome/__init__.py | 83 +++++++++--------- homeassistant/components/evohome/climate.py | 85 +++++++++++++------ homeassistant/components/honeywell/climate.py | 8 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/honeywell/test_climate.py | 5 +- 6 files changed, 107 insertions(+), 78 deletions(-) diff --git a/homeassistant/components/evohome/__init__.py b/homeassistant/components/evohome/__init__.py index 52bb77516e6..87a563ecd6d 100644 --- a/homeassistant/components/evohome/__init__.py +++ b/homeassistant/components/evohome/__init__.py @@ -8,20 +8,18 @@ from datetime import timedelta import logging -from requests.exceptions import HTTPError +import requests.exceptions import voluptuous as vol from homeassistant.const import ( CONF_SCAN_INTERVAL, CONF_USERNAME, CONF_PASSWORD, - EVENT_HOMEASSISTANT_START, - HTTP_BAD_REQUEST, HTTP_SERVICE_UNAVAILABLE, HTTP_TOO_MANY_REQUESTS -) + EVENT_HOMEASSISTANT_START) from homeassistant.core import callback import homeassistant.helpers.config_validation as cv from homeassistant.helpers.discovery import load_platform from homeassistant.helpers.dispatcher import async_dispatcher_send -REQUIREMENTS = ['evohomeclient==0.2.8'] +REQUIREMENTS = ['evohomeclient==0.3.2'] _LOGGER = logging.getLogger(__name__) @@ -43,6 +41,10 @@ CONFIG_SCHEMA = vol.Schema({ }), }, extra=vol.ALLOW_EXTRA) +CONF_SECRETS = [ + CONF_USERNAME, CONF_PASSWORD, +] + # These are used to help prevent E501 (line too long) violations. GWS = 'gateways' TCS = 'temperatureControlSystems' @@ -66,51 +68,40 @@ def setup(hass, hass_config): scan_interval = timedelta( minutes=(scan_interval.total_seconds() + 59) // 60) - from evohomeclient2 import EvohomeClient + import evohomeclient2 try: - client = EvohomeClient( + client = evo_data['client'] = evohomeclient2.EvohomeClient( evo_data['params'][CONF_USERNAME], evo_data['params'][CONF_PASSWORD], debug=False ) - except HTTPError as err: - if err.response.status_code == HTTP_BAD_REQUEST: - _LOGGER.error( - "setup(): Failed to connect with the vendor's web servers. " - "Check your username (%s), and password are correct." - "Unable to continue. Resolve any errors and restart HA.", - evo_data['params'][CONF_USERNAME] - ) - - elif err.response.status_code == HTTP_SERVICE_UNAVAILABLE: - _LOGGER.error( - "setup(): Failed to connect with the vendor's web servers. " - "The server is not contactable. Unable to continue. " - "Resolve any errors and restart HA." - ) - - elif err.response.status_code == HTTP_TOO_MANY_REQUESTS: - _LOGGER.error( - "setup(): Failed to connect with the vendor's web servers. " - "You have exceeded the api rate limit. Unable to continue. " - "Wait a while (say 10 minutes) and restart HA." - ) - - else: - raise # We don't expect/handle any other HTTPErrors - + except evohomeclient2.AuthenticationError as err: + _LOGGER.error( + "setup(): Failed to authenticate with the vendor's server. " + "Check your username and password are correct. " + "Resolve any errors and restart HA. Message is: %s", + err + ) return False - finally: # Redact username, password as no longer needed - evo_data['params'][CONF_USERNAME] = 'REDACTED' - evo_data['params'][CONF_PASSWORD] = 'REDACTED' + except requests.exceptions.ConnectionError: + _LOGGER.error( + "setup(): Unable to connect with the vendor's server. " + "Check your network and the vendor's status page. " + "Resolve any errors and restart HA." + ) + return False + + finally: # Redact any config data that's no longer needed + for parameter in CONF_SECRETS: + evo_data['params'][parameter] = 'REDACTED' \ + if evo_data['params'][parameter] else None - evo_data['client'] = client evo_data['status'] = {} - # Redact any installation data we'll never need + # Redact any installation data that's no longer needed for loc in client.installation_info: loc['locationInfo']['locationId'] = 'REDACTED' loc['locationInfo']['locationOwner'] = 'REDACTED' @@ -120,18 +111,21 @@ def setup(hass, hass_config): # Pull down the installation configuration loc_idx = evo_data['params'][CONF_LOCATION_IDX] - try: evo_data['config'] = client.installation_info[loc_idx] + except IndexError: - _LOGGER.warning( - "setup(): Parameter '%s'=%s, is outside its range (0-%s)", - CONF_LOCATION_IDX, loc_idx, len(client.installation_info) - 1) + _LOGGER.error( + "setup(): config error, '%s' = %s, but its valid range is 0-%s. " + "Unable to continue. Fix any configuration errors and restart HA.", + CONF_LOCATION_IDX, loc_idx, len(client.installation_info) - 1 + ) return False if _LOGGER.isEnabledFor(logging.DEBUG): tmp_loc = dict(evo_data['config']) tmp_loc['locationInfo']['postcode'] = 'REDACTED' + if 'dhw' in tmp_loc[GWS][0][TCS][0]: # if this location has DHW... tmp_loc[GWS][0][TCS][0]['dhw'] = '...' @@ -139,6 +133,11 @@ def setup(hass, hass_config): load_platform(hass, 'climate', DOMAIN, {}, hass_config) + if 'dhw' in evo_data['config'][GWS][0][TCS][0]: + _LOGGER.warning( + "setup(): DHW found, but this component doesn't support DHW." + ) + @callback def _first_update(event): """When HA has started, the hub knows to retrieve it's first update.""" diff --git a/homeassistant/components/evohome/climate.py b/homeassistant/components/evohome/climate.py index eea34e07001..cf6c21df10f 100644 --- a/homeassistant/components/evohome/climate.py +++ b/homeassistant/components/evohome/climate.py @@ -2,22 +2,22 @@ from datetime import datetime, timedelta import logging -from requests.exceptions import HTTPError +import requests.exceptions from homeassistant.components.climate import ClimateDevice from homeassistant.components.climate.const import ( STATE_AUTO, STATE_ECO, STATE_MANUAL, SUPPORT_AWAY_MODE, SUPPORT_ON_OFF, SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE) from homeassistant.const import ( - CONF_SCAN_INTERVAL, HTTP_TOO_MANY_REQUESTS, PRECISION_HALVES, STATE_OFF, - TEMP_CELSIUS) + CONF_SCAN_INTERVAL, HTTP_SERVICE_UNAVAILABLE, HTTP_TOO_MANY_REQUESTS, + PRECISION_HALVES, STATE_OFF, TEMP_CELSIUS) from homeassistant.core import callback from homeassistant.helpers.dispatcher import ( async_dispatcher_connect, dispatcher_send) from . import ( CONF_LOCATION_IDX, DATA_EVOHOME, DISPATCHER_EVOHOME, EVO_CHILD, EVO_PARENT, - GWS, SCAN_INTERVAL_DEFAULT, TCS) + GWS, TCS) _LOGGER = logging.getLogger(__name__) @@ -81,7 +81,7 @@ async def async_setup_platform(hass, hass_config, async_add_entities, # evohomeclient has exposed no means of accessing non-default location # (i.e. loc_idx > 0) other than using a protected member, such as below - tcs_obj_ref = client.locations[loc_idx]._gateways[0]._control_systems[0] # noqa E501; pylint: disable=protected-access + tcs_obj_ref = client.locations[loc_idx]._gateways[0]._control_systems[0] # noqa: E501; pylint: disable=protected-access _LOGGER.debug( "Found Controller, id=%s [%s], name=%s (location_idx=%s)", @@ -128,23 +128,43 @@ class EvoClimateDevice(ClimateDevice): if packet['to'] & self._type and packet['signal'] == 'refresh': self.async_schedule_update_ha_state(force_refresh=True) - def _handle_requests_exceptions(self, err): - if err.response.status_code == HTTP_TOO_MANY_REQUESTS: - # execute a backoff: pause, and also reduce rate - old_interval = self._params[CONF_SCAN_INTERVAL] - new_interval = min(old_interval, SCAN_INTERVAL_DEFAULT) * 2 - self._params[CONF_SCAN_INTERVAL] = new_interval + def _handle_exception(self, err): + try: + import evohomeclient2 + raise err + except evohomeclient2.AuthenticationError: + _LOGGER.error( + "Failed to (re)authenticate with the vendor's server. " + "This may be a temporary error. Message is: %s", + err + ) + + except requests.exceptions.ConnectionError: + # this appears to be common with Honeywell's servers _LOGGER.warning( - "API rate limit has been exceeded. Suspending polling for %s " - "seconds, and increasing '%s' from %s to %s seconds", - new_interval * 3, CONF_SCAN_INTERVAL, old_interval, - new_interval) + "Unable to connect with the vendor's server. " + "Check your network and the vendor's status page." + ) - self._timers['statusUpdated'] = datetime.now() + new_interval * 3 + except requests.exceptions.HTTPError: + if err.response.status_code == HTTP_SERVICE_UNAVAILABLE: + _LOGGER.warning( + "Vendor says their server is currently unavailable. " + "This may be temporary; check the vendor's status page." + ) - else: - raise err # we dont handle any other HTTPErrors + elif err.response.status_code == HTTP_TOO_MANY_REQUESTS: + _LOGGER.warning( + "The vendor's API rate limit has been exceeded. " + "So will cease polling, and will resume after %s seconds.", + (self._params[CONF_SCAN_INTERVAL] * 3).total_seconds() + ) + self._timers['statusUpdated'] = datetime.now() + \ + self._params[CONF_SCAN_INTERVAL] * 3 + + else: + raise # we don't expect/handle any other HTTPErrors @property def name(self) -> str: @@ -239,7 +259,8 @@ class EvoZone(EvoClimateDevice): @property def current_temperature(self): """Return the current temperature of the evohome Zone.""" - return self._status['temperatureStatus']['temperature'] + return (self._status['temperatureStatus']['temperature'] + if self._status['temperatureStatus']['isAvailable'] else None) @property def current_operation(self): @@ -284,9 +305,11 @@ class EvoZone(EvoClimateDevice): - None for PermanentOverride (i.e. indefinitely) """ try: + import evohomeclient2 self._obj.set_temperature(temperature, until) - except HTTPError as err: - self._handle_exception("HTTPError", str(err)) # noqa: E501; pylint: disable=no-member + except (requests.exceptions.RequestException, + evohomeclient2.AuthenticationError) as err: + self._handle_exception(err) def set_temperature(self, **kwargs): """Set new target temperature, indefinitely.""" @@ -334,9 +357,11 @@ class EvoZone(EvoClimateDevice): def _set_operation_mode(self, operation_mode): if operation_mode == EVO_FOLLOW: try: - self._obj.cancel_temp_override(self._obj) - except HTTPError as err: - self._handle_exception("HTTPError", str(err)) # noqa: E501; pylint: disable=no-member + import evohomeclient2 + self._obj.cancel_temp_override() + except (requests.exceptions.RequestException, + evohomeclient2.AuthenticationError) as err: + self._handle_exception(err) elif operation_mode == EVO_TEMPOVER: _LOGGER.error( @@ -496,9 +521,11 @@ class EvoController(EvoClimateDevice): def _set_operation_mode(self, operation_mode): try: + import evohomeclient2 self._obj._set_status(operation_mode) # noqa: E501; pylint: disable=protected-access - except HTTPError as err: - self._handle_requests_exceptions(err) + except (requests.exceptions.RequestException, + evohomeclient2.AuthenticationError) as err: + self._handle_exception(err) def set_operation_mode(self, operation_mode): """Set new target operation mode for the TCS. @@ -532,10 +559,12 @@ class EvoController(EvoClimateDevice): loc_idx = self._params[CONF_LOCATION_IDX] try: + import evohomeclient2 self._status.update( self._client.locations[loc_idx].status()[GWS][0][TCS][0]) - except HTTPError as err: # check if we've exceeded the api rate limit - self._handle_requests_exceptions(err) + except (requests.exceptions.RequestException, + evohomeclient2.AuthenticationError) as err: + self._handle_exception(err) else: self._timers['statusUpdated'] = datetime.now() self._available = True diff --git a/homeassistant/components/honeywell/climate.py b/homeassistant/components/honeywell/climate.py index a76f992a76a..55a7fb5aa48 100644 --- a/homeassistant/components/honeywell/climate.py +++ b/homeassistant/components/honeywell/climate.py @@ -5,7 +5,6 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/climate.honeywell/ """ import logging -import socket import datetime import requests @@ -21,7 +20,7 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_USERNAME, TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_TEMPERATURE, CONF_REGION) -REQUIREMENTS = ['evohomeclient==0.2.8', 'somecomfort==0.5.2'] +REQUIREMENTS = ['evohomeclient==0.3.2', 'somecomfort==0.5.2'] _LOGGER = logging.getLogger(__name__) @@ -78,9 +77,10 @@ def _setup_round(username, password, config, add_entities): [RoundThermostat(evo_api, zone['id'], i == 0, away_temp)], True ) - except socket.error: + except requests.exceptions.RequestException as err: _LOGGER.error( - "Connection error logging into the honeywell evohome web service") + "Connection error logging into the honeywell evohome web service, " + "hint: %s", err) return False return True diff --git a/requirements_all.txt b/requirements_all.txt index 1ef9af9c970..8c85c9edbc5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -414,7 +414,7 @@ eternalegypt==0.0.6 # homeassistant.components.evohome # homeassistant.components.honeywell.climate -evohomeclient==0.2.8 +evohomeclient==0.3.2 # homeassistant.components.dlib_face_detect.image_processing # homeassistant.components.dlib_face_identify.image_processing diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 5d58e42e8b2..e08255c246d 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -92,7 +92,7 @@ ephem==3.7.6.0 # homeassistant.components.evohome # homeassistant.components.honeywell.climate -evohomeclient==0.2.8 +evohomeclient==0.3.2 # homeassistant.components.feedreader feedparser-homeassistant==5.2.2.dev1 diff --git a/tests/components/honeywell/test_climate.py b/tests/components/honeywell/test_climate.py index e8e0c0a2929..2674dac6b1e 100644 --- a/tests/components/honeywell/test_climate.py +++ b/tests/components/honeywell/test_climate.py @@ -1,9 +1,9 @@ """The test the Honeywell thermostat module.""" -import socket import unittest from unittest import mock import voluptuous as vol +import requests.exceptions import somecomfort from homeassistant.const import ( @@ -247,7 +247,8 @@ class TestHoneywell(unittest.TestCase): honeywell.CONF_AWAY_TEMPERATURE: 20, honeywell.CONF_REGION: 'eu', } - mock_evo.return_value.temperatures.side_effect = socket.error + mock_evo.return_value.temperatures.side_effect = \ + requests.exceptions.RequestException add_entities = mock.MagicMock() hass = mock.MagicMock() assert not honeywell.setup_platform(hass, config, add_entities) From 04271549633b612834ee560b123ab9279280e3ea Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Tue, 2 Apr 2019 11:28:55 -0400 Subject: [PATCH 044/167] Don't force updates on ZHA Electrical Measurement sensor. (#22647) --- homeassistant/components/zha/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/zha/sensor.py b/homeassistant/components/zha/sensor.py index 56ce97c87a0..d45d8f8c30d 100644 --- a/homeassistant/components/zha/sensor.py +++ b/homeassistant/components/zha/sensor.py @@ -86,7 +86,7 @@ POLLING_REGISTRY = { } FORCE_UPDATE_REGISTRY = { - ELECTRICAL_MEASUREMENT: True + ELECTRICAL_MEASUREMENT: False } From b8b3f4e88fc66a916664f515d616b19ded019bc4 Mon Sep 17 00:00:00 2001 From: cgtobi Date: Tue, 2 Apr 2019 18:31:29 +0200 Subject: [PATCH 045/167] Fix pytest durations parameter (#22658) * Fix durations parameter * Update config.yml --- .circleci/config.yml | 2 +- tox.ini | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cfc968a1a6a..b1fdc2be93b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -178,7 +178,7 @@ jobs: . venv/bin/activate CC_SWITCH="--cov --cov-report=" TESTFILES=$(circleci tests glob "tests/**/test_*.py" | circleci tests split --split-by=timings) - pytest --timeout=9 --duration=10 --junitxml=test-reports/homeassistant/results.xml -qq -o junit_family=xunit2 -o junit_suite_name=homeassistant -o console_output_style=count -p no:sugar $CC_SWITCH -- ${TESTFILES} + pytest --timeout=9 --durations=10 --junitxml=test-reports/homeassistant/results.xml -qq -o junit_family=xunit2 -o junit_suite_name=homeassistant -o console_output_style=count -p no:sugar $CC_SWITCH -- ${TESTFILES} script/check_dirty codecov diff --git a/tox.ini b/tox.ini index b8995d9e877..d0c4336f544 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ skip_missing_interpreters = True [testenv] basepython = {env:PYTHON3_PATH:python3} commands = - pytest --timeout=9 --duration=10 -qq -o console_output_style=count -p no:sugar {posargs} + pytest --timeout=9 --durations=10 -qq -o console_output_style=count -p no:sugar {posargs} {toxinidir}/script/check_dirty deps = -r{toxinidir}/requirements_test_all.txt @@ -13,7 +13,7 @@ deps = [testenv:cov] commands = - pytest --timeout=9 --duration=10 -qq -o console_output_style=count -p no:sugar --cov --cov-report= {posargs} + pytest --timeout=9 --durations=10 -qq -o console_output_style=count -p no:sugar --cov --cov-report= {posargs} {toxinidir}/script/check_dirty deps = -r{toxinidir}/requirements_test_all.txt From e00ae35e07b571d6cdc1c69cc68f81798792e89e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 2 Apr 2019 09:34:11 -0700 Subject: [PATCH 046/167] Admin service to automatically add empty schema (#22637) * Admin service to automatically add empty schema * Lint --- homeassistant/components/cloud/__init__.py | 5 ++--- homeassistant/helpers/service.py | 7 ++++--- tests/helpers/test_service.py | 21 +++++++++++++++++++-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/cloud/__init__.py b/homeassistant/components/cloud/__init__.py index fca5b292033..41045ba1f91 100644 --- a/homeassistant/components/cloud/__init__.py +++ b/homeassistant/components/cloud/__init__.py @@ -187,11 +187,10 @@ async def async_setup(hass, config): await cloud.remote.disconnect() await prefs.async_update(remote_enabled=False) - empty_schema = vol.Schema({}) hass.helpers.service.async_register_admin_service( - DOMAIN, SERVICE_REMOTE_CONNECT, _service_handler, empty_schema) + DOMAIN, SERVICE_REMOTE_CONNECT, _service_handler) hass.helpers.service.async_register_admin_service( - DOMAIN, SERVICE_REMOTE_DISCONNECT, _service_handler, empty_schema) + DOMAIN, SERVICE_REMOTE_DISCONNECT, _service_handler) await http_api.async_setup(hass) hass.async_create_task(hass.helpers.discovery.async_load_platform( diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index f8af3bdb1c5..3892dbb6607 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -333,9 +333,10 @@ async def _handle_service_platform_call(func, data, entities, context): @bind_hass @ha.callback -def async_register_admin_service(hass: typing.HomeAssistantType, domain: str, - service: str, service_func: Callable, - schema: vol.Schema) -> None: +def async_register_admin_service( + hass: typing.HomeAssistantType, domain: str, + service: str, service_func: Callable, + schema: vol.Schema = vol.Schema({}, extra=vol.PREVENT_EXTRA)) -> None: """Register a service that requires admin access.""" @wraps(service_func) async def admin_handler(call): diff --git a/tests/helpers/test_service.py b/tests/helpers/test_service.py index a36785b6ba0..f59a01ec268 100644 --- a/tests/helpers/test_service.py +++ b/tests/helpers/test_service.py @@ -406,7 +406,11 @@ async def test_register_admin_service(hass, hass_read_only_user, calls.append(call) hass.helpers.service.async_register_admin_service( - 'test', 'test', mock_service, vol.Schema({}) + 'test', 'test', mock_service + ) + hass.helpers.service.async_register_admin_service( + 'test', 'test2', mock_service, + vol.Schema({vol.Required('required'): cv.boolean}) ) with pytest.raises(exceptions.UnknownUser): @@ -423,8 +427,21 @@ async def test_register_admin_service(hass, hass_read_only_user, )) assert len(calls) == 0 + with pytest.raises(vol.Invalid): + await hass.services.async_call( + 'test', 'test', {'invalid': True}, blocking=True, + context=ha.Context(user_id=hass_admin_user.id)) + assert len(calls) == 0 + + with pytest.raises(vol.Invalid): + await hass.services.async_call( + 'test', 'test2', {}, blocking=True, context=ha.Context( + user_id=hass_admin_user.id + )) + assert len(calls) == 0 + await hass.services.async_call( - 'test', 'test', {}, blocking=True, context=ha.Context( + 'test', 'test2', {'required': True}, blocking=True, context=ha.Context( user_id=hass_admin_user.id )) assert len(calls) == 1 From d6e28621151aa6e71046a252a4b708197eb2fa94 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 2 Apr 2019 09:51:44 -0700 Subject: [PATCH 047/167] Ignore code coverages for component without test (#22653) --- .coveragerc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.coveragerc b/.coveragerc index 145efe5c847..cae3bf423a9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -21,6 +21,7 @@ omit = homeassistant/components/alarmdecoder/* homeassistant/components/alarmdotcom/alarm_control_panel.py homeassistant/components/alpha_vantage/sensor.py + homeassistant/components/amazon_polly/tts.py homeassistant/components/ambient_station/* homeassistant/components/amcrest/* homeassistant/components/ampio/* @@ -49,6 +50,7 @@ omit = homeassistant/components/aws_lambda/notify.py homeassistant/components/aws_sns/notify.py homeassistant/components/aws_sqs/notify.py + homeassistant/components/baidu/tts.py homeassistant/components/bbb_gpio/* homeassistant/components/bbox/device_tracker.py homeassistant/components/bbox/sensor.py @@ -93,6 +95,7 @@ omit = homeassistant/components/clicksend_tts/notify.py homeassistant/components/cloudflare/* homeassistant/components/cmus/media_player.py + homeassistant/components/co2signal/* homeassistant/components/coinbase/* homeassistant/components/comed_hourly_pricing/sensor.py homeassistant/components/comfoconnect/* @@ -342,6 +345,7 @@ omit = homeassistant/components/meteo_france/* homeassistant/components/metoffice/sensor.py homeassistant/components/metoffice/weather.py + homeassistant/components/microsoft/tts.py homeassistant/components/miflora/sensor.py homeassistant/components/mikrotik/device_tracker.py homeassistant/components/mill/climate.py @@ -423,6 +427,7 @@ omit = homeassistant/components/pencom/switch.py homeassistant/components/philips_js/media_player.py homeassistant/components/pi_hole/sensor.py + homeassistant/components/picotts/tts.py homeassistant/components/piglow/light.py homeassistant/components/pilight/* homeassistant/components/ping/binary_sensor.py @@ -606,10 +611,6 @@ omit = homeassistant/components/trafikverket_weatherstation/sensor.py homeassistant/components/transmission/* homeassistant/components/travisci/sensor.py - homeassistant/components/tts/amazon_polly.py - homeassistant/components/tts/baidu.py - homeassistant/components/tts/microsoft.py - homeassistant/components/tts/picotts.py homeassistant/components/tuya/* homeassistant/components/twilio_call/notify.py homeassistant/components/twilio_sms/notify.py @@ -651,6 +652,7 @@ omit = homeassistant/components/wirelesstag/* homeassistant/components/worldtidesinfo/sensor.py homeassistant/components/worxlandroid/sensor.py + homeassistant/components/wunderlist/* homeassistant/components/x10/light.py homeassistant/components/xbox_live/sensor.py homeassistant/components/xeoma/camera.py @@ -664,7 +666,7 @@ omit = homeassistant/components/yale_smart_alarm/alarm_control_panel.py homeassistant/components/yamaha/media_player.py homeassistant/components/yamaha_musiccast/media_player.py - homeassistant/components/yeelight/light.py + homeassistant/components/yeelight/* homeassistant/components/yeelightsunflower/light.py homeassistant/components/yi/camera.py homeassistant/components/zabbix/* From 429e2cdde8fe7209e2fe54aef6b50b94ec66ef17 Mon Sep 17 00:00:00 2001 From: Chris Helming Date: Tue, 2 Apr 2019 12:59:38 -0400 Subject: [PATCH 048/167] Return 0 for failed Foscam streams (#22651) * Update Foscam to support stream source * Removing spaces and tabs * Changing to Python3-style string formatting * Adding '_media_port' to hopefully cover other models * changing logic for success and return none --- homeassistant/components/foscam/camera.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/foscam/camera.py b/homeassistant/components/foscam/camera.py index a11d2f48f62..b6f2162d57a 100644 --- a/homeassistant/components/foscam/camera.py +++ b/homeassistant/components/foscam/camera.py @@ -58,7 +58,10 @@ class FoscamCam(Camera): self._foscam_session = FoscamCamera( ip_address, port, self._username, self._password, verbose=False) - self._media_port = self._foscam_session.get_port_info()[1]['mediaPort'] + self._media_port = None + result, response = self._foscam_session.get_port_info() + if result == 0: + self._media_port = response['mediaPort'] def camera_image(self): """Return a still image response from the camera.""" @@ -73,16 +76,20 @@ class FoscamCam(Camera): @property def supported_features(self): """Return supported features.""" - return SUPPORT_STREAM + if self._media_port: + return SUPPORT_STREAM + return 0 @property def stream_source(self): """Return the stream source.""" - return 'rtsp://{}:{}@{}:{}/videoMain'.format( - self._username, - self._password, - self._foscam_session.host, - self._media_port) + if self._media_port: + return 'rtsp://{}:{}@{}:{}/videoMain'.format( + self._username, + self._password, + self._foscam_session.host, + self._media_port) + return None @property def motion_detection_enabled(self): From 6c14e7afa7ff12dfadd673ef6f337d9ee56770fe Mon Sep 17 00:00:00 2001 From: Markus Jankowski Date: Tue, 2 Apr 2019 19:29:48 +0200 Subject: [PATCH 049/167] Add battery sensor to Homematic IP (#22630) --- .../homematicip_cloud/binary_sensor.py | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/binary_sensor.py b/homeassistant/components/homematicip_cloud/binary_sensor.py index 786a28a70a5..071b4a0a3fb 100644 --- a/homeassistant/components/homematicip_cloud/binary_sensor.py +++ b/homeassistant/components/homematicip_cloud/binary_sensor.py @@ -29,8 +29,8 @@ async def async_setup_platform( async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the HomematicIP Cloud binary sensor from a config entry.""" from homematicip.aio.device import ( - AsyncShutterContact, AsyncMotionDetectorIndoor, AsyncSmokeDetector, - AsyncWaterSensor, AsyncRotaryHandleSensor, + AsyncDevice, AsyncShutterContact, AsyncMotionDetectorIndoor, + AsyncSmokeDetector, AsyncWaterSensor, AsyncRotaryHandleSensor, AsyncMotionDetectorPushButton, AsyncWeatherSensor, AsyncWeatherSensorPlus, AsyncWeatherSensorPro) @@ -56,6 +56,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): AsyncWeatherSensorPro)): devices.append(HomematicipStormSensor(home, device)) devices.append(HomematicipSunshineSensor(home, device)) + if isinstance(device, AsyncDevice) and device.lowBat is not None: + devices.append(HomematicipBatterySensor(home, device)) for group in home.groups: if isinstance(group, AsyncSecurityGroup): @@ -197,6 +199,24 @@ class HomematicipSunshineSensor(HomematicipGenericDevice, BinarySensorDevice): return attr +class HomematicipBatterySensor(HomematicipGenericDevice, BinarySensorDevice): + """Representation of a HomematicIP Cloud low battery sensor.""" + + def __init__(self, home, device): + """Initialize battery sensor.""" + super().__init__(home, device, 'Battery') + + @property + def device_class(self): + """Return the class of this sensor.""" + return 'battery' + + @property + def is_on(self): + """Return true if battery is low.""" + return self._device.lowBat + + class HomematicipSecurityZoneSensorGroup(HomematicipGenericDevice, BinarySensorDevice): """Representation of a HomematicIP Cloud security zone group.""" From 8a0b210f87bafd80d638dae90ecc15e11e797a63 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Tue, 2 Apr 2019 20:13:11 +0200 Subject: [PATCH 050/167] Axis discovery updates host address (#22632) * Discovery can update host on existing entries * Add support in device to update host on entry update * Fix tests and listener * Fix hound comment * Fix failing tests from cleanup --- homeassistant/components/axis/__init__.py | 16 ++++----- homeassistant/components/axis/camera.py | 11 +++--- homeassistant/components/axis/config_flow.py | 29 ++++++++++------ homeassistant/components/axis/device.py | 20 ++++++++++- tests/components/axis/test_config_flow.py | 35 ++++++++++++-------- tests/components/axis/test_device.py | 30 +++++++++++++++-- tests/components/axis/test_init.py | 12 +++---- 7 files changed, 104 insertions(+), 49 deletions(-) diff --git a/homeassistant/components/axis/__init__.py b/homeassistant/components/axis/__init__.py index 6082c96863f..e9ed37477a5 100644 --- a/homeassistant/components/axis/__init__.py +++ b/homeassistant/components/axis/__init__.py @@ -4,11 +4,10 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.const import ( - CONF_DEVICE, CONF_HOST, CONF_NAME, CONF_TRIGGER_TIME, - EVENT_HOMEASSISTANT_STOP) + CONF_DEVICE, CONF_NAME, CONF_TRIGGER_TIME, EVENT_HOMEASSISTANT_STOP) from homeassistant.helpers import config_validation as cv -from .config_flow import configured_devices, DEVICE_SCHEMA +from .config_flow import DEVICE_SCHEMA from .const import CONF_CAMERA, CONF_EVENTS, DEFAULT_TRIGGER_TIME, DOMAIN from .device import AxisNetworkDevice, get_device @@ -21,18 +20,17 @@ CONFIG_SCHEMA = vol.Schema({ async def async_setup(hass, config): """Set up for Axis devices.""" - if DOMAIN in config: + if not hass.config_entries.async_entries(DOMAIN) and DOMAIN in config: for device_name, device_config in config[DOMAIN].items(): if CONF_NAME not in device_config: device_config[CONF_NAME] = device_name - if device_config[CONF_HOST] not in configured_devices(hass): - hass.async_create_task(hass.config_entries.flow.async_init( - DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, - data=device_config - )) + hass.async_create_task(hass.config_entries.flow.async_init( + DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, + data=device_config + )) return True diff --git a/homeassistant/components/axis/camera.py b/homeassistant/components/axis/camera.py index 34b6da778a8..ec1d761d3d0 100644 --- a/homeassistant/components/axis/camera.py +++ b/homeassistant/components/axis/camera.py @@ -52,8 +52,7 @@ class AxisCamera(MjpegCamera): async def async_added_to_hass(self): """Subscribe camera events.""" self.unsub_dispatcher.append(async_dispatcher_connect( - self.hass, 'axis_{}_new_ip'.format(self.device.name), - self._new_ip)) + self.hass, self.device.event_new_address, self._new_address)) self.unsub_dispatcher.append(async_dispatcher_connect( self.hass, self.device.event_reachable, self.update_callback)) @@ -67,10 +66,10 @@ class AxisCamera(MjpegCamera): """Return True if device is available.""" return self.device.available - def _new_ip(self, host): - """Set new IP for video stream.""" - self._mjpeg_url = AXIS_VIDEO.format(host, self.port) - self._still_image_url = AXIS_IMAGE.format(host, self.port) + def _new_address(self): + """Set new device address for video stream.""" + self._mjpeg_url = AXIS_VIDEO.format(self.device.host, self.port) + self._still_image_url = AXIS_IMAGE.format(self.device.host, self.port) @property def unique_id(self): diff --git a/homeassistant/components/axis/config_flow.py b/homeassistant/components/axis/config_flow.py index 24c286b140a..54d93f768d2 100644 --- a/homeassistant/components/axis/config_flow.py +++ b/homeassistant/components/axis/config_flow.py @@ -40,8 +40,8 @@ DEVICE_SCHEMA = vol.Schema({ @callback def configured_devices(hass): """Return a set of the configured devices.""" - return set(entry.data[CONF_DEVICE][CONF_HOST] for entry - in hass.config_entries.async_entries(DOMAIN)) + return {entry.data[CONF_MAC]: entry for entry + in hass.config_entries.async_entries(DOMAIN)} @config_entries.HANDLERS.register(DOMAIN) @@ -71,9 +71,6 @@ class AxisFlowHandler(config_entries.ConfigFlow): if user_input is not None: try: - if user_input[CONF_HOST] in configured_devices(self.hass): - raise AlreadyConfigured - self.device_config = { CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT], @@ -84,6 +81,10 @@ class AxisFlowHandler(config_entries.ConfigFlow): self.serial_number = device.vapix.get_param( VAPIX_SERIAL_NUMBER) + + if self.serial_number in configured_devices(self.hass): + raise AlreadyConfigured + self.model = device.vapix.get_param(VAPIX_MODEL_ID) return await self._create_entry() @@ -142,22 +143,30 @@ class AxisFlowHandler(config_entries.ConfigFlow): data=data ) + async def _update_entry(self, entry, host): + """Update existing entry if it is the same device.""" + entry.data[CONF_DEVICE][CONF_HOST] = host + self.hass.config_entries.async_update_entry(entry) + async def async_step_discovery(self, discovery_info): """Prepare configuration for a discovered Axis device. This flow is triggered by the discovery component. """ - if discovery_info[CONF_HOST] in configured_devices(self.hass): - return self.async_abort(reason='already_configured') - if discovery_info[CONF_HOST].startswith('169.254'): return self.async_abort(reason='link_local_address') + serialnumber = discovery_info['properties']['macaddress'] + device_entries = configured_devices(self.hass) + + if serialnumber in device_entries: + entry = device_entries[serialnumber] + await self._update_entry(entry, discovery_info[CONF_HOST]) + return self.async_abort(reason='already_configured') + config_file = await self.hass.async_add_executor_job( load_json, self.hass.config.path(CONFIG_FILE)) - serialnumber = discovery_info['properties']['macaddress'] - if serialnumber not in config_file: self.discovery_schema = { vol.Required( diff --git a/homeassistant/components/axis/device.py b/homeassistant/components/axis/device.py index 746808e0d91..3b3a35f1a2d 100644 --- a/homeassistant/components/axis/device.py +++ b/homeassistant/components/axis/device.py @@ -101,8 +101,26 @@ class AxisNetworkDevice: self.api.enable_events(event_callback=self.async_event_callback) self.api.start() + self.config_entry.add_update_listener(self.async_new_address_callback) + return True + @property + def event_new_address(self): + """Device specific event to signal new device address.""" + return 'axis_new_address_{}'.format(self.serial) + + @staticmethod + async def async_new_address_callback(hass, entry): + """Handle signals of device getting new address. + + This is a static method because a class method (bound method), + can not be used with weak references. + """ + device = hass.data[DOMAIN][entry.data[CONF_MAC]] + device.api.config.host = device.host + async_dispatcher_send(hass, device.event_new_address) + @property def event_reachable(self): """Device specific event to signal a change in connection status.""" @@ -110,7 +128,7 @@ class AxisNetworkDevice: @callback def async_connection_status_callback(self, status): - """Handle signals of gateway connection status. + """Handle signals of device connection status. This is called on every RTSP keep-alive message. Only signal state change if state change is true. diff --git a/tests/components/axis/test_config_flow.py b/tests/components/axis/test_config_flow.py index 086c2692d44..d78123abb79 100644 --- a/tests/components/axis/test_config_flow.py +++ b/tests/components/axis/test_config_flow.py @@ -16,7 +16,7 @@ async def test_configured_devices(hass): assert not result entry = MockConfigEntry(domain=axis.DOMAIN, - data={axis.CONF_DEVICE: {axis.CONF_HOST: ''}}) + data={axis.config_flow.CONF_MAC: '1234'}) entry.add_to_hass(hass) result = config_flow.configured_devices(hass) @@ -76,17 +76,21 @@ async def test_flow_fails_already_configured(hass): flow = config_flow.AxisFlowHandler() flow.hass = hass - entry = MockConfigEntry(domain=axis.DOMAIN, data={axis.CONF_DEVICE: { - axis.CONF_HOST: '1.2.3.4' - }}) + entry = MockConfigEntry(domain=axis.DOMAIN, + data={axis.config_flow.CONF_MAC: '1234'}) entry.add_to_hass(hass) - result = await flow.async_step_user(user_input={ - config_flow.CONF_HOST: '1.2.3.4', - config_flow.CONF_USERNAME: 'user', - config_flow.CONF_PASSWORD: 'pass', - config_flow.CONF_PORT: 81 - }) + mock_device = Mock() + mock_device.vapix.get_param.return_value = '1234' + + with patch('homeassistant.components.axis.config_flow.get_device', + return_value=mock_coro(mock_device)): + result = await flow.async_step_user(user_input={ + config_flow.CONF_HOST: '1.2.3.4', + config_flow.CONF_USERNAME: 'user', + config_flow.CONF_PASSWORD: 'pass', + config_flow.CONF_PORT: 81 + }) assert result['errors'] == {'base': 'already_configured'} @@ -220,16 +224,19 @@ async def test_discovery_flow_already_configured(hass): flow = config_flow.AxisFlowHandler() flow.hass = hass - entry = MockConfigEntry(domain=axis.DOMAIN, data={axis.CONF_DEVICE: { - axis.CONF_HOST: '1.2.3.4' - }}) + entry = MockConfigEntry( + domain=axis.DOMAIN, + data={axis.CONF_DEVICE: {axis.config_flow.CONF_HOST: '1.2.3.4'}, + axis.config_flow.CONF_MAC: '1234ABCD'} + ) entry.add_to_hass(hass) result = await flow.async_step_discovery(discovery_info={ config_flow.CONF_HOST: '1.2.3.4', config_flow.CONF_USERNAME: 'user', config_flow.CONF_PASSWORD: 'pass', - config_flow.CONF_PORT: 81 + config_flow.CONF_PORT: 81, + 'properties': {'macaddress': '1234ABCD'} }) print(result) assert result['type'] == 'abort' diff --git a/tests/components/axis/test_device.py b/tests/components/axis/test_device.py index 72d426819c6..35e350b323c 100644 --- a/tests/components/axis/test_device.py +++ b/tests/components/axis/test_device.py @@ -3,9 +3,10 @@ from unittest.mock import Mock, patch import pytest -from tests.common import mock_coro +from tests.common import mock_coro, MockConfigEntry from homeassistant.components.axis import device, errors +from homeassistant.components.axis.camera import AxisCamera DEVICE_DATA = { device.CONF_HOST: '1.2.3.4', @@ -16,7 +17,7 @@ DEVICE_DATA = { ENTRY_OPTIONS = { device.CONF_CAMERA: True, - device.CONF_EVENTS: ['pir'], + device.CONF_EVENTS: True, } ENTRY_CONFIG = { @@ -53,6 +54,31 @@ async def test_device_setup(): (entry, 'binary_sensor') +async def test_device_signal_new_address(hass): + """Successful setup.""" + entry = MockConfigEntry( + domain=device.DOMAIN, data=ENTRY_CONFIG, options=ENTRY_OPTIONS) + + api = Mock() + api.vapix.get_param.return_value = '1234' + + axis_device = device.AxisNetworkDevice(hass, entry) + hass.data[device.DOMAIN] = {axis_device.serial: axis_device} + + with patch.object(device, 'get_device', return_value=mock_coro(api)), \ + patch.object(AxisCamera, '_new_address') as new_address_mock: + await axis_device.async_setup() + await hass.async_block_till_done() + + entry.data[device.CONF_DEVICE][device.CONF_HOST] = '2.3.4.5' + hass.config_entries.async_update_entry(entry, data=entry.data) + await hass.async_block_till_done() + + assert axis_device.host == '2.3.4.5' + assert axis_device.api.config.host == '2.3.4.5' + assert len(new_address_mock.mock_calls) == 1 + + async def test_device_not_accessible(): """Failed setup schedules a retry of setup.""" hass = Mock() diff --git a/tests/components/axis/test_init.py b/tests/components/axis/test_init.py index c1c4c06f6ac..737c210b2aa 100644 --- a/tests/components/axis/test_init.py +++ b/tests/components/axis/test_init.py @@ -9,30 +9,28 @@ from tests.common import mock_coro, MockConfigEntry async def test_setup(hass): """Test configured options for a device are loaded via config entry.""" - with patch.object(hass, 'config_entries') as mock_config_entries, \ - patch.object(axis, 'configured_devices', return_value={}): + with patch.object(hass.config_entries, 'flow') as mock_config_flow: assert await async_setup_component(hass, axis.DOMAIN, { axis.DOMAIN: { 'device_name': { - axis.CONF_HOST: '1.2.3.4', + axis.config_flow.CONF_HOST: '1.2.3.4', axis.config_flow.CONF_PORT: 80, } } }) - assert len(mock_config_entries.flow.mock_calls) == 1 + assert len(mock_config_flow.mock_calls) == 1 async def test_setup_device_already_configured(hass): """Test already configured device does not configure a second.""" - with patch.object(hass, 'config_entries') as mock_config_entries, \ - patch.object(axis, 'configured_devices', return_value={'1.2.3.4'}): + with patch.object(hass, 'config_entries') as mock_config_entries: assert await async_setup_component(hass, axis.DOMAIN, { axis.DOMAIN: { 'device_name': { - axis.CONF_HOST: '1.2.3.4' + axis.config_flow.CONF_HOST: '1.2.3.4' } } }) From 8a86a790408b8fdac7ce458fad8b3730919c8d80 Mon Sep 17 00:00:00 2001 From: OleksandrBerchenko Date: Tue, 2 Apr 2019 21:14:46 +0300 Subject: [PATCH 051/167] Add missing properties and scenes support to Osram Lightify (#22597) * Rewrite Osram Lightify component * Update python-lightify version to 1.0.7.2 * Remove unneeded code * 1. Remove changes in light/__init__.py, 2. Set properties to None by default * Fix typo * Implement missing features (including scenes) * Make input parameters to setup_platform standardized --- .../components/osramlightify/light.py | 76 ++++++++++++++++++- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/osramlightify/light.py b/homeassistant/components/osramlightify/light.py index 59cc2bac5d6..81b8e2a88ec 100644 --- a/homeassistant/components/osramlightify/light.py +++ b/homeassistant/components/osramlightify/light.py @@ -26,11 +26,15 @@ _LOGGER = logging.getLogger(__name__) CONF_ALLOW_LIGHTIFY_NODES = 'allow_lightify_nodes' CONF_ALLOW_LIGHTIFY_GROUPS = 'allow_lightify_groups' +CONF_ALLOW_LIGHTIFY_SENSORS = 'allow_lightify_sensors' +CONF_ALLOW_LIGHTIFY_SWITCHES = 'allow_lightify_switches' CONF_INTERVAL_LIGHTIFY_STATUS = 'interval_lightify_status' CONF_INTERVAL_LIGHTIFY_CONF = 'interval_lightify_conf' DEFAULT_ALLOW_LIGHTIFY_NODES = True DEFAULT_ALLOW_LIGHTIFY_GROUPS = True +DEFAULT_ALLOW_LIGHTIFY_SENSORS = True +DEFAULT_ALLOW_LIGHTIFY_SWITCHES = True DEFAULT_INTERVAL_LIGHTIFY_STATUS = 5 DEFAULT_INTERVAL_LIGHTIFY_CONF = 3600 @@ -40,6 +44,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ default=DEFAULT_ALLOW_LIGHTIFY_NODES): cv.boolean, vol.Optional(CONF_ALLOW_LIGHTIFY_GROUPS, default=DEFAULT_ALLOW_LIGHTIFY_GROUPS): cv.boolean, + vol.Optional(CONF_ALLOW_LIGHTIFY_SENSORS, + default=DEFAULT_ALLOW_LIGHTIFY_SENSORS): cv.boolean, + vol.Optional(CONF_ALLOW_LIGHTIFY_SWITCHES, + default=DEFAULT_ALLOW_LIGHTIFY_SWITCHES): cv.boolean, vol.Optional(CONF_INTERVAL_LIGHTIFY_STATUS, default=DEFAULT_INTERVAL_LIGHTIFY_STATUS): cv.positive_int, vol.Optional(CONF_INTERVAL_LIGHTIFY_CONF, @@ -50,7 +58,7 @@ DEFAULT_BRIGHTNESS = 2 DEFAULT_KELVIN = 2700 -def setup_platform(_hass, config, add_entities, _discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Osram Lightify lights.""" import lightify @@ -88,6 +96,12 @@ def setup_bridge(bridge, add_entities, config): if new_lights and config[CONF_ALLOW_LIGHTIFY_NODES]: new_entities = [] for addr, light in new_lights.items(): + if ((light.devicetype().name == 'SENSOR' + and not config[CONF_ALLOW_LIGHTIFY_SENSORS]) or + (light.devicetype().name == 'SWITCH' + and not config[CONF_ALLOW_LIGHTIFY_SWITCHES])): + continue + if addr not in lights: osram_light = OsramLightifyLight(light, update_lights, lights_changed) @@ -105,14 +119,15 @@ def setup_bridge(bridge, add_entities, config): lights_changed = update_lights() try: + bridge.update_scene_list(config[CONF_INTERVAL_LIGHTIFY_CONF]) new_groups = bridge.update_group_list( config[CONF_INTERVAL_LIGHTIFY_CONF]) groups_updated = bridge.groups_updated() except TimeoutError: - _LOGGER.error("Timeout during updating of groups") + _LOGGER.error("Timeout during updating of scenes/groups") return 0 except OSError: - _LOGGER.error("OSError during updating of groups") + _LOGGER.error("OSError during updating of scenes/groups") return 0 if new_groups: @@ -155,11 +170,13 @@ class Luminary(Light): self._supported_features = [] self._effect_list = [] self._is_on = False + self._available = True self._min_mireds = None self._max_mireds = None self._brightness = None self._color_temp = None self._rgb_color = None + self._device_attributes = None self.update_static_attributes() self.update_dynamic_attributes() @@ -241,6 +258,16 @@ class Luminary(Light): """Return a unique ID.""" return self._unique_id + @property + def device_state_attributes(self): + """Return device specific state attributes.""" + return self._device_attributes + + @property + def available(self): + """Return True if entity is available.""" + return self._available + def play_effect(self, effect, transition): """Play selected effect.""" if effect == EFFECT_RANDOM: @@ -308,6 +335,8 @@ class Luminary(Light): def update_dynamic_attributes(self): """Update dynamic attributes of the luminary.""" self._is_on = self._luminary.on() + self._available = (self._luminary.reachable() and + not self._luminary.deleted()) if self._supported_features & SUPPORT_BRIGHTNESS: self._brightness = int(self._luminary.lum() * 2.55) @@ -333,6 +362,17 @@ class OsramLightifyLight(Luminary): """Get a unique ID.""" return self._luminary.addr() + def update_static_attributes(self): + """Update static attributes of the luminary.""" + super().update_static_attributes() + attrs = {'device_type': '{} ({})'.format(self._luminary.type_id(), + self._luminary.devicename()), + 'firmware_version': self._luminary.version()} + if self._luminary.devicetype().name == 'SENSOR': + attrs['sensor_values'] = self._luminary.raw_values() + + self._device_attributes = attrs + class OsramLightifyGroup(Luminary): """Representation of an Osram Lightify Group.""" @@ -347,3 +387,33 @@ class OsramLightifyGroup(Luminary): # For now keeping it as is for backward compatibility with existing # users. return '{}'.format(self._luminary.lights()) + + def _get_supported_features(self): + """Get list of supported features.""" + features = super()._get_supported_features() + if self._luminary.scenes(): + features = features | SUPPORT_EFFECT + + return features + + def _get_effect_list(self): + """Get list of supported effects.""" + effects = super()._get_effect_list() + effects.extend(self._luminary.scenes()) + return sorted(effects) + + def play_effect(self, effect, transition): + """Play selected effect.""" + if super().play_effect(effect, transition): + return True + + if effect in self._luminary.scenes(): + self._luminary.activate_scene(effect) + return True + + return False + + def update_static_attributes(self): + """Update static attributes of the luminary.""" + super().update_static_attributes() + self._device_attributes = {'lights': self._luminary.light_names()} From 471afb4702a09933e792971f1adfe2b70000fdfa Mon Sep 17 00:00:00 2001 From: Alex Bahm Date: Tue, 2 Apr 2019 11:25:58 -0700 Subject: [PATCH 052/167] Add color support to emulated hue (#19590) * [Hue API] Add color support Adds color support to the hue api (specifically hue/saturation). Switched from using a tuple to convey state internally to using a dict to make adding new fields easier. * [Hue API] Add unit test for color support --- .../components/emulated_hue/hue_api.py | 255 +++++++++++------- tests/components/emulated_hue/test_hue_api.py | 37 ++- 2 files changed, 197 insertions(+), 95 deletions(-) diff --git a/homeassistant/components/emulated_hue/hue_api.py b/homeassistant/components/emulated_hue/hue_api.py index 4c329cac28f..44a9c6e53ef 100644 --- a/homeassistant/components/emulated_hue/hue_api.py +++ b/homeassistant/components/emulated_hue/hue_api.py @@ -4,42 +4,42 @@ import logging from aiohttp import web from homeassistant import core -from homeassistant.const import ( - ATTR_ENTITY_ID, ATTR_TEMPERATURE, SERVICE_TURN_OFF, SERVICE_TURN_ON, - SERVICE_VOLUME_SET, SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, STATE_ON, - STATE_OFF, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, ATTR_SUPPORTED_FEATURES -) -from homeassistant.components.light import ( - ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS -) +from homeassistant.components import ( + climate, cover, fan, light, media_player, scene, script) from homeassistant.components.climate.const import ( - SERVICE_SET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE -) -from homeassistant.components.media_player.const import ( - ATTR_MEDIA_VOLUME_LEVEL, SUPPORT_VOLUME_SET, -) -from homeassistant.components.fan import ( - ATTR_SPEED, SUPPORT_SET_SPEED, SPEED_OFF, SPEED_LOW, - SPEED_MEDIUM, SPEED_HIGH -) - + SERVICE_SET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE) from homeassistant.components.cover import ( ATTR_CURRENT_POSITION, ATTR_POSITION, SERVICE_SET_COVER_POSITION, - SUPPORT_SET_POSITION -) - -from homeassistant.components import ( - climate, cover, fan, media_player, light, script, scene -) - + SUPPORT_SET_POSITION) +from homeassistant.components.fan import ( + ATTR_SPEED, SPEED_HIGH, SPEED_LOW, SPEED_MEDIUM, SPEED_OFF, + SUPPORT_SET_SPEED) from homeassistant.components.http import HomeAssistantView from homeassistant.components.http.const import KEY_REAL_IP +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, ATTR_HS_COLOR, SUPPORT_BRIGHTNESS, SUPPORT_COLOR) +from homeassistant.components.media_player.const import ( + ATTR_MEDIA_VOLUME_LEVEL, SUPPORT_VOLUME_SET) +from homeassistant.const import ( + ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE, + HTTP_BAD_REQUEST, HTTP_NOT_FOUND, SERVICE_CLOSE_COVER, SERVICE_OPEN_COVER, + SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_VOLUME_SET, STATE_OFF, STATE_ON) from homeassistant.util.network import is_local _LOGGER = logging.getLogger(__name__) HUE_API_STATE_ON = 'on' HUE_API_STATE_BRI = 'bri' +HUE_API_STATE_HUE = 'hue' +HUE_API_STATE_SAT = 'sat' + +HUE_API_STATE_HUE_MAX = 65535.0 +HUE_API_STATE_SAT_MAX = 254.0 +HUE_API_STATE_BRI_MAX = 255.0 + +STATE_BRIGHTNESS = HUE_API_STATE_BRI +STATE_HUE = HUE_API_STATE_HUE +STATE_SATURATION = HUE_API_STATE_SAT class HueUsernameView(HomeAssistantView): @@ -140,11 +140,11 @@ class HueAllLightsStateView(HomeAssistantView): for entity in hass.states.async_all(): if self.config.is_entity_exposed(entity): - state, brightness = get_entity_state(self.config, entity) + state = get_entity_state(self.config, entity) number = self.config.entity_id_to_number(entity.entity_id) - json_response[number] = entity_to_json( - self.config, entity, state, brightness) + json_response[number] = entity_to_json(self.config, + entity, state) return self.json(json_response) @@ -179,9 +179,9 @@ class HueOneLightStateView(HomeAssistantView): _LOGGER.error('Entity not exposed: %s', entity_id) return web.Response(text="Entity not exposed", status=404) - state, brightness = get_entity_state(self.config, entity) + state = get_entity_state(self.config, entity) - json_response = entity_to_json(self.config, entity, state, brightness) + json_response = entity_to_json(self.config, entity, state) return self.json(json_response) @@ -234,8 +234,6 @@ class HueOneLightChangeView(HomeAssistantView): _LOGGER.error('Unable to parse data: %s', request_json) return web.Response(text="Bad request", status=400) - result, brightness = parsed - # Choose general HA domain domain = core.DOMAIN @@ -243,7 +241,7 @@ class HueOneLightChangeView(HomeAssistantView): turn_on_needed = False # Convert the resulting "on" status into the service we need to call - service = SERVICE_TURN_ON if result else SERVICE_TURN_OFF + service = SERVICE_TURN_ON if parsed[STATE_ON] else SERVICE_TURN_OFF # Construct what we need to send to the service data = {ATTR_ENTITY_ID: entity_id} @@ -252,18 +250,32 @@ class HueOneLightChangeView(HomeAssistantView): entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) if entity.domain == light.DOMAIN: - if entity_features & SUPPORT_BRIGHTNESS: - if brightness is not None: - data[ATTR_BRIGHTNESS] = brightness + if parsed[STATE_ON]: + if entity_features & SUPPORT_BRIGHTNESS: + if parsed[STATE_BRIGHTNESS] is not None: + data[ATTR_BRIGHTNESS] = parsed[STATE_BRIGHTNESS] + if entity_features & SUPPORT_COLOR: + if parsed[STATE_HUE] is not None: + if parsed[STATE_SATURATION]: + sat = parsed[STATE_SATURATION] + else: + sat = 0 + hue = parsed[STATE_HUE] + + # Convert hs values to hass hs values + sat = int((sat / HUE_API_STATE_SAT_MAX) * 100) + hue = int((hue / HUE_API_STATE_HUE_MAX) * 360) + + data[ATTR_HS_COLOR] = (hue, sat) # If the requested entity is a script add some variables elif entity.domain == script.DOMAIN: data['variables'] = { - 'requested_state': STATE_ON if result else STATE_OFF + 'requested_state': STATE_ON if parsed[STATE_ON] else STATE_OFF } - if brightness is not None: - data['variables']['requested_level'] = brightness + if parsed[STATE_BRIGHTNESS] is not None: + data['variables']['requested_level'] = parsed[STATE_BRIGHTNESS] # If the requested entity is a climate, set the temperature elif entity.domain == climate.DOMAIN: @@ -272,20 +284,21 @@ class HueOneLightChangeView(HomeAssistantView): service = None if entity_features & SUPPORT_TARGET_TEMPERATURE: - if brightness is not None: + if parsed[STATE_BRIGHTNESS] is not None: domain = entity.domain service = SERVICE_SET_TEMPERATURE - data[ATTR_TEMPERATURE] = brightness + data[ATTR_TEMPERATURE] = parsed[STATE_BRIGHTNESS] # If the requested entity is a media player, convert to volume elif entity.domain == media_player.DOMAIN: if entity_features & SUPPORT_VOLUME_SET: - if brightness is not None: + if parsed[STATE_BRIGHTNESS] is not None: turn_on_needed = True domain = entity.domain service = SERVICE_VOLUME_SET # Convert 0-100 to 0.0-1.0 - data[ATTR_MEDIA_VOLUME_LEVEL] = brightness / 100.0 + data[ATTR_MEDIA_VOLUME_LEVEL] = \ + parsed[STATE_BRIGHTNESS] / 100.0 # If the requested entity is a cover, convert to open_cover/close_cover elif entity.domain == cover.DOMAIN: @@ -296,17 +309,18 @@ class HueOneLightChangeView(HomeAssistantView): service = SERVICE_CLOSE_COVER if entity_features & SUPPORT_SET_POSITION: - if brightness is not None: + if parsed[STATE_BRIGHTNESS] is not None: domain = entity.domain service = SERVICE_SET_COVER_POSITION - data[ATTR_POSITION] = brightness + data[ATTR_POSITION] = parsed[STATE_BRIGHTNESS] # If the requested entity is a fan, convert to speed elif entity.domain == fan.DOMAIN: if entity_features & SUPPORT_SET_SPEED: - if brightness is not None: + if parsed[STATE_BRIGHTNESS] is not None: domain = entity.domain # Convert 0-100 to a fan speed + brightness = parsed[STATE_BRIGHTNESS] if brightness == 0: data[ATTR_SPEED] = SPEED_OFF elif 0 < brightness <= 33.3: @@ -325,7 +339,7 @@ class HueOneLightChangeView(HomeAssistantView): # they'll map to "on". Thus, instead of reporting its actual # status, we report what Alexa will want to see, which is the same # as the actual requested command. - config.cached_states[entity_id] = (result, brightness) + config.cached_states[entity_id] = parsed # Separate call to turn on needed if turn_on_needed: @@ -338,73 +352,120 @@ class HueOneLightChangeView(HomeAssistantView): domain, service, data, blocking=True)) json_response = \ - [create_hue_success_response(entity_id, HUE_API_STATE_ON, result)] + [create_hue_success_response( + entity_id, HUE_API_STATE_ON, parsed[STATE_ON])] - if brightness is not None: + if parsed[STATE_BRIGHTNESS] is not None: json_response.append(create_hue_success_response( - entity_id, HUE_API_STATE_BRI, brightness)) + entity_id, HUE_API_STATE_BRI, parsed[STATE_BRIGHTNESS])) + if parsed[STATE_HUE] is not None: + json_response.append(create_hue_success_response( + entity_id, HUE_API_STATE_HUE, parsed[STATE_HUE])) + if parsed[STATE_SATURATION] is not None: + json_response.append(create_hue_success_response( + entity_id, HUE_API_STATE_SAT, parsed[STATE_SATURATION])) return self.json(json_response) def parse_hue_api_put_light_body(request_json, entity): """Parse the body of a request to change the state of a light.""" + data = { + STATE_BRIGHTNESS: None, + STATE_HUE: None, + STATE_ON: False, + STATE_SATURATION: None, + } + + # Make sure the entity actually supports brightness + entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) + if HUE_API_STATE_ON in request_json: if not isinstance(request_json[HUE_API_STATE_ON], bool): return None - if request_json['on']: + if request_json[HUE_API_STATE_ON]: # Echo requested device be turned on - brightness = None - report_brightness = False - result = True + data[STATE_BRIGHTNESS] = None + data[STATE_ON] = True else: # Echo requested device be turned off - brightness = None - report_brightness = False - result = False + data[STATE_BRIGHTNESS] = None + data[STATE_ON] = False + + if HUE_API_STATE_HUE in request_json: + try: + # Clamp brightness from 0 to 65535 + data[STATE_HUE] = \ + max(0, min(int(request_json[HUE_API_STATE_HUE]), + HUE_API_STATE_HUE_MAX)) + except ValueError: + return None + + if HUE_API_STATE_SAT in request_json: + try: + # Clamp saturation from 0 to 254 + data[STATE_SATURATION] = \ + max(0, min(int(request_json[HUE_API_STATE_SAT]), + HUE_API_STATE_SAT_MAX)) + except ValueError: + return None if HUE_API_STATE_BRI in request_json: try: # Clamp brightness from 0 to 255 - brightness = \ - max(0, min(int(request_json[HUE_API_STATE_BRI]), 255)) + data[STATE_BRIGHTNESS] = \ + max(0, min(int(request_json[HUE_API_STATE_BRI]), + HUE_API_STATE_BRI_MAX)) except ValueError: return None - # Make sure the entity actually supports brightness - entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) - if entity.domain == light.DOMAIN: - if entity_features & SUPPORT_BRIGHTNESS: - report_brightness = True - result = (brightness > 0) + data[STATE_ON] = (data[STATE_BRIGHTNESS] > 0) + if not entity_features & SUPPORT_BRIGHTNESS: + data[STATE_BRIGHTNESS] = None elif entity.domain == scene.DOMAIN: - brightness = None - report_brightness = False - result = True + data[STATE_BRIGHTNESS] = None + data[STATE_ON] = True elif entity.domain in [ script.DOMAIN, media_player.DOMAIN, fan.DOMAIN, cover.DOMAIN, climate.DOMAIN]: # Convert 0-255 to 0-100 - level = brightness / 255 * 100 - brightness = round(level) - report_brightness = True - result = True + level = (data[STATE_BRIGHTNESS] / HUE_API_STATE_BRI_MAX) * 100 + data[STATE_BRIGHTNESS] = round(level) + data[STATE_ON] = True - return (result, brightness) if report_brightness else (result, None) + return data def get_entity_state(config, entity): """Retrieve and convert state and brightness values for an entity.""" cached_state = config.cached_states.get(entity.entity_id, None) + data = { + STATE_BRIGHTNESS: None, + STATE_HUE: None, + STATE_ON: False, + STATE_SATURATION: None + } if cached_state is None: - final_state = entity.state != STATE_OFF - final_brightness = entity.attributes.get( - ATTR_BRIGHTNESS, 255 if final_state else 0) + data[STATE_ON] = entity.state != STATE_OFF + if data[STATE_ON]: + data[STATE_BRIGHTNESS] = entity.attributes.get(ATTR_BRIGHTNESS) + hue_sat = entity.attributes.get(ATTR_HS_COLOR, None) + if hue_sat is not None: + hue = hue_sat[0] + sat = hue_sat[1] + # convert hass hs values back to hue hs values + data[STATE_HUE] = int((hue / 360.0) * HUE_API_STATE_HUE_MAX) + data[STATE_SATURATION] = \ + int((sat / 100.0) * HUE_API_STATE_SAT_MAX) + else: + data[STATE_BRIGHTNESS] = 0 + data[STATE_HUE] = 0 + data[STATE_SATURATION] = 0 # Make sure the entity actually supports brightness entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) @@ -416,41 +477,53 @@ def get_entity_state(config, entity): elif entity.domain == climate.DOMAIN: temperature = entity.attributes.get(ATTR_TEMPERATURE, 0) # Convert 0-100 to 0-255 - final_brightness = round(temperature * 255 / 100) + data[STATE_BRIGHTNESS] = round(temperature * 255 / 100) elif entity.domain == media_player.DOMAIN: level = entity.attributes.get( - ATTR_MEDIA_VOLUME_LEVEL, 1.0 if final_state else 0.0) + ATTR_MEDIA_VOLUME_LEVEL, 1.0 if data[STATE_ON] else 0.0) # Convert 0.0-1.0 to 0-255 - final_brightness = round(min(1.0, level) * 255) + data[STATE_BRIGHTNESS] = \ + round(min(1.0, level) * HUE_API_STATE_BRI_MAX) elif entity.domain == fan.DOMAIN: speed = entity.attributes.get(ATTR_SPEED, 0) # Convert 0.0-1.0 to 0-255 - final_brightness = 0 + data[STATE_BRIGHTNESS] = 0 if speed == SPEED_LOW: - final_brightness = 85 + data[STATE_BRIGHTNESS] = 85 elif speed == SPEED_MEDIUM: - final_brightness = 170 + data[STATE_BRIGHTNESS] = 170 elif speed == SPEED_HIGH: - final_brightness = 255 + data[STATE_BRIGHTNESS] = 255 elif entity.domain == cover.DOMAIN: level = entity.attributes.get(ATTR_CURRENT_POSITION, 0) - final_brightness = round(level / 100 * 255) + data[STATE_BRIGHTNESS] = round(level / 100 * HUE_API_STATE_BRI_MAX) else: - final_state, final_brightness = cached_state + data = cached_state # Make sure brightness is valid - if final_brightness is None: - final_brightness = 255 if final_state else 0 + if data[STATE_BRIGHTNESS] is None: + data[STATE_BRIGHTNESS] = 255 if data[STATE_ON] else 0 + # Make sure hue/saturation are valid + if (data[STATE_HUE] is None) or (data[STATE_SATURATION] is None): + data[STATE_HUE] = 0 + data[STATE_SATURATION] = 0 - return (final_state, final_brightness) + # If the light is off, set the color to off + if data[STATE_BRIGHTNESS] == 0: + data[STATE_HUE] = 0 + data[STATE_SATURATION] = 0 + + return data -def entity_to_json(config, entity, is_on=None, brightness=None): +def entity_to_json(config, entity, state): """Convert an entity to its Hue bridge JSON representation.""" return { 'state': { - HUE_API_STATE_ON: is_on, - HUE_API_STATE_BRI: brightness, + HUE_API_STATE_ON: state[STATE_ON], + HUE_API_STATE_BRI: state[STATE_BRIGHTNESS], + HUE_API_STATE_HUE: state[STATE_HUE], + HUE_API_STATE_SAT: state[STATE_SATURATION], 'reachable': True }, 'type': 'Dimmable light', diff --git a/tests/components/emulated_hue/test_hue_api.py b/tests/components/emulated_hue/test_hue_api.py index 08001b0ebab..3348fdfe87b 100644 --- a/tests/components/emulated_hue/test_hue_api.py +++ b/tests/components/emulated_hue/test_hue_api.py @@ -13,7 +13,8 @@ from homeassistant.components import ( fan, http, light, script, emulated_hue, media_player, cover, climate) from homeassistant.components.emulated_hue import Config from homeassistant.components.emulated_hue.hue_api import ( - HUE_API_STATE_ON, HUE_API_STATE_BRI, HueUsernameView, HueOneLightStateView, + HUE_API_STATE_ON, HUE_API_STATE_BRI, HUE_API_STATE_HUE, HUE_API_STATE_SAT, + HueUsernameView, HueOneLightStateView, HueAllLightsStateView, HueOneLightChangeView, HueAllGroupsStateView) from homeassistant.const import STATE_ON, STATE_OFF @@ -221,12 +222,13 @@ def test_discover_lights(hue_client): @asyncio.coroutine def test_get_light_state(hass_hue, hue_client): """Test the getting of light state.""" - # Turn office light on and set to 127 brightness + # Turn office light on and set to 127 brightness, and set light color yield from hass_hue.services.async_call( light.DOMAIN, const.SERVICE_TURN_ON, { const.ATTR_ENTITY_ID: 'light.ceiling_lights', - light.ATTR_BRIGHTNESS: 127 + light.ATTR_BRIGHTNESS: 127, + light.ATTR_RGB_COLOR: (1, 2, 7) }, blocking=True) @@ -235,6 +237,8 @@ def test_get_light_state(hass_hue, hue_client): assert office_json['state'][HUE_API_STATE_ON] is True assert office_json['state'][HUE_API_STATE_BRI] == 127 + assert office_json['state'][HUE_API_STATE_HUE] == 41869 + assert office_json['state'][HUE_API_STATE_SAT] == 217 # Check all lights view result = yield from hue_client.get('/api/username/lights') @@ -261,6 +265,8 @@ def test_get_light_state(hass_hue, hue_client): assert office_json['state'][HUE_API_STATE_ON] is False assert office_json['state'][HUE_API_STATE_BRI] == 0 + assert office_json['state'][HUE_API_STATE_HUE] == 0 + assert office_json['state'][HUE_API_STATE_SAT] == 0 # Make sure bedroom light isn't accessible yield from perform_get_light_state( @@ -287,6 +293,19 @@ def test_put_light_state(hass_hue, hue_client): assert ceiling_lights.state == STATE_ON assert ceiling_lights.attributes[light.ATTR_BRIGHTNESS] == 153 + # update light state through api + yield from perform_put_light_state( + hass_hue, hue_client, + 'light.ceiling_lights', True, + hue=4369, saturation=127, brightness=123) + + # go through api to get the state back + ceiling_json = yield from perform_get_light_state( + hue_client, 'light.ceiling_lights', 200) + assert ceiling_json['state'][HUE_API_STATE_BRI] == 123 + assert ceiling_json['state'][HUE_API_STATE_HUE] == 4369 + assert ceiling_json['state'][HUE_API_STATE_SAT] == 127 + # Go through the API to turn it off ceiling_result = yield from perform_put_light_state( hass_hue, hue_client, @@ -302,6 +321,11 @@ def test_put_light_state(hass_hue, hue_client): # Check to make sure the state changed ceiling_lights = hass_hue.states.get('light.ceiling_lights') assert ceiling_lights.state == STATE_OFF + ceiling_json = yield from perform_get_light_state( + hue_client, 'light.ceiling_lights', 200) + assert ceiling_json['state'][HUE_API_STATE_BRI] == 0 + assert ceiling_json['state'][HUE_API_STATE_HUE] == 0 + assert ceiling_json['state'][HUE_API_STATE_SAT] == 0 # Make sure we can't change the bedroom light state bedroom_result = yield from perform_put_light_state( @@ -706,7 +730,8 @@ def perform_get_light_state(client, entity_id, expected_status): @asyncio.coroutine def perform_put_light_state(hass_hue, client, entity_id, is_on, - brightness=None, content_type='application/json'): + brightness=None, content_type='application/json', + hue=None, saturation=None): """Test the setting of a light state.""" req_headers = {'Content-Type': content_type} @@ -714,6 +739,10 @@ def perform_put_light_state(hass_hue, client, entity_id, is_on, if brightness is not None: data[HUE_API_STATE_BRI] = brightness + if hue is not None: + data[HUE_API_STATE_HUE] = hue + if saturation is not None: + data[HUE_API_STATE_SAT] = saturation result = yield from client.put( '/api/username/lights/{}/state'.format(entity_id), headers=req_headers, From 5651db4b5c8fa7efbea4f2ea271c4c4e7dbbf01f Mon Sep 17 00:00:00 2001 From: Andrew Sayre <6730289+andrewsayre@users.noreply.github.com> Date: Tue, 2 Apr 2019 15:22:49 -0500 Subject: [PATCH 053/167] Add discovery support to HEOS component (#22652) * Add discovery entry point * Fix test * Correct test call method * Update netdisco to 2.6.0 --- .../components/discovery/__init__.py | 4 ++- homeassistant/components/heos/config_flow.py | 7 +++++- requirements_all.txt | 2 +- tests/components/heos/test_config_flow.py | 25 +++++++++++++++++++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/discovery/__init__.py b/homeassistant/components/discovery/__init__.py index ecbbe7ea5e0..8e3a350c5ca 100644 --- a/homeassistant/components/discovery/__init__.py +++ b/homeassistant/components/discovery/__init__.py @@ -20,7 +20,7 @@ from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.discovery import async_load_platform, async_discover import homeassistant.util.dt as dt_util -REQUIREMENTS = ['netdisco==2.5.0'] +REQUIREMENTS = ['netdisco==2.6.0'] DOMAIN = 'discovery' @@ -35,6 +35,7 @@ SERVICE_FREEBOX = 'freebox' SERVICE_HASS_IOS_APP = 'hass_ios' SERVICE_HASSIO = 'hassio' SERVICE_HOMEKIT = 'homekit' +SERVICE_HEOS = 'heos' SERVICE_HUE = 'philips_hue' SERVICE_IGD = 'igd' SERVICE_IKEA_TRADFRI = 'ikea_tradfri' @@ -57,6 +58,7 @@ CONFIG_ENTRY_HANDLERS = { SERVICE_DECONZ: 'deconz', 'esphome': 'esphome', 'google_cast': 'cast', + SERVICE_HEOS: 'heos', SERVICE_HUE: 'hue', SERVICE_TELLDUSLIVE: 'tellduslive', SERVICE_IKEA_TRADFRI: 'tradfri', diff --git a/homeassistant/components/heos/config_flow.py b/homeassistant/components/heos/config_flow.py index 5fd7ea59912..7ccb43c60e9 100644 --- a/homeassistant/components/heos/config_flow.py +++ b/homeassistant/components/heos/config_flow.py @@ -21,6 +21,11 @@ class HeosFlowHandler(config_entries.ConfigFlow): VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH + async def async_step_discovery(self, discovery_info): + """Handle a discovered Heos device.""" + return await self.async_step_user( + {CONF_HOST: discovery_info[CONF_HOST]}) + async def async_step_import(self, user_input=None): """Occurs when an entry is setup through config.""" host = user_input[CONF_HOST] @@ -32,7 +37,7 @@ class HeosFlowHandler(config_entries.ConfigFlow): """Obtain host and validate connection.""" from pyheos import Heos - # Only a single entry is supported + # Only a single entry is needed for all devices entries = self.hass.config_entries.async_entries(DOMAIN) if entries: return self.async_abort(reason='already_setup') diff --git a/requirements_all.txt b/requirements_all.txt index 8c85c9edbc5..a6f0e055c9a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -741,7 +741,7 @@ nessclient==0.9.15 netdata==0.1.2 # homeassistant.components.discovery -netdisco==2.5.0 +netdisco==2.6.0 # homeassistant.components.neurio_energy.sensor neurio==0.3.1 diff --git a/tests/components/heos/test_config_flow.py b/tests/components/heos/test_config_flow.py index 8314ad07bc2..ddb2bd39384 100644 --- a/tests/components/heos/test_config_flow.py +++ b/tests/components/heos/test_config_flow.py @@ -55,3 +55,28 @@ async def test_create_entry_when_host_valid(hass, controller): assert result['data'] == data assert controller.connect.call_count == 1 assert controller.disconnect.call_count == 1 + + +async def test_create_entry_with_discovery(hass, controller): + """Test result type is create entry when valid through discovery.""" + flow = HeosFlowHandler() + flow.hass = hass + data = { + 'host': '127.0.0.1', + 'manufacturer': 'Denon', + 'model_name': 'HEOS Drive', + 'model_number': 'DWSA-10 4.0', + 'name': 'Office', + 'port': 60006, + 'serial': None, + 'ssdp_description': + 'http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml', + 'udn': 'uuid:e61de70c-2250-1c22-0080-0005cdf512be', + 'upnp_device_type': 'urn:schemas-denon-com:device:AiosDevice:1' + } + result = await flow.async_step_discovery(data) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['title'] == 'Controller (127.0.0.1)' + assert result['data'] == {'host': '127.0.0.1'} + assert controller.connect.call_count == 1 + assert controller.disconnect.call_count == 1 From 22d93a74a41d2d6a6d92fe8f97bbbfc631583669 Mon Sep 17 00:00:00 2001 From: mvn23 Date: Tue, 2 Apr 2019 22:57:38 +0200 Subject: [PATCH 054/167] Don't use room setpoint override in climate.opentherm_gw (#22656) * Dont use DATA_ROOM_SETPOINT_OVRD in climate.opentherm_gw as it is unreliable with some thermostats. * Show new target temperature immediately until the backend notices a change * Only update target temp on the gateway if the value differs from the current target_temperature. --- homeassistant/components/opentherm_gw/climate.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/opentherm_gw/climate.py b/homeassistant/components/opentherm_gw/climate.py index 58ce49a9b02..60f1901d43e 100644 --- a/homeassistant/components/opentherm_gw/climate.py +++ b/homeassistant/components/opentherm_gw/climate.py @@ -39,6 +39,7 @@ class OpenThermGateway(ClimateDevice): self.temp_precision = config.get(CONF_PRECISION) self._current_operation = STATE_IDLE self._current_temperature = None + self._new_target_temperature = None self._target_temperature = None self._away_mode_a = None self._away_mode_b = None @@ -63,11 +64,10 @@ class OpenThermGateway(ClimateDevice): else: self._current_operation = STATE_IDLE self._current_temperature = status.get(self._gw_vars.DATA_ROOM_TEMP) - - temp = status.get(self._gw_vars.DATA_ROOM_SETPOINT_OVRD) - if temp is None: - temp = status.get(self._gw_vars.DATA_ROOM_SETPOINT) - self._target_temperature = temp + temp_upd = status.get(self._gw_vars.DATA_ROOM_SETPOINT) + if self._target_temperature != temp_upd: + self._new_target_temperature = None + self._target_temperature = temp_upd # GPIO mode 5: 0 == Away # GPIO mode 6: 1 == Away @@ -138,7 +138,7 @@ class OpenThermGateway(ClimateDevice): @property def target_temperature(self): """Return the temperature we try to reach.""" - return self._target_temperature + return self._new_target_temperature or self._target_temperature @property def target_temperature_step(self): @@ -154,7 +154,9 @@ class OpenThermGateway(ClimateDevice): """Set new target temperature.""" if ATTR_TEMPERATURE in kwargs: temp = float(kwargs[ATTR_TEMPERATURE]) - self._target_temperature = await self._gateway.set_target_temp( + if temp == self.target_temperature: + return + self._new_target_temperature = await self._gateway.set_target_temp( temp) self.async_schedule_update_ha_state() From 5613e8bb60b5fff83bc30efcfee5915aab2c6def Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 3 Apr 2019 04:23:33 +0200 Subject: [PATCH 055/167] Hass.io discovery flow deconz (#22623) * Add Hass.io deCONZ discovery flow * add bridge ID * fix attribute * fix strings * Address comments * Add test * Add only instance / changed maybe later --- .../components/deconz/config_flow.py | 59 +++++++++++++++++-- homeassistant/components/deconz/const.py | 3 + homeassistant/components/deconz/strings.json | 10 +++- homeassistant/components/hassio/discovery.py | 4 +- tests/components/deconz/test_config_flow.py | 49 +++++++++++++++ 5 files changed, 116 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/deconz/config_flow.py b/homeassistant/components/deconz/config_flow.py index cabb5b46ece..38849fb37b3 100644 --- a/homeassistant/components/deconz/config_flow.py +++ b/homeassistant/components/deconz/config_flow.py @@ -1,17 +1,18 @@ """Config flow to configure deCONZ component.""" import asyncio + import async_timeout import voluptuous as vol from homeassistant import config_entries -from homeassistant.core import callback from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT +from homeassistant.core import callback from homeassistant.helpers import aiohttp_client from .const import ( - CONF_ALLOW_DECONZ_GROUPS, CONF_ALLOW_CLIP_SENSOR, DEFAULT_PORT, DOMAIN) - -CONF_BRIDGEID = 'bridgeid' + CONF_ALLOW_CLIP_SENSOR, CONF_ALLOW_DECONZ_GROUPS, CONF_BRIDGEID, + DEFAULT_ALLOW_CLIP_SENSOR, DEFAULT_ALLOW_DECONZ_GROUPS, DEFAULT_PORT, + DOMAIN) @callback @@ -28,6 +29,8 @@ class DeconzFlowHandler(config_entries.ConfigFlow): VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH + _hassio_discovery = None + def __init__(self): """Initialize the deCONZ config flow.""" self.bridges = [] @@ -151,8 +154,10 @@ class DeconzFlowHandler(config_entries.ConfigFlow): return self.async_show_form( step_id='options', data_schema=vol.Schema({ - vol.Optional(CONF_ALLOW_CLIP_SENSOR): bool, - vol.Optional(CONF_ALLOW_DECONZ_GROUPS): bool, + vol.Optional(CONF_ALLOW_CLIP_SENSOR, + default=DEFAULT_ALLOW_CLIP_SENSOR): bool, + vol.Optional(CONF_ALLOW_DECONZ_GROUPS, + default=DEFAULT_ALLOW_DECONZ_GROUPS): bool, }), ) @@ -191,3 +196,45 @@ class DeconzFlowHandler(config_entries.ConfigFlow): user_input = {CONF_ALLOW_CLIP_SENSOR: True, CONF_ALLOW_DECONZ_GROUPS: True} return await self.async_step_options(user_input=user_input) + + async def async_step_hassio(self, user_input=None): + """Prepare configuration for a Hass.io deCONZ bridge. + + This flow is triggered by the discovery component. + """ + if configured_hosts(self.hass): + return self.async_abort(reason='one_instance_only') + + self._hassio_discovery = user_input + + return await self.async_step_hassio_confirm() + + async def async_step_hassio_confirm(self, user_input=None): + """Confirm a Hass.io discovery.""" + if user_input is not None: + data = self._hassio_discovery + + return self.async_create_entry( + title=data['addon'], data={ + CONF_HOST: data[CONF_HOST], + CONF_PORT: data[CONF_PORT], + CONF_BRIDGEID: data['serial'], + CONF_API_KEY: data[CONF_API_KEY], + CONF_ALLOW_CLIP_SENSOR: + user_input[CONF_ALLOW_CLIP_SENSOR], + CONF_ALLOW_DECONZ_GROUPS: + user_input[CONF_ALLOW_DECONZ_GROUPS], + }) + + return self.async_show_form( + step_id='hassio_confirm', + description_placeholders={ + 'addon': self._hassio_discovery['addon'] + }, + data_schema=vol.Schema({ + vol.Optional(CONF_ALLOW_CLIP_SENSOR, + default=DEFAULT_ALLOW_CLIP_SENSOR): bool, + vol.Optional(CONF_ALLOW_DECONZ_GROUPS, + default=DEFAULT_ALLOW_DECONZ_GROUPS): bool, + }) + ) diff --git a/homeassistant/components/deconz/const.py b/homeassistant/components/deconz/const.py index e728430f202..b26fddd9147 100644 --- a/homeassistant/components/deconz/const.py +++ b/homeassistant/components/deconz/const.py @@ -6,9 +6,12 @@ _LOGGER = logging.getLogger('.') DOMAIN = 'deconz' DEFAULT_PORT = 80 +DEFAULT_ALLOW_CLIP_SENSOR = False +DEFAULT_ALLOW_DECONZ_GROUPS = False CONF_ALLOW_CLIP_SENSOR = 'allow_clip_sensor' CONF_ALLOW_DECONZ_GROUPS = 'allow_deconz_groups' +CONF_BRIDGEID = 'bridgeid' SUPPORTED_PLATFORMS = ['binary_sensor', 'climate', 'cover', 'light', 'scene', 'sensor', 'switch'] diff --git a/homeassistant/components/deconz/strings.json b/homeassistant/components/deconz/strings.json index 1bf7235713a..d0ae34e7c7a 100644 --- a/homeassistant/components/deconz/strings.json +++ b/homeassistant/components/deconz/strings.json @@ -19,6 +19,14 @@ "allow_clip_sensor": "Allow importing virtual sensors", "allow_deconz_groups": "Allow importing deCONZ groups" } + }, + "hassio_confirm": { + "title": "deCONZ Zigbee gateway via Hass.io add-on", + "description": "Do you want to configure Home Assistant to connect to the deCONZ gateway provided by the hass.io add-on {addon}?", + "data": { + "allow_clip_sensor": "Allow importing virtual sensors", + "allow_deconz_groups": "Allow importing deCONZ groups" + } } }, "error": { @@ -30,4 +38,4 @@ "one_instance_only": "Component only supports one deCONZ instance" } } -} \ No newline at end of file +} diff --git a/homeassistant/components/hassio/discovery.py b/homeassistant/components/hassio/discovery.py index 804247d2407..09a98edc148 100644 --- a/homeassistant/components/hassio/discovery.py +++ b/homeassistant/components/hassio/discovery.py @@ -81,7 +81,7 @@ class HassIODiscovery(HomeAssistantView): service = data[ATTR_SERVICE] config_data = data[ATTR_CONFIG] - # Read addinional Add-on info + # Read additional Add-on info try: addon_info = await self.hassio.get_addon_info(data[ATTR_ADDON]) except HassioAPIError as err: @@ -98,7 +98,7 @@ class HassIODiscovery(HomeAssistantView): service = data[ATTR_SERVICE] uuid = data[ATTR_UUID] - # Check if realy deletet / prevent injections + # Check if really deletet / prevent injections try: data = await self.hassio.get_discovery_message(uuid) except HassioAPIError: diff --git a/tests/components/deconz/test_config_flow.py b/tests/components/deconz/test_config_flow.py index 20c74a82883..863e4e93fc5 100644 --- a/tests/components/deconz/test_config_flow.py +++ b/tests/components/deconz/test_config_flow.py @@ -265,3 +265,52 @@ async def test_options(hass, aioclient_mock): 'allow_clip_sensor': False, 'allow_deconz_groups': False } + + +async def test_hassio_single_instance(hass): + """Test we only allow a single config flow.""" + MockConfigEntry(domain='deconz', data={ + 'host': '1.2.3.4' + }).add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + 'deconz', context={'source': 'hassio'}) + assert result['type'] == 'abort' + assert result['reason'] == 'one_instance_only' + + +async def test_hassio_confirm(hass): + """Test we can finish a config flow.""" + result = await hass.config_entries.flow.async_init( + 'deconz', + data={ + 'addon': 'Mock Addon', + 'host': 'mock-deconz', + 'port': 8080, + 'serial': 'aa:bb', + 'api_key': '1234567890ABCDEF', + }, + context={'source': 'hassio'} + ) + assert result['type'] == 'form' + assert result['step_id'] == 'hassio_confirm' + assert result['description_placeholders'] == { + 'addon': 'Mock Addon', + } + + result = await hass.config_entries.flow.async_configure( + result['flow_id'], { + 'allow_clip_sensor': True, + 'allow_deconz_groups': True, + } + ) + + assert result['type'] == 'create_entry' + assert result['result'].data == { + 'host': 'mock-deconz', + 'port': 8080, + 'bridgeid': 'aa:bb', + 'api_key': '1234567890ABCDEF', + 'allow_clip_sensor': True, + 'allow_deconz_groups': True, + } From 3453d67cfe5bef0e0b68d04d1ffe65c50ea2ca92 Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Wed, 3 Apr 2019 04:43:06 +0200 Subject: [PATCH 056/167] Person schema for merge_packages #21307 (#21703) * Person schema for merge_packages #21307 * empty list * skip empty persons * hound * test schema * ensure_none * remove any test changes * remove_falsy validator * nice! * coretests --- homeassistant/components/person/__init__.py | 3 ++- homeassistant/helpers/config_validation.py | 5 +++++ script/inspect_schemas.py | 2 +- tests/helpers/test_config_validation.py | 17 +++++++++++------ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/person/__init__.py b/homeassistant/components/person/__init__.py index e6f83b80ba4..89fac761497 100644 --- a/homeassistant/components/person/__init__.py +++ b/homeassistant/components/person/__init__.py @@ -50,7 +50,8 @@ PERSON_SCHEMA = vol.Schema({ }) CONFIG_SCHEMA = vol.Schema({ - vol.Optional(DOMAIN): vol.Any(vol.All(cv.ensure_list, [PERSON_SCHEMA]), {}) + vol.Optional(DOMAIN): vol.All( + cv.ensure_list, cv.remove_falsy, [PERSON_SCHEMA]) }, extra=vol.ALLOW_EXTRA) _UNDEF = object() diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 6513f9368b0..a954d01856e 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -349,6 +349,11 @@ def positive_timedelta(value: timedelta) -> timedelta: return value +def remove_falsy(value: Sequence[T]) -> Sequence[T]: + """Remove falsy values from a list.""" + return [v for v in value if v] + + def service(value): """Validate service.""" # Services use same format as entities so we can use same helper. diff --git a/script/inspect_schemas.py b/script/inspect_schemas.py index 46d5cf92ecc..9904552c681 100755 --- a/script/inspect_schemas.py +++ b/script/inspect_schemas.py @@ -48,7 +48,7 @@ def main(): schema_type, schema = _identify_config_schema(module) - add_msg("CONFIG_SCHEMA " + schema_type, module_name + ' ' + + add_msg("CONFIG_SCHEMA " + str(schema_type), module_name + ' ' + color('cyan', str(schema)[:60])) for key in sorted(msg): diff --git a/tests/helpers/test_config_validation.py b/tests/helpers/test_config_validation.py index 4a883fbf2fd..e0bd509d330 100644 --- a/tests/helpers/test_config_validation.py +++ b/tests/helpers/test_config_validation.py @@ -1,15 +1,15 @@ """Test config validators.""" -from datetime import timedelta, datetime, date +from datetime import date, datetime, timedelta import enum import os from socket import _GLOBAL_DEFAULT_TIMEOUT from unittest.mock import Mock, patch import uuid -import homeassistant import pytest import voluptuous as vol +import homeassistant import homeassistant.helpers.config_validation as cv @@ -291,6 +291,11 @@ def test_time_period(): assert -1 * timedelta(hours=1, minutes=15) == schema('-1:15') +def test_remove_falsy(): + """Test remove falsy.""" + assert cv.remove_falsy([0, None, 1, "1", {}, [], ""]) == [1, "1"] + + def test_service(): """Test service validation.""" schema = vol.Schema(cv.service) @@ -908,7 +913,7 @@ def test_matches_regex(): schema(" nrtd ") test_str = "This is a test including uiae." - assert (schema(test_str) == test_str) + assert schema(test_str) == test_str def test_is_regex(): @@ -982,6 +987,6 @@ def test_uuid4_hex(caplog): # the 17th char should be 8-a schema('a03d31b22eee4acc7b90eec40be6ed23') - hex = uuid.uuid4().hex - assert schema(hex) == hex - assert schema(hex.upper()) == hex + _hex = uuid.uuid4().hex + assert schema(_hex) == _hex + assert schema(_hex.upper()) == _hex From 4f2435103bf24bd5b158769811947135d99fbaaf Mon Sep 17 00:00:00 2001 From: emontnemery Date: Wed, 3 Apr 2019 04:58:02 +0200 Subject: [PATCH 057/167] Cast: Fix next/previous track (#22634) * Fix next/previous track * Bump pychromecast * Update test, fixup --- homeassistant/components/cast/__init__.py | 2 +- homeassistant/components/cast/media_player.py | 27 +++++++++++++------ requirements_all.txt | 2 +- tests/components/cast/test_media_player.py | 8 +++--- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/cast/__init__.py b/homeassistant/components/cast/__init__.py index 1aea4655e17..0ec3ac150d7 100644 --- a/homeassistant/components/cast/__init__.py +++ b/homeassistant/components/cast/__init__.py @@ -2,7 +2,7 @@ from homeassistant import config_entries from homeassistant.helpers import config_entry_flow -REQUIREMENTS = ['pychromecast==3.1.0'] +REQUIREMENTS = ['pychromecast==3.2.0'] DOMAIN = 'cast' diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index cb60cdc2967..2635a061e60 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -12,8 +12,8 @@ from homeassistant.components.media_player import ( from homeassistant.components.media_player.const import ( MEDIA_TYPE_MOVIE, MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, - SUPPORT_STOP, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, - SUPPORT_VOLUME_SET) + SUPPORT_SEEK, SUPPORT_STOP, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, + SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET) from homeassistant.const import ( CONF_HOST, EVENT_HOMEASSISTANT_STOP, STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING) @@ -36,9 +36,9 @@ CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png' DEFAULT_PORT = 8009 -SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ - SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \ - SUPPORT_NEXT_TRACK | SUPPORT_PLAY_MEDIA | SUPPORT_STOP | SUPPORT_PLAY +SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_PLAY | SUPPORT_PLAY_MEDIA | \ + SUPPORT_STOP | SUPPORT_TURN_OFF | SUPPORT_TURN_ON | \ + SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET # Stores a threading.Lock that is held by the internal pychromecast discovery. INTERNAL_DISCOVERY_RUNNING_KEY = 'cast_discovery_running' @@ -931,12 +931,12 @@ class CastDevice(MediaPlayerDevice): def media_previous_track(self): """Send previous track command.""" media_controller = self._media_controller() - media_controller.rewind() + media_controller.queue_prev() def media_next_track(self): """Send next track command.""" media_controller = self._media_controller() - media_controller.skip() + media_controller.queue_next() def media_seek(self, position): """Seek the media to a specific location.""" @@ -1130,7 +1130,18 @@ class CastDevice(MediaPlayerDevice): @property def supported_features(self): """Flag media player features that are supported.""" - return SUPPORT_CAST + support = SUPPORT_CAST + media_status, _ = self._media_status() + + if media_status: + if media_status.supports_queue_next: + support |= SUPPORT_PREVIOUS_TRACK + if media_status.supports_queue_next: + support |= SUPPORT_NEXT_TRACK + if media_status.supports_seek: + support |= SUPPORT_SEEK + + return support @property def media_position(self): diff --git a/requirements_all.txt b/requirements_all.txt index a6f0e055c9a..6d136a11fb1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -980,7 +980,7 @@ pycfdns==0.0.1 pychannels==1.0.0 # homeassistant.components.cast -pychromecast==3.1.0 +pychromecast==3.2.0 # homeassistant.components.cmus.media_player pycmus==0.1.1 diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index 7c40b09d03e..e7418460c59 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -479,16 +479,16 @@ async def test_dynamic_group_media_control(hass: HomeAssistantType): group_media_status.player_is_playing = True entity.new_dynamic_group_media_status(group_media_status) entity.media_previous_track() - assert entity._dynamic_group_cast.media_controller.rewind.called - assert not chromecast.media_controller.rewind.called + assert entity._dynamic_group_cast.media_controller.queue_prev.called + assert not chromecast.media_controller.queue_prev.called # Player is paused, dynamic group is playing -> Should not forward player_media_status.player_is_playing = False player_media_status.player_is_paused = True entity.new_media_status(player_media_status) entity.media_next_track() - assert not entity._dynamic_group_cast.media_controller.skip.called - assert chromecast.media_controller.skip.called + assert not entity._dynamic_group_cast.media_controller.queue_next.called + assert chromecast.media_controller.queue_next.called # Player is in unknown state, dynamic group is playing -> Should forward player_media_status.player_state = "UNKNOWN" From e736521e9f8971d9e54d401ab9e031a75a5dd930 Mon Sep 17 00:00:00 2001 From: emontnemery Date: Wed, 3 Apr 2019 04:58:28 +0200 Subject: [PATCH 058/167] Fix regression from PR #22396 (#22661) * Fix regression from PR #22396 * Fix test --- homeassistant/components/cast/media_player.py | 3 ++- tests/components/cast/test_media_player.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index 2635a061e60..c4019b4686c 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -986,7 +986,8 @@ class CastDevice(MediaPlayerDevice): media_status = self.media_status media_status_received = self.media_status_received - if media_status is None or media_status.player_state == "UNKNOWN": + if ((media_status is None or media_status.player_state == "UNKNOWN") + and self._dynamic_group_cast is not None): media_status = self.dynamic_group_media_status media_status_received = self.dynamic_group_media_status_received diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index e7418460c59..78140d49e4a 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -373,6 +373,7 @@ async def test_dynamic_group_media_states(hass: HomeAssistantType): player_media_status = MagicMock(images=None) # Player has no state, dynamic group is playing -> Should report 'playing' + entity._dynamic_group_cast = MagicMock() group_media_status.player_is_playing = True entity.new_dynamic_group_media_status(group_media_status) await hass.async_block_till_done() From f2941522cad07effad6a1a793c4fd1c29044b039 Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Wed, 3 Apr 2019 05:35:33 +0200 Subject: [PATCH 059/167] Person tests - split from #21703 (#22663) --- tests/components/person/test_init.py | 43 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/tests/components/person/test_init.py b/tests/components/person/test_init.py index ef129a555be..cde7633b1a3 100644 --- a/tests/components/person/test_init.py +++ b/tests/components/person/test_init.py @@ -1,24 +1,26 @@ """The tests for the person component.""" from unittest.mock import Mock +import pytest + +from homeassistant.components.device_tracker import ( + ATTR_SOURCE_TYPE, SOURCE_TYPE_GPS, SOURCE_TYPE_ROUTER) from homeassistant.components.person import ( ATTR_SOURCE, ATTR_USER_ID, DOMAIN, PersonManager) from homeassistant.const import ( - ATTR_ID, ATTR_LATITUDE, ATTR_LONGITUDE, ATTR_GPS_ACCURACY, - STATE_UNKNOWN, EVENT_HOMEASSISTANT_START) -from homeassistant.components.device_tracker import ( - ATTR_SOURCE_TYPE, SOURCE_TYPE_GPS, SOURCE_TYPE_ROUTER) + ATTR_GPS_ACCURACY, ATTR_ID, ATTR_LATITUDE, ATTR_LONGITUDE, + EVENT_HOMEASSISTANT_START, STATE_UNKNOWN) from homeassistant.core import CoreState, State from homeassistant.setup import async_setup_component -import pytest - -from tests.common import mock_component, mock_restore_cache, mock_coro_func +from tests.common import ( + assert_setup_component, mock_component, mock_coro_func, mock_restore_cache) DEVICE_TRACKER = 'device_tracker.test_tracker' DEVICE_TRACKER_2 = 'device_tracker.test_tracker_2' +# pylint: disable=redefined-outer-name @pytest.fixture def storage_setup(hass, hass_storage, hass_admin_user): """Storage setup.""" @@ -44,7 +46,8 @@ def storage_setup(hass, hass_storage, hass_admin_user): async def test_minimal_setup(hass): """Test minimal config with only name.""" config = {DOMAIN: {'id': '1234', 'name': 'test person'}} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(1): + assert await async_setup_component(hass, DOMAIN, config) state = hass.states.get('person.test_person') assert state.state == STATE_UNKNOWN @@ -71,7 +74,8 @@ async def test_setup_user_id(hass, hass_admin_user): user_id = hass_admin_user.id config = { DOMAIN: {'id': '1234', 'name': 'test person', 'user_id': user_id}} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(1): + assert await async_setup_component(hass, DOMAIN, config) state = hass.states.get('person.test_person') assert state.state == STATE_UNKNOWN @@ -88,7 +92,8 @@ async def test_valid_invalid_user_ids(hass, hass_admin_user): config = {DOMAIN: [ {'id': '1234', 'name': 'test valid user', 'user_id': user_id}, {'id': '5678', 'name': 'test bad user', 'user_id': 'bad_user_id'}]} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(2): + assert await async_setup_component(hass, DOMAIN, config) state = hass.states.get('person.test_valid_user') assert state.state == STATE_UNKNOWN @@ -108,7 +113,8 @@ async def test_setup_tracker(hass, hass_admin_user): config = {DOMAIN: { 'id': '1234', 'name': 'tracked person', 'user_id': user_id, 'device_trackers': DEVICE_TRACKER}} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(1): + assert await async_setup_component(hass, DOMAIN, config) state = hass.states.get('person.tracked_person') assert state.state == STATE_UNKNOWN @@ -159,7 +165,8 @@ async def test_setup_two_trackers(hass, hass_admin_user): config = {DOMAIN: { 'id': '1234', 'name': 'tracked person', 'user_id': user_id, 'device_trackers': [DEVICE_TRACKER, DEVICE_TRACKER_2]}} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(1): + assert await async_setup_component(hass, DOMAIN, config) state = hass.states.get('person.tracked_person') assert state.state == STATE_UNKNOWN @@ -231,7 +238,8 @@ async def test_ignore_unavailable_states(hass, hass_admin_user): config = {DOMAIN: { 'id': '1234', 'name': 'tracked person', 'user_id': user_id, 'device_trackers': [DEVICE_TRACKER, DEVICE_TRACKER_2]}} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(1): + assert await async_setup_component(hass, DOMAIN, config) state = hass.states.get('person.tracked_person') assert state.state == STATE_UNKNOWN @@ -275,7 +283,8 @@ async def test_restore_home_state(hass, hass_admin_user): config = {DOMAIN: { 'id': '1234', 'name': 'tracked person', 'user_id': user_id, 'device_trackers': DEVICE_TRACKER}} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(1): + assert await async_setup_component(hass, DOMAIN, config) state = hass.states.get('person.tracked_person') assert state.state == 'home' @@ -292,7 +301,8 @@ async def test_duplicate_ids(hass, hass_admin_user): config = {DOMAIN: [ {'id': '1234', 'name': 'test user 1'}, {'id': '1234', 'name': 'test user 2'}]} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(2): + assert await async_setup_component(hass, DOMAIN, config) assert len(hass.states.async_entity_ids('person')) == 1 assert hass.states.get('person.test_user_1') is not None @@ -302,7 +312,8 @@ async def test_duplicate_ids(hass, hass_admin_user): async def test_create_person_during_run(hass): """Test that person is updated if created while hass is running.""" config = {DOMAIN: {}} - assert await async_setup_component(hass, DOMAIN, config) + with assert_setup_component(0): + assert await async_setup_component(hass, DOMAIN, config) hass.states.async_set(DEVICE_TRACKER, 'home') await hass.async_block_till_done() From 6a411710dfe84094182146e973a194a89ef931fb Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 2 Apr 2019 21:23:59 -0700 Subject: [PATCH 060/167] Fix trusted networks auth provider warning message (#22671) * Fix trusted networks auth provider warning message * Update auth.py --- homeassistant/components/http/auth.py | 16 ++++++++++------ homeassistant/components/http/view.py | 2 ++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/http/auth.py b/homeassistant/components/http/auth.py index 7b8508894ce..0d8e327e086 100644 --- a/homeassistant/components/http/auth.py +++ b/homeassistant/components/http/auth.py @@ -190,12 +190,16 @@ def setup_auth(hass, app): elif (trusted_networks and await async_validate_trusted_networks(request)): - _LOGGER.warning( - 'Access from trusted networks without auth token is going to ' - 'be removed in Home Assistant 0.96. Configure the trusted ' - 'networks auth provider or use long-lived access tokens to ' - 'access %s from %s', - request.path, request[KEY_REAL_IP]) + if request.path not in old_auth_warning: + # When removing this, don't forget to remove the print logic + # in http/view.py + request['deprecate_warning_message'] = \ + 'Access from trusted networks without auth token is ' \ + 'going to be removed in Home Assistant 0.96. Configure ' \ + 'the trusted networks auth provider or use long-lived ' \ + 'access tokens to access {} from {}'.format( + request.path, request[KEY_REAL_IP]) + old_auth_warning.add(request.path) authenticated = True elif (support_legacy and HTTP_HEADER_HA_AUTH in request.headers and diff --git a/homeassistant/components/http/view.py b/homeassistant/components/http/view.py index d68cabebacf..8d5e0ee88b1 100644 --- a/homeassistant/components/http/view.py +++ b/homeassistant/components/http/view.py @@ -98,6 +98,8 @@ def request_handler_factory(view, handler): if view.requires_auth: if authenticated: + if 'deprecate_warning_message' in request: + _LOGGER.warning(request['deprecate_warning_message']) await process_success_login(request) else: raise HTTPUnauthorized() From a7d49e40c0cc62b5eb81e02dcd1d0b80075c1842 Mon Sep 17 00:00:00 2001 From: Finbarr Brady Date: Wed, 3 Apr 2019 07:25:02 +0100 Subject: [PATCH 061/167] Rebrand Cisco Spark notify to be Cisco Webex Teams (#21938) * Rebrand Cisco Spark notify to be Cisco Webex Teams * Remove property from class * Switch to use html for api * Update notify.py * Rename CONF_ROOMID to CONF_ROOM_ID * updated * Fix lint errors * Update notify.py * Update notify.py * Also validate room ID * Update notify.py * Update .coveragerc * Update notify.py --- .coveragerc | 1 + .../components/cisco_webex_teams/__init__.py | 1 + .../components/cisco_webex_teams/notify.py | 60 +++++++++++++++++++ requirements_all.txt | 3 + 4 files changed, 65 insertions(+) create mode 100644 homeassistant/components/cisco_webex_teams/__init__.py create mode 100644 homeassistant/components/cisco_webex_teams/notify.py diff --git a/.coveragerc b/.coveragerc index cae3bf423a9..25e5cf8bb03 100644 --- a/.coveragerc +++ b/.coveragerc @@ -87,6 +87,7 @@ omit = homeassistant/components/channels/media_player.py homeassistant/components/cisco_ios/device_tracker.py homeassistant/components/cisco_mobility_express/device_tracker.py + homeassistant/components/cisco_webex_teams/notify.py homeassistant/components/ciscospark/notify.py homeassistant/components/citybikes/sensor.py homeassistant/components/clementine/media_player.py diff --git a/homeassistant/components/cisco_webex_teams/__init__.py b/homeassistant/components/cisco_webex_teams/__init__.py new file mode 100644 index 00000000000..0a8714806a1 --- /dev/null +++ b/homeassistant/components/cisco_webex_teams/__init__.py @@ -0,0 +1 @@ +"""Component to integrate the Cisco Webex Teams cloud.""" diff --git a/homeassistant/components/cisco_webex_teams/notify.py b/homeassistant/components/cisco_webex_teams/notify.py new file mode 100644 index 00000000000..f893d4071b0 --- /dev/null +++ b/homeassistant/components/cisco_webex_teams/notify.py @@ -0,0 +1,60 @@ +"""Cisco Webex Teams notify component.""" +import logging + +import voluptuous as vol + +from homeassistant.components.notify import ( + PLATFORM_SCHEMA, BaseNotificationService, ATTR_TITLE) +from homeassistant.const import (CONF_TOKEN) +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['webexteamssdk==1.1.1'] + +_LOGGER = logging.getLogger(__name__) + +CONF_ROOM_ID = 'room_id' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_TOKEN): cv.string, + vol.Required(CONF_ROOM_ID): cv.string, +}) + + +def get_service(hass, config, discovery_info=None): + """Get the CiscoWebexTeams notification service.""" + from webexteamssdk import WebexTeamsAPI, exceptions + client = WebexTeamsAPI(access_token=config[CONF_TOKEN]) + try: + # Validate the token & room_id + client.rooms.get(config[CONF_ROOM_ID]) + except exceptions.ApiError as error: + _LOGGER.error(error) + return None + + return CiscoWebexTeamsNotificationService( + client, + config[CONF_ROOM_ID]) + + +class CiscoWebexTeamsNotificationService(BaseNotificationService): + """The Cisco Webex Teams Notification Service.""" + + def __init__(self, client, room): + """Initialize the service.""" + self.room = room + self.client = client + + def send_message(self, message="", **kwargs): + """Send a message to a user.""" + from webexteamssdk import ApiError + title = "" + if kwargs.get(ATTR_TITLE) is not None: + title = "{}{}".format(kwargs.get(ATTR_TITLE), "
") + + try: + self.client.messages.create(roomId=self.room, + html="{}{}".format(title, message)) + except ApiError as api_error: + _LOGGER.error("Could not send CiscoWebexTeams notification. " + "Error: %s", + api_error) diff --git a/requirements_all.txt b/requirements_all.txt index 6d136a11fb1..8ed77fdfb3e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1783,6 +1783,9 @@ watchdog==0.8.3 # homeassistant.components.waterfurnace waterfurnace==1.1.0 +# homeassistant.components.cisco_webex_teams.notify +webexteamssdk==1.1.1 + # homeassistant.components.gpmdp.media_player websocket-client==0.54.0 From 7c5846aed290e405a31d0861a8842d0944280e84 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Wed, 3 Apr 2019 07:49:53 +0100 Subject: [PATCH 062/167] Fix #22648 - Utility_meter would try to cancel a non existing task (#22669) * don't cancel tariff that are paused * test tariffs --- .../components/utility_meter/sensor.py | 3 +- tests/components/utility_meter/test_sensor.py | 43 ++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index dd1514f5e43..2c151634a95 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -118,7 +118,8 @@ class UtilityMeterSensor(RestoreEntity): self._collecting = async_track_state_change( self.hass, self._sensor_source_id, self.async_reading) else: - self._collecting() + if self._collecting: + self._collecting() self._collecting = None _LOGGER.debug("%s - %s - source <%s>", self._name, diff --git a/tests/components/utility_meter/test_sensor.py b/tests/components/utility_meter/test_sensor.py index ee291439a2c..6b8705bf776 100644 --- a/tests/components/utility_meter/test_sensor.py +++ b/tests/components/utility_meter/test_sensor.py @@ -6,10 +6,11 @@ from unittest.mock import patch from contextlib import contextmanager from tests.common import async_fire_time_changed -from homeassistant.const import EVENT_HOMEASSISTANT_START +from homeassistant.const import EVENT_HOMEASSISTANT_START, ATTR_ENTITY_ID from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util -from homeassistant.components.utility_meter.const import DOMAIN +from homeassistant.components.utility_meter.const import ( + DOMAIN, SERVICE_SELECT_TARIFF, ATTR_TARIFF) from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN _LOGGER = logging.getLogger(__name__) @@ -31,7 +32,7 @@ async def test_state(hass): 'utility_meter': { 'energy_bill': { 'source': 'sensor.energy', - } + 'tariffs': ['onpeak', 'midpeak', 'offpeak']}, } } @@ -51,11 +52,43 @@ async def test_state(hass): force_update=True) await hass.async_block_till_done() - state = hass.states.get('sensor.energy_bill') + state = hass.states.get('sensor.energy_bill_onpeak') assert state is not None - assert state.state == '1' + state = hass.states.get('sensor.energy_bill_midpeak') + assert state is not None + assert state.state == '0' + + state = hass.states.get('sensor.energy_bill_offpeak') + assert state is not None + assert state.state == '0' + + await hass.services.async_call(DOMAIN, SERVICE_SELECT_TARIFF, { + ATTR_ENTITY_ID: 'utility_meter.energy_bill', ATTR_TARIFF: 'offpeak' + }, blocking=True) + + await hass.async_block_till_done() + + now = dt_util.utcnow() + timedelta(seconds=20) + with patch('homeassistant.util.dt.utcnow', + return_value=now): + hass.states.async_set(entity_id, 6, {"unit_of_measurement": "kWh"}, + force_update=True) + await hass.async_block_till_done() + + state = hass.states.get('sensor.energy_bill_onpeak') + assert state is not None + assert state.state == '1' + + state = hass.states.get('sensor.energy_bill_midpeak') + assert state is not None + assert state.state == '0' + + state = hass.states.get('sensor.energy_bill_offpeak') + assert state is not None + assert state.state == '3' + async def test_net_consumption(hass): """Test utility sensor state.""" From 58a89640bb3c6f65ad2c7f0c906c2c6c6fb8da7f Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 3 Apr 2019 12:20:05 +0200 Subject: [PATCH 063/167] Update uvloop to 0.12.2 (#22681) --- virtualization/Docker/Dockerfile.dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtualization/Docker/Dockerfile.dev b/virtualization/Docker/Dockerfile.dev index 90c9eee3485..4be2c382226 100644 --- a/virtualization/Docker/Dockerfile.dev +++ b/virtualization/Docker/Dockerfile.dev @@ -29,7 +29,7 @@ COPY requirements_all.txt requirements_all.txt # Uninstall enum34 because some dependencies install it but breaks Python 3.4+. # See PR #8103 for more info. RUN pip3 install --no-cache-dir -r requirements_all.txt && \ - pip3 install --no-cache-dir mysqlclient psycopg2 uvloop==0.11.3 cchardet cython + pip3 install --no-cache-dir mysqlclient psycopg2 uvloop==0.12.2 cchardet cython # BEGIN: Development additions From 7066fb0d101e075e478736f8476fa845a5011b4c Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 3 Apr 2019 13:46:41 +0200 Subject: [PATCH 064/167] Fix ffmpeg default extra options (#22682) --- homeassistant/components/amcrest/__init__.py | 4 +++- homeassistant/components/arlo/camera.py | 7 ++++--- homeassistant/components/canary/camera.py | 7 ++++--- homeassistant/components/ffmpeg/camera.py | 4 +++- homeassistant/components/onvif/camera.py | 2 +- homeassistant/components/xiaomi/camera.py | 3 ++- homeassistant/components/yi/camera.py | 3 ++- 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/amcrest/__init__.py b/homeassistant/components/amcrest/__init__.py index 295b798c3b1..ff34ca6f5c7 100644 --- a/homeassistant/components/amcrest/__init__.py +++ b/homeassistant/components/amcrest/__init__.py @@ -26,6 +26,7 @@ DEFAULT_NAME = 'Amcrest Camera' DEFAULT_PORT = 80 DEFAULT_RESOLUTION = 'high' DEFAULT_STREAM_SOURCE = 'snapshot' +DEFAULT_ARGUMENTS = '-pred 1' TIMEOUT = 10 DATA_AMCREST = 'amcrest' @@ -77,7 +78,8 @@ CONFIG_SCHEMA = vol.Schema({ vol.All(vol.In(RESOLUTION_LIST)), vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE): vol.All(vol.In(STREAM_SOURCE_LIST)), - vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string, + vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): + cv.string, vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period, vol.Optional(CONF_SENSORS): diff --git a/homeassistant/components/arlo/camera.py b/homeassistant/components/arlo/camera.py index 95d11318bf7..d4b00f00625 100644 --- a/homeassistant/components/arlo/camera.py +++ b/homeassistant/components/arlo/camera.py @@ -13,6 +13,8 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from . import DATA_ARLO, DEFAULT_BRAND, SIGNAL_UPDATE_ARLO +DEPENDENCIES = ['arlo', 'ffmpeg'] + _LOGGER = logging.getLogger(__name__) ARLO_MODE_ARMED = 'armed' @@ -28,8 +30,7 @@ ATTR_UNSEEN_VIDEOS = 'unseen_videos' ATTR_LAST_REFRESH = 'last_refresh' CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments' - -DEPENDENCIES = ['arlo', 'ffmpeg'] +DEFAULT_ARGUMENTS = '-pred 1' POWERSAVE_MODE_MAPPING = { 1: 'best_battery_life', @@ -38,7 +39,7 @@ POWERSAVE_MODE_MAPPING = { } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string, + vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string, }) diff --git a/homeassistant/components/canary/camera.py b/homeassistant/components/canary/camera.py index 63c27d31d93..c3a3af32450 100644 --- a/homeassistant/components/canary/camera.py +++ b/homeassistant/components/canary/camera.py @@ -18,16 +18,17 @@ from homeassistant.util import Throttle from . import DATA_CANARY, DEFAULT_TIMEOUT -CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments' - DEPENDENCIES = ['canary', 'ffmpeg'] _LOGGER = logging.getLogger(__name__) +CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments' +DEFAULT_ARGUMENTS = '-pred 1' + MIN_TIME_BETWEEN_SESSION_RENEW = timedelta(seconds=90) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string, + vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string, }) diff --git a/homeassistant/components/ffmpeg/camera.py b/homeassistant/components/ffmpeg/camera.py index d897293124b..07e56cfd51f 100644 --- a/homeassistant/components/ffmpeg/camera.py +++ b/homeassistant/components/ffmpeg/camera.py @@ -20,11 +20,13 @@ from . import CONF_EXTRA_ARGUMENTS, CONF_INPUT, DATA_FFMPEG _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['ffmpeg'] + DEFAULT_NAME = 'FFmpeg' +DEFAULT_ARGUMENTS = "-pred 1" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_INPUT): cv.string, - vol.Optional(CONF_EXTRA_ARGUMENTS): cv.string, + vol.Optional(CONF_EXTRA_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) diff --git a/homeassistant/components/onvif/camera.py b/homeassistant/components/onvif/camera.py index 09d47c3c0c9..a196f87cd10 100644 --- a/homeassistant/components/onvif/camera.py +++ b/homeassistant/components/onvif/camera.py @@ -33,7 +33,7 @@ DEFAULT_NAME = 'ONVIF Camera' DEFAULT_PORT = 5000 DEFAULT_USERNAME = 'admin' DEFAULT_PASSWORD = '888888' -DEFAULT_ARGUMENTS = '-q:v 2' +DEFAULT_ARGUMENTS = '-pred 1' DEFAULT_PROFILE = 0 CONF_PROFILE = "profile" diff --git a/homeassistant/components/xiaomi/camera.py b/homeassistant/components/xiaomi/camera.py index d8cd59129ab..b0acf50ec8c 100644 --- a/homeassistant/components/xiaomi/camera.py +++ b/homeassistant/components/xiaomi/camera.py @@ -23,6 +23,7 @@ DEFAULT_BRAND = 'Xiaomi Home Camera' DEFAULT_PATH = '/media/mmcblk0p1/record' DEFAULT_PORT = 21 DEFAULT_USERNAME = 'root' +DEFAULT_ARGUMENTS = '-pred 1' CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments' CONF_MODEL = 'model' @@ -39,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string, vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, - vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string + vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string }) diff --git a/homeassistant/components/yi/camera.py b/homeassistant/components/yi/camera.py index c60d4971fb8..f82c8c38129 100644 --- a/homeassistant/components/yi/camera.py +++ b/homeassistant/components/yi/camera.py @@ -26,6 +26,7 @@ DEFAULT_PASSWORD = '' DEFAULT_PATH = '/tmp/sd/record' DEFAULT_PORT = 21 DEFAULT_USERNAME = 'root' +DEFAULT_ARGUMENTS = '-pred 1' CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments' @@ -36,7 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string, vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, - vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string + vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string }) From b1cca25299b247e43ddde1e5fd4c376130547850 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 3 Apr 2019 04:53:44 -0700 Subject: [PATCH 065/167] Deal with cover assumed state (#22673) * Deal with cover assumed state * Add docs --- .../components/google_assistant/trait.py | 17 ++++++++++---- .../components/google_assistant/test_trait.py | 23 +++++++++++++++++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index 81918ff2e88..de3a9530b50 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -27,6 +27,7 @@ from homeassistant.const import ( TEMP_FAHRENHEIT, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE, + ATTR_ASSUMED_STATE, ) from homeassistant.core import DOMAIN as HA_DOMAIN from homeassistant.util import color as color_util, temperature as temp_util @@ -1055,11 +1056,19 @@ class OpenCloseTrait(_Trait): response = {} if domain == cover.DOMAIN: - position = self.state.attributes.get(cover.ATTR_CURRENT_POSITION) - if position is not None: - response['openPercent'] = position + # When it's an assumed state, we will always report it as 50% + # Google will not issue an open command if the assumed state is + # open, even if that is currently incorrect. + if self.state.attributes.get(ATTR_ASSUMED_STATE): + response['openPercent'] = 50 else: - if self.state.state != cover.STATE_CLOSED: + position = self.state.attributes.get( + cover.ATTR_CURRENT_POSITION + ) + + if position is not None: + response['openPercent'] = position + elif self.state.state != cover.STATE_CLOSED: response['openPercent'] = 100 else: response['openPercent'] = 0 diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index a0a710d3d8c..81a7fbe1bf7 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -21,7 +21,8 @@ from homeassistant.components.climate import const as climate from homeassistant.components.google_assistant import trait, helpers, const from homeassistant.const import ( STATE_ON, STATE_OFF, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, - TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE) + TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE, + ATTR_ASSUMED_STATE) from homeassistant.core import State, DOMAIN as HA_DOMAIN, EVENT_CALL_SERVICE from homeassistant.util import color from tests.common import async_mock_service, mock_coro @@ -1059,12 +1060,30 @@ async def test_openclose_cover(hass): assert trait.OpenCloseTrait.supported(cover.DOMAIN, cover.SUPPORT_SET_POSITION) + # No position + trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, { + }), BASIC_CONFIG) + + assert trt.sync_attributes() == {} + assert trt.query_attributes() == { + 'openPercent': 100 + } + + # Assumed state + trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, { + ATTR_ASSUMED_STATE: True, + }), BASIC_CONFIG) + + assert trt.sync_attributes() == {} + assert trt.query_attributes() == { + 'openPercent': 50 + } + trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, { cover.ATTR_CURRENT_POSITION: 75 }), BASIC_CONFIG) assert trt.sync_attributes() == {} - assert trt.query_attributes() == { 'openPercent': 75 } From b797b1513a54a9a6621179de480e60d4932a34f1 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Wed, 3 Apr 2019 05:21:25 -0700 Subject: [PATCH 066/167] Add mobile_app notify platform (#22580) * Add mobile_app notify platform * Requested changes * Fix incorrect param for status code * Move push_registrations to notify platform file * Trim down registration information sent in push * quotes * Use async version of load_platform * Add warning for duplicate device names * Switch to async_get_service * add mobile_app.notify test * Update tests/components/mobile_app/test_notify.py * Update tests/components/mobile_app/test_notify.py --- .../components/mobile_app/__init__.py | 13 +- homeassistant/components/mobile_app/const.py | 2 + homeassistant/components/mobile_app/notify.py | 134 ++++++++++++++++++ tests/components/mobile_app/test_notify.py | 81 +++++++++++ 4 files changed, 225 insertions(+), 5 deletions(-) create mode 100644 homeassistant/components/mobile_app/notify.py create mode 100644 tests/components/mobile_app/test_notify.py diff --git a/homeassistant/components/mobile_app/__init__.py b/homeassistant/components/mobile_app/__init__.py index ecbe8d70847..a4ae78959cf 100644 --- a/homeassistant/components/mobile_app/__init__.py +++ b/homeassistant/components/mobile_app/__init__.py @@ -2,13 +2,13 @@ from homeassistant import config_entries from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.components.webhook import async_register as webhook_register -from homeassistant.helpers import device_registry as dr +from homeassistant.helpers import device_registry as dr, discovery from homeassistant.helpers.typing import ConfigType, HomeAssistantType -from .const import (ATTR_DEVICE_ID, ATTR_DEVICE_NAME, ATTR_MANUFACTURER, - ATTR_MODEL, ATTR_OS_VERSION, DATA_BINARY_SENSOR, - DATA_CONFIG_ENTRIES, DATA_DELETED_IDS, DATA_DEVICES, - DATA_SENSOR, DATA_STORE, DOMAIN, STORAGE_KEY, +from .const import (ATTR_DEVICE_ID, ATTR_DEVICE_NAME, + ATTR_MANUFACTURER, ATTR_MODEL, ATTR_OS_VERSION, + DATA_BINARY_SENSOR, DATA_CONFIG_ENTRIES, DATA_DELETED_IDS, + DATA_DEVICES, DATA_SENSOR, DATA_STORE, DOMAIN, STORAGE_KEY, STORAGE_VERSION) from .http_api import RegistrationsView @@ -52,6 +52,9 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType): except ValueError: pass + hass.async_create_task(discovery.async_load_platform( + hass, 'notify', DOMAIN, {}, config)) + return True diff --git a/homeassistant/components/mobile_app/const.py b/homeassistant/components/mobile_app/const.py index 38897056c11..b59c631ba99 100644 --- a/homeassistant/components/mobile_app/const.py +++ b/homeassistant/components/mobile_app/const.py @@ -40,6 +40,8 @@ ATTR_MANUFACTURER = 'manufacturer' ATTR_MODEL = 'model' ATTR_OS_NAME = 'os_name' ATTR_OS_VERSION = 'os_version' +ATTR_PUSH_TOKEN = 'push_token' +ATTR_PUSH_URL = 'push_url' ATTR_SUPPORTS_ENCRYPTION = 'supports_encryption' ATTR_EVENT_DATA = 'event_data' diff --git a/homeassistant/components/mobile_app/notify.py b/homeassistant/components/mobile_app/notify.py new file mode 100644 index 00000000000..0120b1a6ffb --- /dev/null +++ b/homeassistant/components/mobile_app/notify.py @@ -0,0 +1,134 @@ +"""Support for mobile_app push notifications.""" +import asyncio +from datetime import datetime, timezone +import logging + +import async_timeout + +from homeassistant.components.notify import ( + ATTR_DATA, ATTR_MESSAGE, ATTR_TARGET, ATTR_TITLE, ATTR_TITLE_DEFAULT, + BaseNotificationService) +from homeassistant.components.mobile_app.const import ( + ATTR_APP_DATA, ATTR_APP_ID, ATTR_APP_VERSION, ATTR_DEVICE_NAME, + ATTR_OS_VERSION, ATTR_PUSH_TOKEN, ATTR_PUSH_URL, DATA_CONFIG_ENTRIES, + DOMAIN) +from homeassistant.helpers.aiohttp_client import async_get_clientsession +import homeassistant.util.dt as dt_util + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['mobile_app'] + + +def push_registrations(hass): + """Return a dictionary of push enabled registrations.""" + targets = {} + for webhook_id, entry in hass.data[DOMAIN][DATA_CONFIG_ENTRIES].items(): + data = entry.data + app_data = data[ATTR_APP_DATA] + if ATTR_PUSH_TOKEN in app_data and ATTR_PUSH_URL in app_data: + device_name = data[ATTR_DEVICE_NAME] + if device_name in targets: + _LOGGER.warning("Found duplicate device name %s", device_name) + continue + targets[device_name] = webhook_id + return targets + + +# pylint: disable=invalid-name +def log_rate_limits(hass, device_name, resp, level=logging.INFO): + """Output rate limit log line at given level.""" + rate_limits = resp['rateLimits'] + resetsAt = dt_util.parse_datetime(rate_limits['resetsAt']) + resetsAtTime = resetsAt - datetime.now(timezone.utc) + rate_limit_msg = ("mobile_app push notification rate limits for %s: " + "%d sent, %d allowed, %d errors, " + "resets in %s") + _LOGGER.log(level, rate_limit_msg, + device_name, + rate_limits['successful'], + rate_limits['maximum'], rate_limits['errors'], + str(resetsAtTime).split(".")[0]) + + +async def async_get_service(hass, config, discovery_info=None): + """Get the mobile_app notification service.""" + session = async_get_clientsession(hass) + return MobileAppNotificationService(session) + + +class MobileAppNotificationService(BaseNotificationService): + """Implement the notification service for mobile_app.""" + + def __init__(self, session): + """Initialize the service.""" + self._session = session + + @property + def targets(self): + """Return a dictionary of registered targets.""" + return push_registrations(self.hass) + + async def async_send_message(self, message="", **kwargs): + """Send a message to the Lambda APNS gateway.""" + data = {ATTR_MESSAGE: message} + + if kwargs.get(ATTR_TITLE) is not None: + # Remove default title from notifications. + if kwargs.get(ATTR_TITLE) != ATTR_TITLE_DEFAULT: + data[ATTR_TITLE] = kwargs.get(ATTR_TITLE) + + targets = kwargs.get(ATTR_TARGET) + + if not targets: + targets = push_registrations(self.hass) + + if kwargs.get(ATTR_DATA) is not None: + data[ATTR_DATA] = kwargs.get(ATTR_DATA) + + for target in targets: + + entry = self.hass.data[DOMAIN][DATA_CONFIG_ENTRIES][target] + entry_data = entry.data + + app_data = entry_data[ATTR_APP_DATA] + push_token = app_data[ATTR_PUSH_TOKEN] + push_url = app_data[ATTR_PUSH_URL] + + data[ATTR_PUSH_TOKEN] = push_token + + reg_info = { + ATTR_APP_ID: entry_data[ATTR_APP_ID], + ATTR_APP_VERSION: entry_data[ATTR_APP_VERSION], + } + if ATTR_OS_VERSION in entry_data: + reg_info[ATTR_OS_VERSION] = entry_data[ATTR_OS_VERSION] + + data['registration_info'] = reg_info + + try: + with async_timeout.timeout(10, loop=self.hass.loop): + response = await self._session.post(push_url, json=data) + result = await response.json() + + if response.status == 201: + log_rate_limits(self.hass, + entry_data[ATTR_DEVICE_NAME], result) + return + + fallback_error = result.get("errorMessage", + "Unknown error") + fallback_message = ("Internal server error, " + "please try again later: " + "{}").format(fallback_error) + message = result.get("message", fallback_message) + if response.status == 429: + _LOGGER.warning(message) + log_rate_limits(self.hass, + entry_data[ATTR_DEVICE_NAME], + result, logging.WARNING) + else: + _LOGGER.error(message) + + except asyncio.TimeoutError: + _LOGGER.error("Timeout sending notification to %s", push_url) diff --git a/tests/components/mobile_app/test_notify.py b/tests/components/mobile_app/test_notify.py new file mode 100644 index 00000000000..395dee6c117 --- /dev/null +++ b/tests/components/mobile_app/test_notify.py @@ -0,0 +1,81 @@ +"""Notify platform tests for mobile_app.""" +# pylint: disable=redefined-outer-name +import pytest + +from homeassistant.setup import async_setup_component + +from homeassistant.components.mobile_app.const import DOMAIN + +from tests.common import MockConfigEntry + + +@pytest.fixture +async def setup_push_receiver(hass, aioclient_mock): + """Fixture that sets up a mocked push receiver.""" + push_url = 'https://mobile-push.home-assistant.dev/push' + + from datetime import datetime, timedelta + now = (datetime.now() + timedelta(hours=24)) + iso_time = now.strftime("%Y-%m-%dT%H:%M:%SZ") + + aioclient_mock.post(push_url, json={ + 'rateLimits': { + 'attempts': 1, + 'successful': 1, + 'errors': 0, + 'total': 1, + 'maximum': 150, + 'remaining': 149, + 'resetsAt': iso_time + } + }) + + entry = MockConfigEntry( + connection_class="cloud_push", + data={ + "app_data": { + "push_token": "PUSH_TOKEN", + "push_url": push_url + }, + "app_id": "io.homeassistant.mobile_app", + "app_name": "mobile_app tests", + "app_version": "1.0", + "device_id": "4d5e6f", + "device_name": "Test", + "manufacturer": "Home Assistant", + "model": "mobile_app", + "os_name": "Linux", + "os_version": "5.0.6", + "secret": "123abc", + "supports_encryption": False, + "user_id": "1a2b3c", + "webhook_id": "webhook_id" + }, + domain=DOMAIN, + source="registration", + title="mobile_app test entry", + version=1 + ) + entry.add_to_hass(hass) + + await async_setup_component(hass, DOMAIN, {DOMAIN: {}}) + await hass.async_block_till_done() + + +async def test_notify_works(hass, aioclient_mock, setup_push_receiver): + """Test notify works.""" + assert hass.services.has_service('notify', 'mobile_app_test') is True + assert await hass.services.async_call('notify', 'mobile_app_test', + {'message': 'Hello world'}, + blocking=True) + + assert len(aioclient_mock.mock_calls) == 1 + call = aioclient_mock.mock_calls + + call_json = call[0][2] + + assert call_json["push_token"] == "PUSH_TOKEN" + assert call_json["message"] == "Hello world" + assert call_json["registration_info"]["app_id"] == \ + "io.homeassistant.mobile_app" + assert call_json["registration_info"]["app_version"] == "1.0" From 625c8e0ceeca0eff0513058d3ad784f01eda5644 Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Wed, 3 Apr 2019 09:40:48 -0400 Subject: [PATCH 067/167] Shutdown ZHAGateway on hass closing. (#22646) * Shutdown ZHAGateway on hass stop. * Cleanup ZHA event leftovers. --- homeassistant/components/zha/__init__.py | 21 ++++++++------------ homeassistant/components/zha/core/const.py | 1 - homeassistant/components/zha/core/gateway.py | 16 +++++++++------ homeassistant/components/zha/core/helpers.py | 2 +- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index 292b4fde61f..088ffff13d1 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -16,15 +16,14 @@ from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from . import config_flow # noqa # pylint: disable=unused-import from . import api from .core import ZHAGateway +from .core.channels.registry import populate_channel_registry from .core.const import ( COMPONENTS, CONF_BAUDRATE, CONF_DATABASE, CONF_DEVICE_CONFIG, - CONF_RADIO_TYPE, CONF_USB_PATH, DATA_ZHA, - DATA_ZHA_CONFIG, DATA_ZHA_CORE_COMPONENT, DATA_ZHA_DISPATCHERS, - DATA_ZHA_RADIO, DEFAULT_BAUDRATE, DATA_ZHA_GATEWAY, - DEFAULT_RADIO_TYPE, DOMAIN, RadioType, DATA_ZHA_CORE_EVENTS, ENABLE_QUIRKS) -from .core.registries import establish_device_mappings -from .core.channels.registry import populate_channel_registry + CONF_RADIO_TYPE, CONF_USB_PATH, DATA_ZHA, DATA_ZHA_CONFIG, + DATA_ZHA_CORE_COMPONENT, DATA_ZHA_DISPATCHERS, DATA_ZHA_GATEWAY, + DEFAULT_BAUDRATE, DEFAULT_RADIO_TYPE, DOMAIN, ENABLE_QUIRKS, RadioType) from .core.patches import apply_cluster_listener_patch +from .core.registries import establish_device_mappings REQUIREMENTS = [ 'bellows-homeassistant==0.7.2', @@ -143,9 +142,9 @@ async def async_setup_entry(hass, config_entry): async def async_zha_shutdown(event): """Handle shutdown tasks.""" + await hass.data[DATA_ZHA][DATA_ZHA_GATEWAY].shutdown() await hass.data[DATA_ZHA][ DATA_ZHA_GATEWAY].async_update_device_storage() - hass.data[DATA_ZHA][DATA_ZHA_RADIO].close() hass.bus.async_listen_once( ha_const.EVENT_HOMEASSISTANT_STOP, async_zha_shutdown) @@ -154,6 +153,8 @@ async def async_setup_entry(hass, config_entry): async def async_unload_entry(hass, config_entry): """Unload ZHA config entry.""" + await hass.data[DATA_ZHA][DATA_ZHA_GATEWAY].shutdown() + api.async_unload_api(hass) dispatchers = hass.data[DATA_ZHA].get(DATA_ZHA_DISPATCHERS, []) @@ -170,11 +171,5 @@ async def async_unload_entry(hass, config_entry): for entity_id in entity_ids: await component.async_remove_entity(entity_id) - # clean up events - hass.data[DATA_ZHA][DATA_ZHA_CORE_EVENTS].clear() - - _LOGGER.debug("Closing zha radio") - hass.data[DATA_ZHA][DATA_ZHA_RADIO].close() - del hass.data[DATA_ZHA] return True diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index b7f418253d8..02f43a4bbf6 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -17,7 +17,6 @@ BAUD_RATES = [ DATA_ZHA = 'zha' DATA_ZHA_CONFIG = 'config' DATA_ZHA_BRIDGE_ID = 'zha_bridge_id' -DATA_ZHA_RADIO = 'zha_radio' DATA_ZHA_DISPATCHERS = 'zha_dispatchers' DATA_ZHA_CORE_COMPONENT = 'zha_core_component' DATA_ZHA_CORE_EVENTS = 'zha_core_events' diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 71e41c2509b..83013b7bdf7 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -23,11 +23,11 @@ from .const import ( ADD_DEVICE_RELAY_LOGGERS, ATTR_MANUFACTURER, BELLOWS, CONF_BAUDRATE, CONF_DATABASE, CONF_RADIO_TYPE, CONF_USB_PATH, CONTROLLER, CURRENT, DATA_ZHA, DATA_ZHA_BRIDGE_ID, DATA_ZHA_CORE_COMPONENT, DATA_ZHA_GATEWAY, - DATA_ZHA_RADIO, DEBUG_LEVELS, DEFAULT_BAUDRATE, DEFAULT_DATABASE_NAME, - DEVICE_FULL_INIT, DEVICE_INFO, DEVICE_JOINED, DEVICE_REMOVED, DOMAIN, IEEE, - LOG_ENTRY, LOG_OUTPUT, MODEL, NWK, ORIGINAL, RADIO, RADIO_DESCRIPTION, - RAW_INIT, SIGNAL_REMOVE, SIGNATURE, TYPE, ZHA, ZHA_GW_MSG, ZIGPY, - ZIGPY_DECONZ, ZIGPY_XBEE) + DEBUG_LEVELS, DEFAULT_BAUDRATE, DEFAULT_DATABASE_NAME, DEVICE_FULL_INIT, + DEVICE_INFO, DEVICE_JOINED, DEVICE_REMOVED, DOMAIN, IEEE, LOG_ENTRY, + LOG_OUTPUT, MODEL, NWK, ORIGINAL, RADIO, RADIO_DESCRIPTION, RAW_INIT, + SIGNAL_REMOVE, SIGNATURE, TYPE, ZHA, ZHA_GW_MSG, ZIGPY, ZIGPY_DECONZ, + ZIGPY_XBEE) from .device import DeviceStatus, ZHADevice from .discovery import ( async_create_device_entity, async_dispatch_discovery_info, @@ -76,7 +76,6 @@ class ZHAGateway: radio = radio_details[RADIO] self.radio_description = RADIO_TYPES[radio_type][RADIO_DESCRIPTION] await radio.connect(usb_path, baudrate) - self._hass.data[DATA_ZHA][DATA_ZHA_RADIO] = radio if CONF_DATABASE in self._config: database = self._config[CONF_DATABASE] @@ -312,6 +311,11 @@ class ZHAGateway: } ) + async def shutdown(self): + """Stop ZHA Controller Application.""" + _LOGGER.debug("Shutting down ZHA ControllerApplication") + await self.application_controller.shutdown() + @callback def async_capture_log_levels(): diff --git a/homeassistant/components/zha/core/helpers.py b/homeassistant/components/zha/core/helpers.py index 695f2be5960..ef7c2df6ce0 100644 --- a/homeassistant/components/zha/core/helpers.py +++ b/homeassistant/components/zha/core/helpers.py @@ -139,7 +139,7 @@ async def check_zigpy_connection(usb_path, radio_type, database_path): await radio.connect(usb_path, DEFAULT_BAUDRATE) controller = ControllerApplication(radio, database_path) await asyncio.wait_for(controller.startup(auto_form=True), timeout=30) - radio.close() + await controller.shutdown() except Exception: # pylint: disable=broad-except return False return True From 048b100eea478665ded47a5f238fc68c96199436 Mon Sep 17 00:00:00 2001 From: Tobias Sauerwein Date: Wed, 3 Apr 2019 17:40:03 +0200 Subject: [PATCH 068/167] Clean up docstrings (#22679) * Clean up docstrings * Fix long lines * Fix more docstrings * Fix more docstrings * Fix more docstrings --- homeassistant/components/acer_projector/switch.py | 7 +------ homeassistant/components/actiontec/device_tracker.py | 7 +------ homeassistant/components/aftership/sensor.py | 7 +------ homeassistant/components/air_quality/__init__.py | 7 +------ homeassistant/components/airvisual/sensor.py | 7 +------ homeassistant/components/aladdin_connect/cover.py | 7 +------ .../components/alarm_control_panel/__init__.py | 7 +------ .../components/alarmdotcom/alarm_control_panel.py | 7 +------ homeassistant/components/alpha_vantage/sensor.py | 7 +------ homeassistant/components/amazon_polly/tts.py | 7 +------ homeassistant/components/androidtv/__init__.py | 7 +------ homeassistant/components/androidtv/media_player.py | 7 +------ homeassistant/components/anel_pwrctrl/switch.py | 7 +------ homeassistant/components/anthemav/media_player.py | 7 +------ homeassistant/components/apns/notify.py | 7 +------ homeassistant/components/aquostv/media_player.py | 7 +------ homeassistant/components/arest/binary_sensor.py | 7 +------ homeassistant/components/arest/sensor.py | 7 +------ homeassistant/components/arest/switch.py | 7 +------ homeassistant/components/aruba/device_tracker.py | 7 +------ homeassistant/components/arwn/sensor.py | 7 +------ homeassistant/components/asuswrt/device_tracker.py | 7 +------ homeassistant/components/asuswrt/sensor.py | 7 +------ homeassistant/components/aurora/binary_sensor.py | 7 +------ homeassistant/components/automatic/device_tracker.py | 7 +------ homeassistant/components/avion/light.py | 7 +------ homeassistant/components/awair/sensor.py | 7 +------ homeassistant/components/aws_lambda/notify.py | 7 +------ homeassistant/components/aws_sns/notify.py | 7 +------ homeassistant/components/aws_sqs/notify.py | 7 +------ homeassistant/components/baidu/tts.py | 8 +------- homeassistant/components/bayesian/binary_sensor.py | 7 +------ homeassistant/components/bbox/device_tracker.py | 7 +------ homeassistant/components/bbox/sensor.py | 7 +------ homeassistant/components/bh1750/sensor.py | 7 +------ homeassistant/components/binary_sensor/__init__.py | 7 +------ homeassistant/components/bitcoin/sensor.py | 7 +------ homeassistant/components/blackbird/media_player.py | 7 +------ homeassistant/components/blinksticklight/light.py | 7 +------ homeassistant/components/blinkt/light.py | 7 +------ homeassistant/components/blockchain/sensor.py | 7 +------ homeassistant/components/bluesound/media_player.py | 7 +------ .../components/bluetooth_le_tracker/device_tracker.py | 7 +------ .../components/bluetooth_tracker/device_tracker.py | 7 +------ homeassistant/components/bme280/sensor.py | 7 +------ homeassistant/components/bme680/sensor.py | 10 +--------- homeassistant/components/bom/sensor.py | 7 +------ homeassistant/components/braviatv/media_player.py | 7 +------ homeassistant/components/broadlink/sensor.py | 7 +------ homeassistant/components/broadlink/switch.py | 7 +------ homeassistant/components/brottsplatskartan/sensor.py | 7 +------ homeassistant/components/brunt/cover.py | 7 +------ .../components/bt_home_hub_5/device_tracker.py | 7 +------ homeassistant/components/bt_smarthub/device_tracker.py | 7 +------ homeassistant/components/buienradar/sensor.py | 7 +------ homeassistant/components/caldav/calendar.py | 7 +------ homeassistant/components/camera/__init__.py | 7 +------ homeassistant/components/canary/alarm_control_panel.py | 7 +------ homeassistant/components/canary/camera.py | 7 +------ homeassistant/components/canary/sensor.py | 7 +------ homeassistant/components/cert_expiry/sensor.py | 7 +------ homeassistant/components/channels/media_player.py | 7 +------ homeassistant/components/cisco_ios/device_tracker.py | 7 +------ homeassistant/components/ciscospark/notify.py | 7 +------ homeassistant/components/citybikes/sensor.py | 7 +------ homeassistant/components/clementine/media_player.py | 7 +------ homeassistant/components/clickatell/notify.py | 7 +------ homeassistant/components/clicksend/notify.py | 7 +------ homeassistant/components/clicksend_tts/notify.py | 9 +-------- homeassistant/components/climate/__init__.py | 7 +------ homeassistant/components/cmus/media_player.py | 7 +------ homeassistant/components/co2signal/sensor.py | 6 +----- homeassistant/components/coinbase/sensor.py | 7 +------ homeassistant/components/coinmarketcap/sensor.py | 7 +------ .../components/comed_hourly_pricing/sensor.py | 7 +------ homeassistant/components/command_line/binary_sensor.py | 7 +------ homeassistant/components/command_line/cover.py | 7 +------ homeassistant/components/command_line/notify.py | 7 +------ homeassistant/components/command_line/sensor.py | 7 +------ homeassistant/components/command_line/switch.py | 7 +------ .../components/concord232/alarm_control_panel.py | 7 +------ homeassistant/components/concord232/binary_sensor.py | 7 +------ homeassistant/components/coolmaster/climate.py | 7 +------ homeassistant/components/cover/__init__.py | 7 +------ .../components/cppm_tracker/device_tracker.py | 6 +----- homeassistant/components/cups/sensor.py | 7 +------ homeassistant/components/currencylayer/sensor.py | 7 +------ homeassistant/components/darksky/sensor.py | 7 +------ homeassistant/components/ddwrt/device_tracker.py | 7 +------ homeassistant/components/decora/light.py | 7 +------ homeassistant/components/decora_wifi/light.py | 10 +--------- homeassistant/components/deluge/sensor.py | 7 +------ homeassistant/components/deluge/switch.py | 7 +------ homeassistant/components/demo/air_quality.py | 7 +------ homeassistant/components/demo/alarm_control_panel.py | 7 +------ homeassistant/components/demo/binary_sensor.py | 7 +------ homeassistant/components/demo/calendar.py | 7 +------ homeassistant/components/demo/camera.py | 7 +------ homeassistant/components/demo/climate.py | 7 +------ homeassistant/components/demo/cover.py | 7 +------ homeassistant/components/demo/device_tracker.py | 7 +------ homeassistant/components/demo/fan.py | 7 +------ homeassistant/components/demo/image_processing.py | 7 +------ homeassistant/components/demo/light.py | 7 +------ homeassistant/components/demo/lock.py | 7 +------ homeassistant/components/demo/media_player.py | 7 +------ homeassistant/components/demo/notify.py | 7 +------ homeassistant/components/demo/remote.py | 7 +------ homeassistant/components/demo/sensor.py | 7 +------ homeassistant/components/demo/switch.py | 7 +------ homeassistant/components/demo/tts.py | 7 +------ homeassistant/components/demo/vacuum.py | 7 +------ homeassistant/components/denon/media_player.py | 7 +------ homeassistant/components/denonavr/media_player.py | 7 +------ homeassistant/components/device_tracker/__init__.py | 7 +------ homeassistant/components/dht/sensor.py | 7 +------ homeassistant/components/digitalloggers/switch.py | 7 +------ homeassistant/components/directv/media_player.py | 7 +------ homeassistant/components/discogs/sensor.py | 7 +------ homeassistant/components/discord/notify.py | 7 +------ .../components/dlib_face_detect/image_processing.py | 7 +------ .../components/dlib_face_identify/image_processing.py | 7 +------ homeassistant/components/dlink/switch.py | 7 +------ homeassistant/components/dlna_dmr/media_player.py | 7 +------ homeassistant/components/dnsip/sensor.py | 7 +------ homeassistant/components/dsmr/sensor.py | 7 +------ homeassistant/components/dte_energy_bridge/sensor.py | 7 +------ homeassistant/components/duke_energy/sensor.py | 7 +------ homeassistant/components/dunehd/media_player.py | 7 +------ homeassistant/components/dyson/climate.py | 7 +------ homeassistant/components/dyson/sensor.py | 7 +------ homeassistant/components/dyson/vacuum.py | 7 +------ homeassistant/components/edimax/switch.py | 7 +------ .../components/ee_brightbox/device_tracker.py | 7 +------ homeassistant/components/efergy/sensor.py | 7 +------ homeassistant/components/eliqonline/sensor.py | 7 +------ homeassistant/components/emby/media_player.py | 7 +------ homeassistant/components/emoncms/sensor.py | 7 +------ homeassistant/components/enphase_envoy/sensor.py | 7 +------ homeassistant/components/envirophat/sensor.py | 7 +------ homeassistant/components/ephember/climate.py | 7 +------ homeassistant/components/epson/media_player.py | 7 +------ homeassistant/components/eq3btsmart/climate.py | 7 +------ homeassistant/components/everlights/light.py | 7 +------ homeassistant/components/facebook/notify.py | 7 +------ homeassistant/components/facebox/image_processing.py | 7 +------ homeassistant/components/familyhub/camera.py | 7 +------ homeassistant/components/fan/__init__.py | 7 +------ homeassistant/components/fedex/sensor.py | 7 +------ homeassistant/components/ffmpeg/camera.py | 7 +------ .../components/ffmpeg_motion/binary_sensor.py | 7 +------ homeassistant/components/ffmpeg_noise/binary_sensor.py | 7 +------ homeassistant/components/file/notify.py | 7 +------ homeassistant/components/file/sensor.py | 7 +------ homeassistant/components/filesize/sensor.py | 7 +------ homeassistant/components/filter/sensor.py | 7 +------ homeassistant/components/fints/sensor.py | 7 +------ homeassistant/components/fitbit/sensor.py | 7 +------ homeassistant/components/fixer/sensor.py | 7 +------ homeassistant/components/flic/binary_sensor.py | 7 +------ homeassistant/components/flock/notify.py | 7 +------ homeassistant/components/flunearyou/sensor.py | 7 +------ homeassistant/components/flux_led/light.py | 7 +------ homeassistant/components/folder/sensor.py | 7 +------ homeassistant/components/foobot/sensor.py | 7 +------ homeassistant/components/foscam/camera.py | 7 +------ homeassistant/components/free_mobile/notify.py | 7 +------ homeassistant/components/freedns/__init__.py | 7 +------ homeassistant/components/fritz/device_tracker.py | 7 +------ .../components/fritzbox_callmonitor/sensor.py | 7 +------ homeassistant/components/fritzbox_netmonitor/sensor.py | 7 +------ homeassistant/components/fritzdect/switch.py | 7 +------ .../components/frontier_silicon/media_player.py | 7 +------ homeassistant/components/futurenow/light.py | 7 +------ homeassistant/components/garadget/cover.py | 7 +------ homeassistant/components/gc100/binary_sensor.py | 7 +------ homeassistant/components/gc100/switch.py | 7 +------ homeassistant/components/gearbest/sensor.py | 7 +------ homeassistant/components/geizhals/sensor.py | 7 +------ homeassistant/components/generic/camera.py | 7 +------ homeassistant/components/generic_thermostat/climate.py | 7 +------ homeassistant/components/geofency/device_tracker.py | 7 +------ homeassistant/components/github/sensor.py | 7 +------ homeassistant/components/gitlab_ci/sensor.py | 7 +------ homeassistant/components/gitter/sensor.py | 7 +------ homeassistant/components/glances/sensor.py | 7 +------ homeassistant/components/gntp/notify.py | 7 +------ homeassistant/components/gogogate2/cover.py | 7 +------ homeassistant/components/google_assistant/http.py | 7 +------ homeassistant/components/google_maps/device_tracker.py | 7 +------ homeassistant/components/google_travel_time/sensor.py | 7 +------ homeassistant/components/google_wifi/sensor.py | 7 +------ homeassistant/components/gpmdp/media_player.py | 7 +------ homeassistant/components/gpsd/sensor.py | 7 +------ homeassistant/components/greeneye_monitor/sensor.py | 7 +------ homeassistant/components/greenwave/light.py | 7 +------ homeassistant/components/group/cover.py | 7 +------ homeassistant/components/group/light.py | 7 +------ homeassistant/components/group/notify.py | 7 +------ homeassistant/components/gstreamer/media_player.py | 7 +------ homeassistant/components/gtfs/sensor.py | 7 +------ homeassistant/components/gtt/sensor.py | 7 +------ .../components/harman_kardon_avr/media_player.py | 7 +------ homeassistant/components/haveibeenpwned/sensor.py | 7 +------ homeassistant/components/hddtemp/sensor.py | 7 +------ homeassistant/components/heatmiser/climate.py | 7 +------ homeassistant/components/hikvision/binary_sensor.py | 7 +------ homeassistant/components/hikvisioncam/switch.py | 7 +------ homeassistant/components/hipchat/notify.py | 7 +------ homeassistant/components/history_stats/sensor.py | 7 +------ homeassistant/components/hitron_coda/device_tracker.py | 7 +------ homeassistant/components/homematic/notify.py | 7 +------ homeassistant/components/honeywell/climate.py | 7 +------ homeassistant/components/hook/switch.py | 7 +------ homeassistant/components/horizon/media_player.py | 7 +------ homeassistant/components/html5/notify.py | 7 +------ homeassistant/components/htu21d/sensor.py | 7 +------ .../components/huawei_router/device_tracker.py | 7 +------ homeassistant/components/ialarm/alarm_control_panel.py | 7 +------ homeassistant/components/icloud/device_tracker.py | 7 +------ homeassistant/components/iglo/light.py | 7 +------ homeassistant/components/image_processing/__init__.py | 7 +------ homeassistant/components/imap/sensor.py | 7 +------ homeassistant/components/imap_email_content/sensor.py | 7 +------ homeassistant/components/influxdb/sensor.py | 7 +------ homeassistant/components/integration/sensor.py | 7 +------ .../components/islamic_prayer_times/sensor.py | 7 +------ homeassistant/components/iss/binary_sensor.py | 7 +------ homeassistant/components/itunes/media_player.py | 7 +------ homeassistant/components/jewish_calendar/sensor.py | 7 +------ homeassistant/components/kankun/switch.py | 7 +------ .../components/keenetic_ndms2/device_tracker.py | 7 +------ homeassistant/components/kiwi/lock.py | 7 +------ homeassistant/components/kodi/media_player.py | 7 +------ homeassistant/components/kodi/notify.py | 7 +------ homeassistant/components/kwb/sensor.py | 7 +------ homeassistant/components/lacrosse/sensor.py | 7 +------ homeassistant/components/lannouncer/notify.py | 7 +------ homeassistant/components/launch_library/sensor.py | 7 +------ homeassistant/components/lg_netcast/media_player.py | 7 +------ homeassistant/components/lg_soundbar/media_player.py | 7 +------ homeassistant/components/light/__init__.py | 7 +------ homeassistant/components/limitlessled/light.py | 7 +------ homeassistant/components/linksys_ap/device_tracker.py | 7 +------ homeassistant/components/linky/sensor.py | 7 +------ homeassistant/components/linux_battery/sensor.py | 7 +------ homeassistant/components/litejet/light.py | 7 +------ homeassistant/components/litejet/switch.py | 7 +------ homeassistant/components/liveboxplaytv/media_player.py | 7 +------ homeassistant/components/llamalab_automate/notify.py | 7 +------ homeassistant/components/local_file/camera.py | 7 +------ homeassistant/components/locative/device_tracker.py | 7 +------ homeassistant/components/lock/__init__.py | 7 +------ homeassistant/components/lockitron/lock.py | 7 +------ homeassistant/components/london_air/sensor.py | 7 +------ homeassistant/components/london_underground/sensor.py | 7 +------ homeassistant/components/loopenergy/sensor.py | 7 +------ homeassistant/components/luci/device_tracker.py | 7 +------ homeassistant/components/lw12wifi/light.py | 7 +------ homeassistant/components/lyft/sensor.py | 7 +------ homeassistant/components/magicseaweed/sensor.py | 7 +------ homeassistant/components/manual/alarm_control_panel.py | 7 +------ .../components/manual_mqtt/alarm_control_panel.py | 7 +------ homeassistant/components/marytts/tts.py | 7 +------ homeassistant/components/mastodon/notify.py | 7 +------ homeassistant/components/media_player/__init__.py | 7 +------ homeassistant/components/mediaroom/media_player.py | 7 +------ homeassistant/components/melissa/climate.py | 7 +------ homeassistant/components/message_bird/notify.py | 7 +------ homeassistant/components/metoffice/sensor.py | 7 +------ homeassistant/components/mfi/sensor.py | 7 +------ homeassistant/components/mfi/switch.py | 7 +------ homeassistant/components/mhz19/sensor.py | 7 +------ homeassistant/components/microsoft/tts.py | 7 +------ .../microsoft_face_detect/image_processing.py | 7 +------ .../microsoft_face_identify/image_processing.py | 7 +------ homeassistant/components/miflora/sensor.py | 7 +------ homeassistant/components/mikrotik/device_tracker.py | 7 +------ homeassistant/components/mill/climate.py | 7 +------ homeassistant/components/min_max/sensor.py | 7 +------ homeassistant/components/mitemp_bt/sensor.py | 7 +------ homeassistant/components/mjpeg/camera.py | 7 +------ homeassistant/components/modem_callerid/sensor.py | 7 +------ homeassistant/components/mold_indicator/sensor.py | 7 +------ homeassistant/components/monoprice/media_player.py | 7 +------ homeassistant/components/moon/sensor.py | 7 +------ homeassistant/components/mpchc/media_player.py | 7 +------ homeassistant/components/mpd/media_player.py | 7 +------ homeassistant/components/mqtt/__init__.py | 7 +------ homeassistant/components/mqtt/alarm_control_panel.py | 7 +------ homeassistant/components/mqtt/binary_sensor.py | 7 +------ homeassistant/components/mqtt/camera.py | 7 +------ homeassistant/components/mqtt/climate.py | 7 +------ homeassistant/components/mqtt/cover.py | 7 +------ homeassistant/components/mqtt/device_tracker.py | 7 +------ homeassistant/components/mqtt/discovery.py | 7 +------ homeassistant/components/mqtt/fan.py | 7 +------ homeassistant/components/mqtt/lock.py | 7 +------ homeassistant/components/mqtt/sensor.py | 7 +------ homeassistant/components/mqtt/server.py | 7 +------ homeassistant/components/mqtt/subscription.py | 7 +------ homeassistant/components/mqtt/switch.py | 7 +------ homeassistant/components/mqtt/vacuum.py | 7 +------ homeassistant/components/mqtt_json/device_tracker.py | 7 +------ homeassistant/components/mqtt_room/sensor.py | 7 +------ homeassistant/components/mvglive/sensor.py | 7 +------ homeassistant/components/mycroft/notify.py | 7 +------ homeassistant/components/myq/cover.py | 7 +------ homeassistant/components/mystrom/binary_sensor.py | 7 +------ homeassistant/components/nad/media_player.py | 7 +------ homeassistant/components/nanoleaf/light.py | 7 +------ .../components/nederlandse_spoorwegen/sensor.py | 7 +------ homeassistant/components/nello/lock.py | 7 +------ .../components/ness_alarm/alarm_control_panel.py | 7 +------ homeassistant/components/ness_alarm/binary_sensor.py | 7 +------ homeassistant/components/netatmo_public/sensor.py | 7 +------ homeassistant/components/netdata/sensor.py | 7 +------ homeassistant/components/netgear/device_tracker.py | 7 +------ homeassistant/components/netio/switch.py | 7 +------ homeassistant/components/neurio_energy/sensor.py | 7 +------ homeassistant/components/nfandroidtv/notify.py | 7 +------ homeassistant/components/niko_home_control/light.py | 7 +------ homeassistant/components/nilu/air_quality.py | 7 +------ homeassistant/components/nmbs/sensor.py | 7 +------ homeassistant/components/noaa_tides/sensor.py | 7 +------ homeassistant/components/norway_air/air_quality.py | 7 +------ homeassistant/components/notify/__init__.py | 7 +------ homeassistant/components/nsw_fuel_station/sensor.py | 7 +------ homeassistant/components/nuheat/climate.py | 7 +------ homeassistant/components/nuki/lock.py | 7 +------ homeassistant/components/nut/sensor.py | 7 +------ homeassistant/components/nx584/alarm_control_panel.py | 7 +------ homeassistant/components/nx584/binary_sensor.py | 7 +------ homeassistant/components/nzbget/sensor.py | 7 +------ homeassistant/components/ohmconnect/sensor.py | 7 +------ homeassistant/components/onewire/sensor.py | 7 +------ homeassistant/components/onkyo/media_player.py | 7 +------ homeassistant/components/onvif/camera.py | 7 +------ .../components/openalpr_cloud/image_processing.py | 7 +------ .../components/openalpr_local/image_processing.py | 7 +------ homeassistant/components/openevse/sensor.py | 7 +------ homeassistant/components/openexchangerates/sensor.py | 7 +------ homeassistant/components/opengarage/cover.py | 7 +------ homeassistant/components/openhardwaremonitor/sensor.py | 7 +------ homeassistant/components/openhome/media_player.py | 7 +------ homeassistant/components/opensky/sensor.py | 7 +------ homeassistant/components/openweathermap/sensor.py | 7 +------ homeassistant/components/opple/light.py | 7 +------ homeassistant/components/orvibo/switch.py | 7 +------ homeassistant/components/osramlightify/light.py | 7 +------ homeassistant/components/otp/sensor.py | 7 +------ homeassistant/components/owntracks/device_tracker.py | 7 +------ .../components/panasonic_bluray/media_player.py | 7 +------ .../components/panasonic_viera/media_player.py | 7 +------ homeassistant/components/pandora/media_player.py | 7 +------ homeassistant/components/philips_js/media_player.py | 7 +------ homeassistant/components/pi_hole/sensor.py | 7 +------ homeassistant/components/picotts/tts.py | 7 +------ homeassistant/components/piglow/light.py | 7 +------ homeassistant/components/pilight/__init__.py | 7 +------ homeassistant/components/pilight/binary_sensor.py | 7 +------ homeassistant/components/pilight/sensor.py | 7 +------ homeassistant/components/pilight/switch.py | 7 +------ homeassistant/components/ping/binary_sensor.py | 7 +------ homeassistant/components/ping/device_tracker.py | 7 +------ homeassistant/components/pioneer/media_player.py | 7 +------ homeassistant/components/pjlink/media_player.py | 7 +------ homeassistant/components/plex/media_player.py | 7 +------ homeassistant/components/plex/sensor.py | 7 +------ homeassistant/components/pocketcasts/sensor.py | 7 +------ homeassistant/components/postnl/sensor.py | 7 +------ homeassistant/components/prezzibenzina/sensor.py | 7 +------ homeassistant/components/proliphix/climate.py | 7 +------ homeassistant/components/prowl/notify.py | 7 +------ homeassistant/components/proxy/camera.py | 7 +------ homeassistant/components/ps4/__init__.py | 7 +------ homeassistant/components/ps4/media_player.py | 7 +------ homeassistant/components/pulseaudio_loopback/switch.py | 7 +------ homeassistant/components/push/camera.py | 7 +------ homeassistant/components/pushbullet/notify.py | 7 +------ homeassistant/components/pushbullet/sensor.py | 7 +------ homeassistant/components/pushetta/notify.py | 7 +------ homeassistant/components/pushover/notify.py | 7 +------ homeassistant/components/pushsafer/notify.py | 7 +------ homeassistant/components/pvoutput/sensor.py | 7 +------ homeassistant/components/pyload/sensor.py | 7 +------ homeassistant/components/python_script/__init__.py | 7 +------ homeassistant/components/qbittorrent/sensor.py | 7 +------ homeassistant/components/qnap/sensor.py | 7 +------ homeassistant/components/qrcode/image_processing.py | 7 +------ .../components/quantum_gateway/device_tracker.py | 7 +------ homeassistant/components/qwikswitch/__init__.py | 7 +------ homeassistant/components/qwikswitch/binary_sensor.py | 7 +------ homeassistant/components/qwikswitch/light.py | 7 +------ homeassistant/components/qwikswitch/sensor.py | 7 +------ homeassistant/components/qwikswitch/switch.py | 7 +------ homeassistant/components/rachio/__init__.py | 7 +------ homeassistant/components/rachio/binary_sensor.py | 7 +------ homeassistant/components/rachio/switch.py | 7 +------ homeassistant/components/radarr/sensor.py | 7 +------ homeassistant/components/radiotherm/climate.py | 7 +------ homeassistant/components/rainbird/__init__.py | 7 +------ homeassistant/components/rainbird/sensor.py | 7 +------ homeassistant/components/rainbird/switch.py | 7 +------ homeassistant/components/raincloud/__init__.py | 7 +------ homeassistant/components/raincloud/binary_sensor.py | 7 +------ homeassistant/components/raincloud/sensor.py | 7 +------ homeassistant/components/rainmachine/binary_sensor.py | 7 +------ homeassistant/components/rainmachine/sensor.py | 7 +------ homeassistant/components/rainmachine/switch.py | 7 +------ homeassistant/components/random/binary_sensor.py | 7 +------ homeassistant/components/random/sensor.py | 7 +------ homeassistant/components/raspyrfm/switch.py | 7 +------ homeassistant/components/recollect_waste/sensor.py | 7 +------ homeassistant/components/recswitch/switch.py | 7 +------ homeassistant/components/rest/binary_sensor.py | 7 +------ homeassistant/components/rest/notify.py | 7 +------ homeassistant/components/rest/sensor.py | 7 +------ homeassistant/components/rest/switch.py | 7 +------ homeassistant/components/rflink/binary_sensor.py | 7 +------ homeassistant/components/rflink/cover.py | 7 +------ homeassistant/components/rflink/light.py | 7 +------ homeassistant/components/rflink/sensor.py | 7 +------ homeassistant/components/rflink/switch.py | 7 +------ homeassistant/components/ring/binary_sensor.py | 7 +------ homeassistant/components/ring/camera.py | 7 +------ homeassistant/components/ring/sensor.py | 7 +------ homeassistant/components/ritassist/device_tracker.py | 7 +------ homeassistant/components/rmvtransport/sensor.py | 7 +------ homeassistant/components/rocketchat/notify.py | 7 +------ homeassistant/components/roomba/vacuum.py | 7 +------ homeassistant/components/rova/sensor.py | 7 +------ homeassistant/components/rpi_camera/camera.py | 7 +------ homeassistant/components/rpi_rf/switch.py | 7 +------ homeassistant/components/russound_rio/media_player.py | 7 +------ homeassistant/components/russound_rnet/media_player.py | 7 +------ homeassistant/components/ruter/sensor.py | 7 +------ homeassistant/components/samsungtv/media_player.py | 7 +------ homeassistant/components/scrape/sensor.py | 7 +------ homeassistant/components/scsgate/__init__.py | 7 +------ homeassistant/components/season/sensor.py | 7 +------ homeassistant/components/sendgrid/notify.py | 7 +------ homeassistant/components/sensehat/light.py | 7 +------ homeassistant/components/sensehat/sensor.py | 7 +------ homeassistant/components/sensibo/climate.py | 7 +------ homeassistant/components/sensor/__init__.py | 7 +------ homeassistant/components/serial/sensor.py | 7 +------ homeassistant/components/serial_pm/sensor.py | 7 +------ homeassistant/components/sesame/lock.py | 7 +------ .../components/seven_segments/image_processing.py | 7 +------ homeassistant/components/seventeentrack/sensor.py | 7 +------ homeassistant/components/sht31/sensor.py | 7 +------ homeassistant/components/sigfox/sensor.py | 7 +------ homeassistant/components/simplepush/notify.py | 7 +------ homeassistant/components/simulated/sensor.py | 7 +------ homeassistant/components/sky_hub/device_tracker.py | 7 +------ homeassistant/components/skybeacon/sensor.py | 7 +------ homeassistant/components/slack/notify.py | 7 +------ homeassistant/components/sleepiq/binary_sensor.py | 7 +------ homeassistant/components/sleepiq/sensor.py | 7 +------ homeassistant/components/sma/sensor.py | 7 +------ homeassistant/components/smartthings/smartapp.py | 8 +------- homeassistant/components/smtp/notify.py | 7 +------ homeassistant/components/snapcast/media_player.py | 7 +------ homeassistant/components/snmp/device_tracker.py | 7 +------ homeassistant/components/snmp/sensor.py | 7 +------ homeassistant/components/snmp/switch.py | 7 +------ homeassistant/components/socialblade/sensor.py | 7 +------ homeassistant/components/solaredge/sensor.py | 7 +------ homeassistant/components/sonarr/sensor.py | 7 +------ homeassistant/components/songpal/media_player.py | 7 +------ homeassistant/components/soundtouch/media_player.py | 7 +------ homeassistant/components/spc/alarm_control_panel.py | 7 +------ homeassistant/components/spc/binary_sensor.py | 7 +------ homeassistant/components/spotcrime/sensor.py | 7 +------ homeassistant/components/spotify/media_player.py | 7 +------ homeassistant/components/squeezebox/media_player.py | 7 +------ homeassistant/components/srp_energy/sensor.py | 7 +------ homeassistant/components/starlingbank/sensor.py | 7 +------ homeassistant/components/startca/sensor.py | 7 +------ homeassistant/components/statistics/sensor.py | 7 +------ homeassistant/components/steam_online/sensor.py | 7 +------ homeassistant/components/stream/__init__.py | 7 +------ homeassistant/components/stream/hls.py | 7 +------ homeassistant/components/stride/notify.py | 7 +------ homeassistant/components/supervisord/sensor.py | 7 +------ .../components/swiss_hydrological_data/sensor.py | 7 +------ .../components/swiss_public_transport/sensor.py | 7 +------ homeassistant/components/swisscom/device_tracker.py | 7 +------ homeassistant/components/switch/__init__.py | 7 +------ homeassistant/components/switch/light.py | 7 +------ homeassistant/components/switchmate/switch.py | 7 +------ homeassistant/components/syncthru/sensor.py | 7 +------ homeassistant/components/synology/camera.py | 7 +------ homeassistant/components/synology_chat/notify.py | 7 +------ homeassistant/components/syslog/notify.py | 7 +------ homeassistant/components/sytadin/sensor.py | 7 +------ homeassistant/components/tank_utility/sensor.py | 7 +------ homeassistant/components/tapsaff/binary_sensor.py | 7 +------ homeassistant/components/tautulli/sensor.py | 7 +------ homeassistant/components/tcp/binary_sensor.py | 7 +------ homeassistant/components/tcp/sensor.py | 7 +------ homeassistant/components/ted5000/sensor.py | 7 +------ homeassistant/components/teksavvy/sensor.py | 7 +------ homeassistant/components/telegram/notify.py | 7 +------ homeassistant/components/telnet/switch.py | 7 +------ homeassistant/components/temper/sensor.py | 7 +------ homeassistant/components/template/binary_sensor.py | 7 +------ homeassistant/components/template/cover.py | 7 +------ homeassistant/components/template/fan.py | 7 +------ homeassistant/components/template/light.py | 7 +------ homeassistant/components/template/lock.py | 7 +------ homeassistant/components/template/sensor.py | 7 +------ homeassistant/components/template/switch.py | 7 +------ homeassistant/components/thomson/device_tracker.py | 7 +------ homeassistant/components/threshold/binary_sensor.py | 7 +------ homeassistant/components/tikteck/light.py | 7 +------ homeassistant/components/tile/device_tracker.py | 7 +------ homeassistant/components/time_date/sensor.py | 7 +------ homeassistant/components/todoist/calendar.py | 7 +------ homeassistant/components/tomato/device_tracker.py | 7 +------ homeassistant/components/torque/sensor.py | 7 +------ .../components/totalconnect/alarm_control_panel.py | 7 +------ homeassistant/components/touchline/climate.py | 7 +------ homeassistant/components/tplink/device_tracker.py | 7 +------ homeassistant/components/tplink/light.py | 7 +------ homeassistant/components/tplink/switch.py | 7 +------ homeassistant/components/traccar/device_tracker.py | 7 +------ homeassistant/components/trackr/device_tracker.py | 7 +------ .../components/trafikverket_weatherstation/sensor.py | 7 +------ homeassistant/components/travisci/sensor.py | 7 +------ homeassistant/components/tts/__init__.py | 7 +------ homeassistant/components/twilio_call/notify.py | 7 +------ homeassistant/components/twilio_sms/notify.py | 7 +------ homeassistant/components/twitch/sensor.py | 7 +------ homeassistant/components/twitter/notify.py | 7 +------ homeassistant/components/ubee/device_tracker.py | 7 +------ homeassistant/components/uber/sensor.py | 7 +------ homeassistant/components/ubus/device_tracker.py | 7 +------ .../components/ue_smart_radio/media_player.py | 7 +------ homeassistant/components/unifi/device_tracker.py | 7 +------ .../components/unifi_direct/device_tracker.py | 7 +------ homeassistant/components/universal/media_player.py | 7 +------ homeassistant/components/upc_connect/device_tracker.py | 7 +------ homeassistant/components/upnp/sensor.py | 7 +------ homeassistant/components/ups/sensor.py | 7 +------ homeassistant/components/uptime/sensor.py | 7 +------ homeassistant/components/uptimerobot/binary_sensor.py | 7 +------ homeassistant/components/uscis/sensor.py | 7 +------ homeassistant/components/uvc/camera.py | 7 +------ homeassistant/components/vacuum/__init__.py | 7 +------ homeassistant/components/vasttrafik/sensor.py | 7 +------ homeassistant/components/venstar/climate.py | 7 +------ homeassistant/components/version/sensor.py | 7 +------ homeassistant/components/vesync/switch.py | 7 +------ homeassistant/components/viaggiatreno/sensor.py | 7 +------ homeassistant/components/vizio/media_player.py | 7 +------ homeassistant/components/vlc/media_player.py | 7 +------ homeassistant/components/voicerss/tts.py | 7 +------ homeassistant/components/volkszaehler/sensor.py | 7 +------ homeassistant/components/vultr/binary_sensor.py | 7 +------ homeassistant/components/vultr/sensor.py | 7 +------ homeassistant/components/vultr/switch.py | 7 +------ homeassistant/components/wake_on_lan/switch.py | 7 +------ homeassistant/components/waqi/sensor.py | 7 +------ homeassistant/components/waterfurnace/sensor.py | 7 +------ homeassistant/components/waze_travel_time/sensor.py | 7 +------ homeassistant/components/whois/sensor.py | 7 +------ homeassistant/components/worldclock/sensor.py | 7 +------ homeassistant/components/worldtidesinfo/sensor.py | 7 +------ homeassistant/components/worxlandroid/sensor.py | 7 +------ homeassistant/components/wsdot/sensor.py | 7 +------ homeassistant/components/wunderground/sensor.py | 7 +------ homeassistant/components/x10/light.py | 7 +------ homeassistant/components/xbox_live/sensor.py | 7 +------ homeassistant/components/xeoma/camera.py | 7 +------ homeassistant/components/xiaomi/camera.py | 7 +------ homeassistant/components/xiaomi/device_tracker.py | 7 +------ homeassistant/components/xiaomi_tv/media_player.py | 7 +------ homeassistant/components/xmpp/notify.py | 7 +------ .../components/yale_smart_alarm/alarm_control_panel.py | 7 +------ homeassistant/components/yamaha/media_player.py | 7 +------ .../components/yamaha_musiccast/media_player.py | 7 +------ homeassistant/components/yandextts/tts.py | 7 +------ homeassistant/components/yeelightsunflower/light.py | 7 +------ homeassistant/components/yessssms/notify.py | 7 +------ homeassistant/components/yi/camera.py | 7 +------ homeassistant/components/yr/sensor.py | 7 +------ homeassistant/components/yweather/sensor.py | 7 +------ homeassistant/components/zamg/sensor.py | 7 +------ homeassistant/components/zengge/light.py | 7 +------ homeassistant/components/zestimate/sensor.py | 7 +------ homeassistant/components/zha/__init__.py | 7 +------ homeassistant/components/zha/api.py | 7 +------ homeassistant/components/zha/binary_sensor.py | 7 +------ homeassistant/components/zha/const.py | 7 +------ homeassistant/components/zha/device_entity.py | 7 +------ homeassistant/components/zha/entity.py | 7 +------ homeassistant/components/zha/fan.py | 7 +------ homeassistant/components/zha/light.py | 7 +------ homeassistant/components/zha/sensor.py | 7 +------ homeassistant/components/zha/switch.py | 7 +------ homeassistant/components/zhong_hong/climate.py | 7 +------ .../components/ziggo_mediabox_xl/media_player.py | 7 +------ 604 files changed, 604 insertions(+), 3632 deletions(-) diff --git a/homeassistant/components/acer_projector/switch.py b/homeassistant/components/acer_projector/switch.py index 7abb3d1edbc..df6fb8816aa 100644 --- a/homeassistant/components/acer_projector/switch.py +++ b/homeassistant/components/acer_projector/switch.py @@ -1,9 +1,4 @@ -""" -Use serial protocol of Acer projector to obtain state of the projector. - -For more details about this component, please refer to the documentation -at https://home-assistant.io/components/switch.acer_projector/ -""" +"""Use serial protocol of Acer projector to obtain state of the projector.""" import logging import re diff --git a/homeassistant/components/actiontec/device_tracker.py b/homeassistant/components/actiontec/device_tracker.py index 72d9992c60f..3f0c8786794 100644 --- a/homeassistant/components/actiontec/device_tracker.py +++ b/homeassistant/components/actiontec/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Actiontec MI424WR (Verizon FIOS) routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.actiontec/ -""" +"""Support for Actiontec MI424WR (Verizon FIOS) routers.""" import logging import re import telnetlib diff --git a/homeassistant/components/aftership/sensor.py b/homeassistant/components/aftership/sensor.py index eb5188a95cb..18bc3cb3430 100644 --- a/homeassistant/components/aftership/sensor.py +++ b/homeassistant/components/aftership/sensor.py @@ -1,9 +1,4 @@ -""" -Support for non-delivered packages recorded in AfterShip. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/sensor.aftership/ -""" +"""Support for non-delivered packages recorded in AfterShip.""" from datetime import timedelta import logging diff --git a/homeassistant/components/air_quality/__init__.py b/homeassistant/components/air_quality/__init__.py index 66af51efcb1..87d5c3b6bd4 100644 --- a/homeassistant/components/air_quality/__init__.py +++ b/homeassistant/components/air_quality/__init__.py @@ -1,9 +1,4 @@ -""" -Component for handling Air Quality data for your location. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/air_quality/ -""" +"""Component for handling Air Quality data for your location.""" from datetime import timedelta import logging diff --git a/homeassistant/components/airvisual/sensor.py b/homeassistant/components/airvisual/sensor.py index b9e7a3315e3..7fad7bb35be 100644 --- a/homeassistant/components/airvisual/sensor.py +++ b/homeassistant/components/airvisual/sensor.py @@ -1,9 +1,4 @@ -""" -Support for AirVisual air quality sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.airvisual/ -""" +"""Support for AirVisual air quality sensors.""" from logging import getLogger from datetime import timedelta diff --git a/homeassistant/components/aladdin_connect/cover.py b/homeassistant/components/aladdin_connect/cover.py index 4627ba77781..01146fecbb6 100644 --- a/homeassistant/components/aladdin_connect/cover.py +++ b/homeassistant/components/aladdin_connect/cover.py @@ -1,9 +1,4 @@ -""" -Platform for the Aladdin Connect cover component. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/cover.aladdin_connect/ -""" +"""Platform for the Aladdin Connect cover component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 86bb3e73bda..36a68eda174 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -1,9 +1,4 @@ -""" -Component to interface with an alarm control panel. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel/ -""" +"""Component to interface with an alarm control panel.""" from datetime import timedelta import logging diff --git a/homeassistant/components/alarmdotcom/alarm_control_panel.py b/homeassistant/components/alarmdotcom/alarm_control_panel.py index 4f2913771b1..ea581aca747 100644 --- a/homeassistant/components/alarmdotcom/alarm_control_panel.py +++ b/homeassistant/components/alarmdotcom/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Interfaces with Alarm.com alarm control panels. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.alarmdotcom/ -""" +"""Interfaces with Alarm.com alarm control panels.""" import logging import re diff --git a/homeassistant/components/alpha_vantage/sensor.py b/homeassistant/components/alpha_vantage/sensor.py index 774a3fe95f6..0eb57e5b27a 100644 --- a/homeassistant/components/alpha_vantage/sensor.py +++ b/homeassistant/components/alpha_vantage/sensor.py @@ -1,9 +1,4 @@ -""" -Stock market information from Alpha Vantage. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.alpha_vantage/ -""" +"""Stock market information from Alpha Vantage.""" from datetime import timedelta import logging diff --git a/homeassistant/components/amazon_polly/tts.py b/homeassistant/components/amazon_polly/tts.py index 167cd9cfc78..d29ae32fb57 100644 --- a/homeassistant/components/amazon_polly/tts.py +++ b/homeassistant/components/amazon_polly/tts.py @@ -1,9 +1,4 @@ -""" -Support for the Amazon Polly text to speech service. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/tts.amazon_polly/ -""" +"""Support for the Amazon Polly text to speech service.""" import logging import voluptuous as vol diff --git a/homeassistant/components/androidtv/__init__.py b/homeassistant/components/androidtv/__init__.py index fd108e05973..14832aef315 100644 --- a/homeassistant/components/androidtv/__init__.py +++ b/homeassistant/components/androidtv/__init__.py @@ -1,6 +1 @@ -""" -Support for functionality to interact with Android TV and Fire TV devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.androidtv/ -""" +"""Support for functionality to interact with Android TV/Fire TV devices.""" diff --git a/homeassistant/components/androidtv/media_player.py b/homeassistant/components/androidtv/media_player.py index 0129b547acf..a62a7f2a6d9 100644 --- a/homeassistant/components/androidtv/media_player.py +++ b/homeassistant/components/androidtv/media_player.py @@ -1,9 +1,4 @@ -""" -Support for functionality to interact with Android TV and Fire TV devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.androidtv/ -""" +"""Support for functionality to interact with Android TV / Fire TV devices.""" import functools import logging import voluptuous as vol diff --git a/homeassistant/components/anel_pwrctrl/switch.py b/homeassistant/components/anel_pwrctrl/switch.py index fadb3cd96ff..b9b3070b97e 100644 --- a/homeassistant/components/anel_pwrctrl/switch.py +++ b/homeassistant/components/anel_pwrctrl/switch.py @@ -1,9 +1,4 @@ -""" -Support for ANEL PwrCtrl switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.pwrctrl/ -""" +"""Support for ANEL PwrCtrl switches.""" import logging import socket from datetime import timedelta diff --git a/homeassistant/components/anthemav/media_player.py b/homeassistant/components/anthemav/media_player.py index 36bc5ae10e1..c7ee579bc17 100644 --- a/homeassistant/components/anthemav/media_player.py +++ b/homeassistant/components/anthemav/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Anthem Network Receivers and Processors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.anthemav/ -""" +"""Support for Anthem Network Receivers and Processors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/apns/notify.py b/homeassistant/components/apns/notify.py index b2c6b63864f..d7f6559fe7e 100644 --- a/homeassistant/components/apns/notify.py +++ b/homeassistant/components/apns/notify.py @@ -1,9 +1,4 @@ -""" -APNS Notification platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.apns/ -""" +"""APNS Notification platform.""" import logging import os diff --git a/homeassistant/components/aquostv/media_player.py b/homeassistant/components/aquostv/media_player.py index 59723b47522..0ffe48d21ec 100644 --- a/homeassistant/components/aquostv/media_player.py +++ b/homeassistant/components/aquostv/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interface with an Aquos TV. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.aquostv/ -""" +"""Support for interface with an Aquos TV.""" import logging import voluptuous as vol diff --git a/homeassistant/components/arest/binary_sensor.py b/homeassistant/components/arest/binary_sensor.py index b70620df3e2..3fd669a2bba 100644 --- a/homeassistant/components/arest/binary_sensor.py +++ b/homeassistant/components/arest/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for an exposed aREST RESTful API of a device. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.arest/ -""" +"""Support for an exposed aREST RESTful API of a device.""" import logging from datetime import timedelta diff --git a/homeassistant/components/arest/sensor.py b/homeassistant/components/arest/sensor.py index e0c5ef129ce..fc443cd60b6 100644 --- a/homeassistant/components/arest/sensor.py +++ b/homeassistant/components/arest/sensor.py @@ -1,9 +1,4 @@ -""" -Support for an exposed aREST RESTful API of a device. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.arest/ -""" +"""Support for an exposed aREST RESTful API of a device.""" import logging from datetime import timedelta diff --git a/homeassistant/components/arest/switch.py b/homeassistant/components/arest/switch.py index ab445db10d8..717acc2f336 100644 --- a/homeassistant/components/arest/switch.py +++ b/homeassistant/components/arest/switch.py @@ -1,9 +1,4 @@ -""" -Support for an exposed aREST RESTful API of a device. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.arest/ -""" +"""Support for an exposed aREST RESTful API of a device.""" import logging diff --git a/homeassistant/components/aruba/device_tracker.py b/homeassistant/components/aruba/device_tracker.py index 142842b12d2..ed1fee25a6c 100644 --- a/homeassistant/components/aruba/device_tracker.py +++ b/homeassistant/components/aruba/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Aruba Access Points. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.aruba/ -""" +"""Support for Aruba Access Points.""" import logging import re diff --git a/homeassistant/components/arwn/sensor.py b/homeassistant/components/arwn/sensor.py index 95825f4ca13..aef43c4b401 100644 --- a/homeassistant/components/arwn/sensor.py +++ b/homeassistant/components/arwn/sensor.py @@ -1,9 +1,4 @@ -""" -Support for collecting data from the ARWN project. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.arwn/ -""" +"""Support for collecting data from the ARWN project.""" import json import logging diff --git a/homeassistant/components/asuswrt/device_tracker.py b/homeassistant/components/asuswrt/device_tracker.py index f5c6dd4a42a..d115e640ffa 100644 --- a/homeassistant/components/asuswrt/device_tracker.py +++ b/homeassistant/components/asuswrt/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for ASUSWRT routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.asuswrt/ -""" +"""Support for ASUSWRT routers.""" import logging from homeassistant.components.device_tracker import DeviceScanner diff --git a/homeassistant/components/asuswrt/sensor.py b/homeassistant/components/asuswrt/sensor.py index 53d232862c6..ac80a447e28 100644 --- a/homeassistant/components/asuswrt/sensor.py +++ b/homeassistant/components/asuswrt/sensor.py @@ -1,9 +1,4 @@ -""" -Asuswrt status sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.asuswrt/ -""" +"""Asuswrt status sensors.""" import logging from homeassistant.helpers.entity import Entity diff --git a/homeassistant/components/aurora/binary_sensor.py b/homeassistant/components/aurora/binary_sensor.py index cfd683346ff..58546382a50 100644 --- a/homeassistant/components/aurora/binary_sensor.py +++ b/homeassistant/components/aurora/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for aurora forecast data sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.aurora/ -""" +"""Support for aurora forecast data sensor.""" from datetime import timedelta import logging diff --git a/homeassistant/components/automatic/device_tracker.py b/homeassistant/components/automatic/device_tracker.py index 9f20eb6d493..8abd81e63be 100644 --- a/homeassistant/components/automatic/device_tracker.py +++ b/homeassistant/components/automatic/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for the Automatic platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.automatic/ -""" +"""Support for the Automatic platform.""" import asyncio from datetime import timedelta import json diff --git a/homeassistant/components/avion/light.py b/homeassistant/components/avion/light.py index 617198b2c8c..65172025b56 100644 --- a/homeassistant/components/avion/light.py +++ b/homeassistant/components/avion/light.py @@ -1,9 +1,4 @@ -""" -Support for Avion dimmers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.avion/ -""" +"""Support for Avion dimmers.""" import importlib import logging import time diff --git a/homeassistant/components/awair/sensor.py b/homeassistant/components/awair/sensor.py index 9a45cb66a86..5b199538e68 100644 --- a/homeassistant/components/awair/sensor.py +++ b/homeassistant/components/awair/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Awair indoor air quality monitor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.awair/ -""" +"""Support for the Awair indoor air quality monitor.""" from datetime import timedelta import logging diff --git a/homeassistant/components/aws_lambda/notify.py b/homeassistant/components/aws_lambda/notify.py index d7ebb40d19a..e5fed20d997 100644 --- a/homeassistant/components/aws_lambda/notify.py +++ b/homeassistant/components/aws_lambda/notify.py @@ -1,9 +1,4 @@ -""" -AWS Lambda platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.aws_lambda/ -""" +"""AWS Lambda platform for notify component.""" import base64 import json import logging diff --git a/homeassistant/components/aws_sns/notify.py b/homeassistant/components/aws_sns/notify.py index 09018562cb8..daac710d40a 100644 --- a/homeassistant/components/aws_sns/notify.py +++ b/homeassistant/components/aws_sns/notify.py @@ -1,9 +1,4 @@ -""" -AWS SNS platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.aws_sns/ -""" +"""AWS SNS platform for notify component.""" import json import logging diff --git a/homeassistant/components/aws_sqs/notify.py b/homeassistant/components/aws_sqs/notify.py index eff9018bae9..4c4c831482b 100644 --- a/homeassistant/components/aws_sqs/notify.py +++ b/homeassistant/components/aws_sqs/notify.py @@ -1,9 +1,4 @@ -""" -AWS SQS platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.aws_sqs/ -""" +"""AWS SQS platform for notify component.""" import json import logging diff --git a/homeassistant/components/baidu/tts.py b/homeassistant/components/baidu/tts.py index 07b69d41dfd..fbe27591ef5 100644 --- a/homeassistant/components/baidu/tts.py +++ b/homeassistant/components/baidu/tts.py @@ -1,10 +1,4 @@ -""" -Support for Baidu speech service. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/tts.baidu/ -""" - +"""Support for Baidu speech service.""" import logging import voluptuous as vol diff --git a/homeassistant/components/bayesian/binary_sensor.py b/homeassistant/components/bayesian/binary_sensor.py index 97889ea7497..6b2395ef6d2 100644 --- a/homeassistant/components/bayesian/binary_sensor.py +++ b/homeassistant/components/bayesian/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Use Bayesian Inference to trigger a binary sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.bayesian/ -""" +"""Use Bayesian Inference to trigger a binary sensor.""" from collections import OrderedDict import voluptuous as vol diff --git a/homeassistant/components/bbox/device_tracker.py b/homeassistant/components/bbox/device_tracker.py index f59c922577b..badbcdc8a0b 100644 --- a/homeassistant/components/bbox/device_tracker.py +++ b/homeassistant/components/bbox/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for French FAI Bouygues Bbox routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.bbox/ -""" +"""Support for French FAI Bouygues Bbox routers.""" from collections import namedtuple from datetime import timedelta import logging diff --git a/homeassistant/components/bbox/sensor.py b/homeassistant/components/bbox/sensor.py index c81160dc2ae..5b3c31d1ddf 100644 --- a/homeassistant/components/bbox/sensor.py +++ b/homeassistant/components/bbox/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Bbox Bouygues Modem Router. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.bbox/ -""" +"""Support for Bbox Bouygues Modem Router.""" import logging from datetime import timedelta diff --git a/homeassistant/components/bh1750/sensor.py b/homeassistant/components/bh1750/sensor.py index 592a6acbe58..e30eededa51 100644 --- a/homeassistant/components/bh1750/sensor.py +++ b/homeassistant/components/bh1750/sensor.py @@ -1,9 +1,4 @@ -""" -Support for BH1750 light sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.bh1750/ -""" +"""Support for BH1750 light sensor.""" from functools import partial import logging diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py index 9972e4dca3b..029ed8faa6b 100644 --- a/homeassistant/components/binary_sensor/__init__.py +++ b/homeassistant/components/binary_sensor/__init__.py @@ -1,9 +1,4 @@ -""" -Component to interface with binary sensors. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/binary_sensor/ -""" +"""Component to interface with binary sensors.""" from datetime import timedelta import logging diff --git a/homeassistant/components/bitcoin/sensor.py b/homeassistant/components/bitcoin/sensor.py index e654f29f42a..3bc14637a87 100644 --- a/homeassistant/components/bitcoin/sensor.py +++ b/homeassistant/components/bitcoin/sensor.py @@ -1,9 +1,4 @@ -""" -Bitcoin information service that uses blockchain.info. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.bitcoin/ -""" +"""Bitcoin information service that uses blockchain.info.""" import logging from datetime import timedelta diff --git a/homeassistant/components/blackbird/media_player.py b/homeassistant/components/blackbird/media_player.py index 2daa2656e83..c66bc412160 100644 --- a/homeassistant/components/blackbird/media_player.py +++ b/homeassistant/components/blackbird/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interfacing with Monoprice Blackbird 4k 8x8 HDBaseT Matrix. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.blackbird -""" +"""Support for interfacing with Monoprice Blackbird 4k 8x8 HDBaseT Matrix.""" import logging import socket diff --git a/homeassistant/components/blinksticklight/light.py b/homeassistant/components/blinksticklight/light.py index e145005a5a7..0d4c7b736f3 100644 --- a/homeassistant/components/blinksticklight/light.py +++ b/homeassistant/components/blinksticklight/light.py @@ -1,9 +1,4 @@ -""" -Support for Blinkstick lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.blinksticklight/ -""" +"""Support for Blinkstick lights.""" import logging import voluptuous as vol diff --git a/homeassistant/components/blinkt/light.py b/homeassistant/components/blinkt/light.py index 0704881bff9..57d19172614 100644 --- a/homeassistant/components/blinkt/light.py +++ b/homeassistant/components/blinkt/light.py @@ -1,9 +1,4 @@ -""" -Support for Blinkt! lights on Raspberry Pi. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.blinkt/ -""" +"""Support for Blinkt! lights on Raspberry Pi.""" import importlib import logging diff --git a/homeassistant/components/blockchain/sensor.py b/homeassistant/components/blockchain/sensor.py index 241c98d2328..def1dc3309f 100644 --- a/homeassistant/components/blockchain/sensor.py +++ b/homeassistant/components/blockchain/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Blockchain.info sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.blockchain/ -""" +"""Support for Blockchain.info sensors.""" import logging from datetime import timedelta diff --git a/homeassistant/components/bluesound/media_player.py b/homeassistant/components/bluesound/media_player.py index b25916c7f66..c4cd3572e75 100644 --- a/homeassistant/components/bluesound/media_player.py +++ b/homeassistant/components/bluesound/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Bluesound devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.bluesound/ -""" +"""Support for Bluesound devices.""" import asyncio from asyncio.futures import CancelledError from datetime import timedelta diff --git a/homeassistant/components/bluetooth_le_tracker/device_tracker.py b/homeassistant/components/bluetooth_le_tracker/device_tracker.py index 825ef04ccc5..dfb5fa073b9 100644 --- a/homeassistant/components/bluetooth_le_tracker/device_tracker.py +++ b/homeassistant/components/bluetooth_le_tracker/device_tracker.py @@ -1,9 +1,4 @@ -""" -Tracking for bluetooth low energy devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.bluetooth_le_tracker/ -""" +"""Tracking for bluetooth low energy devices.""" import logging from homeassistant.helpers.event import track_point_in_utc_time diff --git a/homeassistant/components/bluetooth_tracker/device_tracker.py b/homeassistant/components/bluetooth_tracker/device_tracker.py index 89f3b95ac1b..3a4aa888001 100644 --- a/homeassistant/components/bluetooth_tracker/device_tracker.py +++ b/homeassistant/components/bluetooth_tracker/device_tracker.py @@ -1,9 +1,4 @@ -""" -Tracking for bluetooth devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.bluetooth_tracker/ -""" +"""Tracking for bluetooth devices.""" import logging import voluptuous as vol diff --git a/homeassistant/components/bme280/sensor.py b/homeassistant/components/bme280/sensor.py index a6b773040ef..73982ecc628 100644 --- a/homeassistant/components/bme280/sensor.py +++ b/homeassistant/components/bme280/sensor.py @@ -1,9 +1,4 @@ -""" -Support for BME280 temperature, humidity and pressure sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.bme280/ -""" +"""Support for BME280 temperature, humidity and pressure sensor.""" from datetime import timedelta from functools import partial import logging diff --git a/homeassistant/components/bme680/sensor.py b/homeassistant/components/bme680/sensor.py index 8d620e459d0..8f515cc469a 100644 --- a/homeassistant/components/bme680/sensor.py +++ b/homeassistant/components/bme680/sensor.py @@ -1,12 +1,4 @@ -""" -Support for BME680 Sensor over SMBus. - -Temperature, humidity, pressure and volatile gas support. -Air Quality calculation based on humidity and volatile gas. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.bme680/ -""" +"""Support for BME680 Sensor over SMBus.""" import importlib import logging diff --git a/homeassistant/components/bom/sensor.py b/homeassistant/components/bom/sensor.py index 62a3706034a..4c96315ec1f 100644 --- a/homeassistant/components/bom/sensor.py +++ b/homeassistant/components/bom/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Australian BOM (Bureau of Meteorology) weather service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.bom/ -""" +"""Support for Australian BOM (Bureau of Meteorology) weather service.""" import datetime import ftplib import gzip diff --git a/homeassistant/components/braviatv/media_player.py b/homeassistant/components/braviatv/media_player.py index 7efb7abd569..45fdb63a4a9 100644 --- a/homeassistant/components/braviatv/media_player.py +++ b/homeassistant/components/braviatv/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interface with a Sony Bravia TV. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.braviatv/ -""" +"""Support for interface with a Sony Bravia TV.""" import logging import re diff --git a/homeassistant/components/broadlink/sensor.py b/homeassistant/components/broadlink/sensor.py index 5720201b3f2..60f1ed5c6bc 100644 --- a/homeassistant/components/broadlink/sensor.py +++ b/homeassistant/components/broadlink/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Broadlink RM2 Pro (only temperature) and A1 devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.broadlink/ -""" +"""Support for the Broadlink RM2 Pro (only temperature) and A1 devices.""" from datetime import timedelta import binascii import logging diff --git a/homeassistant/components/broadlink/switch.py b/homeassistant/components/broadlink/switch.py index 2237a0a2977..8695f70786c 100644 --- a/homeassistant/components/broadlink/switch.py +++ b/homeassistant/components/broadlink/switch.py @@ -1,9 +1,4 @@ -""" -Support for Broadlink RM devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.broadlink/ -""" +"""Support for Broadlink RM devices.""" import asyncio from base64 import b64decode, b64encode import binascii diff --git a/homeassistant/components/brottsplatskartan/sensor.py b/homeassistant/components/brottsplatskartan/sensor.py index c308f2eac53..f990dd1aba1 100644 --- a/homeassistant/components/brottsplatskartan/sensor.py +++ b/homeassistant/components/brottsplatskartan/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor platform for Brottsplatskartan information. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.brottsplatskartan/ -""" +"""Sensor platform for Brottsplatskartan information.""" from collections import defaultdict from datetime import timedelta import logging diff --git a/homeassistant/components/brunt/cover.py b/homeassistant/components/brunt/cover.py index 746f3840a01..dc17cebcec2 100644 --- a/homeassistant/components/brunt/cover.py +++ b/homeassistant/components/brunt/cover.py @@ -1,9 +1,4 @@ -""" -Support for Brunt Blind Engine covers. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/cover.brunt -""" +"""Support for Brunt Blind Engine covers.""" import logging diff --git a/homeassistant/components/bt_home_hub_5/device_tracker.py b/homeassistant/components/bt_home_hub_5/device_tracker.py index 21c41df3a1d..61853c0af89 100644 --- a/homeassistant/components/bt_home_hub_5/device_tracker.py +++ b/homeassistant/components/bt_home_hub_5/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for BT Home Hub 5. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.bt_home_hub_5/ -""" +"""Support for BT Home Hub 5.""" import logging import voluptuous as vol diff --git a/homeassistant/components/bt_smarthub/device_tracker.py b/homeassistant/components/bt_smarthub/device_tracker.py index 821182ec103..5820feda567 100644 --- a/homeassistant/components/bt_smarthub/device_tracker.py +++ b/homeassistant/components/bt_smarthub/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for BT Smart Hub (Sometimes referred to as BT Home Hub 6). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.bt_smarthub/ -""" +"""Support for BT Smart Hub (Sometimes referred to as BT Home Hub 6).""" import logging import voluptuous as vol diff --git a/homeassistant/components/buienradar/sensor.py b/homeassistant/components/buienradar/sensor.py index d144d84cbf8..754873fa2c9 100644 --- a/homeassistant/components/buienradar/sensor.py +++ b/homeassistant/components/buienradar/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Buienradar.nl weather service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.buienradar/ -""" +"""Support for Buienradar.nl weather service.""" import asyncio from datetime import datetime, timedelta import logging diff --git a/homeassistant/components/caldav/calendar.py b/homeassistant/components/caldav/calendar.py index cb8874a817c..65cb20811b8 100644 --- a/homeassistant/components/caldav/calendar.py +++ b/homeassistant/components/caldav/calendar.py @@ -1,9 +1,4 @@ -""" -Support for WebDav Calendar. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/calendar.caldav/ -""" +"""Support for WebDav Calendar.""" from datetime import datetime, timedelta import logging import re diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index e453cdfd1a1..10739a1c7bb 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -1,9 +1,4 @@ -""" -Component to interface with cameras. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/camera/ -""" +"""Component to interface with cameras.""" import asyncio import base64 import collections diff --git a/homeassistant/components/canary/alarm_control_panel.py b/homeassistant/components/canary/alarm_control_panel.py index 61794224666..faa7d819a2e 100644 --- a/homeassistant/components/canary/alarm_control_panel.py +++ b/homeassistant/components/canary/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Support for Canary alarm. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.canary/ -""" +"""Support for Canary alarm.""" import logging from homeassistant.components.alarm_control_panel import AlarmControlPanel diff --git a/homeassistant/components/canary/camera.py b/homeassistant/components/canary/camera.py index c3a3af32450..fc740a46f62 100644 --- a/homeassistant/components/canary/camera.py +++ b/homeassistant/components/canary/camera.py @@ -1,9 +1,4 @@ -""" -Support for Canary camera. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.canary/ -""" +"""Support for Canary camera.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/canary/sensor.py b/homeassistant/components/canary/sensor.py index d24c00c9266..fb3aaf78b0a 100644 --- a/homeassistant/components/canary/sensor.py +++ b/homeassistant/components/canary/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Canary sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.canary/ -""" +"""Support for Canary sensors.""" from homeassistant.const import TEMP_CELSIUS from homeassistant.helpers.entity import Entity diff --git a/homeassistant/components/cert_expiry/sensor.py b/homeassistant/components/cert_expiry/sensor.py index a04a631f2e9..54ba378f91c 100644 --- a/homeassistant/components/cert_expiry/sensor.py +++ b/homeassistant/components/cert_expiry/sensor.py @@ -1,9 +1,4 @@ -""" -Counter for the days until an HTTPS (TLS) certificate will expire. - -For more details about this sensor please refer to the documentation at -https://home-assistant.io/components/sensor.cert_expiry/ -""" +"""Counter for the days until an HTTPS (TLS) certificate will expire.""" import logging import socket import ssl diff --git a/homeassistant/components/channels/media_player.py b/homeassistant/components/channels/media_player.py index 2f7b169601c..afe29ae079f 100644 --- a/homeassistant/components/channels/media_player.py +++ b/homeassistant/components/channels/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interfacing with an instance of Channels (https://getchannels.com). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.channels/ -""" +"""Support for interfacing with an instance of getchannels.com.""" import logging import voluptuous as vol diff --git a/homeassistant/components/cisco_ios/device_tracker.py b/homeassistant/components/cisco_ios/device_tracker.py index 1afea2c1607..d5a64626e89 100644 --- a/homeassistant/components/cisco_ios/device_tracker.py +++ b/homeassistant/components/cisco_ios/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Cisco IOS Routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.cisco_ios/ -""" +"""Support for Cisco IOS Routers.""" import logging import voluptuous as vol diff --git a/homeassistant/components/ciscospark/notify.py b/homeassistant/components/ciscospark/notify.py index 1eeb9b51f28..2eccb233a3c 100644 --- a/homeassistant/components/ciscospark/notify.py +++ b/homeassistant/components/ciscospark/notify.py @@ -1,9 +1,4 @@ -""" -Cisco Spark platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.ciscospark/ -""" +"""Cisco Spark platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/citybikes/sensor.py b/homeassistant/components/citybikes/sensor.py index 12c475e62ff..bcf6fb923f9 100644 --- a/homeassistant/components/citybikes/sensor.py +++ b/homeassistant/components/citybikes/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for the CityBikes data. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.citybikes/ -""" +"""Sensor for the CityBikes data.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/clementine/media_player.py b/homeassistant/components/clementine/media_player.py index 24df7c24611..65c6be19845 100644 --- a/homeassistant/components/clementine/media_player.py +++ b/homeassistant/components/clementine/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Clementine Music Player as media player. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.clementine/ -""" +"""Support for Clementine Music Player as media player.""" from datetime import timedelta import logging import time diff --git a/homeassistant/components/clickatell/notify.py b/homeassistant/components/clickatell/notify.py index e473e54a3b7..b512a288ed5 100644 --- a/homeassistant/components/clickatell/notify.py +++ b/homeassistant/components/clickatell/notify.py @@ -1,9 +1,4 @@ -""" -Clickatell platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.clickatell/ -""" +"""Clickatell platform for notify component.""" import logging import requests diff --git a/homeassistant/components/clicksend/notify.py b/homeassistant/components/clicksend/notify.py index 3b2cdb7496d..111ae63601f 100644 --- a/homeassistant/components/clicksend/notify.py +++ b/homeassistant/components/clicksend/notify.py @@ -1,9 +1,4 @@ -""" -Clicksend platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.clicksend/ -""" +"""Clicksend platform for notify component.""" import json import logging diff --git a/homeassistant/components/clicksend_tts/notify.py b/homeassistant/components/clicksend_tts/notify.py index 93e5126bbab..feb4481fb56 100644 --- a/homeassistant/components/clicksend_tts/notify.py +++ b/homeassistant/components/clicksend_tts/notify.py @@ -1,11 +1,4 @@ -""" -clicksend_tts 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.clicksend_tts/ -""" +"""clicksend_tts platform for notify component.""" import json import logging diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 0283359b1f2..18b56049f83 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -1,9 +1,4 @@ -""" -Provides functionality to interact with climate devices. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/climate/ -""" +"""Provides functionality to interact with climate devices.""" from datetime import timedelta import logging import functools as ft diff --git a/homeassistant/components/cmus/media_player.py b/homeassistant/components/cmus/media_player.py index 20b292749b4..e5134508fea 100644 --- a/homeassistant/components/cmus/media_player.py +++ b/homeassistant/components/cmus/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interacting with and controlling the cmus music player. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.cmus/ -""" +"""Support for interacting with and controlling the cmus music player.""" import logging import voluptuous as vol diff --git a/homeassistant/components/co2signal/sensor.py b/homeassistant/components/co2signal/sensor.py index 7b4cd67bd70..b9ae5e26ebe 100644 --- a/homeassistant/components/co2signal/sensor.py +++ b/homeassistant/components/co2signal/sensor.py @@ -1,8 +1,4 @@ -""" -Support for the CO2signal platform. - -For more details about this platform, please refer to the documentation -""" +"""Support for the CO2signal platform.""" import logging import voluptuous as vol diff --git a/homeassistant/components/coinbase/sensor.py b/homeassistant/components/coinbase/sensor.py index 54af94944d6..2483d46b38a 100644 --- a/homeassistant/components/coinbase/sensor.py +++ b/homeassistant/components/coinbase/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Coinbase sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.coinbase/ -""" +"""Support for Coinbase sensors.""" from homeassistant.const import ATTR_ATTRIBUTION from homeassistant.helpers.entity import Entity diff --git a/homeassistant/components/coinmarketcap/sensor.py b/homeassistant/components/coinmarketcap/sensor.py index 9143405a553..a39f11b5352 100644 --- a/homeassistant/components/coinmarketcap/sensor.py +++ b/homeassistant/components/coinmarketcap/sensor.py @@ -1,9 +1,4 @@ -""" -Details about crypto currencies from CoinMarketCap. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.coinmarketcap/ -""" +"""Details about crypto currencies from CoinMarketCap.""" import logging from datetime import timedelta from urllib.error import HTTPError diff --git a/homeassistant/components/comed_hourly_pricing/sensor.py b/homeassistant/components/comed_hourly_pricing/sensor.py index 1771fd0f1a3..384aadd8bf4 100644 --- a/homeassistant/components/comed_hourly_pricing/sensor.py +++ b/homeassistant/components/comed_hourly_pricing/sensor.py @@ -1,9 +1,4 @@ -""" -Support for ComEd Hourly Pricing data. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.comed_hourly_pricing/ -""" +"""Support for ComEd Hourly Pricing data.""" import asyncio from datetime import timedelta import json diff --git a/homeassistant/components/command_line/binary_sensor.py b/homeassistant/components/command_line/binary_sensor.py index 21ee1312e7a..860367d8091 100644 --- a/homeassistant/components/command_line/binary_sensor.py +++ b/homeassistant/components/command_line/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for custom shell commands to retrieve values. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.command_line/ -""" +"""Support for custom shell commands to retrieve values.""" from datetime import timedelta import logging diff --git a/homeassistant/components/command_line/cover.py b/homeassistant/components/command_line/cover.py index 4f4fca1b27a..7f3c5279905 100644 --- a/homeassistant/components/command_line/cover.py +++ b/homeassistant/components/command_line/cover.py @@ -1,9 +1,4 @@ -""" -Support for command line covers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/cover.command_line/ -""" +"""Support for command line covers.""" import logging import subprocess diff --git a/homeassistant/components/command_line/notify.py b/homeassistant/components/command_line/notify.py index 7ea5a6d8880..941be72aa81 100644 --- a/homeassistant/components/command_line/notify.py +++ b/homeassistant/components/command_line/notify.py @@ -1,9 +1,4 @@ -""" -Support for command line notification services. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.command_line/ -""" +"""Support for command line notification services.""" import logging import subprocess diff --git a/homeassistant/components/command_line/sensor.py b/homeassistant/components/command_line/sensor.py index e1d151410b1..16d39762879 100644 --- a/homeassistant/components/command_line/sensor.py +++ b/homeassistant/components/command_line/sensor.py @@ -1,9 +1,4 @@ -""" -Allows to configure custom shell commands to turn a value for a sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.command_line/ -""" +"""Allows to configure custom shell commands to turn a value for a sensor.""" import collections from datetime import timedelta import json diff --git a/homeassistant/components/command_line/switch.py b/homeassistant/components/command_line/switch.py index 4edbd79ee0c..8d97198ad66 100644 --- a/homeassistant/components/command_line/switch.py +++ b/homeassistant/components/command_line/switch.py @@ -1,9 +1,4 @@ -""" -Support for custom shell commands to turn a switch on/off. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.command_line/ -""" +"""Support for custom shell commands to turn a switch on/off.""" import logging import subprocess diff --git a/homeassistant/components/concord232/alarm_control_panel.py b/homeassistant/components/concord232/alarm_control_panel.py index 155d6b6ae49..4821e589b13 100644 --- a/homeassistant/components/concord232/alarm_control_panel.py +++ b/homeassistant/components/concord232/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Support for Concord232 alarm control panels. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.concord232/ -""" +"""Support for Concord232 alarm control panels.""" import datetime import logging diff --git a/homeassistant/components/concord232/binary_sensor.py b/homeassistant/components/concord232/binary_sensor.py index 26f35d60305..5aff0f09983 100644 --- a/homeassistant/components/concord232/binary_sensor.py +++ b/homeassistant/components/concord232/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for exposing Concord232 elements as sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.concord232/ -""" +"""Support for exposing Concord232 elements as sensors.""" import datetime import logging diff --git a/homeassistant/components/coolmaster/climate.py b/homeassistant/components/coolmaster/climate.py index fd00c9f22c4..77bb9a6b213 100644 --- a/homeassistant/components/coolmaster/climate.py +++ b/homeassistant/components/coolmaster/climate.py @@ -1,9 +1,4 @@ -""" -CoolMasterNet platform that offers control of CoolMasteNet Climate Devices. - -For more details about this platform, please refer to the documentation -https://www.home-assistant.io/components/climate.coolmaster/ -""" +"""CoolMasterNet platform to control of CoolMasteNet Climate Devices.""" import logging diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index 8b4031f09ed..9bb1aacfaf1 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -1,9 +1,4 @@ -""" -Support for Cover devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/cover/ -""" +"""Support for Cover devices.""" from datetime import timedelta import functools as ft import logging diff --git a/homeassistant/components/cppm_tracker/device_tracker.py b/homeassistant/components/cppm_tracker/device_tracker.py index 2ca0ebf62e5..31d8122692a 100755 --- a/homeassistant/components/cppm_tracker/device_tracker.py +++ b/homeassistant/components/cppm_tracker/device_tracker.py @@ -1,8 +1,4 @@ -""" -Support for ClearPass Policy Manager. - -Allows tracking devices with CPPM. -""" +"""Support for ClearPass Policy Manager.""" import logging from datetime import timedelta diff --git a/homeassistant/components/cups/sensor.py b/homeassistant/components/cups/sensor.py index 99dadcfe596..97f894aed86 100644 --- a/homeassistant/components/cups/sensor.py +++ b/homeassistant/components/cups/sensor.py @@ -1,9 +1,4 @@ -""" -Details about printers which are connected to CUPS. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.cups/ -""" +"""Details about printers which are connected to CUPS.""" import importlib import logging from datetime import timedelta diff --git a/homeassistant/components/currencylayer/sensor.py b/homeassistant/components/currencylayer/sensor.py index 9b7186e8e09..bedd5f079ce 100644 --- a/homeassistant/components/currencylayer/sensor.py +++ b/homeassistant/components/currencylayer/sensor.py @@ -1,9 +1,4 @@ -""" -Support for currencylayer.com exchange rates service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.currencylayer/ -""" +"""Support for currencylayer.com exchange rates service.""" from datetime import timedelta import logging diff --git a/homeassistant/components/darksky/sensor.py b/homeassistant/components/darksky/sensor.py index 540568b5785..70b07ee773f 100644 --- a/homeassistant/components/darksky/sensor.py +++ b/homeassistant/components/darksky/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Dark Sky weather service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.darksky/ -""" +"""Support for Dark Sky weather service.""" from datetime import timedelta import logging diff --git a/homeassistant/components/ddwrt/device_tracker.py b/homeassistant/components/ddwrt/device_tracker.py index cf8c8e1779b..a97fe340f92 100644 --- a/homeassistant/components/ddwrt/device_tracker.py +++ b/homeassistant/components/ddwrt/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for DD-WRT routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.ddwrt/ -""" +"""Support for DD-WRT routers.""" import logging import re diff --git a/homeassistant/components/decora/light.py b/homeassistant/components/decora/light.py index 7c3274cf83b..fc8b2859c07 100644 --- a/homeassistant/components/decora/light.py +++ b/homeassistant/components/decora/light.py @@ -1,9 +1,4 @@ -""" -Support for Decora dimmers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.decora/ -""" +"""Support for Decora dimmers.""" import importlib import logging from functools import wraps diff --git a/homeassistant/components/decora_wifi/light.py b/homeassistant/components/decora_wifi/light.py index b9c575dbd5a..b7be6bffb01 100644 --- a/homeassistant/components/decora_wifi/light.py +++ b/homeassistant/components/decora_wifi/light.py @@ -1,12 +1,4 @@ -""" -Interfaces with the myLeviton API for Decora Smart WiFi products. - -See: -http://www.leviton.com/en/products/lighting-controls/decora-smart-with-wifi - -Uses Leviton's cloud services API for cloud-to-cloud integration. - -""" +"""Interfaces with the myLeviton API for Decora Smart WiFi products.""" import logging diff --git a/homeassistant/components/deluge/sensor.py b/homeassistant/components/deluge/sensor.py index f56b3ac4b97..32b1c16a47c 100644 --- a/homeassistant/components/deluge/sensor.py +++ b/homeassistant/components/deluge/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring the Deluge BitTorrent client API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.deluge/ -""" +"""Support for monitoring the Deluge BitTorrent client API.""" import logging import voluptuous as vol diff --git a/homeassistant/components/deluge/switch.py b/homeassistant/components/deluge/switch.py index 0ece742aa03..d7c60bd96e2 100644 --- a/homeassistant/components/deluge/switch.py +++ b/homeassistant/components/deluge/switch.py @@ -1,9 +1,4 @@ -""" -Support for setting the Deluge BitTorrent client in Pause. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.deluge/ -""" +"""Support for setting the Deluge BitTorrent client in Pause.""" import logging import voluptuous as vol diff --git a/homeassistant/components/demo/air_quality.py b/homeassistant/components/demo/air_quality.py index b2b9c10574f..77e5c0b2b1a 100644 --- a/homeassistant/components/demo/air_quality.py +++ b/homeassistant/components/demo/air_quality.py @@ -1,9 +1,4 @@ -""" -Demo platform that offers fake air quality data. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform that offers fake air quality data.""" from homeassistant.components.air_quality import AirQualityEntity diff --git a/homeassistant/components/demo/alarm_control_panel.py b/homeassistant/components/demo/alarm_control_panel.py index 4d317f52daa..3cf5aaca57e 100644 --- a/homeassistant/components/demo/alarm_control_panel.py +++ b/homeassistant/components/demo/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Demo platform that has two fake alarm control panels. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform that has two fake alarm control panels.""" import datetime from homeassistant.components.manual.alarm_control_panel import ManualAlarm from homeassistant.const import ( diff --git a/homeassistant/components/demo/binary_sensor.py b/homeassistant/components/demo/binary_sensor.py index d656b79e8ed..437497e4fac 100644 --- a/homeassistant/components/demo/binary_sensor.py +++ b/homeassistant/components/demo/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Demo platform that has two fake binary sensors. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform that has two fake binary sensors.""" from homeassistant.components.binary_sensor import BinarySensorDevice diff --git a/homeassistant/components/demo/calendar.py b/homeassistant/components/demo/calendar.py index 720b4cc5180..6096f8247c4 100644 --- a/homeassistant/components/demo/calendar.py +++ b/homeassistant/components/demo/calendar.py @@ -1,9 +1,4 @@ -""" -Demo platform that has two fake binary sensors. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform that has two fake binary sensors.""" import copy from homeassistant.components.google import CONF_DEVICE_ID, CONF_NAME diff --git a/homeassistant/components/demo/camera.py b/homeassistant/components/demo/camera.py index 34a0894ac60..95c7df58200 100644 --- a/homeassistant/components/demo/camera.py +++ b/homeassistant/components/demo/camera.py @@ -1,9 +1,4 @@ -""" -Demo camera platform that has a fake camera. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo camera platform that has a fake camera.""" import logging import os diff --git a/homeassistant/components/demo/climate.py b/homeassistant/components/demo/climate.py index b1dd1b0ba45..70eed0c3616 100644 --- a/homeassistant/components/demo/climate.py +++ b/homeassistant/components/demo/climate.py @@ -1,9 +1,4 @@ -""" -Demo platform that offers a fake climate device. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform that offers a fake climate device.""" from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT from homeassistant.components.climate import ClimateDevice diff --git a/homeassistant/components/demo/cover.py b/homeassistant/components/demo/cover.py index ddcf07fd5e5..aa2931a987a 100644 --- a/homeassistant/components/demo/cover.py +++ b/homeassistant/components/demo/cover.py @@ -1,9 +1,4 @@ -""" -Demo platform for the cover component. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform for the cover component.""" from homeassistant.helpers.event import track_utc_time_change from homeassistant.components.cover import ( diff --git a/homeassistant/components/demo/device_tracker.py b/homeassistant/components/demo/device_tracker.py index 608fc560cf9..ff038d7009e 100644 --- a/homeassistant/components/demo/device_tracker.py +++ b/homeassistant/components/demo/device_tracker.py @@ -1,9 +1,4 @@ -""" -Demo platform for the Device tracker component. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform for the Device tracker component.""" import random from homeassistant.components.device_tracker import DOMAIN diff --git a/homeassistant/components/demo/fan.py b/homeassistant/components/demo/fan.py index 53729795f71..4710bbecfe1 100644 --- a/homeassistant/components/demo/fan.py +++ b/homeassistant/components/demo/fan.py @@ -1,9 +1,4 @@ -""" -Demo fan platform that has a fake fan. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo fan platform that has a fake fan.""" from homeassistant.const import STATE_OFF from homeassistant.components.fan import ( diff --git a/homeassistant/components/demo/image_processing.py b/homeassistant/components/demo/image_processing.py index 71ec2dccbc6..acb97e4ebd6 100644 --- a/homeassistant/components/demo/image_processing.py +++ b/homeassistant/components/demo/image_processing.py @@ -1,9 +1,4 @@ -""" -Support for the demo image processing. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/demo/ -""" +"""Support for the demo image processing.""" from homeassistant.components.image_processing import ( ImageProcessingFaceEntity, ATTR_CONFIDENCE, ATTR_NAME, ATTR_AGE, ATTR_GENDER diff --git a/homeassistant/components/demo/light.py b/homeassistant/components/demo/light.py index a5b22108e81..285866c6eb8 100644 --- a/homeassistant/components/demo/light.py +++ b/homeassistant/components/demo/light.py @@ -1,9 +1,4 @@ -""" -Demo light platform that implements lights. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo light platform that implements lights.""" import random from homeassistant.components.light import ( diff --git a/homeassistant/components/demo/lock.py b/homeassistant/components/demo/lock.py index 03935c4f603..cd15a434138 100644 --- a/homeassistant/components/demo/lock.py +++ b/homeassistant/components/demo/lock.py @@ -1,9 +1,4 @@ -""" -Demo lock platform that has two fake locks. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo lock platform that has two fake locks.""" from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED from homeassistant.components.lock import SUPPORT_OPEN, LockDevice diff --git a/homeassistant/components/demo/media_player.py b/homeassistant/components/demo/media_player.py index 33d2b98d225..5ad13b4e995 100644 --- a/homeassistant/components/demo/media_player.py +++ b/homeassistant/components/demo/media_player.py @@ -1,9 +1,4 @@ -""" -Demo implementation of the media player. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo implementation of the media player.""" from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING import homeassistant.util.dt as dt_util diff --git a/homeassistant/components/demo/notify.py b/homeassistant/components/demo/notify.py index 5b8e1f1688f..92aaea6882d 100644 --- a/homeassistant/components/demo/notify.py +++ b/homeassistant/components/demo/notify.py @@ -1,9 +1,4 @@ -""" -Demo notification service. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo notification service.""" from homeassistant.components.notify import BaseNotificationService EVENT_NOTIFY = "notify" diff --git a/homeassistant/components/demo/remote.py b/homeassistant/components/demo/remote.py index f44061ac8f9..b28330fdc67 100644 --- a/homeassistant/components/demo/remote.py +++ b/homeassistant/components/demo/remote.py @@ -1,9 +1,4 @@ -""" -Demo platform that has two fake remotes. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform that has two fake remotes.""" from homeassistant.components.remote import RemoteDevice from homeassistant.const import DEVICE_DEFAULT_NAME diff --git a/homeassistant/components/demo/sensor.py b/homeassistant/components/demo/sensor.py index 7921181b742..ea35c729517 100644 --- a/homeassistant/components/demo/sensor.py +++ b/homeassistant/components/demo/sensor.py @@ -1,9 +1,4 @@ -""" -Demo platform that has a couple of fake sensors. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform that has a couple of fake sensors.""" from homeassistant.const import ( ATTR_BATTERY_LEVEL, TEMP_CELSIUS, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE) diff --git a/homeassistant/components/demo/switch.py b/homeassistant/components/demo/switch.py index 0ac2011a6dc..04a55a591b7 100644 --- a/homeassistant/components/demo/switch.py +++ b/homeassistant/components/demo/switch.py @@ -1,9 +1,4 @@ -""" -Demo platform that has two fake switches. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform that has two fake switches.""" from homeassistant.components.switch import SwitchDevice from homeassistant.const import DEVICE_DEFAULT_NAME diff --git a/homeassistant/components/demo/tts.py b/homeassistant/components/demo/tts.py index 1498472ef9f..bf18bc1630f 100644 --- a/homeassistant/components/demo/tts.py +++ b/homeassistant/components/demo/tts.py @@ -1,9 +1,4 @@ -""" -Support for the demo speech service. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/demo/ -""" +"""Support for the demo speech service.""" import os import voluptuous as vol diff --git a/homeassistant/components/demo/vacuum.py b/homeassistant/components/demo/vacuum.py index 5ec7030f56c..dfb9c4e943e 100644 --- a/homeassistant/components/demo/vacuum.py +++ b/homeassistant/components/demo/vacuum.py @@ -1,9 +1,4 @@ -""" -Demo platform for the vacuum component. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" +"""Demo platform for the vacuum component.""" import logging from homeassistant.components.vacuum import ( diff --git a/homeassistant/components/denon/media_player.py b/homeassistant/components/denon/media_player.py index 3dc4e550d9b..07f6fcc7f9c 100644 --- a/homeassistant/components/denon/media_player.py +++ b/homeassistant/components/denon/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Denon Network Receivers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.denon/ -""" +"""Support for Denon Network Receivers.""" import logging import telnetlib diff --git a/homeassistant/components/denonavr/media_player.py b/homeassistant/components/denonavr/media_player.py index 380484add53..0adafe4f472 100644 --- a/homeassistant/components/denonavr/media_player.py +++ b/homeassistant/components/denonavr/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Denon AVR receivers using their HTTP interface. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.denon/ -""" +"""Support for Denon AVR receivers using their HTTP interface.""" from collections import namedtuple import logging diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 1263811aae7..42d301721da 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -1,9 +1,4 @@ -""" -Provide functionality to keep track of devices. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/device_tracker/ -""" +"""Provide functionality to keep track of devices.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/dht/sensor.py b/homeassistant/components/dht/sensor.py index 04c084784c7..719c2525f0a 100644 --- a/homeassistant/components/dht/sensor.py +++ b/homeassistant/components/dht/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Adafruit DHT temperature and humidity sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.dht/ -""" +"""Support for Adafruit DHT temperature and humidity sensor.""" import logging from datetime import timedelta diff --git a/homeassistant/components/digitalloggers/switch.py b/homeassistant/components/digitalloggers/switch.py index 7bb2be19899..89973cfad0c 100644 --- a/homeassistant/components/digitalloggers/switch.py +++ b/homeassistant/components/digitalloggers/switch.py @@ -1,9 +1,4 @@ -""" -Support for Digital Loggers DIN III Relays. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.digitalloggers/ -""" +"""Support for Digital Loggers DIN III Relays.""" import logging from datetime import timedelta diff --git a/homeassistant/components/directv/media_player.py b/homeassistant/components/directv/media_player.py index 9c5a3bf07b8..3a30282bdf4 100644 --- a/homeassistant/components/directv/media_player.py +++ b/homeassistant/components/directv/media_player.py @@ -1,9 +1,4 @@ -""" -Support for the DirecTV receivers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.directv/ -""" +"""Support for the DirecTV receivers.""" import logging import requests import voluptuous as vol diff --git a/homeassistant/components/discogs/sensor.py b/homeassistant/components/discogs/sensor.py index 8cdc89a540e..f8d66688b4f 100644 --- a/homeassistant/components/discogs/sensor.py +++ b/homeassistant/components/discogs/sensor.py @@ -1,9 +1,4 @@ -""" -Show the amount of records in a user's Discogs collection. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.discogs/ -""" +"""Show the amount of records in a user's Discogs collection.""" from datetime import timedelta import logging import random diff --git a/homeassistant/components/discord/notify.py b/homeassistant/components/discord/notify.py index d73382d8bcf..cb6fc8329c6 100644 --- a/homeassistant/components/discord/notify.py +++ b/homeassistant/components/discord/notify.py @@ -1,9 +1,4 @@ -""" -Discord platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.discord/ -""" +"""Discord platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/dlib_face_detect/image_processing.py b/homeassistant/components/dlib_face_detect/image_processing.py index fea756395e4..49fbfadff7e 100644 --- a/homeassistant/components/dlib_face_detect/image_processing.py +++ b/homeassistant/components/dlib_face_detect/image_processing.py @@ -1,9 +1,4 @@ -""" -Component that will help set the Dlib face detect processing. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/image_processing.dlib_face_detect/ -""" +"""Component that will help set the Dlib face detect processing.""" import logging import io diff --git a/homeassistant/components/dlib_face_identify/image_processing.py b/homeassistant/components/dlib_face_identify/image_processing.py index 6611fb0edfb..a3b91235125 100644 --- a/homeassistant/components/dlib_face_identify/image_processing.py +++ b/homeassistant/components/dlib_face_identify/image_processing.py @@ -1,9 +1,4 @@ -""" -Component that will help set the Dlib face detect processing. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/image_processing.dlib_face_identify/ -""" +"""Component that will help set the Dlib face detect processing.""" import logging import io diff --git a/homeassistant/components/dlink/switch.py b/homeassistant/components/dlink/switch.py index de584510008..812fd3882b3 100644 --- a/homeassistant/components/dlink/switch.py +++ b/homeassistant/components/dlink/switch.py @@ -1,9 +1,4 @@ -""" -Support for D-Link W215 smart switch. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.dlink/ -""" +"""Support for D-Link W215 smart switch.""" from datetime import timedelta import logging import urllib diff --git a/homeassistant/components/dlna_dmr/media_player.py b/homeassistant/components/dlna_dmr/media_player.py index 71195d66c69..54c19f70ef3 100644 --- a/homeassistant/components/dlna_dmr/media_player.py +++ b/homeassistant/components/dlna_dmr/media_player.py @@ -1,9 +1,4 @@ -""" -Support for DLNA DMR (Device Media Renderer). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.dlna_dmr/ -""" +"""Support for DLNA DMR (Device Media Renderer).""" import asyncio from datetime import datetime from datetime import timedelta diff --git a/homeassistant/components/dnsip/sensor.py b/homeassistant/components/dnsip/sensor.py index 48cf8debea6..13c9be7bb14 100644 --- a/homeassistant/components/dnsip/sensor.py +++ b/homeassistant/components/dnsip/sensor.py @@ -1,9 +1,4 @@ -""" -Get your own public IP address or that of any host. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.dnsip/ -""" +"""Get your own public IP address or that of any host.""" import logging from datetime import timedelta diff --git a/homeassistant/components/dsmr/sensor.py b/homeassistant/components/dsmr/sensor.py index 6319a68b0c8..74f6cb37fc2 100644 --- a/homeassistant/components/dsmr/sensor.py +++ b/homeassistant/components/dsmr/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Dutch Smart Meter (also known as Smartmeter or P1 port). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.dsmr/ -""" +"""Support for Dutch Smart Meter (also known as Smartmeter or P1 port).""" import asyncio from datetime import timedelta from functools import partial diff --git a/homeassistant/components/dte_energy_bridge/sensor.py b/homeassistant/components/dte_energy_bridge/sensor.py index 5de2fc4a4ee..8610a1e7f70 100644 --- a/homeassistant/components/dte_energy_bridge/sensor.py +++ b/homeassistant/components/dte_energy_bridge/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring energy usage using the DTE energy bridge. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.dte_energy_bridge/ -""" +"""Support for monitoring energy usage using the DTE energy bridge.""" import logging import voluptuous as vol diff --git a/homeassistant/components/duke_energy/sensor.py b/homeassistant/components/duke_energy/sensor.py index 41d3e5706de..9aada348418 100644 --- a/homeassistant/components/duke_energy/sensor.py +++ b/homeassistant/components/duke_energy/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Duke Energy Gas and Electric meters. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.duke_energy/ -""" +"""Support for Duke Energy Gas and Electric meters.""" import logging import voluptuous as vol diff --git a/homeassistant/components/dunehd/media_player.py b/homeassistant/components/dunehd/media_player.py index 796aea86414..70d96424ced 100644 --- a/homeassistant/components/dunehd/media_player.py +++ b/homeassistant/components/dunehd/media_player.py @@ -1,9 +1,4 @@ -""" -DuneHD implementation of the media player. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/media_player.dunehd/ -""" +"""DuneHD implementation of the media player.""" import voluptuous as vol from homeassistant.components.media_player import ( diff --git a/homeassistant/components/dyson/climate.py b/homeassistant/components/dyson/climate.py index a24d011623b..a0c4c56d318 100644 --- a/homeassistant/components/dyson/climate.py +++ b/homeassistant/components/dyson/climate.py @@ -1,9 +1,4 @@ -""" -Support for Dyson Pure Hot+Cool link fan. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.dyson/ -""" +"""Support for Dyson Pure Hot+Cool link fan.""" import logging from homeassistant.components.climate import ClimateDevice diff --git a/homeassistant/components/dyson/sensor.py b/homeassistant/components/dyson/sensor.py index abf06f15437..2c7a71f5724 100644 --- a/homeassistant/components/dyson/sensor.py +++ b/homeassistant/components/dyson/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Dyson Pure Cool Link Sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.dyson/ -""" +"""Support for Dyson Pure Cool Link Sensors.""" import logging from homeassistant.const import STATE_OFF, TEMP_CELSIUS diff --git a/homeassistant/components/dyson/vacuum.py b/homeassistant/components/dyson/vacuum.py index 72c7b95562f..f1822b4043b 100644 --- a/homeassistant/components/dyson/vacuum.py +++ b/homeassistant/components/dyson/vacuum.py @@ -1,9 +1,4 @@ -""" -Support for the Dyson 360 eye vacuum cleaner robot. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/vacuum.dyson/ -""" +"""Support for the Dyson 360 eye vacuum cleaner robot.""" import logging from homeassistant.components.vacuum import ( diff --git a/homeassistant/components/edimax/switch.py b/homeassistant/components/edimax/switch.py index 90ad3fff57f..338e6ac932c 100644 --- a/homeassistant/components/edimax/switch.py +++ b/homeassistant/components/edimax/switch.py @@ -1,9 +1,4 @@ -""" -Support for Edimax switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.edimax/ -""" +"""Support for Edimax switches.""" import logging import voluptuous as vol diff --git a/homeassistant/components/ee_brightbox/device_tracker.py b/homeassistant/components/ee_brightbox/device_tracker.py index fc23abda1db..46e4a3c3c24 100644 --- a/homeassistant/components/ee_brightbox/device_tracker.py +++ b/homeassistant/components/ee_brightbox/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for EE Brightbox router. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.ee_brightbox/ -""" +"""Support for EE Brightbox router.""" import logging import voluptuous as vol diff --git a/homeassistant/components/efergy/sensor.py b/homeassistant/components/efergy/sensor.py index b3c40b4fa25..eb8912abe18 100644 --- a/homeassistant/components/efergy/sensor.py +++ b/homeassistant/components/efergy/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Efergy sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.efergy/ -""" +"""Support for Efergy sensors.""" import logging import requests diff --git a/homeassistant/components/eliqonline/sensor.py b/homeassistant/components/eliqonline/sensor.py index b03164a30d4..198ca327997 100644 --- a/homeassistant/components/eliqonline/sensor.py +++ b/homeassistant/components/eliqonline/sensor.py @@ -1,9 +1,4 @@ -""" -Monitors home energy use for the ELIQ Online service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.eliqonline/ -""" +"""Monitors home energy use for the ELIQ Online service.""" from datetime import timedelta import logging diff --git a/homeassistant/components/emby/media_player.py b/homeassistant/components/emby/media_player.py index b1259db913d..8a94664f352 100644 --- a/homeassistant/components/emby/media_player.py +++ b/homeassistant/components/emby/media_player.py @@ -1,9 +1,4 @@ -""" -Support to interface with the Emby API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.emby/ -""" +"""Support to interface with the Emby API.""" import logging import voluptuous as vol diff --git a/homeassistant/components/emoncms/sensor.py b/homeassistant/components/emoncms/sensor.py index 5d619878d98..6e059e1a30f 100644 --- a/homeassistant/components/emoncms/sensor.py +++ b/homeassistant/components/emoncms/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring emoncms feeds. - -For more details about this component, please refer to the documentation -at https://home-assistant.io/components/sensor.emoncms/ -""" +"""Support for monitoring emoncms feeds.""" from datetime import timedelta import logging diff --git a/homeassistant/components/enphase_envoy/sensor.py b/homeassistant/components/enphase_envoy/sensor.py index 1bfee88d41c..2b62732dc91 100644 --- a/homeassistant/components/enphase_envoy/sensor.py +++ b/homeassistant/components/enphase_envoy/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Enphase Envoy solar energy monitor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.enphase_envoy/ -""" +"""Support for Enphase Envoy solar energy monitor.""" import logging import voluptuous as vol diff --git a/homeassistant/components/envirophat/sensor.py b/homeassistant/components/envirophat/sensor.py index 7683c06b69c..16cb79406a9 100644 --- a/homeassistant/components/envirophat/sensor.py +++ b/homeassistant/components/envirophat/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Enviro pHAT sensors. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.envirophat -""" +"""Support for Enviro pHAT sensors.""" import importlib import logging from datetime import timedelta diff --git a/homeassistant/components/ephember/climate.py b/homeassistant/components/ephember/climate.py index 220c073ef80..3052dd911ee 100644 --- a/homeassistant/components/ephember/climate.py +++ b/homeassistant/components/ephember/climate.py @@ -1,9 +1,4 @@ -""" -Support for the EPH Controls Ember themostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.ephember/ -""" +"""Support for the EPH Controls Ember themostats.""" import logging from datetime import timedelta import voluptuous as vol diff --git a/homeassistant/components/epson/media_player.py b/homeassistant/components/epson/media_player.py index 38c0ffacc32..75be4f7fe2c 100644 --- a/homeassistant/components/epson/media_player.py +++ b/homeassistant/components/epson/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Epson projector. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/media_player.epson/ -""" +"""Support for Epson projector.""" import logging import voluptuous as vol diff --git a/homeassistant/components/eq3btsmart/climate.py b/homeassistant/components/eq3btsmart/climate.py index 43a26c27ce1..f02bd2bc9a5 100644 --- a/homeassistant/components/eq3btsmart/climate.py +++ b/homeassistant/components/eq3btsmart/climate.py @@ -1,9 +1,4 @@ -""" -Support for eQ-3 Bluetooth Smart thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.eq3btsmart/ -""" +"""Support for eQ-3 Bluetooth Smart thermostats.""" import logging import voluptuous as vol diff --git a/homeassistant/components/everlights/light.py b/homeassistant/components/everlights/light.py index 31e72c78fd6..a628f25ea28 100644 --- a/homeassistant/components/everlights/light.py +++ b/homeassistant/components/everlights/light.py @@ -1,9 +1,4 @@ -""" -Support for EverLights lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.everlights/ -""" +"""Support for EverLights lights.""" import logging from datetime import timedelta from typing import Tuple diff --git a/homeassistant/components/facebook/notify.py b/homeassistant/components/facebook/notify.py index 2c691661a29..625b922927c 100644 --- a/homeassistant/components/facebook/notify.py +++ b/homeassistant/components/facebook/notify.py @@ -1,9 +1,4 @@ -""" -Facebook platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.facebook/ -""" +"""Facebook platform for notify component.""" import json import logging diff --git a/homeassistant/components/facebox/image_processing.py b/homeassistant/components/facebox/image_processing.py index 2fbd1c5c81c..2b4f184c3fd 100644 --- a/homeassistant/components/facebox/image_processing.py +++ b/homeassistant/components/facebox/image_processing.py @@ -1,9 +1,4 @@ -""" -Component that will perform facial detection and identification via facebox. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/image_processing.facebox -""" +"""Component for facial detection and identification via facebox.""" import base64 import logging diff --git a/homeassistant/components/familyhub/camera.py b/homeassistant/components/familyhub/camera.py index e14bd9f1098..18aa969132d 100644 --- a/homeassistant/components/familyhub/camera.py +++ b/homeassistant/components/familyhub/camera.py @@ -1,9 +1,4 @@ -""" -Family Hub camera for Samsung Refrigerators. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/camera.familyhub/ -""" +"""Family Hub camera for Samsung Refrigerators.""" import logging import voluptuous as vol diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index 50d6802c4d2..e67ba390a98 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -1,9 +1,4 @@ -""" -Provides functionality to interact with fans. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/fan/ -""" +"""Provides functionality to interact with fans.""" from datetime import timedelta import functools as ft import logging diff --git a/homeassistant/components/fedex/sensor.py b/homeassistant/components/fedex/sensor.py index 54c319e6441..f535195bd07 100644 --- a/homeassistant/components/fedex/sensor.py +++ b/homeassistant/components/fedex/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for Fedex packages. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.fedex/ -""" +"""Sensor for Fedex packages.""" from collections import defaultdict import logging from datetime import timedelta diff --git a/homeassistant/components/ffmpeg/camera.py b/homeassistant/components/ffmpeg/camera.py index 07e56cfd51f..8bca13cfbb7 100644 --- a/homeassistant/components/ffmpeg/camera.py +++ b/homeassistant/components/ffmpeg/camera.py @@ -1,9 +1,4 @@ -""" -Support for Cameras with FFmpeg as decoder. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.ffmpeg/ -""" +"""Support for Cameras with FFmpeg as decoder.""" import asyncio import logging diff --git a/homeassistant/components/ffmpeg_motion/binary_sensor.py b/homeassistant/components/ffmpeg_motion/binary_sensor.py index 8183b0e66a6..c274d84329e 100644 --- a/homeassistant/components/ffmpeg_motion/binary_sensor.py +++ b/homeassistant/components/ffmpeg_motion/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Provides a binary sensor which is a collection of ffmpeg tools. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.ffmpeg_motion/ -""" +"""Provides a binary sensor which is a collection of ffmpeg tools.""" import logging import voluptuous as vol diff --git a/homeassistant/components/ffmpeg_noise/binary_sensor.py b/homeassistant/components/ffmpeg_noise/binary_sensor.py index 56edf1ddfd6..7efcc3deda2 100644 --- a/homeassistant/components/ffmpeg_noise/binary_sensor.py +++ b/homeassistant/components/ffmpeg_noise/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Provides a binary sensor which is a collection of ffmpeg tools. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.ffmpeg_noise/ -""" +"""Provides a binary sensor which is a collection of ffmpeg tools.""" import logging import voluptuous as vol diff --git a/homeassistant/components/file/notify.py b/homeassistant/components/file/notify.py index d449476469b..07718dcf36c 100644 --- a/homeassistant/components/file/notify.py +++ b/homeassistant/components/file/notify.py @@ -1,9 +1,4 @@ -""" -Support for file notification. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.file/ -""" +"""Support for file notification.""" import logging import os diff --git a/homeassistant/components/file/sensor.py b/homeassistant/components/file/sensor.py index 3e2a5c21be8..a618c1e56dc 100644 --- a/homeassistant/components/file/sensor.py +++ b/homeassistant/components/file/sensor.py @@ -1,9 +1,4 @@ -""" -Support for sensor value(s) stored in local files. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.file/ -""" +"""Support for sensor value(s) stored in local files.""" import os import logging diff --git a/homeassistant/components/filesize/sensor.py b/homeassistant/components/filesize/sensor.py index 4df858fda23..3e1394c72d6 100644 --- a/homeassistant/components/filesize/sensor.py +++ b/homeassistant/components/filesize/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for monitoring the size of a file. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.filesize/ -""" +"""Sensor for monitoring the size of a file.""" import datetime import logging import os diff --git a/homeassistant/components/filter/sensor.py b/homeassistant/components/filter/sensor.py index 92e2cc751ac..734caa31270 100644 --- a/homeassistant/components/filter/sensor.py +++ b/homeassistant/components/filter/sensor.py @@ -1,9 +1,4 @@ -""" -Allows the creation of a sensor that filters state property. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.filter/ -""" +"""Allows the creation of a sensor that filters state property.""" import logging import statistics from collections import deque, Counter diff --git a/homeassistant/components/fints/sensor.py b/homeassistant/components/fints/sensor.py index e5dae70070b..dce52785fbf 100644 --- a/homeassistant/components/fints/sensor.py +++ b/homeassistant/components/fints/sensor.py @@ -1,9 +1,4 @@ -""" -Read the balance of your bank accounts via FinTS. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.fints/ -""" +"""Read the balance of your bank accounts via FinTS.""" from collections import namedtuple from datetime import timedelta diff --git a/homeassistant/components/fitbit/sensor.py b/homeassistant/components/fitbit/sensor.py index d5d9150e4e8..abbe69c3e1d 100644 --- a/homeassistant/components/fitbit/sensor.py +++ b/homeassistant/components/fitbit/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Fitbit API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.fitbit/ -""" +"""Support for the Fitbit API.""" import os import logging import datetime diff --git a/homeassistant/components/fixer/sensor.py b/homeassistant/components/fixer/sensor.py index c46fa751319..f746d2008e1 100644 --- a/homeassistant/components/fixer/sensor.py +++ b/homeassistant/components/fixer/sensor.py @@ -1,9 +1,4 @@ -""" -Currency exchange rate support that comes from fixer.io. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.fixer/ -""" +"""Currency exchange rate support that comes from fixer.io.""" from datetime import timedelta import logging diff --git a/homeassistant/components/flic/binary_sensor.py b/homeassistant/components/flic/binary_sensor.py index baf1d469b28..083ac01ab4a 100644 --- a/homeassistant/components/flic/binary_sensor.py +++ b/homeassistant/components/flic/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support to use flic buttons as a binary sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.flic/ -""" +"""Support to use flic buttons as a binary sensor.""" import logging import threading diff --git a/homeassistant/components/flock/notify.py b/homeassistant/components/flock/notify.py index b37483d2f13..384bf26599a 100644 --- a/homeassistant/components/flock/notify.py +++ b/homeassistant/components/flock/notify.py @@ -1,9 +1,4 @@ -""" -Flock platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.flock/ -""" +"""Flock platform for notify component.""" import asyncio import logging diff --git a/homeassistant/components/flunearyou/sensor.py b/homeassistant/components/flunearyou/sensor.py index 8dfb330cf5c..65de2c6ae43 100644 --- a/homeassistant/components/flunearyou/sensor.py +++ b/homeassistant/components/flunearyou/sensor.py @@ -1,9 +1,4 @@ -""" -Support for user- and CDC-based flu info sensors from Flu Near You. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.flunearyou/ -""" +"""Support for user- and CDC-based flu info sensors from Flu Near You.""" import logging from datetime import timedelta diff --git a/homeassistant/components/flux_led/light.py b/homeassistant/components/flux_led/light.py index 17c288da6c2..0ed14c49ec8 100644 --- a/homeassistant/components/flux_led/light.py +++ b/homeassistant/components/flux_led/light.py @@ -1,9 +1,4 @@ -""" -Support for Flux lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.flux_led/ -""" +"""Support for Flux lights.""" import logging import socket import random diff --git a/homeassistant/components/folder/sensor.py b/homeassistant/components/folder/sensor.py index 8101bbd059a..d742166a192 100644 --- a/homeassistant/components/folder/sensor.py +++ b/homeassistant/components/folder/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for monitoring the contents of a folder. - -For more details about this platform, refer to the documentation at -https://home-assistant.io/components/sensor.folder/ -""" +"""Sensor for monitoring the contents of a folder.""" from datetime import timedelta import glob import logging diff --git a/homeassistant/components/foobot/sensor.py b/homeassistant/components/foobot/sensor.py index 62139c53c4b..2eeca5243a6 100644 --- a/homeassistant/components/foobot/sensor.py +++ b/homeassistant/components/foobot/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Foobot indoor air quality monitor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.foobot/ -""" +"""Support for the Foobot indoor air quality monitor.""" import asyncio import logging from datetime import timedelta diff --git a/homeassistant/components/foscam/camera.py b/homeassistant/components/foscam/camera.py index b6f2162d57a..9852f617d01 100644 --- a/homeassistant/components/foscam/camera.py +++ b/homeassistant/components/foscam/camera.py @@ -1,9 +1,4 @@ -""" -This component provides basic support for Foscam IP cameras. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.foscam/ -""" +"""This component provides basic support for Foscam IP cameras.""" import logging import voluptuous as vol diff --git a/homeassistant/components/free_mobile/notify.py b/homeassistant/components/free_mobile/notify.py index 1c6804f6d82..03beef52357 100644 --- a/homeassistant/components/free_mobile/notify.py +++ b/homeassistant/components/free_mobile/notify.py @@ -1,9 +1,4 @@ -""" -Support for thr Free Mobile SMS platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.free_mobile/ -""" +"""Support for thr Free Mobile SMS platform.""" import logging import voluptuous as vol diff --git a/homeassistant/components/freedns/__init__.py b/homeassistant/components/freedns/__init__.py index edb3a57c28c..a0b14757745 100644 --- a/homeassistant/components/freedns/__init__.py +++ b/homeassistant/components/freedns/__init__.py @@ -1,9 +1,4 @@ -""" -Integrate with FreeDNS Dynamic DNS service at freedns.afraid.org. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/freedns/ -""" +"""Integrate with FreeDNS Dynamic DNS service at freedns.afraid.org.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/fritz/device_tracker.py b/homeassistant/components/fritz/device_tracker.py index 75e280fe908..3e3e04f4447 100644 --- a/homeassistant/components/fritz/device_tracker.py +++ b/homeassistant/components/fritz/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for FRITZ!Box routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.fritz/ -""" +"""Support for FRITZ!Box routers.""" import logging import voluptuous as vol diff --git a/homeassistant/components/fritzbox_callmonitor/sensor.py b/homeassistant/components/fritzbox_callmonitor/sensor.py index 397f08d8a7c..a6641bc14ad 100644 --- a/homeassistant/components/fritzbox_callmonitor/sensor.py +++ b/homeassistant/components/fritzbox_callmonitor/sensor.py @@ -1,9 +1,4 @@ -""" -A sensor to monitor incoming and outgoing phone calls on a Fritz!Box router. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.fritzbox_callmonitor/ -""" +"""Sensor to monitor incoming/outgoing phone calls on a Fritz!Box router.""" import logging import socket import threading diff --git a/homeassistant/components/fritzbox_netmonitor/sensor.py b/homeassistant/components/fritzbox_netmonitor/sensor.py index 356c1424012..93f834a894d 100644 --- a/homeassistant/components/fritzbox_netmonitor/sensor.py +++ b/homeassistant/components/fritzbox_netmonitor/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring an AVM Fritz!Box router. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.fritzbox_netmonitor/ -""" +"""Support for monitoring an AVM Fritz!Box router.""" import logging from datetime import timedelta from requests.exceptions import RequestException diff --git a/homeassistant/components/fritzdect/switch.py b/homeassistant/components/fritzdect/switch.py index 0d9008552a1..449ae5a76f1 100644 --- a/homeassistant/components/fritzdect/switch.py +++ b/homeassistant/components/fritzdect/switch.py @@ -1,9 +1,4 @@ -""" -Support for FRITZ!DECT Switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.fritzdect/ -""" +"""Support for FRITZ!DECT Switches.""" import logging from requests.exceptions import RequestException, HTTPError diff --git a/homeassistant/components/frontier_silicon/media_player.py b/homeassistant/components/frontier_silicon/media_player.py index ed7041a3b82..4f28d83e6cf 100644 --- a/homeassistant/components/frontier_silicon/media_player.py +++ b/homeassistant/components/frontier_silicon/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Frontier Silicon Devices (Medion, Hama, Auna,...). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.frontier_silicon/ -""" +"""Support for Frontier Silicon Devices (Medion, Hama, Auna,...).""" import logging import voluptuous as vol diff --git a/homeassistant/components/futurenow/light.py b/homeassistant/components/futurenow/light.py index 8b0a809b667..4b570fd0a4d 100644 --- a/homeassistant/components/futurenow/light.py +++ b/homeassistant/components/futurenow/light.py @@ -1,9 +1,4 @@ -""" -Support for FutureNow Ethernet unit outputs as Lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.futurenow/ -""" +"""Support for FutureNow Ethernet unit outputs as Lights.""" import logging diff --git a/homeassistant/components/garadget/cover.py b/homeassistant/components/garadget/cover.py index 426afc6d314..b3c7c7c1215 100644 --- a/homeassistant/components/garadget/cover.py +++ b/homeassistant/components/garadget/cover.py @@ -1,9 +1,4 @@ -""" -Platform for the Garadget cover component. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/garadget/ -""" +"""Platform for the Garadget cover component.""" import logging import requests diff --git a/homeassistant/components/gc100/binary_sensor.py b/homeassistant/components/gc100/binary_sensor.py index ec69d1eec83..9588506af77 100644 --- a/homeassistant/components/gc100/binary_sensor.py +++ b/homeassistant/components/gc100/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for binary sensor using GC100. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.gc100/ -""" +"""Support for binary sensor using GC100.""" import voluptuous as vol from homeassistant.components.binary_sensor import ( diff --git a/homeassistant/components/gc100/switch.py b/homeassistant/components/gc100/switch.py index 94c824fa5d7..1ffb2726495 100644 --- a/homeassistant/components/gc100/switch.py +++ b/homeassistant/components/gc100/switch.py @@ -1,9 +1,4 @@ -""" -Support for switches using GC100. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.gc100/ -""" +"""Support for switches using GC100.""" import voluptuous as vol from homeassistant.components.switch import PLATFORM_SCHEMA diff --git a/homeassistant/components/gearbest/sensor.py b/homeassistant/components/gearbest/sensor.py index 5521e9a644c..e4f85a1892d 100644 --- a/homeassistant/components/gearbest/sensor.py +++ b/homeassistant/components/gearbest/sensor.py @@ -1,9 +1,4 @@ -""" -Parse prices of an item from gearbest. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.gearbest/ -""" +"""Parse prices of an item from gearbest.""" import logging from datetime import timedelta diff --git a/homeassistant/components/geizhals/sensor.py b/homeassistant/components/geizhals/sensor.py index 66cab473f49..d619d768c23 100644 --- a/homeassistant/components/geizhals/sensor.py +++ b/homeassistant/components/geizhals/sensor.py @@ -1,9 +1,4 @@ -""" -Parse prices of a device from geizhals. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.geizhals/ -""" +"""Parse prices of a device from geizhals.""" import logging from datetime import timedelta diff --git a/homeassistant/components/generic/camera.py b/homeassistant/components/generic/camera.py index c9f8616f637..bfe42a5b080 100644 --- a/homeassistant/components/generic/camera.py +++ b/homeassistant/components/generic/camera.py @@ -1,9 +1,4 @@ -""" -Support for IP Cameras. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.generic/ -""" +"""Support for IP Cameras.""" import asyncio import logging diff --git a/homeassistant/components/generic_thermostat/climate.py b/homeassistant/components/generic_thermostat/climate.py index 1eb0f8e79db..35efa82c8a3 100644 --- a/homeassistant/components/generic_thermostat/climate.py +++ b/homeassistant/components/generic_thermostat/climate.py @@ -1,9 +1,4 @@ -""" -Adds support for generic thermostat units. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.generic_thermostat/ -""" +"""Adds support for generic thermostat units.""" import asyncio import logging diff --git a/homeassistant/components/geofency/device_tracker.py b/homeassistant/components/geofency/device_tracker.py index 5e7b8291840..0a1a9d5f32e 100644 --- a/homeassistant/components/geofency/device_tracker.py +++ b/homeassistant/components/geofency/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for the Geofency device tracker platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.geofency/ -""" +"""Support for the Geofency device tracker platform.""" import logging from homeassistant.components.device_tracker import ( diff --git a/homeassistant/components/github/sensor.py b/homeassistant/components/github/sensor.py index 335dbc668d9..5a86233d561 100644 --- a/homeassistant/components/github/sensor.py +++ b/homeassistant/components/github/sensor.py @@ -1,9 +1,4 @@ -""" -Support for GitHub. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.github/ -""" +"""Support for GitHub.""" from datetime import timedelta import logging import voluptuous as vol diff --git a/homeassistant/components/gitlab_ci/sensor.py b/homeassistant/components/gitlab_ci/sensor.py index 7f3b444bb75..dd574b348d8 100644 --- a/homeassistant/components/gitlab_ci/sensor.py +++ b/homeassistant/components/gitlab_ci/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for retrieving latest GitLab CI job information. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.gitlab_ci/ -""" +"""Sensor for retrieving latest GitLab CI job information.""" from datetime import timedelta import logging diff --git a/homeassistant/components/gitter/sensor.py b/homeassistant/components/gitter/sensor.py index 97cd3f662d5..2af9c20fb29 100644 --- a/homeassistant/components/gitter/sensor.py +++ b/homeassistant/components/gitter/sensor.py @@ -1,9 +1,4 @@ -""" -Support for displaying details about a Gitter.im chat room. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.gitter/ -""" +"""Support for displaying details about a Gitter.im chat room.""" import logging import voluptuous as vol diff --git a/homeassistant/components/glances/sensor.py b/homeassistant/components/glances/sensor.py index 53db254e4b3..e59b9144b4c 100644 --- a/homeassistant/components/glances/sensor.py +++ b/homeassistant/components/glances/sensor.py @@ -1,9 +1,4 @@ -""" -Support gathering system information of hosts which are running glances. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.glances/ -""" +"""Support gathering system information of hosts which are running glances.""" from datetime import timedelta import logging diff --git a/homeassistant/components/gntp/notify.py b/homeassistant/components/gntp/notify.py index 915d33668b4..fb3e96e83ab 100644 --- a/homeassistant/components/gntp/notify.py +++ b/homeassistant/components/gntp/notify.py @@ -1,9 +1,4 @@ -""" -GNTP (aka Growl) notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.gntp/ -""" +"""GNTP (aka Growl) notification service.""" import logging import os diff --git a/homeassistant/components/gogogate2/cover.py b/homeassistant/components/gogogate2/cover.py index accc4f9ec98..4d40ddd2c72 100644 --- a/homeassistant/components/gogogate2/cover.py +++ b/homeassistant/components/gogogate2/cover.py @@ -1,9 +1,4 @@ -""" -Support for Gogogate2 garage Doors. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/cover.gogogate2/ -""" +"""Support for Gogogate2 garage Doors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/google_assistant/http.py b/homeassistant/components/google_assistant/http.py index cbe2015f4f9..11d8a384165 100644 --- a/homeassistant/components/google_assistant/http.py +++ b/homeassistant/components/google_assistant/http.py @@ -1,9 +1,4 @@ -""" -Support for Google Actions Smart Home Control. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/google_assistant/ -""" +"""Support for Google Actions Smart Home Control.""" import logging from aiohttp.web import Request, Response diff --git a/homeassistant/components/google_maps/device_tracker.py b/homeassistant/components/google_maps/device_tracker.py index 3de60d6cb38..7bc9be00b8c 100644 --- a/homeassistant/components/google_maps/device_tracker.py +++ b/homeassistant/components/google_maps/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Google Maps location sharing. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.google_maps/ -""" +"""Support for Google Maps location sharing.""" from datetime import timedelta import logging diff --git a/homeassistant/components/google_travel_time/sensor.py b/homeassistant/components/google_travel_time/sensor.py index 86b1a7aff44..b448830ab02 100644 --- a/homeassistant/components/google_travel_time/sensor.py +++ b/homeassistant/components/google_travel_time/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Google travel time sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.google_travel_time/ -""" +"""Support for Google travel time sensors.""" import logging from datetime import datetime from datetime import timedelta diff --git a/homeassistant/components/google_wifi/sensor.py b/homeassistant/components/google_wifi/sensor.py index b78e9afb8b9..202e2a0eb46 100644 --- a/homeassistant/components/google_wifi/sensor.py +++ b/homeassistant/components/google_wifi/sensor.py @@ -1,9 +1,4 @@ -""" -Support for retrieving status info from Google Wifi/OnHub routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.google_wifi/ -""" +"""Support for retrieving status info from Google Wifi/OnHub routers.""" import logging from datetime import timedelta diff --git a/homeassistant/components/gpmdp/media_player.py b/homeassistant/components/gpmdp/media_player.py index c72d14ebb8a..788126b957f 100644 --- a/homeassistant/components/gpmdp/media_player.py +++ b/homeassistant/components/gpmdp/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Google Play Music Desktop Player. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.gpmdp/ -""" +"""Support for Google Play Music Desktop Player.""" import json import logging import socket diff --git a/homeassistant/components/gpsd/sensor.py b/homeassistant/components/gpsd/sensor.py index b1ce428e1f2..62307cb1011 100644 --- a/homeassistant/components/gpsd/sensor.py +++ b/homeassistant/components/gpsd/sensor.py @@ -1,9 +1,4 @@ -""" -Support for GPSD. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.gpsd/ -""" +"""Support for GPSD.""" import logging import voluptuous as vol diff --git a/homeassistant/components/greeneye_monitor/sensor.py b/homeassistant/components/greeneye_monitor/sensor.py index 4dee9d69b42..8321bb768ca 100644 --- a/homeassistant/components/greeneye_monitor/sensor.py +++ b/homeassistant/components/greeneye_monitor/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the sensors in a GreenEye Monitor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensors.greeneye_monitor_temperature/ -""" +"""Support for the sensors in a GreenEye Monitor.""" import logging from homeassistant.const import CONF_NAME, CONF_TEMPERATURE_UNIT, POWER_WATT diff --git a/homeassistant/components/greenwave/light.py b/homeassistant/components/greenwave/light.py index 0c484a0e3f4..b8efe8ae17d 100644 --- a/homeassistant/components/greenwave/light.py +++ b/homeassistant/components/greenwave/light.py @@ -1,9 +1,4 @@ -""" -Support for Greenwave Reality (TCP Connected) lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.greenwave/ -""" +"""Support for Greenwave Reality (TCP Connected) lights.""" import logging from datetime import timedelta diff --git a/homeassistant/components/group/cover.py b/homeassistant/components/group/cover.py index c1825211433..385d20949d6 100644 --- a/homeassistant/components/group/cover.py +++ b/homeassistant/components/group/cover.py @@ -1,9 +1,4 @@ -""" -This platform allows several cover to be grouped into one cover. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/cover.group/ -""" +"""This platform allows several cover to be grouped into one cover.""" import logging import voluptuous as vol diff --git a/homeassistant/components/group/light.py b/homeassistant/components/group/light.py index c37c5cc4e8e..170e93398a1 100644 --- a/homeassistant/components/group/light.py +++ b/homeassistant/components/group/light.py @@ -1,9 +1,4 @@ -""" -This platform allows several lights to be grouped into one light. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.group/ -""" +"""This platform allows several lights to be grouped into one light.""" from collections import Counter import itertools import logging diff --git a/homeassistant/components/group/notify.py b/homeassistant/components/group/notify.py index 200464bb8cb..b59c49563e2 100644 --- a/homeassistant/components/group/notify.py +++ b/homeassistant/components/group/notify.py @@ -1,9 +1,4 @@ -""" -Group platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.group/ -""" +"""Group platform for notify component.""" import asyncio from collections.abc import Mapping from copy import deepcopy diff --git a/homeassistant/components/gstreamer/media_player.py b/homeassistant/components/gstreamer/media_player.py index c6571894472..094a561d310 100644 --- a/homeassistant/components/gstreamer/media_player.py +++ b/homeassistant/components/gstreamer/media_player.py @@ -1,9 +1,4 @@ -""" -Play media via gstreamer. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.gstreamer/ -""" +"""Play media via gstreamer.""" import logging import voluptuous as vol diff --git a/homeassistant/components/gtfs/sensor.py b/homeassistant/components/gtfs/sensor.py index c94f97d93dc..9e89a8ad844 100644 --- a/homeassistant/components/gtfs/sensor.py +++ b/homeassistant/components/gtfs/sensor.py @@ -1,9 +1,4 @@ -""" -Support for GTFS (Google/General Transport Format Schema). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.gtfs/ -""" +"""Support for GTFS (Google/General Transport Format Schema).""" import datetime import logging import os diff --git a/homeassistant/components/gtt/sensor.py b/homeassistant/components/gtt/sensor.py index a64c743381d..659984fadea 100644 --- a/homeassistant/components/gtt/sensor.py +++ b/homeassistant/components/gtt/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor to get GTT's timetable for a stop. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.gtt/ -""" +"""Sensor to get GTT's timetable for a stop.""" import logging from datetime import timedelta, datetime diff --git a/homeassistant/components/harman_kardon_avr/media_player.py b/homeassistant/components/harman_kardon_avr/media_player.py index 334757c086d..cec0ac4f5c8 100644 --- a/homeassistant/components/harman_kardon_avr/media_player.py +++ b/homeassistant/components/harman_kardon_avr/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interface with an Harman/Kardon or JBL AVR. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.harman_kardon_avr/ -""" +"""Support for interface with an Harman/Kardon or JBL AVR.""" import logging import voluptuous as vol diff --git a/homeassistant/components/haveibeenpwned/sensor.py b/homeassistant/components/haveibeenpwned/sensor.py index a4ae2349e24..72cc5ced3ef 100644 --- a/homeassistant/components/haveibeenpwned/sensor.py +++ b/homeassistant/components/haveibeenpwned/sensor.py @@ -1,9 +1,4 @@ -""" -Support for haveibeenpwned (email breaches) sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.haveibeenpwned/ -""" +"""Support for haveibeenpwned (email breaches) sensor.""" from datetime import timedelta import logging diff --git a/homeassistant/components/hddtemp/sensor.py b/homeassistant/components/hddtemp/sensor.py index 52514a2de39..6d96f244f58 100644 --- a/homeassistant/components/hddtemp/sensor.py +++ b/homeassistant/components/hddtemp/sensor.py @@ -1,9 +1,4 @@ -""" -Support for getting the disk temperature of a host. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.hddtemp/ -""" +"""Support for getting the disk temperature of a host.""" import logging from datetime import timedelta from telnetlib import Telnet diff --git a/homeassistant/components/heatmiser/climate.py b/homeassistant/components/heatmiser/climate.py index ff495706be7..fc9057bc905 100644 --- a/homeassistant/components/heatmiser/climate.py +++ b/homeassistant/components/heatmiser/climate.py @@ -1,9 +1,4 @@ -""" -Support for the PRT Heatmiser themostats using the V3 protocol. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.heatmiser/ -""" +"""Support for the PRT Heatmiser themostats using the V3 protocol.""" import logging import voluptuous as vol diff --git a/homeassistant/components/hikvision/binary_sensor.py b/homeassistant/components/hikvision/binary_sensor.py index fdefc40d8fd..a6a82c9ee1b 100644 --- a/homeassistant/components/hikvision/binary_sensor.py +++ b/homeassistant/components/hikvision/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for Hikvision event stream events represented as binary sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.hikvision/ -""" +"""Support for Hikvision event stream events represented as binary sensors.""" import logging from datetime import timedelta import voluptuous as vol diff --git a/homeassistant/components/hikvisioncam/switch.py b/homeassistant/components/hikvisioncam/switch.py index 3a3dec26e1d..6e5dcdac9aa 100644 --- a/homeassistant/components/hikvisioncam/switch.py +++ b/homeassistant/components/hikvisioncam/switch.py @@ -1,9 +1,4 @@ -""" -Support turning on/off motion detection on Hikvision cameras. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.hikvision/ -""" +"""Support turning on/off motion detection on Hikvision cameras.""" import logging import voluptuous as vol diff --git a/homeassistant/components/hipchat/notify.py b/homeassistant/components/hipchat/notify.py index 9e415171f29..5128b8beea3 100644 --- a/homeassistant/components/hipchat/notify.py +++ b/homeassistant/components/hipchat/notify.py @@ -1,9 +1,4 @@ -""" -HipChat platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.hipchat/ -""" +"""HipChat platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/history_stats/sensor.py b/homeassistant/components/history_stats/sensor.py index f5b76c89aba..f1eea4dd693 100644 --- a/homeassistant/components/history_stats/sensor.py +++ b/homeassistant/components/history_stats/sensor.py @@ -1,9 +1,4 @@ -""" -Component to make instant statistics about your history. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.history_stats/ -""" +"""Component to make instant statistics about your history.""" import datetime import logging import math diff --git a/homeassistant/components/hitron_coda/device_tracker.py b/homeassistant/components/hitron_coda/device_tracker.py index 72817ca695c..e6f68d704fd 100644 --- a/homeassistant/components/hitron_coda/device_tracker.py +++ b/homeassistant/components/hitron_coda/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for the Hitron CODA-4582U, provided by Rogers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.hitron_coda/ -""" +"""Support for the Hitron CODA-4582U, provided by Rogers.""" import logging from collections import namedtuple diff --git a/homeassistant/components/homematic/notify.py b/homeassistant/components/homematic/notify.py index 021560eee3c..9054c1fa0ad 100644 --- a/homeassistant/components/homematic/notify.py +++ b/homeassistant/components/homematic/notify.py @@ -1,9 +1,4 @@ -""" -Notification support for Homematic. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.homematic/ -""" +"""Notification support for Homematic.""" import logging import voluptuous as vol diff --git a/homeassistant/components/honeywell/climate.py b/homeassistant/components/honeywell/climate.py index 55a7fb5aa48..7460ed6e9d0 100644 --- a/homeassistant/components/honeywell/climate.py +++ b/homeassistant/components/honeywell/climate.py @@ -1,9 +1,4 @@ -""" -Support for Honeywell Round Connected and Honeywell Evohome thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.honeywell/ -""" +"""Support for Honeywell Round Connected and Honeywell Evohome thermostats.""" import logging import datetime diff --git a/homeassistant/components/hook/switch.py b/homeassistant/components/hook/switch.py index fdc13f59d28..7a11c1dd8b7 100644 --- a/homeassistant/components/hook/switch.py +++ b/homeassistant/components/hook/switch.py @@ -1,9 +1,4 @@ -""" -Support Hook, available at hooksmarthome.com. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.hook/ -""" +"""Support Hook, available at hooksmarthome.com.""" import logging import asyncio diff --git a/homeassistant/components/horizon/media_player.py b/homeassistant/components/horizon/media_player.py index 3b1ae36152d..51168e4ef2e 100644 --- a/homeassistant/components/horizon/media_player.py +++ b/homeassistant/components/horizon/media_player.py @@ -1,9 +1,4 @@ -""" -Support for the Unitymedia Horizon HD Recorder. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/media_player.horizon/ -""" +"""Support for the Unitymedia Horizon HD Recorder.""" from datetime import timedelta import logging diff --git a/homeassistant/components/html5/notify.py b/homeassistant/components/html5/notify.py index 8744d0afb28..f7b220ff138 100644 --- a/homeassistant/components/html5/notify.py +++ b/homeassistant/components/html5/notify.py @@ -1,9 +1,4 @@ -""" -HTML5 Push Messaging notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.html5/ -""" +"""HTML5 Push Messaging notification service.""" import datetime from functools import partial import json diff --git a/homeassistant/components/htu21d/sensor.py b/homeassistant/components/htu21d/sensor.py index 4f8665b2011..17182bb833d 100644 --- a/homeassistant/components/htu21d/sensor.py +++ b/homeassistant/components/htu21d/sensor.py @@ -1,9 +1,4 @@ -""" -Support for HTU21D temperature and humidity sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.htu21d/ -""" +"""Support for HTU21D temperature and humidity sensor.""" from datetime import timedelta from functools import partial import logging diff --git a/homeassistant/components/huawei_router/device_tracker.py b/homeassistant/components/huawei_router/device_tracker.py index 18f3c0b8c62..88e2a57a579 100644 --- a/homeassistant/components/huawei_router/device_tracker.py +++ b/homeassistant/components/huawei_router/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for HUAWEI routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.huawei_router/ -""" +"""Support for HUAWEI routers.""" import base64 import logging import re diff --git a/homeassistant/components/ialarm/alarm_control_panel.py b/homeassistant/components/ialarm/alarm_control_panel.py index df975ef00ac..8152c2496e6 100644 --- a/homeassistant/components/ialarm/alarm_control_panel.py +++ b/homeassistant/components/ialarm/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Interfaces with iAlarm control panels. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.ialarm/ -""" +"""Interfaces with iAlarm control panels.""" import logging import re diff --git a/homeassistant/components/icloud/device_tracker.py b/homeassistant/components/icloud/device_tracker.py index 9ac77cf7f01..1d0e0d2fafb 100644 --- a/homeassistant/components/icloud/device_tracker.py +++ b/homeassistant/components/icloud/device_tracker.py @@ -1,9 +1,4 @@ -""" -Platform that supports scanning iCloud. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.icloud/ -""" +"""Platform that supports scanning iCloud.""" import logging import random import os diff --git a/homeassistant/components/iglo/light.py b/homeassistant/components/iglo/light.py index 9dca5f8e5f5..6851141efb4 100644 --- a/homeassistant/components/iglo/light.py +++ b/homeassistant/components/iglo/light.py @@ -1,9 +1,4 @@ -""" -Support for lights under the iGlo brand. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.iglo/ -""" +"""Support for lights under the iGlo brand.""" import logging import math diff --git a/homeassistant/components/image_processing/__init__.py b/homeassistant/components/image_processing/__init__.py index aa3b2db7369..e5193985629 100644 --- a/homeassistant/components/image_processing/__init__.py +++ b/homeassistant/components/image_processing/__init__.py @@ -1,9 +1,4 @@ -""" -Provides functionality to interact with image processing services. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/image_processing/ -""" +"""Provides functionality to interact with image processing services.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/imap/sensor.py b/homeassistant/components/imap/sensor.py index 571d05e78e9..5ff23eb8e5d 100644 --- a/homeassistant/components/imap/sensor.py +++ b/homeassistant/components/imap/sensor.py @@ -1,9 +1,4 @@ -""" -IMAP sensor support. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.imap/ -""" +"""IMAP sensor support.""" import asyncio import logging diff --git a/homeassistant/components/imap_email_content/sensor.py b/homeassistant/components/imap_email_content/sensor.py index 714a6c38781..950007b462b 100644 --- a/homeassistant/components/imap_email_content/sensor.py +++ b/homeassistant/components/imap_email_content/sensor.py @@ -1,9 +1,4 @@ -""" -Email sensor support. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.imap_email_content/ -""" +"""Email sensor support.""" import logging import datetime import email diff --git a/homeassistant/components/influxdb/sensor.py b/homeassistant/components/influxdb/sensor.py index 9dbb4787df7..3bec7e3c657 100644 --- a/homeassistant/components/influxdb/sensor.py +++ b/homeassistant/components/influxdb/sensor.py @@ -1,9 +1,4 @@ -""" -InfluxDB component which allows you to get data from an Influx database. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.influxdb/ -""" +"""InfluxDB component which allows you to get data from an Influx database.""" from datetime import timedelta import logging diff --git a/homeassistant/components/integration/sensor.py b/homeassistant/components/integration/sensor.py index 9250c8dde05..3a72c81fa11 100644 --- a/homeassistant/components/integration/sensor.py +++ b/homeassistant/components/integration/sensor.py @@ -1,9 +1,4 @@ -""" -Numeric integration of data coming from a source sensor over time. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.integration/ -""" +"""Numeric integration of data coming from a source sensor over time.""" import logging from decimal import Decimal, DecimalException diff --git a/homeassistant/components/islamic_prayer_times/sensor.py b/homeassistant/components/islamic_prayer_times/sensor.py index 50331435491..9efbc237e30 100644 --- a/homeassistant/components/islamic_prayer_times/sensor.py +++ b/homeassistant/components/islamic_prayer_times/sensor.py @@ -1,9 +1,4 @@ -""" -Platform to retrieve Islamic prayer times information for Home Assistant. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.islamic_prayer_times/ -""" +"""Platform to retrieve Islamic prayer times information for Home Assistant.""" import logging from datetime import datetime, timedelta diff --git a/homeassistant/components/iss/binary_sensor.py b/homeassistant/components/iss/binary_sensor.py index b986c51ddaa..381bc167918 100644 --- a/homeassistant/components/iss/binary_sensor.py +++ b/homeassistant/components/iss/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for International Space Station data sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.iss/ -""" +"""Support for International Space Station data sensor.""" import logging from datetime import timedelta diff --git a/homeassistant/components/itunes/media_player.py b/homeassistant/components/itunes/media_player.py index f8380032aea..8451d751954 100644 --- a/homeassistant/components/itunes/media_player.py +++ b/homeassistant/components/itunes/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interfacing to iTunes API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.itunes/ -""" +"""Support for interfacing to iTunes API.""" import logging import requests diff --git a/homeassistant/components/jewish_calendar/sensor.py b/homeassistant/components/jewish_calendar/sensor.py index 65aeaf7fba9..478bbed98fa 100644 --- a/homeassistant/components/jewish_calendar/sensor.py +++ b/homeassistant/components/jewish_calendar/sensor.py @@ -1,9 +1,4 @@ -""" -Platform to retrieve Jewish calendar information for Home Assistant. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.jewish_calendar/ -""" +"""Platform to retrieve Jewish calendar information for Home Assistant.""" import logging import voluptuous as vol diff --git a/homeassistant/components/kankun/switch.py b/homeassistant/components/kankun/switch.py index 86e7fcdab3e..a8282a366ad 100644 --- a/homeassistant/components/kankun/switch.py +++ b/homeassistant/components/kankun/switch.py @@ -1,9 +1,4 @@ -""" -Support for customised Kankun SP3 Wifi switch. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.kankun/ -""" +"""Support for customised Kankun SP3 Wifi switch.""" import logging import requests diff --git a/homeassistant/components/keenetic_ndms2/device_tracker.py b/homeassistant/components/keenetic_ndms2/device_tracker.py index b8c2124ff0f..f873507112d 100644 --- a/homeassistant/components/keenetic_ndms2/device_tracker.py +++ b/homeassistant/components/keenetic_ndms2/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Zyxel Keenetic NDMS2 based routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.keenetic_ndms2/ -""" +"""Support for Zyxel Keenetic NDMS2 based routers.""" import logging import voluptuous as vol diff --git a/homeassistant/components/kiwi/lock.py b/homeassistant/components/kiwi/lock.py index 5d217796767..0b5806425d9 100644 --- a/homeassistant/components/kiwi/lock.py +++ b/homeassistant/components/kiwi/lock.py @@ -1,9 +1,4 @@ -""" -Support for the KIWI.KI lock platform. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/lock.kiwi/ -""" +"""Support for the KIWI.KI lock platform.""" import logging import voluptuous as vol diff --git a/homeassistant/components/kodi/media_player.py b/homeassistant/components/kodi/media_player.py index f8d0cdc5a12..81c93dba2ac 100644 --- a/homeassistant/components/kodi/media_player.py +++ b/homeassistant/components/kodi/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interfacing with the XBMC/Kodi JSON-RPC API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.kodi/ -""" +"""Support for interfacing with the XBMC/Kodi JSON-RPC API.""" import asyncio from collections import OrderedDict from functools import wraps diff --git a/homeassistant/components/kodi/notify.py b/homeassistant/components/kodi/notify.py index 7c2a60f3498..f6ee2c47b96 100644 --- a/homeassistant/components/kodi/notify.py +++ b/homeassistant/components/kodi/notify.py @@ -1,9 +1,4 @@ -""" -Kodi notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.kodi/ -""" +"""Kodi notification service.""" import logging import aiohttp diff --git a/homeassistant/components/kwb/sensor.py b/homeassistant/components/kwb/sensor.py index f490fbd5b14..bad0ea3cded 100644 --- a/homeassistant/components/kwb/sensor.py +++ b/homeassistant/components/kwb/sensor.py @@ -1,9 +1,4 @@ -""" -Support for KWB Easyfire. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.kwb/ -""" +"""Support for KWB Easyfire.""" import logging import voluptuous as vol diff --git a/homeassistant/components/lacrosse/sensor.py b/homeassistant/components/lacrosse/sensor.py index 32b1dac9250..9240343a5e3 100644 --- a/homeassistant/components/lacrosse/sensor.py +++ b/homeassistant/components/lacrosse/sensor.py @@ -1,9 +1,4 @@ -""" -Support for LaCrosse sensor components. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.lacrosse/ -""" +"""Support for LaCrosse sensor components.""" from datetime import timedelta import logging diff --git a/homeassistant/components/lannouncer/notify.py b/homeassistant/components/lannouncer/notify.py index 3b2e72b398c..535940a80f5 100644 --- a/homeassistant/components/lannouncer/notify.py +++ b/homeassistant/components/lannouncer/notify.py @@ -1,9 +1,4 @@ -""" -Lannouncer platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.lannouncer/ -""" +"""Lannouncer platform for notify component.""" import logging import socket from urllib.parse import urlencode diff --git a/homeassistant/components/launch_library/sensor.py b/homeassistant/components/launch_library/sensor.py index aaed2f9663f..4b42ddba268 100644 --- a/homeassistant/components/launch_library/sensor.py +++ b/homeassistant/components/launch_library/sensor.py @@ -1,9 +1,4 @@ -""" -A sensor platform that give you information about the next space launch. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/sensor.launch_library/ -""" +"""A sensor platform that give you information about the next space launch.""" from datetime import timedelta import logging diff --git a/homeassistant/components/lg_netcast/media_player.py b/homeassistant/components/lg_netcast/media_player.py index 7c5d9789372..12fee5fae96 100644 --- a/homeassistant/components/lg_netcast/media_player.py +++ b/homeassistant/components/lg_netcast/media_player.py @@ -1,9 +1,4 @@ -""" -Support for LG TV running on NetCast 3 or 4. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.lg_netcast/ -""" +"""Support for LG TV running on NetCast 3 or 4.""" from datetime import timedelta import logging diff --git a/homeassistant/components/lg_soundbar/media_player.py b/homeassistant/components/lg_soundbar/media_player.py index b45baf88bca..2e2481a462b 100644 --- a/homeassistant/components/lg_soundbar/media_player.py +++ b/homeassistant/components/lg_soundbar/media_player.py @@ -1,9 +1,4 @@ -""" -Support for LG soundbars. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.lg_soundbar/ -""" +"""Support for LG soundbars.""" import logging from homeassistant.components.media_player import ( diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index e3971cd8e42..db2e9ce0197 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -1,9 +1,4 @@ -""" -Provides functionality to interact with lights. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/light/ -""" +"""Provides functionality to interact with lights.""" import asyncio import csv from datetime import timedelta diff --git a/homeassistant/components/limitlessled/light.py b/homeassistant/components/limitlessled/light.py index 3a0225d8d65..4f187afa1d7 100644 --- a/homeassistant/components/limitlessled/light.py +++ b/homeassistant/components/limitlessled/light.py @@ -1,9 +1,4 @@ -""" -Support for LimitlessLED bulbs. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.limitlessled/ -""" +"""Support for LimitlessLED bulbs.""" import logging import voluptuous as vol diff --git a/homeassistant/components/linksys_ap/device_tracker.py b/homeassistant/components/linksys_ap/device_tracker.py index 5638db4caaf..46cc78d4e4a 100644 --- a/homeassistant/components/linksys_ap/device_tracker.py +++ b/homeassistant/components/linksys_ap/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Linksys Access Points. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.linksys_ap/ -""" +"""Support for Linksys Access Points.""" import base64 import logging diff --git a/homeassistant/components/linky/sensor.py b/homeassistant/components/linky/sensor.py index 7a10513016f..35f85f15ed6 100644 --- a/homeassistant/components/linky/sensor.py +++ b/homeassistant/components/linky/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Linky. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.linky/ -""" +"""Support for Linky.""" import logging import json from datetime import timedelta diff --git a/homeassistant/components/linux_battery/sensor.py b/homeassistant/components/linux_battery/sensor.py index 69fc145a4a5..7164315de8e 100644 --- a/homeassistant/components/linux_battery/sensor.py +++ b/homeassistant/components/linux_battery/sensor.py @@ -1,9 +1,4 @@ -""" -Details about the built-in battery. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.linux_battery/ -""" +"""Details about the built-in battery.""" import logging import os diff --git a/homeassistant/components/litejet/light.py b/homeassistant/components/litejet/light.py index 8662afc668e..e52e50ed21a 100644 --- a/homeassistant/components/litejet/light.py +++ b/homeassistant/components/litejet/light.py @@ -1,9 +1,4 @@ -""" -Support for LiteJet lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.litejet/ -""" +"""Support for LiteJet lights.""" import logging from homeassistant.components import litejet diff --git a/homeassistant/components/litejet/switch.py b/homeassistant/components/litejet/switch.py index b9755569fd2..9972dcb9f44 100644 --- a/homeassistant/components/litejet/switch.py +++ b/homeassistant/components/litejet/switch.py @@ -1,9 +1,4 @@ -""" -Support for LiteJet switch. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.litejet/ -""" +"""Support for LiteJet switch.""" import logging from homeassistant.components import litejet diff --git a/homeassistant/components/liveboxplaytv/media_player.py b/homeassistant/components/liveboxplaytv/media_player.py index f69c3c67aec..1ee9931d233 100644 --- a/homeassistant/components/liveboxplaytv/media_player.py +++ b/homeassistant/components/liveboxplaytv/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interface with an Orange Livebox Play TV appliance. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.liveboxplaytv/ -""" +"""Support for interface with an Orange Livebox Play TV appliance.""" from datetime import timedelta import logging diff --git a/homeassistant/components/llamalab_automate/notify.py b/homeassistant/components/llamalab_automate/notify.py index 6b59d11e0a3..d43988ada43 100644 --- a/homeassistant/components/llamalab_automate/notify.py +++ b/homeassistant/components/llamalab_automate/notify.py @@ -1,9 +1,4 @@ -""" -LlamaLab Automate notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.llamalab_automate/ -""" +"""LlamaLab Automate notification service.""" import logging import requests diff --git a/homeassistant/components/local_file/camera.py b/homeassistant/components/local_file/camera.py index 56780d16f56..444f4109e98 100644 --- a/homeassistant/components/local_file/camera.py +++ b/homeassistant/components/local_file/camera.py @@ -1,9 +1,4 @@ -""" -Camera that loads a picture from a local file. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.local_file/ -""" +"""Camera that loads a picture from a local file.""" import logging import mimetypes import os diff --git a/homeassistant/components/locative/device_tracker.py b/homeassistant/components/locative/device_tracker.py index 9dbf7e74fe3..51135f4e21a 100644 --- a/homeassistant/components/locative/device_tracker.py +++ b/homeassistant/components/locative/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for the Locative platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.locative/ -""" +"""Support for the Locative platform.""" import logging from homeassistant.components.device_tracker import ( diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index 71c838679fb..fe5286ba813 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -1,9 +1,4 @@ -""" -Component to interface with various locks that can be controlled remotely. - -For more details about this component, please refer to the documentation -at https://home-assistant.io/components/lock/ -""" +"""Component to interface with locks that can be controlled remotely.""" from datetime import timedelta import functools as ft import logging diff --git a/homeassistant/components/lockitron/lock.py b/homeassistant/components/lockitron/lock.py index b190a5cd2cd..0ec838f4d4b 100644 --- a/homeassistant/components/lockitron/lock.py +++ b/homeassistant/components/lockitron/lock.py @@ -1,9 +1,4 @@ -""" -Lockitron lock platform. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/lockitron/ -""" +"""Lockitron lock platform.""" import logging import requests diff --git a/homeassistant/components/london_air/sensor.py b/homeassistant/components/london_air/sensor.py index afb50d766f4..fbdc8966ad0 100644 --- a/homeassistant/components/london_air/sensor.py +++ b/homeassistant/components/london_air/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for checking the status of London air. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.london_air/ -""" +"""Sensor for checking the status of London air.""" from datetime import timedelta import logging diff --git a/homeassistant/components/london_underground/sensor.py b/homeassistant/components/london_underground/sensor.py index 1c93d6a1bcb..948b60b1b79 100644 --- a/homeassistant/components/london_underground/sensor.py +++ b/homeassistant/components/london_underground/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for checking the status of London Underground tube lines. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.london_underground/ -""" +"""Sensor for checking the status of London Underground tube lines.""" import logging from datetime import timedelta diff --git a/homeassistant/components/loopenergy/sensor.py b/homeassistant/components/loopenergy/sensor.py index fefba2972f2..23bdf48f645 100644 --- a/homeassistant/components/loopenergy/sensor.py +++ b/homeassistant/components/loopenergy/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Loop Energy sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.loopenergy/ -""" +"""Support for Loop Energy sensors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/luci/device_tracker.py b/homeassistant/components/luci/device_tracker.py index f60e8edd8c4..df65ed99f29 100644 --- a/homeassistant/components/luci/device_tracker.py +++ b/homeassistant/components/luci/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for OpenWRT (luci) routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.luci/ -""" +"""Support for OpenWRT (luci) routers.""" import logging import voluptuous as vol diff --git a/homeassistant/components/lw12wifi/light.py b/homeassistant/components/lw12wifi/light.py index 71716b4130d..5d9b7635ad2 100644 --- a/homeassistant/components/lw12wifi/light.py +++ b/homeassistant/components/lw12wifi/light.py @@ -1,9 +1,4 @@ -""" -Support for Lagute LW-12 WiFi LED Controller. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.lw12wifi/ -""" +"""Support for Lagute LW-12 WiFi LED Controller.""" import logging diff --git a/homeassistant/components/lyft/sensor.py b/homeassistant/components/lyft/sensor.py index 6fb4a6bf8be..98d79cd970b 100644 --- a/homeassistant/components/lyft/sensor.py +++ b/homeassistant/components/lyft/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Lyft API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.lyft/ -""" +"""Support for the Lyft API.""" import logging from datetime import timedelta diff --git a/homeassistant/components/magicseaweed/sensor.py b/homeassistant/components/magicseaweed/sensor.py index 0500597b96a..4c09d1e09e0 100644 --- a/homeassistant/components/magicseaweed/sensor.py +++ b/homeassistant/components/magicseaweed/sensor.py @@ -1,9 +1,4 @@ -""" -Support for magicseaweed data from magicseaweed.com. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.magicseaweed/ -""" +"""Support for magicseaweed data from magicseaweed.com.""" from datetime import timedelta import logging import voluptuous as vol diff --git a/homeassistant/components/manual/alarm_control_panel.py b/homeassistant/components/manual/alarm_control_panel.py index a36a38f596f..14934db41c2 100644 --- a/homeassistant/components/manual/alarm_control_panel.py +++ b/homeassistant/components/manual/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Support for manual alarms. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.manual/ -""" +"""Support for manual alarms.""" import copy import datetime import logging diff --git a/homeassistant/components/manual_mqtt/alarm_control_panel.py b/homeassistant/components/manual_mqtt/alarm_control_panel.py index 9bee2b81d61..8057a899347 100644 --- a/homeassistant/components/manual_mqtt/alarm_control_panel.py +++ b/homeassistant/components/manual_mqtt/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Support for manual alarms controllable via MQTT. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.manual_mqtt/ -""" +"""Support for manual alarms controllable via MQTT.""" import copy import datetime import logging diff --git a/homeassistant/components/marytts/tts.py b/homeassistant/components/marytts/tts.py index f5d19c977a4..294383cb4dd 100644 --- a/homeassistant/components/marytts/tts.py +++ b/homeassistant/components/marytts/tts.py @@ -1,9 +1,4 @@ -""" -Support for the MaryTTS service. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/tts.marytts/ -""" +"""Support for the MaryTTS service.""" import asyncio import logging import re diff --git a/homeassistant/components/mastodon/notify.py b/homeassistant/components/mastodon/notify.py index 6192f6cdca5..c1a91b8312e 100644 --- a/homeassistant/components/mastodon/notify.py +++ b/homeassistant/components/mastodon/notify.py @@ -1,9 +1,4 @@ -""" -Mastodon platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.mastodon/ -""" +"""Mastodon platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index ad29a645765..3421551320e 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -1,9 +1,4 @@ -""" -Component to interface with various media players. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/media_player/ -""" +"""Component to interface with various media players.""" import asyncio import base64 import collections diff --git a/homeassistant/components/mediaroom/media_player.py b/homeassistant/components/mediaroom/media_player.py index 29cc7332936..acbc0462722 100644 --- a/homeassistant/components/mediaroom/media_player.py +++ b/homeassistant/components/mediaroom/media_player.py @@ -1,9 +1,4 @@ -""" -Support for the Mediaroom Set-up-box. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.mediaroom/ -""" +"""Support for the Mediaroom Set-up-box.""" import logging import voluptuous as vol diff --git a/homeassistant/components/melissa/climate.py b/homeassistant/components/melissa/climate.py index 0df294a148d..79d94a41991 100644 --- a/homeassistant/components/melissa/climate.py +++ b/homeassistant/components/melissa/climate.py @@ -1,9 +1,4 @@ -""" -Support for Melissa Climate A/C. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/climate.melissa/ -""" +"""Support for Melissa Climate A/C.""" import logging from homeassistant.components.climate import ClimateDevice diff --git a/homeassistant/components/message_bird/notify.py b/homeassistant/components/message_bird/notify.py index cfb22ff1d52..c801de34a9a 100644 --- a/homeassistant/components/message_bird/notify.py +++ b/homeassistant/components/message_bird/notify.py @@ -1,9 +1,4 @@ -""" -MessageBird platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.message_bird/ -""" +"""MessageBird platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/metoffice/sensor.py b/homeassistant/components/metoffice/sensor.py index 3d9c9485da3..6c4e91517da 100644 --- a/homeassistant/components/metoffice/sensor.py +++ b/homeassistant/components/metoffice/sensor.py @@ -1,9 +1,4 @@ -""" -Support for UK Met Office weather service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.metoffice/ -""" +"""Support for UK Met Office weather service.""" from datetime import timedelta import logging diff --git a/homeassistant/components/mfi/sensor.py b/homeassistant/components/mfi/sensor.py index 44e5dbda84f..36f9d1a829c 100644 --- a/homeassistant/components/mfi/sensor.py +++ b/homeassistant/components/mfi/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Ubiquiti mFi sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.mfi/ -""" +"""Support for Ubiquiti mFi sensors.""" import logging import requests diff --git a/homeassistant/components/mfi/switch.py b/homeassistant/components/mfi/switch.py index 521230ccbd5..818081f7a2e 100644 --- a/homeassistant/components/mfi/switch.py +++ b/homeassistant/components/mfi/switch.py @@ -1,9 +1,4 @@ -""" -Support for Ubiquiti mFi switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.mfi/ -""" +"""Support for Ubiquiti mFi switches.""" import logging import requests diff --git a/homeassistant/components/mhz19/sensor.py b/homeassistant/components/mhz19/sensor.py index dd8a0395088..3aa82950fa7 100644 --- a/homeassistant/components/mhz19/sensor.py +++ b/homeassistant/components/mhz19/sensor.py @@ -1,9 +1,4 @@ -""" -Support for CO2 sensor connected to a serial port. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.mhz19/ -""" +"""Support for CO2 sensor connected to a serial port.""" import logging from datetime import timedelta diff --git a/homeassistant/components/microsoft/tts.py b/homeassistant/components/microsoft/tts.py index 55cf7a4ae7a..9fe31ef495e 100644 --- a/homeassistant/components/microsoft/tts.py +++ b/homeassistant/components/microsoft/tts.py @@ -1,9 +1,4 @@ -""" -Support for the Microsoft Cognitive Services text-to-speech service. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/tts.microsoft/ -""" +"""Support for the Microsoft Cognitive Services text-to-speech service.""" from http.client import HTTPException import logging diff --git a/homeassistant/components/microsoft_face_detect/image_processing.py b/homeassistant/components/microsoft_face_detect/image_processing.py index ae6b9c260cd..91eae07e992 100644 --- a/homeassistant/components/microsoft_face_detect/image_processing.py +++ b/homeassistant/components/microsoft_face_detect/image_processing.py @@ -1,9 +1,4 @@ -""" -Component that will help set the Microsoft face detect processing. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/image_processing.microsoft_face_detect/ -""" +"""Component that will help set the Microsoft face detect processing.""" import logging import voluptuous as vol diff --git a/homeassistant/components/microsoft_face_identify/image_processing.py b/homeassistant/components/microsoft_face_identify/image_processing.py index 7a427d9b046..52baa3617e8 100644 --- a/homeassistant/components/microsoft_face_identify/image_processing.py +++ b/homeassistant/components/microsoft_face_identify/image_processing.py @@ -1,9 +1,4 @@ -""" -Component that will help set the Microsoft face for verify processing. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/image_processing.microsoft_face_identify/ -""" +"""Component that will help set the Microsoft face for verify processing.""" import logging import voluptuous as vol diff --git a/homeassistant/components/miflora/sensor.py b/homeassistant/components/miflora/sensor.py index 91f873f5a2d..04595b0daeb 100644 --- a/homeassistant/components/miflora/sensor.py +++ b/homeassistant/components/miflora/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Xiaomi Mi Flora BLE plant sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.miflora/ -""" +"""Support for Xiaomi Mi Flora BLE plant sensor.""" from datetime import timedelta import logging import voluptuous as vol diff --git a/homeassistant/components/mikrotik/device_tracker.py b/homeassistant/components/mikrotik/device_tracker.py index c4635f8dc43..ed0734588ef 100644 --- a/homeassistant/components/mikrotik/device_tracker.py +++ b/homeassistant/components/mikrotik/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Mikrotik routers as device tracker. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.mikrotik/ -""" +"""Support for Mikrotik routers as device tracker.""" import logging import ssl diff --git a/homeassistant/components/mill/climate.py b/homeassistant/components/mill/climate.py index 6867f57ee48..cb6d47a52b0 100644 --- a/homeassistant/components/mill/climate.py +++ b/homeassistant/components/mill/climate.py @@ -1,9 +1,4 @@ -""" -Support for mill wifi-enabled home heaters. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.mill/ -""" +"""Support for mill wifi-enabled home heaters.""" import logging diff --git a/homeassistant/components/min_max/sensor.py b/homeassistant/components/min_max/sensor.py index e18c67471d9..929ef42a2d5 100644 --- a/homeassistant/components/min_max/sensor.py +++ b/homeassistant/components/min_max/sensor.py @@ -1,9 +1,4 @@ -""" -Support for displaying the minimal and the maximal value. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.min_max/ -""" +"""Support for displaying the minimal and the maximal value.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mitemp_bt/sensor.py b/homeassistant/components/mitemp_bt/sensor.py index f8bee17978d..cea2c6a55db 100644 --- a/homeassistant/components/mitemp_bt/sensor.py +++ b/homeassistant/components/mitemp_bt/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Xiaomi Mi Temp BLE environmental sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.mitemp_bt/ -""" +"""Support for Xiaomi Mi Temp BLE environmental sensor.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mjpeg/camera.py b/homeassistant/components/mjpeg/camera.py index 0e73dfac0b7..b9aa9c3e186 100644 --- a/homeassistant/components/mjpeg/camera.py +++ b/homeassistant/components/mjpeg/camera.py @@ -1,9 +1,4 @@ -""" -Support for IP Cameras. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.mjpeg/ -""" +"""Support for IP Cameras.""" import asyncio import logging from contextlib import closing diff --git a/homeassistant/components/modem_callerid/sensor.py b/homeassistant/components/modem_callerid/sensor.py index 2da7953c12a..b87f4840334 100644 --- a/homeassistant/components/modem_callerid/sensor.py +++ b/homeassistant/components/modem_callerid/sensor.py @@ -1,9 +1,4 @@ -""" -A sensor to monitor incoming calls using a USB modem that supports caller ID. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.modem_callerid/ -""" +"""A sensor for incoming calls using a USB modem that supports caller ID.""" import logging import voluptuous as vol from homeassistant.const import (STATE_IDLE, diff --git a/homeassistant/components/mold_indicator/sensor.py b/homeassistant/components/mold_indicator/sensor.py index 2a250f0e63d..645e04a890c 100644 --- a/homeassistant/components/mold_indicator/sensor.py +++ b/homeassistant/components/mold_indicator/sensor.py @@ -1,9 +1,4 @@ -""" -Calculates mold growth indication from temperature and humidity. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.mold_indicator/ -""" +"""Calculates mold growth indication from temperature and humidity.""" import logging import math diff --git a/homeassistant/components/monoprice/media_player.py b/homeassistant/components/monoprice/media_player.py index e98ad47a6e7..edffd6ac7ce 100644 --- a/homeassistant/components/monoprice/media_player.py +++ b/homeassistant/components/monoprice/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interfacing with Monoprice 6 zone home audio controller. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.monoprice/ -""" +"""Support for interfacing with Monoprice 6 zone home audio controller.""" import logging import voluptuous as vol diff --git a/homeassistant/components/moon/sensor.py b/homeassistant/components/moon/sensor.py index a019d21fd78..3b1d70bc731 100644 --- a/homeassistant/components/moon/sensor.py +++ b/homeassistant/components/moon/sensor.py @@ -1,9 +1,4 @@ -""" -Support for tracking the moon phases. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.moon/ -""" +"""Support for tracking the moon phases.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mpchc/media_player.py b/homeassistant/components/mpchc/media_player.py index 61d89c6d0b1..54518667949 100644 --- a/homeassistant/components/mpchc/media_player.py +++ b/homeassistant/components/mpchc/media_player.py @@ -1,9 +1,4 @@ -""" -Support to interface with the MPC-HC Web API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.mpchc/ -""" +"""Support to interface with the MPC-HC Web API.""" import logging import re diff --git a/homeassistant/components/mpd/media_player.py b/homeassistant/components/mpd/media_player.py index 9d8015109b2..8cbc1406e0b 100644 --- a/homeassistant/components/mpd/media_player.py +++ b/homeassistant/components/mpd/media_player.py @@ -1,9 +1,4 @@ -""" -Support to interact with a Music Player Daemon. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.mpd/ -""" +"""Support to interact with a Music Player Daemon.""" from datetime import timedelta import logging import os diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 2c605fb4b0d..3f1f8617689 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -1,9 +1,4 @@ -""" -Support for MQTT message handling. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/mqtt/ -""" +"""Support for MQTT message handling.""" import asyncio from functools import partial, wraps import inspect diff --git a/homeassistant/components/mqtt/alarm_control_panel.py b/homeassistant/components/mqtt/alarm_control_panel.py index f1142baa37a..d30c91bb9b2 100644 --- a/homeassistant/components/mqtt/alarm_control_panel.py +++ b/homeassistant/components/mqtt/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -This platform enables the possibility to control a MQTT alarm. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.mqtt/ -""" +"""This platform enables the possibility to control a MQTT alarm.""" import logging import re diff --git a/homeassistant/components/mqtt/binary_sensor.py b/homeassistant/components/mqtt/binary_sensor.py index 7532f305328..f942091984a 100644 --- a/homeassistant/components/mqtt/binary_sensor.py +++ b/homeassistant/components/mqtt/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for MQTT binary sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.mqtt/ -""" +"""Support for MQTT binary sensors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mqtt/camera.py b/homeassistant/components/mqtt/camera.py index 889e5533403..34e83a51f28 100644 --- a/homeassistant/components/mqtt/camera.py +++ b/homeassistant/components/mqtt/camera.py @@ -1,9 +1,4 @@ -""" -Camera that loads a picture from an MQTT topic. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.mqtt/ -""" +"""Camera that loads a picture from an MQTT topic.""" import asyncio import logging diff --git a/homeassistant/components/mqtt/climate.py b/homeassistant/components/mqtt/climate.py index a9c23d27e11..52d18a03419 100644 --- a/homeassistant/components/mqtt/climate.py +++ b/homeassistant/components/mqtt/climate.py @@ -1,9 +1,4 @@ -""" -Support for MQTT climate devices. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/climate.mqtt/ -""" +"""Support for MQTT climate devices.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mqtt/cover.py b/homeassistant/components/mqtt/cover.py index 8116421ac10..08b6c2b74ba 100644 --- a/homeassistant/components/mqtt/cover.py +++ b/homeassistant/components/mqtt/cover.py @@ -1,9 +1,4 @@ -""" -Support for MQTT cover devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/cover.mqtt/ -""" +"""Support for MQTT cover devices.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mqtt/device_tracker.py b/homeassistant/components/mqtt/device_tracker.py index 0f22ed150ca..659c6315b21 100644 --- a/homeassistant/components/mqtt/device_tracker.py +++ b/homeassistant/components/mqtt/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for tracking MQTT enabled devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.mqtt/ -""" +"""Support for tracking MQTT enabled devices.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mqtt/discovery.py b/homeassistant/components/mqtt/discovery.py index cb87a208b4f..b10e05cbf0f 100644 --- a/homeassistant/components/mqtt/discovery.py +++ b/homeassistant/components/mqtt/discovery.py @@ -1,9 +1,4 @@ -""" -Support for MQTT discovery. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/mqtt/#discovery -""" +"""Support for MQTT discovery.""" import asyncio import json import logging diff --git a/homeassistant/components/mqtt/fan.py b/homeassistant/components/mqtt/fan.py index b8bff6088d8..7dff81160e0 100644 --- a/homeassistant/components/mqtt/fan.py +++ b/homeassistant/components/mqtt/fan.py @@ -1,9 +1,4 @@ -""" -Support for MQTT fans. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/fan.mqtt/ -""" +"""Support for MQTT fans.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mqtt/lock.py b/homeassistant/components/mqtt/lock.py index ee459d2174f..e01a30f0fab 100644 --- a/homeassistant/components/mqtt/lock.py +++ b/homeassistant/components/mqtt/lock.py @@ -1,9 +1,4 @@ -""" -Support for MQTT locks. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/lock.mqtt/ -""" +"""Support for MQTT locks.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mqtt/sensor.py b/homeassistant/components/mqtt/sensor.py index aa8d5e2a31e..1e024fdc768 100644 --- a/homeassistant/components/mqtt/sensor.py +++ b/homeassistant/components/mqtt/sensor.py @@ -1,9 +1,4 @@ -""" -Support for MQTT sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.mqtt/ -""" +"""Support for MQTT sensors.""" from datetime import timedelta import json import logging diff --git a/homeassistant/components/mqtt/server.py b/homeassistant/components/mqtt/server.py index 3373149a013..d7d36add517 100644 --- a/homeassistant/components/mqtt/server.py +++ b/homeassistant/components/mqtt/server.py @@ -1,9 +1,4 @@ -""" -Support for a local MQTT broker. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/mqtt/#use-the-embedded-broker -""" +"""Support for a local MQTT broker.""" import asyncio import logging import tempfile diff --git a/homeassistant/components/mqtt/subscription.py b/homeassistant/components/mqtt/subscription.py index e159132d560..368a12c1956 100644 --- a/homeassistant/components/mqtt/subscription.py +++ b/homeassistant/components/mqtt/subscription.py @@ -1,9 +1,4 @@ -""" -Helper to handle a set of topics to subscribe to. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/mqtt/ -""" +"""Helper to handle a set of topics to subscribe to.""" import logging from typing import Any, Callable, Dict, Optional diff --git a/homeassistant/components/mqtt/switch.py b/homeassistant/components/mqtt/switch.py index 4847afd80c9..acfcf3de01c 100644 --- a/homeassistant/components/mqtt/switch.py +++ b/homeassistant/components/mqtt/switch.py @@ -1,9 +1,4 @@ -""" -Support for MQTT switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.mqtt/ -""" +"""Support for MQTT switches.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mqtt/vacuum.py b/homeassistant/components/mqtt/vacuum.py index efa00821c1b..63a764e8746 100644 --- a/homeassistant/components/mqtt/vacuum.py +++ b/homeassistant/components/mqtt/vacuum.py @@ -1,9 +1,4 @@ -""" -Support for a generic MQTT vacuum. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/vacuum.mqtt/ -""" +"""Support for a generic MQTT vacuum.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mqtt_json/device_tracker.py b/homeassistant/components/mqtt_json/device_tracker.py index 0a1b327dca9..6059b26bcbd 100644 --- a/homeassistant/components/mqtt_json/device_tracker.py +++ b/homeassistant/components/mqtt_json/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for GPS tracking MQTT enabled devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.mqtt_json/ -""" +"""Support for GPS tracking MQTT enabled devices.""" import json import logging diff --git a/homeassistant/components/mqtt_room/sensor.py b/homeassistant/components/mqtt_room/sensor.py index 36f99719da4..961769711a4 100644 --- a/homeassistant/components/mqtt_room/sensor.py +++ b/homeassistant/components/mqtt_room/sensor.py @@ -1,9 +1,4 @@ -""" -Support for MQTT room presence detection. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.mqtt_room/ -""" +"""Support for MQTT room presence detection.""" import logging import json from datetime import timedelta diff --git a/homeassistant/components/mvglive/sensor.py b/homeassistant/components/mvglive/sensor.py index 71690f643f4..978c9ad34eb 100644 --- a/homeassistant/components/mvglive/sensor.py +++ b/homeassistant/components/mvglive/sensor.py @@ -1,9 +1,4 @@ -""" -Support for real-time departure information for public transport in Munich. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.mvglive/ -""" +"""Support for departure information for public transport in Munich.""" import logging from datetime import timedelta diff --git a/homeassistant/components/mycroft/notify.py b/homeassistant/components/mycroft/notify.py index a8a401a9c1f..d66be629f17 100644 --- a/homeassistant/components/mycroft/notify.py +++ b/homeassistant/components/mycroft/notify.py @@ -1,9 +1,4 @@ -""" -Mycroft AI notification platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.mycroft/ -""" +"""Mycroft AI notification platform.""" import logging from homeassistant.components.notify import BaseNotificationService diff --git a/homeassistant/components/myq/cover.py b/homeassistant/components/myq/cover.py index b2587c06512..b1112f153b2 100644 --- a/homeassistant/components/myq/cover.py +++ b/homeassistant/components/myq/cover.py @@ -1,9 +1,4 @@ -""" -Support for MyQ-Enabled Garage Doors. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/cover.myq/ -""" +"""Support for MyQ-Enabled Garage Doors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/mystrom/binary_sensor.py b/homeassistant/components/mystrom/binary_sensor.py index 4927be27eb3..42245dc4df3 100644 --- a/homeassistant/components/mystrom/binary_sensor.py +++ b/homeassistant/components/mystrom/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for the myStrom buttons. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.mystrom/ -""" +"""Support for the myStrom buttons.""" import logging from homeassistant.components.binary_sensor import DOMAIN, BinarySensorDevice diff --git a/homeassistant/components/nad/media_player.py b/homeassistant/components/nad/media_player.py index 00738abe4d1..8c5a14a3524 100644 --- a/homeassistant/components/nad/media_player.py +++ b/homeassistant/components/nad/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interfacing with NAD receivers through RS-232. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.nad/ -""" +"""Support for interfacing with NAD receivers through RS-232.""" import logging import voluptuous as vol diff --git a/homeassistant/components/nanoleaf/light.py b/homeassistant/components/nanoleaf/light.py index 818617f1b9a..60457e21f9a 100644 --- a/homeassistant/components/nanoleaf/light.py +++ b/homeassistant/components/nanoleaf/light.py @@ -1,9 +1,4 @@ -""" -Support for Nanoleaf Lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.nanoleaf/ -""" +"""Support for Nanoleaf Lights.""" import logging import voluptuous as vol diff --git a/homeassistant/components/nederlandse_spoorwegen/sensor.py b/homeassistant/components/nederlandse_spoorwegen/sensor.py index 5d9376ad9eb..224d16e4869 100644 --- a/homeassistant/components/nederlandse_spoorwegen/sensor.py +++ b/homeassistant/components/nederlandse_spoorwegen/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Nederlandse Spoorwegen public transport. - -For more details on this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.nederlandse_spoorwegen/ -""" +"""Support for Nederlandse Spoorwegen public transport.""" from datetime import datetime, timedelta import logging diff --git a/homeassistant/components/nello/lock.py b/homeassistant/components/nello/lock.py index e7eaea8fcd3..efb7719e201 100644 --- a/homeassistant/components/nello/lock.py +++ b/homeassistant/components/nello/lock.py @@ -1,9 +1,4 @@ -""" -Nello.io lock platform. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/lock.nello/ -""" +"""Nello.io lock platform.""" from itertools import filterfalse import logging diff --git a/homeassistant/components/ness_alarm/alarm_control_panel.py b/homeassistant/components/ness_alarm/alarm_control_panel.py index f77b534980f..618297ef9a5 100644 --- a/homeassistant/components/ness_alarm/alarm_control_panel.py +++ b/homeassistant/components/ness_alarm/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Support for Ness D8X/D16X alarm panel. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.ness_alarm/ -""" +"""Support for Ness D8X/D16X alarm panel.""" import logging diff --git a/homeassistant/components/ness_alarm/binary_sensor.py b/homeassistant/components/ness_alarm/binary_sensor.py index 7b684f74aa1..2bed9eb6404 100644 --- a/homeassistant/components/ness_alarm/binary_sensor.py +++ b/homeassistant/components/ness_alarm/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for Ness D8X/D16X zone states - represented as binary sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.ness_alarm/ -""" +"""Support for Ness D8X/D16X zone states - represented as binary sensors.""" import logging from homeassistant.components.binary_sensor import BinarySensorDevice diff --git a/homeassistant/components/netatmo_public/sensor.py b/homeassistant/components/netatmo_public/sensor.py index 7a500b66183..3480534436d 100644 --- a/homeassistant/components/netatmo_public/sensor.py +++ b/homeassistant/components/netatmo_public/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Sensors using public Netatmo data. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.netatmo_public/. -""" +"""Support for Sensors using public Netatmo data.""" from datetime import timedelta import logging diff --git a/homeassistant/components/netdata/sensor.py b/homeassistant/components/netdata/sensor.py index 6a6eea02005..6d99722a416 100644 --- a/homeassistant/components/netdata/sensor.py +++ b/homeassistant/components/netdata/sensor.py @@ -1,9 +1,4 @@ -""" -Support gathering system information of hosts which are running netdata. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.netdata/ -""" +"""Support gathering system information of hosts which are running netdata.""" from datetime import timedelta import logging diff --git a/homeassistant/components/netgear/device_tracker.py b/homeassistant/components/netgear/device_tracker.py index 49bce932159..ce8c2d6066d 100644 --- a/homeassistant/components/netgear/device_tracker.py +++ b/homeassistant/components/netgear/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Netgear routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.netgear/ -""" +"""Support for Netgear routers.""" import logging import voluptuous as vol diff --git a/homeassistant/components/netio/switch.py b/homeassistant/components/netio/switch.py index 4492697406d..27a7dfbd5e7 100644 --- a/homeassistant/components/netio/switch.py +++ b/homeassistant/components/netio/switch.py @@ -1,9 +1,4 @@ -""" -The Netio switch component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.netio/ -""" +"""The Netio switch component.""" import logging from collections import namedtuple from datetime import timedelta diff --git a/homeassistant/components/neurio_energy/sensor.py b/homeassistant/components/neurio_energy/sensor.py index 673cd8da724..9e12465c69b 100644 --- a/homeassistant/components/neurio_energy/sensor.py +++ b/homeassistant/components/neurio_energy/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring a Neurio energy sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.neurio_energy/ -""" +"""Support for monitoring a Neurio energy sensor.""" import logging from datetime import timedelta diff --git a/homeassistant/components/nfandroidtv/notify.py b/homeassistant/components/nfandroidtv/notify.py index c4003a6312a..1cf1fbd0dbc 100644 --- a/homeassistant/components/nfandroidtv/notify.py +++ b/homeassistant/components/nfandroidtv/notify.py @@ -1,9 +1,4 @@ -""" -Notifications for Android TV notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.nfandroidtv/ -""" +"""Notifications for Android TV notification service.""" import base64 import io import logging diff --git a/homeassistant/components/niko_home_control/light.py b/homeassistant/components/niko_home_control/light.py index 6b58ced5989..00e8dc838a6 100644 --- a/homeassistant/components/niko_home_control/light.py +++ b/homeassistant/components/niko_home_control/light.py @@ -1,9 +1,4 @@ -""" -Support for Niko Home Control. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/light.niko_home_control/ -""" +"""Support for Niko Home Control.""" import logging import voluptuous as vol diff --git a/homeassistant/components/nilu/air_quality.py b/homeassistant/components/nilu/air_quality.py index 2ab38c1ad95..979d5736d6a 100644 --- a/homeassistant/components/nilu/air_quality.py +++ b/homeassistant/components/nilu/air_quality.py @@ -1,9 +1,4 @@ -""" -Sensor for checking the air quality around Norway. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/air_quality.nilu/ -""" +"""Sensor for checking the air quality around Norway.""" from datetime import timedelta import logging diff --git a/homeassistant/components/nmbs/sensor.py b/homeassistant/components/nmbs/sensor.py index 15f29339087..034c37530b3 100644 --- a/homeassistant/components/nmbs/sensor.py +++ b/homeassistant/components/nmbs/sensor.py @@ -1,9 +1,4 @@ -""" -Get ride details and liveboard details for NMBS (Belgian railway). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.nmbs/ -""" +"""Get ride details and liveboard details for NMBS (Belgian railway).""" import logging import voluptuous as vol diff --git a/homeassistant/components/noaa_tides/sensor.py b/homeassistant/components/noaa_tides/sensor.py index 6a72fdf8f2a..0c4bde94f57 100644 --- a/homeassistant/components/noaa_tides/sensor.py +++ b/homeassistant/components/noaa_tides/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the NOAA Tides and Currents API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.noaa_tides/ -""" +"""Support for the NOAA Tides and Currents API.""" from datetime import datetime, timedelta import logging diff --git a/homeassistant/components/norway_air/air_quality.py b/homeassistant/components/norway_air/air_quality.py index 712f2734ea8..06ed68801f8 100644 --- a/homeassistant/components/norway_air/air_quality.py +++ b/homeassistant/components/norway_air/air_quality.py @@ -1,9 +1,4 @@ -""" -Sensor for checking the air quality forecast around Norway. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/air_quality.norway_air/ -""" +"""Sensor for checking the air quality forecast around Norway.""" import logging from datetime import timedelta diff --git a/homeassistant/components/notify/__init__.py b/homeassistant/components/notify/__init__.py index f0320617e19..8bb3384aebd 100644 --- a/homeassistant/components/notify/__init__.py +++ b/homeassistant/components/notify/__init__.py @@ -1,9 +1,4 @@ -""" -Provides functionality to notify people. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/notify/ -""" +"""Provides functionality to notify people.""" import asyncio import logging from functools import partial diff --git a/homeassistant/components/nsw_fuel_station/sensor.py b/homeassistant/components/nsw_fuel_station/sensor.py index f0da619a6e7..ce4337fc93a 100644 --- a/homeassistant/components/nsw_fuel_station/sensor.py +++ b/homeassistant/components/nsw_fuel_station/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor platform to display the current fuel prices at a NSW fuel station. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.nsw_fuel_station/ -""" +"""Sensor platform to display the current fuel prices at a NSW fuel station.""" import datetime import logging from typing import Optional diff --git a/homeassistant/components/nuheat/climate.py b/homeassistant/components/nuheat/climate.py index 27e909f8f04..32adc1d216f 100644 --- a/homeassistant/components/nuheat/climate.py +++ b/homeassistant/components/nuheat/climate.py @@ -1,9 +1,4 @@ -""" -Support for NuHeat thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.nuheat/ -""" +"""Support for NuHeat thermostats.""" from datetime import timedelta import logging diff --git a/homeassistant/components/nuki/lock.py b/homeassistant/components/nuki/lock.py index 8af798e31e0..ef49d4b97dd 100644 --- a/homeassistant/components/nuki/lock.py +++ b/homeassistant/components/nuki/lock.py @@ -1,9 +1,4 @@ -""" -Nuki.io lock platform. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/lock.nuki/ -""" +"""Nuki.io lock platform.""" from datetime import timedelta import logging diff --git a/homeassistant/components/nut/sensor.py b/homeassistant/components/nut/sensor.py index 1464c0d91c1..43ba06f70eb 100644 --- a/homeassistant/components/nut/sensor.py +++ b/homeassistant/components/nut/sensor.py @@ -1,9 +1,4 @@ -""" -Provides a sensor to track various status aspects of a UPS. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.nut/ -""" +"""Provides a sensor to track various status aspects of a UPS.""" import logging from datetime import timedelta diff --git a/homeassistant/components/nx584/alarm_control_panel.py b/homeassistant/components/nx584/alarm_control_panel.py index c84872d0b25..c5e1fede6fd 100644 --- a/homeassistant/components/nx584/alarm_control_panel.py +++ b/homeassistant/components/nx584/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Support for NX584 alarm control panels. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.nx584/ -""" +"""Support for NX584 alarm control panels.""" import logging import requests diff --git a/homeassistant/components/nx584/binary_sensor.py b/homeassistant/components/nx584/binary_sensor.py index 2929acc2709..61f8fb801ea 100644 --- a/homeassistant/components/nx584/binary_sensor.py +++ b/homeassistant/components/nx584/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for exposing NX584 elements as sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.nx584/ -""" +"""Support for exposing NX584 elements as sensors.""" import logging import threading import time diff --git a/homeassistant/components/nzbget/sensor.py b/homeassistant/components/nzbget/sensor.py index 2ee8e37a57a..bb0b7c912fd 100644 --- a/homeassistant/components/nzbget/sensor.py +++ b/homeassistant/components/nzbget/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring NZBGet NZB client. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.nzbget/ -""" +"""Support for monitoring NZBGet NZB client.""" from datetime import timedelta import logging diff --git a/homeassistant/components/ohmconnect/sensor.py b/homeassistant/components/ohmconnect/sensor.py index 3487cab2fcd..1d870e4d15a 100644 --- a/homeassistant/components/ohmconnect/sensor.py +++ b/homeassistant/components/ohmconnect/sensor.py @@ -1,9 +1,4 @@ -""" -Support for OhmConnect. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/sensor.ohmconnect/ -""" +"""Support for OhmConnect.""" import logging from datetime import timedelta diff --git a/homeassistant/components/onewire/sensor.py b/homeassistant/components/onewire/sensor.py index d39ab24230c..2e55b5cea36 100644 --- a/homeassistant/components/onewire/sensor.py +++ b/homeassistant/components/onewire/sensor.py @@ -1,9 +1,4 @@ -""" -Support for 1-Wire environment sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.onewire/ -""" +"""Support for 1-Wire environment sensors.""" import os import time import logging diff --git a/homeassistant/components/onkyo/media_player.py b/homeassistant/components/onkyo/media_player.py index 2fb284bb24a..64b9684c58c 100644 --- a/homeassistant/components/onkyo/media_player.py +++ b/homeassistant/components/onkyo/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Onkyo Receivers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.onkyo/ -""" +"""Support for Onkyo Receivers.""" import logging # pylint: disable=unused-import diff --git a/homeassistant/components/onvif/camera.py b/homeassistant/components/onvif/camera.py index a196f87cd10..90222b9cafc 100644 --- a/homeassistant/components/onvif/camera.py +++ b/homeassistant/components/onvif/camera.py @@ -1,9 +1,4 @@ -""" -Support for ONVIF Cameras with FFmpeg as decoder. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.onvif/ -""" +"""Support for ONVIF Cameras with FFmpeg as decoder.""" import asyncio import logging import os diff --git a/homeassistant/components/openalpr_cloud/image_processing.py b/homeassistant/components/openalpr_cloud/image_processing.py index c983a945548..12146009fac 100644 --- a/homeassistant/components/openalpr_cloud/image_processing.py +++ b/homeassistant/components/openalpr_cloud/image_processing.py @@ -1,9 +1,4 @@ -""" -Component that will help set the OpenALPR cloud for ALPR processing. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/image_processing.openalpr_cloud/ -""" +"""Component that will help set the OpenALPR cloud for ALPR processing.""" import asyncio import logging from base64 import b64encode diff --git a/homeassistant/components/openalpr_local/image_processing.py b/homeassistant/components/openalpr_local/image_processing.py index 4a98594d50c..811a160dd02 100644 --- a/homeassistant/components/openalpr_local/image_processing.py +++ b/homeassistant/components/openalpr_local/image_processing.py @@ -1,9 +1,4 @@ -""" -Component that will help set the OpenALPR local for ALPR processing. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/image_processing.openalpr_local/ -""" +"""Component that will help set the OpenALPR local for ALPR processing.""" import asyncio import io import logging diff --git a/homeassistant/components/openevse/sensor.py b/homeassistant/components/openevse/sensor.py index cf41f87718d..e54b47236c5 100644 --- a/homeassistant/components/openevse/sensor.py +++ b/homeassistant/components/openevse/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring an OpenEVSE Charger. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.openevse/ -""" +"""Support for monitoring an OpenEVSE Charger.""" import logging from requests import RequestException diff --git a/homeassistant/components/openexchangerates/sensor.py b/homeassistant/components/openexchangerates/sensor.py index 6361b823dea..6c146044140 100644 --- a/homeassistant/components/openexchangerates/sensor.py +++ b/homeassistant/components/openexchangerates/sensor.py @@ -1,9 +1,4 @@ -""" -Support for openexchangerates.org exchange rates service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.openexchangerates/ -""" +"""Support for openexchangerates.org exchange rates service.""" from datetime import timedelta import logging diff --git a/homeassistant/components/opengarage/cover.py b/homeassistant/components/opengarage/cover.py index 664d2e291ac..1e3d3128829 100644 --- a/homeassistant/components/opengarage/cover.py +++ b/homeassistant/components/opengarage/cover.py @@ -1,9 +1,4 @@ -""" -Platform for the opengarage.io cover component. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/cover.opengarage/ -""" +"""Platform for the opengarage.io cover component.""" import logging import requests diff --git a/homeassistant/components/openhardwaremonitor/sensor.py b/homeassistant/components/openhardwaremonitor/sensor.py index d429cad9d97..7c5072db97c 100644 --- a/homeassistant/components/openhardwaremonitor/sensor.py +++ b/homeassistant/components/openhardwaremonitor/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Open Hardware Monitor Sensor Platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.openhardwaremonitor/ -""" +"""Support for Open Hardware Monitor Sensor Platform.""" from datetime import timedelta import logging diff --git a/homeassistant/components/openhome/media_player.py b/homeassistant/components/openhome/media_player.py index d828284a563..03926bce8c5 100644 --- a/homeassistant/components/openhome/media_player.py +++ b/homeassistant/components/openhome/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Openhome Devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.openhome/ -""" +"""Support for Openhome Devices.""" import logging from homeassistant.components.media_player import ( diff --git a/homeassistant/components/opensky/sensor.py b/homeassistant/components/opensky/sensor.py index 5ee11af4e60..3019c54471f 100644 --- a/homeassistant/components/opensky/sensor.py +++ b/homeassistant/components/opensky/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for the Open Sky Network. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.opensky/ -""" +"""Sensor for the Open Sky Network.""" import logging from datetime import timedelta diff --git a/homeassistant/components/openweathermap/sensor.py b/homeassistant/components/openweathermap/sensor.py index a137836138b..5de67721e30 100644 --- a/homeassistant/components/openweathermap/sensor.py +++ b/homeassistant/components/openweathermap/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the OpenWeatherMap (OWM) service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.openweathermap/ -""" +"""Support for the OpenWeatherMap (OWM) service.""" from datetime import timedelta import logging diff --git a/homeassistant/components/opple/light.py b/homeassistant/components/opple/light.py index fb503d33d31..03e36dc179d 100644 --- a/homeassistant/components/opple/light.py +++ b/homeassistant/components/opple/light.py @@ -1,9 +1,4 @@ -""" -Support for the Opple light. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.opple/ -""" +"""Support for the Opple light.""" import logging diff --git a/homeassistant/components/orvibo/switch.py b/homeassistant/components/orvibo/switch.py index 9e6686ca3ae..c77e24446ec 100644 --- a/homeassistant/components/orvibo/switch.py +++ b/homeassistant/components/orvibo/switch.py @@ -1,9 +1,4 @@ -""" -Support for Orvibo S20 Wifi Smart Switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.orvibo/ -""" +"""Support for Orvibo S20 Wifi Smart Switches.""" import logging import voluptuous as vol diff --git a/homeassistant/components/osramlightify/light.py b/homeassistant/components/osramlightify/light.py index 81b8e2a88ec..b880273fd1e 100644 --- a/homeassistant/components/osramlightify/light.py +++ b/homeassistant/components/osramlightify/light.py @@ -1,9 +1,4 @@ -""" -Support for Osram Lightify. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.osramlightify/ -""" +"""Support for Osram Lightify.""" import logging import random import socket diff --git a/homeassistant/components/otp/sensor.py b/homeassistant/components/otp/sensor.py index 5394b49c389..2ac4c519984 100644 --- a/homeassistant/components/otp/sensor.py +++ b/homeassistant/components/otp/sensor.py @@ -1,9 +1,4 @@ -""" -Support for One-Time Password (OTP). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.otp/ -""" +"""Support for One-Time Password (OTP).""" import time import logging diff --git a/homeassistant/components/owntracks/device_tracker.py b/homeassistant/components/owntracks/device_tracker.py index f1214b62b0e..69ea723d84c 100644 --- a/homeassistant/components/owntracks/device_tracker.py +++ b/homeassistant/components/owntracks/device_tracker.py @@ -1,9 +1,4 @@ -""" -Device tracker platform that adds support for OwnTracks over MQTT. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.owntracks/ -""" +"""Device tracker platform that adds support for OwnTracks over MQTT.""" import json import logging diff --git a/homeassistant/components/panasonic_bluray/media_player.py b/homeassistant/components/panasonic_bluray/media_player.py index 36a3160d3b5..ebf71135d34 100644 --- a/homeassistant/components/panasonic_bluray/media_player.py +++ b/homeassistant/components/panasonic_bluray/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Panasonic Blu-Ray players. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/panasonic_bluray/ -""" +"""Support for Panasonic Blu-Ray players.""" from datetime import timedelta import logging diff --git a/homeassistant/components/panasonic_viera/media_player.py b/homeassistant/components/panasonic_viera/media_player.py index f1ac0cd90d4..324becd0bf7 100644 --- a/homeassistant/components/panasonic_viera/media_player.py +++ b/homeassistant/components/panasonic_viera/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interface with a Panasonic Viera TV. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.panasonic_viera/ -""" +"""Support for interface with a Panasonic Viera TV.""" import logging import voluptuous as vol diff --git a/homeassistant/components/pandora/media_player.py b/homeassistant/components/pandora/media_player.py index ca78f7a4318..32cde430d0e 100644 --- a/homeassistant/components/pandora/media_player.py +++ b/homeassistant/components/pandora/media_player.py @@ -1,9 +1,4 @@ -""" -Component for controlling Pandora stations through the pianobar client. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/media_player.pandora/ -""" +"""Component for controlling Pandora stations through the pianobar client.""" from datetime import timedelta import logging import os diff --git a/homeassistant/components/philips_js/media_player.py b/homeassistant/components/philips_js/media_player.py index 97ec758e6cf..f5eddff8d13 100644 --- a/homeassistant/components/philips_js/media_player.py +++ b/homeassistant/components/philips_js/media_player.py @@ -1,9 +1,4 @@ -""" -Media Player component to integrate TVs exposing the Joint Space API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.philips_js/ -""" +"""Media Player component to integrate TVs exposing the Joint Space API.""" from datetime import timedelta import logging diff --git a/homeassistant/components/pi_hole/sensor.py b/homeassistant/components/pi_hole/sensor.py index ae9aca5bc79..805e17ebdff 100644 --- a/homeassistant/components/pi_hole/sensor.py +++ b/homeassistant/components/pi_hole/sensor.py @@ -1,9 +1,4 @@ -""" -Support for getting statistical data from a Pi-hole system. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.pi_hole/ -""" +"""Support for getting statistical data from a Pi-hole system.""" from datetime import timedelta import logging diff --git a/homeassistant/components/picotts/tts.py b/homeassistant/components/picotts/tts.py index c164e7fb85d..fffadae0f13 100644 --- a/homeassistant/components/picotts/tts.py +++ b/homeassistant/components/picotts/tts.py @@ -1,9 +1,4 @@ -""" -Support for the Pico TTS speech service. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/tts.picotts/ -""" +"""Support for the Pico TTS speech service.""" import logging import os import shutil diff --git a/homeassistant/components/piglow/light.py b/homeassistant/components/piglow/light.py index 56c72e01fdf..dc3906b2002 100644 --- a/homeassistant/components/piglow/light.py +++ b/homeassistant/components/piglow/light.py @@ -1,9 +1,4 @@ -""" -Support for Piglow LED's. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.piglow/ -""" +"""Support for Piglow LED's.""" import logging import subprocess diff --git a/homeassistant/components/pilight/__init__.py b/homeassistant/components/pilight/__init__.py index d307a428e0e..46be3b37204 100644 --- a/homeassistant/components/pilight/__init__.py +++ b/homeassistant/components/pilight/__init__.py @@ -1,9 +1,4 @@ -""" -Component to create an interface to a Pilight daemon. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/pilight/ -""" +"""Component to create an interface to a Pilight daemon.""" import logging import functools import socket diff --git a/homeassistant/components/pilight/binary_sensor.py b/homeassistant/components/pilight/binary_sensor.py index de23baef884..131a91b5fc3 100644 --- a/homeassistant/components/pilight/binary_sensor.py +++ b/homeassistant/components/pilight/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for Pilight binary sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.pilight/ -""" +"""Support for Pilight binary sensors.""" import datetime import logging diff --git a/homeassistant/components/pilight/sensor.py b/homeassistant/components/pilight/sensor.py index ddcbe018f8e..c36151c90dc 100644 --- a/homeassistant/components/pilight/sensor.py +++ b/homeassistant/components/pilight/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Pilight sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.pilight/ -""" +"""Support for Pilight sensors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/pilight/switch.py b/homeassistant/components/pilight/switch.py index 3bbe2e69110..d645d8e3013 100644 --- a/homeassistant/components/pilight/switch.py +++ b/homeassistant/components/pilight/switch.py @@ -1,9 +1,4 @@ -""" -Support for switching devices via Pilight to on and off. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.pilight/ -""" +"""Support for switching devices via Pilight to on and off.""" import logging import voluptuous as vol diff --git a/homeassistant/components/ping/binary_sensor.py b/homeassistant/components/ping/binary_sensor.py index 4c597dd63e1..4f95a470efb 100644 --- a/homeassistant/components/ping/binary_sensor.py +++ b/homeassistant/components/ping/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Tracks the latency of a host by sending ICMP echo requests (ping). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.ping/ -""" +"""Tracks the latency of a host by sending ICMP echo requests (ping).""" import logging import subprocess import re diff --git a/homeassistant/components/ping/device_tracker.py b/homeassistant/components/ping/device_tracker.py index f3492da9e80..9f9bf4475b4 100644 --- a/homeassistant/components/ping/device_tracker.py +++ b/homeassistant/components/ping/device_tracker.py @@ -1,9 +1,4 @@ -""" -Tracks devices by sending a ICMP echo request (ping). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.ping/ -""" +"""Tracks devices by sending a ICMP echo request (ping).""" import logging import subprocess import sys diff --git a/homeassistant/components/pioneer/media_player.py b/homeassistant/components/pioneer/media_player.py index 00fa453100a..a687ba5ad4a 100644 --- a/homeassistant/components/pioneer/media_player.py +++ b/homeassistant/components/pioneer/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Pioneer Network Receivers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.pioneer/ -""" +"""Support for Pioneer Network Receivers.""" import logging import telnetlib diff --git a/homeassistant/components/pjlink/media_player.py b/homeassistant/components/pjlink/media_player.py index c1b883a0295..ad7bdc9e77c 100644 --- a/homeassistant/components/pjlink/media_player.py +++ b/homeassistant/components/pjlink/media_player.py @@ -1,9 +1,4 @@ -""" -Support for controlling projector via the PJLink protocol. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.pjlink/ -""" +"""Support for controlling projector via the PJLink protocol.""" import logging import voluptuous as vol diff --git a/homeassistant/components/plex/media_player.py b/homeassistant/components/plex/media_player.py index a68a2faade8..f2af6836e3b 100644 --- a/homeassistant/components/plex/media_player.py +++ b/homeassistant/components/plex/media_player.py @@ -1,9 +1,4 @@ -""" -Support to interface with the Plex API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.plex/ -""" +"""Support to interface with the Plex API.""" from datetime import timedelta import json import logging diff --git a/homeassistant/components/plex/sensor.py b/homeassistant/components/plex/sensor.py index eaf73ceb566..a3df6fdb41e 100644 --- a/homeassistant/components/plex/sensor.py +++ b/homeassistant/components/plex/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Plex media server monitoring. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.plex/ -""" +"""Support for Plex media server monitoring.""" from datetime import timedelta import logging import voluptuous as vol diff --git a/homeassistant/components/pocketcasts/sensor.py b/homeassistant/components/pocketcasts/sensor.py index 9d5b837bba9..f09e9012004 100644 --- a/homeassistant/components/pocketcasts/sensor.py +++ b/homeassistant/components/pocketcasts/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Pocket Casts. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.pocketcasts/ -""" +"""Support for Pocket Casts.""" import logging from datetime import timedelta diff --git a/homeassistant/components/postnl/sensor.py b/homeassistant/components/postnl/sensor.py index 84cb42c0957..f9c8019cd31 100644 --- a/homeassistant/components/postnl/sensor.py +++ b/homeassistant/components/postnl/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for PostNL packages. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.postnl/ -""" +"""Sensor for PostNL packages.""" from datetime import timedelta import logging diff --git a/homeassistant/components/prezzibenzina/sensor.py b/homeassistant/components/prezzibenzina/sensor.py index 171fea53314..525de7dad2f 100644 --- a/homeassistant/components/prezzibenzina/sensor.py +++ b/homeassistant/components/prezzibenzina/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the PrezziBenzina.it service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.prezzibenzina/ -""" +"""Support for the PrezziBenzina.it service.""" import datetime as dt from datetime import timedelta import logging diff --git a/homeassistant/components/proliphix/climate.py b/homeassistant/components/proliphix/climate.py index c88ece033df..c165334201d 100644 --- a/homeassistant/components/proliphix/climate.py +++ b/homeassistant/components/proliphix/climate.py @@ -1,9 +1,4 @@ -""" -Support for Proliphix NT10e Thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.proliphix/ -""" +"""Support for Proliphix NT10e Thermostats.""" import voluptuous as vol from homeassistant.components.climate import ClimateDevice, PLATFORM_SCHEMA diff --git a/homeassistant/components/prowl/notify.py b/homeassistant/components/prowl/notify.py index 6d911789121..1f2067cc660 100644 --- a/homeassistant/components/prowl/notify.py +++ b/homeassistant/components/prowl/notify.py @@ -1,9 +1,4 @@ -""" -Prowl notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.prowl/ -""" +"""Prowl notification service.""" import asyncio import logging diff --git a/homeassistant/components/proxy/camera.py b/homeassistant/components/proxy/camera.py index 3e6e4911d27..fda2cdea60e 100644 --- a/homeassistant/components/proxy/camera.py +++ b/homeassistant/components/proxy/camera.py @@ -1,9 +1,4 @@ -""" -Proxy camera platform that enables image processing of camera data. - -For more details about this platform, please refer to the documentation -https://www.home-assistant.io/components/camera.proxy/ -""" +"""Proxy camera platform that enables image processing of camera data.""" import asyncio import logging diff --git a/homeassistant/components/ps4/__init__.py b/homeassistant/components/ps4/__init__.py index 9183bbe1989..191eb223707 100644 --- a/homeassistant/components/ps4/__init__.py +++ b/homeassistant/components/ps4/__init__.py @@ -1,9 +1,4 @@ -""" -Support for PlayStation 4 consoles. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/ps4/ -""" +"""Support for PlayStation 4 consoles.""" import logging from homeassistant.const import CONF_REGION diff --git a/homeassistant/components/ps4/media_player.py b/homeassistant/components/ps4/media_player.py index 80c1fda52de..4dc4fa0a317 100644 --- a/homeassistant/components/ps4/media_player.py +++ b/homeassistant/components/ps4/media_player.py @@ -1,9 +1,4 @@ -""" -Support for PlayStation 4 consoles. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/ps4/ -""" +"""Support for PlayStation 4 consoles.""" import logging import socket diff --git a/homeassistant/components/pulseaudio_loopback/switch.py b/homeassistant/components/pulseaudio_loopback/switch.py index f112608d760..9ec6587f678 100644 --- a/homeassistant/components/pulseaudio_loopback/switch.py +++ b/homeassistant/components/pulseaudio_loopback/switch.py @@ -1,9 +1,4 @@ -""" -Switch logic for loading/unloading pulseaudio loopback modules. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.pulseaudio_loopback/ -""" +"""Switch logic for loading/unloading pulseaudio loopback modules.""" import logging import re import socket diff --git a/homeassistant/components/push/camera.py b/homeassistant/components/push/camera.py index 5490cd1508c..c0424f15898 100644 --- a/homeassistant/components/push/camera.py +++ b/homeassistant/components/push/camera.py @@ -1,9 +1,4 @@ -""" -Camera platform that receives images through HTTP POST. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/camera.push/ -""" +"""Camera platform that receives images through HTTP POST.""" import logging import asyncio diff --git a/homeassistant/components/pushbullet/notify.py b/homeassistant/components/pushbullet/notify.py index f0b4ec24da8..3fc90161ae0 100644 --- a/homeassistant/components/pushbullet/notify.py +++ b/homeassistant/components/pushbullet/notify.py @@ -1,9 +1,4 @@ -""" -Pushbullet platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.pushbullet/ -""" +"""Pushbullet platform for notify component.""" import logging import mimetypes diff --git a/homeassistant/components/pushbullet/sensor.py b/homeassistant/components/pushbullet/sensor.py index 9b26bdfbbe9..c90f952e7de 100644 --- a/homeassistant/components/pushbullet/sensor.py +++ b/homeassistant/components/pushbullet/sensor.py @@ -1,9 +1,4 @@ -""" -Pushbullet platform for sensor component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.pushbullet/ -""" +"""Pushbullet platform for sensor component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/pushetta/notify.py b/homeassistant/components/pushetta/notify.py index 106c0641a69..028b0cfd492 100644 --- a/homeassistant/components/pushetta/notify.py +++ b/homeassistant/components/pushetta/notify.py @@ -1,9 +1,4 @@ -""" -Pushetta platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.pushetta/ -""" +"""Pushetta platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/pushover/notify.py b/homeassistant/components/pushover/notify.py index 78e9ed11c95..39a1ce5d2f7 100644 --- a/homeassistant/components/pushover/notify.py +++ b/homeassistant/components/pushover/notify.py @@ -1,9 +1,4 @@ -""" -Pushover platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.pushover/ -""" +"""Pushover platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/pushsafer/notify.py b/homeassistant/components/pushsafer/notify.py index a1fa2b7409c..c64b861631a 100644 --- a/homeassistant/components/pushsafer/notify.py +++ b/homeassistant/components/pushsafer/notify.py @@ -1,9 +1,4 @@ -""" -Pushsafer platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.pushsafer/ -""" +"""Pushsafer platform for notify component.""" import base64 import logging import mimetypes diff --git a/homeassistant/components/pvoutput/sensor.py b/homeassistant/components/pvoutput/sensor.py index dbcd38af3cc..22368212442 100644 --- a/homeassistant/components/pvoutput/sensor.py +++ b/homeassistant/components/pvoutput/sensor.py @@ -1,9 +1,4 @@ -""" -Support for getting collected information from PVOutput. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.pvoutput/ -""" +"""Support for getting collected information from PVOutput.""" import logging from collections import namedtuple from datetime import timedelta diff --git a/homeassistant/components/pyload/sensor.py b/homeassistant/components/pyload/sensor.py index 78a191c16f4..7c7d1e7ae08 100644 --- a/homeassistant/components/pyload/sensor.py +++ b/homeassistant/components/pyload/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring pyLoad. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.pyload/ -""" +"""Support for monitoring pyLoad.""" from datetime import timedelta import logging diff --git a/homeassistant/components/python_script/__init__.py b/homeassistant/components/python_script/__init__.py index d639b638033..56a82b39120 100644 --- a/homeassistant/components/python_script/__init__.py +++ b/homeassistant/components/python_script/__init__.py @@ -1,9 +1,4 @@ -""" -Component to allow running Python scripts. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/python_script/ -""" +"""Component to allow running Python scripts.""" import datetime import glob import logging diff --git a/homeassistant/components/qbittorrent/sensor.py b/homeassistant/components/qbittorrent/sensor.py index 8718f3a9d74..7e91c0ab276 100644 --- a/homeassistant/components/qbittorrent/sensor.py +++ b/homeassistant/components/qbittorrent/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring the qBittorrent API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.qbittorrent/ -""" +"""Support for monitoring the qBittorrent API.""" import logging import voluptuous as vol diff --git a/homeassistant/components/qnap/sensor.py b/homeassistant/components/qnap/sensor.py index a6a9c6e30d0..e12f20c25b1 100644 --- a/homeassistant/components/qnap/sensor.py +++ b/homeassistant/components/qnap/sensor.py @@ -1,9 +1,4 @@ -""" -Support for QNAP NAS Sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.qnap/ -""" +"""Support for QNAP NAS Sensors.""" import logging from datetime import timedelta diff --git a/homeassistant/components/qrcode/image_processing.py b/homeassistant/components/qrcode/image_processing.py index 00f4ad025b2..46fa78cca7f 100644 --- a/homeassistant/components/qrcode/image_processing.py +++ b/homeassistant/components/qrcode/image_processing.py @@ -1,9 +1,4 @@ -""" -Support for the QR image processing. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/image_processing.qr/ -""" +"""Support for the QR image processing.""" from homeassistant.core import split_entity_id from homeassistant.components.image_processing import ( ImageProcessingEntity, CONF_SOURCE, CONF_ENTITY_ID, CONF_NAME) diff --git a/homeassistant/components/quantum_gateway/device_tracker.py b/homeassistant/components/quantum_gateway/device_tracker.py index 90ba3575cfa..3472a4dbb97 100644 --- a/homeassistant/components/quantum_gateway/device_tracker.py +++ b/homeassistant/components/quantum_gateway/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Verizon FiOS Quantum Gateways. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.quantum_gateway/ -""" +"""Support for Verizon FiOS Quantum Gateways.""" import logging from requests.exceptions import RequestException diff --git a/homeassistant/components/qwikswitch/__init__.py b/homeassistant/components/qwikswitch/__init__.py index 23144ed82b8..a6468595622 100644 --- a/homeassistant/components/qwikswitch/__init__.py +++ b/homeassistant/components/qwikswitch/__init__.py @@ -1,9 +1,4 @@ -""" -Support for Qwikswitch devices. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/qwikswitch/ -""" +"""Support for Qwikswitch devices.""" import logging import voluptuous as vol diff --git a/homeassistant/components/qwikswitch/binary_sensor.py b/homeassistant/components/qwikswitch/binary_sensor.py index 6cdc29deae4..a92c4d0b435 100644 --- a/homeassistant/components/qwikswitch/binary_sensor.py +++ b/homeassistant/components/qwikswitch/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for Qwikswitch Binary Sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.qwikswitch/ -""" +"""Support for Qwikswitch Binary Sensors.""" import logging from homeassistant.components.binary_sensor import BinarySensorDevice diff --git a/homeassistant/components/qwikswitch/light.py b/homeassistant/components/qwikswitch/light.py index 46a0a88483b..cb4df24f978 100644 --- a/homeassistant/components/qwikswitch/light.py +++ b/homeassistant/components/qwikswitch/light.py @@ -1,9 +1,4 @@ -""" -Support for Qwikswitch Relays and Dimmers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.qwikswitch/ -""" +"""Support for Qwikswitch Relays and Dimmers.""" from homeassistant.components.light import SUPPORT_BRIGHTNESS, Light from . import DOMAIN as QWIKSWITCH, QSToggleEntity diff --git a/homeassistant/components/qwikswitch/sensor.py b/homeassistant/components/qwikswitch/sensor.py index b9ccb3c3a7b..8befce4f7e2 100644 --- a/homeassistant/components/qwikswitch/sensor.py +++ b/homeassistant/components/qwikswitch/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Qwikswitch Sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.qwikswitch/ -""" +"""Support for Qwikswitch Sensors.""" import logging from homeassistant.core import callback diff --git a/homeassistant/components/qwikswitch/switch.py b/homeassistant/components/qwikswitch/switch.py index ec544df8c75..4ee5396ae0c 100644 --- a/homeassistant/components/qwikswitch/switch.py +++ b/homeassistant/components/qwikswitch/switch.py @@ -1,9 +1,4 @@ -""" -Support for Qwikswitch relays. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.qwikswitch/ -""" +"""Support for Qwikswitch relays.""" from homeassistant.components.switch import SwitchDevice from . import DOMAIN as QWIKSWITCH, QSToggleEntity diff --git a/homeassistant/components/rachio/__init__.py b/homeassistant/components/rachio/__init__.py index 27827da0182..64a7a5af4d7 100644 --- a/homeassistant/components/rachio/__init__.py +++ b/homeassistant/components/rachio/__init__.py @@ -1,9 +1,4 @@ -""" -Integration with the Rachio Iro sprinkler system controller. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/rachio/ -""" +"""Integration with the Rachio Iro sprinkler system controller.""" import asyncio import logging from typing import Optional diff --git a/homeassistant/components/rachio/binary_sensor.py b/homeassistant/components/rachio/binary_sensor.py index 9cf57ea3230..ffcaeccacff 100644 --- a/homeassistant/components/rachio/binary_sensor.py +++ b/homeassistant/components/rachio/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Integration with the Rachio Iro sprinkler system controller. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.rachio/ -""" +"""Integration with the Rachio Iro sprinkler system controller.""" from abc import abstractmethod import logging diff --git a/homeassistant/components/rachio/switch.py b/homeassistant/components/rachio/switch.py index fe584441afd..483e07e96f4 100644 --- a/homeassistant/components/rachio/switch.py +++ b/homeassistant/components/rachio/switch.py @@ -1,9 +1,4 @@ -""" -Integration with the Rachio Iro sprinkler system controller. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.rachio/ -""" +"""Integration with the Rachio Iro sprinkler system controller.""" from abc import abstractmethod from datetime import timedelta import logging diff --git a/homeassistant/components/radarr/sensor.py b/homeassistant/components/radarr/sensor.py index 67695ae0e32..a3932acf862 100644 --- a/homeassistant/components/radarr/sensor.py +++ b/homeassistant/components/radarr/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Radarr. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.radarr/ -""" +"""Support for Radarr.""" import logging import time from datetime import datetime, timedelta diff --git a/homeassistant/components/radiotherm/climate.py b/homeassistant/components/radiotherm/climate.py index 4132d3c27c7..66dfc4cc385 100644 --- a/homeassistant/components/radiotherm/climate.py +++ b/homeassistant/components/radiotherm/climate.py @@ -1,9 +1,4 @@ -""" -Support for Radio Thermostat wifi-enabled home thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.radiotherm/ -""" +"""Support for Radio Thermostat wifi-enabled home thermostats.""" import datetime import logging diff --git a/homeassistant/components/rainbird/__init__.py b/homeassistant/components/rainbird/__init__.py index bbce7f752af..de0f42fda4a 100644 --- a/homeassistant/components/rainbird/__init__.py +++ b/homeassistant/components/rainbird/__init__.py @@ -1,9 +1,4 @@ -""" -Support for Rain Bird Irrigation system LNK WiFi Module. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/rainbird/ -""" +"""Support for Rain Bird Irrigation system LNK WiFi Module.""" import logging import voluptuous as vol diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index 3d0de04e53e..0cee202ecb2 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Rain Bird Irrigation system LNK WiFi Module. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.rainbird/ -""" +"""Support for Rain Bird Irrigation system LNK WiFi Module.""" import logging import voluptuous as vol diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index 2031769b343..32c7c49ab99 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -1,9 +1,4 @@ -""" -Support for Rain Bird Irrigation system LNK WiFi Module. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/switch.rainbird/ -""" +"""Support for Rain Bird Irrigation system LNK WiFi Module.""" import logging diff --git a/homeassistant/components/raincloud/__init__.py b/homeassistant/components/raincloud/__init__.py index 7ccf9f33ada..473d52bdbdd 100644 --- a/homeassistant/components/raincloud/__init__.py +++ b/homeassistant/components/raincloud/__init__.py @@ -1,9 +1,4 @@ -""" -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/ -""" +"""Support for Melnor RainCloud sprinkler water timer.""" from datetime import timedelta import logging diff --git a/homeassistant/components/raincloud/binary_sensor.py b/homeassistant/components/raincloud/binary_sensor.py index cb66fc3c6af..6ebad7cc121 100644 --- a/homeassistant/components/raincloud/binary_sensor.py +++ b/homeassistant/components/raincloud/binary_sensor.py @@ -1,9 +1,4 @@ -""" -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/ -""" +"""Support for Melnor RainCloud sprinkler water timer.""" import logging import voluptuous as vol diff --git a/homeassistant/components/raincloud/sensor.py b/homeassistant/components/raincloud/sensor.py index 8bcccf06171..6774d48ae99 100644 --- a/homeassistant/components/raincloud/sensor.py +++ b/homeassistant/components/raincloud/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Melnor RainCloud sprinkler water timer. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.raincloud/ -""" +"""Support for Melnor RainCloud sprinkler water timer.""" import logging import voluptuous as vol diff --git a/homeassistant/components/rainmachine/binary_sensor.py b/homeassistant/components/rainmachine/binary_sensor.py index 929dbcf314c..4387e6b67be 100644 --- a/homeassistant/components/rainmachine/binary_sensor.py +++ b/homeassistant/components/rainmachine/binary_sensor.py @@ -1,9 +1,4 @@ -""" -This platform provides binary sensors for key RainMachine data. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.rainmachine/ -""" +"""This platform provides binary sensors for key RainMachine data.""" import logging from homeassistant.components.binary_sensor import BinarySensorDevice diff --git a/homeassistant/components/rainmachine/sensor.py b/homeassistant/components/rainmachine/sensor.py index 908daa2c83d..1d438b8035f 100644 --- a/homeassistant/components/rainmachine/sensor.py +++ b/homeassistant/components/rainmachine/sensor.py @@ -1,9 +1,4 @@ -""" -This platform provides support for sensor data from RainMachine. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.rainmachine/ -""" +"""This platform provides support for sensor data from RainMachine.""" import logging from homeassistant.core import callback diff --git a/homeassistant/components/rainmachine/switch.py b/homeassistant/components/rainmachine/switch.py index 6b658c0fcbf..adcbe559819 100644 --- a/homeassistant/components/rainmachine/switch.py +++ b/homeassistant/components/rainmachine/switch.py @@ -1,9 +1,4 @@ -""" -This component provides support for RainMachine programs and zones. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/switch.rainmachine/ -""" +"""This component provides support for RainMachine programs and zones.""" from datetime import datetime import logging diff --git a/homeassistant/components/random/binary_sensor.py b/homeassistant/components/random/binary_sensor.py index 9bdc57c6e46..ad8bafaf4c2 100644 --- a/homeassistant/components/random/binary_sensor.py +++ b/homeassistant/components/random/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for showing random states. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.random/ -""" +"""Support for showing random states.""" import logging import voluptuous as vol diff --git a/homeassistant/components/random/sensor.py b/homeassistant/components/random/sensor.py index 4dec96bec2e..cc412ff7773 100644 --- a/homeassistant/components/random/sensor.py +++ b/homeassistant/components/random/sensor.py @@ -1,9 +1,4 @@ -""" -Support for showing random numbers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.random/ -""" +"""Support for showing random numbers.""" import logging import voluptuous as vol diff --git a/homeassistant/components/raspyrfm/switch.py b/homeassistant/components/raspyrfm/switch.py index a8a6230fc09..a141721f3e5 100644 --- a/homeassistant/components/raspyrfm/switch.py +++ b/homeassistant/components/raspyrfm/switch.py @@ -1,9 +1,4 @@ -""" -Support for switch devices that can be controlled using the RaspyRFM rc module. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.raspyrfm/ -""" +"""Support for switchs that can be controlled using the RaspyRFM rc module.""" import logging import voluptuous as vol diff --git a/homeassistant/components/recollect_waste/sensor.py b/homeassistant/components/recollect_waste/sensor.py index 9122973c919..1e3803ab866 100644 --- a/homeassistant/components/recollect_waste/sensor.py +++ b/homeassistant/components/recollect_waste/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Recollect Waste curbside collection pickup. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/sensor.recollect_waste/ -""" +"""Support for Recollect Waste curbside collection pickup.""" import logging import voluptuous as vol diff --git a/homeassistant/components/recswitch/switch.py b/homeassistant/components/recswitch/switch.py index 636c302cea1..ed2da8022f8 100644 --- a/homeassistant/components/recswitch/switch.py +++ b/homeassistant/components/recswitch/switch.py @@ -1,9 +1,4 @@ -""" -Support for Ankuoo RecSwitch MS6126 devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.recswitch/ -""" +"""Support for Ankuoo RecSwitch MS6126 devices.""" import logging diff --git a/homeassistant/components/rest/binary_sensor.py b/homeassistant/components/rest/binary_sensor.py index 1a94159290f..0d28e98229c 100644 --- a/homeassistant/components/rest/binary_sensor.py +++ b/homeassistant/components/rest/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for RESTful binary sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.rest/ -""" +"""Support for RESTful binary sensors.""" import logging from requests.auth import HTTPBasicAuth, HTTPDigestAuth diff --git a/homeassistant/components/rest/notify.py b/homeassistant/components/rest/notify.py index de75db83848..8134e73ae6b 100644 --- a/homeassistant/components/rest/notify.py +++ b/homeassistant/components/rest/notify.py @@ -1,9 +1,4 @@ -""" -RESTful platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.rest/ -""" +"""RESTful platform for notify component.""" import logging import requests diff --git a/homeassistant/components/rest/sensor.py b/homeassistant/components/rest/sensor.py index a9446ee3503..fe92f9d8a10 100644 --- a/homeassistant/components/rest/sensor.py +++ b/homeassistant/components/rest/sensor.py @@ -1,9 +1,4 @@ -""" -Support for RESTful API sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.rest/ -""" +"""Support for RESTful API sensors.""" import logging import json diff --git a/homeassistant/components/rest/switch.py b/homeassistant/components/rest/switch.py index 5f1920ae1af..2ef45b226fe 100644 --- a/homeassistant/components/rest/switch.py +++ b/homeassistant/components/rest/switch.py @@ -1,9 +1,4 @@ -""" -Support for RESTful switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.rest/ -""" +"""Support for RESTful switches.""" import asyncio import logging diff --git a/homeassistant/components/rflink/binary_sensor.py b/homeassistant/components/rflink/binary_sensor.py index 5318642a5b1..e98fb756659 100644 --- a/homeassistant/components/rflink/binary_sensor.py +++ b/homeassistant/components/rflink/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for Rflink binary sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.rflink/ -""" +"""Support for Rflink binary sensors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/rflink/cover.py b/homeassistant/components/rflink/cover.py index f91ef1cc682..409d27862f9 100644 --- a/homeassistant/components/rflink/cover.py +++ b/homeassistant/components/rflink/cover.py @@ -1,9 +1,4 @@ -""" -Support for Rflink Cover devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/cover.rflink/ -""" +"""Support for Rflink Cover devices.""" import logging import voluptuous as vol diff --git a/homeassistant/components/rflink/light.py b/homeassistant/components/rflink/light.py index cdb34328b51..112ed4b4f51 100644 --- a/homeassistant/components/rflink/light.py +++ b/homeassistant/components/rflink/light.py @@ -1,9 +1,4 @@ -""" -Support for Rflink lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.rflink/ -""" +"""Support for Rflink lights.""" import logging import voluptuous as vol diff --git a/homeassistant/components/rflink/sensor.py b/homeassistant/components/rflink/sensor.py index e46cc09d0ba..c7498ece241 100644 --- a/homeassistant/components/rflink/sensor.py +++ b/homeassistant/components/rflink/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Rflink sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.rflink/ -""" +"""Support for Rflink sensors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/rflink/switch.py b/homeassistant/components/rflink/switch.py index a1470bf115f..d5889c797f0 100644 --- a/homeassistant/components/rflink/switch.py +++ b/homeassistant/components/rflink/switch.py @@ -1,9 +1,4 @@ -""" -Support for Rflink switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.rflink/ -""" +"""Support for Rflink switches.""" import logging import voluptuous as vol diff --git a/homeassistant/components/ring/binary_sensor.py b/homeassistant/components/ring/binary_sensor.py index bcc365a2e83..79de0424d85 100644 --- a/homeassistant/components/ring/binary_sensor.py +++ b/homeassistant/components/ring/binary_sensor.py @@ -1,9 +1,4 @@ -""" -This component provides HA sensor support for Ring Door Bell/Chimes. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.ring/ -""" +"""This component provides HA sensor support for Ring Door Bell/Chimes.""" from datetime import timedelta import logging diff --git a/homeassistant/components/ring/camera.py b/homeassistant/components/ring/camera.py index 905cbd46158..18427b9b6f9 100644 --- a/homeassistant/components/ring/camera.py +++ b/homeassistant/components/ring/camera.py @@ -1,9 +1,4 @@ -""" -This component provides support to the Ring Door Bell camera. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.ring/ -""" +"""This component provides support to the Ring Door Bell camera.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/ring/sensor.py b/homeassistant/components/ring/sensor.py index 5e323d89ad8..c9cb2f1159a 100644 --- a/homeassistant/components/ring/sensor.py +++ b/homeassistant/components/ring/sensor.py @@ -1,9 +1,4 @@ -""" -This component provides HA sensor support for Ring Door Bell/Chimes. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.ring/ -""" +"""This component provides HA sensor support for Ring Door Bell/Chimes.""" from datetime import timedelta import logging diff --git a/homeassistant/components/ritassist/device_tracker.py b/homeassistant/components/ritassist/device_tracker.py index c41ae9f2ec2..74bec1b8711 100644 --- a/homeassistant/components/ritassist/device_tracker.py +++ b/homeassistant/components/ritassist/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for RitAssist Platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.ritassist/ -""" +"""Support for RitAssist Platform.""" import logging import requests diff --git a/homeassistant/components/rmvtransport/sensor.py b/homeassistant/components/rmvtransport/sensor.py index 7835b74ac98..7a3afb3f324 100644 --- a/homeassistant/components/rmvtransport/sensor.py +++ b/homeassistant/components/rmvtransport/sensor.py @@ -1,9 +1,4 @@ -""" -Support for real-time departure information for Rhein-Main public transport. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.rmvtransport/ -""" +"""Support for departure information for Rhein-Main public transport.""" import asyncio import logging from datetime import timedelta diff --git a/homeassistant/components/rocketchat/notify.py b/homeassistant/components/rocketchat/notify.py index 8bf1e172264..e404114736a 100644 --- a/homeassistant/components/rocketchat/notify.py +++ b/homeassistant/components/rocketchat/notify.py @@ -1,9 +1,4 @@ -""" -Rocket.Chat notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.rocketchat/ -""" +"""Rocket.Chat notification service.""" import logging import voluptuous as vol diff --git a/homeassistant/components/roomba/vacuum.py b/homeassistant/components/roomba/vacuum.py index d06ecc5141f..fadbe2a82d5 100644 --- a/homeassistant/components/roomba/vacuum.py +++ b/homeassistant/components/roomba/vacuum.py @@ -1,9 +1,4 @@ -""" -Support for Wi-Fi enabled iRobot Roombas. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/vacuum.roomba/ -""" +"""Support for Wi-Fi enabled iRobot Roombas.""" import asyncio import logging diff --git a/homeassistant/components/rova/sensor.py b/homeassistant/components/rova/sensor.py index 07be331f23f..2c2c36b1245 100644 --- a/homeassistant/components/rova/sensor.py +++ b/homeassistant/components/rova/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Rova garbage calendar. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.rova/ -""" +"""Support for Rova garbage calendar.""" from datetime import datetime, timedelta import logging diff --git a/homeassistant/components/rpi_camera/camera.py b/homeassistant/components/rpi_camera/camera.py index ba6f5e93304..f0dd1d36539 100644 --- a/homeassistant/components/rpi_camera/camera.py +++ b/homeassistant/components/rpi_camera/camera.py @@ -1,9 +1,4 @@ -""" -Camera platform that has a Raspberry Pi camera. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.rpi_camera/ -""" +"""Camera platform that has a Raspberry Pi camera.""" import os import subprocess import logging diff --git a/homeassistant/components/rpi_rf/switch.py b/homeassistant/components/rpi_rf/switch.py index 6844cb0f383..d0a23372802 100644 --- a/homeassistant/components/rpi_rf/switch.py +++ b/homeassistant/components/rpi_rf/switch.py @@ -1,9 +1,4 @@ -""" -Allows to configure a switch using a 433MHz module via GPIO on a Raspberry Pi. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.rpi_rf/ -""" +"""Support for a switch using a 433MHz module via GPIO on a Raspberry Pi.""" import importlib import logging diff --git a/homeassistant/components/russound_rio/media_player.py b/homeassistant/components/russound_rio/media_player.py index 972594e07e6..b8f9d29f5ca 100644 --- a/homeassistant/components/russound_rio/media_player.py +++ b/homeassistant/components/russound_rio/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Russound multizone controllers using RIO Protocol. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.russound_rio/ -""" +"""Support for Russound multizone controllers using RIO Protocol.""" import logging import voluptuous as vol diff --git a/homeassistant/components/russound_rnet/media_player.py b/homeassistant/components/russound_rnet/media_player.py index 6d919cdf7a8..f489d48a9d5 100644 --- a/homeassistant/components/russound_rnet/media_player.py +++ b/homeassistant/components/russound_rnet/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interfacing with Russound via RNET Protocol. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.russound_rnet/ -""" +"""Support for interfacing with Russound via RNET Protocol.""" import logging import voluptuous as vol diff --git a/homeassistant/components/ruter/sensor.py b/homeassistant/components/ruter/sensor.py index 91966f0df9c..f6fefc96198 100644 --- a/homeassistant/components/ruter/sensor.py +++ b/homeassistant/components/ruter/sensor.py @@ -1,9 +1,4 @@ -""" -A sensor platform that give you information about next departures from Ruter. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/sensor.ruter/ -""" +"""A sensor to provide information about next departures from Ruter.""" import logging import voluptuous as vol diff --git a/homeassistant/components/samsungtv/media_player.py b/homeassistant/components/samsungtv/media_player.py index e6715669da7..1a2a24c3621 100644 --- a/homeassistant/components/samsungtv/media_player.py +++ b/homeassistant/components/samsungtv/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interface with an Samsung TV. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.samsungtv/ -""" +"""Support for interface with an Samsung TV.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/scrape/sensor.py b/homeassistant/components/scrape/sensor.py index a6d16852df3..e576eca78e8 100644 --- a/homeassistant/components/scrape/sensor.py +++ b/homeassistant/components/scrape/sensor.py @@ -1,9 +1,4 @@ -""" -Support for getting data from websites with scraping. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.scrape/ -""" +"""Support for getting data from websites with scraping.""" import logging import voluptuous as vol diff --git a/homeassistant/components/scsgate/__init__.py b/homeassistant/components/scsgate/__init__.py index 79bf4e217c9..67421e9a46a 100644 --- a/homeassistant/components/scsgate/__init__.py +++ b/homeassistant/components/scsgate/__init__.py @@ -1,9 +1,4 @@ -""" -Support for SCSGate components. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/scsgate/ -""" +"""Support for SCSGate components.""" import logging from threading import Lock diff --git a/homeassistant/components/season/sensor.py b/homeassistant/components/season/sensor.py index 84a2b426e9e..7c7b1054961 100644 --- a/homeassistant/components/season/sensor.py +++ b/homeassistant/components/season/sensor.py @@ -1,9 +1,4 @@ -""" -Support for tracking which astronomical or meteorological season it is. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor/season/ -""" +"""Support for tracking which astronomical or meteorological season it is.""" import logging from datetime import datetime diff --git a/homeassistant/components/sendgrid/notify.py b/homeassistant/components/sendgrid/notify.py index 211e288725e..a717c7f24ed 100644 --- a/homeassistant/components/sendgrid/notify.py +++ b/homeassistant/components/sendgrid/notify.py @@ -1,9 +1,4 @@ -""" -SendGrid notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.sendgrid/ -""" +"""SendGrid notification service.""" import logging import voluptuous as vol diff --git a/homeassistant/components/sensehat/light.py b/homeassistant/components/sensehat/light.py index 86153fffef8..c68e77b40a4 100644 --- a/homeassistant/components/sensehat/light.py +++ b/homeassistant/components/sensehat/light.py @@ -1,9 +1,4 @@ -""" -Support for Sense Hat LEDs. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.sensehat/ -""" +"""Support for Sense Hat LEDs.""" import logging import voluptuous as vol diff --git a/homeassistant/components/sensehat/sensor.py b/homeassistant/components/sensehat/sensor.py index 15c73d990e1..870150c1a98 100644 --- a/homeassistant/components/sensehat/sensor.py +++ b/homeassistant/components/sensehat/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Sense HAT sensors. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.sensehat -""" +"""Support for Sense HAT sensors.""" import os import logging from datetime import timedelta diff --git a/homeassistant/components/sensibo/climate.py b/homeassistant/components/sensibo/climate.py index 3affaba3e1f..bf06f232427 100644 --- a/homeassistant/components/sensibo/climate.py +++ b/homeassistant/components/sensibo/climate.py @@ -1,9 +1,4 @@ -""" -Support for Sensibo wifi-enabled home thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.sensibo/ -""" +"""Support for Sensibo wifi-enabled home thermostats.""" import asyncio import logging diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index 50549f28fd7..031657066cb 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -1,9 +1,4 @@ -""" -Component to interface with various sensors that can be monitored. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor/ -""" +"""Component to interface with various sensors that can be monitored.""" from datetime import timedelta import logging diff --git a/homeassistant/components/serial/sensor.py b/homeassistant/components/serial/sensor.py index 5d49b065558..c01981f9021 100644 --- a/homeassistant/components/serial/sensor.py +++ b/homeassistant/components/serial/sensor.py @@ -1,9 +1,4 @@ -""" -Support for reading data from a serial port. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.serial/ -""" +"""Support for reading data from a serial port.""" import logging import json diff --git a/homeassistant/components/serial_pm/sensor.py b/homeassistant/components/serial_pm/sensor.py index 46dfc9fae75..9ad65f7256f 100644 --- a/homeassistant/components/serial_pm/sensor.py +++ b/homeassistant/components/serial_pm/sensor.py @@ -1,9 +1,4 @@ -""" -Support for particulate matter sensors connected to a serial port. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.serial_pm/ -""" +"""Support for particulate matter sensors connected to a serial port.""" import logging import voluptuous as vol diff --git a/homeassistant/components/sesame/lock.py b/homeassistant/components/sesame/lock.py index 44a6cfb265c..263914f389c 100644 --- a/homeassistant/components/sesame/lock.py +++ b/homeassistant/components/sesame/lock.py @@ -1,9 +1,4 @@ -""" -Support for Sesame, by CANDY HOUSE. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/lock.sesame/ -""" +"""Support for Sesame, by CANDY HOUSE.""" from typing import Callable import voluptuous as vol diff --git a/homeassistant/components/seven_segments/image_processing.py b/homeassistant/components/seven_segments/image_processing.py index a460115cc34..7bbfceb15e4 100644 --- a/homeassistant/components/seven_segments/image_processing.py +++ b/homeassistant/components/seven_segments/image_processing.py @@ -1,9 +1,4 @@ -""" -Local optical character recognition processing of seven segments displays. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/image_processing.seven_segments/ -""" +"""Optical character recognition processing of seven segments displays.""" import logging import io import os diff --git a/homeassistant/components/seventeentrack/sensor.py b/homeassistant/components/seventeentrack/sensor.py index 6fb4884989b..ff17d1a4c54 100644 --- a/homeassistant/components/seventeentrack/sensor.py +++ b/homeassistant/components/seventeentrack/sensor.py @@ -1,9 +1,4 @@ -""" -Support for package tracking sensors from 17track.net. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.seventeentrack/ -""" +"""Support for package tracking sensors from 17track.net.""" import logging from datetime import timedelta diff --git a/homeassistant/components/sht31/sensor.py b/homeassistant/components/sht31/sensor.py index 4b849849771..613b1f8c92a 100644 --- a/homeassistant/components/sht31/sensor.py +++ b/homeassistant/components/sht31/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Sensirion SHT31 temperature and humidity sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.sht31/ -""" +"""Support for Sensirion SHT31 temperature and humidity sensor.""" from datetime import timedelta import logging diff --git a/homeassistant/components/sigfox/sensor.py b/homeassistant/components/sigfox/sensor.py index 5e2a56cadc3..1bce2d6b28d 100644 --- a/homeassistant/components/sigfox/sensor.py +++ b/homeassistant/components/sigfox/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for SigFox devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.sigfox/ -""" +"""Sensor for SigFox devices.""" import logging import datetime import json diff --git a/homeassistant/components/simplepush/notify.py b/homeassistant/components/simplepush/notify.py index 63222d4adc1..081351238d9 100644 --- a/homeassistant/components/simplepush/notify.py +++ b/homeassistant/components/simplepush/notify.py @@ -1,9 +1,4 @@ -""" -Simplepush notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.simplepush/ -""" +"""Simplepush notification service.""" import logging import voluptuous as vol diff --git a/homeassistant/components/simulated/sensor.py b/homeassistant/components/simulated/sensor.py index 8f2c3dd36e0..562f355f76b 100644 --- a/homeassistant/components/simulated/sensor.py +++ b/homeassistant/components/simulated/sensor.py @@ -1,9 +1,4 @@ -""" -Adds a simulated sensor. - -For more details about this platform, refer to the documentation at -https://home-assistant.io/components/sensor.simulated/ -""" +"""Adds a simulated sensor.""" import logging import math from random import Random diff --git a/homeassistant/components/sky_hub/device_tracker.py b/homeassistant/components/sky_hub/device_tracker.py index 0d69e08aa71..4e0ce4352cc 100644 --- a/homeassistant/components/sky_hub/device_tracker.py +++ b/homeassistant/components/sky_hub/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Sky Hub. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.sky_hub/ -""" +"""Support for Sky Hub.""" import logging import re diff --git a/homeassistant/components/skybeacon/sensor.py b/homeassistant/components/skybeacon/sensor.py index 6960999306d..9b8b4872cdc 100644 --- a/homeassistant/components/skybeacon/sensor.py +++ b/homeassistant/components/skybeacon/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Skybeacon temperature/humidity Bluetooth LE sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.skybeacon/ -""" +"""Support for Skybeacon temperature/humidity Bluetooth LE sensors.""" import logging import threading from uuid import UUID diff --git a/homeassistant/components/slack/notify.py b/homeassistant/components/slack/notify.py index eabddf01299..026fed0a58e 100644 --- a/homeassistant/components/slack/notify.py +++ b/homeassistant/components/slack/notify.py @@ -1,9 +1,4 @@ -""" -Slack platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.slack/ -""" +"""Slack platform for notify component.""" import logging import requests diff --git a/homeassistant/components/sleepiq/binary_sensor.py b/homeassistant/components/sleepiq/binary_sensor.py index 808eda4967d..11f9e25d8c9 100644 --- a/homeassistant/components/sleepiq/binary_sensor.py +++ b/homeassistant/components/sleepiq/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for SleepIQ sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.sleepiq/ -""" +"""Support for SleepIQ sensors.""" from homeassistant.components import sleepiq from homeassistant.components.binary_sensor import BinarySensorDevice diff --git a/homeassistant/components/sleepiq/sensor.py b/homeassistant/components/sleepiq/sensor.py index 2c97d7eb1e1..3de444c3324 100644 --- a/homeassistant/components/sleepiq/sensor.py +++ b/homeassistant/components/sleepiq/sensor.py @@ -1,9 +1,4 @@ -""" -Support for SleepIQ sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sleepiq/ -""" +"""Support for SleepIQ sensors.""" from homeassistant.components import sleepiq DEPENDENCIES = ['sleepiq'] diff --git a/homeassistant/components/sma/sensor.py b/homeassistant/components/sma/sensor.py index 61009a472fb..a2ec7871f60 100644 --- a/homeassistant/components/sma/sensor.py +++ b/homeassistant/components/sma/sensor.py @@ -1,9 +1,4 @@ -""" -SMA Solar Webconnect interface. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.sma/ -""" +"""SMA Solar Webconnect interface.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/smartthings/smartapp.py b/homeassistant/components/smartthings/smartapp.py index 548a38711bd..9aa44d26f2d 100644 --- a/homeassistant/components/smartthings/smartapp.py +++ b/homeassistant/components/smartthings/smartapp.py @@ -1,10 +1,4 @@ -""" -SmartApp functionality to receive cloud-push notifications. - -This module defines the functions to manage the SmartApp integration -within the SmartThings ecosystem in order to receive real-time webhook-based -callbacks when device states change. -""" +"""SmartApp functionality to receive cloud-push notifications.""" import asyncio import functools import logging diff --git a/homeassistant/components/smtp/notify.py b/homeassistant/components/smtp/notify.py index 4104013bcf7..1aaf3464e2b 100644 --- a/homeassistant/components/smtp/notify.py +++ b/homeassistant/components/smtp/notify.py @@ -1,9 +1,4 @@ -""" -Mail (SMTP) notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.smtp/ -""" +"""Mail (SMTP) notification service.""" from email.mime.application import MIMEApplication from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart diff --git a/homeassistant/components/snapcast/media_player.py b/homeassistant/components/snapcast/media_player.py index 74b17ae5ff1..b1589c4db51 100644 --- a/homeassistant/components/snapcast/media_player.py +++ b/homeassistant/components/snapcast/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interacting with Snapcast clients. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.snapcast/ -""" +"""Support for interacting with Snapcast clients.""" import logging import socket diff --git a/homeassistant/components/snmp/device_tracker.py b/homeassistant/components/snmp/device_tracker.py index 7c6efc82ef9..8a0fe7c6101 100644 --- a/homeassistant/components/snmp/device_tracker.py +++ b/homeassistant/components/snmp/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for fetching WiFi associations through SNMP. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.snmp/ -""" +"""Support for fetching WiFi associations through SNMP.""" import binascii import logging diff --git a/homeassistant/components/snmp/sensor.py b/homeassistant/components/snmp/sensor.py index 3964e44e376..83d31118988 100644 --- a/homeassistant/components/snmp/sensor.py +++ b/homeassistant/components/snmp/sensor.py @@ -1,9 +1,4 @@ -""" -Support for displaying collected data over SNMP. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.snmp/ -""" +"""Support for displaying collected data over SNMP.""" import logging from datetime import timedelta diff --git a/homeassistant/components/snmp/switch.py b/homeassistant/components/snmp/switch.py index 0baa129657d..fdb3267a3c7 100644 --- a/homeassistant/components/snmp/switch.py +++ b/homeassistant/components/snmp/switch.py @@ -1,9 +1,4 @@ -""" -Support for SNMP enabled switch. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.snmp/ -""" +"""Support for SNMP enabled switch.""" import logging import voluptuous as vol diff --git a/homeassistant/components/socialblade/sensor.py b/homeassistant/components/socialblade/sensor.py index 9a73e9cdd68..77433ac6d57 100644 --- a/homeassistant/components/socialblade/sensor.py +++ b/homeassistant/components/socialblade/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Social Blade. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.socialblade/ -""" +"""Support for Social Blade.""" from datetime import timedelta import logging diff --git a/homeassistant/components/solaredge/sensor.py b/homeassistant/components/solaredge/sensor.py index d56ccc53b68..6c6d7557282 100644 --- a/homeassistant/components/solaredge/sensor.py +++ b/homeassistant/components/solaredge/sensor.py @@ -1,9 +1,4 @@ -""" -Support for SolarEdge Monitoring API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.solaredge/ -""" +"""Support for SolarEdge Monitoring API.""" from datetime import timedelta import logging diff --git a/homeassistant/components/sonarr/sensor.py b/homeassistant/components/sonarr/sensor.py index b0e87992e39..b593f6d3182 100644 --- a/homeassistant/components/sonarr/sensor.py +++ b/homeassistant/components/sonarr/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Sonarr. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.sonarr/ -""" +"""Support for Sonarr.""" import logging import time from datetime import datetime diff --git a/homeassistant/components/songpal/media_player.py b/homeassistant/components/songpal/media_player.py index 7665b409d1d..842360484cf 100644 --- a/homeassistant/components/songpal/media_player.py +++ b/homeassistant/components/songpal/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Songpal-enabled (Sony) media devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.songpal/ -""" +"""Support for Songpal-enabled (Sony) media devices.""" import asyncio import logging from collections import OrderedDict diff --git a/homeassistant/components/soundtouch/media_player.py b/homeassistant/components/soundtouch/media_player.py index b2045b9b65e..027fad43a40 100644 --- a/homeassistant/components/soundtouch/media_player.py +++ b/homeassistant/components/soundtouch/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interface with a Bose Soundtouch. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.soundtouch/ -""" +"""Support for interface with a Bose Soundtouch.""" import logging import re diff --git a/homeassistant/components/spc/alarm_control_panel.py b/homeassistant/components/spc/alarm_control_panel.py index 623a4b0dbd1..77b412021aa 100644 --- a/homeassistant/components/spc/alarm_control_panel.py +++ b/homeassistant/components/spc/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Support for Vanderbilt (formerly Siemens) SPC alarm systems. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.spc/ -""" +"""Support for Vanderbilt (formerly Siemens) SPC alarm systems.""" import logging import homeassistant.components.alarm_control_panel as alarm diff --git a/homeassistant/components/spc/binary_sensor.py b/homeassistant/components/spc/binary_sensor.py index 6a0712d62bb..78ec2a11a97 100644 --- a/homeassistant/components/spc/binary_sensor.py +++ b/homeassistant/components/spc/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for Vanderbilt (formerly Siemens) SPC alarm systems. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.spc/ -""" +"""Support for Vanderbilt (formerly Siemens) SPC alarm systems.""" import logging from homeassistant.components.binary_sensor import BinarySensorDevice diff --git a/homeassistant/components/spotcrime/sensor.py b/homeassistant/components/spotcrime/sensor.py index 46f5fdc1c85..fa9cfa687ec 100644 --- a/homeassistant/components/spotcrime/sensor.py +++ b/homeassistant/components/spotcrime/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for Spot Crime. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.spotcrime/ -""" +"""Sensor for Spot Crime.""" from datetime import timedelta from collections import defaultdict diff --git a/homeassistant/components/spotify/media_player.py b/homeassistant/components/spotify/media_player.py index 9965487ded9..b9252d5035b 100644 --- a/homeassistant/components/spotify/media_player.py +++ b/homeassistant/components/spotify/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interacting with Spotify Connect. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.spotify/ -""" +"""Support for interacting with Spotify Connect.""" from datetime import timedelta import logging diff --git a/homeassistant/components/squeezebox/media_player.py b/homeassistant/components/squeezebox/media_player.py index 5f6fd525a11..d25d2f03fce 100644 --- a/homeassistant/components/squeezebox/media_player.py +++ b/homeassistant/components/squeezebox/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interfacing to the Logitech SqueezeBox API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.squeezebox/ -""" +"""Support for interfacing to the Logitech SqueezeBox API.""" import asyncio import json import logging diff --git a/homeassistant/components/srp_energy/sensor.py b/homeassistant/components/srp_energy/sensor.py index 4d2cd863b12..0ebae427da1 100644 --- a/homeassistant/components/srp_energy/sensor.py +++ b/homeassistant/components/srp_energy/sensor.py @@ -1,9 +1,4 @@ -""" -Platform for retrieving energy data from SRP. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/sensor.srp_energy/ -""" +"""Platform for retrieving energy data from SRP.""" from datetime import datetime, timedelta import logging diff --git a/homeassistant/components/starlingbank/sensor.py b/homeassistant/components/starlingbank/sensor.py index e325e5e1a57..00640ea4963 100644 --- a/homeassistant/components/starlingbank/sensor.py +++ b/homeassistant/components/starlingbank/sensor.py @@ -1,9 +1,4 @@ -""" -Support for balance data via the Starling Bank API. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/sensor.starlingbank/ -""" +"""Support for balance data via the Starling Bank API.""" import logging import requests diff --git a/homeassistant/components/startca/sensor.py b/homeassistant/components/startca/sensor.py index 85939ea72ae..1e57a4cf859 100644 --- a/homeassistant/components/startca/sensor.py +++ b/homeassistant/components/startca/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Start.ca Bandwidth Monitor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.startca/ -""" +"""Support for Start.ca Bandwidth Monitor.""" from datetime import timedelta from xml.parsers.expat import ExpatError import logging diff --git a/homeassistant/components/statistics/sensor.py b/homeassistant/components/statistics/sensor.py index 01c783dc1db..a777a921f31 100644 --- a/homeassistant/components/statistics/sensor.py +++ b/homeassistant/components/statistics/sensor.py @@ -1,9 +1,4 @@ -""" -Support for statistics for sensor values. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.statistics/ -""" +"""Support for statistics for sensor values.""" import logging import statistics from collections import deque diff --git a/homeassistant/components/steam_online/sensor.py b/homeassistant/components/steam_online/sensor.py index 861a5958dd3..4b4b73ad8cf 100644 --- a/homeassistant/components/steam_online/sensor.py +++ b/homeassistant/components/steam_online/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for Steam account status. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.steam_online/ -""" +"""Sensor for Steam account status.""" import logging import voluptuous as vol diff --git a/homeassistant/components/stream/__init__.py b/homeassistant/components/stream/__init__.py index 1e8ae5d60e3..43debc504e1 100644 --- a/homeassistant/components/stream/__init__.py +++ b/homeassistant/components/stream/__init__.py @@ -1,9 +1,4 @@ -""" -Provide functionality to stream video source. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/stream/ -""" +"""Provide functionality to stream video source.""" import logging import threading diff --git a/homeassistant/components/stream/hls.py b/homeassistant/components/stream/hls.py index aa5ce105764..c19db4f203f 100644 --- a/homeassistant/components/stream/hls.py +++ b/homeassistant/components/stream/hls.py @@ -1,9 +1,4 @@ -""" -Provide functionality to stream HLS. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/stream/hls -""" +"""Provide functionality to stream HLS.""" from aiohttp import web from homeassistant.core import callback diff --git a/homeassistant/components/stride/notify.py b/homeassistant/components/stride/notify.py index 9d05bd17f34..fa08697d798 100644 --- a/homeassistant/components/stride/notify.py +++ b/homeassistant/components/stride/notify.py @@ -1,9 +1,4 @@ -""" -Stride platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.stride/ -""" +"""Stride platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/supervisord/sensor.py b/homeassistant/components/supervisord/sensor.py index 894881dad86..fc40bd4e867 100644 --- a/homeassistant/components/supervisord/sensor.py +++ b/homeassistant/components/supervisord/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for Supervisord process status. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.supervisord/ -""" +"""Sensor for Supervisord process status.""" import logging import xmlrpc.client diff --git a/homeassistant/components/swiss_hydrological_data/sensor.py b/homeassistant/components/swiss_hydrological_data/sensor.py index c354ebedb2b..84964a94cbd 100644 --- a/homeassistant/components/swiss_hydrological_data/sensor.py +++ b/homeassistant/components/swiss_hydrological_data/sensor.py @@ -1,9 +1,4 @@ -""" -Support for hydrological data from the Federal Office for the Environment FOEN. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.swiss_hydrological_data/ -""" +"""Support for hydrological data from the Fed. Office for the Environment.""" from datetime import timedelta import logging diff --git a/homeassistant/components/swiss_public_transport/sensor.py b/homeassistant/components/swiss_public_transport/sensor.py index d9f2410f8ca..8d6b7fdee0e 100644 --- a/homeassistant/components/swiss_public_transport/sensor.py +++ b/homeassistant/components/swiss_public_transport/sensor.py @@ -1,9 +1,4 @@ -""" -Support for transport.opendata.ch. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.swiss_public_transport/ -""" +"""Support for transport.opendata.ch.""" from datetime import timedelta import logging diff --git a/homeassistant/components/swisscom/device_tracker.py b/homeassistant/components/swisscom/device_tracker.py index d5826ecedff..7371762da92 100644 --- a/homeassistant/components/swisscom/device_tracker.py +++ b/homeassistant/components/swisscom/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Swisscom routers (Internet-Box). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.swisscom/ -""" +"""Support for Swisscom routers (Internet-Box).""" import logging from aiohttp.hdrs import CONTENT_TYPE diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index d517f635a92..7e89a5369c8 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -1,9 +1,4 @@ -""" -Component to interface with various switches that can be controlled remotely. - -For more details about this component, please refer to the documentation -at https://home-assistant.io/components/switch/ -""" +"""Component to interface with switches that can be controlled remotely.""" from datetime import timedelta import logging diff --git a/homeassistant/components/switch/light.py b/homeassistant/components/switch/light.py index 64f8779e4ab..8f9e489bd9c 100644 --- a/homeassistant/components/switch/light.py +++ b/homeassistant/components/switch/light.py @@ -1,9 +1,4 @@ -""" -Light support for switch entities. - -For more information about this platform, please refer to the documentation at -https://home-assistant.io/components/light.switch/ -""" +"""Light support for switch entities.""" import logging import voluptuous as vol diff --git a/homeassistant/components/switchmate/switch.py b/homeassistant/components/switchmate/switch.py index 60497e0207b..c14a6ca8087 100644 --- a/homeassistant/components/switchmate/switch.py +++ b/homeassistant/components/switchmate/switch.py @@ -1,9 +1,4 @@ -""" -Support for Switchmate. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.switchmate/ -""" +"""Support for Switchmate.""" import logging from datetime import timedelta diff --git a/homeassistant/components/syncthru/sensor.py b/homeassistant/components/syncthru/sensor.py index 862efb63fd7..5596d4ab86a 100644 --- a/homeassistant/components/syncthru/sensor.py +++ b/homeassistant/components/syncthru/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Samsung Printers with SyncThru web interface. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.syncthru/ -""" +"""Support for Samsung Printers with SyncThru web interface.""" import logging import voluptuous as vol diff --git a/homeassistant/components/synology/camera.py b/homeassistant/components/synology/camera.py index b094cf98edf..c452f60cc2a 100644 --- a/homeassistant/components/synology/camera.py +++ b/homeassistant/components/synology/camera.py @@ -1,9 +1,4 @@ -""" -Support for Synology Surveillance Station Cameras. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.synology/ -""" +"""Support for Synology Surveillance Station Cameras.""" import logging import requests diff --git a/homeassistant/components/synology_chat/notify.py b/homeassistant/components/synology_chat/notify.py index 32277dc1971..8f2f654da3c 100644 --- a/homeassistant/components/synology_chat/notify.py +++ b/homeassistant/components/synology_chat/notify.py @@ -1,9 +1,4 @@ -""" -SynologyChat platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.synology_chat/ -""" +"""SynologyChat platform for notify component.""" import json import logging diff --git a/homeassistant/components/syslog/notify.py b/homeassistant/components/syslog/notify.py index 740148e28e5..2e6c3bf6123 100644 --- a/homeassistant/components/syslog/notify.py +++ b/homeassistant/components/syslog/notify.py @@ -1,9 +1,4 @@ -""" -Syslog notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.syslog/ -""" +"""Syslog notification service.""" import logging import voluptuous as vol diff --git a/homeassistant/components/sytadin/sensor.py b/homeassistant/components/sytadin/sensor.py index f8ef18fcffe..517deda7ca2 100644 --- a/homeassistant/components/sytadin/sensor.py +++ b/homeassistant/components/sytadin/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Sytadin Traffic, French Traffic Supervision. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.sytadin/ -""" +"""Support for Sytadin Traffic, French Traffic Supervision.""" import logging import re from datetime import timedelta diff --git a/homeassistant/components/tank_utility/sensor.py b/homeassistant/components/tank_utility/sensor.py index c807f1aa4c7..5389d60ef46 100644 --- a/homeassistant/components/tank_utility/sensor.py +++ b/homeassistant/components/tank_utility/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Tank Utility propane monitor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.tank_utility/ -""" +"""Support for the Tank Utility propane monitor.""" import datetime import logging diff --git a/homeassistant/components/tapsaff/binary_sensor.py b/homeassistant/components/tapsaff/binary_sensor.py index 1978a127c17..639e9574ed9 100644 --- a/homeassistant/components/tapsaff/binary_sensor.py +++ b/homeassistant/components/tapsaff/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for Taps Affs. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.tapsaff/ -""" +"""Support for Taps Affs.""" from datetime import timedelta import logging diff --git a/homeassistant/components/tautulli/sensor.py b/homeassistant/components/tautulli/sensor.py index 5c48731f7df..44be10749bf 100644 --- a/homeassistant/components/tautulli/sensor.py +++ b/homeassistant/components/tautulli/sensor.py @@ -1,9 +1,4 @@ -""" -A platform which allows you to get information from Tautulli. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/sensor.tautulli/ -""" +"""A platform which allows you to get information from Tautulli.""" from datetime import timedelta import logging diff --git a/homeassistant/components/tcp/binary_sensor.py b/homeassistant/components/tcp/binary_sensor.py index 80d77cd52a1..4d26d819ede 100644 --- a/homeassistant/components/tcp/binary_sensor.py +++ b/homeassistant/components/tcp/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Provides a binary sensor which gets its values from a TCP socket. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.tcp/ -""" +"""Provides a binary sensor which gets its values from a TCP socket.""" import logging from homeassistant.components.binary_sensor import BinarySensorDevice diff --git a/homeassistant/components/tcp/sensor.py b/homeassistant/components/tcp/sensor.py index d214bd3d425..6788848df07 100644 --- a/homeassistant/components/tcp/sensor.py +++ b/homeassistant/components/tcp/sensor.py @@ -1,9 +1,4 @@ -""" -Support for TCP socket based sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.tcp/ -""" +"""Support for TCP socket based sensors.""" import logging import socket import select diff --git a/homeassistant/components/ted5000/sensor.py b/homeassistant/components/ted5000/sensor.py index 23a20b3e830..fba9866302d 100644 --- a/homeassistant/components/ted5000/sensor.py +++ b/homeassistant/components/ted5000/sensor.py @@ -1,9 +1,4 @@ -""" -Support gathering ted500 information. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.ted5000/ -""" +"""Support gathering ted500 information.""" import logging from datetime import timedelta diff --git a/homeassistant/components/teksavvy/sensor.py b/homeassistant/components/teksavvy/sensor.py index 0be18cbd6b6..de74ceda9f5 100644 --- a/homeassistant/components/teksavvy/sensor.py +++ b/homeassistant/components/teksavvy/sensor.py @@ -1,9 +1,4 @@ -""" -Support for TekSavvy Bandwidth Monitor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.teksavvy/ -""" +"""Support for TekSavvy Bandwidth Monitor.""" from datetime import timedelta import logging import async_timeout diff --git a/homeassistant/components/telegram/notify.py b/homeassistant/components/telegram/notify.py index 428c7e093d2..3602bbd2441 100644 --- a/homeassistant/components/telegram/notify.py +++ b/homeassistant/components/telegram/notify.py @@ -1,9 +1,4 @@ -""" -Telegram platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.telegram/ -""" +"""Telegram platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/telnet/switch.py b/homeassistant/components/telnet/switch.py index 7c3baf2981a..6ad7e7b43a9 100644 --- a/homeassistant/components/telnet/switch.py +++ b/homeassistant/components/telnet/switch.py @@ -1,9 +1,4 @@ -""" -Support for switch controlled using a telnet connection. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.telnet/ -""" +"""Support for switch controlled using a telnet connection.""" from datetime import timedelta import logging import telnetlib diff --git a/homeassistant/components/temper/sensor.py b/homeassistant/components/temper/sensor.py index 72184df7c8f..1c6cb9fdff4 100644 --- a/homeassistant/components/temper/sensor.py +++ b/homeassistant/components/temper/sensor.py @@ -1,9 +1,4 @@ -""" -Support for getting temperature from TEMPer devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.temper/ -""" +"""Support for getting temperature from TEMPer devices.""" import logging import voluptuous as vol diff --git a/homeassistant/components/template/binary_sensor.py b/homeassistant/components/template/binary_sensor.py index 605ab24a264..bd9c4dfc698 100644 --- a/homeassistant/components/template/binary_sensor.py +++ b/homeassistant/components/template/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for exposing a templated binary sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.template/ -""" +"""Support for exposing a templated binary sensor.""" import logging import voluptuous as vol diff --git a/homeassistant/components/template/cover.py b/homeassistant/components/template/cover.py index 1d3642a6036..2fdcc9f1036 100644 --- a/homeassistant/components/template/cover.py +++ b/homeassistant/components/template/cover.py @@ -1,9 +1,4 @@ -""" -Support for covers which integrate with other components. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/cover.template/ -""" +"""Support for covers which integrate with other components.""" import logging import voluptuous as vol diff --git a/homeassistant/components/template/fan.py b/homeassistant/components/template/fan.py index d9182b79a40..cc6505d22f7 100644 --- a/homeassistant/components/template/fan.py +++ b/homeassistant/components/template/fan.py @@ -1,9 +1,4 @@ -""" -Support for Template fans. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/fan.template/ -""" +"""Support for Template fans.""" import logging import voluptuous as vol diff --git a/homeassistant/components/template/light.py b/homeassistant/components/template/light.py index bf930dd1b38..980f0ad152c 100644 --- a/homeassistant/components/template/light.py +++ b/homeassistant/components/template/light.py @@ -1,9 +1,4 @@ -""" -Support for Template lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.template/ -""" +"""Support for Template lights.""" import logging import voluptuous as vol diff --git a/homeassistant/components/template/lock.py b/homeassistant/components/template/lock.py index 527af4c5b85..ad5d0c4aea7 100644 --- a/homeassistant/components/template/lock.py +++ b/homeassistant/components/template/lock.py @@ -1,9 +1,4 @@ -""" -Support for locks which integrates with other components. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/lock.template/ -""" +"""Support for locks which integrates with other components.""" import logging import voluptuous as vol diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index 5f3af4a06a4..41dc6f8aeeb 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -1,9 +1,4 @@ -""" -Allows the creation of a sensor that breaks out state_attributes. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.template/ -""" +"""Allows the creation of a sensor that breaks out state_attributes.""" import logging from typing import Optional diff --git a/homeassistant/components/template/switch.py b/homeassistant/components/template/switch.py index a2098c2f5fd..541bfd3bcfe 100644 --- a/homeassistant/components/template/switch.py +++ b/homeassistant/components/template/switch.py @@ -1,9 +1,4 @@ -""" -Support for switches which integrates with other components. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.template/ -""" +"""Support for switches which integrates with other components.""" import logging import voluptuous as vol diff --git a/homeassistant/components/thomson/device_tracker.py b/homeassistant/components/thomson/device_tracker.py index 8a56fcee702..bbce443696d 100644 --- a/homeassistant/components/thomson/device_tracker.py +++ b/homeassistant/components/thomson/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for THOMSON routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.thomson/ -""" +"""Support for THOMSON routers.""" import logging import re import telnetlib diff --git a/homeassistant/components/threshold/binary_sensor.py b/homeassistant/components/threshold/binary_sensor.py index 0dadf3a61fd..916a5b968b2 100644 --- a/homeassistant/components/threshold/binary_sensor.py +++ b/homeassistant/components/threshold/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring if a sensor value is below/above a threshold. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.threshold/ -""" +"""Support for monitoring if a sensor value is below/above a threshold.""" import logging import voluptuous as vol diff --git a/homeassistant/components/tikteck/light.py b/homeassistant/components/tikteck/light.py index 64b4069d98e..4f5596c71be 100644 --- a/homeassistant/components/tikteck/light.py +++ b/homeassistant/components/tikteck/light.py @@ -1,9 +1,4 @@ -""" -Support for Tikteck lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.tikteck/ -""" +"""Support for Tikteck lights.""" import logging import voluptuous as vol diff --git a/homeassistant/components/tile/device_tracker.py b/homeassistant/components/tile/device_tracker.py index 6da520280e2..c471c1e23b4 100644 --- a/homeassistant/components/tile/device_tracker.py +++ b/homeassistant/components/tile/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Tile® Bluetooth trackers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.tile/ -""" +"""Support for Tile® Bluetooth trackers.""" import logging from datetime import timedelta diff --git a/homeassistant/components/time_date/sensor.py b/homeassistant/components/time_date/sensor.py index 7825867df64..5342dc57692 100644 --- a/homeassistant/components/time_date/sensor.py +++ b/homeassistant/components/time_date/sensor.py @@ -1,9 +1,4 @@ -""" -Support for showing the date and the time. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.time_date/ -""" +"""Support for showing the date and the time.""" from datetime import timedelta import logging diff --git a/homeassistant/components/todoist/calendar.py b/homeassistant/components/todoist/calendar.py index a0a3457667f..313935e1221 100644 --- a/homeassistant/components/todoist/calendar.py +++ b/homeassistant/components/todoist/calendar.py @@ -1,9 +1,4 @@ -""" -Support for Todoist task management (https://todoist.com). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/calendar.todoist/ -""" +"""Support for Todoist task management (https://todoist.com).""" from datetime import datetime, timedelta import logging diff --git a/homeassistant/components/tomato/device_tracker.py b/homeassistant/components/tomato/device_tracker.py index 718adad4212..9d0506fe042 100644 --- a/homeassistant/components/tomato/device_tracker.py +++ b/homeassistant/components/tomato/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Tomato routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.tomato/ -""" +"""Support for Tomato routers.""" import json import logging import re diff --git a/homeassistant/components/torque/sensor.py b/homeassistant/components/torque/sensor.py index 4941633677c..2f947c178b8 100644 --- a/homeassistant/components/torque/sensor.py +++ b/homeassistant/components/torque/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Torque OBD application. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.torque/ -""" +"""Support for the Torque OBD application.""" import logging import re diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index a272a22abe5..c56c4ed95a6 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Interfaces with TotalConnect alarm control panels. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/alarm_control_panel.totalconnect/ -""" +"""Interfaces with TotalConnect alarm control panels.""" import logging import voluptuous as vol diff --git a/homeassistant/components/touchline/climate.py b/homeassistant/components/touchline/climate.py index fa38bd37c8f..e003ea257d7 100644 --- a/homeassistant/components/touchline/climate.py +++ b/homeassistant/components/touchline/climate.py @@ -1,9 +1,4 @@ -""" -Platform for Roth Touchline heat pump controller. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/climate.touchline/ -""" +"""Platform for Roth Touchline heat pump controller.""" import logging import voluptuous as vol diff --git a/homeassistant/components/tplink/device_tracker.py b/homeassistant/components/tplink/device_tracker.py index 33a5d5f32f8..7f5c4a37d24 100644 --- a/homeassistant/components/tplink/device_tracker.py +++ b/homeassistant/components/tplink/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for TP-Link routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.tplink/ -""" +"""Support for TP-Link routers.""" import base64 from datetime import datetime import hashlib diff --git a/homeassistant/components/tplink/light.py b/homeassistant/components/tplink/light.py index 0ba1dfaa33a..9f13766c4ef 100644 --- a/homeassistant/components/tplink/light.py +++ b/homeassistant/components/tplink/light.py @@ -1,9 +1,4 @@ -""" -Support for TPLink lights. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/light.tplink/ -""" +"""Support for TPLink lights.""" import logging import time diff --git a/homeassistant/components/tplink/switch.py b/homeassistant/components/tplink/switch.py index a75945e9956..a4eeadd1c60 100644 --- a/homeassistant/components/tplink/switch.py +++ b/homeassistant/components/tplink/switch.py @@ -1,9 +1,4 @@ -""" -Support for TPLink HS100/HS110/HS200 smart switch. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.tplink/ -""" +"""Support for TPLink HS100/HS110/HS200 smart switch.""" import logging import time diff --git a/homeassistant/components/traccar/device_tracker.py b/homeassistant/components/traccar/device_tracker.py index e3ac1427941..28d13dd4fe6 100644 --- a/homeassistant/components/traccar/device_tracker.py +++ b/homeassistant/components/traccar/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Traccar device tracking. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.traccar/ -""" +"""Support for Traccar device tracking.""" from datetime import datetime, timedelta import logging diff --git a/homeassistant/components/trackr/device_tracker.py b/homeassistant/components/trackr/device_tracker.py index 08d3a4c9445..1322fde7e1a 100644 --- a/homeassistant/components/trackr/device_tracker.py +++ b/homeassistant/components/trackr/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for the TrackR platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.trackr/ -""" +"""Support for the TrackR platform.""" import logging import voluptuous as vol diff --git a/homeassistant/components/trafikverket_weatherstation/sensor.py b/homeassistant/components/trafikverket_weatherstation/sensor.py index 2dffd580b7e..bf8f4c803e0 100644 --- a/homeassistant/components/trafikverket_weatherstation/sensor.py +++ b/homeassistant/components/trafikverket_weatherstation/sensor.py @@ -1,9 +1,4 @@ -""" -Weather information for air and road temperature, provided by Trafikverket. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.trafikverket_weatherstation/ -""" +"""Weather information for air and road temperature (by Trafikverket).""" import asyncio from datetime import timedelta diff --git a/homeassistant/components/travisci/sensor.py b/homeassistant/components/travisci/sensor.py index c96bb18e958..99309f7e2b7 100644 --- a/homeassistant/components/travisci/sensor.py +++ b/homeassistant/components/travisci/sensor.py @@ -1,9 +1,4 @@ -""" -This component provides HA sensor support for Travis CI framework. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.travisci/ -""" +"""This component provides HA sensor support for Travis CI framework.""" import logging from datetime import timedelta diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py index 0cd4a1bb6c6..763baa262be 100644 --- a/homeassistant/components/tts/__init__.py +++ b/homeassistant/components/tts/__init__.py @@ -1,9 +1,4 @@ -""" -Provide functionality to TTS. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/tts/ -""" +"""Provide functionality to TTS.""" import asyncio import ctypes import functools as ft diff --git a/homeassistant/components/twilio_call/notify.py b/homeassistant/components/twilio_call/notify.py index a1a28a03b18..ab57d721465 100644 --- a/homeassistant/components/twilio_call/notify.py +++ b/homeassistant/components/twilio_call/notify.py @@ -1,9 +1,4 @@ -""" -Twilio Call platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.twilio_call/ -""" +"""Twilio Call platform for notify component.""" import logging import urllib diff --git a/homeassistant/components/twilio_sms/notify.py b/homeassistant/components/twilio_sms/notify.py index b3b35ea1789..a04e397a568 100644 --- a/homeassistant/components/twilio_sms/notify.py +++ b/homeassistant/components/twilio_sms/notify.py @@ -1,9 +1,4 @@ -""" -Twilio SMS platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.twilio_sms/ -""" +"""Twilio SMS platform for notify component.""" import logging import voluptuous as vol diff --git a/homeassistant/components/twitch/sensor.py b/homeassistant/components/twitch/sensor.py index 3e00f799dcf..123de752d51 100644 --- a/homeassistant/components/twitch/sensor.py +++ b/homeassistant/components/twitch/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Twitch stream status. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.twitch/ -""" +"""Support for the Twitch stream status.""" import logging import voluptuous as vol diff --git a/homeassistant/components/twitter/notify.py b/homeassistant/components/twitter/notify.py index 9172da36785..54cd591f394 100644 --- a/homeassistant/components/twitter/notify.py +++ b/homeassistant/components/twitter/notify.py @@ -1,9 +1,4 @@ -""" -Twitter platform for notify component. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.twitter/ -""" +"""Twitter platform for notify component.""" from datetime import datetime, timedelta from functools import partial import json diff --git a/homeassistant/components/ubee/device_tracker.py b/homeassistant/components/ubee/device_tracker.py index f4ecc7d4855..bbe028bbb78 100644 --- a/homeassistant/components/ubee/device_tracker.py +++ b/homeassistant/components/ubee/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Ubee router. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.ubee/ -""" +"""Support for Ubee router.""" import logging import voluptuous as vol diff --git a/homeassistant/components/uber/sensor.py b/homeassistant/components/uber/sensor.py index a97ccaffed0..87d87de66ee 100644 --- a/homeassistant/components/uber/sensor.py +++ b/homeassistant/components/uber/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Uber API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.uber/ -""" +"""Support for the Uber API.""" import logging from datetime import timedelta diff --git a/homeassistant/components/ubus/device_tracker.py b/homeassistant/components/ubus/device_tracker.py index 96f2f60c1e5..54572524fb2 100644 --- a/homeassistant/components/ubus/device_tracker.py +++ b/homeassistant/components/ubus/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for OpenWRT (ubus) routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.ubus/ -""" +"""Support for OpenWRT (ubus) routers.""" import json import logging import re diff --git a/homeassistant/components/ue_smart_radio/media_player.py b/homeassistant/components/ue_smart_radio/media_player.py index 2261aadc2f6..0d1f17e10ec 100644 --- a/homeassistant/components/ue_smart_radio/media_player.py +++ b/homeassistant/components/ue_smart_radio/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Logitech UE Smart Radios. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.ue_smart_radio/ -""" +"""Support for Logitech UE Smart Radios.""" import logging diff --git a/homeassistant/components/unifi/device_tracker.py b/homeassistant/components/unifi/device_tracker.py index 2dc5f7a4df3..49e28114b17 100644 --- a/homeassistant/components/unifi/device_tracker.py +++ b/homeassistant/components/unifi/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Unifi WAP controllers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.unifi/ -""" +"""Support for Unifi WAP controllers.""" import logging from datetime import timedelta import voluptuous as vol diff --git a/homeassistant/components/unifi_direct/device_tracker.py b/homeassistant/components/unifi_direct/device_tracker.py index bd90099e45c..29a3c58fab9 100644 --- a/homeassistant/components/unifi_direct/device_tracker.py +++ b/homeassistant/components/unifi_direct/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Unifi AP direct access. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.unifi_direct/ -""" +"""Support for Unifi AP direct access.""" import logging import json diff --git a/homeassistant/components/universal/media_player.py b/homeassistant/components/universal/media_player.py index 5730a086731..69af20917c5 100644 --- a/homeassistant/components/universal/media_player.py +++ b/homeassistant/components/universal/media_player.py @@ -1,9 +1,4 @@ -""" -Combination of multiple media players into one for a universal controller. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.universal/ -""" +"""Combination of multiple media players for a universal controller.""" from copy import copy import logging diff --git a/homeassistant/components/upc_connect/device_tracker.py b/homeassistant/components/upc_connect/device_tracker.py index 2ee6d64730d..4a583b8349a 100644 --- a/homeassistant/components/upc_connect/device_tracker.py +++ b/homeassistant/components/upc_connect/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for UPC ConnectBox router. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.upc_connect/ -""" +"""Support for UPC ConnectBox router.""" import asyncio import logging diff --git a/homeassistant/components/upnp/sensor.py b/homeassistant/components/upnp/sensor.py index 708ef314ab4..86bcee879b9 100644 --- a/homeassistant/components/upnp/sensor.py +++ b/homeassistant/components/upnp/sensor.py @@ -1,9 +1,4 @@ -""" -Support for UPnP/IGD Sensors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.upnp/ -""" +"""Support for UPnP/IGD Sensors.""" from datetime import datetime import logging diff --git a/homeassistant/components/ups/sensor.py b/homeassistant/components/ups/sensor.py index e4aab555050..f338e990b00 100644 --- a/homeassistant/components/ups/sensor.py +++ b/homeassistant/components/ups/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for UPS packages. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.ups/ -""" +"""Sensor for UPS packages.""" from collections import defaultdict import logging from datetime import timedelta diff --git a/homeassistant/components/uptime/sensor.py b/homeassistant/components/uptime/sensor.py index 197233461fb..7e741499f73 100644 --- a/homeassistant/components/uptime/sensor.py +++ b/homeassistant/components/uptime/sensor.py @@ -1,9 +1,4 @@ -""" -Platform to retrieve uptime for Home Assistant. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.uptime/ -""" +"""Platform to retrieve uptime for Home Assistant.""" import logging import voluptuous as vol diff --git a/homeassistant/components/uptimerobot/binary_sensor.py b/homeassistant/components/uptimerobot/binary_sensor.py index e48ac3039ae..8e11966b680 100644 --- a/homeassistant/components/uptimerobot/binary_sensor.py +++ b/homeassistant/components/uptimerobot/binary_sensor.py @@ -1,9 +1,4 @@ -""" -A platform that to monitor Uptime Robot monitors. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/binary_sensor.uptimerobot/ -""" +"""A platform that to monitor Uptime Robot monitors.""" import logging import voluptuous as vol diff --git a/homeassistant/components/uscis/sensor.py b/homeassistant/components/uscis/sensor.py index e3a917b0a5a..501c6c9665c 100644 --- a/homeassistant/components/uscis/sensor.py +++ b/homeassistant/components/uscis/sensor.py @@ -1,9 +1,4 @@ -""" -Support for USCIS Case Status. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.uscis/ -""" +"""Support for USCIS Case Status.""" import logging from datetime import timedelta diff --git a/homeassistant/components/uvc/camera.py b/homeassistant/components/uvc/camera.py index 50e7c3d8fe2..65251054060 100644 --- a/homeassistant/components/uvc/camera.py +++ b/homeassistant/components/uvc/camera.py @@ -1,9 +1,4 @@ -""" -Support for Ubiquiti's UVC cameras. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.uvc/ -""" +"""Support for Ubiquiti's UVC cameras.""" import logging import socket diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 3fdc7cb1a51..02266986ccf 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -1,9 +1,4 @@ -""" -Support for vacuum cleaner robots (botvacs). - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/vacuum/ -""" +"""Support for vacuum cleaner robots (botvacs).""" from datetime import timedelta from functools import partial import logging diff --git a/homeassistant/components/vasttrafik/sensor.py b/homeassistant/components/vasttrafik/sensor.py index 8148a5c2fc7..d8e9f1e7675 100644 --- a/homeassistant/components/vasttrafik/sensor.py +++ b/homeassistant/components/vasttrafik/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Västtrafik public transport. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.vasttrafik/ -""" +"""Support for Västtrafik public transport.""" from datetime import datetime from datetime import timedelta import logging diff --git a/homeassistant/components/venstar/climate.py b/homeassistant/components/venstar/climate.py index 820443ee186..f3e7542af5c 100644 --- a/homeassistant/components/venstar/climate.py +++ b/homeassistant/components/venstar/climate.py @@ -1,9 +1,4 @@ -""" -Support for Venstar WiFi Thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.venstar/ -""" +"""Support for Venstar WiFi Thermostats.""" import logging import voluptuous as vol diff --git a/homeassistant/components/version/sensor.py b/homeassistant/components/version/sensor.py index 8a2a7593b2c..6982b77a51a 100644 --- a/homeassistant/components/version/sensor.py +++ b/homeassistant/components/version/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor that can display the current Home Assistant versions. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.version/ -""" +"""Sensor that can display the current Home Assistant versions.""" import logging from datetime import timedelta diff --git a/homeassistant/components/vesync/switch.py b/homeassistant/components/vesync/switch.py index d9ffbf9c12d..d37728624ef 100644 --- a/homeassistant/components/vesync/switch.py +++ b/homeassistant/components/vesync/switch.py @@ -1,9 +1,4 @@ -""" -Support for Etekcity VeSync switches. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.vesync/ -""" +"""Support for Etekcity VeSync switches.""" import logging import voluptuous as vol from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) diff --git a/homeassistant/components/viaggiatreno/sensor.py b/homeassistant/components/viaggiatreno/sensor.py index 2b8de2042fa..ee939d4a594 100644 --- a/homeassistant/components/viaggiatreno/sensor.py +++ b/homeassistant/components/viaggiatreno/sensor.py @@ -1,9 +1,4 @@ -""" -Support for information about the Italian train system using ViaggiaTreno API. - -For more details about this platform please refer to the documentation at -https://home-assistant.io/components/sensor.viaggiatreno -""" +"""Support for the Italian train system using ViaggiaTreno API.""" import asyncio import logging diff --git a/homeassistant/components/vizio/media_player.py b/homeassistant/components/vizio/media_player.py index af3fdd1e15a..bab54c68a90 100644 --- a/homeassistant/components/vizio/media_player.py +++ b/homeassistant/components/vizio/media_player.py @@ -1,9 +1,4 @@ -""" -Vizio SmartCast TV support. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.vizio/ -""" +"""Vizio SmartCast TV support.""" from datetime import timedelta import logging diff --git a/homeassistant/components/vlc/media_player.py b/homeassistant/components/vlc/media_player.py index 592243938d7..41f9b5b16d4 100644 --- a/homeassistant/components/vlc/media_player.py +++ b/homeassistant/components/vlc/media_player.py @@ -1,9 +1,4 @@ -""" -Provide functionality to interact with vlc devices on the network. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.vlc/ -""" +"""Provide functionality to interact with vlc devices on the network.""" import logging import voluptuous as vol diff --git a/homeassistant/components/voicerss/tts.py b/homeassistant/components/voicerss/tts.py index 436f070e503..d5340e45b5c 100644 --- a/homeassistant/components/voicerss/tts.py +++ b/homeassistant/components/voicerss/tts.py @@ -1,9 +1,4 @@ -""" -Support for the voicerss speech service. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/tts.voicerss/ -""" +"""Support for the voicerss speech service.""" import asyncio import logging diff --git a/homeassistant/components/volkszaehler/sensor.py b/homeassistant/components/volkszaehler/sensor.py index e67d9d6424a..5b808ff3c38 100644 --- a/homeassistant/components/volkszaehler/sensor.py +++ b/homeassistant/components/volkszaehler/sensor.py @@ -1,9 +1,4 @@ -""" -Support for consuming values for the Volkszaehler API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.volkszaehler/ -""" +"""Support for consuming values for the Volkszaehler API.""" from datetime import timedelta import logging diff --git a/homeassistant/components/vultr/binary_sensor.py b/homeassistant/components/vultr/binary_sensor.py index dccb648c9c2..87e8e93bda7 100644 --- a/homeassistant/components/vultr/binary_sensor.py +++ b/homeassistant/components/vultr/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring the state of Vultr subscriptions (VPS). - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.vultr/ -""" +"""Support for monitoring the state of Vultr subscriptions (VPS).""" import logging import voluptuous as vol diff --git a/homeassistant/components/vultr/sensor.py b/homeassistant/components/vultr/sensor.py index 7ca731cabac..f7e03dddace 100644 --- a/homeassistant/components/vultr/sensor.py +++ b/homeassistant/components/vultr/sensor.py @@ -1,9 +1,4 @@ -""" -Support for monitoring the state of Vultr Subscriptions. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.vultr/ -""" +"""Support for monitoring the state of Vultr Subscriptions.""" import logging import voluptuous as vol diff --git a/homeassistant/components/vultr/switch.py b/homeassistant/components/vultr/switch.py index 1f7d9ceaa28..502aaf9daa8 100644 --- a/homeassistant/components/vultr/switch.py +++ b/homeassistant/components/vultr/switch.py @@ -1,9 +1,4 @@ -""" -Support for interacting with Vultr subscriptions. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/switch.vultr/ -""" +"""Support for interacting with Vultr subscriptions.""" import logging import voluptuous as vol diff --git a/homeassistant/components/wake_on_lan/switch.py b/homeassistant/components/wake_on_lan/switch.py index 16bd700e1d5..c81a476f0f8 100644 --- a/homeassistant/components/wake_on_lan/switch.py +++ b/homeassistant/components/wake_on_lan/switch.py @@ -1,9 +1,4 @@ -""" -Support for wake on lan. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/switch.wake_on_lan/ -""" +"""Support for wake on lan.""" import logging import platform import subprocess as sp diff --git a/homeassistant/components/waqi/sensor.py b/homeassistant/components/waqi/sensor.py index d6b8d278fb1..f3000890de6 100644 --- a/homeassistant/components/waqi/sensor.py +++ b/homeassistant/components/waqi/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the World Air Quality Index service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.waqi/ -""" +"""Support for the World Air Quality Index service.""" import asyncio import logging from datetime import timedelta diff --git a/homeassistant/components/waterfurnace/sensor.py b/homeassistant/components/waterfurnace/sensor.py index 8a43a7dac77..8b1fc46312c 100644 --- a/homeassistant/components/waterfurnace/sensor.py +++ b/homeassistant/components/waterfurnace/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Waterfurnace. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.waterfurnace/ -""" +"""Support for Waterfurnace.""" from homeassistant.components.sensor import ENTITY_ID_FORMAT from homeassistant.const import TEMP_FAHRENHEIT diff --git a/homeassistant/components/waze_travel_time/sensor.py b/homeassistant/components/waze_travel_time/sensor.py index 96a4c747293..984a5800898 100644 --- a/homeassistant/components/waze_travel_time/sensor.py +++ b/homeassistant/components/waze_travel_time/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Waze travel time sensor. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.waze_travel_time/ -""" +"""Support for Waze travel time sensor.""" from datetime import timedelta import logging diff --git a/homeassistant/components/whois/sensor.py b/homeassistant/components/whois/sensor.py index 3685652387a..e36bdea08c3 100644 --- a/homeassistant/components/whois/sensor.py +++ b/homeassistant/components/whois/sensor.py @@ -1,9 +1,4 @@ -""" -Get WHOIS information for a given host. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.whois/ -""" +"""Get WHOIS information for a given host.""" from datetime import timedelta import logging diff --git a/homeassistant/components/worldclock/sensor.py b/homeassistant/components/worldclock/sensor.py index 6bb5d1fee2e..1fdf97b7088 100644 --- a/homeassistant/components/worldclock/sensor.py +++ b/homeassistant/components/worldclock/sensor.py @@ -1,9 +1,4 @@ -""" -Support for showing the time in a different time zone. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.worldclock/ -""" +"""Support for showing the time in a different time zone.""" import logging import voluptuous as vol diff --git a/homeassistant/components/worldtidesinfo/sensor.py b/homeassistant/components/worldtidesinfo/sensor.py index 0f7bfeaa900..1a1e349feee 100644 --- a/homeassistant/components/worldtidesinfo/sensor.py +++ b/homeassistant/components/worldtidesinfo/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the worldtides.info API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.worldtidesinfo/ -""" +"""Support for the worldtides.info API.""" from datetime import timedelta import logging import time diff --git a/homeassistant/components/worxlandroid/sensor.py b/homeassistant/components/worxlandroid/sensor.py index be5c8452d88..fa4fcc96c12 100644 --- a/homeassistant/components/worxlandroid/sensor.py +++ b/homeassistant/components/worxlandroid/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Worx Landroid mower. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.worxlandroid/ -""" +"""Support for Worx Landroid mower.""" import logging import asyncio diff --git a/homeassistant/components/wsdot/sensor.py b/homeassistant/components/wsdot/sensor.py index 4e53a2c17c4..3c3e9300a02 100644 --- a/homeassistant/components/wsdot/sensor.py +++ b/homeassistant/components/wsdot/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Washington State Department of Transportation (WSDOT) data. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.wsdot/ -""" +"""Support for Washington State Department of Transportation (WSDOT) data.""" import logging import re from datetime import datetime, timezone, timedelta diff --git a/homeassistant/components/wunderground/sensor.py b/homeassistant/components/wunderground/sensor.py index 74a4c2089b2..7ad1a6fd75a 100644 --- a/homeassistant/components/wunderground/sensor.py +++ b/homeassistant/components/wunderground/sensor.py @@ -1,9 +1,4 @@ -""" -Support for WUnderground weather service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.wunderground/ -""" +"""Support for WUnderground weather service.""" import asyncio from datetime import timedelta import logging diff --git a/homeassistant/components/x10/light.py b/homeassistant/components/x10/light.py index 9618a13a1a9..6c8c5f3fe6f 100644 --- a/homeassistant/components/x10/light.py +++ b/homeassistant/components/x10/light.py @@ -1,9 +1,4 @@ -""" -Support for X10 lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.x10/ -""" +"""Support for X10 lights.""" import logging from subprocess import check_output, CalledProcessError, STDOUT diff --git a/homeassistant/components/xbox_live/sensor.py b/homeassistant/components/xbox_live/sensor.py index 9670b4b2f9c..9f8a02686ac 100644 --- a/homeassistant/components/xbox_live/sensor.py +++ b/homeassistant/components/xbox_live/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for Xbox Live account status. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.xbox_live/ -""" +"""Sensor for Xbox Live account status.""" import logging import voluptuous as vol diff --git a/homeassistant/components/xeoma/camera.py b/homeassistant/components/xeoma/camera.py index 74532a935fc..dd0ee432707 100644 --- a/homeassistant/components/xeoma/camera.py +++ b/homeassistant/components/xeoma/camera.py @@ -1,9 +1,4 @@ -""" -Support for Xeoma Cameras. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.xeoma/ -""" +"""Support for Xeoma Cameras.""" import logging import voluptuous as vol diff --git a/homeassistant/components/xiaomi/camera.py b/homeassistant/components/xiaomi/camera.py index b0acf50ec8c..98e54d2bc73 100644 --- a/homeassistant/components/xiaomi/camera.py +++ b/homeassistant/components/xiaomi/camera.py @@ -1,9 +1,4 @@ -""" -This component provides support for Xiaomi Cameras. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.xiaomi/ -""" +"""This component provides support for Xiaomi Cameras.""" import asyncio import logging diff --git a/homeassistant/components/xiaomi/device_tracker.py b/homeassistant/components/xiaomi/device_tracker.py index 12e64b724dd..6c588271c9b 100644 --- a/homeassistant/components/xiaomi/device_tracker.py +++ b/homeassistant/components/xiaomi/device_tracker.py @@ -1,9 +1,4 @@ -""" -Support for Xiaomi Mi routers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.xiaomi/ -""" +"""Support for Xiaomi Mi routers.""" import logging import requests diff --git a/homeassistant/components/xiaomi_tv/media_player.py b/homeassistant/components/xiaomi_tv/media_player.py index e3b25c3c31f..2c8a2e1ea83 100644 --- a/homeassistant/components/xiaomi_tv/media_player.py +++ b/homeassistant/components/xiaomi_tv/media_player.py @@ -1,9 +1,4 @@ -""" -Add support for the Xiaomi TVs. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/xiaomi_tv/ -""" +"""Add support for the Xiaomi TVs.""" import logging import voluptuous as vol diff --git a/homeassistant/components/xmpp/notify.py b/homeassistant/components/xmpp/notify.py index 5a14046bd41..d8036f5ee1e 100644 --- a/homeassistant/components/xmpp/notify.py +++ b/homeassistant/components/xmpp/notify.py @@ -1,9 +1,4 @@ -""" -Jabber (XMPP) notification service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.xmpp/ -""" +"""Jabber (XMPP) notification service.""" from concurrent.futures import TimeoutError as FutTimeoutError import logging import mimetypes diff --git a/homeassistant/components/yale_smart_alarm/alarm_control_panel.py b/homeassistant/components/yale_smart_alarm/alarm_control_panel.py index 67b74033442..1a8e03a6363 100755 --- a/homeassistant/components/yale_smart_alarm/alarm_control_panel.py +++ b/homeassistant/components/yale_smart_alarm/alarm_control_panel.py @@ -1,9 +1,4 @@ -""" -Yale Smart Alarm client for interacting with the Yale Smart Alarm System API. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/alarm_control_panel.yale_smart_alarm -""" +"""Component for interacting with the Yale Smart Alarm System API.""" import logging import voluptuous as vol diff --git a/homeassistant/components/yamaha/media_player.py b/homeassistant/components/yamaha/media_player.py index f652d95e713..53c6b466f6e 100644 --- a/homeassistant/components/yamaha/media_player.py +++ b/homeassistant/components/yamaha/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Yamaha Receivers. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.yamaha/ -""" +"""Support for Yamaha Receivers.""" import logging import requests diff --git a/homeassistant/components/yamaha_musiccast/media_player.py b/homeassistant/components/yamaha_musiccast/media_player.py index 6aa06b604c5..94002a4cc55 100644 --- a/homeassistant/components/yamaha_musiccast/media_player.py +++ b/homeassistant/components/yamaha_musiccast/media_player.py @@ -1,9 +1,4 @@ -""" -Support for Yamaha MusicCast Receivers. - -For more details about this platform, please refer to the documentation at -https://www.home-assistant.io/components/media_player.yamaha_musiccast/ -""" +"""Support for Yamaha MusicCast Receivers.""" import logging import voluptuous as vol diff --git a/homeassistant/components/yandextts/tts.py b/homeassistant/components/yandextts/tts.py index e60b890e84f..e08f44d1974 100644 --- a/homeassistant/components/yandextts/tts.py +++ b/homeassistant/components/yandextts/tts.py @@ -1,9 +1,4 @@ -""" -Support for the yandex speechkit tts service. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/tts/yandextts/ -""" +"""Support for the yandex speechkit tts service.""" import asyncio import logging diff --git a/homeassistant/components/yeelightsunflower/light.py b/homeassistant/components/yeelightsunflower/light.py index 2250a85c55c..9252143526b 100644 --- a/homeassistant/components/yeelightsunflower/light.py +++ b/homeassistant/components/yeelightsunflower/light.py @@ -1,9 +1,4 @@ -""" -Support for Yeelight Sunflower color bulbs (not Yeelight Blue or WiFi). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.yeelightsunflower/ -""" +"""Support for Yeelight Sunflower color bulbs (not Yeelight Blue or WiFi).""" import logging import voluptuous as vol diff --git a/homeassistant/components/yessssms/notify.py b/homeassistant/components/yessssms/notify.py index 529aa4e7b6e..c229c361e28 100644 --- a/homeassistant/components/yessssms/notify.py +++ b/homeassistant/components/yessssms/notify.py @@ -1,9 +1,4 @@ -""" -Support for the YesssSMS platform. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/notify.yessssms/ -""" +"""Support for the YesssSMS platform.""" import logging import voluptuous as vol diff --git a/homeassistant/components/yi/camera.py b/homeassistant/components/yi/camera.py index f82c8c38129..7ed36b97868 100644 --- a/homeassistant/components/yi/camera.py +++ b/homeassistant/components/yi/camera.py @@ -1,9 +1,4 @@ -""" -This component provides support for Xiaomi Cameras (HiSilicon Hi3518e V200). - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/camera.yi/ -""" +"""Support for Xiaomi Cameras (HiSilicon Hi3518e V200).""" import asyncio import logging diff --git a/homeassistant/components/yr/sensor.py b/homeassistant/components/yr/sensor.py index 665c482f050..4c898a7c9fe 100644 --- a/homeassistant/components/yr/sensor.py +++ b/homeassistant/components/yr/sensor.py @@ -1,9 +1,4 @@ -""" -Support for Yr.no weather service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.yr/ -""" +"""Support for Yr.no weather service.""" import asyncio import logging diff --git a/homeassistant/components/yweather/sensor.py b/homeassistant/components/yweather/sensor.py index 349ee2c7aae..129532ceb57 100644 --- a/homeassistant/components/yweather/sensor.py +++ b/homeassistant/components/yweather/sensor.py @@ -1,9 +1,4 @@ -""" -Support for the Yahoo! Weather service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.yweather/ -""" +"""Support for the Yahoo! Weather service.""" import logging from datetime import timedelta diff --git a/homeassistant/components/zamg/sensor.py b/homeassistant/components/zamg/sensor.py index c101e4da920..9ce5da6fb95 100644 --- a/homeassistant/components/zamg/sensor.py +++ b/homeassistant/components/zamg/sensor.py @@ -1,9 +1,4 @@ -""" -Sensor for data from Austrian "Zentralanstalt für Meteorologie und Geodynamik". - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.zamg/ -""" +"""Sensor for the Austrian "Zentralanstalt für Meteorologie und Geodynamik".""" import csv from datetime import datetime, timedelta import gzip diff --git a/homeassistant/components/zengge/light.py b/homeassistant/components/zengge/light.py index 69ca3da0af9..8bbd56a483e 100644 --- a/homeassistant/components/zengge/light.py +++ b/homeassistant/components/zengge/light.py @@ -1,9 +1,4 @@ -""" -Support for Zengge lights. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/light.zengge/ -""" +"""Support for Zengge lights.""" import logging import voluptuous as vol diff --git a/homeassistant/components/zestimate/sensor.py b/homeassistant/components/zestimate/sensor.py index ed3af84d396..f69e3b16ebe 100644 --- a/homeassistant/components/zestimate/sensor.py +++ b/homeassistant/components/zestimate/sensor.py @@ -1,9 +1,4 @@ -""" -Support for zestimate data from zillow.com. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.zestimate/ -""" +"""Support for zestimate data from zillow.com.""" from datetime import timedelta import logging diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index 088ffff13d1..08362eba082 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -1,9 +1,4 @@ -""" -Support for Zigbee Home Automation devices. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/zha/ -""" +"""Support for Zigbee Home Automation devices.""" import logging import voluptuous as vol diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 2f88ad3a78b..aacb0a711a5 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -1,9 +1,4 @@ -""" -Web socket API for Zigbee Home Automation devices. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/zha/ -""" +"""Web socket API for Zigbee Home Automation devices.""" import asyncio import logging diff --git a/homeassistant/components/zha/binary_sensor.py b/homeassistant/components/zha/binary_sensor.py index 7c08c758af2..b4254eb83e7 100644 --- a/homeassistant/components/zha/binary_sensor.py +++ b/homeassistant/components/zha/binary_sensor.py @@ -1,9 +1,4 @@ -""" -Binary sensors on Zigbee Home Automation networks. - -For more details on this platform, please refer to the documentation -at https://home-assistant.io/components/binary_sensor.zha/ -""" +"""Binary sensors on Zigbee Home Automation networks.""" import logging from homeassistant.components.binary_sensor import DOMAIN, BinarySensorDevice diff --git a/homeassistant/components/zha/const.py b/homeassistant/components/zha/const.py index e7cf424990b..1ccc3e0ea25 100644 --- a/homeassistant/components/zha/const.py +++ b/homeassistant/components/zha/const.py @@ -1,9 +1,4 @@ -""" -Backwards compatible constants bridge. - -For more details on this platform, please refer to the documentation -at https://home-assistant.io/components/fan.zha/ -""" +"""Backwards compatible constants bridge.""" # pylint: disable=W0614,W0401 from .core.const import * # noqa: F401,F403 from .core.registries import * # noqa: F401,F403 diff --git a/homeassistant/components/zha/device_entity.py b/homeassistant/components/zha/device_entity.py index 7563481bbb7..3937e597b78 100644 --- a/homeassistant/components/zha/device_entity.py +++ b/homeassistant/components/zha/device_entity.py @@ -1,9 +1,4 @@ -""" -Device entity for Zigbee Home Automation. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/zha/ -""" +"""Device entity for Zigbee Home Automation.""" import logging import time diff --git a/homeassistant/components/zha/entity.py b/homeassistant/components/zha/entity.py index 1e98118e09f..d894ef5d7a3 100644 --- a/homeassistant/components/zha/entity.py +++ b/homeassistant/components/zha/entity.py @@ -1,9 +1,4 @@ -""" -Entity for Zigbee Home Automation. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/zha/ -""" +"""Entity for Zigbee Home Automation.""" import logging import time diff --git a/homeassistant/components/zha/fan.py b/homeassistant/components/zha/fan.py index 73989ef32b4..b80834af1d7 100644 --- a/homeassistant/components/zha/fan.py +++ b/homeassistant/components/zha/fan.py @@ -1,9 +1,4 @@ -""" -Fans on Zigbee Home Automation networks. - -For more details on this platform, please refer to the documentation -at https://home-assistant.io/components/fan.zha/ -""" +"""Fans on Zigbee Home Automation networks.""" import logging from homeassistant.core import callback diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index 6ba4efa9b0f..573936d6ac2 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -1,9 +1,4 @@ -""" -Lights on Zigbee Home Automation networks. - -For more details on this platform, please refer to the documentation -at https://home-assistant.io/components/light.zha/ -""" +"""Lights on Zigbee Home Automation networks.""" from datetime import timedelta import logging diff --git a/homeassistant/components/zha/sensor.py b/homeassistant/components/zha/sensor.py index d45d8f8c30d..13932d7dd7a 100644 --- a/homeassistant/components/zha/sensor.py +++ b/homeassistant/components/zha/sensor.py @@ -1,9 +1,4 @@ -""" -Sensors on Zigbee Home Automation networks. - -For more details on this platform, please refer to the documentation -at https://home-assistant.io/components/sensor.zha/ -""" +"""Sensors on Zigbee Home Automation networks.""" import logging from homeassistant.core import callback diff --git a/homeassistant/components/zha/switch.py b/homeassistant/components/zha/switch.py index f1bf671a43d..34c9ab2514d 100644 --- a/homeassistant/components/zha/switch.py +++ b/homeassistant/components/zha/switch.py @@ -1,9 +1,4 @@ -""" -Switches on Zigbee Home Automation networks. - -For more details on this platform, please refer to the documentation -at https://home-assistant.io/components/switch.zha/ -""" +"""Switches on Zigbee Home Automation networks.""" import logging from homeassistant.components.switch import DOMAIN, SwitchDevice diff --git a/homeassistant/components/zhong_hong/climate.py b/homeassistant/components/zhong_hong/climate.py index 78cd7d16c48..7fd2b971009 100644 --- a/homeassistant/components/zhong_hong/climate.py +++ b/homeassistant/components/zhong_hong/climate.py @@ -1,9 +1,4 @@ -""" -Support for ZhongHong HVAC Controller. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/climate.zhong_hong/ -""" +"""Support for ZhongHong HVAC Controller.""" import logging import voluptuous as vol diff --git a/homeassistant/components/ziggo_mediabox_xl/media_player.py b/homeassistant/components/ziggo_mediabox_xl/media_player.py index abad22d89eb..574d08e97a4 100644 --- a/homeassistant/components/ziggo_mediabox_xl/media_player.py +++ b/homeassistant/components/ziggo_mediabox_xl/media_player.py @@ -1,9 +1,4 @@ -""" -Support for interface with a Ziggo Mediabox XL. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.ziggo_mediabox_xl/ -""" +"""Support for interface with a Ziggo Mediabox XL.""" import logging import socket From b4fc1d77ea8fdd1bf53efd222fbb28b46ffd497b Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 3 Apr 2019 09:04:30 -0700 Subject: [PATCH 069/167] Fix trend binary sensor and tests (#22686) --- .../components/trend/binary_sensor.py | 2 +- tests/components/trend/test_binary_sensor.py | 35 +++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/trend/binary_sensor.py b/homeassistant/components/trend/binary_sensor.py index 2b1ae0e083a..163703373d3 100644 --- a/homeassistant/components/trend/binary_sensor.py +++ b/homeassistant/components/trend/binary_sensor.py @@ -141,7 +141,7 @@ class SensorTrend(BinarySensorDevice): else: state = new_state.state if state not in (STATE_UNKNOWN, STATE_UNAVAILABLE): - sample = (utcnow().timestamp(), float(state)) + sample = (new_state.last_updated.timestamp(), float(state)) self.samples.append(sample) self.async_schedule_update_ha_state(True) except (ValueError, TypeError) as ex: diff --git a/tests/components/trend/test_binary_sensor.py b/tests/components/trend/test_binary_sensor.py index b77f9060b40..2116382eafe 100644 --- a/tests/components/trend/test_binary_sensor.py +++ b/tests/components/trend/test_binary_sensor.py @@ -1,5 +1,9 @@ """The test for the Trend sensor platform.""" +from datetime import timedelta +from unittest.mock import patch + from homeassistant import setup +import homeassistant.util.dt as dt_util from tests.common import get_test_home_assistant, assert_setup_component @@ -46,7 +50,7 @@ class TestTrendBinarySensor: 'sensors': { 'test_trend_sensor': { 'entity_id': "sensor.test_state", - 'sample_duration': 300, + 'sample_duration': 10000, 'min_gradient': 1, 'max_samples': 25, } @@ -54,16 +58,22 @@ class TestTrendBinarySensor: } }) - for val in [1, 0, 2, 3]: - self.hass.states.set('sensor.test_state', val) + now = dt_util.utcnow() + for val in [10, 0, 20, 30]: + with patch('homeassistant.util.dt.utcnow', return_value=now): + self.hass.states.set('sensor.test_state', val) self.hass.block_till_done() + now += timedelta(seconds=2) state = self.hass.states.get('binary_sensor.test_trend_sensor') assert state.state == 'on' - for val in [0, 1, 0, 0]: - self.hass.states.set('sensor.test_state', val) + # have to change state value, otherwise sample will lost + for val in [0, 30, 1, 0]: + with patch('homeassistant.util.dt.utcnow', return_value=now): + self.hass.states.set('sensor.test_state', val) self.hass.block_till_done() + now += timedelta(seconds=2) state = self.hass.states.get('binary_sensor.test_trend_sensor') assert state.state == 'off' @@ -76,7 +86,7 @@ class TestTrendBinarySensor: 'sensors': { 'test_trend_sensor': { 'entity_id': "sensor.test_state", - 'sample_duration': 300, + 'sample_duration': 10000, 'min_gradient': 1, 'max_samples': 25, 'invert': 'Yes' @@ -85,16 +95,21 @@ class TestTrendBinarySensor: } }) - for val in [3, 2, 3, 1]: - self.hass.states.set('sensor.test_state', val) + now = dt_util.utcnow() + for val in [30, 20, 30, 10]: + with patch('homeassistant.util.dt.utcnow', return_value=now): + self.hass.states.set('sensor.test_state', val) self.hass.block_till_done() + now += timedelta(seconds=2) state = self.hass.states.get('binary_sensor.test_trend_sensor') assert state.state == 'on' - for val in [4, 2, 4, 4]: - self.hass.states.set('sensor.test_state', val) + for val in [30, 0, 45, 50]: + with patch('homeassistant.util.dt.utcnow', return_value=now): + self.hass.states.set('sensor.test_state', val) self.hass.block_till_done() + now += timedelta(seconds=2) state = self.hass.states.get('binary_sensor.test_trend_sensor') assert state.state == 'off' From 3872ac9bf9ba061096b818a3fd61ba6f9495efdb Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Wed, 3 Apr 2019 18:05:18 +0200 Subject: [PATCH 070/167] Fix citybikes (#22683) * Move asyncio condition to instance from class, to be able to pass in lopp. * Avoid not needed sife effects in init methods. * Clean up. --- homeassistant/components/citybikes/sensor.py | 89 +++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/homeassistant/components/citybikes/sensor.py b/homeassistant/components/citybikes/sensor.py index bcf6fb923f9..344311aa231 100644 --- a/homeassistant/components/citybikes/sensor.py +++ b/homeassistant/components/citybikes/sensor.py @@ -49,6 +49,8 @@ STATIONS_URI = 'v2/networks/{uid}?fields=network.stations' CITYBIKES_ATTRIBUTION = "Information provided by the CityBikes Project "\ "(https://citybik.es/#about)" +CITYBIKES_NETWORKS = 'citybikes_networks' + PLATFORM_SCHEMA = vol.All( cv.has_at_least_one_key(CONF_RADIUS, CONF_STATIONS_LIST), PLATFORM_SCHEMA.extend({ @@ -67,12 +69,12 @@ NETWORK_SCHEMA = vol.Schema({ vol.Required(ATTR_LOCATION): vol.Schema({ vol.Required(ATTR_LATITUDE): cv.latitude, vol.Required(ATTR_LONGITUDE): cv.longitude, - }, extra=vol.REMOVE_EXTRA), - }, extra=vol.REMOVE_EXTRA) + }, extra=vol.REMOVE_EXTRA), +}, extra=vol.REMOVE_EXTRA) NETWORKS_RESPONSE_SCHEMA = vol.Schema({ vol.Required(ATTR_NETWORKS_LIST): [NETWORK_SCHEMA], - }) +}) STATION_SCHEMA = vol.Schema({ vol.Required(ATTR_FREE_BIKES): cv.positive_int, @@ -84,13 +86,13 @@ STATION_SCHEMA = vol.Schema({ vol.Required(ATTR_TIMESTAMP): cv.string, vol.Optional(ATTR_EXTRA): vol.Schema({vol.Optional(ATTR_UID): cv.string}, extra=vol.REMOVE_EXTRA) - }, extra=vol.REMOVE_EXTRA) +}, extra=vol.REMOVE_EXTRA) STATIONS_RESPONSE_SCHEMA = vol.Schema({ vol.Required(ATTR_NETWORK): vol.Schema({ vol.Required(ATTR_STATIONS_LIST): [STATION_SCHEMA] - }, extra=vol.REMOVE_EXTRA) - }) + }, extra=vol.REMOVE_EXTRA) +}) class CityBikesRequestError(Exception): @@ -130,18 +132,21 @@ async def async_setup_platform(hass, config, async_add_entities, network_id = config.get(CONF_NETWORK) stations_list = set(config.get(CONF_STATIONS_LIST, [])) radius = config.get(CONF_RADIUS, 0) - name = config.get(CONF_NAME) + name = config[CONF_NAME] if not hass.config.units.is_metric: radius = distance.convert(radius, LENGTH_FEET, LENGTH_METERS) + # Create a single instance of CityBikesNetworks. + networks = hass.data.setdefault( + CITYBIKES_NETWORKS, CityBikesNetworks(hass)) + if not network_id: - network_id = await CityBikesNetwork.get_closest_network_id( - hass, latitude, longitude) + network_id = await networks.get_closest_network_id(latitude, longitude) if network_id not in hass.data[PLATFORM][MONITORED_NETWORKS]: network = CityBikesNetwork(hass, network_id) hass.data[PLATFORM][MONITORED_NETWORKS][network_id] = network - hass.async_add_job(network.async_refresh) + hass.async_create_task(network.async_refresh()) async_track_time_interval(hass, network.async_refresh, SCAN_INTERVAL) else: network = hass.data[PLATFORM][MONITORED_NETWORKS][network_id] @@ -158,29 +163,37 @@ async def async_setup_platform(hass, config, async_add_entities, if radius > dist or stations_list.intersection( (station_id, station_uid)): - devices.append(CityBikesStation(hass, network, station_id, name)) + if name: + uid = "_".join([network.network_id, name, station_id]) + else: + uid = "_".join([network.network_id, station_id]) + entity_id = async_generate_entity_id( + ENTITY_ID_FORMAT, uid, hass=hass) + devices.append(CityBikesStation(network, station_id, entity_id)) async_add_entities(devices, True) -class CityBikesNetwork: - """Thin wrapper around a CityBikes network object.""" +class CityBikesNetworks: + """Represent all CityBikes networks.""" - NETWORKS_LIST = None - NETWORKS_LIST_LOADING = asyncio.Condition() + def __init__(self, hass): + """Initialize the networks instance.""" + self.hass = hass + self.networks = None + self.networks_loading = asyncio.Condition(loop=hass.loop) - @classmethod - async def get_closest_network_id(cls, hass, latitude, longitude): + async def get_closest_network_id(self, latitude, longitude): """Return the id of the network closest to provided location.""" try: - await cls.NETWORKS_LIST_LOADING.acquire() - if cls.NETWORKS_LIST is None: + await self.networks_loading.acquire() + if self.networks is None: networks = await async_citybikes_request( - hass, NETWORKS_URI, NETWORKS_RESPONSE_SCHEMA) - cls.NETWORKS_LIST = networks[ATTR_NETWORKS_LIST] + self.hass, NETWORKS_URI, NETWORKS_RESPONSE_SCHEMA) + self.networks = networks[ATTR_NETWORKS_LIST] result = None minimum_dist = None - for network in cls.NETWORKS_LIST: + for network in self.networks: network_latitude = network[ATTR_LOCATION][ATTR_LATITUDE] network_longitude = network[ATTR_LOCATION][ATTR_LONGITUDE] dist = location.distance( @@ -193,14 +206,18 @@ class CityBikesNetwork: except CityBikesRequestError: raise PlatformNotReady finally: - cls.NETWORKS_LIST_LOADING.release() + self.networks_loading.release() + + +class CityBikesNetwork: + """Thin wrapper around a CityBikes network object.""" def __init__(self, hass, network_id): """Initialize the network object.""" self.hass = hass self.network_id = network_id self.stations = [] - self.ready = asyncio.Event() + self.ready = asyncio.Event(loop=hass.loop) async def async_refresh(self, now=None): """Refresh the state of the network.""" @@ -220,37 +237,29 @@ class CityBikesNetwork: class CityBikesStation(Entity): """CityBikes API Sensor.""" - def __init__(self, hass, network, station_id, base_name=''): + def __init__(self, network, station_id, entity_id): """Initialize the sensor.""" self._network = network self._station_id = station_id self._station_data = {} - if base_name: - uid = "_".join([network.network_id, base_name, station_id]) - else: - uid = "_".join([network.network_id, station_id]) - self.entity_id = async_generate_entity_id( - ENTITY_ID_FORMAT, uid, hass=hass) + self.entity_id = entity_id @property def state(self): """Return the state of the sensor.""" - return self._station_data.get(ATTR_FREE_BIKES, None) + return self._station_data.get(ATTR_FREE_BIKES) @property def name(self): """Return the name of the sensor.""" - if ATTR_NAME in self._station_data: - return self._station_data[ATTR_NAME] - return None + return self._station_data.get(ATTR_NAME) async def async_update(self): """Update station state.""" - if self._network.ready.is_set(): - for station in self._network.stations: - if station[ATTR_ID] == self._station_id: - self._station_data = station - break + for station in self._network.stations: + if station[ATTR_ID] == self._station_id: + self._station_data = station + break @property def device_state_attributes(self): From 14da2fd8c9001cf6343c6bc41a3aefecac373e71 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 3 Apr 2019 10:20:56 -0700 Subject: [PATCH 071/167] Google Assistant: Add support for open/close binary sensors (#22674) * Google Assistant: Add support for binary sensors * Update test --- .../components/binary_sensor/__init__.py | 116 ++++++++++++++---- .../components/google_assistant/smart_home.py | 5 +- .../components/google_assistant/trait.py | 49 +++++--- .../components/google_assistant/test_trait.py | 110 ++++++++++++----- 4 files changed, 207 insertions(+), 73 deletions(-) diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py index 029ed8faa6b..19054588ee7 100644 --- a/homeassistant/components/binary_sensor/__init__.py +++ b/homeassistant/components/binary_sensor/__init__.py @@ -15,30 +15,100 @@ DOMAIN = 'binary_sensor' SCAN_INTERVAL = timedelta(seconds=30) ENTITY_ID_FORMAT = DOMAIN + '.{}' + +# On means low, Off means normal +DEVICE_CLASS_BATTERY = 'battery' + +# On means cold, Off means normal +DEVICE_CLASS_COLD = 'cold' + +# On means connected, Off means disconnected +DEVICE_CLASS_CONNECTIVITY = 'connectivity' + +# On means open, Off means closed +DEVICE_CLASS_DOOR = 'door' + +# On means open, Off means closed +DEVICE_CLASS_GARAGE_DOOR = 'garage_door' + +# On means gas detected, Off means no gas (clear) +DEVICE_CLASS_GAS = 'gas' + +# On means hot, Off means normal +DEVICE_CLASS_HEAT = 'heat' + +# On means light detected, Off means no light +DEVICE_CLASS_LIGHT = 'light' + +# On means open (unlocked), Off means closed (locked) +DEVICE_CLASS_LOCK = 'lock' + +# On means wet, Off means dry +DEVICE_CLASS_MOISTURE = 'moisture' + +# On means motion detected, Off means no motion (clear) +DEVICE_CLASS_MOTION = 'motion' + +# On means moving, Off means not moving (stopped) +DEVICE_CLASS_MOVING = 'moving' + +# On means occupied, Off means not occupied (clear) +DEVICE_CLASS_OCCUPANCY = 'occupancy' + +# On means open, Off means closed +DEVICE_CLASS_OPENING = 'opening' + +# On means plugged in, Off means unplugged +DEVICE_CLASS_PLUG = 'plug' + +# On means power detected, Off means no power +DEVICE_CLASS_POWER = 'power' + +# On means home, Off means away +DEVICE_CLASS_PRESENCE = 'presence' + +# On means problem detected, Off means no problem (OK) +DEVICE_CLASS_PROBLEM = 'problem' + +# On means unsafe, Off means safe +DEVICE_CLASS_SAFETY = 'safety' + +# On means smoke detected, Off means no smoke (clear) +DEVICE_CLASS_SMOKE = 'smoke' + +# On means sound detected, Off means no sound (clear) +DEVICE_CLASS_SOUND = 'sound' + +# On means vibration detected, Off means no vibration +DEVICE_CLASS_VIBRATION = 'vibration' + +# On means open, Off means closed +DEVICE_CLASS_WINDOW = 'window' + DEVICE_CLASSES = [ - 'battery', # On means low, Off means normal - 'cold', # On means cold, Off means normal - 'connectivity', # On means connected, Off means disconnected - 'door', # On means open, Off means closed - 'garage_door', # On means open, Off means closed - 'gas', # On means gas detected, Off means no gas (clear) - 'heat', # On means hot, Off means normal - 'light', # On means light detected, Off means no light - 'lock', # On means open (unlocked), Off means closed (locked) - 'moisture', # On means wet, Off means dry - 'motion', # On means motion detected, Off means no motion (clear) - 'moving', # On means moving, Off means not moving (stopped) - 'occupancy', # On means occupied, Off means not occupied (clear) - 'opening', # On means open, Off means closed - 'plug', # On means plugged in, Off means unplugged - 'power', # On means power detected, Off means no power - 'presence', # On means home, Off means away - 'problem', # On means problem detected, Off means no problem (OK) - 'safety', # On means unsafe, Off means safe - 'smoke', # On means smoke detected, Off means no smoke (clear) - 'sound', # On means sound detected, Off means no sound (clear) - 'vibration', # On means vibration detected, Off means no vibration - 'window', # On means open, Off means closed + DEVICE_CLASS_BATTERY, + DEVICE_CLASS_COLD, + DEVICE_CLASS_CONNECTIVITY, + DEVICE_CLASS_DOOR, + DEVICE_CLASS_GARAGE_DOOR, + DEVICE_CLASS_GAS, + DEVICE_CLASS_HEAT, + DEVICE_CLASS_LIGHT, + DEVICE_CLASS_LOCK, + DEVICE_CLASS_MOISTURE, + DEVICE_CLASS_MOTION, + DEVICE_CLASS_MOVING, + DEVICE_CLASS_OCCUPANCY, + DEVICE_CLASS_OPENING, + DEVICE_CLASS_PLUG, + DEVICE_CLASS_POWER, + DEVICE_CLASS_PRESENCE, + DEVICE_CLASS_PROBLEM, + DEVICE_CLASS_SAFETY, + DEVICE_CLASS_SMOKE, + DEVICE_CLASS_SOUND, + DEVICE_CLASS_VIBRATION, + DEVICE_CLASS_WINDOW, ] DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.In(DEVICE_CLASSES)) diff --git a/homeassistant/components/google_assistant/smart_home.py b/homeassistant/components/google_assistant/smart_home.py index d84c8037c60..cf31e3423a7 100644 --- a/homeassistant/components/google_assistant/smart_home.py +++ b/homeassistant/components/google_assistant/smart_home.py @@ -9,7 +9,7 @@ from homeassistant.util.decorator import Registry from homeassistant.core import callback from homeassistant.const import ( CLOUD_NEVER_EXPOSED_ENTITIES, CONF_NAME, STATE_UNAVAILABLE, - ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID, + ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID, ATTR_DEVICE_CLASS, ) from homeassistant.components import ( camera, @@ -92,10 +92,11 @@ class _GoogleEntity: state = self.state domain = state.domain features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) + device_class = state.attributes.get(ATTR_DEVICE_CLASS) self._traits = [Trait(self.hass, state, self.config) for Trait in trait.TRAITS - if Trait.supported(domain, features)] + if Trait.supported(domain, features, device_class)] return self._traits async def sync_serialize(self): diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index de3a9530b50..41549c021fe 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -2,6 +2,7 @@ import logging from homeassistant.components import ( + binary_sensor, camera, cover, group, @@ -127,7 +128,7 @@ class BrightnessTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" if domain == light.DOMAIN: return features & light.SUPPORT_BRIGHTNESS @@ -193,7 +194,7 @@ class CameraStreamTrait(_Trait): stream_info = None @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" if domain == camera.DOMAIN: return features & camera.SUPPORT_STREAM @@ -236,7 +237,7 @@ class OnOffTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" return domain in ( group.DOMAIN, @@ -285,7 +286,7 @@ class ColorSpectrumTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" if domain != light.DOMAIN: return False @@ -341,7 +342,7 @@ class ColorTemperatureTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" if domain != light.DOMAIN: return False @@ -414,7 +415,7 @@ class SceneTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" return domain in (scene.DOMAIN, script.DOMAIN) @@ -450,7 +451,7 @@ class DockTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" return domain == vacuum.DOMAIN @@ -484,7 +485,7 @@ class StartStopTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" return domain == vacuum.DOMAIN @@ -554,7 +555,7 @@ class TemperatureSettingTrait(_Trait): google_to_hass = {value: key for key, value in hass_to_google.items()} @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" if domain != climate.DOMAIN: return False @@ -739,7 +740,7 @@ class LockUnlockTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" return domain == lock.DOMAIN @@ -790,7 +791,7 @@ class FanSpeedTrait(_Trait): } @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" if domain != fan.DOMAIN: return False @@ -941,7 +942,7 @@ class ModesTrait(_Trait): } @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" if domain != media_player.DOMAIN: return False @@ -1042,13 +1043,25 @@ class OpenCloseTrait(_Trait): ] @staticmethod - def supported(domain, features): + def supported(domain, features, device_class): """Test if state is supported.""" - return domain == cover.DOMAIN + if domain == cover.DOMAIN: + return True + + return domain == binary_sensor.DOMAIN and device_class in ( + binary_sensor.DEVICE_CLASS_DOOR, + binary_sensor.DEVICE_CLASS_GARAGE_DOOR, + binary_sensor.DEVICE_CLASS_LOCK, + binary_sensor.DEVICE_CLASS_OPENING, + binary_sensor.DEVICE_CLASS_WINDOW, + ) def sync_attributes(self): """Return opening direction.""" - return {} + attrs = {} + if self.state.domain == binary_sensor.DOMAIN: + attrs['queryOnlyOpenClose'] = True + return attrs def query_attributes(self): """Return state query attributes.""" @@ -1073,6 +1086,12 @@ class OpenCloseTrait(_Trait): else: response['openPercent'] = 0 + elif domain == binary_sensor.DOMAIN: + if self.state.state == STATE_ON: + response['openPercent'] = 100 + else: + response['openPercent'] = 0 + return response async def execute(self, command, data, params): diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index 81a7fbe1bf7..d85fc692cb9 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -4,6 +4,7 @@ from unittest.mock import patch, Mock import pytest from homeassistant.components import ( + binary_sensor, camera, cover, fan, @@ -22,7 +23,7 @@ from homeassistant.components.google_assistant import trait, helpers, const from homeassistant.const import ( STATE_ON, STATE_OFF, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE, - ATTR_ASSUMED_STATE) + ATTR_DEVICE_CLASS, ATTR_ASSUMED_STATE) from homeassistant.core import State, DOMAIN as HA_DOMAIN, EVENT_CALL_SERVICE from homeassistant.util import color from tests.common import async_mock_service, mock_coro @@ -49,7 +50,7 @@ UNSAFE_CONFIG = helpers.Config( async def test_brightness_light(hass): """Test brightness trait support for light domain.""" assert trait.BrightnessTrait.supported(light.DOMAIN, - light.SUPPORT_BRIGHTNESS) + light.SUPPORT_BRIGHTNESS, None) trt = trait.BrightnessTrait(hass, State('light.bla', light.STATE_ON, { light.ATTR_BRIGHTNESS: 243 @@ -87,7 +88,8 @@ async def test_brightness_light(hass): async def test_brightness_media_player(hass): """Test brightness trait support for media player domain.""" assert trait.BrightnessTrait.supported(media_player.DOMAIN, - media_player.SUPPORT_VOLUME_SET) + media_player.SUPPORT_VOLUME_SET, + None) trt = trait.BrightnessTrait(hass, State( 'media_player.bla', media_player.STATE_PLAYING, { @@ -116,7 +118,7 @@ async def test_camera_stream(hass): """Test camera stream trait support for camera domain.""" hass.config.api = Mock(base_url='http://1.1.1.1:8123') assert trait.CameraStreamTrait.supported(camera.DOMAIN, - camera.SUPPORT_STREAM) + camera.SUPPORT_STREAM, None) trt = trait.CameraStreamTrait( hass, State('camera.bla', camera.STATE_IDLE, {}), BASIC_CONFIG @@ -143,7 +145,7 @@ async def test_camera_stream(hass): async def test_onoff_group(hass): """Test OnOff trait support for group domain.""" - assert trait.OnOffTrait.supported(group.DOMAIN, 0) + assert trait.OnOffTrait.supported(group.DOMAIN, 0, None) trt_on = trait.OnOffTrait(hass, State('group.bla', STATE_ON), BASIC_CONFIG) @@ -181,7 +183,7 @@ async def test_onoff_group(hass): async def test_onoff_input_boolean(hass): """Test OnOff trait support for input_boolean domain.""" - assert trait.OnOffTrait.supported(input_boolean.DOMAIN, 0) + assert trait.OnOffTrait.supported(input_boolean.DOMAIN, 0, None) trt_on = trait.OnOffTrait(hass, State('input_boolean.bla', STATE_ON), BASIC_CONFIG) @@ -221,7 +223,7 @@ async def test_onoff_input_boolean(hass): async def test_onoff_switch(hass): """Test OnOff trait support for switch domain.""" - assert trait.OnOffTrait.supported(switch.DOMAIN, 0) + assert trait.OnOffTrait.supported(switch.DOMAIN, 0, None) trt_on = trait.OnOffTrait(hass, State('switch.bla', STATE_ON), BASIC_CONFIG) @@ -260,7 +262,7 @@ async def test_onoff_switch(hass): async def test_onoff_fan(hass): """Test OnOff trait support for fan domain.""" - assert trait.OnOffTrait.supported(fan.DOMAIN, 0) + assert trait.OnOffTrait.supported(fan.DOMAIN, 0, None) trt_on = trait.OnOffTrait(hass, State('fan.bla', STATE_ON), BASIC_CONFIG) @@ -296,7 +298,7 @@ async def test_onoff_fan(hass): async def test_onoff_light(hass): """Test OnOff trait support for light domain.""" - assert trait.OnOffTrait.supported(light.DOMAIN, 0) + assert trait.OnOffTrait.supported(light.DOMAIN, 0, None) trt_on = trait.OnOffTrait(hass, State('light.bla', STATE_ON), BASIC_CONFIG) @@ -334,7 +336,7 @@ async def test_onoff_light(hass): async def test_onoff_media_player(hass): """Test OnOff trait support for media_player domain.""" - assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) + assert trait.OnOffTrait.supported(media_player.DOMAIN, 0, None) trt_on = trait.OnOffTrait(hass, State('media_player.bla', STATE_ON), BASIC_CONFIG) @@ -376,12 +378,12 @@ async def test_onoff_media_player(hass): async def test_onoff_climate(hass): """Test OnOff trait not supported for climate domain.""" assert not trait.OnOffTrait.supported( - climate.DOMAIN, climate.SUPPORT_ON_OFF) + climate.DOMAIN, climate.SUPPORT_ON_OFF, None) async def test_dock_vacuum(hass): """Test dock trait support for vacuum domain.""" - assert trait.DockTrait.supported(vacuum.DOMAIN, 0) + assert trait.DockTrait.supported(vacuum.DOMAIN, 0, None) trt = trait.DockTrait(hass, State('vacuum.bla', vacuum.STATE_IDLE), BASIC_CONFIG) @@ -404,7 +406,7 @@ async def test_dock_vacuum(hass): async def test_startstop_vacuum(hass): """Test startStop trait support for vacuum domain.""" - assert trait.StartStopTrait.supported(vacuum.DOMAIN, 0) + assert trait.StartStopTrait.supported(vacuum.DOMAIN, 0, None) trt = trait.StartStopTrait(hass, State('vacuum.bla', vacuum.STATE_PAUSED, { ATTR_SUPPORTED_FEATURES: vacuum.SUPPORT_PAUSE, @@ -452,9 +454,9 @@ async def test_startstop_vacuum(hass): async def test_color_spectrum_light(hass): """Test ColorSpectrum trait support for light domain.""" - assert not trait.ColorSpectrumTrait.supported(light.DOMAIN, 0) + assert not trait.ColorSpectrumTrait.supported(light.DOMAIN, 0, None) assert trait.ColorSpectrumTrait.supported(light.DOMAIN, - light.SUPPORT_COLOR) + light.SUPPORT_COLOR, None) trt = trait.ColorSpectrumTrait(hass, State('light.bla', STATE_ON, { light.ATTR_HS_COLOR: (0, 94), @@ -496,9 +498,10 @@ async def test_color_spectrum_light(hass): async def test_color_temperature_light(hass): """Test ColorTemperature trait support for light domain.""" - assert not trait.ColorTemperatureTrait.supported(light.DOMAIN, 0) + assert not trait.ColorTemperatureTrait.supported(light.DOMAIN, 0, None) assert trait.ColorTemperatureTrait.supported(light.DOMAIN, - light.SUPPORT_COLOR_TEMP) + light.SUPPORT_COLOR_TEMP, + None) trt = trait.ColorTemperatureTrait(hass, State('light.bla', STATE_ON, { light.ATTR_MIN_MIREDS: 200, @@ -552,9 +555,10 @@ async def test_color_temperature_light(hass): async def test_color_temperature_light_bad_temp(hass): """Test ColorTemperature trait support for light domain.""" - assert not trait.ColorTemperatureTrait.supported(light.DOMAIN, 0) + assert not trait.ColorTemperatureTrait.supported(light.DOMAIN, 0, None) assert trait.ColorTemperatureTrait.supported(light.DOMAIN, - light.SUPPORT_COLOR_TEMP) + light.SUPPORT_COLOR_TEMP, + None) trt = trait.ColorTemperatureTrait(hass, State('light.bla', STATE_ON, { light.ATTR_MIN_MIREDS: 200, @@ -568,7 +572,7 @@ async def test_color_temperature_light_bad_temp(hass): async def test_scene_scene(hass): """Test Scene trait support for scene domain.""" - assert trait.SceneTrait.supported(scene.DOMAIN, 0) + assert trait.SceneTrait.supported(scene.DOMAIN, 0, None) trt = trait.SceneTrait(hass, State('scene.bla', scene.STATE), BASIC_CONFIG) assert trt.sync_attributes() == {} @@ -585,7 +589,7 @@ async def test_scene_scene(hass): async def test_scene_script(hass): """Test Scene trait support for script domain.""" - assert trait.SceneTrait.supported(script.DOMAIN, 0) + assert trait.SceneTrait.supported(script.DOMAIN, 0, None) trt = trait.SceneTrait(hass, State('script.bla', STATE_OFF), BASIC_CONFIG) assert trt.sync_attributes() == {} @@ -606,9 +610,9 @@ async def test_scene_script(hass): async def test_temperature_setting_climate_onoff(hass): """Test TemperatureSetting trait support for climate domain - range.""" - assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0) + assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0, None) assert trait.TemperatureSettingTrait.supported( - climate.DOMAIN, climate.SUPPORT_OPERATION_MODE) + climate.DOMAIN, climate.SUPPORT_OPERATION_MODE, None) hass.config.units.temperature_unit = TEMP_FAHRENHEIT @@ -650,9 +654,9 @@ async def test_temperature_setting_climate_onoff(hass): async def test_temperature_setting_climate_range(hass): """Test TemperatureSetting trait support for climate domain - range.""" - assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0) + assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0, None) assert trait.TemperatureSettingTrait.supported( - climate.DOMAIN, climate.SUPPORT_OPERATION_MODE) + climate.DOMAIN, climate.SUPPORT_OPERATION_MODE, None) hass.config.units.temperature_unit = TEMP_FAHRENHEIT @@ -725,9 +729,9 @@ async def test_temperature_setting_climate_range(hass): async def test_temperature_setting_climate_setpoint(hass): """Test TemperatureSetting trait support for climate domain - setpoint.""" - assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0) + assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0, None) assert trait.TemperatureSettingTrait.supported( - climate.DOMAIN, climate.SUPPORT_OPERATION_MODE) + climate.DOMAIN, climate.SUPPORT_OPERATION_MODE, None) hass.config.units.temperature_unit = TEMP_CELSIUS @@ -825,7 +829,8 @@ async def test_temperature_setting_climate_setpoint_auto(hass): async def test_lock_unlock_lock(hass): """Test LockUnlock trait locking support for lock domain.""" - assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN) + assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN, + None) trt = trait.LockUnlockTrait(hass, State('lock.front_door', lock.STATE_UNLOCKED), @@ -850,7 +855,8 @@ async def test_lock_unlock_lock(hass): async def test_lock_unlock_unlock(hass): """Test LockUnlock trait unlocking support for lock domain.""" - assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN) + assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN, + None) trt = trait.LockUnlockTrait(hass, State('lock.front_door', lock.STATE_LOCKED), @@ -887,7 +893,8 @@ async def test_lock_unlock_unlock(hass): async def test_fan_speed(hass): """Test FanSpeed trait speed control support for fan domain.""" - assert trait.FanSpeedTrait.supported(fan.DOMAIN, fan.SUPPORT_SET_SPEED) + assert trait.FanSpeedTrait.supported(fan.DOMAIN, fan.SUPPORT_SET_SPEED, + None) trt = trait.FanSpeedTrait( hass, State( @@ -970,7 +977,7 @@ async def test_fan_speed(hass): async def test_modes(hass): """Test Mode trait.""" assert trait.ModesTrait.supported( - media_player.DOMAIN, media_player.SUPPORT_SELECT_SOURCE) + media_player.DOMAIN, media_player.SUPPORT_SELECT_SOURCE, None) trt = trait.ModesTrait( hass, State( @@ -1056,9 +1063,9 @@ async def test_modes(hass): async def test_openclose_cover(hass): - """Test cover trait.""" + """Test OpenClose trait support for cover domain.""" assert trait.OpenCloseTrait.supported(cover.DOMAIN, - cover.SUPPORT_SET_POSITION) + cover.SUPPORT_SET_POSITION, None) # No position trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, { @@ -1098,3 +1105,40 @@ async def test_openclose_cover(hass): ATTR_ENTITY_ID: 'cover.bla', cover.ATTR_POSITION: 50 } + + +@pytest.mark.parametrize('device_class', ( + binary_sensor.DEVICE_CLASS_DOOR, + binary_sensor.DEVICE_CLASS_GARAGE_DOOR, + binary_sensor.DEVICE_CLASS_LOCK, + binary_sensor.DEVICE_CLASS_OPENING, + binary_sensor.DEVICE_CLASS_WINDOW, +)) +async def test_openclose_binary_sensor(hass, device_class): + """Test OpenClose trait support for binary_sensor domain.""" + assert trait.OpenCloseTrait.supported(binary_sensor.DOMAIN, + 0, device_class) + + trt = trait.OpenCloseTrait(hass, State('binary_sensor.test', STATE_ON, { + ATTR_DEVICE_CLASS: device_class, + }), BASIC_CONFIG) + + assert trt.sync_attributes() == { + 'queryOnlyOpenClose': True, + } + + assert trt.query_attributes() == { + 'openPercent': 100 + } + + trt = trait.OpenCloseTrait(hass, State('binary_sensor.test', STATE_OFF, { + ATTR_DEVICE_CLASS: device_class, + }), BASIC_CONFIG) + + assert trt.sync_attributes() == { + 'queryOnlyOpenClose': True, + } + + assert trt.query_attributes() == { + 'openPercent': 0 + } From 98644135fac42cf7ee56e96fd88b53a923580c4d Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 3 Apr 2019 20:30:03 +0200 Subject: [PATCH 072/167] Update light/services.yaml (#22662) --- homeassistant/components/light/services.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/services.yaml b/homeassistant/components/light/services.yaml index cdf82e97429..d4985258368 100644 --- a/homeassistant/components/light/services.yaml +++ b/homeassistant/components/light/services.yaml @@ -31,10 +31,10 @@ turn_on: description: Number between 0..255 indicating level of white. example: '250' brightness: - description: Number between 0..255 indicating brightness. + description: Number between 0..255 indicating brightness, where 0 turns the light off, 1 is the minimum brightness and 255 is the maximum brightness supported by the light. example: 120 brightness_pct: - description: Number between 0..100 indicating percentage of full brightness. + description: Number between 0..100 indicating percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness and 100 is the maximum brightness supported by the light. example: 47 profile: description: Name of a light profile to use. From a85bcce857e02b6e202232df481b633be06d5119 Mon Sep 17 00:00:00 2001 From: ehendrix23 Date: Wed, 3 Apr 2019 18:29:49 -0600 Subject: [PATCH 073/167] Fix connection loss issues for Harmony (#22687) * Increase aioharmony version to 0.1.11 Update aioharmony version to 0.1.11, this new update contains fixes for websocket connection losses. * Update requirements_all --- homeassistant/components/harmony/remote.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/harmony/remote.py b/homeassistant/components/harmony/remote.py index 78f2674243c..12b3a91e12b 100644 --- a/homeassistant/components/harmony/remote.py +++ b/homeassistant/components/harmony/remote.py @@ -16,7 +16,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.exceptions import PlatformNotReady from homeassistant.util import slugify -REQUIREMENTS = ['aioharmony==0.1.8'] +REQUIREMENTS = ['aioharmony==0.1.11'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 8ed77fdfb3e..801f850375d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -121,7 +121,7 @@ aiofreepybox==0.0.8 aioftp==0.12.0 # homeassistant.components.harmony.remote -aioharmony==0.1.8 +aioharmony==0.1.11 # homeassistant.components.emulated_hue # homeassistant.components.http From 6aac49de7ef3fad33aa6c7878b2ea7c51b241fda Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 3 Apr 2019 20:14:02 -0700 Subject: [PATCH 074/167] Remove aws_* notify platforms (#22698) --- .coveragerc | 3 - CODEOWNERS | 30 +++---- .../components/aws_lambda/__init__.py | 1 - homeassistant/components/aws_lambda/notify.py | 89 ------------------- homeassistant/components/aws_sns/__init__.py | 1 - homeassistant/components/aws_sns/notify.py | 79 ---------------- homeassistant/components/aws_sqs/__init__.py | 1 - homeassistant/components/aws_sqs/notify.py | 81 ----------------- requirements_all.txt | 3 - 9 files changed, 14 insertions(+), 274 deletions(-) delete mode 100644 homeassistant/components/aws_lambda/__init__.py delete mode 100644 homeassistant/components/aws_lambda/notify.py delete mode 100644 homeassistant/components/aws_sns/__init__.py delete mode 100644 homeassistant/components/aws_sns/notify.py delete mode 100644 homeassistant/components/aws_sqs/__init__.py delete mode 100644 homeassistant/components/aws_sqs/notify.py diff --git a/.coveragerc b/.coveragerc index 25e5cf8bb03..f8d8b0fc521 100644 --- a/.coveragerc +++ b/.coveragerc @@ -47,9 +47,6 @@ omit = homeassistant/components/august/* homeassistant/components/automatic/device_tracker.py homeassistant/components/avion/light.py - homeassistant/components/aws_lambda/notify.py - homeassistant/components/aws_sns/notify.py - homeassistant/components/aws_sqs/notify.py homeassistant/components/baidu/tts.py homeassistant/components/bbb_gpio/* homeassistant/components/bbox/device_tracker.py diff --git a/CODEOWNERS b/CODEOWNERS index 9abf1396c61..276c730a47a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -47,31 +47,18 @@ homeassistant/components/*/zwave.py @home-assistant/z-wave homeassistant/components/hassio/* @home-assistant/hassio # Individual platforms -homeassistant/components/notify/aws_lambda.py @robbiet480 -homeassistant/components/notify/aws_sns.py @robbiet480 -homeassistant/components/notify/aws_sqs.py @robbiet480 -homeassistant/components/notify/file.py @fabaff -homeassistant/components/notify/flock.py @fabaff -homeassistant/components/notify/gntp.py @robbiet480 -homeassistant/components/notify/html5.py @robbiet480 -homeassistant/components/notify/mastodon.py @fabaff -homeassistant/components/notify/smtp.py @fabaff -homeassistant/components/notify/syslog.py @fabaff -homeassistant/components/notify/twilio_call.py @robbiet480 -homeassistant/components/notify/twilio_sms.py @robbiet480 -homeassistant/components/notify/xmpp.py @fabaff -homeassistant/components/notify/yessssms.py @flowolf -homeassistant/components/tts/amazon_polly.py @robbiet480 # A homeassistant/components/airvisual/sensor.py @bachya homeassistant/components/alarm_control_panel/manual_mqtt.py @colinodell homeassistant/components/alpha_vantage/sensor.py @fabaff +homeassistant/components/amazon_polly/* @robbiet480 homeassistant/components/ambient_station/* @bachya homeassistant/components/arduino/* @fabaff homeassistant/components/arest/* @fabaff homeassistant/components/asuswrt/device_tracker.py @kennedyshead homeassistant/components/automatic/device_tracker.py @armills +homeassistant/components/aws/* @awarecan @robbiet480 homeassistant/components/axis/* @kane610 # B @@ -112,10 +99,11 @@ homeassistant/components/eq3btsmart/climate.py @rytilahti homeassistant/components/esphome/* @OttoWinter # F -homeassistant/components/file/sensor.py @fabaff +homeassistant/components/file/* @fabaff homeassistant/components/filter/sensor.py @dgomes homeassistant/components/fitbit/sensor.py @robbiet480 homeassistant/components/fixer/sensor.py @fabaff +homeassistant/components/flock/notify.py @fabaff homeassistant/components/flunearyou/sensor.py @bachya homeassistant/components/foursquare/* @robbiet480 homeassistant/components/freebox/* @snoof85 @@ -124,6 +112,7 @@ homeassistant/components/freebox/* @snoof85 homeassistant/components/gearbest/sensor.py @HerrHofrat homeassistant/components/gitter/sensor.py @fabaff homeassistant/components/glances/sensor.py @fabaff +homeassistant/components/gntp/notify.py @robbiet480 homeassistant/components/google_travel_time/sensor.py @robbiet480 homeassistant/components/googlehome/* @ludeeus homeassistant/components/gpsd/sensor.py @fabaff @@ -136,6 +125,7 @@ homeassistant/components/hikvision/binary_sensor.py @mezz64 homeassistant/components/history_graph/* @andrey-git homeassistant/components/hive/* @Rendili @KJonline homeassistant/components/homekit/* @cdce8p +homeassistant/components/html5/notify.py @robbiet480 homeassistant/components/huawei_lte/* @scop homeassistant/components/huawei_router/device_tracker.py @abmantis @@ -165,6 +155,7 @@ homeassistant/components/liveboxplaytv/media_player.py @pschmitt homeassistant/components/luftdaten/* @fabaff # M +homeassistant/components/mastodon/notify.py @fabaff homeassistant/components/matrix/* @tinloaf homeassistant/components/mediaroom/media_player.py @dgomes homeassistant/components/melissa/* @kennedyshead @@ -181,6 +172,7 @@ homeassistant/components/mystrom/* @fabaff # N homeassistant/components/nello/lock.py @pschmitt homeassistant/components/ness_alarm/* @nickw444 +homeassistant/components/nest/* @awarecan homeassistant/components/netdata/sensor.py @fabaff homeassistant/components/nissan_leaf/* @filcole homeassistant/components/nmbs/sensor.py @thibmaek @@ -225,6 +217,7 @@ homeassistant/components/shodan/sensor.py @fabaff homeassistant/components/simplisafe/* @bachya homeassistant/components/sma/sensor.py @kellerza homeassistant/components/smartthings/* @andrewsayre +homeassistant/components/smtp/notify.py @fabaff homeassistant/components/sonos/* @amelchio homeassistant/components/spaceapi/* @fabaff homeassistant/components/spider/* @peternijssen @@ -234,6 +227,7 @@ homeassistant/components/swiss_*/* @fabaff homeassistant/components/switchbot/switch.py @danielhiversen homeassistant/components/switchmate/switch.py @danielhiversen homeassistant/components/synology_srm/device_tracker.py @aerialls +homeassistant/components/syslog/notify.py @fabaff homeassistant/components/sytadin/sensor.py @gautric # T @@ -252,6 +246,8 @@ homeassistant/components/toon/* @frenck homeassistant/components/tplink/* @rytilahti homeassistant/components/traccar/device_tracker.py @ludeeus homeassistant/components/tradfri/* @ggravlingen +homeassistant/components/twilio_call/notify.py @robbiet480 +homeassistant/components/twilio_sms/notify.py @robbiet480 # U homeassistant/components/uber/sensor.py @robbiet480 @@ -276,11 +272,13 @@ homeassistant/components/xfinity/device_tracker.py @cisasteelersfan homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi homeassistant/components/xiaomi_miio/* @rytilahti @syssi homeassistant/components/xiaomi_tv/media_player.py @fattdev +homeassistant/components/xmpp/notify.py @fabaff # Y homeassistant/components/yamaha_musiccast/* @jalmeroth homeassistant/components/yeelight/* @rytilahti @zewelor homeassistant/components/yeelightsunflower/light.py @lindsaymarkward +homeassistant/components/yessssms/notify.py @flowolf homeassistant/components/yi/camera.py @bachya # Z diff --git a/homeassistant/components/aws_lambda/__init__.py b/homeassistant/components/aws_lambda/__init__.py deleted file mode 100644 index f6d86d02e93..00000000000 --- a/homeassistant/components/aws_lambda/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The aws_lambda component.""" diff --git a/homeassistant/components/aws_lambda/notify.py b/homeassistant/components/aws_lambda/notify.py deleted file mode 100644 index e5fed20d997..00000000000 --- a/homeassistant/components/aws_lambda/notify.py +++ /dev/null @@ -1,89 +0,0 @@ -"""AWS Lambda platform for notify component.""" -import base64 -import json -import logging - -import voluptuous as vol - -from homeassistant.const import CONF_NAME, CONF_PLATFORM -import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.json import JSONEncoder - -from homeassistant.components.notify import (ATTR_TARGET, PLATFORM_SCHEMA, - BaseNotificationService) - -REQUIREMENTS = ['boto3==1.9.16'] - -_LOGGER = logging.getLogger(__name__) - -CONF_REGION = 'region_name' -CONF_ACCESS_KEY_ID = 'aws_access_key_id' -CONF_SECRET_ACCESS_KEY = 'aws_secret_access_key' -CONF_PROFILE_NAME = 'profile_name' -CONF_CONTEXT = 'context' -ATTR_CREDENTIALS = 'credentials' - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_REGION, default='us-east-1'): cv.string, - vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string, - vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string, - vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string, - vol.Optional(CONF_CONTEXT, default=dict()): vol.Coerce(dict) -}) - - -def get_service(hass, config, discovery_info=None): - """Get the AWS Lambda notification service.""" - _LOGGER.warning( - "aws_lambda notify platform is deprecated, please replace it" - " with aws component. This config will become invalid in version 0.92." - " See https://www.home-assistant.io/components/aws/ for details." - ) - - context_str = json.dumps({'custom': config[CONF_CONTEXT]}, cls=JSONEncoder) - context_b64 = base64.b64encode(context_str.encode('utf-8')) - context = context_b64.decode('utf-8') - - import boto3 - - aws_config = config.copy() - - del aws_config[CONF_PLATFORM] - del aws_config[CONF_NAME] - del aws_config[CONF_CONTEXT] - - profile = aws_config.get(CONF_PROFILE_NAME) - - if profile is not None: - boto3.setup_default_session(profile_name=profile) - del aws_config[CONF_PROFILE_NAME] - - lambda_client = boto3.client("lambda", **aws_config) - - return AWSLambda(lambda_client, context) - - -class AWSLambda(BaseNotificationService): - """Implement the notification service for the AWS Lambda service.""" - - def __init__(self, lambda_client, context): - """Initialize the service.""" - self.client = lambda_client - self.context = context - - def send_message(self, message="", **kwargs): - """Send notification to specified LAMBDA ARN.""" - targets = kwargs.get(ATTR_TARGET) - - if not targets: - _LOGGER.info("At least 1 target is required") - return - - for target in targets: - cleaned_kwargs = dict((k, v) for k, v in kwargs.items() if v) - payload = {"message": message} - payload.update(cleaned_kwargs) - - self.client.invoke(FunctionName=target, - Payload=json.dumps(payload), - ClientContext=self.context) diff --git a/homeassistant/components/aws_sns/__init__.py b/homeassistant/components/aws_sns/__init__.py deleted file mode 100644 index b51698ce0dc..00000000000 --- a/homeassistant/components/aws_sns/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The aws_sns component.""" diff --git a/homeassistant/components/aws_sns/notify.py b/homeassistant/components/aws_sns/notify.py deleted file mode 100644 index daac710d40a..00000000000 --- a/homeassistant/components/aws_sns/notify.py +++ /dev/null @@ -1,79 +0,0 @@ -"""AWS SNS platform for notify component.""" -import json -import logging - -import voluptuous as vol - -from homeassistant.const import CONF_NAME, CONF_PLATFORM -import homeassistant.helpers.config_validation as cv - -from homeassistant.components.notify import ( - ATTR_TARGET, ATTR_TITLE, ATTR_TITLE_DEFAULT, PLATFORM_SCHEMA, - BaseNotificationService) - -_LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ["boto3==1.9.16"] - -CONF_REGION = 'region_name' -CONF_ACCESS_KEY_ID = 'aws_access_key_id' -CONF_SECRET_ACCESS_KEY = 'aws_secret_access_key' -CONF_PROFILE_NAME = 'profile_name' -ATTR_CREDENTIALS = 'credentials' - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_REGION, default='us-east-1'): cv.string, - vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string, - vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string, - vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string, -}) - - -def get_service(hass, config, discovery_info=None): - """Get the AWS SNS notification service.""" - _LOGGER.warning( - "aws_sns notify platform is deprecated, please replace it" - " with aws component. This config will become invalid in version 0.92." - " See https://www.home-assistant.io/components/aws/ for details." - ) - - import boto3 - - aws_config = config.copy() - - del aws_config[CONF_PLATFORM] - del aws_config[CONF_NAME] - - profile = aws_config.get(CONF_PROFILE_NAME) - - if profile is not None: - boto3.setup_default_session(profile_name=profile) - del aws_config[CONF_PROFILE_NAME] - - sns_client = boto3.client("sns", **aws_config) - - return AWSSNS(sns_client) - - -class AWSSNS(BaseNotificationService): - """Implement the notification service for the AWS SNS service.""" - - def __init__(self, sns_client): - """Initialize the service.""" - self.client = sns_client - - def send_message(self, message="", **kwargs): - """Send notification to specified SNS ARN.""" - targets = kwargs.get(ATTR_TARGET) - - if not targets: - _LOGGER.info("At least 1 target is required") - return - - message_attributes = {k: {"StringValue": json.dumps(v), - "DataType": "String"} - for k, v in kwargs.items() if v} - for target in targets: - self.client.publish(TargetArn=target, Message=message, - Subject=kwargs.get(ATTR_TITLE, - ATTR_TITLE_DEFAULT), - MessageAttributes=message_attributes) diff --git a/homeassistant/components/aws_sqs/__init__.py b/homeassistant/components/aws_sqs/__init__.py deleted file mode 100644 index 79b29a76009..00000000000 --- a/homeassistant/components/aws_sqs/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The aws_sqs component.""" diff --git a/homeassistant/components/aws_sqs/notify.py b/homeassistant/components/aws_sqs/notify.py deleted file mode 100644 index 4c4c831482b..00000000000 --- a/homeassistant/components/aws_sqs/notify.py +++ /dev/null @@ -1,81 +0,0 @@ -"""AWS SQS platform for notify component.""" -import json -import logging - -import voluptuous as vol - -from homeassistant.const import CONF_NAME, CONF_PLATFORM -import homeassistant.helpers.config_validation as cv - -from homeassistant.components.notify import (ATTR_TARGET, PLATFORM_SCHEMA, - BaseNotificationService) - -_LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ["boto3==1.9.16"] - -CONF_REGION = 'region_name' -CONF_ACCESS_KEY_ID = 'aws_access_key_id' -CONF_SECRET_ACCESS_KEY = 'aws_secret_access_key' -CONF_PROFILE_NAME = 'profile_name' -ATTR_CREDENTIALS = 'credentials' - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_REGION, default='us-east-1'): cv.string, - vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string, - vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string, - vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string, -}) - - -def get_service(hass, config, discovery_info=None): - """Get the AWS SQS notification service.""" - _LOGGER.warning( - "aws_sqs notify platform is deprecated, please replace it" - " with aws component. This config will become invalid in version 0.92." - " See https://www.home-assistant.io/components/aws/ for details." - ) - - import boto3 - - aws_config = config.copy() - - del aws_config[CONF_PLATFORM] - del aws_config[CONF_NAME] - - profile = aws_config.get(CONF_PROFILE_NAME) - - if profile is not None: - boto3.setup_default_session(profile_name=profile) - del aws_config[CONF_PROFILE_NAME] - - sqs_client = boto3.client("sqs", **aws_config) - - return AWSSQS(sqs_client) - - -class AWSSQS(BaseNotificationService): - """Implement the notification service for the AWS SQS service.""" - - def __init__(self, sqs_client): - """Initialize the service.""" - self.client = sqs_client - - def send_message(self, message="", **kwargs): - """Send notification to specified SQS ARN.""" - targets = kwargs.get(ATTR_TARGET) - - if not targets: - _LOGGER.info("At least 1 target is required") - return - - for target in targets: - cleaned_kwargs = dict((k, v) for k, v in kwargs.items() if v) - message_body = {"message": message} - message_body.update(cleaned_kwargs) - message_attributes = {} - for key, val in cleaned_kwargs.items(): - message_attributes[key] = {"StringValue": json.dumps(val), - "DataType": "String"} - self.client.send_message(QueueUrl=target, - MessageBody=json.dumps(message_body), - MessageAttributes=message_attributes) diff --git a/requirements_all.txt b/requirements_all.txt index 801f850375d..69430c8cf98 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -237,9 +237,6 @@ blockchain==1.4.4 # homeassistant.components.route53 # homeassistant.components.amazon_polly.tts -# homeassistant.components.aws_lambda.notify -# homeassistant.components.aws_sns.notify -# homeassistant.components.aws_sqs.notify boto3==1.9.16 # homeassistant.components.braviatv.media_player From cfe4cf30ad3ce6359420aae77ad5e27cdf45baed Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 3 Apr 2019 21:14:45 -0700 Subject: [PATCH 075/167] Add manifests (#22699) * Add manifests * Update auto name * Update codeowners * Add requirements from platforms * Minor cleanup * Incorporate changes from awarecan PR --- CODEOWNERS | 10 +++++--- homeassistant/components/abode/manifest.json | 10 ++++++++ .../components/acer_projector/manifest.json | 10 ++++++++ .../components/actiontec/manifest.json | 8 ++++++ homeassistant/components/ads/manifest.json | 10 ++++++++ .../components/aftership/manifest.json | 10 ++++++++ .../components/air_quality/manifest.json | 8 ++++++ .../components/airvisual/manifest.json | 12 +++++++++ .../components/aladdin_connect/manifest.json | 10 ++++++++ .../alarm_control_panel/manifest.json | 10 ++++++++ .../components/alarmdecoder/manifest.json | 10 ++++++++ .../components/alarmdotcom/manifest.json | 10 ++++++++ homeassistant/components/alert/manifest.json | 8 ++++++ homeassistant/components/alexa/manifest.json | 10 ++++++++ .../components/alpha_vantage/manifest.json | 12 +++++++++ .../components/amazon_polly/manifest.json | 12 +++++++++ .../components/ambient_station/manifest.json | 12 +++++++++ .../components/amcrest/manifest.json | 12 +++++++++ homeassistant/components/ampio/manifest.json | 10 ++++++++ .../android_ip_webcam/manifest.json | 10 ++++++++ .../components/androidtv/manifest.json | 10 ++++++++ .../components/anel_pwrctrl/manifest.json | 10 ++++++++ .../components/anthemav/manifest.json | 10 ++++++++ .../components/apcupsd/manifest.json | 10 ++++++++ homeassistant/components/api/manifest.json | 12 +++++++++ .../components/api_streams/__init__.py | 1 - homeassistant/components/apns/manifest.json | 10 ++++++++ .../components/apple_tv/manifest.json | 10 ++++++++ .../components/aqualogic/manifest.json | 10 ++++++++ .../components/aquostv/manifest.json | 10 ++++++++ .../components/arduino/manifest.json | 12 +++++++++ homeassistant/components/arest/manifest.json | 10 ++++++++ homeassistant/components/arlo/manifest.json | 10 ++++++++ homeassistant/components/aruba/manifest.json | 10 ++++++++ homeassistant/components/arwn/manifest.json | 8 ++++++ .../components/asterisk_cdr/manifest.json | 8 ++++++ .../components/asterisk_mbox/manifest.json | 10 ++++++++ .../components/asuswrt/manifest.json | 12 +++++++++ homeassistant/components/august/manifest.json | 10 ++++++++ homeassistant/components/aurora/manifest.json | 8 ++++++ homeassistant/components/auth/manifest.json | 12 +++++++++ .../components/automatic/manifest.json | 12 +++++++++ .../components/automation/manifest.json | 12 +++++++++ homeassistant/components/avion/manifest.json | 10 ++++++++ homeassistant/components/awair/manifest.json | 10 ++++++++ homeassistant/components/aws/manifest.json | 13 ++++++++++ .../components/aws_lambda/manifest.json | 10 ++++++++ .../components/aws_sns/manifest.json | 10 ++++++++ .../components/aws_sqs/manifest.json | 10 ++++++++ homeassistant/components/axis/manifest.json | 12 +++++++++ homeassistant/components/baidu/manifest.json | 10 ++++++++ .../components/bayesian/manifest.json | 8 ++++++ .../components/bbb_gpio/manifest.json | 10 ++++++++ homeassistant/components/bbox/manifest.json | 10 ++++++++ homeassistant/components/bh1750/manifest.json | 11 ++++++++ .../components/binary_sensor/manifest.json | 8 ++++++ .../components/bitcoin/manifest.json | 12 +++++++++ .../components/blackbird/manifest.json | 10 ++++++++ homeassistant/components/blink/manifest.json | 12 +++++++++ .../components/blinksticklight/manifest.json | 10 ++++++++ homeassistant/components/blinkt/manifest.json | 10 ++++++++ .../components/blockchain/manifest.json | 10 ++++++++ .../components/bloomsky/manifest.json | 8 ++++++ .../components/bluesound/manifest.json | 10 ++++++++ .../bluetooth_le_tracker/manifest.json | 10 ++++++++ .../bluetooth_tracker/manifest.json | 11 ++++++++ homeassistant/components/bme280/manifest.json | 11 ++++++++ homeassistant/components/bme680/manifest.json | 11 ++++++++ .../bmw_connected_drive/manifest.json | 12 +++++++++ homeassistant/components/bom/manifest.json | 8 ++++++ .../components/braviatv/manifest.json | 12 +++++++++ .../components/broadlink/manifest.json | 12 +++++++++ .../brottsplatskartan/manifest.json | 10 ++++++++ .../components/browser/manifest.json | 8 ++++++ homeassistant/components/brunt/manifest.json | 12 +++++++++ .../components/bt_home_hub_5/manifest.json | 10 ++++++++ .../components/bt_smarthub/manifest.json | 12 +++++++++ .../components/buienradar/manifest.json | 10 ++++++++ homeassistant/components/caldav/manifest.json | 10 ++++++++ .../components/calendar/manifest.json | 10 ++++++++ homeassistant/components/camera/manifest.json | 10 ++++++++ homeassistant/components/canary/manifest.json | 10 ++++++++ homeassistant/components/cast/manifest.json | 10 ++++++++ .../components/cert_expiry/manifest.json | 8 ++++++ .../components/channels/manifest.json | 10 ++++++++ .../components/cisco_ios/manifest.json | 10 ++++++++ .../cisco_mobility_express/manifest.json | 10 ++++++++ .../cisco_webex_teams/manifest.json | 10 ++++++++ .../components/ciscospark/manifest.json | 10 ++++++++ .../components/citybikes/manifest.json | 8 ++++++ .../components/clementine/manifest.json | 10 ++++++++ .../components/clickatell/manifest.json | 8 ++++++ .../components/clicksend/manifest.json | 8 ++++++ .../components/clicksend_tts/manifest.json | 8 ++++++ .../components/climate/manifest.json | 8 ++++++ homeassistant/components/cloud/manifest.json | 14 +++++++++++ .../components/cloudflare/manifest.json | 12 +++++++++ homeassistant/components/cmus/manifest.json | 10 ++++++++ .../components/co2signal/manifest.json | 10 ++++++++ .../components/coinbase/manifest.json | 10 ++++++++ .../components/coinmarketcap/manifest.json | 10 ++++++++ .../comed_hourly_pricing/manifest.json | 8 ++++++ .../components/comfoconnect/manifest.json | 10 ++++++++ .../components/command_line/manifest.json | 8 ++++++ .../components/concord232/manifest.json | 10 ++++++++ homeassistant/components/config/manifest.json | 12 +++++++++ .../components/configurator/manifest.json | 10 ++++++++ .../components/conversation/manifest.json | 12 +++++++++ .../components/coolmaster/manifest.json | 12 +++++++++ .../components/counter/manifest.json | 10 ++++++++ homeassistant/components/cover/manifest.json | 12 +++++++++ .../components/cppm_tracker/manifest.json | 10 ++++++++ .../components/cpuspeed/manifest.json | 12 +++++++++ .../components/crimereports/manifest.json | 10 ++++++++ homeassistant/components/cups/manifest.json | 12 +++++++++ .../components/currencylayer/manifest.json | 8 ++++++ homeassistant/components/daikin/manifest.json | 13 ++++++++++ .../components/danfoss_air/manifest.json | 10 ++++++++ .../components/darksky/manifest.json | 12 +++++++++ .../components/datadog/manifest.json | 10 ++++++++ homeassistant/components/ddwrt/manifest.json | 8 ++++++ homeassistant/components/deconz/manifest.json | 12 +++++++++ homeassistant/components/decora/manifest.json | 11 ++++++++ .../components/decora_wifi/manifest.json | 10 ++++++++ .../components/default_config/manifest.json | 25 +++++++++++++++++++ homeassistant/components/deluge/manifest.json | 10 ++++++++ homeassistant/components/demo/manifest.json | 14 +++++++++++ homeassistant/components/denon/manifest.json | 8 ++++++ .../components/denonavr/manifest.json | 10 ++++++++ .../components/deutsche_bahn/manifest.json | 10 ++++++++ .../device_sun_light_trigger/manifest.json | 12 +++++++++ .../components/device_tracker/manifest.json | 11 ++++++++ homeassistant/components/dht/manifest.json | 10 ++++++++ .../components/dialogflow/manifest.json | 10 ++++++++ .../components/digital_ocean/manifest.json | 12 +++++++++ .../components/digitalloggers/manifest.json | 10 ++++++++ .../components/directv/manifest.json | 10 ++++++++ .../components/discogs/manifest.json | 12 +++++++++ .../components/discord/manifest.json | 10 ++++++++ .../components/discovery/manifest.json | 10 ++++++++ .../components/dlib_face_detect/manifest.json | 10 ++++++++ .../dlib_face_identify/manifest.json | 10 ++++++++ homeassistant/components/dlink/manifest.json | 10 ++++++++ .../components/dlna_dmr/manifest.json | 10 ++++++++ homeassistant/components/dnsip/manifest.json | 10 ++++++++ .../components/dominos/manifest.json | 12 +++++++++ .../components/doorbird/manifest.json | 12 +++++++++ homeassistant/components/dovado/manifest.json | 10 ++++++++ .../components/downloader/manifest.json | 8 ++++++ homeassistant/components/dsmr/manifest.json | 10 ++++++++ .../dte_energy_bridge/manifest.json | 8 ++++++ .../dublin_bus_transport/manifest.json | 8 ++++++ .../components/duckdns/manifest.json | 8 ++++++ .../components/duke_energy/manifest.json | 10 ++++++++ homeassistant/components/dunehd/manifest.json | 10 ++++++++ .../dwd_weather_warnings/manifest.json | 8 ++++++ homeassistant/components/dweet/manifest.json | 12 +++++++++ homeassistant/components/dyson/manifest.json | 10 ++++++++ homeassistant/components/ebox/manifest.json | 10 ++++++++ homeassistant/components/ebusd/manifest.json | 10 ++++++++ .../components/ecoal_boiler/manifest.json | 10 ++++++++ homeassistant/components/ecobee/manifest.json | 10 ++++++++ homeassistant/components/econet/manifest.json | 10 ++++++++ .../components/ecovacs/manifest.json | 12 +++++++++ .../eddystone_temperature/manifest.json | 11 ++++++++ homeassistant/components/edimax/manifest.json | 10 ++++++++ .../components/edp_redy/manifest.json | 12 +++++++++ .../components/ee_brightbox/manifest.json | 10 ++++++++ homeassistant/components/efergy/manifest.json | 8 ++++++ .../components/egardia/manifest.json | 12 +++++++++ .../components/eight_sleep/manifest.json | 12 +++++++++ .../components/eliqonline/manifest.json | 10 ++++++++ homeassistant/components/elkm1/manifest.json | 10 ++++++++ homeassistant/components/emby/manifest.json | 12 +++++++++ .../components/emoncms/manifest.json | 8 ++++++ .../components/emoncms_history/manifest.json | 8 ++++++ .../components/emulated_hue/manifest.json | 10 ++++++++ .../components/emulated_roku/manifest.json | 10 ++++++++ .../components/enigma2/manifest.json | 10 ++++++++ .../components/enocean/manifest.json | 10 ++++++++ .../components/enphase_envoy/manifest.json | 10 ++++++++ .../entur_public_transport/manifest.json | 10 ++++++++ .../components/envirophat/manifest.json | 11 ++++++++ .../components/envisalink/manifest.json | 10 ++++++++ .../components/ephember/manifest.json | 12 +++++++++ homeassistant/components/epson/manifest.json | 10 ++++++++ .../components/eq3btsmart/manifest.json | 13 ++++++++++ .../components/esphome/manifest.json | 12 +++++++++ .../components/etherscan/manifest.json | 10 ++++++++ homeassistant/components/eufy/manifest.json | 10 ++++++++ .../components/everlights/manifest.json | 10 ++++++++ .../components/evohome/manifest.json | 10 ++++++++ .../components/facebook/manifest.json | 8 ++++++ .../components/facebox/manifest.json | 8 ++++++ .../components/fail2ban/manifest.json | 8 ++++++ .../components/familyhub/manifest.json | 10 ++++++++ homeassistant/components/fan/manifest.json | 10 ++++++++ .../components/fastdotcom/manifest.json | 10 ++++++++ homeassistant/components/fedex/manifest.json | 10 ++++++++ .../components/feedreader/manifest.json | 10 ++++++++ homeassistant/components/ffmpeg/manifest.json | 10 ++++++++ .../components/ffmpeg_motion/manifest.json | 8 ++++++ .../components/ffmpeg_noise/manifest.json | 8 ++++++ homeassistant/components/fibaro/manifest.json | 10 ++++++++ homeassistant/components/fido/manifest.json | 10 ++++++++ homeassistant/components/file/manifest.json | 10 ++++++++ .../components/filesize/manifest.json | 8 ++++++ homeassistant/components/filter/manifest.json | 10 ++++++++ homeassistant/components/fints/manifest.json | 10 ++++++++ homeassistant/components/fitbit/manifest.json | 12 +++++++++ homeassistant/components/fixer/manifest.json | 12 +++++++++ homeassistant/components/flexit/manifest.json | 10 ++++++++ homeassistant/components/flic/manifest.json | 10 ++++++++ homeassistant/components/flock/manifest.json | 10 ++++++++ .../components/flunearyou/manifest.json | 12 +++++++++ homeassistant/components/flux/manifest.json | 8 ++++++ .../components/flux_led/manifest.json | 10 ++++++++ homeassistant/components/folder/manifest.json | 8 ++++++ .../components/folder_watcher/manifest.json | 10 ++++++++ homeassistant/components/foobot/manifest.json | 10 ++++++++ homeassistant/components/foscam/manifest.json | 10 ++++++++ .../components/foursquare/manifest.json | 12 +++++++++ .../components/free_mobile/manifest.json | 10 ++++++++ .../components/freebox/manifest.json | 12 +++++++++ .../components/freedns/manifest.json | 8 ++++++ homeassistant/components/fritz/manifest.json | 10 ++++++++ .../components/fritzbox/manifest.json | 10 ++++++++ .../fritzbox_callmonitor/manifest.json | 10 ++++++++ .../fritzbox_netmonitor/manifest.json | 10 ++++++++ .../components/fritzdect/manifest.json | 10 ++++++++ .../components/frontend/manifest.json | 20 +++++++++++++++ .../components/frontier_silicon/manifest.json | 10 ++++++++ .../components/futurenow/manifest.json | 10 ++++++++ .../components/garadget/manifest.json | 8 ++++++ homeassistant/components/gc100/manifest.json | 10 ++++++++ .../components/gearbest/manifest.json | 12 +++++++++ .../components/geizhals/manifest.json | 10 ++++++++ .../components/generic/manifest.json | 8 ++++++ .../generic_thermostat/manifest.json | 8 ++++++ .../components/geo_json_events/manifest.json | 10 ++++++++ .../components/geo_location/manifest.json | 8 ++++++ .../components/geo_rss_events/manifest.json | 10 ++++++++ .../components/geofency/manifest.json | 10 ++++++++ homeassistant/components/github/manifest.json | 10 ++++++++ .../components/gitlab_ci/manifest.json | 10 ++++++++ homeassistant/components/gitter/manifest.json | 12 +++++++++ .../components/glances/manifest.json | 12 +++++++++ homeassistant/components/gntp/manifest.json | 12 +++++++++ .../components/goalfeed/manifest.json | 10 ++++++++ .../components/gogogate2/manifest.json | 10 ++++++++ homeassistant/components/google/manifest.json | 13 ++++++++++ .../components/google_assistant/manifest.json | 10 ++++++++ .../components/google_domains/manifest.json | 8 ++++++ .../components/google_maps/manifest.json | 10 ++++++++ .../components/google_pubsub/manifest.json | 10 ++++++++ .../google_travel_time/manifest.json | 12 +++++++++ .../components/google_wifi/manifest.json | 8 ++++++ .../components/googlehome/manifest.json | 12 +++++++++ homeassistant/components/gpmdp/manifest.json | 10 ++++++++ homeassistant/components/gpsd/manifest.json | 12 +++++++++ .../components/gpslogger/manifest.json | 10 ++++++++ .../components/graphite/manifest.json | 8 ++++++ .../components/greeneye_monitor/manifest.json | 10 ++++++++ .../components/greenwave/manifest.json | 10 ++++++++ homeassistant/components/group/manifest.json | 10 ++++++++ .../components/gstreamer/manifest.json | 10 ++++++++ homeassistant/components/gtfs/manifest.json | 12 +++++++++ homeassistant/components/gtt/manifest.json | 10 ++++++++ .../components/habitica/manifest.json | 10 ++++++++ .../components/hangouts/manifest.json | 10 ++++++++ .../harman_kardon_avr/manifest.json | 10 ++++++++ .../components/harmony/manifest.json | 12 +++++++++ homeassistant/components/hassio/manifest.json | 12 +++++++++ .../components/haveibeenpwned/manifest.json | 8 ++++++ .../components/hddtemp/manifest.json | 8 ++++++ .../components/hdmi_cec/manifest.json | 10 ++++++++ .../components/heatmiser/manifest.json | 10 ++++++++ homeassistant/components/heos/manifest.json | 12 +++++++++ .../components/hikvision/manifest.json | 12 +++++++++ .../components/hikvisioncam/manifest.json | 10 ++++++++ .../components/hipchat/manifest.json | 10 ++++++++ .../components/history/manifest.json | 13 ++++++++++ .../components/history_graph/manifest.json | 12 +++++++++ .../components/history_stats/manifest.json | 8 ++++++ .../components/hitron_coda/manifest.json | 8 ++++++ homeassistant/components/hive/manifest.json | 13 ++++++++++ .../components/hlk_sw16/manifest.json | 10 ++++++++ .../components/homeassistant/manifest.json | 10 ++++++++ .../components/homekit/manifest.json | 12 +++++++++ .../homekit_controller/manifest.json | 10 ++++++++ .../components/homematic/manifest.json | 10 ++++++++ .../homematicip_cloud/manifest.json | 10 ++++++++ .../components/homeworks/manifest.json | 10 ++++++++ .../components/honeywell/manifest.json | 11 ++++++++ homeassistant/components/hook/manifest.json | 8 ++++++ .../components/horizon/manifest.json | 10 ++++++++ homeassistant/components/hp_ilo/manifest.json | 10 ++++++++ homeassistant/components/html5/manifest.json | 12 +++++++++ homeassistant/components/http/manifest.json | 12 +++++++++ homeassistant/components/htu21d/manifest.json | 11 ++++++++ .../components/huawei_lte/manifest.json | 12 +++++++++ .../components/huawei_router/manifest.json | 10 ++++++++ homeassistant/components/hue/manifest.json | 12 +++++++++ .../hunterdouglas_powerview/manifest.json | 10 ++++++++ .../components/hydrawise/manifest.json | 10 ++++++++ .../components/hydroquebec/manifest.json | 10 ++++++++ .../components/hyperion/manifest.json | 8 ++++++ homeassistant/components/ialarm/manifest.json | 10 ++++++++ homeassistant/components/icloud/manifest.json | 10 ++++++++ .../components/idteck_prox/manifest.json | 10 ++++++++ homeassistant/components/ifttt/manifest.json | 12 +++++++++ homeassistant/components/iglo/manifest.json | 10 ++++++++ homeassistant/components/ihc/manifest.json | 11 ++++++++ .../components/image_processing/manifest.json | 10 ++++++++ homeassistant/components/imap/manifest.json | 10 ++++++++ .../imap_email_content/manifest.json | 8 ++++++ .../components/influxdb/manifest.json | 12 +++++++++ .../components/input_boolean/manifest.json | 10 ++++++++ .../components/input_datetime/manifest.json | 10 ++++++++ .../components/input_number/manifest.json | 10 ++++++++ .../components/input_select/manifest.json | 10 ++++++++ .../components/input_text/manifest.json | 10 ++++++++ .../components/insteon/manifest.json | 10 ++++++++ .../components/insteon_local/manifest.json | 8 ++++++ .../components/insteon_plm/manifest.json | 8 ++++++ .../components/integration/manifest.json | 10 ++++++++ .../components/intent_script/manifest.json | 8 ++++++ .../components/introduction/manifest.json | 10 ++++++++ homeassistant/components/ios/manifest.json | 14 +++++++++++ homeassistant/components/iota/manifest.json | 10 ++++++++ homeassistant/components/iperf3/manifest.json | 10 ++++++++ homeassistant/components/ipma/manifest.json | 12 +++++++++ .../irish_rail_transport/manifest.json | 12 +++++++++ .../islamic_prayer_times/manifest.json | 10 ++++++++ homeassistant/components/iss/manifest.json | 10 ++++++++ homeassistant/components/isy994/manifest.json | 10 ++++++++ homeassistant/components/itach/manifest.json | 10 ++++++++ homeassistant/components/itunes/manifest.json | 8 ++++++ .../components/jewish_calendar/manifest.json | 12 +++++++++ .../components/joaoapps_join/manifest.json | 10 ++++++++ .../components/juicenet/manifest.json | 10 ++++++++ homeassistant/components/kankun/manifest.json | 8 ++++++ .../components/keenetic_ndms2/manifest.json | 10 ++++++++ .../components/keyboard/manifest.json | 10 ++++++++ .../components/keyboard_remote/manifest.json | 10 ++++++++ homeassistant/components/kira/manifest.json | 10 ++++++++ homeassistant/components/kiwi/manifest.json | 10 ++++++++ homeassistant/components/knx/manifest.json | 12 +++++++++ homeassistant/components/kodi/manifest.json | 13 ++++++++++ .../components/konnected/manifest.json | 14 +++++++++++ homeassistant/components/kwb/manifest.json | 10 ++++++++ .../components/lacrosse/manifest.json | 10 ++++++++ .../components/lametric/manifest.json | 12 +++++++++ .../components/lannouncer/manifest.json | 8 ++++++ homeassistant/components/lastfm/manifest.json | 10 ++++++++ .../components/launch_library/manifest.json | 12 +++++++++ homeassistant/components/lcn/manifest.json | 10 ++++++++ .../components/lg_netcast/manifest.json | 10 ++++++++ .../components/lg_soundbar/manifest.json | 10 ++++++++ homeassistant/components/lifx/manifest.json | 13 ++++++++++ .../components/lifx_cloud/manifest.json | 10 ++++++++ .../components/lifx_legacy/manifest.json | 12 +++++++++ homeassistant/components/light/manifest.json | 10 ++++++++ .../components/lightwave/manifest.json | 10 ++++++++ .../components/limitlessled/manifest.json | 10 ++++++++ .../components/linksys_ap/manifest.json | 10 ++++++++ .../components/linksys_smart/manifest.json | 8 ++++++ homeassistant/components/linky/manifest.json | 10 ++++++++ homeassistant/components/linode/manifest.json | 10 ++++++++ .../components/linux_battery/manifest.json | 12 +++++++++ homeassistant/components/lirc/manifest.json | 10 ++++++++ .../components/litejet/manifest.json | 10 ++++++++ .../components/liveboxplaytv/manifest.json | 13 ++++++++++ .../llamalab_automate/manifest.json | 8 ++++++ .../components/local_file/manifest.json | 8 ++++++ .../components/locative/manifest.json | 10 ++++++++ homeassistant/components/lock/manifest.json | 10 ++++++++ .../components/lockitron/manifest.json | 8 ++++++ .../components/logbook/manifest.json | 11 ++++++++ .../components/logentries/manifest.json | 8 ++++++ homeassistant/components/logger/manifest.json | 10 ++++++++ .../components/logi_circle/manifest.json | 10 ++++++++ .../components/london_air/manifest.json | 8 ++++++ .../london_underground/manifest.json | 10 ++++++++ .../components/loopenergy/manifest.json | 10 ++++++++ .../components/lovelace/manifest.json | 10 ++++++++ homeassistant/components/luci/manifest.json | 10 ++++++++ .../components/luftdaten/manifest.json | 12 +++++++++ .../components/lupusec/manifest.json | 10 ++++++++ homeassistant/components/lutron/manifest.json | 10 ++++++++ .../components/lutron_caseta/manifest.json | 10 ++++++++ .../components/lw12wifi/manifest.json | 10 ++++++++ homeassistant/components/lyft/manifest.json | 10 ++++++++ .../components/magicseaweed/manifest.json | 10 ++++++++ .../components/mailbox/manifest.json | 10 ++++++++ .../components/mailgun/manifest.json | 12 +++++++++ homeassistant/components/manual/manifest.json | 8 ++++++ .../components/manual_mqtt/manifest.json | 8 ++++++ homeassistant/components/map/manifest.json | 8 ++++++ .../components/marytts/manifest.json | 8 ++++++ .../components/mastodon/manifest.json | 12 +++++++++ homeassistant/components/matrix/manifest.json | 12 +++++++++ .../components/maxcube/manifest.json | 10 ++++++++ .../components/media_extractor/manifest.json | 12 +++++++++ .../components/media_player/manifest.json | 10 ++++++++ .../components/mediaroom/manifest.json | 12 +++++++++ .../components/melissa/manifest.json | 12 +++++++++ homeassistant/components/meraki/manifest.json | 8 ++++++ .../components/message_bird/manifest.json | 10 ++++++++ homeassistant/components/met/manifest.json | 12 +++++++++ .../components/meteo_france/manifest.json | 10 ++++++++ .../components/metoffice/manifest.json | 10 ++++++++ homeassistant/components/mfi/manifest.json | 10 ++++++++ homeassistant/components/mhz19/manifest.json | 10 ++++++++ .../components/microsoft/manifest.json | 10 ++++++++ .../components/microsoft_face/manifest.json | 10 ++++++++ .../microsoft_face_detect/manifest.json | 8 ++++++ .../microsoft_face_identify/manifest.json | 8 ++++++ .../components/miflora/manifest.json | 13 ++++++++++ .../components/mikrotik/manifest.json | 10 ++++++++ homeassistant/components/mill/manifest.json | 12 +++++++++ .../components/min_max/manifest.json | 10 ++++++++ .../components/mitemp_bt/manifest.json | 10 ++++++++ homeassistant/components/mjpeg/manifest.json | 8 ++++++ .../components/mobile_app/manifest.json | 16 ++++++++++++ homeassistant/components/mochad/manifest.json | 10 ++++++++ homeassistant/components/modbus/manifest.json | 10 ++++++++ .../components/modem_callerid/manifest.json | 10 ++++++++ .../components/mold_indicator/manifest.json | 8 ++++++ .../components/monoprice/manifest.json | 12 +++++++++ homeassistant/components/moon/manifest.json | 10 ++++++++ homeassistant/components/mopar/manifest.json | 10 ++++++++ homeassistant/components/mpchc/manifest.json | 8 ++++++ homeassistant/components/mpd/manifest.json | 12 +++++++++ homeassistant/components/mqtt/manifest.json | 13 ++++++++++ .../components/mqtt_eventstream/manifest.json | 10 ++++++++ .../components/mqtt_json/manifest.json | 8 ++++++ .../components/mqtt_room/manifest.json | 8 ++++++ .../components/mqtt_statestream/manifest.json | 10 ++++++++ .../components/mvglive/manifest.json | 10 ++++++++ .../components/mychevy/manifest.json | 10 ++++++++ .../components/mycroft/manifest.json | 10 ++++++++ homeassistant/components/myq/manifest.json | 10 ++++++++ .../components/mysensors/manifest.json | 10 ++++++++ .../components/mystrom/manifest.json | 12 +++++++++ .../components/mythicbeastsdns/manifest.json | 10 ++++++++ homeassistant/components/nad/manifest.json | 10 ++++++++ .../components/namecheapdns/manifest.json | 10 ++++++++ .../components/nanoleaf/manifest.json | 10 ++++++++ homeassistant/components/neato/manifest.json | 10 ++++++++ .../nederlandse_spoorwegen/manifest.json | 10 ++++++++ homeassistant/components/nello/manifest.json | 12 +++++++++ .../components/ness_alarm/manifest.json | 12 +++++++++ homeassistant/components/nest/manifest.json | 12 +++++++++ .../components/netatmo/manifest.json | 12 +++++++++ .../components/netatmo_public/manifest.json | 8 ++++++ .../components/netdata/manifest.json | 12 +++++++++ .../components/netgear/manifest.json | 10 ++++++++ .../components/netgear_lte/manifest.json | 10 ++++++++ homeassistant/components/netio/manifest.json | 10 ++++++++ .../components/neurio_energy/manifest.json | 10 ++++++++ .../components/nfandroidtv/manifest.json | 8 ++++++ .../niko_home_control/manifest.json | 10 ++++++++ homeassistant/components/nilu/manifest.json | 10 ++++++++ .../components/nissan_leaf/manifest.json | 12 +++++++++ .../components/nmap_tracker/manifest.json | 10 ++++++++ homeassistant/components/nmbs/manifest.json | 12 +++++++++ homeassistant/components/no_ip/manifest.json | 10 ++++++++ .../components/noaa_tides/manifest.json | 10 ++++++++ .../components/norway_air/manifest.json | 10 ++++++++ homeassistant/components/notify/manifest.json | 10 ++++++++ .../components/nsw_fuel_station/manifest.json | 12 +++++++++ .../nsw_rural_fire_service_feed/manifest.json | 10 ++++++++ homeassistant/components/nuheat/manifest.json | 10 ++++++++ .../components/nuimo_controller/manifest.json | 10 ++++++++ homeassistant/components/nuki/manifest.json | 12 +++++++++ homeassistant/components/nut/manifest.json | 10 ++++++++ homeassistant/components/nx584/manifest.json | 10 ++++++++ homeassistant/components/nzbget/manifest.json | 8 ++++++ .../components/octoprint/manifest.json | 8 ++++++ homeassistant/components/oem/manifest.json | 10 ++++++++ .../components/ohmconnect/manifest.json | 12 +++++++++ .../components/onboarding/manifest.json | 13 ++++++++++ .../components/onewire/manifest.json | 8 ++++++ homeassistant/components/onkyo/manifest.json | 10 ++++++++ homeassistant/components/onvif/manifest.json | 12 +++++++++ .../components/openalpr_cloud/manifest.json | 8 ++++++ .../components/openalpr_local/manifest.json | 8 ++++++ homeassistant/components/opencv/manifest.json | 10 ++++++++ .../components/openevse/manifest.json | 10 ++++++++ .../openexchangerates/manifest.json | 8 ++++++ .../components/opengarage/manifest.json | 8 ++++++ .../openhardwaremonitor/manifest.json | 8 ++++++ .../components/openhome/manifest.json | 10 ++++++++ .../components/opensensemap/manifest.json | 10 ++++++++ .../components/opensky/manifest.json | 8 ++++++ .../components/opentherm_gw/manifest.json | 10 ++++++++ homeassistant/components/openuv/manifest.json | 12 +++++++++ .../components/openweathermap/manifest.json | 12 +++++++++ homeassistant/components/opple/manifest.json | 10 ++++++++ homeassistant/components/orvibo/manifest.json | 10 ++++++++ .../components/osramlightify/manifest.json | 10 ++++++++ homeassistant/components/otp/manifest.json | 10 ++++++++ homeassistant/components/owlet/manifest.json | 12 +++++++++ .../components/owntracks/manifest.json | 12 +++++++++ .../components/panasonic_bluray/manifest.json | 10 ++++++++ .../components/panasonic_viera/manifest.json | 11 ++++++++ .../components/pandora/manifest.json | 10 ++++++++ .../components/panel_custom/manifest.json | 12 +++++++++ .../components/panel_iframe/manifest.json | 12 +++++++++ homeassistant/components/pencom/manifest.json | 10 ++++++++ .../persistent_notification/manifest.json | 10 ++++++++ homeassistant/components/person/manifest.json | 8 ++++++ .../components/philips_js/manifest.json | 10 ++++++++ .../components/pi_hole/manifest.json | 12 +++++++++ .../components/picotts/manifest.json | 8 ++++++ homeassistant/components/piglow/manifest.json | 10 ++++++++ .../components/pilight/manifest.json | 10 ++++++++ homeassistant/components/ping/manifest.json | 8 ++++++ .../components/pioneer/manifest.json | 8 ++++++ homeassistant/components/pjlink/manifest.json | 10 ++++++++ homeassistant/components/plant/manifest.json | 13 ++++++++++ homeassistant/components/plex/manifest.json | 10 ++++++++ .../components/plum_lightpad/manifest.json | 10 ++++++++ .../components/pocketcasts/manifest.json | 10 ++++++++ homeassistant/components/point/manifest.json | 14 +++++++++++ homeassistant/components/pollen/manifest.json | 13 ++++++++++ homeassistant/components/postnl/manifest.json | 10 ++++++++ .../components/prezzibenzina/manifest.json | 10 ++++++++ .../components/proliphix/manifest.json | 10 ++++++++ .../components/prometheus/manifest.json | 12 +++++++++ homeassistant/components/prowl/manifest.json | 8 ++++++ .../components/proximity/manifest.json | 11 ++++++++ homeassistant/components/proxy/manifest.json | 10 ++++++++ homeassistant/components/ps4/manifest.json | 10 ++++++++ .../pulseaudio_loopback/manifest.json | 8 ++++++ homeassistant/components/push/manifest.json | 10 ++++++++ .../components/pushbullet/manifest.json | 10 ++++++++ .../components/pushetta/manifest.json | 10 ++++++++ .../components/pushover/manifest.json | 10 ++++++++ .../components/pushsafer/manifest.json | 8 ++++++ .../components/pvoutput/manifest.json | 10 ++++++++ homeassistant/components/pyload/manifest.json | 8 ++++++ .../components/python_script/manifest.json | 10 ++++++++ .../components/qbittorrent/manifest.json | 10 ++++++++ homeassistant/components/qnap/manifest.json | 12 +++++++++ homeassistant/components/qrcode/manifest.json | 11 ++++++++ .../components/quantum_gateway/manifest.json | 12 +++++++++ .../components/qwikswitch/manifest.json | 12 +++++++++ homeassistant/components/rachio/manifest.json | 10 ++++++++ homeassistant/components/radarr/manifest.json | 8 ++++++ .../components/radiotherm/manifest.json | 10 ++++++++ .../components/rainbird/manifest.json | 10 ++++++++ .../components/raincloud/manifest.json | 10 ++++++++ .../components/rainmachine/manifest.json | 12 +++++++++ homeassistant/components/random/manifest.json | 10 ++++++++ .../components/raspihats/manifest.json | 11 ++++++++ .../components/raspyrfm/manifest.json | 10 ++++++++ .../components/recollect_waste/manifest.json | 10 ++++++++ .../components/recorder/manifest.json | 10 ++++++++ .../components/recswitch/manifest.json | 10 ++++++++ homeassistant/components/reddit/manifest.json | 10 ++++++++ .../components/rejseplanen/manifest.json | 10 ++++++++ .../remember_the_milk/manifest.json | 11 ++++++++ homeassistant/components/remote/manifest.json | 10 ++++++++ homeassistant/components/rest/manifest.json | 8 ++++++ .../components/rest_command/manifest.json | 8 ++++++ homeassistant/components/rflink/manifest.json | 10 ++++++++ homeassistant/components/rfxtrx/manifest.json | 12 +++++++++ homeassistant/components/ring/manifest.json | 10 ++++++++ homeassistant/components/ripple/manifest.json | 10 ++++++++ .../components/ritassist/manifest.json | 10 ++++++++ .../components/rmvtransport/manifest.json | 12 +++++++++ .../components/rocketchat/manifest.json | 10 ++++++++ homeassistant/components/roku/manifest.json | 10 ++++++++ homeassistant/components/roomba/manifest.json | 12 +++++++++ .../components/route53/manifest.json | 11 ++++++++ homeassistant/components/rova/manifest.json | 10 ++++++++ .../components/rpi_camera/manifest.json | 8 ++++++ .../components/rpi_gpio/manifest.json | 10 ++++++++ .../components/rpi_gpio_pwm/manifest.json | 10 ++++++++ .../components/rpi_pfio/manifest.json | 11 ++++++++ homeassistant/components/rpi_rf/manifest.json | 10 ++++++++ .../rss_feed_template/manifest.json | 10 ++++++++ .../components/rtorrent/manifest.json | 8 ++++++ .../components/russound_rio/manifest.json | 10 ++++++++ .../components/russound_rnet/manifest.json | 10 ++++++++ homeassistant/components/ruter/manifest.json | 12 +++++++++ .../components/sabnzbd/manifest.json | 10 ++++++++ .../components/samsungtv/manifest.json | 11 ++++++++ .../components/satel_integra/manifest.json | 10 ++++++++ homeassistant/components/scene/manifest.json | 10 ++++++++ homeassistant/components/scrape/manifest.json | 12 +++++++++ homeassistant/components/script/manifest.json | 12 +++++++++ .../components/scsgate/manifest.json | 10 ++++++++ homeassistant/components/season/manifest.json | 10 ++++++++ .../components/sendgrid/manifest.json | 10 ++++++++ homeassistant/components/sense/manifest.json | 10 ++++++++ .../components/sensehat/manifest.json | 10 ++++++++ .../components/sensibo/manifest.json | 12 +++++++++ homeassistant/components/sensor/manifest.json | 8 ++++++ homeassistant/components/serial/manifest.json | 12 +++++++++ .../components/serial_pm/manifest.json | 10 ++++++++ homeassistant/components/sesame/manifest.json | 10 ++++++++ .../components/seven_segments/manifest.json | 8 ++++++ .../components/seventeentrack/manifest.json | 12 +++++++++ .../components/shell_command/manifest.json | 10 ++++++++ homeassistant/components/shiftr/manifest.json | 12 +++++++++ homeassistant/components/shodan/manifest.json | 12 +++++++++ .../components/shopping_list/manifest.json | 10 ++++++++ homeassistant/components/sht31/manifest.json | 11 ++++++++ homeassistant/components/sigfox/manifest.json | 8 ++++++ .../components/simplepush/manifest.json | 10 ++++++++ .../components/simplisafe/manifest.json | 12 +++++++++ .../components/simulated/manifest.json | 8 ++++++ .../components/sisyphus/manifest.json | 10 ++++++++ .../components/sky_hub/manifest.json | 8 ++++++ .../components/skybeacon/manifest.json | 10 ++++++++ .../components/skybell/manifest.json | 10 ++++++++ homeassistant/components/slack/manifest.json | 10 ++++++++ .../components/sleepiq/manifest.json | 10 ++++++++ homeassistant/components/sma/manifest.json | 12 +++++++++ .../components/smappee/manifest.json | 10 ++++++++ .../components/smartthings/manifest.json | 15 +++++++++++ homeassistant/components/smhi/manifest.json | 10 ++++++++ homeassistant/components/smtp/manifest.json | 10 ++++++++ .../components/snapcast/manifest.json | 10 ++++++++ homeassistant/components/snips/manifest.json | 10 ++++++++ homeassistant/components/snmp/manifest.json | 10 ++++++++ .../components/sochain/manifest.json | 10 ++++++++ .../components/socialblade/manifest.json | 10 ++++++++ .../components/solaredge/manifest.json | 11 ++++++++ homeassistant/components/sonarr/manifest.json | 8 ++++++ .../components/songpal/manifest.json | 10 ++++++++ homeassistant/components/sonos/manifest.json | 12 +++++++++ .../components/sony_projector/manifest.json | 10 ++++++++ .../components/soundtouch/manifest.json | 10 ++++++++ .../components/spaceapi/manifest.json | 12 +++++++++ homeassistant/components/spc/manifest.json | 10 ++++++++ .../components/speedtestdotnet/manifest.json | 10 ++++++++ homeassistant/components/spider/manifest.json | 12 +++++++++ homeassistant/components/splunk/manifest.json | 8 ++++++ .../components/spotcrime/manifest.json | 10 ++++++++ .../components/spotify/manifest.json | 10 ++++++++ homeassistant/components/sql/manifest.json | 12 +++++++++ .../components/squeezebox/manifest.json | 8 ++++++ .../components/srp_energy/manifest.json | 10 ++++++++ .../components/starlingbank/manifest.json | 10 ++++++++ .../components/startca/manifest.json | 10 ++++++++ .../components/statistics/manifest.json | 10 ++++++++ homeassistant/components/statsd/manifest.json | 10 ++++++++ .../components/steam_online/manifest.json | 10 ++++++++ homeassistant/components/stream/manifest.json | 12 +++++++++ homeassistant/components/stride/manifest.json | 10 ++++++++ homeassistant/components/sun/manifest.json | 10 ++++++++ .../components/supervisord/manifest.json | 8 ++++++ .../swiss_hydrological_data/manifest.json | 12 +++++++++ .../swiss_public_transport/manifest.json | 12 +++++++++ .../components/swisscom/manifest.json | 8 ++++++ homeassistant/components/switch/manifest.json | 10 ++++++++ .../components/switchbot/manifest.json | 12 +++++++++ .../components/switchmate/manifest.json | 12 +++++++++ .../components/syncthru/manifest.json | 10 ++++++++ .../components/synology/manifest.json | 10 ++++++++ .../components/synology_chat/manifest.json | 8 ++++++ .../components/synology_srm/manifest.json | 12 +++++++++ .../components/synologydsm/manifest.json | 10 ++++++++ homeassistant/components/syslog/manifest.json | 10 ++++++++ .../components/system_health/manifest.json | 10 ++++++++ .../components/system_log/manifest.json | 10 ++++++++ .../components/systemmonitor/manifest.json | 10 ++++++++ .../components/sytadin/manifest.json | 12 +++++++++ homeassistant/components/tado/manifest.json | 10 ++++++++ homeassistant/components/tahoma/manifest.json | 12 +++++++++ .../components/tank_utility/manifest.json | 10 ++++++++ .../components/tapsaff/manifest.json | 10 ++++++++ .../components/tautulli/manifest.json | 12 +++++++++ homeassistant/components/tcp/manifest.json | 8 ++++++ .../components/ted5000/manifest.json | 10 ++++++++ .../components/teksavvy/manifest.json | 8 ++++++ .../components/telegram/manifest.json | 8 ++++++ .../components/telegram_bot/manifest.json | 10 ++++++++ .../components/tellduslive/manifest.json | 12 +++++++++ .../components/tellstick/manifest.json | 11 ++++++++ homeassistant/components/telnet/manifest.json | 8 ++++++ homeassistant/components/temper/manifest.json | 10 ++++++++ .../components/template/manifest.json | 10 ++++++++ .../components/tensorflow/manifest.json | 12 +++++++++ homeassistant/components/tesla/manifest.json | 12 +++++++++ homeassistant/components/tfiac/manifest.json | 13 ++++++++++ .../thermoworks_smoke/manifest.json | 11 ++++++++ .../components/thethingsnetwork/manifest.json | 10 ++++++++ .../components/thingspeak/manifest.json | 10 ++++++++ .../components/thinkingcleaner/manifest.json | 10 ++++++++ .../components/thomson/manifest.json | 8 ++++++ .../components/threshold/manifest.json | 10 ++++++++ homeassistant/components/tibber/manifest.json | 12 +++++++++ .../components/tikteck/manifest.json | 10 ++++++++ homeassistant/components/tile/manifest.json | 12 +++++++++ .../components/time_date/manifest.json | 10 ++++++++ homeassistant/components/timer/manifest.json | 8 ++++++ homeassistant/components/tod/manifest.json | 8 ++++++ .../components/todoist/manifest.json | 10 ++++++++ homeassistant/components/tof/manifest.json | 10 ++++++++ homeassistant/components/tomato/manifest.json | 8 ++++++ homeassistant/components/toon/manifest.json | 12 +++++++++ homeassistant/components/torque/manifest.json | 8 ++++++ .../components/totalconnect/manifest.json | 10 ++++++++ .../components/touchline/manifest.json | 10 ++++++++ homeassistant/components/tplink/manifest.json | 13 ++++++++++ .../components/tplink_lte/manifest.json | 10 ++++++++ .../components/traccar/manifest.json | 13 ++++++++++ homeassistant/components/trackr/manifest.json | 10 ++++++++ .../components/tradfri/manifest.json | 12 +++++++++ .../trafikverket_weatherstation/manifest.json | 10 ++++++++ .../components/transmission/manifest.json | 10 ++++++++ .../components/transport_nsw/manifest.json | 10 ++++++++ .../components/travisci/manifest.json | 10 ++++++++ homeassistant/components/trend/manifest.json | 10 ++++++++ homeassistant/components/tts/manifest.json | 14 +++++++++++ homeassistant/components/tuya/manifest.json | 10 ++++++++ homeassistant/components/twilio/manifest.json | 12 +++++++++ .../components/twilio_call/manifest.json | 10 ++++++++ .../components/twilio_sms/manifest.json | 10 ++++++++ homeassistant/components/twitch/manifest.json | 10 ++++++++ .../components/twitter/manifest.json | 10 ++++++++ homeassistant/components/ubee/manifest.json | 10 ++++++++ homeassistant/components/uber/manifest.json | 12 +++++++++ homeassistant/components/ubus/manifest.json | 8 ++++++ .../components/ue_smart_radio/manifest.json | 8 ++++++ .../components/uk_transport/manifest.json | 8 ++++++ homeassistant/components/unifi/manifest.json | 13 ++++++++++ .../components/unifi_direct/manifest.json | 10 ++++++++ .../components/universal/manifest.json | 8 ++++++ .../components/upc_connect/manifest.json | 10 ++++++++ .../components/upcloud/manifest.json | 12 +++++++++ .../components/updater/manifest.json | 12 +++++++++ homeassistant/components/upnp/manifest.json | 12 +++++++++ homeassistant/components/ups/manifest.json | 10 ++++++++ homeassistant/components/uptime/manifest.json | 8 ++++++ .../components/uptimerobot/manifest.json | 12 +++++++++ homeassistant/components/uscis/manifest.json | 10 ++++++++ .../usgs_earthquakes_feed/manifest.json | 10 ++++++++ homeassistant/components/usps/manifest.json | 10 ++++++++ .../components/utility_meter/manifest.json | 10 ++++++++ homeassistant/components/uvc/manifest.json | 10 ++++++++ homeassistant/components/vacuum/manifest.json | 10 ++++++++ .../components/vasttrafik/manifest.json | 10 ++++++++ homeassistant/components/velbus/manifest.json | 10 ++++++++ homeassistant/components/velux/manifest.json | 12 +++++++++ .../components/venstar/manifest.json | 10 ++++++++ homeassistant/components/vera/manifest.json | 10 ++++++++ .../components/verisure/manifest.json | 11 ++++++++ .../components/version/manifest.json | 12 +++++++++ homeassistant/components/vesync/manifest.json | 10 ++++++++ .../components/viaggiatreno/manifest.json | 8 ++++++ homeassistant/components/vizio/manifest.json | 10 ++++++++ homeassistant/components/vlc/manifest.json | 10 ++++++++ .../components/voicerss/manifest.json | 8 ++++++ .../components/volkszaehler/manifest.json | 10 ++++++++ .../components/volumio/manifest.json | 8 ++++++ .../components/volvooncall/manifest.json | 10 ++++++++ homeassistant/components/vultr/manifest.json | 10 ++++++++ .../components/w800rf32/manifest.json | 10 ++++++++ .../components/wake_on_lan/manifest.json | 10 ++++++++ homeassistant/components/waqi/manifest.json | 12 +++++++++ .../components/water_heater/manifest.json | 8 ++++++ .../components/waterfurnace/manifest.json | 10 ++++++++ .../components/watson_iot/manifest.json | 10 ++++++++ .../components/waze_travel_time/manifest.json | 10 ++++++++ .../components/weather/manifest.json | 10 ++++++++ .../components/webhook/manifest.json | 10 ++++++++ .../components/weblink/manifest.json | 10 ++++++++ .../components/webostv/manifest.json | 11 ++++++++ .../components/websocket_api/manifest.json | 12 +++++++++ homeassistant/components/wemo/manifest.json | 12 +++++++++ homeassistant/components/whois/manifest.json | 10 ++++++++ homeassistant/components/wink/manifest.json | 11 ++++++++ .../components/wirelesstag/manifest.json | 10 ++++++++ .../components/workday/manifest.json | 10 ++++++++ .../components/worldclock/manifest.json | 10 ++++++++ .../components/worldtidesinfo/manifest.json | 8 ++++++ .../components/worxlandroid/manifest.json | 8 ++++++ homeassistant/components/wsdot/manifest.json | 8 ++++++ .../components/wunderground/manifest.json | 8 ++++++ .../components/wunderlist/manifest.json | 10 ++++++++ homeassistant/components/x10/manifest.json | 8 ++++++ .../components/xbox_live/manifest.json | 10 ++++++++ homeassistant/components/xeoma/manifest.json | 10 ++++++++ .../components/xfinity/manifest.json | 12 +++++++++ homeassistant/components/xiaomi/manifest.json | 8 ++++++ .../components/xiaomi_aqara/manifest.json | 13 ++++++++++ .../components/xiaomi_miio/manifest.json | 14 +++++++++++ .../components/xiaomi_tv/manifest.json | 12 +++++++++ homeassistant/components/xmpp/manifest.json | 12 +++++++++ homeassistant/components/xs1/manifest.json | 10 ++++++++ .../components/yale_smart_alarm/manifest.json | 10 ++++++++ homeassistant/components/yamaha/manifest.json | 10 ++++++++ .../components/yamaha_musiccast/manifest.json | 12 +++++++++ .../components/yandextts/manifest.json | 8 ++++++ .../components/yeelight/manifest.json | 13 ++++++++++ .../yeelightsunflower/manifest.json | 12 +++++++++ .../components/yessssms/manifest.json | 12 +++++++++ homeassistant/components/yi/manifest.json | 12 +++++++++ homeassistant/components/yr/manifest.json | 10 ++++++++ .../components/yweather/manifest.json | 10 ++++++++ homeassistant/components/zabbix/manifest.json | 10 ++++++++ homeassistant/components/zamg/manifest.json | 8 ++++++ homeassistant/components/zengge/manifest.json | 10 ++++++++ .../components/zeroconf/manifest.json | 14 +++++++++++ .../components/zestimate/manifest.json | 10 ++++++++ homeassistant/components/zha/manifest.json | 17 +++++++++++++ .../components/zhong_hong/manifest.json | 10 ++++++++ homeassistant/components/zigbee/manifest.json | 10 ++++++++ .../ziggo_mediabox_xl/manifest.json | 10 ++++++++ homeassistant/components/zone/manifest.json | 10 ++++++++ .../components/zoneminder/manifest.json | 12 +++++++++ homeassistant/components/zwave/manifest.json | 13 ++++++++++ 818 files changed, 8378 insertions(+), 4 deletions(-) create mode 100644 homeassistant/components/abode/manifest.json create mode 100644 homeassistant/components/acer_projector/manifest.json create mode 100644 homeassistant/components/actiontec/manifest.json create mode 100644 homeassistant/components/ads/manifest.json create mode 100644 homeassistant/components/aftership/manifest.json create mode 100644 homeassistant/components/air_quality/manifest.json create mode 100644 homeassistant/components/airvisual/manifest.json create mode 100644 homeassistant/components/aladdin_connect/manifest.json create mode 100644 homeassistant/components/alarm_control_panel/manifest.json create mode 100644 homeassistant/components/alarmdecoder/manifest.json create mode 100644 homeassistant/components/alarmdotcom/manifest.json create mode 100644 homeassistant/components/alert/manifest.json create mode 100644 homeassistant/components/alexa/manifest.json create mode 100644 homeassistant/components/alpha_vantage/manifest.json create mode 100644 homeassistant/components/amazon_polly/manifest.json create mode 100644 homeassistant/components/ambient_station/manifest.json create mode 100644 homeassistant/components/amcrest/manifest.json create mode 100644 homeassistant/components/ampio/manifest.json create mode 100644 homeassistant/components/android_ip_webcam/manifest.json create mode 100644 homeassistant/components/androidtv/manifest.json create mode 100644 homeassistant/components/anel_pwrctrl/manifest.json create mode 100644 homeassistant/components/anthemav/manifest.json create mode 100644 homeassistant/components/apcupsd/manifest.json create mode 100644 homeassistant/components/api/manifest.json delete mode 100644 homeassistant/components/api_streams/__init__.py create mode 100644 homeassistant/components/apns/manifest.json create mode 100644 homeassistant/components/apple_tv/manifest.json create mode 100644 homeassistant/components/aqualogic/manifest.json create mode 100644 homeassistant/components/aquostv/manifest.json create mode 100644 homeassistant/components/arduino/manifest.json create mode 100644 homeassistant/components/arest/manifest.json create mode 100644 homeassistant/components/arlo/manifest.json create mode 100644 homeassistant/components/aruba/manifest.json create mode 100644 homeassistant/components/arwn/manifest.json create mode 100644 homeassistant/components/asterisk_cdr/manifest.json create mode 100644 homeassistant/components/asterisk_mbox/manifest.json create mode 100644 homeassistant/components/asuswrt/manifest.json create mode 100644 homeassistant/components/august/manifest.json create mode 100644 homeassistant/components/aurora/manifest.json create mode 100644 homeassistant/components/auth/manifest.json create mode 100644 homeassistant/components/automatic/manifest.json create mode 100644 homeassistant/components/automation/manifest.json create mode 100644 homeassistant/components/avion/manifest.json create mode 100644 homeassistant/components/awair/manifest.json create mode 100644 homeassistant/components/aws/manifest.json create mode 100644 homeassistant/components/aws_lambda/manifest.json create mode 100644 homeassistant/components/aws_sns/manifest.json create mode 100644 homeassistant/components/aws_sqs/manifest.json create mode 100644 homeassistant/components/axis/manifest.json create mode 100644 homeassistant/components/baidu/manifest.json create mode 100644 homeassistant/components/bayesian/manifest.json create mode 100644 homeassistant/components/bbb_gpio/manifest.json create mode 100644 homeassistant/components/bbox/manifest.json create mode 100644 homeassistant/components/bh1750/manifest.json create mode 100644 homeassistant/components/binary_sensor/manifest.json create mode 100644 homeassistant/components/bitcoin/manifest.json create mode 100644 homeassistant/components/blackbird/manifest.json create mode 100644 homeassistant/components/blink/manifest.json create mode 100644 homeassistant/components/blinksticklight/manifest.json create mode 100644 homeassistant/components/blinkt/manifest.json create mode 100644 homeassistant/components/blockchain/manifest.json create mode 100644 homeassistant/components/bloomsky/manifest.json create mode 100644 homeassistant/components/bluesound/manifest.json create mode 100644 homeassistant/components/bluetooth_le_tracker/manifest.json create mode 100644 homeassistant/components/bluetooth_tracker/manifest.json create mode 100644 homeassistant/components/bme280/manifest.json create mode 100644 homeassistant/components/bme680/manifest.json create mode 100644 homeassistant/components/bmw_connected_drive/manifest.json create mode 100644 homeassistant/components/bom/manifest.json create mode 100644 homeassistant/components/braviatv/manifest.json create mode 100644 homeassistant/components/broadlink/manifest.json create mode 100644 homeassistant/components/brottsplatskartan/manifest.json create mode 100644 homeassistant/components/browser/manifest.json create mode 100644 homeassistant/components/brunt/manifest.json create mode 100644 homeassistant/components/bt_home_hub_5/manifest.json create mode 100644 homeassistant/components/bt_smarthub/manifest.json create mode 100644 homeassistant/components/buienradar/manifest.json create mode 100644 homeassistant/components/caldav/manifest.json create mode 100644 homeassistant/components/calendar/manifest.json create mode 100644 homeassistant/components/camera/manifest.json create mode 100644 homeassistant/components/canary/manifest.json create mode 100644 homeassistant/components/cast/manifest.json create mode 100644 homeassistant/components/cert_expiry/manifest.json create mode 100644 homeassistant/components/channels/manifest.json create mode 100644 homeassistant/components/cisco_ios/manifest.json create mode 100644 homeassistant/components/cisco_mobility_express/manifest.json create mode 100644 homeassistant/components/cisco_webex_teams/manifest.json create mode 100644 homeassistant/components/ciscospark/manifest.json create mode 100644 homeassistant/components/citybikes/manifest.json create mode 100644 homeassistant/components/clementine/manifest.json create mode 100644 homeassistant/components/clickatell/manifest.json create mode 100644 homeassistant/components/clicksend/manifest.json create mode 100644 homeassistant/components/clicksend_tts/manifest.json create mode 100644 homeassistant/components/climate/manifest.json create mode 100644 homeassistant/components/cloud/manifest.json create mode 100644 homeassistant/components/cloudflare/manifest.json create mode 100644 homeassistant/components/cmus/manifest.json create mode 100644 homeassistant/components/co2signal/manifest.json create mode 100644 homeassistant/components/coinbase/manifest.json create mode 100644 homeassistant/components/coinmarketcap/manifest.json create mode 100644 homeassistant/components/comed_hourly_pricing/manifest.json create mode 100644 homeassistant/components/comfoconnect/manifest.json create mode 100644 homeassistant/components/command_line/manifest.json create mode 100644 homeassistant/components/concord232/manifest.json create mode 100644 homeassistant/components/config/manifest.json create mode 100644 homeassistant/components/configurator/manifest.json create mode 100644 homeassistant/components/conversation/manifest.json create mode 100644 homeassistant/components/coolmaster/manifest.json create mode 100644 homeassistant/components/counter/manifest.json create mode 100644 homeassistant/components/cover/manifest.json create mode 100644 homeassistant/components/cppm_tracker/manifest.json create mode 100644 homeassistant/components/cpuspeed/manifest.json create mode 100644 homeassistant/components/crimereports/manifest.json create mode 100644 homeassistant/components/cups/manifest.json create mode 100644 homeassistant/components/currencylayer/manifest.json create mode 100644 homeassistant/components/daikin/manifest.json create mode 100644 homeassistant/components/danfoss_air/manifest.json create mode 100644 homeassistant/components/darksky/manifest.json create mode 100644 homeassistant/components/datadog/manifest.json create mode 100644 homeassistant/components/ddwrt/manifest.json create mode 100644 homeassistant/components/deconz/manifest.json create mode 100644 homeassistant/components/decora/manifest.json create mode 100644 homeassistant/components/decora_wifi/manifest.json create mode 100644 homeassistant/components/default_config/manifest.json create mode 100644 homeassistant/components/deluge/manifest.json create mode 100644 homeassistant/components/demo/manifest.json create mode 100644 homeassistant/components/denon/manifest.json create mode 100644 homeassistant/components/denonavr/manifest.json create mode 100644 homeassistant/components/deutsche_bahn/manifest.json create mode 100644 homeassistant/components/device_sun_light_trigger/manifest.json create mode 100644 homeassistant/components/device_tracker/manifest.json create mode 100644 homeassistant/components/dht/manifest.json create mode 100644 homeassistant/components/dialogflow/manifest.json create mode 100644 homeassistant/components/digital_ocean/manifest.json create mode 100644 homeassistant/components/digitalloggers/manifest.json create mode 100644 homeassistant/components/directv/manifest.json create mode 100644 homeassistant/components/discogs/manifest.json create mode 100644 homeassistant/components/discord/manifest.json create mode 100644 homeassistant/components/discovery/manifest.json create mode 100644 homeassistant/components/dlib_face_detect/manifest.json create mode 100644 homeassistant/components/dlib_face_identify/manifest.json create mode 100644 homeassistant/components/dlink/manifest.json create mode 100644 homeassistant/components/dlna_dmr/manifest.json create mode 100644 homeassistant/components/dnsip/manifest.json create mode 100644 homeassistant/components/dominos/manifest.json create mode 100644 homeassistant/components/doorbird/manifest.json create mode 100644 homeassistant/components/dovado/manifest.json create mode 100644 homeassistant/components/downloader/manifest.json create mode 100644 homeassistant/components/dsmr/manifest.json create mode 100644 homeassistant/components/dte_energy_bridge/manifest.json create mode 100644 homeassistant/components/dublin_bus_transport/manifest.json create mode 100644 homeassistant/components/duckdns/manifest.json create mode 100644 homeassistant/components/duke_energy/manifest.json create mode 100644 homeassistant/components/dunehd/manifest.json create mode 100644 homeassistant/components/dwd_weather_warnings/manifest.json create mode 100644 homeassistant/components/dweet/manifest.json create mode 100644 homeassistant/components/dyson/manifest.json create mode 100644 homeassistant/components/ebox/manifest.json create mode 100644 homeassistant/components/ebusd/manifest.json create mode 100644 homeassistant/components/ecoal_boiler/manifest.json create mode 100644 homeassistant/components/ecobee/manifest.json create mode 100644 homeassistant/components/econet/manifest.json create mode 100644 homeassistant/components/ecovacs/manifest.json create mode 100644 homeassistant/components/eddystone_temperature/manifest.json create mode 100644 homeassistant/components/edimax/manifest.json create mode 100644 homeassistant/components/edp_redy/manifest.json create mode 100644 homeassistant/components/ee_brightbox/manifest.json create mode 100644 homeassistant/components/efergy/manifest.json create mode 100644 homeassistant/components/egardia/manifest.json create mode 100644 homeassistant/components/eight_sleep/manifest.json create mode 100644 homeassistant/components/eliqonline/manifest.json create mode 100644 homeassistant/components/elkm1/manifest.json create mode 100644 homeassistant/components/emby/manifest.json create mode 100644 homeassistant/components/emoncms/manifest.json create mode 100644 homeassistant/components/emoncms_history/manifest.json create mode 100644 homeassistant/components/emulated_hue/manifest.json create mode 100644 homeassistant/components/emulated_roku/manifest.json create mode 100644 homeassistant/components/enigma2/manifest.json create mode 100644 homeassistant/components/enocean/manifest.json create mode 100644 homeassistant/components/enphase_envoy/manifest.json create mode 100644 homeassistant/components/entur_public_transport/manifest.json create mode 100644 homeassistant/components/envirophat/manifest.json create mode 100644 homeassistant/components/envisalink/manifest.json create mode 100644 homeassistant/components/ephember/manifest.json create mode 100644 homeassistant/components/epson/manifest.json create mode 100644 homeassistant/components/eq3btsmart/manifest.json create mode 100644 homeassistant/components/esphome/manifest.json create mode 100644 homeassistant/components/etherscan/manifest.json create mode 100644 homeassistant/components/eufy/manifest.json create mode 100644 homeassistant/components/everlights/manifest.json create mode 100644 homeassistant/components/evohome/manifest.json create mode 100644 homeassistant/components/facebook/manifest.json create mode 100644 homeassistant/components/facebox/manifest.json create mode 100644 homeassistant/components/fail2ban/manifest.json create mode 100644 homeassistant/components/familyhub/manifest.json create mode 100644 homeassistant/components/fan/manifest.json create mode 100644 homeassistant/components/fastdotcom/manifest.json create mode 100644 homeassistant/components/fedex/manifest.json create mode 100644 homeassistant/components/feedreader/manifest.json create mode 100644 homeassistant/components/ffmpeg/manifest.json create mode 100644 homeassistant/components/ffmpeg_motion/manifest.json create mode 100644 homeassistant/components/ffmpeg_noise/manifest.json create mode 100644 homeassistant/components/fibaro/manifest.json create mode 100644 homeassistant/components/fido/manifest.json create mode 100644 homeassistant/components/file/manifest.json create mode 100644 homeassistant/components/filesize/manifest.json create mode 100644 homeassistant/components/filter/manifest.json create mode 100644 homeassistant/components/fints/manifest.json create mode 100644 homeassistant/components/fitbit/manifest.json create mode 100644 homeassistant/components/fixer/manifest.json create mode 100644 homeassistant/components/flexit/manifest.json create mode 100644 homeassistant/components/flic/manifest.json create mode 100644 homeassistant/components/flock/manifest.json create mode 100644 homeassistant/components/flunearyou/manifest.json create mode 100644 homeassistant/components/flux/manifest.json create mode 100644 homeassistant/components/flux_led/manifest.json create mode 100644 homeassistant/components/folder/manifest.json create mode 100644 homeassistant/components/folder_watcher/manifest.json create mode 100644 homeassistant/components/foobot/manifest.json create mode 100644 homeassistant/components/foscam/manifest.json create mode 100644 homeassistant/components/foursquare/manifest.json create mode 100644 homeassistant/components/free_mobile/manifest.json create mode 100644 homeassistant/components/freebox/manifest.json create mode 100644 homeassistant/components/freedns/manifest.json create mode 100644 homeassistant/components/fritz/manifest.json create mode 100644 homeassistant/components/fritzbox/manifest.json create mode 100644 homeassistant/components/fritzbox_callmonitor/manifest.json create mode 100644 homeassistant/components/fritzbox_netmonitor/manifest.json create mode 100644 homeassistant/components/fritzdect/manifest.json create mode 100644 homeassistant/components/frontend/manifest.json create mode 100644 homeassistant/components/frontier_silicon/manifest.json create mode 100644 homeassistant/components/futurenow/manifest.json create mode 100644 homeassistant/components/garadget/manifest.json create mode 100644 homeassistant/components/gc100/manifest.json create mode 100644 homeassistant/components/gearbest/manifest.json create mode 100644 homeassistant/components/geizhals/manifest.json create mode 100644 homeassistant/components/generic/manifest.json create mode 100644 homeassistant/components/generic_thermostat/manifest.json create mode 100644 homeassistant/components/geo_json_events/manifest.json create mode 100644 homeassistant/components/geo_location/manifest.json create mode 100644 homeassistant/components/geo_rss_events/manifest.json create mode 100644 homeassistant/components/geofency/manifest.json create mode 100644 homeassistant/components/github/manifest.json create mode 100644 homeassistant/components/gitlab_ci/manifest.json create mode 100644 homeassistant/components/gitter/manifest.json create mode 100644 homeassistant/components/glances/manifest.json create mode 100644 homeassistant/components/gntp/manifest.json create mode 100644 homeassistant/components/goalfeed/manifest.json create mode 100644 homeassistant/components/gogogate2/manifest.json create mode 100644 homeassistant/components/google/manifest.json create mode 100644 homeassistant/components/google_assistant/manifest.json create mode 100644 homeassistant/components/google_domains/manifest.json create mode 100644 homeassistant/components/google_maps/manifest.json create mode 100644 homeassistant/components/google_pubsub/manifest.json create mode 100644 homeassistant/components/google_travel_time/manifest.json create mode 100644 homeassistant/components/google_wifi/manifest.json create mode 100644 homeassistant/components/googlehome/manifest.json create mode 100644 homeassistant/components/gpmdp/manifest.json create mode 100644 homeassistant/components/gpsd/manifest.json create mode 100644 homeassistant/components/gpslogger/manifest.json create mode 100644 homeassistant/components/graphite/manifest.json create mode 100644 homeassistant/components/greeneye_monitor/manifest.json create mode 100644 homeassistant/components/greenwave/manifest.json create mode 100644 homeassistant/components/group/manifest.json create mode 100644 homeassistant/components/gstreamer/manifest.json create mode 100644 homeassistant/components/gtfs/manifest.json create mode 100644 homeassistant/components/gtt/manifest.json create mode 100644 homeassistant/components/habitica/manifest.json create mode 100644 homeassistant/components/hangouts/manifest.json create mode 100644 homeassistant/components/harman_kardon_avr/manifest.json create mode 100644 homeassistant/components/harmony/manifest.json create mode 100644 homeassistant/components/hassio/manifest.json create mode 100644 homeassistant/components/haveibeenpwned/manifest.json create mode 100644 homeassistant/components/hddtemp/manifest.json create mode 100644 homeassistant/components/hdmi_cec/manifest.json create mode 100644 homeassistant/components/heatmiser/manifest.json create mode 100644 homeassistant/components/heos/manifest.json create mode 100644 homeassistant/components/hikvision/manifest.json create mode 100644 homeassistant/components/hikvisioncam/manifest.json create mode 100644 homeassistant/components/hipchat/manifest.json create mode 100644 homeassistant/components/history/manifest.json create mode 100644 homeassistant/components/history_graph/manifest.json create mode 100644 homeassistant/components/history_stats/manifest.json create mode 100644 homeassistant/components/hitron_coda/manifest.json create mode 100644 homeassistant/components/hive/manifest.json create mode 100644 homeassistant/components/hlk_sw16/manifest.json create mode 100644 homeassistant/components/homeassistant/manifest.json create mode 100644 homeassistant/components/homekit/manifest.json create mode 100644 homeassistant/components/homekit_controller/manifest.json create mode 100644 homeassistant/components/homematic/manifest.json create mode 100644 homeassistant/components/homematicip_cloud/manifest.json create mode 100644 homeassistant/components/homeworks/manifest.json create mode 100644 homeassistant/components/honeywell/manifest.json create mode 100644 homeassistant/components/hook/manifest.json create mode 100644 homeassistant/components/horizon/manifest.json create mode 100644 homeassistant/components/hp_ilo/manifest.json create mode 100644 homeassistant/components/html5/manifest.json create mode 100644 homeassistant/components/http/manifest.json create mode 100644 homeassistant/components/htu21d/manifest.json create mode 100644 homeassistant/components/huawei_lte/manifest.json create mode 100644 homeassistant/components/huawei_router/manifest.json create mode 100644 homeassistant/components/hue/manifest.json create mode 100644 homeassistant/components/hunterdouglas_powerview/manifest.json create mode 100644 homeassistant/components/hydrawise/manifest.json create mode 100644 homeassistant/components/hydroquebec/manifest.json create mode 100644 homeassistant/components/hyperion/manifest.json create mode 100644 homeassistant/components/ialarm/manifest.json create mode 100644 homeassistant/components/icloud/manifest.json create mode 100644 homeassistant/components/idteck_prox/manifest.json create mode 100644 homeassistant/components/ifttt/manifest.json create mode 100644 homeassistant/components/iglo/manifest.json create mode 100644 homeassistant/components/ihc/manifest.json create mode 100644 homeassistant/components/image_processing/manifest.json create mode 100644 homeassistant/components/imap/manifest.json create mode 100644 homeassistant/components/imap_email_content/manifest.json create mode 100644 homeassistant/components/influxdb/manifest.json create mode 100644 homeassistant/components/input_boolean/manifest.json create mode 100644 homeassistant/components/input_datetime/manifest.json create mode 100644 homeassistant/components/input_number/manifest.json create mode 100644 homeassistant/components/input_select/manifest.json create mode 100644 homeassistant/components/input_text/manifest.json create mode 100644 homeassistant/components/insteon/manifest.json create mode 100644 homeassistant/components/insteon_local/manifest.json create mode 100644 homeassistant/components/insteon_plm/manifest.json create mode 100644 homeassistant/components/integration/manifest.json create mode 100644 homeassistant/components/intent_script/manifest.json create mode 100644 homeassistant/components/introduction/manifest.json create mode 100644 homeassistant/components/ios/manifest.json create mode 100644 homeassistant/components/iota/manifest.json create mode 100644 homeassistant/components/iperf3/manifest.json create mode 100644 homeassistant/components/ipma/manifest.json create mode 100644 homeassistant/components/irish_rail_transport/manifest.json create mode 100644 homeassistant/components/islamic_prayer_times/manifest.json create mode 100644 homeassistant/components/iss/manifest.json create mode 100644 homeassistant/components/isy994/manifest.json create mode 100644 homeassistant/components/itach/manifest.json create mode 100644 homeassistant/components/itunes/manifest.json create mode 100644 homeassistant/components/jewish_calendar/manifest.json create mode 100644 homeassistant/components/joaoapps_join/manifest.json create mode 100644 homeassistant/components/juicenet/manifest.json create mode 100644 homeassistant/components/kankun/manifest.json create mode 100644 homeassistant/components/keenetic_ndms2/manifest.json create mode 100644 homeassistant/components/keyboard/manifest.json create mode 100644 homeassistant/components/keyboard_remote/manifest.json create mode 100644 homeassistant/components/kira/manifest.json create mode 100644 homeassistant/components/kiwi/manifest.json create mode 100644 homeassistant/components/knx/manifest.json create mode 100644 homeassistant/components/kodi/manifest.json create mode 100644 homeassistant/components/konnected/manifest.json create mode 100644 homeassistant/components/kwb/manifest.json create mode 100644 homeassistant/components/lacrosse/manifest.json create mode 100644 homeassistant/components/lametric/manifest.json create mode 100644 homeassistant/components/lannouncer/manifest.json create mode 100644 homeassistant/components/lastfm/manifest.json create mode 100644 homeassistant/components/launch_library/manifest.json create mode 100644 homeassistant/components/lcn/manifest.json create mode 100644 homeassistant/components/lg_netcast/manifest.json create mode 100644 homeassistant/components/lg_soundbar/manifest.json create mode 100644 homeassistant/components/lifx/manifest.json create mode 100644 homeassistant/components/lifx_cloud/manifest.json create mode 100644 homeassistant/components/lifx_legacy/manifest.json create mode 100644 homeassistant/components/light/manifest.json create mode 100644 homeassistant/components/lightwave/manifest.json create mode 100644 homeassistant/components/limitlessled/manifest.json create mode 100644 homeassistant/components/linksys_ap/manifest.json create mode 100644 homeassistant/components/linksys_smart/manifest.json create mode 100644 homeassistant/components/linky/manifest.json create mode 100644 homeassistant/components/linode/manifest.json create mode 100644 homeassistant/components/linux_battery/manifest.json create mode 100644 homeassistant/components/lirc/manifest.json create mode 100644 homeassistant/components/litejet/manifest.json create mode 100644 homeassistant/components/liveboxplaytv/manifest.json create mode 100644 homeassistant/components/llamalab_automate/manifest.json create mode 100644 homeassistant/components/local_file/manifest.json create mode 100644 homeassistant/components/locative/manifest.json create mode 100644 homeassistant/components/lock/manifest.json create mode 100644 homeassistant/components/lockitron/manifest.json create mode 100644 homeassistant/components/logbook/manifest.json create mode 100644 homeassistant/components/logentries/manifest.json create mode 100644 homeassistant/components/logger/manifest.json create mode 100644 homeassistant/components/logi_circle/manifest.json create mode 100644 homeassistant/components/london_air/manifest.json create mode 100644 homeassistant/components/london_underground/manifest.json create mode 100644 homeassistant/components/loopenergy/manifest.json create mode 100644 homeassistant/components/lovelace/manifest.json create mode 100644 homeassistant/components/luci/manifest.json create mode 100644 homeassistant/components/luftdaten/manifest.json create mode 100644 homeassistant/components/lupusec/manifest.json create mode 100644 homeassistant/components/lutron/manifest.json create mode 100644 homeassistant/components/lutron_caseta/manifest.json create mode 100644 homeassistant/components/lw12wifi/manifest.json create mode 100644 homeassistant/components/lyft/manifest.json create mode 100644 homeassistant/components/magicseaweed/manifest.json create mode 100644 homeassistant/components/mailbox/manifest.json create mode 100644 homeassistant/components/mailgun/manifest.json create mode 100644 homeassistant/components/manual/manifest.json create mode 100644 homeassistant/components/manual_mqtt/manifest.json create mode 100644 homeassistant/components/map/manifest.json create mode 100644 homeassistant/components/marytts/manifest.json create mode 100644 homeassistant/components/mastodon/manifest.json create mode 100644 homeassistant/components/matrix/manifest.json create mode 100644 homeassistant/components/maxcube/manifest.json create mode 100644 homeassistant/components/media_extractor/manifest.json create mode 100644 homeassistant/components/media_player/manifest.json create mode 100644 homeassistant/components/mediaroom/manifest.json create mode 100644 homeassistant/components/melissa/manifest.json create mode 100644 homeassistant/components/meraki/manifest.json create mode 100644 homeassistant/components/message_bird/manifest.json create mode 100644 homeassistant/components/met/manifest.json create mode 100644 homeassistant/components/meteo_france/manifest.json create mode 100644 homeassistant/components/metoffice/manifest.json create mode 100644 homeassistant/components/mfi/manifest.json create mode 100644 homeassistant/components/mhz19/manifest.json create mode 100644 homeassistant/components/microsoft/manifest.json create mode 100644 homeassistant/components/microsoft_face/manifest.json create mode 100644 homeassistant/components/microsoft_face_detect/manifest.json create mode 100644 homeassistant/components/microsoft_face_identify/manifest.json create mode 100644 homeassistant/components/miflora/manifest.json create mode 100644 homeassistant/components/mikrotik/manifest.json create mode 100644 homeassistant/components/mill/manifest.json create mode 100644 homeassistant/components/min_max/manifest.json create mode 100644 homeassistant/components/mitemp_bt/manifest.json create mode 100644 homeassistant/components/mjpeg/manifest.json create mode 100644 homeassistant/components/mobile_app/manifest.json create mode 100644 homeassistant/components/mochad/manifest.json create mode 100644 homeassistant/components/modbus/manifest.json create mode 100644 homeassistant/components/modem_callerid/manifest.json create mode 100644 homeassistant/components/mold_indicator/manifest.json create mode 100644 homeassistant/components/monoprice/manifest.json create mode 100644 homeassistant/components/moon/manifest.json create mode 100644 homeassistant/components/mopar/manifest.json create mode 100644 homeassistant/components/mpchc/manifest.json create mode 100644 homeassistant/components/mpd/manifest.json create mode 100644 homeassistant/components/mqtt/manifest.json create mode 100644 homeassistant/components/mqtt_eventstream/manifest.json create mode 100644 homeassistant/components/mqtt_json/manifest.json create mode 100644 homeassistant/components/mqtt_room/manifest.json create mode 100644 homeassistant/components/mqtt_statestream/manifest.json create mode 100644 homeassistant/components/mvglive/manifest.json create mode 100644 homeassistant/components/mychevy/manifest.json create mode 100644 homeassistant/components/mycroft/manifest.json create mode 100644 homeassistant/components/myq/manifest.json create mode 100644 homeassistant/components/mysensors/manifest.json create mode 100644 homeassistant/components/mystrom/manifest.json create mode 100644 homeassistant/components/mythicbeastsdns/manifest.json create mode 100644 homeassistant/components/nad/manifest.json create mode 100644 homeassistant/components/namecheapdns/manifest.json create mode 100644 homeassistant/components/nanoleaf/manifest.json create mode 100644 homeassistant/components/neato/manifest.json create mode 100644 homeassistant/components/nederlandse_spoorwegen/manifest.json create mode 100644 homeassistant/components/nello/manifest.json create mode 100644 homeassistant/components/ness_alarm/manifest.json create mode 100644 homeassistant/components/nest/manifest.json create mode 100644 homeassistant/components/netatmo/manifest.json create mode 100644 homeassistant/components/netatmo_public/manifest.json create mode 100644 homeassistant/components/netdata/manifest.json create mode 100644 homeassistant/components/netgear/manifest.json create mode 100644 homeassistant/components/netgear_lte/manifest.json create mode 100644 homeassistant/components/netio/manifest.json create mode 100644 homeassistant/components/neurio_energy/manifest.json create mode 100644 homeassistant/components/nfandroidtv/manifest.json create mode 100644 homeassistant/components/niko_home_control/manifest.json create mode 100644 homeassistant/components/nilu/manifest.json create mode 100644 homeassistant/components/nissan_leaf/manifest.json create mode 100644 homeassistant/components/nmap_tracker/manifest.json create mode 100644 homeassistant/components/nmbs/manifest.json create mode 100644 homeassistant/components/no_ip/manifest.json create mode 100644 homeassistant/components/noaa_tides/manifest.json create mode 100644 homeassistant/components/norway_air/manifest.json create mode 100644 homeassistant/components/notify/manifest.json create mode 100644 homeassistant/components/nsw_fuel_station/manifest.json create mode 100644 homeassistant/components/nsw_rural_fire_service_feed/manifest.json create mode 100644 homeassistant/components/nuheat/manifest.json create mode 100644 homeassistant/components/nuimo_controller/manifest.json create mode 100644 homeassistant/components/nuki/manifest.json create mode 100644 homeassistant/components/nut/manifest.json create mode 100644 homeassistant/components/nx584/manifest.json create mode 100644 homeassistant/components/nzbget/manifest.json create mode 100644 homeassistant/components/octoprint/manifest.json create mode 100644 homeassistant/components/oem/manifest.json create mode 100644 homeassistant/components/ohmconnect/manifest.json create mode 100644 homeassistant/components/onboarding/manifest.json create mode 100644 homeassistant/components/onewire/manifest.json create mode 100644 homeassistant/components/onkyo/manifest.json create mode 100644 homeassistant/components/onvif/manifest.json create mode 100644 homeassistant/components/openalpr_cloud/manifest.json create mode 100644 homeassistant/components/openalpr_local/manifest.json create mode 100644 homeassistant/components/opencv/manifest.json create mode 100644 homeassistant/components/openevse/manifest.json create mode 100644 homeassistant/components/openexchangerates/manifest.json create mode 100644 homeassistant/components/opengarage/manifest.json create mode 100644 homeassistant/components/openhardwaremonitor/manifest.json create mode 100644 homeassistant/components/openhome/manifest.json create mode 100644 homeassistant/components/opensensemap/manifest.json create mode 100644 homeassistant/components/opensky/manifest.json create mode 100644 homeassistant/components/opentherm_gw/manifest.json create mode 100644 homeassistant/components/openuv/manifest.json create mode 100644 homeassistant/components/openweathermap/manifest.json create mode 100644 homeassistant/components/opple/manifest.json create mode 100644 homeassistant/components/orvibo/manifest.json create mode 100644 homeassistant/components/osramlightify/manifest.json create mode 100644 homeassistant/components/otp/manifest.json create mode 100644 homeassistant/components/owlet/manifest.json create mode 100644 homeassistant/components/owntracks/manifest.json create mode 100644 homeassistant/components/panasonic_bluray/manifest.json create mode 100644 homeassistant/components/panasonic_viera/manifest.json create mode 100644 homeassistant/components/pandora/manifest.json create mode 100644 homeassistant/components/panel_custom/manifest.json create mode 100644 homeassistant/components/panel_iframe/manifest.json create mode 100644 homeassistant/components/pencom/manifest.json create mode 100644 homeassistant/components/persistent_notification/manifest.json create mode 100644 homeassistant/components/person/manifest.json create mode 100644 homeassistant/components/philips_js/manifest.json create mode 100644 homeassistant/components/pi_hole/manifest.json create mode 100644 homeassistant/components/picotts/manifest.json create mode 100644 homeassistant/components/piglow/manifest.json create mode 100644 homeassistant/components/pilight/manifest.json create mode 100644 homeassistant/components/ping/manifest.json create mode 100644 homeassistant/components/pioneer/manifest.json create mode 100644 homeassistant/components/pjlink/manifest.json create mode 100644 homeassistant/components/plant/manifest.json create mode 100644 homeassistant/components/plex/manifest.json create mode 100644 homeassistant/components/plum_lightpad/manifest.json create mode 100644 homeassistant/components/pocketcasts/manifest.json create mode 100644 homeassistant/components/point/manifest.json create mode 100644 homeassistant/components/pollen/manifest.json create mode 100644 homeassistant/components/postnl/manifest.json create mode 100644 homeassistant/components/prezzibenzina/manifest.json create mode 100644 homeassistant/components/proliphix/manifest.json create mode 100644 homeassistant/components/prometheus/manifest.json create mode 100644 homeassistant/components/prowl/manifest.json create mode 100644 homeassistant/components/proximity/manifest.json create mode 100644 homeassistant/components/proxy/manifest.json create mode 100644 homeassistant/components/ps4/manifest.json create mode 100644 homeassistant/components/pulseaudio_loopback/manifest.json create mode 100644 homeassistant/components/push/manifest.json create mode 100644 homeassistant/components/pushbullet/manifest.json create mode 100644 homeassistant/components/pushetta/manifest.json create mode 100644 homeassistant/components/pushover/manifest.json create mode 100644 homeassistant/components/pushsafer/manifest.json create mode 100644 homeassistant/components/pvoutput/manifest.json create mode 100644 homeassistant/components/pyload/manifest.json create mode 100644 homeassistant/components/python_script/manifest.json create mode 100644 homeassistant/components/qbittorrent/manifest.json create mode 100644 homeassistant/components/qnap/manifest.json create mode 100644 homeassistant/components/qrcode/manifest.json create mode 100644 homeassistant/components/quantum_gateway/manifest.json create mode 100644 homeassistant/components/qwikswitch/manifest.json create mode 100644 homeassistant/components/rachio/manifest.json create mode 100644 homeassistant/components/radarr/manifest.json create mode 100644 homeassistant/components/radiotherm/manifest.json create mode 100644 homeassistant/components/rainbird/manifest.json create mode 100644 homeassistant/components/raincloud/manifest.json create mode 100644 homeassistant/components/rainmachine/manifest.json create mode 100644 homeassistant/components/random/manifest.json create mode 100644 homeassistant/components/raspihats/manifest.json create mode 100644 homeassistant/components/raspyrfm/manifest.json create mode 100644 homeassistant/components/recollect_waste/manifest.json create mode 100644 homeassistant/components/recorder/manifest.json create mode 100644 homeassistant/components/recswitch/manifest.json create mode 100644 homeassistant/components/reddit/manifest.json create mode 100644 homeassistant/components/rejseplanen/manifest.json create mode 100644 homeassistant/components/remember_the_milk/manifest.json create mode 100644 homeassistant/components/remote/manifest.json create mode 100644 homeassistant/components/rest/manifest.json create mode 100644 homeassistant/components/rest_command/manifest.json create mode 100644 homeassistant/components/rflink/manifest.json create mode 100644 homeassistant/components/rfxtrx/manifest.json create mode 100644 homeassistant/components/ring/manifest.json create mode 100644 homeassistant/components/ripple/manifest.json create mode 100644 homeassistant/components/ritassist/manifest.json create mode 100644 homeassistant/components/rmvtransport/manifest.json create mode 100644 homeassistant/components/rocketchat/manifest.json create mode 100644 homeassistant/components/roku/manifest.json create mode 100644 homeassistant/components/roomba/manifest.json create mode 100644 homeassistant/components/route53/manifest.json create mode 100644 homeassistant/components/rova/manifest.json create mode 100644 homeassistant/components/rpi_camera/manifest.json create mode 100644 homeassistant/components/rpi_gpio/manifest.json create mode 100644 homeassistant/components/rpi_gpio_pwm/manifest.json create mode 100644 homeassistant/components/rpi_pfio/manifest.json create mode 100644 homeassistant/components/rpi_rf/manifest.json create mode 100644 homeassistant/components/rss_feed_template/manifest.json create mode 100644 homeassistant/components/rtorrent/manifest.json create mode 100644 homeassistant/components/russound_rio/manifest.json create mode 100644 homeassistant/components/russound_rnet/manifest.json create mode 100644 homeassistant/components/ruter/manifest.json create mode 100644 homeassistant/components/sabnzbd/manifest.json create mode 100644 homeassistant/components/samsungtv/manifest.json create mode 100644 homeassistant/components/satel_integra/manifest.json create mode 100644 homeassistant/components/scene/manifest.json create mode 100644 homeassistant/components/scrape/manifest.json create mode 100644 homeassistant/components/script/manifest.json create mode 100644 homeassistant/components/scsgate/manifest.json create mode 100644 homeassistant/components/season/manifest.json create mode 100644 homeassistant/components/sendgrid/manifest.json create mode 100644 homeassistant/components/sense/manifest.json create mode 100644 homeassistant/components/sensehat/manifest.json create mode 100644 homeassistant/components/sensibo/manifest.json create mode 100644 homeassistant/components/sensor/manifest.json create mode 100644 homeassistant/components/serial/manifest.json create mode 100644 homeassistant/components/serial_pm/manifest.json create mode 100644 homeassistant/components/sesame/manifest.json create mode 100644 homeassistant/components/seven_segments/manifest.json create mode 100644 homeassistant/components/seventeentrack/manifest.json create mode 100644 homeassistant/components/shell_command/manifest.json create mode 100644 homeassistant/components/shiftr/manifest.json create mode 100644 homeassistant/components/shodan/manifest.json create mode 100644 homeassistant/components/shopping_list/manifest.json create mode 100644 homeassistant/components/sht31/manifest.json create mode 100644 homeassistant/components/sigfox/manifest.json create mode 100644 homeassistant/components/simplepush/manifest.json create mode 100644 homeassistant/components/simplisafe/manifest.json create mode 100644 homeassistant/components/simulated/manifest.json create mode 100644 homeassistant/components/sisyphus/manifest.json create mode 100644 homeassistant/components/sky_hub/manifest.json create mode 100644 homeassistant/components/skybeacon/manifest.json create mode 100644 homeassistant/components/skybell/manifest.json create mode 100644 homeassistant/components/slack/manifest.json create mode 100644 homeassistant/components/sleepiq/manifest.json create mode 100644 homeassistant/components/sma/manifest.json create mode 100644 homeassistant/components/smappee/manifest.json create mode 100644 homeassistant/components/smartthings/manifest.json create mode 100644 homeassistant/components/smhi/manifest.json create mode 100644 homeassistant/components/smtp/manifest.json create mode 100644 homeassistant/components/snapcast/manifest.json create mode 100644 homeassistant/components/snips/manifest.json create mode 100644 homeassistant/components/snmp/manifest.json create mode 100644 homeassistant/components/sochain/manifest.json create mode 100644 homeassistant/components/socialblade/manifest.json create mode 100644 homeassistant/components/solaredge/manifest.json create mode 100644 homeassistant/components/sonarr/manifest.json create mode 100644 homeassistant/components/songpal/manifest.json create mode 100644 homeassistant/components/sonos/manifest.json create mode 100644 homeassistant/components/sony_projector/manifest.json create mode 100644 homeassistant/components/soundtouch/manifest.json create mode 100644 homeassistant/components/spaceapi/manifest.json create mode 100644 homeassistant/components/spc/manifest.json create mode 100644 homeassistant/components/speedtestdotnet/manifest.json create mode 100644 homeassistant/components/spider/manifest.json create mode 100644 homeassistant/components/splunk/manifest.json create mode 100644 homeassistant/components/spotcrime/manifest.json create mode 100644 homeassistant/components/spotify/manifest.json create mode 100644 homeassistant/components/sql/manifest.json create mode 100644 homeassistant/components/squeezebox/manifest.json create mode 100644 homeassistant/components/srp_energy/manifest.json create mode 100644 homeassistant/components/starlingbank/manifest.json create mode 100644 homeassistant/components/startca/manifest.json create mode 100644 homeassistant/components/statistics/manifest.json create mode 100644 homeassistant/components/statsd/manifest.json create mode 100644 homeassistant/components/steam_online/manifest.json create mode 100644 homeassistant/components/stream/manifest.json create mode 100644 homeassistant/components/stride/manifest.json create mode 100644 homeassistant/components/sun/manifest.json create mode 100644 homeassistant/components/supervisord/manifest.json create mode 100644 homeassistant/components/swiss_hydrological_data/manifest.json create mode 100644 homeassistant/components/swiss_public_transport/manifest.json create mode 100644 homeassistant/components/swisscom/manifest.json create mode 100644 homeassistant/components/switch/manifest.json create mode 100644 homeassistant/components/switchbot/manifest.json create mode 100644 homeassistant/components/switchmate/manifest.json create mode 100644 homeassistant/components/syncthru/manifest.json create mode 100644 homeassistant/components/synology/manifest.json create mode 100644 homeassistant/components/synology_chat/manifest.json create mode 100644 homeassistant/components/synology_srm/manifest.json create mode 100644 homeassistant/components/synologydsm/manifest.json create mode 100644 homeassistant/components/syslog/manifest.json create mode 100644 homeassistant/components/system_health/manifest.json create mode 100644 homeassistant/components/system_log/manifest.json create mode 100644 homeassistant/components/systemmonitor/manifest.json create mode 100644 homeassistant/components/sytadin/manifest.json create mode 100644 homeassistant/components/tado/manifest.json create mode 100644 homeassistant/components/tahoma/manifest.json create mode 100644 homeassistant/components/tank_utility/manifest.json create mode 100644 homeassistant/components/tapsaff/manifest.json create mode 100644 homeassistant/components/tautulli/manifest.json create mode 100644 homeassistant/components/tcp/manifest.json create mode 100644 homeassistant/components/ted5000/manifest.json create mode 100644 homeassistant/components/teksavvy/manifest.json create mode 100644 homeassistant/components/telegram/manifest.json create mode 100644 homeassistant/components/telegram_bot/manifest.json create mode 100644 homeassistant/components/tellduslive/manifest.json create mode 100644 homeassistant/components/tellstick/manifest.json create mode 100644 homeassistant/components/telnet/manifest.json create mode 100644 homeassistant/components/temper/manifest.json create mode 100644 homeassistant/components/template/manifest.json create mode 100644 homeassistant/components/tensorflow/manifest.json create mode 100644 homeassistant/components/tesla/manifest.json create mode 100644 homeassistant/components/tfiac/manifest.json create mode 100644 homeassistant/components/thermoworks_smoke/manifest.json create mode 100644 homeassistant/components/thethingsnetwork/manifest.json create mode 100644 homeassistant/components/thingspeak/manifest.json create mode 100644 homeassistant/components/thinkingcleaner/manifest.json create mode 100644 homeassistant/components/thomson/manifest.json create mode 100644 homeassistant/components/threshold/manifest.json create mode 100644 homeassistant/components/tibber/manifest.json create mode 100644 homeassistant/components/tikteck/manifest.json create mode 100644 homeassistant/components/tile/manifest.json create mode 100644 homeassistant/components/time_date/manifest.json create mode 100644 homeassistant/components/timer/manifest.json create mode 100644 homeassistant/components/tod/manifest.json create mode 100644 homeassistant/components/todoist/manifest.json create mode 100644 homeassistant/components/tof/manifest.json create mode 100644 homeassistant/components/tomato/manifest.json create mode 100644 homeassistant/components/toon/manifest.json create mode 100644 homeassistant/components/torque/manifest.json create mode 100644 homeassistant/components/totalconnect/manifest.json create mode 100644 homeassistant/components/touchline/manifest.json create mode 100644 homeassistant/components/tplink/manifest.json create mode 100644 homeassistant/components/tplink_lte/manifest.json create mode 100644 homeassistant/components/traccar/manifest.json create mode 100644 homeassistant/components/trackr/manifest.json create mode 100644 homeassistant/components/tradfri/manifest.json create mode 100644 homeassistant/components/trafikverket_weatherstation/manifest.json create mode 100644 homeassistant/components/transmission/manifest.json create mode 100644 homeassistant/components/transport_nsw/manifest.json create mode 100644 homeassistant/components/travisci/manifest.json create mode 100644 homeassistant/components/trend/manifest.json create mode 100644 homeassistant/components/tts/manifest.json create mode 100644 homeassistant/components/tuya/manifest.json create mode 100644 homeassistant/components/twilio/manifest.json create mode 100644 homeassistant/components/twilio_call/manifest.json create mode 100644 homeassistant/components/twilio_sms/manifest.json create mode 100644 homeassistant/components/twitch/manifest.json create mode 100644 homeassistant/components/twitter/manifest.json create mode 100644 homeassistant/components/ubee/manifest.json create mode 100644 homeassistant/components/uber/manifest.json create mode 100644 homeassistant/components/ubus/manifest.json create mode 100644 homeassistant/components/ue_smart_radio/manifest.json create mode 100644 homeassistant/components/uk_transport/manifest.json create mode 100644 homeassistant/components/unifi/manifest.json create mode 100644 homeassistant/components/unifi_direct/manifest.json create mode 100644 homeassistant/components/universal/manifest.json create mode 100644 homeassistant/components/upc_connect/manifest.json create mode 100644 homeassistant/components/upcloud/manifest.json create mode 100644 homeassistant/components/updater/manifest.json create mode 100644 homeassistant/components/upnp/manifest.json create mode 100644 homeassistant/components/ups/manifest.json create mode 100644 homeassistant/components/uptime/manifest.json create mode 100644 homeassistant/components/uptimerobot/manifest.json create mode 100644 homeassistant/components/uscis/manifest.json create mode 100644 homeassistant/components/usgs_earthquakes_feed/manifest.json create mode 100644 homeassistant/components/usps/manifest.json create mode 100644 homeassistant/components/utility_meter/manifest.json create mode 100644 homeassistant/components/uvc/manifest.json create mode 100644 homeassistant/components/vacuum/manifest.json create mode 100644 homeassistant/components/vasttrafik/manifest.json create mode 100644 homeassistant/components/velbus/manifest.json create mode 100644 homeassistant/components/velux/manifest.json create mode 100644 homeassistant/components/venstar/manifest.json create mode 100644 homeassistant/components/vera/manifest.json create mode 100644 homeassistant/components/verisure/manifest.json create mode 100644 homeassistant/components/version/manifest.json create mode 100644 homeassistant/components/vesync/manifest.json create mode 100644 homeassistant/components/viaggiatreno/manifest.json create mode 100644 homeassistant/components/vizio/manifest.json create mode 100644 homeassistant/components/vlc/manifest.json create mode 100644 homeassistant/components/voicerss/manifest.json create mode 100644 homeassistant/components/volkszaehler/manifest.json create mode 100644 homeassistant/components/volumio/manifest.json create mode 100644 homeassistant/components/volvooncall/manifest.json create mode 100644 homeassistant/components/vultr/manifest.json create mode 100644 homeassistant/components/w800rf32/manifest.json create mode 100644 homeassistant/components/wake_on_lan/manifest.json create mode 100644 homeassistant/components/waqi/manifest.json create mode 100644 homeassistant/components/water_heater/manifest.json create mode 100644 homeassistant/components/waterfurnace/manifest.json create mode 100644 homeassistant/components/watson_iot/manifest.json create mode 100644 homeassistant/components/waze_travel_time/manifest.json create mode 100644 homeassistant/components/weather/manifest.json create mode 100644 homeassistant/components/webhook/manifest.json create mode 100644 homeassistant/components/weblink/manifest.json create mode 100644 homeassistant/components/webostv/manifest.json create mode 100644 homeassistant/components/websocket_api/manifest.json create mode 100644 homeassistant/components/wemo/manifest.json create mode 100644 homeassistant/components/whois/manifest.json create mode 100644 homeassistant/components/wink/manifest.json create mode 100644 homeassistant/components/wirelesstag/manifest.json create mode 100644 homeassistant/components/workday/manifest.json create mode 100644 homeassistant/components/worldclock/manifest.json create mode 100644 homeassistant/components/worldtidesinfo/manifest.json create mode 100644 homeassistant/components/worxlandroid/manifest.json create mode 100644 homeassistant/components/wsdot/manifest.json create mode 100644 homeassistant/components/wunderground/manifest.json create mode 100644 homeassistant/components/wunderlist/manifest.json create mode 100644 homeassistant/components/x10/manifest.json create mode 100644 homeassistant/components/xbox_live/manifest.json create mode 100644 homeassistant/components/xeoma/manifest.json create mode 100644 homeassistant/components/xfinity/manifest.json create mode 100644 homeassistant/components/xiaomi/manifest.json create mode 100644 homeassistant/components/xiaomi_aqara/manifest.json create mode 100644 homeassistant/components/xiaomi_miio/manifest.json create mode 100644 homeassistant/components/xiaomi_tv/manifest.json create mode 100644 homeassistant/components/xmpp/manifest.json create mode 100644 homeassistant/components/xs1/manifest.json create mode 100644 homeassistant/components/yale_smart_alarm/manifest.json create mode 100644 homeassistant/components/yamaha/manifest.json create mode 100644 homeassistant/components/yamaha_musiccast/manifest.json create mode 100644 homeassistant/components/yandextts/manifest.json create mode 100644 homeassistant/components/yeelight/manifest.json create mode 100644 homeassistant/components/yeelightsunflower/manifest.json create mode 100644 homeassistant/components/yessssms/manifest.json create mode 100644 homeassistant/components/yi/manifest.json create mode 100644 homeassistant/components/yr/manifest.json create mode 100644 homeassistant/components/yweather/manifest.json create mode 100644 homeassistant/components/zabbix/manifest.json create mode 100644 homeassistant/components/zamg/manifest.json create mode 100644 homeassistant/components/zengge/manifest.json create mode 100644 homeassistant/components/zeroconf/manifest.json create mode 100644 homeassistant/components/zestimate/manifest.json create mode 100644 homeassistant/components/zha/manifest.json create mode 100644 homeassistant/components/zhong_hong/manifest.json create mode 100644 homeassistant/components/zigbee/manifest.json create mode 100644 homeassistant/components/ziggo_mediabox_xl/manifest.json create mode 100644 homeassistant/components/zone/manifest.json create mode 100644 homeassistant/components/zoneminder/manifest.json create mode 100644 homeassistant/components/zwave/manifest.json diff --git a/CODEOWNERS b/CODEOWNERS index 276c730a47a..5be5610a5c7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -18,7 +18,11 @@ homeassistant/components/frontend/* @home-assistant/core homeassistant/components/group/* @home-assistant/core homeassistant/components/history/* @home-assistant/core homeassistant/components/http/* @home-assistant/core -homeassistant/components/input_*/* @home-assistant/core +homeassistant/components/input_boolean/* @home-assistant/core +homeassistant/components/input_datetime/* @home-assistant/core +homeassistant/components/input_number/* @home-assistant/core +homeassistant/components/input_select/* @home-assistant/core +homeassistant/components/input_text/* @home-assistant/core homeassistant/components/introduction/* @home-assistant/core homeassistant/components/logger/* @home-assistant/core homeassistant/components/lovelace/* @home-assistant/core @@ -42,7 +46,6 @@ Dockerfile @home-assistant/docker virtualization/Docker/* @home-assistant/docker homeassistant/components/zwave/* @home-assistant/z-wave -homeassistant/components/*/zwave.py @home-assistant/z-wave homeassistant/components/hassio/* @home-assistant/hassio @@ -223,7 +226,8 @@ homeassistant/components/spaceapi/* @fabaff homeassistant/components/spider/* @peternijssen homeassistant/components/sql/sensor.py @dgomes homeassistant/components/statistics/sensor.py @fabaff -homeassistant/components/swiss_*/* @fabaff +homeassistant/components/swiss_public_transport/* @fabaff +homeassistant/components/swiss_hydrological_data/* @fabaff homeassistant/components/switchbot/switch.py @danielhiversen homeassistant/components/switchmate/switch.py @danielhiversen homeassistant/components/synology_srm/device_tracker.py @aerialls diff --git a/homeassistant/components/abode/manifest.json b/homeassistant/components/abode/manifest.json new file mode 100644 index 00000000000..49e0c46fd55 --- /dev/null +++ b/homeassistant/components/abode/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "abode", + "name": "Abode", + "documentation": "https://www.home-assistant.io/components/abode", + "requirements": [ + "abodepy==0.15.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/acer_projector/manifest.json b/homeassistant/components/acer_projector/manifest.json new file mode 100644 index 00000000000..4b8d6967491 --- /dev/null +++ b/homeassistant/components/acer_projector/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "acer_projector", + "name": "Acer projector", + "documentation": "https://www.home-assistant.io/components/acer_projector", + "requirements": [ + "pyserial==3.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/actiontec/manifest.json b/homeassistant/components/actiontec/manifest.json new file mode 100644 index 00000000000..e233f430cfc --- /dev/null +++ b/homeassistant/components/actiontec/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "actiontec", + "name": "Actiontec", + "documentation": "https://www.home-assistant.io/components/actiontec", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ads/manifest.json b/homeassistant/components/ads/manifest.json new file mode 100644 index 00000000000..0c759f0ad60 --- /dev/null +++ b/homeassistant/components/ads/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ads", + "name": "Ads", + "documentation": "https://www.home-assistant.io/components/ads", + "requirements": [ + "pyads==3.0.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/aftership/manifest.json b/homeassistant/components/aftership/manifest.json new file mode 100644 index 00000000000..b9ee8939dc4 --- /dev/null +++ b/homeassistant/components/aftership/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "aftership", + "name": "Aftership", + "documentation": "https://www.home-assistant.io/components/aftership", + "requirements": [ + "pyaftership==0.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/air_quality/manifest.json b/homeassistant/components/air_quality/manifest.json new file mode 100644 index 00000000000..5bfe85547ff --- /dev/null +++ b/homeassistant/components/air_quality/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "air_quality", + "name": "Air quality", + "documentation": "https://www.home-assistant.io/components/air_quality", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/airvisual/manifest.json b/homeassistant/components/airvisual/manifest.json new file mode 100644 index 00000000000..ddb109a99b0 --- /dev/null +++ b/homeassistant/components/airvisual/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "airvisual", + "name": "Airvisual", + "documentation": "https://www.home-assistant.io/components/airvisual", + "requirements": [ + "pyairvisual==3.0.1" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/aladdin_connect/manifest.json b/homeassistant/components/aladdin_connect/manifest.json new file mode 100644 index 00000000000..0681d5df38b --- /dev/null +++ b/homeassistant/components/aladdin_connect/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "aladdin_connect", + "name": "Aladdin connect", + "documentation": "https://www.home-assistant.io/components/aladdin_connect", + "requirements": [ + "aladdin_connect==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/alarm_control_panel/manifest.json b/homeassistant/components/alarm_control_panel/manifest.json new file mode 100644 index 00000000000..95e26de53bc --- /dev/null +++ b/homeassistant/components/alarm_control_panel/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "alarm_control_panel", + "name": "Alarm control panel", + "documentation": "https://www.home-assistant.io/components/alarm_control_panel", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@colinodell" + ] +} diff --git a/homeassistant/components/alarmdecoder/manifest.json b/homeassistant/components/alarmdecoder/manifest.json new file mode 100644 index 00000000000..3e0d4112d27 --- /dev/null +++ b/homeassistant/components/alarmdecoder/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "alarmdecoder", + "name": "Alarmdecoder", + "documentation": "https://www.home-assistant.io/components/alarmdecoder", + "requirements": [ + "alarmdecoder==1.13.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/alarmdotcom/manifest.json b/homeassistant/components/alarmdotcom/manifest.json new file mode 100644 index 00000000000..9d2c0a2056e --- /dev/null +++ b/homeassistant/components/alarmdotcom/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "alarmdotcom", + "name": "Alarmdotcom", + "documentation": "https://www.home-assistant.io/components/alarmdotcom", + "requirements": [ + "pyalarmdotcom==0.3.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/alert/manifest.json b/homeassistant/components/alert/manifest.json new file mode 100644 index 00000000000..f3dcc18208c --- /dev/null +++ b/homeassistant/components/alert/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "alert", + "name": "Alert", + "documentation": "https://www.home-assistant.io/components/alert", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/alexa/manifest.json b/homeassistant/components/alexa/manifest.json new file mode 100644 index 00000000000..e4fc9eb8680 --- /dev/null +++ b/homeassistant/components/alexa/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "alexa", + "name": "Alexa", + "documentation": "https://www.home-assistant.io/components/alexa", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/alpha_vantage/manifest.json b/homeassistant/components/alpha_vantage/manifest.json new file mode 100644 index 00000000000..dacc428ea2e --- /dev/null +++ b/homeassistant/components/alpha_vantage/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "alpha_vantage", + "name": "Alpha vantage", + "documentation": "https://www.home-assistant.io/components/alpha_vantage", + "requirements": [ + "alpha_vantage==2.1.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/amazon_polly/manifest.json b/homeassistant/components/amazon_polly/manifest.json new file mode 100644 index 00000000000..19140aac939 --- /dev/null +++ b/homeassistant/components/amazon_polly/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "amazon_polly", + "name": "Amazon polly", + "documentation": "https://www.home-assistant.io/components/amazon_polly", + "requirements": [ + "boto3==1.9.16" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/ambient_station/manifest.json b/homeassistant/components/ambient_station/manifest.json new file mode 100644 index 00000000000..13a74fec26e --- /dev/null +++ b/homeassistant/components/ambient_station/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "ambient_station", + "name": "Ambient station", + "documentation": "https://www.home-assistant.io/components/ambient_station", + "requirements": [ + "aioambient==0.1.3" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/amcrest/manifest.json b/homeassistant/components/amcrest/manifest.json new file mode 100644 index 00000000000..e05fdcf4bd4 --- /dev/null +++ b/homeassistant/components/amcrest/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "amcrest", + "name": "Amcrest", + "documentation": "https://www.home-assistant.io/components/amcrest", + "requirements": [ + "amcrest==1.3.0" + ], + "dependencies": [ + "ffmpeg" + ], + "codeowners": [] +} diff --git a/homeassistant/components/ampio/manifest.json b/homeassistant/components/ampio/manifest.json new file mode 100644 index 00000000000..d20b10b2d15 --- /dev/null +++ b/homeassistant/components/ampio/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ampio", + "name": "Ampio", + "documentation": "https://www.home-assistant.io/components/ampio", + "requirements": [ + "asmog==0.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/android_ip_webcam/manifest.json b/homeassistant/components/android_ip_webcam/manifest.json new file mode 100644 index 00000000000..28909f7e053 --- /dev/null +++ b/homeassistant/components/android_ip_webcam/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "android_ip_webcam", + "name": "Android ip webcam", + "documentation": "https://www.home-assistant.io/components/android_ip_webcam", + "requirements": [ + "pydroid-ipcam==0.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/androidtv/manifest.json b/homeassistant/components/androidtv/manifest.json new file mode 100644 index 00000000000..815a97394cb --- /dev/null +++ b/homeassistant/components/androidtv/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "androidtv", + "name": "Androidtv", + "documentation": "https://www.home-assistant.io/components/androidtv", + "requirements": [ + "androidtv==0.0.14" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/anel_pwrctrl/manifest.json b/homeassistant/components/anel_pwrctrl/manifest.json new file mode 100644 index 00000000000..17802918cd2 --- /dev/null +++ b/homeassistant/components/anel_pwrctrl/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "anel_pwrctrl", + "name": "Anel pwrctrl", + "documentation": "https://www.home-assistant.io/components/anel_pwrctrl", + "requirements": [ + "anel_pwrctrl-homeassistant==0.0.1.dev2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/anthemav/manifest.json b/homeassistant/components/anthemav/manifest.json new file mode 100644 index 00000000000..9b2e3c697bb --- /dev/null +++ b/homeassistant/components/anthemav/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "anthemav", + "name": "Anthemav", + "documentation": "https://www.home-assistant.io/components/anthemav", + "requirements": [ + "anthemav==1.1.10" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/apcupsd/manifest.json b/homeassistant/components/apcupsd/manifest.json new file mode 100644 index 00000000000..813176728f2 --- /dev/null +++ b/homeassistant/components/apcupsd/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "apcupsd", + "name": "Apcupsd", + "documentation": "https://www.home-assistant.io/components/apcupsd", + "requirements": [ + "apcaccess==0.0.13" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/api/manifest.json b/homeassistant/components/api/manifest.json new file mode 100644 index 00000000000..25d9a76036e --- /dev/null +++ b/homeassistant/components/api/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "api", + "name": "Home Assistant API", + "documentation": "https://www.home-assistant.io/components/api", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/api_streams/__init__.py b/homeassistant/components/api_streams/__init__.py deleted file mode 100644 index dba43061313..00000000000 --- a/homeassistant/components/api_streams/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The api_streams component.""" diff --git a/homeassistant/components/apns/manifest.json b/homeassistant/components/apns/manifest.json new file mode 100644 index 00000000000..9a310a096a5 --- /dev/null +++ b/homeassistant/components/apns/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "apns", + "name": "Apns", + "documentation": "https://www.home-assistant.io/components/apns", + "requirements": [ + "apns2==0.3.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/apple_tv/manifest.json b/homeassistant/components/apple_tv/manifest.json new file mode 100644 index 00000000000..4f27fde2aa3 --- /dev/null +++ b/homeassistant/components/apple_tv/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "apple_tv", + "name": "Apple tv", + "documentation": "https://www.home-assistant.io/components/apple_tv", + "requirements": [ + "pyatv==0.3.12" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/aqualogic/manifest.json b/homeassistant/components/aqualogic/manifest.json new file mode 100644 index 00000000000..40f1805d83a --- /dev/null +++ b/homeassistant/components/aqualogic/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "aqualogic", + "name": "Aqualogic", + "documentation": "https://www.home-assistant.io/components/aqualogic", + "requirements": [ + "aqualogic==1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/aquostv/manifest.json b/homeassistant/components/aquostv/manifest.json new file mode 100644 index 00000000000..16865905ae9 --- /dev/null +++ b/homeassistant/components/aquostv/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "aquostv", + "name": "Aquostv", + "documentation": "https://www.home-assistant.io/components/aquostv", + "requirements": [ + "sharp_aquos_rc==0.3.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/arduino/manifest.json b/homeassistant/components/arduino/manifest.json new file mode 100644 index 00000000000..cf21cbe87ea --- /dev/null +++ b/homeassistant/components/arduino/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "arduino", + "name": "Arduino", + "documentation": "https://www.home-assistant.io/components/arduino", + "requirements": [ + "PyMata==2.14" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/arest/manifest.json b/homeassistant/components/arest/manifest.json new file mode 100644 index 00000000000..d5bcf92a39d --- /dev/null +++ b/homeassistant/components/arest/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "arest", + "name": "Arest", + "documentation": "https://www.home-assistant.io/components/arest", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/arlo/manifest.json b/homeassistant/components/arlo/manifest.json new file mode 100644 index 00000000000..a8b6befb70f --- /dev/null +++ b/homeassistant/components/arlo/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "arlo", + "name": "Arlo", + "documentation": "https://www.home-assistant.io/components/arlo", + "requirements": [ + "pyarlo==0.2.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/aruba/manifest.json b/homeassistant/components/aruba/manifest.json new file mode 100644 index 00000000000..597975619e6 --- /dev/null +++ b/homeassistant/components/aruba/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "aruba", + "name": "Aruba", + "documentation": "https://www.home-assistant.io/components/aruba", + "requirements": [ + "pexpect==4.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/arwn/manifest.json b/homeassistant/components/arwn/manifest.json new file mode 100644 index 00000000000..15ef7fa48ba --- /dev/null +++ b/homeassistant/components/arwn/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "arwn", + "name": "Arwn", + "documentation": "https://www.home-assistant.io/components/arwn", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/asterisk_cdr/manifest.json b/homeassistant/components/asterisk_cdr/manifest.json new file mode 100644 index 00000000000..2c8713ac191 --- /dev/null +++ b/homeassistant/components/asterisk_cdr/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "asterisk_cdr", + "name": "Asterisk cdr", + "documentation": "https://www.home-assistant.io/components/asterisk_cdr", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/asterisk_mbox/manifest.json b/homeassistant/components/asterisk_mbox/manifest.json new file mode 100644 index 00000000000..bafe43c480f --- /dev/null +++ b/homeassistant/components/asterisk_mbox/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "asterisk_mbox", + "name": "Asterisk mbox", + "documentation": "https://www.home-assistant.io/components/asterisk_mbox", + "requirements": [ + "asterisk_mbox==0.5.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/asuswrt/manifest.json b/homeassistant/components/asuswrt/manifest.json new file mode 100644 index 00000000000..f36819f133d --- /dev/null +++ b/homeassistant/components/asuswrt/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "asuswrt", + "name": "Asuswrt", + "documentation": "https://www.home-assistant.io/components/asuswrt", + "requirements": [ + "aioasuswrt==1.1.21" + ], + "dependencies": [], + "codeowners": [ + "@kennedyshead" + ] +} diff --git a/homeassistant/components/august/manifest.json b/homeassistant/components/august/manifest.json new file mode 100644 index 00000000000..39bc70fba7b --- /dev/null +++ b/homeassistant/components/august/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "august", + "name": "August", + "documentation": "https://www.home-assistant.io/components/august", + "requirements": [ + "py-august==0.7.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/aurora/manifest.json b/homeassistant/components/aurora/manifest.json new file mode 100644 index 00000000000..56ba3fe9356 --- /dev/null +++ b/homeassistant/components/aurora/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "aurora", + "name": "Aurora", + "documentation": "https://www.home-assistant.io/components/aurora", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/auth/manifest.json b/homeassistant/components/auth/manifest.json new file mode 100644 index 00000000000..10be545f5e1 --- /dev/null +++ b/homeassistant/components/auth/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "auth", + "name": "Auth", + "documentation": "https://www.home-assistant.io/components/auth", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/automatic/manifest.json b/homeassistant/components/automatic/manifest.json new file mode 100644 index 00000000000..db2f676813e --- /dev/null +++ b/homeassistant/components/automatic/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "automatic", + "name": "Automatic", + "documentation": "https://www.home-assistant.io/components/automatic", + "requirements": [ + "aioautomatic==0.6.5" + ], + "dependencies": [], + "codeowners": [ + "@armills" + ] +} diff --git a/homeassistant/components/automation/manifest.json b/homeassistant/components/automation/manifest.json new file mode 100644 index 00000000000..93f1abe0f0d --- /dev/null +++ b/homeassistant/components/automation/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "automation", + "name": "Automation", + "documentation": "https://www.home-assistant.io/components/automation", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/avion/manifest.json b/homeassistant/components/avion/manifest.json new file mode 100644 index 00000000000..e7d97f13313 --- /dev/null +++ b/homeassistant/components/avion/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "avion", + "name": "Avion", + "documentation": "https://www.home-assistant.io/components/avion", + "requirements": [ + "avion==0.10" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/awair/manifest.json b/homeassistant/components/awair/manifest.json new file mode 100644 index 00000000000..bc63ef06cc2 --- /dev/null +++ b/homeassistant/components/awair/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "awair", + "name": "Awair", + "documentation": "https://www.home-assistant.io/components/awair", + "requirements": [ + "python_awair==0.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/aws/manifest.json b/homeassistant/components/aws/manifest.json new file mode 100644 index 00000000000..a473a23f917 --- /dev/null +++ b/homeassistant/components/aws/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "aws", + "name": "Aws", + "documentation": "https://www.home-assistant.io/components/aws", + "requirements": [ + "aiobotocore==0.10.2" + ], + "dependencies": [], + "codeowners": [ + "@awarecan", + "@robbiet480" + ] +} diff --git a/homeassistant/components/aws_lambda/manifest.json b/homeassistant/components/aws_lambda/manifest.json new file mode 100644 index 00000000000..40c8c7b0629 --- /dev/null +++ b/homeassistant/components/aws_lambda/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "aws_lambda", + "name": "Aws lambda", + "documentation": "https://www.home-assistant.io/components/aws_lambda", + "requirements": [ + "boto3==1.9.16" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/aws_sns/manifest.json b/homeassistant/components/aws_sns/manifest.json new file mode 100644 index 00000000000..f6c3438025d --- /dev/null +++ b/homeassistant/components/aws_sns/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "aws_sns", + "name": "Aws sns", + "documentation": "https://www.home-assistant.io/components/aws_sns", + "requirements": [ + "boto3==1.9.16" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/aws_sqs/manifest.json b/homeassistant/components/aws_sqs/manifest.json new file mode 100644 index 00000000000..fcfc8cfb297 --- /dev/null +++ b/homeassistant/components/aws_sqs/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "aws_sqs", + "name": "Aws sqs", + "documentation": "https://www.home-assistant.io/components/aws_sqs", + "requirements": [ + "boto3==1.9.16" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/axis/manifest.json b/homeassistant/components/axis/manifest.json new file mode 100644 index 00000000000..66ccce8d98f --- /dev/null +++ b/homeassistant/components/axis/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "axis", + "name": "Axis", + "documentation": "https://www.home-assistant.io/components/axis", + "requirements": [ + "axis==19" + ], + "dependencies": [], + "codeowners": [ + "@kane610" + ] +} diff --git a/homeassistant/components/baidu/manifest.json b/homeassistant/components/baidu/manifest.json new file mode 100644 index 00000000000..1dea1b7e37b --- /dev/null +++ b/homeassistant/components/baidu/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "baidu", + "name": "Baidu", + "documentation": "https://www.home-assistant.io/components/baidu", + "requirements": [ + "baidu-aip==1.6.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bayesian/manifest.json b/homeassistant/components/bayesian/manifest.json new file mode 100644 index 00000000000..25480ac8bdc --- /dev/null +++ b/homeassistant/components/bayesian/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "bayesian", + "name": "Bayesian", + "documentation": "https://www.home-assistant.io/components/bayesian", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bbb_gpio/manifest.json b/homeassistant/components/bbb_gpio/manifest.json new file mode 100644 index 00000000000..5632836bfbb --- /dev/null +++ b/homeassistant/components/bbb_gpio/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "bbb_gpio", + "name": "Bbb gpio", + "documentation": "https://www.home-assistant.io/components/bbb_gpio", + "requirements": [ + "Adafruit_BBIO==1.0.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bbox/manifest.json b/homeassistant/components/bbox/manifest.json new file mode 100644 index 00000000000..54cd9a3af64 --- /dev/null +++ b/homeassistant/components/bbox/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "bbox", + "name": "Bbox", + "documentation": "https://www.home-assistant.io/components/bbox", + "requirements": [ + "pybbox==0.0.5-alpha" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bh1750/manifest.json b/homeassistant/components/bh1750/manifest.json new file mode 100644 index 00000000000..90e62c78356 --- /dev/null +++ b/homeassistant/components/bh1750/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "bh1750", + "name": "Bh1750", + "documentation": "https://www.home-assistant.io/components/bh1750", + "requirements": [ + "i2csense==0.0.4", + "smbus-cffi==0.5.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/binary_sensor/manifest.json b/homeassistant/components/binary_sensor/manifest.json new file mode 100644 index 00000000000..d627351958d --- /dev/null +++ b/homeassistant/components/binary_sensor/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "binary_sensor", + "name": "Binary sensor", + "documentation": "https://www.home-assistant.io/components/binary_sensor", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bitcoin/manifest.json b/homeassistant/components/bitcoin/manifest.json new file mode 100644 index 00000000000..85da99a6885 --- /dev/null +++ b/homeassistant/components/bitcoin/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "bitcoin", + "name": "Bitcoin", + "documentation": "https://www.home-assistant.io/components/bitcoin", + "requirements": [ + "blockchain==1.4.4" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/blackbird/manifest.json b/homeassistant/components/blackbird/manifest.json new file mode 100644 index 00000000000..9e3e41290ea --- /dev/null +++ b/homeassistant/components/blackbird/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "blackbird", + "name": "Blackbird", + "documentation": "https://www.home-assistant.io/components/blackbird", + "requirements": [ + "pyblackbird==0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/blink/manifest.json b/homeassistant/components/blink/manifest.json new file mode 100644 index 00000000000..7be44f95a53 --- /dev/null +++ b/homeassistant/components/blink/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "blink", + "name": "Blink", + "documentation": "https://www.home-assistant.io/components/blink", + "requirements": [ + "blinkpy==0.13.1" + ], + "dependencies": [], + "codeowners": [ + "@fronzbot" + ] +} diff --git a/homeassistant/components/blinksticklight/manifest.json b/homeassistant/components/blinksticklight/manifest.json new file mode 100644 index 00000000000..a5277c97d99 --- /dev/null +++ b/homeassistant/components/blinksticklight/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "blinksticklight", + "name": "Blinksticklight", + "documentation": "https://www.home-assistant.io/components/blinksticklight", + "requirements": [ + "blinkstick==1.1.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/blinkt/manifest.json b/homeassistant/components/blinkt/manifest.json new file mode 100644 index 00000000000..c11583ed59e --- /dev/null +++ b/homeassistant/components/blinkt/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "blinkt", + "name": "Blinkt", + "documentation": "https://www.home-assistant.io/components/blinkt", + "requirements": [ + "blinkt==0.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/blockchain/manifest.json b/homeassistant/components/blockchain/manifest.json new file mode 100644 index 00000000000..8a2a9f7b71f --- /dev/null +++ b/homeassistant/components/blockchain/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "blockchain", + "name": "Blockchain", + "documentation": "https://www.home-assistant.io/components/blockchain", + "requirements": [ + "python-blockchain-api==0.0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bloomsky/manifest.json b/homeassistant/components/bloomsky/manifest.json new file mode 100644 index 00000000000..3a780507dd5 --- /dev/null +++ b/homeassistant/components/bloomsky/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "bloomsky", + "name": "Bloomsky", + "documentation": "https://www.home-assistant.io/components/bloomsky", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bluesound/manifest.json b/homeassistant/components/bluesound/manifest.json new file mode 100644 index 00000000000..9016502b5d3 --- /dev/null +++ b/homeassistant/components/bluesound/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "bluesound", + "name": "Bluesound", + "documentation": "https://www.home-assistant.io/components/bluesound", + "requirements": [ + "xmltodict==0.11.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bluetooth_le_tracker/manifest.json b/homeassistant/components/bluetooth_le_tracker/manifest.json new file mode 100644 index 00000000000..cd67ec31536 --- /dev/null +++ b/homeassistant/components/bluetooth_le_tracker/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "bluetooth_le_tracker", + "name": "Bluetooth le tracker", + "documentation": "https://www.home-assistant.io/components/bluetooth_le_tracker", + "requirements": [ + "pygatt[GATTTOOL]==3.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bluetooth_tracker/manifest.json b/homeassistant/components/bluetooth_tracker/manifest.json new file mode 100644 index 00000000000..7eaeb4ef927 --- /dev/null +++ b/homeassistant/components/bluetooth_tracker/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "bluetooth_tracker", + "name": "Bluetooth tracker", + "documentation": "https://www.home-assistant.io/components/bluetooth_tracker", + "requirements": [ + "bt_proximity==0.1.2", + "pybluez==0.22" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bme280/manifest.json b/homeassistant/components/bme280/manifest.json new file mode 100644 index 00000000000..2342c8418eb --- /dev/null +++ b/homeassistant/components/bme280/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "bme280", + "name": "Bme280", + "documentation": "https://www.home-assistant.io/components/bme280", + "requirements": [ + "i2csense==0.0.4", + "smbus-cffi==0.5.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bme680/manifest.json b/homeassistant/components/bme680/manifest.json new file mode 100644 index 00000000000..976be85ca94 --- /dev/null +++ b/homeassistant/components/bme680/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "bme680", + "name": "Bme680", + "documentation": "https://www.home-assistant.io/components/bme680", + "requirements": [ + "bme680==1.0.5", + "smbus-cffi==0.5.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bmw_connected_drive/manifest.json b/homeassistant/components/bmw_connected_drive/manifest.json new file mode 100644 index 00000000000..67bfac91052 --- /dev/null +++ b/homeassistant/components/bmw_connected_drive/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "bmw_connected_drive", + "name": "Bmw connected drive", + "documentation": "https://www.home-assistant.io/components/bmw_connected_drive", + "requirements": [ + "bimmer_connected==0.5.3" + ], + "dependencies": [], + "codeowners": [ + "@ChristianKuehnel" + ] +} diff --git a/homeassistant/components/bom/manifest.json b/homeassistant/components/bom/manifest.json new file mode 100644 index 00000000000..e4744d4cfd2 --- /dev/null +++ b/homeassistant/components/bom/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "bom", + "name": "Bom", + "documentation": "https://www.home-assistant.io/components/bom", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/braviatv/manifest.json b/homeassistant/components/braviatv/manifest.json new file mode 100644 index 00000000000..35e2698af4d --- /dev/null +++ b/homeassistant/components/braviatv/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "braviatv", + "name": "Braviatv", + "documentation": "https://www.home-assistant.io/components/braviatv", + "requirements": [ + "braviarc-homeassistant==0.3.7.dev0" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/broadlink/manifest.json b/homeassistant/components/broadlink/manifest.json new file mode 100644 index 00000000000..a2c565c3dd5 --- /dev/null +++ b/homeassistant/components/broadlink/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "broadlink", + "name": "Broadlink", + "documentation": "https://www.home-assistant.io/components/broadlink", + "requirements": [ + "broadlink==0.9.0" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen" + ] +} diff --git a/homeassistant/components/brottsplatskartan/manifest.json b/homeassistant/components/brottsplatskartan/manifest.json new file mode 100644 index 00000000000..d3b0657fed8 --- /dev/null +++ b/homeassistant/components/brottsplatskartan/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "brottsplatskartan", + "name": "Brottsplatskartan", + "documentation": "https://www.home-assistant.io/components/brottsplatskartan", + "requirements": [ + "brottsplatskartan==0.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/browser/manifest.json b/homeassistant/components/browser/manifest.json new file mode 100644 index 00000000000..61823564fe9 --- /dev/null +++ b/homeassistant/components/browser/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "browser", + "name": "Browser", + "documentation": "https://www.home-assistant.io/components/browser", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/brunt/manifest.json b/homeassistant/components/brunt/manifest.json new file mode 100644 index 00000000000..a47e3f69d5c --- /dev/null +++ b/homeassistant/components/brunt/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "brunt", + "name": "Brunt", + "documentation": "https://www.home-assistant.io/components/brunt", + "requirements": [ + "brunt==0.1.3" + ], + "dependencies": [], + "codeowners": [ + "@eavanvalkenburg" + ] +} diff --git a/homeassistant/components/bt_home_hub_5/manifest.json b/homeassistant/components/bt_home_hub_5/manifest.json new file mode 100644 index 00000000000..927d9ea9412 --- /dev/null +++ b/homeassistant/components/bt_home_hub_5/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "bt_home_hub_5", + "name": "Bt home hub 5", + "documentation": "https://www.home-assistant.io/components/bt_home_hub_5", + "requirements": [ + "bthomehub5-devicelist==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/bt_smarthub/manifest.json b/homeassistant/components/bt_smarthub/manifest.json new file mode 100644 index 00000000000..725541082e7 --- /dev/null +++ b/homeassistant/components/bt_smarthub/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "bt_smarthub", + "name": "Bt smarthub", + "documentation": "https://www.home-assistant.io/components/bt_smarthub", + "requirements": [ + "btsmarthub_devicelist==0.1.3" + ], + "dependencies": [], + "codeowners": [ + "@jxwolstenholme" + ] +} diff --git a/homeassistant/components/buienradar/manifest.json b/homeassistant/components/buienradar/manifest.json new file mode 100644 index 00000000000..98fc5fbdeac --- /dev/null +++ b/homeassistant/components/buienradar/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "buienradar", + "name": "Buienradar", + "documentation": "https://www.home-assistant.io/components/buienradar", + "requirements": [ + "buienradar==0.91" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/caldav/manifest.json b/homeassistant/components/caldav/manifest.json new file mode 100644 index 00000000000..6e233ba6ccd --- /dev/null +++ b/homeassistant/components/caldav/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "caldav", + "name": "Caldav", + "documentation": "https://www.home-assistant.io/components/caldav", + "requirements": [ + "caldav==0.5.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/calendar/manifest.json b/homeassistant/components/calendar/manifest.json new file mode 100644 index 00000000000..3a09cd090a5 --- /dev/null +++ b/homeassistant/components/calendar/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "calendar", + "name": "Calendar", + "documentation": "https://www.home-assistant.io/components/calendar", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/camera/manifest.json b/homeassistant/components/camera/manifest.json new file mode 100644 index 00000000000..afa6f0d9bb7 --- /dev/null +++ b/homeassistant/components/camera/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "camera", + "name": "Camera", + "documentation": "https://www.home-assistant.io/components/camera", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/canary/manifest.json b/homeassistant/components/canary/manifest.json new file mode 100644 index 00000000000..e7cc5fa7efc --- /dev/null +++ b/homeassistant/components/canary/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "canary", + "name": "Canary", + "documentation": "https://www.home-assistant.io/components/canary", + "requirements": [ + "py-canary==0.5.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/cast/manifest.json b/homeassistant/components/cast/manifest.json new file mode 100644 index 00000000000..c506dba8cf1 --- /dev/null +++ b/homeassistant/components/cast/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "cast", + "name": "Cast", + "documentation": "https://www.home-assistant.io/components/cast", + "requirements": [ + "pychromecast==3.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/cert_expiry/manifest.json b/homeassistant/components/cert_expiry/manifest.json new file mode 100644 index 00000000000..7ef2e0b7d10 --- /dev/null +++ b/homeassistant/components/cert_expiry/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "cert_expiry", + "name": "Cert expiry", + "documentation": "https://www.home-assistant.io/components/cert_expiry", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/channels/manifest.json b/homeassistant/components/channels/manifest.json new file mode 100644 index 00000000000..152c7d3a2dc --- /dev/null +++ b/homeassistant/components/channels/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "channels", + "name": "Channels", + "documentation": "https://www.home-assistant.io/components/channels", + "requirements": [ + "pychannels==1.0.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/cisco_ios/manifest.json b/homeassistant/components/cisco_ios/manifest.json new file mode 100644 index 00000000000..d1a9e9933b9 --- /dev/null +++ b/homeassistant/components/cisco_ios/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "cisco_ios", + "name": "Cisco ios", + "documentation": "https://www.home-assistant.io/components/cisco_ios", + "requirements": [ + "pexpect==4.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/cisco_mobility_express/manifest.json b/homeassistant/components/cisco_mobility_express/manifest.json new file mode 100644 index 00000000000..6bd56ccd15e --- /dev/null +++ b/homeassistant/components/cisco_mobility_express/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "cisco_mobility_express", + "name": "Cisco mobility express", + "documentation": "https://www.home-assistant.io/components/cisco_mobility_express", + "requirements": [ + "ciscomobilityexpress==0.1.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/cisco_webex_teams/manifest.json b/homeassistant/components/cisco_webex_teams/manifest.json new file mode 100644 index 00000000000..d13b893ce69 --- /dev/null +++ b/homeassistant/components/cisco_webex_teams/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "cisco_webex_teams", + "name": "Cisco webex teams", + "documentation": "https://www.home-assistant.io/components/cisco_webex_teams", + "requirements": [ + "webexteamssdk==1.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ciscospark/manifest.json b/homeassistant/components/ciscospark/manifest.json new file mode 100644 index 00000000000..c6b0c42e89c --- /dev/null +++ b/homeassistant/components/ciscospark/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ciscospark", + "name": "Ciscospark", + "documentation": "https://www.home-assistant.io/components/ciscospark", + "requirements": [ + "ciscosparkapi==0.4.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/citybikes/manifest.json b/homeassistant/components/citybikes/manifest.json new file mode 100644 index 00000000000..ea1ceaa9531 --- /dev/null +++ b/homeassistant/components/citybikes/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "citybikes", + "name": "Citybikes", + "documentation": "https://www.home-assistant.io/components/citybikes", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/clementine/manifest.json b/homeassistant/components/clementine/manifest.json new file mode 100644 index 00000000000..4d835ed4e7c --- /dev/null +++ b/homeassistant/components/clementine/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "clementine", + "name": "Clementine", + "documentation": "https://www.home-assistant.io/components/clementine", + "requirements": [ + "python-clementine-remote==1.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/clickatell/manifest.json b/homeassistant/components/clickatell/manifest.json new file mode 100644 index 00000000000..ffd550eebee --- /dev/null +++ b/homeassistant/components/clickatell/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "clickatell", + "name": "Clickatell", + "documentation": "https://www.home-assistant.io/components/clickatell", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/clicksend/manifest.json b/homeassistant/components/clicksend/manifest.json new file mode 100644 index 00000000000..38319825094 --- /dev/null +++ b/homeassistant/components/clicksend/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "clicksend", + "name": "Clicksend", + "documentation": "https://www.home-assistant.io/components/clicksend", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/clicksend_tts/manifest.json b/homeassistant/components/clicksend_tts/manifest.json new file mode 100644 index 00000000000..c2a86f426e4 --- /dev/null +++ b/homeassistant/components/clicksend_tts/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "clicksend_tts", + "name": "Clicksend tts", + "documentation": "https://www.home-assistant.io/components/clicksend_tts", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/climate/manifest.json b/homeassistant/components/climate/manifest.json new file mode 100644 index 00000000000..ca5312e7670 --- /dev/null +++ b/homeassistant/components/climate/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "climate", + "name": "Climate", + "documentation": "https://www.home-assistant.io/components/climate", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/cloud/manifest.json b/homeassistant/components/cloud/manifest.json new file mode 100644 index 00000000000..b7822fcd903 --- /dev/null +++ b/homeassistant/components/cloud/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "cloud", + "name": "Cloud", + "documentation": "https://www.home-assistant.io/components/cloud", + "requirements": [ + "hass-nabucasa==0.11" + ], + "dependencies": [ + "http" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/cloudflare/manifest.json b/homeassistant/components/cloudflare/manifest.json new file mode 100644 index 00000000000..7716ae65c4e --- /dev/null +++ b/homeassistant/components/cloudflare/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "cloudflare", + "name": "Cloudflare", + "documentation": "https://www.home-assistant.io/components/cloudflare", + "requirements": [ + "pycfdns==0.0.1" + ], + "dependencies": [], + "codeowners": [ + "@ludeeus" + ] +} diff --git a/homeassistant/components/cmus/manifest.json b/homeassistant/components/cmus/manifest.json new file mode 100644 index 00000000000..1528f4252b1 --- /dev/null +++ b/homeassistant/components/cmus/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "cmus", + "name": "Cmus", + "documentation": "https://www.home-assistant.io/components/cmus", + "requirements": [ + "pycmus==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/co2signal/manifest.json b/homeassistant/components/co2signal/manifest.json new file mode 100644 index 00000000000..ac42e374fdd --- /dev/null +++ b/homeassistant/components/co2signal/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "co2signal", + "name": "Co2signal", + "documentation": "https://www.home-assistant.io/components/co2signal", + "requirements": [ + "co2signal==0.4.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/coinbase/manifest.json b/homeassistant/components/coinbase/manifest.json new file mode 100644 index 00000000000..5f8a189c7d1 --- /dev/null +++ b/homeassistant/components/coinbase/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "coinbase", + "name": "Coinbase", + "documentation": "https://www.home-assistant.io/components/coinbase", + "requirements": [ + "coinbase==2.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/coinmarketcap/manifest.json b/homeassistant/components/coinmarketcap/manifest.json new file mode 100644 index 00000000000..0afb1b1c28f --- /dev/null +++ b/homeassistant/components/coinmarketcap/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "coinmarketcap", + "name": "Coinmarketcap", + "documentation": "https://www.home-assistant.io/components/coinmarketcap", + "requirements": [ + "coinmarketcap==5.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/comed_hourly_pricing/manifest.json b/homeassistant/components/comed_hourly_pricing/manifest.json new file mode 100644 index 00000000000..47c7931a0e9 --- /dev/null +++ b/homeassistant/components/comed_hourly_pricing/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "comed_hourly_pricing", + "name": "Comed hourly pricing", + "documentation": "https://www.home-assistant.io/components/comed_hourly_pricing", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/comfoconnect/manifest.json b/homeassistant/components/comfoconnect/manifest.json new file mode 100644 index 00000000000..03319aeffa8 --- /dev/null +++ b/homeassistant/components/comfoconnect/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "comfoconnect", + "name": "Comfoconnect", + "documentation": "https://www.home-assistant.io/components/comfoconnect", + "requirements": [ + "pycomfoconnect==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/command_line/manifest.json b/homeassistant/components/command_line/manifest.json new file mode 100644 index 00000000000..ff94522210d --- /dev/null +++ b/homeassistant/components/command_line/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "command_line", + "name": "Command line", + "documentation": "https://www.home-assistant.io/components/command_line", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/concord232/manifest.json b/homeassistant/components/concord232/manifest.json new file mode 100644 index 00000000000..f26da49d3f1 --- /dev/null +++ b/homeassistant/components/concord232/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "concord232", + "name": "Concord232", + "documentation": "https://www.home-assistant.io/components/concord232", + "requirements": [ + "concord232==0.15" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/config/manifest.json b/homeassistant/components/config/manifest.json new file mode 100644 index 00000000000..9c0c50a2595 --- /dev/null +++ b/homeassistant/components/config/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "config", + "name": "Config", + "documentation": "https://www.home-assistant.io/components/config", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/configurator/manifest.json b/homeassistant/components/configurator/manifest.json new file mode 100644 index 00000000000..f01fe7324fa --- /dev/null +++ b/homeassistant/components/configurator/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "configurator", + "name": "Configurator", + "documentation": "https://www.home-assistant.io/components/configurator", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/conversation/manifest.json b/homeassistant/components/conversation/manifest.json new file mode 100644 index 00000000000..ddd3b6205ef --- /dev/null +++ b/homeassistant/components/conversation/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "conversation", + "name": "Conversation", + "documentation": "https://www.home-assistant.io/components/conversation", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/coolmaster/manifest.json b/homeassistant/components/coolmaster/manifest.json new file mode 100644 index 00000000000..9489dc72689 --- /dev/null +++ b/homeassistant/components/coolmaster/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "coolmaster", + "name": "Coolmaster", + "documentation": "https://www.home-assistant.io/components/coolmaster", + "requirements": [ + "pycoolmasternet==0.0.4" + ], + "dependencies": [], + "codeowners": [ + "@OnFreund" + ] +} diff --git a/homeassistant/components/counter/manifest.json b/homeassistant/components/counter/manifest.json new file mode 100644 index 00000000000..ae7066ea82d --- /dev/null +++ b/homeassistant/components/counter/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "counter", + "name": "Counter", + "documentation": "https://www.home-assistant.io/components/counter", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/cover/manifest.json b/homeassistant/components/cover/manifest.json new file mode 100644 index 00000000000..f39f7fb0650 --- /dev/null +++ b/homeassistant/components/cover/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "cover", + "name": "Cover", + "documentation": "https://www.home-assistant.io/components/cover", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [ + "@cdce8p" + ] +} diff --git a/homeassistant/components/cppm_tracker/manifest.json b/homeassistant/components/cppm_tracker/manifest.json new file mode 100644 index 00000000000..5a1bdbf5a45 --- /dev/null +++ b/homeassistant/components/cppm_tracker/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "cppm_tracker", + "name": "Cppm tracker", + "documentation": "https://www.home-assistant.io/components/cppm_tracker", + "requirements": [ + "clearpasspy==1.0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/cpuspeed/manifest.json b/homeassistant/components/cpuspeed/manifest.json new file mode 100644 index 00000000000..9034cb7740d --- /dev/null +++ b/homeassistant/components/cpuspeed/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "cpuspeed", + "name": "Cpuspeed", + "documentation": "https://www.home-assistant.io/components/cpuspeed", + "requirements": [ + "py-cpuinfo==5.0.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/crimereports/manifest.json b/homeassistant/components/crimereports/manifest.json new file mode 100644 index 00000000000..0f74216b9b2 --- /dev/null +++ b/homeassistant/components/crimereports/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "crimereports", + "name": "Crimereports", + "documentation": "https://www.home-assistant.io/components/crimereports", + "requirements": [ + "crimereports==1.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/cups/manifest.json b/homeassistant/components/cups/manifest.json new file mode 100644 index 00000000000..def2846c4ca --- /dev/null +++ b/homeassistant/components/cups/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "cups", + "name": "Cups", + "documentation": "https://www.home-assistant.io/components/cups", + "requirements": [ + "pycups==1.9.73" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/currencylayer/manifest.json b/homeassistant/components/currencylayer/manifest.json new file mode 100644 index 00000000000..7064590bf25 --- /dev/null +++ b/homeassistant/components/currencylayer/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "currencylayer", + "name": "Currencylayer", + "documentation": "https://www.home-assistant.io/components/currencylayer", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/daikin/manifest.json b/homeassistant/components/daikin/manifest.json new file mode 100644 index 00000000000..28314bdf084 --- /dev/null +++ b/homeassistant/components/daikin/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "daikin", + "name": "Daikin", + "documentation": "https://www.home-assistant.io/components/daikin", + "requirements": [ + "pydaikin==1.3.1" + ], + "dependencies": [], + "codeowners": [ + "@fredrike", + "@rofrantz" + ] +} diff --git a/homeassistant/components/danfoss_air/manifest.json b/homeassistant/components/danfoss_air/manifest.json new file mode 100644 index 00000000000..8af1707de65 --- /dev/null +++ b/homeassistant/components/danfoss_air/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "danfoss_air", + "name": "Danfoss air", + "documentation": "https://www.home-assistant.io/components/danfoss_air", + "requirements": [ + "pydanfossair==0.0.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/darksky/manifest.json b/homeassistant/components/darksky/manifest.json new file mode 100644 index 00000000000..e4e6482484c --- /dev/null +++ b/homeassistant/components/darksky/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "darksky", + "name": "Darksky", + "documentation": "https://www.home-assistant.io/components/darksky", + "requirements": [ + "python-forecastio==1.4.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/datadog/manifest.json b/homeassistant/components/datadog/manifest.json new file mode 100644 index 00000000000..40a2e82d53a --- /dev/null +++ b/homeassistant/components/datadog/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "datadog", + "name": "Datadog", + "documentation": "https://www.home-assistant.io/components/datadog", + "requirements": [ + "datadog==0.15.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ddwrt/manifest.json b/homeassistant/components/ddwrt/manifest.json new file mode 100644 index 00000000000..3c877a34841 --- /dev/null +++ b/homeassistant/components/ddwrt/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "ddwrt", + "name": "Ddwrt", + "documentation": "https://www.home-assistant.io/components/ddwrt", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/deconz/manifest.json b/homeassistant/components/deconz/manifest.json new file mode 100644 index 00000000000..c68da4b566c --- /dev/null +++ b/homeassistant/components/deconz/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "deconz", + "name": "Deconz", + "documentation": "https://www.home-assistant.io/components/deconz", + "requirements": [ + "pydeconz==54" + ], + "dependencies": [], + "codeowners": [ + "@kane610" + ] +} diff --git a/homeassistant/components/decora/manifest.json b/homeassistant/components/decora/manifest.json new file mode 100644 index 00000000000..923a543e827 --- /dev/null +++ b/homeassistant/components/decora/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "decora", + "name": "Decora", + "documentation": "https://www.home-assistant.io/components/decora", + "requirements": [ + "bluepy==1.1.4", + "decora==0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/decora_wifi/manifest.json b/homeassistant/components/decora_wifi/manifest.json new file mode 100644 index 00000000000..3e938d743bd --- /dev/null +++ b/homeassistant/components/decora_wifi/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "decora_wifi", + "name": "Decora wifi", + "documentation": "https://www.home-assistant.io/components/decora_wifi", + "requirements": [ + "decora_wifi==1.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/default_config/manifest.json b/homeassistant/components/default_config/manifest.json new file mode 100644 index 00000000000..deda9c06805 --- /dev/null +++ b/homeassistant/components/default_config/manifest.json @@ -0,0 +1,25 @@ +{ + "domain": "default_config", + "name": "Default config", + "documentation": "https://www.home-assistant.io/components/default_config", + "requirements": [], + "dependencies": [ + "automation", + "cloud", + "config", + "conversation", + "frontend", + "history", + "logbook", + "map", + "mobile_app", + "person", + "script", + "stream", + "sun", + "system_health", + "updater", + "zeroconf" + ], + "codeowners": [] +} diff --git a/homeassistant/components/deluge/manifest.json b/homeassistant/components/deluge/manifest.json new file mode 100644 index 00000000000..2b3c6d4c055 --- /dev/null +++ b/homeassistant/components/deluge/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "deluge", + "name": "Deluge", + "documentation": "https://www.home-assistant.io/components/deluge", + "requirements": [ + "deluge-client==1.4.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/demo/manifest.json b/homeassistant/components/demo/manifest.json new file mode 100644 index 00000000000..08cf75a3c53 --- /dev/null +++ b/homeassistant/components/demo/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "demo", + "name": "Demo", + "documentation": "https://www.home-assistant.io/components/demo", + "requirements": [], + "dependencies": [ + "conversation", + "introduction", + "zone" + ], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/denon/manifest.json b/homeassistant/components/denon/manifest.json new file mode 100644 index 00000000000..2068b72fa9d --- /dev/null +++ b/homeassistant/components/denon/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "denon", + "name": "Denon", + "documentation": "https://www.home-assistant.io/components/denon", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/denonavr/manifest.json b/homeassistant/components/denonavr/manifest.json new file mode 100644 index 00000000000..df7d58169e0 --- /dev/null +++ b/homeassistant/components/denonavr/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "denonavr", + "name": "Denonavr", + "documentation": "https://www.home-assistant.io/components/denonavr", + "requirements": [ + "denonavr==0.7.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/deutsche_bahn/manifest.json b/homeassistant/components/deutsche_bahn/manifest.json new file mode 100644 index 00000000000..463c7d03fbb --- /dev/null +++ b/homeassistant/components/deutsche_bahn/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "deutsche_bahn", + "name": "Deutsche bahn", + "documentation": "https://www.home-assistant.io/components/deutsche_bahn", + "requirements": [ + "schiene==0.23" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/device_sun_light_trigger/manifest.json b/homeassistant/components/device_sun_light_trigger/manifest.json new file mode 100644 index 00000000000..abe5a1d500c --- /dev/null +++ b/homeassistant/components/device_sun_light_trigger/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "device_sun_light_trigger", + "name": "Device sun light trigger", + "documentation": "https://www.home-assistant.io/components/device_sun_light_trigger", + "requirements": [], + "dependencies": [ + "device_tracker", + "group", + "light" + ], + "codeowners": [] +} diff --git a/homeassistant/components/device_tracker/manifest.json b/homeassistant/components/device_tracker/manifest.json new file mode 100644 index 00000000000..7b32f7845a6 --- /dev/null +++ b/homeassistant/components/device_tracker/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "device_tracker", + "name": "Device tracker", + "documentation": "https://www.home-assistant.io/components/device_tracker", + "requirements": [], + "dependencies": [ + "group", + "zone" + ], + "codeowners": [] +} diff --git a/homeassistant/components/dht/manifest.json b/homeassistant/components/dht/manifest.json new file mode 100644 index 00000000000..05889bdd326 --- /dev/null +++ b/homeassistant/components/dht/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dht", + "name": "Dht", + "documentation": "https://www.home-assistant.io/components/dht", + "requirements": [ + "Adafruit-DHT==1.4.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dialogflow/manifest.json b/homeassistant/components/dialogflow/manifest.json new file mode 100644 index 00000000000..d136b8a984d --- /dev/null +++ b/homeassistant/components/dialogflow/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dialogflow", + "name": "Dialogflow", + "documentation": "https://www.home-assistant.io/components/dialogflow", + "requirements": [], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/digital_ocean/manifest.json b/homeassistant/components/digital_ocean/manifest.json new file mode 100644 index 00000000000..2ef940f60bd --- /dev/null +++ b/homeassistant/components/digital_ocean/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "digital_ocean", + "name": "Digital ocean", + "documentation": "https://www.home-assistant.io/components/digital_ocean", + "requirements": [ + "python-digitalocean==1.13.2" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/digitalloggers/manifest.json b/homeassistant/components/digitalloggers/manifest.json new file mode 100644 index 00000000000..990b39b21a5 --- /dev/null +++ b/homeassistant/components/digitalloggers/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "digitalloggers", + "name": "Digitalloggers", + "documentation": "https://www.home-assistant.io/components/digitalloggers", + "requirements": [ + "dlipower==0.7.165" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/directv/manifest.json b/homeassistant/components/directv/manifest.json new file mode 100644 index 00000000000..7dbe6122ac1 --- /dev/null +++ b/homeassistant/components/directv/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "directv", + "name": "Directv", + "documentation": "https://www.home-assistant.io/components/directv", + "requirements": [ + "directpy==0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/discogs/manifest.json b/homeassistant/components/discogs/manifest.json new file mode 100644 index 00000000000..ca304bce88b --- /dev/null +++ b/homeassistant/components/discogs/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "discogs", + "name": "Discogs", + "documentation": "https://www.home-assistant.io/components/discogs", + "requirements": [ + "discogs_client==2.2.1" + ], + "dependencies": [], + "codeowners": [ + "@thibmaek" + ] +} diff --git a/homeassistant/components/discord/manifest.json b/homeassistant/components/discord/manifest.json new file mode 100644 index 00000000000..155e2b6806f --- /dev/null +++ b/homeassistant/components/discord/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "discord", + "name": "Discord", + "documentation": "https://www.home-assistant.io/components/discord", + "requirements": [ + "discord.py==0.16.12" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/discovery/manifest.json b/homeassistant/components/discovery/manifest.json new file mode 100644 index 00000000000..845e1af15d4 --- /dev/null +++ b/homeassistant/components/discovery/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "discovery", + "name": "Discovery", + "documentation": "https://www.home-assistant.io/components/discovery", + "requirements": [ + "netdisco==2.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dlib_face_detect/manifest.json b/homeassistant/components/dlib_face_detect/manifest.json new file mode 100644 index 00000000000..c2ede62ee5b --- /dev/null +++ b/homeassistant/components/dlib_face_detect/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dlib_face_detect", + "name": "Dlib face detect", + "documentation": "https://www.home-assistant.io/components/dlib_face_detect", + "requirements": [ + "face_recognition==1.2.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dlib_face_identify/manifest.json b/homeassistant/components/dlib_face_identify/manifest.json new file mode 100644 index 00000000000..388017f78bb --- /dev/null +++ b/homeassistant/components/dlib_face_identify/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dlib_face_identify", + "name": "Dlib face identify", + "documentation": "https://www.home-assistant.io/components/dlib_face_identify", + "requirements": [ + "face_recognition==1.2.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dlink/manifest.json b/homeassistant/components/dlink/manifest.json new file mode 100644 index 00000000000..8f7d07eb0db --- /dev/null +++ b/homeassistant/components/dlink/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dlink", + "name": "Dlink", + "documentation": "https://www.home-assistant.io/components/dlink", + "requirements": [ + "pyW215==0.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dlna_dmr/manifest.json b/homeassistant/components/dlna_dmr/manifest.json new file mode 100644 index 00000000000..be2e655454e --- /dev/null +++ b/homeassistant/components/dlna_dmr/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dlna_dmr", + "name": "Dlna dmr", + "documentation": "https://www.home-assistant.io/components/dlna_dmr", + "requirements": [ + "async-upnp-client==0.14.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dnsip/manifest.json b/homeassistant/components/dnsip/manifest.json new file mode 100644 index 00000000000..2a92f1a0446 --- /dev/null +++ b/homeassistant/components/dnsip/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dnsip", + "name": "Dnsip", + "documentation": "https://www.home-assistant.io/components/dnsip", + "requirements": [ + "aiodns==1.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dominos/manifest.json b/homeassistant/components/dominos/manifest.json new file mode 100644 index 00000000000..f8d13b49f93 --- /dev/null +++ b/homeassistant/components/dominos/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "dominos", + "name": "Dominos", + "documentation": "https://www.home-assistant.io/components/dominos", + "requirements": [ + "pizzapi==0.0.3" + ], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/doorbird/manifest.json b/homeassistant/components/doorbird/manifest.json new file mode 100644 index 00000000000..f65af20f93c --- /dev/null +++ b/homeassistant/components/doorbird/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "doorbird", + "name": "Doorbird", + "documentation": "https://www.home-assistant.io/components/doorbird", + "requirements": [ + "doorbirdpy==2.0.6" + ], + "dependencies": [], + "codeowners": [ + "@oblogic7" + ] +} diff --git a/homeassistant/components/dovado/manifest.json b/homeassistant/components/dovado/manifest.json new file mode 100644 index 00000000000..122d774c268 --- /dev/null +++ b/homeassistant/components/dovado/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dovado", + "name": "Dovado", + "documentation": "https://www.home-assistant.io/components/dovado", + "requirements": [ + "dovado==0.4.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/downloader/manifest.json b/homeassistant/components/downloader/manifest.json new file mode 100644 index 00000000000..514509c004d --- /dev/null +++ b/homeassistant/components/downloader/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "downloader", + "name": "Downloader", + "documentation": "https://www.home-assistant.io/components/downloader", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dsmr/manifest.json b/homeassistant/components/dsmr/manifest.json new file mode 100644 index 00000000000..21c98d56d1d --- /dev/null +++ b/homeassistant/components/dsmr/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dsmr", + "name": "Dsmr", + "documentation": "https://www.home-assistant.io/components/dsmr", + "requirements": [ + "dsmr_parser==0.12" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dte_energy_bridge/manifest.json b/homeassistant/components/dte_energy_bridge/manifest.json new file mode 100644 index 00000000000..fbf7a00f8e6 --- /dev/null +++ b/homeassistant/components/dte_energy_bridge/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "dte_energy_bridge", + "name": "Dte energy bridge", + "documentation": "https://www.home-assistant.io/components/dte_energy_bridge", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dublin_bus_transport/manifest.json b/homeassistant/components/dublin_bus_transport/manifest.json new file mode 100644 index 00000000000..fc13fddc936 --- /dev/null +++ b/homeassistant/components/dublin_bus_transport/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "dublin_bus_transport", + "name": "Dublin bus transport", + "documentation": "https://www.home-assistant.io/components/dublin_bus_transport", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/duckdns/manifest.json b/homeassistant/components/duckdns/manifest.json new file mode 100644 index 00000000000..ed38d35346f --- /dev/null +++ b/homeassistant/components/duckdns/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "duckdns", + "name": "Duckdns", + "documentation": "https://www.home-assistant.io/components/duckdns", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/duke_energy/manifest.json b/homeassistant/components/duke_energy/manifest.json new file mode 100644 index 00000000000..602dfec801f --- /dev/null +++ b/homeassistant/components/duke_energy/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "duke_energy", + "name": "Duke energy", + "documentation": "https://www.home-assistant.io/components/duke_energy", + "requirements": [ + "pydukeenergy==0.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dunehd/manifest.json b/homeassistant/components/dunehd/manifest.json new file mode 100644 index 00000000000..35e6c4a2449 --- /dev/null +++ b/homeassistant/components/dunehd/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dunehd", + "name": "Dunehd", + "documentation": "https://www.home-assistant.io/components/dunehd", + "requirements": [ + "pdunehd==1.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dwd_weather_warnings/manifest.json b/homeassistant/components/dwd_weather_warnings/manifest.json new file mode 100644 index 00000000000..a2b21a9e0bf --- /dev/null +++ b/homeassistant/components/dwd_weather_warnings/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "dwd_weather_warnings", + "name": "Dwd weather warnings", + "documentation": "https://www.home-assistant.io/components/dwd_weather_warnings", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/dweet/manifest.json b/homeassistant/components/dweet/manifest.json new file mode 100644 index 00000000000..e0a00620210 --- /dev/null +++ b/homeassistant/components/dweet/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "dweet", + "name": "Dweet", + "documentation": "https://www.home-assistant.io/components/dweet", + "requirements": [ + "dweepy==0.3.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/dyson/manifest.json b/homeassistant/components/dyson/manifest.json new file mode 100644 index 00000000000..7b956dd96c8 --- /dev/null +++ b/homeassistant/components/dyson/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "dyson", + "name": "Dyson", + "documentation": "https://www.home-assistant.io/components/dyson", + "requirements": [ + "libpurecool==0.5.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ebox/manifest.json b/homeassistant/components/ebox/manifest.json new file mode 100644 index 00000000000..16b033df8fd --- /dev/null +++ b/homeassistant/components/ebox/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ebox", + "name": "Ebox", + "documentation": "https://www.home-assistant.io/components/ebox", + "requirements": [ + "pyebox==1.1.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ebusd/manifest.json b/homeassistant/components/ebusd/manifest.json new file mode 100644 index 00000000000..46b8fb761dc --- /dev/null +++ b/homeassistant/components/ebusd/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ebusd", + "name": "Ebusd", + "documentation": "https://www.home-assistant.io/components/ebusd", + "requirements": [ + "ebusdpy==0.0.16" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ecoal_boiler/manifest.json b/homeassistant/components/ecoal_boiler/manifest.json new file mode 100644 index 00000000000..5bd488e0ff4 --- /dev/null +++ b/homeassistant/components/ecoal_boiler/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ecoal_boiler", + "name": "Ecoal boiler", + "documentation": "https://www.home-assistant.io/components/ecoal_boiler", + "requirements": [ + "ecoaliface==0.4.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ecobee/manifest.json b/homeassistant/components/ecobee/manifest.json new file mode 100644 index 00000000000..3c7275a3895 --- /dev/null +++ b/homeassistant/components/ecobee/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ecobee", + "name": "Ecobee", + "documentation": "https://www.home-assistant.io/components/ecobee", + "requirements": [ + "python-ecobee-api==0.0.18" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/econet/manifest.json b/homeassistant/components/econet/manifest.json new file mode 100644 index 00000000000..bd2cd19d519 --- /dev/null +++ b/homeassistant/components/econet/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "econet", + "name": "Econet", + "documentation": "https://www.home-assistant.io/components/econet", + "requirements": [ + "pyeconet==0.0.10" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ecovacs/manifest.json b/homeassistant/components/ecovacs/manifest.json new file mode 100644 index 00000000000..d36768fb1b0 --- /dev/null +++ b/homeassistant/components/ecovacs/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "ecovacs", + "name": "Ecovacs", + "documentation": "https://www.home-assistant.io/components/ecovacs", + "requirements": [ + "sucks==0.9.3" + ], + "dependencies": [], + "codeowners": [ + "@OverloadUT" + ] +} diff --git a/homeassistant/components/eddystone_temperature/manifest.json b/homeassistant/components/eddystone_temperature/manifest.json new file mode 100644 index 00000000000..4684655aa37 --- /dev/null +++ b/homeassistant/components/eddystone_temperature/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "eddystone_temperature", + "name": "Eddystone temperature", + "documentation": "https://www.home-assistant.io/components/eddystone_temperature", + "requirements": [ + "beacontools[scan]==1.2.3", + "construct==2.9.45" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/edimax/manifest.json b/homeassistant/components/edimax/manifest.json new file mode 100644 index 00000000000..9fe0e4c50c9 --- /dev/null +++ b/homeassistant/components/edimax/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "edimax", + "name": "Edimax", + "documentation": "https://www.home-assistant.io/components/edimax", + "requirements": [ + "pyedimax==0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/edp_redy/manifest.json b/homeassistant/components/edp_redy/manifest.json new file mode 100644 index 00000000000..90404b21678 --- /dev/null +++ b/homeassistant/components/edp_redy/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "edp_redy", + "name": "Edp redy", + "documentation": "https://www.home-assistant.io/components/edp_redy", + "requirements": [ + "edp_redy==0.0.3" + ], + "dependencies": [], + "codeowners": [ + "@abmantis" + ] +} diff --git a/homeassistant/components/ee_brightbox/manifest.json b/homeassistant/components/ee_brightbox/manifest.json new file mode 100644 index 00000000000..967f04228a8 --- /dev/null +++ b/homeassistant/components/ee_brightbox/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ee_brightbox", + "name": "Ee brightbox", + "documentation": "https://www.home-assistant.io/components/ee_brightbox", + "requirements": [ + "eebrightbox==0.0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/efergy/manifest.json b/homeassistant/components/efergy/manifest.json new file mode 100644 index 00000000000..f4ca116a647 --- /dev/null +++ b/homeassistant/components/efergy/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "efergy", + "name": "Efergy", + "documentation": "https://www.home-assistant.io/components/efergy", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/egardia/manifest.json b/homeassistant/components/egardia/manifest.json new file mode 100644 index 00000000000..3a95b90db99 --- /dev/null +++ b/homeassistant/components/egardia/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "egardia", + "name": "Egardia", + "documentation": "https://www.home-assistant.io/components/egardia", + "requirements": [ + "pythonegardia==1.0.39" + ], + "dependencies": [], + "codeowners": [ + "@jeroenterheerdt" + ] +} diff --git a/homeassistant/components/eight_sleep/manifest.json b/homeassistant/components/eight_sleep/manifest.json new file mode 100644 index 00000000000..2b008c3c370 --- /dev/null +++ b/homeassistant/components/eight_sleep/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "eight_sleep", + "name": "Eight sleep", + "documentation": "https://www.home-assistant.io/components/eight_sleep", + "requirements": [ + "pyeight==0.1.1" + ], + "dependencies": [], + "codeowners": [ + "@mezz64" + ] +} diff --git a/homeassistant/components/eliqonline/manifest.json b/homeassistant/components/eliqonline/manifest.json new file mode 100644 index 00000000000..98d94fd009e --- /dev/null +++ b/homeassistant/components/eliqonline/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "eliqonline", + "name": "Eliqonline", + "documentation": "https://www.home-assistant.io/components/eliqonline", + "requirements": [ + "eliqonline==1.2.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/elkm1/manifest.json b/homeassistant/components/elkm1/manifest.json new file mode 100644 index 00000000000..73b48623260 --- /dev/null +++ b/homeassistant/components/elkm1/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "elkm1", + "name": "Elkm1", + "documentation": "https://www.home-assistant.io/components/elkm1", + "requirements": [ + "elkm1-lib==0.7.13" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/emby/manifest.json b/homeassistant/components/emby/manifest.json new file mode 100644 index 00000000000..87688733e59 --- /dev/null +++ b/homeassistant/components/emby/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "emby", + "name": "Emby", + "documentation": "https://www.home-assistant.io/components/emby", + "requirements": [ + "pyemby==1.6" + ], + "dependencies": [], + "codeowners": [ + "@mezz64" + ] +} diff --git a/homeassistant/components/emoncms/manifest.json b/homeassistant/components/emoncms/manifest.json new file mode 100644 index 00000000000..90623c01d1b --- /dev/null +++ b/homeassistant/components/emoncms/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "emoncms", + "name": "Emoncms", + "documentation": "https://www.home-assistant.io/components/emoncms", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/emoncms_history/manifest.json b/homeassistant/components/emoncms_history/manifest.json new file mode 100644 index 00000000000..0cb09e3fb73 --- /dev/null +++ b/homeassistant/components/emoncms_history/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "emoncms_history", + "name": "Emoncms history", + "documentation": "https://www.home-assistant.io/components/emoncms_history", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/emulated_hue/manifest.json b/homeassistant/components/emulated_hue/manifest.json new file mode 100644 index 00000000000..75fcbc4c555 --- /dev/null +++ b/homeassistant/components/emulated_hue/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "emulated_hue", + "name": "Emulated hue", + "documentation": "https://www.home-assistant.io/components/emulated_hue", + "requirements": [ + "aiohttp_cors==0.7.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/emulated_roku/manifest.json b/homeassistant/components/emulated_roku/manifest.json new file mode 100644 index 00000000000..3b8eba396ec --- /dev/null +++ b/homeassistant/components/emulated_roku/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "emulated_roku", + "name": "Emulated roku", + "documentation": "https://www.home-assistant.io/components/emulated_roku", + "requirements": [ + "emulated_roku==0.1.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/enigma2/manifest.json b/homeassistant/components/enigma2/manifest.json new file mode 100644 index 00000000000..78eb9f9deff --- /dev/null +++ b/homeassistant/components/enigma2/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "enigma2", + "name": "Enigma2", + "documentation": "https://www.home-assistant.io/components/enigma2", + "requirements": [ + "openwebifpy==3.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/enocean/manifest.json b/homeassistant/components/enocean/manifest.json new file mode 100644 index 00000000000..7c4d7c0b8d9 --- /dev/null +++ b/homeassistant/components/enocean/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "enocean", + "name": "Enocean", + "documentation": "https://www.home-assistant.io/components/enocean", + "requirements": [ + "enocean==0.40" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/enphase_envoy/manifest.json b/homeassistant/components/enphase_envoy/manifest.json new file mode 100644 index 00000000000..6fee88b39fc --- /dev/null +++ b/homeassistant/components/enphase_envoy/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "enphase_envoy", + "name": "Enphase envoy", + "documentation": "https://www.home-assistant.io/components/enphase_envoy", + "requirements": [ + "envoy_reader==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/entur_public_transport/manifest.json b/homeassistant/components/entur_public_transport/manifest.json new file mode 100644 index 00000000000..b2b60cff95a --- /dev/null +++ b/homeassistant/components/entur_public_transport/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "entur_public_transport", + "name": "Entur public transport", + "documentation": "https://www.home-assistant.io/components/entur_public_transport", + "requirements": [ + "enturclient==0.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/envirophat/manifest.json b/homeassistant/components/envirophat/manifest.json new file mode 100644 index 00000000000..c69a66d43f8 --- /dev/null +++ b/homeassistant/components/envirophat/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "envirophat", + "name": "Envirophat", + "documentation": "https://www.home-assistant.io/components/envirophat", + "requirements": [ + "envirophat==0.0.6", + "smbus-cffi==0.5.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/envisalink/manifest.json b/homeassistant/components/envisalink/manifest.json new file mode 100644 index 00000000000..b34aa08951c --- /dev/null +++ b/homeassistant/components/envisalink/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "envisalink", + "name": "Envisalink", + "documentation": "https://www.home-assistant.io/components/envisalink", + "requirements": [ + "pyenvisalink==3.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ephember/manifest.json b/homeassistant/components/ephember/manifest.json new file mode 100644 index 00000000000..3fed307aed5 --- /dev/null +++ b/homeassistant/components/ephember/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "ephember", + "name": "Ephember", + "documentation": "https://www.home-assistant.io/components/ephember", + "requirements": [ + "pyephember==0.2.0" + ], + "dependencies": [], + "codeowners": [ + "@ttroy50" + ] +} diff --git a/homeassistant/components/epson/manifest.json b/homeassistant/components/epson/manifest.json new file mode 100644 index 00000000000..e6623b83013 --- /dev/null +++ b/homeassistant/components/epson/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "epson", + "name": "Epson", + "documentation": "https://www.home-assistant.io/components/epson", + "requirements": [ + "epson-projector==0.1.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/eq3btsmart/manifest.json b/homeassistant/components/eq3btsmart/manifest.json new file mode 100644 index 00000000000..6d13c79bcec --- /dev/null +++ b/homeassistant/components/eq3btsmart/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "eq3btsmart", + "name": "Eq3btsmart", + "documentation": "https://www.home-assistant.io/components/eq3btsmart", + "requirements": [ + "construct==2.9.45", + "python-eq3bt==0.1.9" + ], + "dependencies": [], + "codeowners": [ + "@rytilahti" + ] +} diff --git a/homeassistant/components/esphome/manifest.json b/homeassistant/components/esphome/manifest.json new file mode 100644 index 00000000000..b00cdf9607d --- /dev/null +++ b/homeassistant/components/esphome/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "esphome", + "name": "Esphome", + "documentation": "https://www.home-assistant.io/components/esphome", + "requirements": [ + "aioesphomeapi==1.7.0" + ], + "dependencies": [], + "codeowners": [ + "@OttoWinter" + ] +} diff --git a/homeassistant/components/etherscan/manifest.json b/homeassistant/components/etherscan/manifest.json new file mode 100644 index 00000000000..452d1c4c475 --- /dev/null +++ b/homeassistant/components/etherscan/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "etherscan", + "name": "Etherscan", + "documentation": "https://www.home-assistant.io/components/etherscan", + "requirements": [ + "python-etherscan-api==0.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/eufy/manifest.json b/homeassistant/components/eufy/manifest.json new file mode 100644 index 00000000000..ec7f1fe7072 --- /dev/null +++ b/homeassistant/components/eufy/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "eufy", + "name": "Eufy", + "documentation": "https://www.home-assistant.io/components/eufy", + "requirements": [ + "lakeside==0.12" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/everlights/manifest.json b/homeassistant/components/everlights/manifest.json new file mode 100644 index 00000000000..9c2e1b2ae4f --- /dev/null +++ b/homeassistant/components/everlights/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "everlights", + "name": "Everlights", + "documentation": "https://www.home-assistant.io/components/everlights", + "requirements": [ + "pyeverlights==0.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/evohome/manifest.json b/homeassistant/components/evohome/manifest.json new file mode 100644 index 00000000000..b612baa476a --- /dev/null +++ b/homeassistant/components/evohome/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "evohome", + "name": "Evohome", + "documentation": "https://www.home-assistant.io/components/evohome", + "requirements": [ + "evohomeclient==0.3.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/facebook/manifest.json b/homeassistant/components/facebook/manifest.json new file mode 100644 index 00000000000..9632906a25a --- /dev/null +++ b/homeassistant/components/facebook/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "facebook", + "name": "Facebook", + "documentation": "https://www.home-assistant.io/components/facebook", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/facebox/manifest.json b/homeassistant/components/facebox/manifest.json new file mode 100644 index 00000000000..4a3eefc135c --- /dev/null +++ b/homeassistant/components/facebox/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "facebox", + "name": "Facebox", + "documentation": "https://www.home-assistant.io/components/facebox", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fail2ban/manifest.json b/homeassistant/components/fail2ban/manifest.json new file mode 100644 index 00000000000..fc60658a3f2 --- /dev/null +++ b/homeassistant/components/fail2ban/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "fail2ban", + "name": "Fail2ban", + "documentation": "https://www.home-assistant.io/components/fail2ban", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/familyhub/manifest.json b/homeassistant/components/familyhub/manifest.json new file mode 100644 index 00000000000..48a73dfb030 --- /dev/null +++ b/homeassistant/components/familyhub/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "familyhub", + "name": "Familyhub", + "documentation": "https://www.home-assistant.io/components/familyhub", + "requirements": [ + "python-family-hub-local==0.0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fan/manifest.json b/homeassistant/components/fan/manifest.json new file mode 100644 index 00000000000..85bb982d2d1 --- /dev/null +++ b/homeassistant/components/fan/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fan", + "name": "Fan", + "documentation": "https://www.home-assistant.io/components/fan", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [] +} diff --git a/homeassistant/components/fastdotcom/manifest.json b/homeassistant/components/fastdotcom/manifest.json new file mode 100644 index 00000000000..f4bf021380c --- /dev/null +++ b/homeassistant/components/fastdotcom/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fastdotcom", + "name": "Fastdotcom", + "documentation": "https://www.home-assistant.io/components/fastdotcom", + "requirements": [ + "fastdotcom==0.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fedex/manifest.json b/homeassistant/components/fedex/manifest.json new file mode 100644 index 00000000000..b34a8b8383e --- /dev/null +++ b/homeassistant/components/fedex/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fedex", + "name": "Fedex", + "documentation": "https://www.home-assistant.io/components/fedex", + "requirements": [ + "fedexdeliverymanager==1.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/feedreader/manifest.json b/homeassistant/components/feedreader/manifest.json new file mode 100644 index 00000000000..e458d30073e --- /dev/null +++ b/homeassistant/components/feedreader/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "feedreader", + "name": "Feedreader", + "documentation": "https://www.home-assistant.io/components/feedreader", + "requirements": [ + "feedparser-homeassistant==5.2.2.dev1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ffmpeg/manifest.json b/homeassistant/components/ffmpeg/manifest.json new file mode 100644 index 00000000000..4a3695e7dcc --- /dev/null +++ b/homeassistant/components/ffmpeg/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ffmpeg", + "name": "Ffmpeg", + "documentation": "https://www.home-assistant.io/components/ffmpeg", + "requirements": [ + "ha-ffmpeg==2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ffmpeg_motion/manifest.json b/homeassistant/components/ffmpeg_motion/manifest.json new file mode 100644 index 00000000000..bc5dfaa4209 --- /dev/null +++ b/homeassistant/components/ffmpeg_motion/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "ffmpeg_motion", + "name": "Ffmpeg motion", + "documentation": "https://www.home-assistant.io/components/ffmpeg_motion", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ffmpeg_noise/manifest.json b/homeassistant/components/ffmpeg_noise/manifest.json new file mode 100644 index 00000000000..6fdf07899fd --- /dev/null +++ b/homeassistant/components/ffmpeg_noise/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "ffmpeg_noise", + "name": "Ffmpeg noise", + "documentation": "https://www.home-assistant.io/components/ffmpeg_noise", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fibaro/manifest.json b/homeassistant/components/fibaro/manifest.json new file mode 100644 index 00000000000..3574e6254de --- /dev/null +++ b/homeassistant/components/fibaro/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fibaro", + "name": "Fibaro", + "documentation": "https://www.home-assistant.io/components/fibaro", + "requirements": [ + "fiblary3==0.1.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fido/manifest.json b/homeassistant/components/fido/manifest.json new file mode 100644 index 00000000000..343a21ff072 --- /dev/null +++ b/homeassistant/components/fido/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fido", + "name": "Fido", + "documentation": "https://www.home-assistant.io/components/fido", + "requirements": [ + "pyfido==2.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/file/manifest.json b/homeassistant/components/file/manifest.json new file mode 100644 index 00000000000..581b0e14156 --- /dev/null +++ b/homeassistant/components/file/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "file", + "name": "File", + "documentation": "https://www.home-assistant.io/components/file", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/filesize/manifest.json b/homeassistant/components/filesize/manifest.json new file mode 100644 index 00000000000..f76bcd27466 --- /dev/null +++ b/homeassistant/components/filesize/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "filesize", + "name": "Filesize", + "documentation": "https://www.home-assistant.io/components/filesize", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/filter/manifest.json b/homeassistant/components/filter/manifest.json new file mode 100644 index 00000000000..28f061d26f7 --- /dev/null +++ b/homeassistant/components/filter/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "filter", + "name": "Filter", + "documentation": "https://www.home-assistant.io/components/filter", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@dgomes" + ] +} diff --git a/homeassistant/components/fints/manifest.json b/homeassistant/components/fints/manifest.json new file mode 100644 index 00000000000..e3580676290 --- /dev/null +++ b/homeassistant/components/fints/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fints", + "name": "Fints", + "documentation": "https://www.home-assistant.io/components/fints", + "requirements": [ + "fints==1.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fitbit/manifest.json b/homeassistant/components/fitbit/manifest.json new file mode 100644 index 00000000000..d1335a1347d --- /dev/null +++ b/homeassistant/components/fitbit/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "fitbit", + "name": "Fitbit", + "documentation": "https://www.home-assistant.io/components/fitbit", + "requirements": [ + "fitbit==0.3.0" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/fixer/manifest.json b/homeassistant/components/fixer/manifest.json new file mode 100644 index 00000000000..1e010bb06ed --- /dev/null +++ b/homeassistant/components/fixer/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "fixer", + "name": "Fixer", + "documentation": "https://www.home-assistant.io/components/fixer", + "requirements": [ + "fixerio==1.0.0a0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/flexit/manifest.json b/homeassistant/components/flexit/manifest.json new file mode 100644 index 00000000000..1af86243f86 --- /dev/null +++ b/homeassistant/components/flexit/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "flexit", + "name": "Flexit", + "documentation": "https://www.home-assistant.io/components/flexit", + "requirements": [ + "pyflexit==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/flic/manifest.json b/homeassistant/components/flic/manifest.json new file mode 100644 index 00000000000..827bcb167c3 --- /dev/null +++ b/homeassistant/components/flic/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "flic", + "name": "Flic", + "documentation": "https://www.home-assistant.io/components/flic", + "requirements": [ + "pyflic-homeassistant==0.4.dev0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/flock/manifest.json b/homeassistant/components/flock/manifest.json new file mode 100644 index 00000000000..a5af541eeee --- /dev/null +++ b/homeassistant/components/flock/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "flock", + "name": "Flock", + "documentation": "https://www.home-assistant.io/components/flock", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/flunearyou/manifest.json b/homeassistant/components/flunearyou/manifest.json new file mode 100644 index 00000000000..76053f75081 --- /dev/null +++ b/homeassistant/components/flunearyou/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "flunearyou", + "name": "Flunearyou", + "documentation": "https://www.home-assistant.io/components/flunearyou", + "requirements": [ + "pyflunearyou==1.0.3" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/flux/manifest.json b/homeassistant/components/flux/manifest.json new file mode 100644 index 00000000000..8c07a70bca6 --- /dev/null +++ b/homeassistant/components/flux/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "flux", + "name": "Flux", + "documentation": "https://www.home-assistant.io/components/flux", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/flux_led/manifest.json b/homeassistant/components/flux_led/manifest.json new file mode 100644 index 00000000000..0d00275200c --- /dev/null +++ b/homeassistant/components/flux_led/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "flux_led", + "name": "Flux led", + "documentation": "https://www.home-assistant.io/components/flux_led", + "requirements": [ + "flux_led==0.22" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/folder/manifest.json b/homeassistant/components/folder/manifest.json new file mode 100644 index 00000000000..7a0bf76e0aa --- /dev/null +++ b/homeassistant/components/folder/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "folder", + "name": "Folder", + "documentation": "https://www.home-assistant.io/components/folder", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/folder_watcher/manifest.json b/homeassistant/components/folder_watcher/manifest.json new file mode 100644 index 00000000000..1a5b547e5ff --- /dev/null +++ b/homeassistant/components/folder_watcher/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "folder_watcher", + "name": "Folder watcher", + "documentation": "https://www.home-assistant.io/components/folder_watcher", + "requirements": [ + "watchdog==0.8.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/foobot/manifest.json b/homeassistant/components/foobot/manifest.json new file mode 100644 index 00000000000..9ed95597e41 --- /dev/null +++ b/homeassistant/components/foobot/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "foobot", + "name": "Foobot", + "documentation": "https://www.home-assistant.io/components/foobot", + "requirements": [ + "foobot_async==0.3.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/foscam/manifest.json b/homeassistant/components/foscam/manifest.json new file mode 100644 index 00000000000..b05aa956b42 --- /dev/null +++ b/homeassistant/components/foscam/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "foscam", + "name": "Foscam", + "documentation": "https://www.home-assistant.io/components/foscam", + "requirements": [ + "libpyfoscam==1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/foursquare/manifest.json b/homeassistant/components/foursquare/manifest.json new file mode 100644 index 00000000000..84a98ca0336 --- /dev/null +++ b/homeassistant/components/foursquare/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "foursquare", + "name": "Foursquare", + "documentation": "https://www.home-assistant.io/components/foursquare", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/free_mobile/manifest.json b/homeassistant/components/free_mobile/manifest.json new file mode 100644 index 00000000000..b8a40c3fc1d --- /dev/null +++ b/homeassistant/components/free_mobile/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "free_mobile", + "name": "Free mobile", + "documentation": "https://www.home-assistant.io/components/free_mobile", + "requirements": [ + "freesms==0.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/freebox/manifest.json b/homeassistant/components/freebox/manifest.json new file mode 100644 index 00000000000..9ee134d4170 --- /dev/null +++ b/homeassistant/components/freebox/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "freebox", + "name": "Freebox", + "documentation": "https://www.home-assistant.io/components/freebox", + "requirements": [ + "aiofreepybox==0.0.8" + ], + "dependencies": [], + "codeowners": [ + "@snoof85" + ] +} diff --git a/homeassistant/components/freedns/manifest.json b/homeassistant/components/freedns/manifest.json new file mode 100644 index 00000000000..63f929754db --- /dev/null +++ b/homeassistant/components/freedns/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "freedns", + "name": "Freedns", + "documentation": "https://www.home-assistant.io/components/freedns", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fritz/manifest.json b/homeassistant/components/fritz/manifest.json new file mode 100644 index 00000000000..b2aacbd48ad --- /dev/null +++ b/homeassistant/components/fritz/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fritz", + "name": "Fritz", + "documentation": "https://www.home-assistant.io/components/fritz", + "requirements": [ + "fritzconnection==0.6.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fritzbox/manifest.json b/homeassistant/components/fritzbox/manifest.json new file mode 100644 index 00000000000..1ed18140bd2 --- /dev/null +++ b/homeassistant/components/fritzbox/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fritzbox", + "name": "Fritzbox", + "documentation": "https://www.home-assistant.io/components/fritzbox", + "requirements": [ + "pyfritzhome==0.4.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fritzbox_callmonitor/manifest.json b/homeassistant/components/fritzbox_callmonitor/manifest.json new file mode 100644 index 00000000000..19f232ed667 --- /dev/null +++ b/homeassistant/components/fritzbox_callmonitor/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fritzbox_callmonitor", + "name": "Fritzbox callmonitor", + "documentation": "https://www.home-assistant.io/components/fritzbox_callmonitor", + "requirements": [ + "fritzconnection==0.6.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fritzbox_netmonitor/manifest.json b/homeassistant/components/fritzbox_netmonitor/manifest.json new file mode 100644 index 00000000000..ac1ce2893e4 --- /dev/null +++ b/homeassistant/components/fritzbox_netmonitor/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fritzbox_netmonitor", + "name": "Fritzbox netmonitor", + "documentation": "https://www.home-assistant.io/components/fritzbox_netmonitor", + "requirements": [ + "fritzconnection==0.6.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/fritzdect/manifest.json b/homeassistant/components/fritzdect/manifest.json new file mode 100644 index 00000000000..98d628fe078 --- /dev/null +++ b/homeassistant/components/fritzdect/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fritzdect", + "name": "Fritzdect", + "documentation": "https://www.home-assistant.io/components/fritzdect", + "requirements": [ + "fritzhome==1.0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json new file mode 100644 index 00000000000..5be4593a8bd --- /dev/null +++ b/homeassistant/components/frontend/manifest.json @@ -0,0 +1,20 @@ +{ + "domain": "frontend", + "name": "Home Assistant Frontend", + "documentation": "https://www.home-assistant.io/components/frontend", + "requirements": [ + "home-assistant-frontend==20190331.0" + ], + "dependencies": [ + "api", + "auth", + "http", + "lovelace", + "onboarding", + "system_log", + "websocket_api" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/frontier_silicon/manifest.json b/homeassistant/components/frontier_silicon/manifest.json new file mode 100644 index 00000000000..0e20a509d1f --- /dev/null +++ b/homeassistant/components/frontier_silicon/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "frontier_silicon", + "name": "Frontier silicon", + "documentation": "https://www.home-assistant.io/components/frontier_silicon", + "requirements": [ + "afsapi==0.0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/futurenow/manifest.json b/homeassistant/components/futurenow/manifest.json new file mode 100644 index 00000000000..5191ab611ac --- /dev/null +++ b/homeassistant/components/futurenow/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "futurenow", + "name": "Futurenow", + "documentation": "https://www.home-assistant.io/components/futurenow", + "requirements": [ + "pyfnip==0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/garadget/manifest.json b/homeassistant/components/garadget/manifest.json new file mode 100644 index 00000000000..d3781f81d04 --- /dev/null +++ b/homeassistant/components/garadget/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "garadget", + "name": "Garadget", + "documentation": "https://www.home-assistant.io/components/garadget", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/gc100/manifest.json b/homeassistant/components/gc100/manifest.json new file mode 100644 index 00000000000..96d792196ce --- /dev/null +++ b/homeassistant/components/gc100/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "gc100", + "name": "Gc100", + "documentation": "https://www.home-assistant.io/components/gc100", + "requirements": [ + "python-gc100==1.0.3a" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/gearbest/manifest.json b/homeassistant/components/gearbest/manifest.json new file mode 100644 index 00000000000..39ceca41d08 --- /dev/null +++ b/homeassistant/components/gearbest/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "gearbest", + "name": "Gearbest", + "documentation": "https://www.home-assistant.io/components/gearbest", + "requirements": [ + "gearbest_parser==1.0.7" + ], + "dependencies": [], + "codeowners": [ + "@HerrHofrat" + ] +} diff --git a/homeassistant/components/geizhals/manifest.json b/homeassistant/components/geizhals/manifest.json new file mode 100644 index 00000000000..d53bceaa145 --- /dev/null +++ b/homeassistant/components/geizhals/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "geizhals", + "name": "Geizhals", + "documentation": "https://www.home-assistant.io/components/geizhals", + "requirements": [ + "geizhals==0.0.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/generic/manifest.json b/homeassistant/components/generic/manifest.json new file mode 100644 index 00000000000..e4d3622a562 --- /dev/null +++ b/homeassistant/components/generic/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "generic", + "name": "Generic", + "documentation": "https://www.home-assistant.io/components/generic", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/generic_thermostat/manifest.json b/homeassistant/components/generic_thermostat/manifest.json new file mode 100644 index 00000000000..67306b1e7cd --- /dev/null +++ b/homeassistant/components/generic_thermostat/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "generic_thermostat", + "name": "Generic thermostat", + "documentation": "https://www.home-assistant.io/components/generic_thermostat", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/geo_json_events/manifest.json b/homeassistant/components/geo_json_events/manifest.json new file mode 100644 index 00000000000..8e4d7b8a7cd --- /dev/null +++ b/homeassistant/components/geo_json_events/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "geo_json_events", + "name": "Geo json events", + "documentation": "https://www.home-assistant.io/components/geo_json_events", + "requirements": [ + "geojson_client==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/geo_location/manifest.json b/homeassistant/components/geo_location/manifest.json new file mode 100644 index 00000000000..83b4241284e --- /dev/null +++ b/homeassistant/components/geo_location/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "geo_location", + "name": "Geo location", + "documentation": "https://www.home-assistant.io/components/geo_location", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/geo_rss_events/manifest.json b/homeassistant/components/geo_rss_events/manifest.json new file mode 100644 index 00000000000..bce6758b0fe --- /dev/null +++ b/homeassistant/components/geo_rss_events/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "geo_rss_events", + "name": "Geo rss events", + "documentation": "https://www.home-assistant.io/components/geo_rss_events", + "requirements": [ + "georss_generic_client==0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/geofency/manifest.json b/homeassistant/components/geofency/manifest.json new file mode 100644 index 00000000000..576d0e419a7 --- /dev/null +++ b/homeassistant/components/geofency/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "geofency", + "name": "Geofency", + "documentation": "https://www.home-assistant.io/components/geofency", + "requirements": [], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/github/manifest.json b/homeassistant/components/github/manifest.json new file mode 100644 index 00000000000..a2c2ae04376 --- /dev/null +++ b/homeassistant/components/github/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "github", + "name": "Github", + "documentation": "https://www.home-assistant.io/components/github", + "requirements": [ + "PyGithub==1.43.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/gitlab_ci/manifest.json b/homeassistant/components/gitlab_ci/manifest.json new file mode 100644 index 00000000000..4ea04de9e02 --- /dev/null +++ b/homeassistant/components/gitlab_ci/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "gitlab_ci", + "name": "Gitlab ci", + "documentation": "https://www.home-assistant.io/components/gitlab_ci", + "requirements": [ + "python-gitlab==1.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/gitter/manifest.json b/homeassistant/components/gitter/manifest.json new file mode 100644 index 00000000000..6600e46a4ce --- /dev/null +++ b/homeassistant/components/gitter/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "gitter", + "name": "Gitter", + "documentation": "https://www.home-assistant.io/components/gitter", + "requirements": [ + "gitterpy==0.1.7" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/glances/manifest.json b/homeassistant/components/glances/manifest.json new file mode 100644 index 00000000000..621bca8c430 --- /dev/null +++ b/homeassistant/components/glances/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "glances", + "name": "Glances", + "documentation": "https://www.home-assistant.io/components/glances", + "requirements": [ + "glances_api==0.2.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/gntp/manifest.json b/homeassistant/components/gntp/manifest.json new file mode 100644 index 00000000000..7315e3c7c84 --- /dev/null +++ b/homeassistant/components/gntp/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "gntp", + "name": "Gntp", + "documentation": "https://www.home-assistant.io/components/gntp", + "requirements": [ + "gntp==1.0.3" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/goalfeed/manifest.json b/homeassistant/components/goalfeed/manifest.json new file mode 100644 index 00000000000..861abe0b462 --- /dev/null +++ b/homeassistant/components/goalfeed/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "goalfeed", + "name": "Goalfeed", + "documentation": "https://www.home-assistant.io/components/goalfeed", + "requirements": [ + "pysher==1.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/gogogate2/manifest.json b/homeassistant/components/gogogate2/manifest.json new file mode 100644 index 00000000000..3f3f2c25d0c --- /dev/null +++ b/homeassistant/components/gogogate2/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "gogogate2", + "name": "Gogogate2", + "documentation": "https://www.home-assistant.io/components/gogogate2", + "requirements": [ + "pygogogate2==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/google/manifest.json b/homeassistant/components/google/manifest.json new file mode 100644 index 00000000000..2db50b2d5b9 --- /dev/null +++ b/homeassistant/components/google/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "google", + "name": "Google", + "documentation": "https://www.home-assistant.io/components/google", + "requirements": [ + "gTTS-token==1.1.3", + "google-api-python-client==1.6.4", + "httplib2==0.10.3", + "oauth2client==4.0.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/google_assistant/manifest.json b/homeassistant/components/google_assistant/manifest.json new file mode 100644 index 00000000000..ff916930216 --- /dev/null +++ b/homeassistant/components/google_assistant/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "google_assistant", + "name": "Google assistant", + "documentation": "https://www.home-assistant.io/components/google_assistant", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/google_domains/manifest.json b/homeassistant/components/google_domains/manifest.json new file mode 100644 index 00000000000..190e5860ee6 --- /dev/null +++ b/homeassistant/components/google_domains/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "google_domains", + "name": "Google domains", + "documentation": "https://www.home-assistant.io/components/google_domains", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/google_maps/manifest.json b/homeassistant/components/google_maps/manifest.json new file mode 100644 index 00000000000..7d6aeeef041 --- /dev/null +++ b/homeassistant/components/google_maps/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "google_maps", + "name": "Google maps", + "documentation": "https://www.home-assistant.io/components/google_maps", + "requirements": [ + "locationsharinglib==3.0.11" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/google_pubsub/manifest.json b/homeassistant/components/google_pubsub/manifest.json new file mode 100644 index 00000000000..ff61ad0e05d --- /dev/null +++ b/homeassistant/components/google_pubsub/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "google_pubsub", + "name": "Google pubsub", + "documentation": "https://www.home-assistant.io/components/google_pubsub", + "requirements": [ + "google-cloud-pubsub==0.39.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/google_travel_time/manifest.json b/homeassistant/components/google_travel_time/manifest.json new file mode 100644 index 00000000000..eaa168332a6 --- /dev/null +++ b/homeassistant/components/google_travel_time/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "google_travel_time", + "name": "Google travel time", + "documentation": "https://www.home-assistant.io/components/google_travel_time", + "requirements": [ + "googlemaps==2.5.1" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/google_wifi/manifest.json b/homeassistant/components/google_wifi/manifest.json new file mode 100644 index 00000000000..6e840458207 --- /dev/null +++ b/homeassistant/components/google_wifi/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "google_wifi", + "name": "Google wifi", + "documentation": "https://www.home-assistant.io/components/google_wifi", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/googlehome/manifest.json b/homeassistant/components/googlehome/manifest.json new file mode 100644 index 00000000000..107e7d634f0 --- /dev/null +++ b/homeassistant/components/googlehome/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "googlehome", + "name": "Googlehome", + "documentation": "https://www.home-assistant.io/components/googlehome", + "requirements": [ + "googledevices==1.0.2" + ], + "dependencies": [], + "codeowners": [ + "@ludeeus" + ] +} diff --git a/homeassistant/components/gpmdp/manifest.json b/homeassistant/components/gpmdp/manifest.json new file mode 100644 index 00000000000..97e97e7645c --- /dev/null +++ b/homeassistant/components/gpmdp/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "gpmdp", + "name": "Gpmdp", + "documentation": "https://www.home-assistant.io/components/gpmdp", + "requirements": [ + "websocket-client==0.54.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/gpsd/manifest.json b/homeassistant/components/gpsd/manifest.json new file mode 100644 index 00000000000..b35d5cb1850 --- /dev/null +++ b/homeassistant/components/gpsd/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "gpsd", + "name": "Gpsd", + "documentation": "https://www.home-assistant.io/components/gpsd", + "requirements": [ + "gps3==0.33.3" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/gpslogger/manifest.json b/homeassistant/components/gpslogger/manifest.json new file mode 100644 index 00000000000..2d2166c1bb1 --- /dev/null +++ b/homeassistant/components/gpslogger/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "gpslogger", + "name": "Gpslogger", + "documentation": "https://www.home-assistant.io/components/gpslogger", + "requirements": [], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/graphite/manifest.json b/homeassistant/components/graphite/manifest.json new file mode 100644 index 00000000000..a5eefc5af04 --- /dev/null +++ b/homeassistant/components/graphite/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "graphite", + "name": "Graphite", + "documentation": "https://www.home-assistant.io/components/graphite", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/greeneye_monitor/manifest.json b/homeassistant/components/greeneye_monitor/manifest.json new file mode 100644 index 00000000000..7bfb87ede47 --- /dev/null +++ b/homeassistant/components/greeneye_monitor/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "greeneye_monitor", + "name": "Greeneye monitor", + "documentation": "https://www.home-assistant.io/components/greeneye_monitor", + "requirements": [ + "greeneye_monitor==1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/greenwave/manifest.json b/homeassistant/components/greenwave/manifest.json new file mode 100644 index 00000000000..1032b5eaf2a --- /dev/null +++ b/homeassistant/components/greenwave/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "greenwave", + "name": "Greenwave", + "documentation": "https://www.home-assistant.io/components/greenwave", + "requirements": [ + "greenwavereality==0.5.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/group/manifest.json b/homeassistant/components/group/manifest.json new file mode 100644 index 00000000000..aa99e20a4df --- /dev/null +++ b/homeassistant/components/group/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "group", + "name": "Group", + "documentation": "https://www.home-assistant.io/components/group", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/gstreamer/manifest.json b/homeassistant/components/gstreamer/manifest.json new file mode 100644 index 00000000000..6bfb8abbe0b --- /dev/null +++ b/homeassistant/components/gstreamer/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "gstreamer", + "name": "Gstreamer", + "documentation": "https://www.home-assistant.io/components/gstreamer", + "requirements": [ + "gstreamer-player==1.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/gtfs/manifest.json b/homeassistant/components/gtfs/manifest.json new file mode 100644 index 00000000000..1c7ddbd65ee --- /dev/null +++ b/homeassistant/components/gtfs/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "gtfs", + "name": "Gtfs", + "documentation": "https://www.home-assistant.io/components/gtfs", + "requirements": [ + "pygtfs==0.1.5" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/gtt/manifest.json b/homeassistant/components/gtt/manifest.json new file mode 100644 index 00000000000..142261fe155 --- /dev/null +++ b/homeassistant/components/gtt/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "gtt", + "name": "Gtt", + "documentation": "https://www.home-assistant.io/components/gtt", + "requirements": [ + "pygtt==1.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/habitica/manifest.json b/homeassistant/components/habitica/manifest.json new file mode 100644 index 00000000000..b8e622823d3 --- /dev/null +++ b/homeassistant/components/habitica/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "habitica", + "name": "Habitica", + "documentation": "https://www.home-assistant.io/components/habitica", + "requirements": [ + "habitipy==0.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hangouts/manifest.json b/homeassistant/components/hangouts/manifest.json new file mode 100644 index 00000000000..a17bd76adb4 --- /dev/null +++ b/homeassistant/components/hangouts/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hangouts", + "name": "Hangouts", + "documentation": "https://www.home-assistant.io/components/hangouts", + "requirements": [ + "hangups==0.4.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/harman_kardon_avr/manifest.json b/homeassistant/components/harman_kardon_avr/manifest.json new file mode 100644 index 00000000000..eecbf0edd63 --- /dev/null +++ b/homeassistant/components/harman_kardon_avr/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "harman_kardon_avr", + "name": "Harman kardon avr", + "documentation": "https://www.home-assistant.io/components/harman_kardon_avr", + "requirements": [ + "hkavr==0.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/harmony/manifest.json b/homeassistant/components/harmony/manifest.json new file mode 100644 index 00000000000..c82e9b7bf10 --- /dev/null +++ b/homeassistant/components/harmony/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "harmony", + "name": "Harmony", + "documentation": "https://www.home-assistant.io/components/harmony", + "requirements": [ + "aioharmony==0.1.8" + ], + "dependencies": [], + "codeowners": [ + "@ehendrix23" + ] +} diff --git a/homeassistant/components/hassio/manifest.json b/homeassistant/components/hassio/manifest.json new file mode 100644 index 00000000000..e412f587abd --- /dev/null +++ b/homeassistant/components/hassio/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "hassio", + "name": "Hass.io", + "documentation": "https://www.home-assistant.io/hassio", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [ + "@home-assistant/hassio" + ] +} diff --git a/homeassistant/components/haveibeenpwned/manifest.json b/homeassistant/components/haveibeenpwned/manifest.json new file mode 100644 index 00000000000..f0b0561e170 --- /dev/null +++ b/homeassistant/components/haveibeenpwned/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "haveibeenpwned", + "name": "Haveibeenpwned", + "documentation": "https://www.home-assistant.io/components/haveibeenpwned", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hddtemp/manifest.json b/homeassistant/components/hddtemp/manifest.json new file mode 100644 index 00000000000..2d34d3b4e7b --- /dev/null +++ b/homeassistant/components/hddtemp/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "hddtemp", + "name": "Hddtemp", + "documentation": "https://www.home-assistant.io/components/hddtemp", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hdmi_cec/manifest.json b/homeassistant/components/hdmi_cec/manifest.json new file mode 100644 index 00000000000..b59d5622821 --- /dev/null +++ b/homeassistant/components/hdmi_cec/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hdmi_cec", + "name": "Hdmi cec", + "documentation": "https://www.home-assistant.io/components/hdmi_cec", + "requirements": [ + "pyCEC==0.4.13" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/heatmiser/manifest.json b/homeassistant/components/heatmiser/manifest.json new file mode 100644 index 00000000000..0a11aecd079 --- /dev/null +++ b/homeassistant/components/heatmiser/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "heatmiser", + "name": "Heatmiser", + "documentation": "https://www.home-assistant.io/components/heatmiser", + "requirements": [ + "heatmiserV3==0.9.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/heos/manifest.json b/homeassistant/components/heos/manifest.json new file mode 100644 index 00000000000..91cefed75f7 --- /dev/null +++ b/homeassistant/components/heos/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "heos", + "name": "Heos", + "documentation": "https://www.home-assistant.io/components/heos", + "requirements": [ + "pyheos==0.3.0" + ], + "dependencies": [], + "codeowners": [ + "@andrewsayre" + ] +} diff --git a/homeassistant/components/hikvision/manifest.json b/homeassistant/components/hikvision/manifest.json new file mode 100644 index 00000000000..db6af975081 --- /dev/null +++ b/homeassistant/components/hikvision/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "hikvision", + "name": "Hikvision", + "documentation": "https://www.home-assistant.io/components/hikvision", + "requirements": [ + "pyhik==0.2.2" + ], + "dependencies": [], + "codeowners": [ + "@mezz64" + ] +} diff --git a/homeassistant/components/hikvisioncam/manifest.json b/homeassistant/components/hikvisioncam/manifest.json new file mode 100644 index 00000000000..ec63425572d --- /dev/null +++ b/homeassistant/components/hikvisioncam/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hikvisioncam", + "name": "Hikvisioncam", + "documentation": "https://www.home-assistant.io/components/hikvisioncam", + "requirements": [ + "hikvision==0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hipchat/manifest.json b/homeassistant/components/hipchat/manifest.json new file mode 100644 index 00000000000..d49e05a5416 --- /dev/null +++ b/homeassistant/components/hipchat/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hipchat", + "name": "Hipchat", + "documentation": "https://www.home-assistant.io/components/hipchat", + "requirements": [ + "hipnotify==1.0.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/history/manifest.json b/homeassistant/components/history/manifest.json new file mode 100644 index 00000000000..e0989958626 --- /dev/null +++ b/homeassistant/components/history/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "history", + "name": "History", + "documentation": "https://www.home-assistant.io/components/history", + "requirements": [], + "dependencies": [ + "http", + "recorder" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/history_graph/manifest.json b/homeassistant/components/history_graph/manifest.json new file mode 100644 index 00000000000..fa0d437a700 --- /dev/null +++ b/homeassistant/components/history_graph/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "history_graph", + "name": "History graph", + "documentation": "https://www.home-assistant.io/components/history_graph", + "requirements": [], + "dependencies": [ + "history" + ], + "codeowners": [ + "@andrey-git" + ] +} diff --git a/homeassistant/components/history_stats/manifest.json b/homeassistant/components/history_stats/manifest.json new file mode 100644 index 00000000000..8e0c1b24910 --- /dev/null +++ b/homeassistant/components/history_stats/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "history_stats", + "name": "History stats", + "documentation": "https://www.home-assistant.io/components/history_stats", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hitron_coda/manifest.json b/homeassistant/components/hitron_coda/manifest.json new file mode 100644 index 00000000000..9f3c20fcca5 --- /dev/null +++ b/homeassistant/components/hitron_coda/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "hitron_coda", + "name": "Hitron coda", + "documentation": "https://www.home-assistant.io/components/hitron_coda", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hive/manifest.json b/homeassistant/components/hive/manifest.json new file mode 100644 index 00000000000..76403f293ac --- /dev/null +++ b/homeassistant/components/hive/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "hive", + "name": "Hive", + "documentation": "https://www.home-assistant.io/components/hive", + "requirements": [ + "pyhiveapi==0.2.17" + ], + "dependencies": [], + "codeowners": [ + "@Rendili", + "@KJonline" + ] +} diff --git a/homeassistant/components/hlk_sw16/manifest.json b/homeassistant/components/hlk_sw16/manifest.json new file mode 100644 index 00000000000..5266b81ab03 --- /dev/null +++ b/homeassistant/components/hlk_sw16/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hlk_sw16", + "name": "Hlk sw16", + "documentation": "https://www.home-assistant.io/components/hlk_sw16", + "requirements": [ + "hlk-sw16==0.0.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/homeassistant/manifest.json b/homeassistant/components/homeassistant/manifest.json new file mode 100644 index 00000000000..b612c3a9fa6 --- /dev/null +++ b/homeassistant/components/homeassistant/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "homeassistant", + "name": "Home Assistant Core Integration", + "documentation": "https://www.home-assistant.io/components/homeassistant", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/homekit/manifest.json b/homeassistant/components/homekit/manifest.json new file mode 100644 index 00000000000..fd781f206d1 --- /dev/null +++ b/homeassistant/components/homekit/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "homekit", + "name": "Homekit", + "documentation": "https://www.home-assistant.io/components/homekit", + "requirements": [ + "HAP-python==2.4.2" + ], + "dependencies": [], + "codeowners": [ + "@cdce8p" + ] +} diff --git a/homeassistant/components/homekit_controller/manifest.json b/homeassistant/components/homekit_controller/manifest.json new file mode 100644 index 00000000000..e641f87e2a3 --- /dev/null +++ b/homeassistant/components/homekit_controller/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "homekit_controller", + "name": "Homekit controller", + "documentation": "https://www.home-assistant.io/components/homekit_controller", + "requirements": [ + "homekit[IP]==0.13.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/homematic/manifest.json b/homeassistant/components/homematic/manifest.json new file mode 100644 index 00000000000..cba29992f23 --- /dev/null +++ b/homeassistant/components/homematic/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "homematic", + "name": "Homematic", + "documentation": "https://www.home-assistant.io/components/homematic", + "requirements": [ + "pyhomematic==0.1.58" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/homematicip_cloud/manifest.json b/homeassistant/components/homematicip_cloud/manifest.json new file mode 100644 index 00000000000..622928e8629 --- /dev/null +++ b/homeassistant/components/homematicip_cloud/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "homematicip_cloud", + "name": "Homematicip cloud", + "documentation": "https://www.home-assistant.io/components/homematicip_cloud", + "requirements": [ + "homematicip==0.10.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/homeworks/manifest.json b/homeassistant/components/homeworks/manifest.json new file mode 100644 index 00000000000..cdbbffb8d36 --- /dev/null +++ b/homeassistant/components/homeworks/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "homeworks", + "name": "Homeworks", + "documentation": "https://www.home-assistant.io/components/homeworks", + "requirements": [ + "pyhomeworks==0.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/honeywell/manifest.json b/homeassistant/components/honeywell/manifest.json new file mode 100644 index 00000000000..c3d76703e91 --- /dev/null +++ b/homeassistant/components/honeywell/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "honeywell", + "name": "Honeywell", + "documentation": "https://www.home-assistant.io/components/honeywell", + "requirements": [ + "evohomeclient==0.3.2", + "somecomfort==0.5.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hook/manifest.json b/homeassistant/components/hook/manifest.json new file mode 100644 index 00000000000..d9898a71f8b --- /dev/null +++ b/homeassistant/components/hook/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "hook", + "name": "Hook", + "documentation": "https://www.home-assistant.io/components/hook", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/horizon/manifest.json b/homeassistant/components/horizon/manifest.json new file mode 100644 index 00000000000..2916e81ce4f --- /dev/null +++ b/homeassistant/components/horizon/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "horizon", + "name": "Horizon", + "documentation": "https://www.home-assistant.io/components/horizon", + "requirements": [ + "horimote==0.4.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hp_ilo/manifest.json b/homeassistant/components/hp_ilo/manifest.json new file mode 100644 index 00000000000..3df6632e47a --- /dev/null +++ b/homeassistant/components/hp_ilo/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hp_ilo", + "name": "Hp ilo", + "documentation": "https://www.home-assistant.io/components/hp_ilo", + "requirements": [ + "python-hpilo==3.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/html5/manifest.json b/homeassistant/components/html5/manifest.json new file mode 100644 index 00000000000..98b2834be7f --- /dev/null +++ b/homeassistant/components/html5/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "html5", + "name": "HTML5 Notifications", + "documentation": "https://www.home-assistant.io/components/html5", + "requirements": [ + "pywebpush==1.6.0" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/http/manifest.json b/homeassistant/components/http/manifest.json new file mode 100644 index 00000000000..0bc5586445d --- /dev/null +++ b/homeassistant/components/http/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "http", + "name": "HTTP", + "documentation": "https://www.home-assistant.io/components/http", + "requirements": [ + "aiohttp_cors==0.7.0" + ], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/htu21d/manifest.json b/homeassistant/components/htu21d/manifest.json new file mode 100644 index 00000000000..70093df9b55 --- /dev/null +++ b/homeassistant/components/htu21d/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "htu21d", + "name": "Htu21d", + "documentation": "https://www.home-assistant.io/components/htu21d", + "requirements": [ + "i2csense==0.0.4", + "smbus-cffi==0.5.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/huawei_lte/manifest.json b/homeassistant/components/huawei_lte/manifest.json new file mode 100644 index 00000000000..2e096343b09 --- /dev/null +++ b/homeassistant/components/huawei_lte/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "huawei_lte", + "name": "Huawei lte", + "documentation": "https://www.home-assistant.io/components/huawei_lte", + "requirements": [ + "huawei-lte-api==1.1.5" + ], + "dependencies": [], + "codeowners": [ + "@scop" + ] +} diff --git a/homeassistant/components/huawei_router/manifest.json b/homeassistant/components/huawei_router/manifest.json new file mode 100644 index 00000000000..54fd155b557 --- /dev/null +++ b/homeassistant/components/huawei_router/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "huawei_router", + "name": "Huawei router", + "documentation": "https://www.home-assistant.io/components/huawei_router", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@abmantis" + ] +} diff --git a/homeassistant/components/hue/manifest.json b/homeassistant/components/hue/manifest.json new file mode 100644 index 00000000000..54a3a11a189 --- /dev/null +++ b/homeassistant/components/hue/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "hue", + "name": "Philips Hue", + "documentation": "https://www.home-assistant.io/components/hue", + "requirements": [ + "aiohue==1.9.1" + ], + "dependencies": [], + "codeowners": [ + "@balloob" + ] +} diff --git a/homeassistant/components/hunterdouglas_powerview/manifest.json b/homeassistant/components/hunterdouglas_powerview/manifest.json new file mode 100644 index 00000000000..c4e1bcc28e8 --- /dev/null +++ b/homeassistant/components/hunterdouglas_powerview/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hunterdouglas_powerview", + "name": "Hunterdouglas powerview", + "documentation": "https://www.home-assistant.io/components/hunterdouglas_powerview", + "requirements": [ + "aiopvapi==1.6.14" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hydrawise/manifest.json b/homeassistant/components/hydrawise/manifest.json new file mode 100644 index 00000000000..6d332a28bcc --- /dev/null +++ b/homeassistant/components/hydrawise/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hydrawise", + "name": "Hydrawise", + "documentation": "https://www.home-assistant.io/components/hydrawise", + "requirements": [ + "hydrawiser==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hydroquebec/manifest.json b/homeassistant/components/hydroquebec/manifest.json new file mode 100644 index 00000000000..efea5ce0f2e --- /dev/null +++ b/homeassistant/components/hydroquebec/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "hydroquebec", + "name": "Hydroquebec", + "documentation": "https://www.home-assistant.io/components/hydroquebec", + "requirements": [ + "pyhydroquebec==2.2.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/hyperion/manifest.json b/homeassistant/components/hyperion/manifest.json new file mode 100644 index 00000000000..980c227944a --- /dev/null +++ b/homeassistant/components/hyperion/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "hyperion", + "name": "Hyperion", + "documentation": "https://www.home-assistant.io/components/hyperion", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ialarm/manifest.json b/homeassistant/components/ialarm/manifest.json new file mode 100644 index 00000000000..df492d136fd --- /dev/null +++ b/homeassistant/components/ialarm/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ialarm", + "name": "Ialarm", + "documentation": "https://www.home-assistant.io/components/ialarm", + "requirements": [ + "pyialarm==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/icloud/manifest.json b/homeassistant/components/icloud/manifest.json new file mode 100644 index 00000000000..865d64c6860 --- /dev/null +++ b/homeassistant/components/icloud/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "icloud", + "name": "Icloud", + "documentation": "https://www.home-assistant.io/components/icloud", + "requirements": [ + "pyicloud==0.9.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/idteck_prox/manifest.json b/homeassistant/components/idteck_prox/manifest.json new file mode 100644 index 00000000000..8df144a0f81 --- /dev/null +++ b/homeassistant/components/idteck_prox/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "idteck_prox", + "name": "Idteck prox", + "documentation": "https://www.home-assistant.io/components/idteck_prox", + "requirements": [ + "rfk101py==0.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ifttt/manifest.json b/homeassistant/components/ifttt/manifest.json new file mode 100644 index 00000000000..007e0870023 --- /dev/null +++ b/homeassistant/components/ifttt/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "ifttt", + "name": "Ifttt", + "documentation": "https://www.home-assistant.io/components/ifttt", + "requirements": [ + "pyfttt==0.3" + ], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/iglo/manifest.json b/homeassistant/components/iglo/manifest.json new file mode 100644 index 00000000000..4d84c27cd93 --- /dev/null +++ b/homeassistant/components/iglo/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "iglo", + "name": "Iglo", + "documentation": "https://www.home-assistant.io/components/iglo", + "requirements": [ + "iglo==1.2.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ihc/manifest.json b/homeassistant/components/ihc/manifest.json new file mode 100644 index 00000000000..bbcd4ab9389 --- /dev/null +++ b/homeassistant/components/ihc/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "ihc", + "name": "Ihc", + "documentation": "https://www.home-assistant.io/components/ihc", + "requirements": [ + "defusedxml==0.5.0", + "ihcsdk==2.3.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/image_processing/manifest.json b/homeassistant/components/image_processing/manifest.json new file mode 100644 index 00000000000..e675d18a00b --- /dev/null +++ b/homeassistant/components/image_processing/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "image_processing", + "name": "Image processing", + "documentation": "https://www.home-assistant.io/components/image_processing", + "requirements": [], + "dependencies": [ + "camera" + ], + "codeowners": [] +} diff --git a/homeassistant/components/imap/manifest.json b/homeassistant/components/imap/manifest.json new file mode 100644 index 00000000000..9e0f387a7a6 --- /dev/null +++ b/homeassistant/components/imap/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "imap", + "name": "Imap", + "documentation": "https://www.home-assistant.io/components/imap", + "requirements": [ + "aioimaplib==0.7.15" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/imap_email_content/manifest.json b/homeassistant/components/imap_email_content/manifest.json new file mode 100644 index 00000000000..a1e2c616832 --- /dev/null +++ b/homeassistant/components/imap_email_content/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "imap_email_content", + "name": "Imap email content", + "documentation": "https://www.home-assistant.io/components/imap_email_content", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/influxdb/manifest.json b/homeassistant/components/influxdb/manifest.json new file mode 100644 index 00000000000..20652ddd046 --- /dev/null +++ b/homeassistant/components/influxdb/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "influxdb", + "name": "Influxdb", + "documentation": "https://www.home-assistant.io/components/influxdb", + "requirements": [ + "influxdb==5.2.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/input_boolean/manifest.json b/homeassistant/components/input_boolean/manifest.json new file mode 100644 index 00000000000..e233b5635fc --- /dev/null +++ b/homeassistant/components/input_boolean/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "input_boolean", + "name": "Input boolean", + "documentation": "https://www.home-assistant.io/components/input_boolean", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/input_datetime/manifest.json b/homeassistant/components/input_datetime/manifest.json new file mode 100644 index 00000000000..287777e2ccf --- /dev/null +++ b/homeassistant/components/input_datetime/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "input_datetime", + "name": "Input datetime", + "documentation": "https://www.home-assistant.io/components/input_datetime", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/input_number/manifest.json b/homeassistant/components/input_number/manifest.json new file mode 100644 index 00000000000..2015b8ea734 --- /dev/null +++ b/homeassistant/components/input_number/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "input_number", + "name": "Input number", + "documentation": "https://www.home-assistant.io/components/input_number", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/input_select/manifest.json b/homeassistant/components/input_select/manifest.json new file mode 100644 index 00000000000..a71fb53a5d1 --- /dev/null +++ b/homeassistant/components/input_select/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "input_select", + "name": "Input select", + "documentation": "https://www.home-assistant.io/components/input_select", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/input_text/manifest.json b/homeassistant/components/input_text/manifest.json new file mode 100644 index 00000000000..6362e679319 --- /dev/null +++ b/homeassistant/components/input_text/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "input_text", + "name": "Input text", + "documentation": "https://www.home-assistant.io/components/input_text", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/insteon/manifest.json b/homeassistant/components/insteon/manifest.json new file mode 100644 index 00000000000..7ba27cbe625 --- /dev/null +++ b/homeassistant/components/insteon/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "insteon", + "name": "Insteon", + "documentation": "https://www.home-assistant.io/components/insteon", + "requirements": [ + "insteonplm==0.15.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/insteon_local/manifest.json b/homeassistant/components/insteon_local/manifest.json new file mode 100644 index 00000000000..64b6bccdba6 --- /dev/null +++ b/homeassistant/components/insteon_local/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "insteon_local", + "name": "Insteon local", + "documentation": "https://www.home-assistant.io/components/insteon_local", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/insteon_plm/manifest.json b/homeassistant/components/insteon_plm/manifest.json new file mode 100644 index 00000000000..fa382dd2df0 --- /dev/null +++ b/homeassistant/components/insteon_plm/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "insteon_plm", + "name": "Insteon plm", + "documentation": "https://www.home-assistant.io/components/insteon_plm", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/integration/manifest.json b/homeassistant/components/integration/manifest.json new file mode 100644 index 00000000000..869ad2766f9 --- /dev/null +++ b/homeassistant/components/integration/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "integration", + "name": "Integration", + "documentation": "https://www.home-assistant.io/components/integration", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@dgomes" + ] +} diff --git a/homeassistant/components/intent_script/manifest.json b/homeassistant/components/intent_script/manifest.json new file mode 100644 index 00000000000..891be6b2180 --- /dev/null +++ b/homeassistant/components/intent_script/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "intent_script", + "name": "Intent script", + "documentation": "https://www.home-assistant.io/components/intent_script", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/introduction/manifest.json b/homeassistant/components/introduction/manifest.json new file mode 100644 index 00000000000..4caa31e34e6 --- /dev/null +++ b/homeassistant/components/introduction/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "introduction", + "name": "Introduction", + "documentation": "https://www.home-assistant.io/components/introduction", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/ios/manifest.json b/homeassistant/components/ios/manifest.json new file mode 100644 index 00000000000..97c2e2ae28f --- /dev/null +++ b/homeassistant/components/ios/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "ios", + "name": "Ios", + "documentation": "https://www.home-assistant.io/components/ios", + "requirements": [], + "dependencies": [ + "device_tracker", + "http", + "zeroconf" + ], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/iota/manifest.json b/homeassistant/components/iota/manifest.json new file mode 100644 index 00000000000..d83defbbec3 --- /dev/null +++ b/homeassistant/components/iota/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "iota", + "name": "Iota", + "documentation": "https://www.home-assistant.io/components/iota", + "requirements": [ + "pyota==2.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/iperf3/manifest.json b/homeassistant/components/iperf3/manifest.json new file mode 100644 index 00000000000..e35be24fc80 --- /dev/null +++ b/homeassistant/components/iperf3/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "iperf3", + "name": "Iperf3", + "documentation": "https://www.home-assistant.io/components/iperf3", + "requirements": [ + "iperf3==0.1.10" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ipma/manifest.json b/homeassistant/components/ipma/manifest.json new file mode 100644 index 00000000000..29fc0429e86 --- /dev/null +++ b/homeassistant/components/ipma/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "ipma", + "name": "Ipma", + "documentation": "https://www.home-assistant.io/components/ipma", + "requirements": [ + "pyipma==1.2.1" + ], + "dependencies": [], + "codeowners": [ + "@dgomes" + ] +} diff --git a/homeassistant/components/irish_rail_transport/manifest.json b/homeassistant/components/irish_rail_transport/manifest.json new file mode 100644 index 00000000000..5961400e68e --- /dev/null +++ b/homeassistant/components/irish_rail_transport/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "irish_rail_transport", + "name": "Irish rail transport", + "documentation": "https://www.home-assistant.io/components/irish_rail_transport", + "requirements": [ + "pyirishrail==0.0.2" + ], + "dependencies": [], + "codeowners": [ + "@ttroy50" + ] +} diff --git a/homeassistant/components/islamic_prayer_times/manifest.json b/homeassistant/components/islamic_prayer_times/manifest.json new file mode 100644 index 00000000000..4dc9e2cb7c3 --- /dev/null +++ b/homeassistant/components/islamic_prayer_times/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "islamic_prayer_times", + "name": "Islamic prayer times", + "documentation": "https://www.home-assistant.io/components/islamic_prayer_times", + "requirements": [ + "prayer_times_calculator==0.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/iss/manifest.json b/homeassistant/components/iss/manifest.json new file mode 100644 index 00000000000..dc71e81ac08 --- /dev/null +++ b/homeassistant/components/iss/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "iss", + "name": "Iss", + "documentation": "https://www.home-assistant.io/components/iss", + "requirements": [ + "pyiss==1.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/isy994/manifest.json b/homeassistant/components/isy994/manifest.json new file mode 100644 index 00000000000..7860c080b2f --- /dev/null +++ b/homeassistant/components/isy994/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "isy994", + "name": "Isy994", + "documentation": "https://www.home-assistant.io/components/isy994", + "requirements": [ + "PyISY==1.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/itach/manifest.json b/homeassistant/components/itach/manifest.json new file mode 100644 index 00000000000..c26b19c636e --- /dev/null +++ b/homeassistant/components/itach/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "itach", + "name": "Itach", + "documentation": "https://www.home-assistant.io/components/itach", + "requirements": [ + "pyitachip2ir==0.0.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/itunes/manifest.json b/homeassistant/components/itunes/manifest.json new file mode 100644 index 00000000000..6f05125661e --- /dev/null +++ b/homeassistant/components/itunes/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "itunes", + "name": "Itunes", + "documentation": "https://www.home-assistant.io/components/itunes", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/jewish_calendar/manifest.json b/homeassistant/components/jewish_calendar/manifest.json new file mode 100644 index 00000000000..1f2917865b3 --- /dev/null +++ b/homeassistant/components/jewish_calendar/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "jewish_calendar", + "name": "Jewish calendar", + "documentation": "https://www.home-assistant.io/components/jewish_calendar", + "requirements": [ + "hdate==0.8.7" + ], + "dependencies": [], + "codeowners": [ + "@tsvi" + ] +} diff --git a/homeassistant/components/joaoapps_join/manifest.json b/homeassistant/components/joaoapps_join/manifest.json new file mode 100644 index 00000000000..220f2af2035 --- /dev/null +++ b/homeassistant/components/joaoapps_join/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "joaoapps_join", + "name": "Joaoapps join", + "documentation": "https://www.home-assistant.io/components/joaoapps_join", + "requirements": [ + "python-join-api==0.0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/juicenet/manifest.json b/homeassistant/components/juicenet/manifest.json new file mode 100644 index 00000000000..e65aab2b69d --- /dev/null +++ b/homeassistant/components/juicenet/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "juicenet", + "name": "Juicenet", + "documentation": "https://www.home-assistant.io/components/juicenet", + "requirements": [ + "python-juicenet==0.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/kankun/manifest.json b/homeassistant/components/kankun/manifest.json new file mode 100644 index 00000000000..8e4e9747901 --- /dev/null +++ b/homeassistant/components/kankun/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "kankun", + "name": "Kankun", + "documentation": "https://www.home-assistant.io/components/kankun", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/keenetic_ndms2/manifest.json b/homeassistant/components/keenetic_ndms2/manifest.json new file mode 100644 index 00000000000..d95e6384606 --- /dev/null +++ b/homeassistant/components/keenetic_ndms2/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "keenetic_ndms2", + "name": "Keenetic ndms2", + "documentation": "https://www.home-assistant.io/components/keenetic_ndms2", + "requirements": [ + "ndms2_client==0.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/keyboard/manifest.json b/homeassistant/components/keyboard/manifest.json new file mode 100644 index 00000000000..0e8ade339c2 --- /dev/null +++ b/homeassistant/components/keyboard/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "keyboard", + "name": "Keyboard", + "documentation": "https://www.home-assistant.io/components/keyboard", + "requirements": [ + "pyuserinput==0.1.11" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/keyboard_remote/manifest.json b/homeassistant/components/keyboard_remote/manifest.json new file mode 100644 index 00000000000..d87d1abca48 --- /dev/null +++ b/homeassistant/components/keyboard_remote/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "keyboard_remote", + "name": "Keyboard remote", + "documentation": "https://www.home-assistant.io/components/keyboard_remote", + "requirements": [ + "evdev==0.6.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/kira/manifest.json b/homeassistant/components/kira/manifest.json new file mode 100644 index 00000000000..b7edd1f6c5f --- /dev/null +++ b/homeassistant/components/kira/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "kira", + "name": "Kira", + "documentation": "https://www.home-assistant.io/components/kira", + "requirements": [ + "pykira==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/kiwi/manifest.json b/homeassistant/components/kiwi/manifest.json new file mode 100644 index 00000000000..9f1595ebd77 --- /dev/null +++ b/homeassistant/components/kiwi/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "kiwi", + "name": "Kiwi", + "documentation": "https://www.home-assistant.io/components/kiwi", + "requirements": [ + "kiwiki-client==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/knx/manifest.json b/homeassistant/components/knx/manifest.json new file mode 100644 index 00000000000..1b1f16ccb03 --- /dev/null +++ b/homeassistant/components/knx/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "knx", + "name": "Knx", + "documentation": "https://www.home-assistant.io/components/knx", + "requirements": [ + "xknx==0.10.0" + ], + "dependencies": [], + "codeowners": [ + "@Julius2342" + ] +} diff --git a/homeassistant/components/kodi/manifest.json b/homeassistant/components/kodi/manifest.json new file mode 100644 index 00000000000..8c684d495e9 --- /dev/null +++ b/homeassistant/components/kodi/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "kodi", + "name": "Kodi", + "documentation": "https://www.home-assistant.io/components/kodi", + "requirements": [ + "jsonrpc-async==0.6", + "jsonrpc-websocket==0.6" + ], + "dependencies": [], + "codeowners": [ + "@armills" + ] +} diff --git a/homeassistant/components/konnected/manifest.json b/homeassistant/components/konnected/manifest.json new file mode 100644 index 00000000000..e4129af39bd --- /dev/null +++ b/homeassistant/components/konnected/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "konnected", + "name": "Konnected", + "documentation": "https://www.home-assistant.io/components/konnected", + "requirements": [ + "konnected==0.1.5" + ], + "dependencies": [ + "http" + ], + "codeowners": [ + "@heythisisnate" + ] +} diff --git a/homeassistant/components/kwb/manifest.json b/homeassistant/components/kwb/manifest.json new file mode 100644 index 00000000000..783907c0220 --- /dev/null +++ b/homeassistant/components/kwb/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "kwb", + "name": "Kwb", + "documentation": "https://www.home-assistant.io/components/kwb", + "requirements": [ + "pykwb==0.0.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lacrosse/manifest.json b/homeassistant/components/lacrosse/manifest.json new file mode 100644 index 00000000000..4716b3cb548 --- /dev/null +++ b/homeassistant/components/lacrosse/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lacrosse", + "name": "Lacrosse", + "documentation": "https://www.home-assistant.io/components/lacrosse", + "requirements": [ + "pylacrosse==0.3.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lametric/manifest.json b/homeassistant/components/lametric/manifest.json new file mode 100644 index 00000000000..bbf22918a75 --- /dev/null +++ b/homeassistant/components/lametric/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "lametric", + "name": "Lametric", + "documentation": "https://www.home-assistant.io/components/lametric", + "requirements": [ + "lmnotify==0.0.4" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/lannouncer/manifest.json b/homeassistant/components/lannouncer/manifest.json new file mode 100644 index 00000000000..951dd3ff85b --- /dev/null +++ b/homeassistant/components/lannouncer/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "lannouncer", + "name": "Lannouncer", + "documentation": "https://www.home-assistant.io/components/lannouncer", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lastfm/manifest.json b/homeassistant/components/lastfm/manifest.json new file mode 100644 index 00000000000..2617b3e206b --- /dev/null +++ b/homeassistant/components/lastfm/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lastfm", + "name": "Lastfm", + "documentation": "https://www.home-assistant.io/components/lastfm", + "requirements": [ + "pylast==3.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/launch_library/manifest.json b/homeassistant/components/launch_library/manifest.json new file mode 100644 index 00000000000..bbe9fa8ad05 --- /dev/null +++ b/homeassistant/components/launch_library/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "launch_library", + "name": "Launch library", + "documentation": "https://www.home-assistant.io/components/launch_library", + "requirements": [ + "pylaunches==0.2.0" + ], + "dependencies": [], + "codeowners": [ + "@ludeeus" + ] +} diff --git a/homeassistant/components/lcn/manifest.json b/homeassistant/components/lcn/manifest.json new file mode 100644 index 00000000000..bbf2746c067 --- /dev/null +++ b/homeassistant/components/lcn/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lcn", + "name": "Lcn", + "documentation": "https://www.home-assistant.io/components/lcn", + "requirements": [ + "pypck==0.5.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lg_netcast/manifest.json b/homeassistant/components/lg_netcast/manifest.json new file mode 100644 index 00000000000..1728aa50614 --- /dev/null +++ b/homeassistant/components/lg_netcast/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lg_netcast", + "name": "Lg netcast", + "documentation": "https://www.home-assistant.io/components/lg_netcast", + "requirements": [ + "pylgnetcast-homeassistant==0.2.0.dev0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lg_soundbar/manifest.json b/homeassistant/components/lg_soundbar/manifest.json new file mode 100644 index 00000000000..b09c8809382 --- /dev/null +++ b/homeassistant/components/lg_soundbar/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lg_soundbar", + "name": "Lg soundbar", + "documentation": "https://www.home-assistant.io/components/lg_soundbar", + "requirements": [ + "temescal==0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lifx/manifest.json b/homeassistant/components/lifx/manifest.json new file mode 100644 index 00000000000..6b811b01f51 --- /dev/null +++ b/homeassistant/components/lifx/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "lifx", + "name": "Lifx", + "documentation": "https://www.home-assistant.io/components/lifx", + "requirements": [ + "aiolifx==0.6.7", + "aiolifx_effects==0.2.1" + ], + "dependencies": [], + "codeowners": [ + "@amelchio" + ] +} diff --git a/homeassistant/components/lifx_cloud/manifest.json b/homeassistant/components/lifx_cloud/manifest.json new file mode 100644 index 00000000000..c2834fbc788 --- /dev/null +++ b/homeassistant/components/lifx_cloud/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lifx_cloud", + "name": "Lifx cloud", + "documentation": "https://www.home-assistant.io/components/lifx_cloud", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@amelchio" + ] +} diff --git a/homeassistant/components/lifx_legacy/manifest.json b/homeassistant/components/lifx_legacy/manifest.json new file mode 100644 index 00000000000..4ff59ac1770 --- /dev/null +++ b/homeassistant/components/lifx_legacy/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "lifx_legacy", + "name": "Lifx legacy", + "documentation": "https://www.home-assistant.io/components/lifx_legacy", + "requirements": [ + "liffylights==0.9.4" + ], + "dependencies": [], + "codeowners": [ + "@amelchio" + ] +} diff --git a/homeassistant/components/light/manifest.json b/homeassistant/components/light/manifest.json new file mode 100644 index 00000000000..62eb96967f5 --- /dev/null +++ b/homeassistant/components/light/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "light", + "name": "Light", + "documentation": "https://www.home-assistant.io/components/light", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [] +} diff --git a/homeassistant/components/lightwave/manifest.json b/homeassistant/components/lightwave/manifest.json new file mode 100644 index 00000000000..a26500f69a6 --- /dev/null +++ b/homeassistant/components/lightwave/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lightwave", + "name": "Lightwave", + "documentation": "https://www.home-assistant.io/components/lightwave", + "requirements": [ + "lightwave==0.15" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/limitlessled/manifest.json b/homeassistant/components/limitlessled/manifest.json new file mode 100644 index 00000000000..f8b42fabcbe --- /dev/null +++ b/homeassistant/components/limitlessled/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "limitlessled", + "name": "Limitlessled", + "documentation": "https://www.home-assistant.io/components/limitlessled", + "requirements": [ + "limitlessled==1.1.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/linksys_ap/manifest.json b/homeassistant/components/linksys_ap/manifest.json new file mode 100644 index 00000000000..ccad7298d6b --- /dev/null +++ b/homeassistant/components/linksys_ap/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "linksys_ap", + "name": "Linksys ap", + "documentation": "https://www.home-assistant.io/components/linksys_ap", + "requirements": [ + "beautifulsoup4==4.7.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/linksys_smart/manifest.json b/homeassistant/components/linksys_smart/manifest.json new file mode 100644 index 00000000000..19bb079c29c --- /dev/null +++ b/homeassistant/components/linksys_smart/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "linksys_smart", + "name": "Linksys smart", + "documentation": "https://www.home-assistant.io/components/linksys_smart", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/linky/manifest.json b/homeassistant/components/linky/manifest.json new file mode 100644 index 00000000000..706962b5c4d --- /dev/null +++ b/homeassistant/components/linky/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "linky", + "name": "Linky", + "documentation": "https://www.home-assistant.io/components/linky", + "requirements": [ + "pylinky==0.3.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/linode/manifest.json b/homeassistant/components/linode/manifest.json new file mode 100644 index 00000000000..7dc2e0d7518 --- /dev/null +++ b/homeassistant/components/linode/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "linode", + "name": "Linode", + "documentation": "https://www.home-assistant.io/components/linode", + "requirements": [ + "linode-api==4.1.9b1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/linux_battery/manifest.json b/homeassistant/components/linux_battery/manifest.json new file mode 100644 index 00000000000..4c32b88b2d5 --- /dev/null +++ b/homeassistant/components/linux_battery/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "linux_battery", + "name": "Linux battery", + "documentation": "https://www.home-assistant.io/components/linux_battery", + "requirements": [ + "batinfo==0.4.2" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/lirc/manifest.json b/homeassistant/components/lirc/manifest.json new file mode 100644 index 00000000000..d11cf0b2f1e --- /dev/null +++ b/homeassistant/components/lirc/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lirc", + "name": "Lirc", + "documentation": "https://www.home-assistant.io/components/lirc", + "requirements": [ + "python-lirc==1.2.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/litejet/manifest.json b/homeassistant/components/litejet/manifest.json new file mode 100644 index 00000000000..08bcac67903 --- /dev/null +++ b/homeassistant/components/litejet/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "litejet", + "name": "Litejet", + "documentation": "https://www.home-assistant.io/components/litejet", + "requirements": [ + "pylitejet==0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/liveboxplaytv/manifest.json b/homeassistant/components/liveboxplaytv/manifest.json new file mode 100644 index 00000000000..863507ada6c --- /dev/null +++ b/homeassistant/components/liveboxplaytv/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "liveboxplaytv", + "name": "Liveboxplaytv", + "documentation": "https://www.home-assistant.io/components/liveboxplaytv", + "requirements": [ + "liveboxplaytv==2.0.2", + "pyteleloisirs==3.4" + ], + "dependencies": [], + "codeowners": [ + "@pschmitt" + ] +} diff --git a/homeassistant/components/llamalab_automate/manifest.json b/homeassistant/components/llamalab_automate/manifest.json new file mode 100644 index 00000000000..e66050fceb5 --- /dev/null +++ b/homeassistant/components/llamalab_automate/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "llamalab_automate", + "name": "Llamalab automate", + "documentation": "https://www.home-assistant.io/components/llamalab_automate", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/local_file/manifest.json b/homeassistant/components/local_file/manifest.json new file mode 100644 index 00000000000..14a503f33f5 --- /dev/null +++ b/homeassistant/components/local_file/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "local_file", + "name": "Local file", + "documentation": "https://www.home-assistant.io/components/local_file", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/locative/manifest.json b/homeassistant/components/locative/manifest.json new file mode 100644 index 00000000000..afe2850caf8 --- /dev/null +++ b/homeassistant/components/locative/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "locative", + "name": "Locative", + "documentation": "https://www.home-assistant.io/components/locative", + "requirements": [], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/lock/manifest.json b/homeassistant/components/lock/manifest.json new file mode 100644 index 00000000000..29a7a5513d0 --- /dev/null +++ b/homeassistant/components/lock/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lock", + "name": "Lock", + "documentation": "https://www.home-assistant.io/components/lock", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [] +} diff --git a/homeassistant/components/lockitron/manifest.json b/homeassistant/components/lockitron/manifest.json new file mode 100644 index 00000000000..b515d65a14f --- /dev/null +++ b/homeassistant/components/lockitron/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "lockitron", + "name": "Lockitron", + "documentation": "https://www.home-assistant.io/components/lockitron", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/logbook/manifest.json b/homeassistant/components/logbook/manifest.json new file mode 100644 index 00000000000..cedce8152a2 --- /dev/null +++ b/homeassistant/components/logbook/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "logbook", + "name": "Logbook", + "documentation": "https://www.home-assistant.io/components/logbook", + "requirements": [], + "dependencies": [ + "frontend", + "recorder" + ], + "codeowners": [] +} diff --git a/homeassistant/components/logentries/manifest.json b/homeassistant/components/logentries/manifest.json new file mode 100644 index 00000000000..60be8f275ee --- /dev/null +++ b/homeassistant/components/logentries/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "logentries", + "name": "Logentries", + "documentation": "https://www.home-assistant.io/components/logentries", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/logger/manifest.json b/homeassistant/components/logger/manifest.json new file mode 100644 index 00000000000..c6b62387039 --- /dev/null +++ b/homeassistant/components/logger/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "logger", + "name": "Logger", + "documentation": "https://www.home-assistant.io/components/logger", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/logi_circle/manifest.json b/homeassistant/components/logi_circle/manifest.json new file mode 100644 index 00000000000..3e8281d5a9c --- /dev/null +++ b/homeassistant/components/logi_circle/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "logi_circle", + "name": "Logi circle", + "documentation": "https://www.home-assistant.io/components/logi_circle", + "requirements": [ + "logi_circle==0.1.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/london_air/manifest.json b/homeassistant/components/london_air/manifest.json new file mode 100644 index 00000000000..3f0c97edfe0 --- /dev/null +++ b/homeassistant/components/london_air/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "london_air", + "name": "London air", + "documentation": "https://www.home-assistant.io/components/london_air", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/london_underground/manifest.json b/homeassistant/components/london_underground/manifest.json new file mode 100644 index 00000000000..5262fa4837e --- /dev/null +++ b/homeassistant/components/london_underground/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "london_underground", + "name": "London underground", + "documentation": "https://www.home-assistant.io/components/london_underground", + "requirements": [ + "london-tube-status==0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/loopenergy/manifest.json b/homeassistant/components/loopenergy/manifest.json new file mode 100644 index 00000000000..b282755b1a0 --- /dev/null +++ b/homeassistant/components/loopenergy/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "loopenergy", + "name": "Loopenergy", + "documentation": "https://www.home-assistant.io/components/loopenergy", + "requirements": [ + "pyloopenergy==0.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lovelace/manifest.json b/homeassistant/components/lovelace/manifest.json new file mode 100644 index 00000000000..1c1a7a107e4 --- /dev/null +++ b/homeassistant/components/lovelace/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lovelace", + "name": "Lovelace", + "documentation": "https://www.home-assistant.io/components/lovelace", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/luci/manifest.json b/homeassistant/components/luci/manifest.json new file mode 100644 index 00000000000..46e1702c36e --- /dev/null +++ b/homeassistant/components/luci/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "luci", + "name": "Luci", + "documentation": "https://www.home-assistant.io/components/luci", + "requirements": [ + "openwrt-luci-rpc==1.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/luftdaten/manifest.json b/homeassistant/components/luftdaten/manifest.json new file mode 100644 index 00000000000..0e6a46a5c5d --- /dev/null +++ b/homeassistant/components/luftdaten/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "luftdaten", + "name": "Luftdaten", + "documentation": "https://www.home-assistant.io/components/luftdaten", + "requirements": [ + "luftdaten==0.3.4" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/lupusec/manifest.json b/homeassistant/components/lupusec/manifest.json new file mode 100644 index 00000000000..344ec82d976 --- /dev/null +++ b/homeassistant/components/lupusec/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lupusec", + "name": "Lupusec", + "documentation": "https://www.home-assistant.io/components/lupusec", + "requirements": [ + "lupupy==0.0.17" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lutron/manifest.json b/homeassistant/components/lutron/manifest.json new file mode 100644 index 00000000000..b536eef0285 --- /dev/null +++ b/homeassistant/components/lutron/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lutron", + "name": "Lutron", + "documentation": "https://www.home-assistant.io/components/lutron", + "requirements": [ + "pylutron==0.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lutron_caseta/manifest.json b/homeassistant/components/lutron_caseta/manifest.json new file mode 100644 index 00000000000..4da58cdfc40 --- /dev/null +++ b/homeassistant/components/lutron_caseta/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lutron_caseta", + "name": "Lutron caseta", + "documentation": "https://www.home-assistant.io/components/lutron_caseta", + "requirements": [ + "pylutron-caseta==0.5.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lw12wifi/manifest.json b/homeassistant/components/lw12wifi/manifest.json new file mode 100644 index 00000000000..205072055bb --- /dev/null +++ b/homeassistant/components/lw12wifi/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lw12wifi", + "name": "Lw12wifi", + "documentation": "https://www.home-assistant.io/components/lw12wifi", + "requirements": [ + "lw12==0.9.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/lyft/manifest.json b/homeassistant/components/lyft/manifest.json new file mode 100644 index 00000000000..ff7da7190d9 --- /dev/null +++ b/homeassistant/components/lyft/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "lyft", + "name": "Lyft", + "documentation": "https://www.home-assistant.io/components/lyft", + "requirements": [ + "lyft_rides==0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/magicseaweed/manifest.json b/homeassistant/components/magicseaweed/manifest.json new file mode 100644 index 00000000000..6534d927f1b --- /dev/null +++ b/homeassistant/components/magicseaweed/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "magicseaweed", + "name": "Magicseaweed", + "documentation": "https://www.home-assistant.io/components/magicseaweed", + "requirements": [ + "magicseaweed==1.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mailbox/manifest.json b/homeassistant/components/mailbox/manifest.json new file mode 100644 index 00000000000..4ca1db564a4 --- /dev/null +++ b/homeassistant/components/mailbox/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mailbox", + "name": "Mailbox", + "documentation": "https://www.home-assistant.io/components/mailbox", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/mailgun/manifest.json b/homeassistant/components/mailgun/manifest.json new file mode 100644 index 00000000000..2979b391ec2 --- /dev/null +++ b/homeassistant/components/mailgun/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "mailgun", + "name": "Mailgun", + "documentation": "https://www.home-assistant.io/components/mailgun", + "requirements": [ + "pymailgunner==1.4" + ], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/manual/manifest.json b/homeassistant/components/manual/manifest.json new file mode 100644 index 00000000000..6c788971629 --- /dev/null +++ b/homeassistant/components/manual/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "manual", + "name": "Manual", + "documentation": "https://www.home-assistant.io/components/manual", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/manual_mqtt/manifest.json b/homeassistant/components/manual_mqtt/manifest.json new file mode 100644 index 00000000000..cc467ade5c1 --- /dev/null +++ b/homeassistant/components/manual_mqtt/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "manual_mqtt", + "name": "Manual mqtt", + "documentation": "https://www.home-assistant.io/components/manual_mqtt", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/map/manifest.json b/homeassistant/components/map/manifest.json new file mode 100644 index 00000000000..993dfc6577e --- /dev/null +++ b/homeassistant/components/map/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "map", + "name": "Map", + "documentation": "https://www.home-assistant.io/components/map", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/marytts/manifest.json b/homeassistant/components/marytts/manifest.json new file mode 100644 index 00000000000..5316935c442 --- /dev/null +++ b/homeassistant/components/marytts/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "marytts", + "name": "Marytts", + "documentation": "https://www.home-assistant.io/components/marytts", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mastodon/manifest.json b/homeassistant/components/mastodon/manifest.json new file mode 100644 index 00000000000..fd7e023fc91 --- /dev/null +++ b/homeassistant/components/mastodon/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "mastodon", + "name": "Mastodon", + "documentation": "https://www.home-assistant.io/components/mastodon", + "requirements": [ + "Mastodon.py==1.3.1" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/matrix/manifest.json b/homeassistant/components/matrix/manifest.json new file mode 100644 index 00000000000..9ea1a6f0c55 --- /dev/null +++ b/homeassistant/components/matrix/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "matrix", + "name": "Matrix", + "documentation": "https://www.home-assistant.io/components/matrix", + "requirements": [ + "matrix-client==0.2.0" + ], + "dependencies": [], + "codeowners": [ + "@tinloaf" + ] +} diff --git a/homeassistant/components/maxcube/manifest.json b/homeassistant/components/maxcube/manifest.json new file mode 100644 index 00000000000..a28096c5eb7 --- /dev/null +++ b/homeassistant/components/maxcube/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "maxcube", + "name": "Maxcube", + "documentation": "https://www.home-assistant.io/components/maxcube", + "requirements": [ + "maxcube-api==0.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/media_extractor/manifest.json b/homeassistant/components/media_extractor/manifest.json new file mode 100644 index 00000000000..53375f14bfe --- /dev/null +++ b/homeassistant/components/media_extractor/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "media_extractor", + "name": "Media extractor", + "documentation": "https://www.home-assistant.io/components/media_extractor", + "requirements": [ + "youtube_dl==2019.03.18" + ], + "dependencies": [ + "media_player" + ], + "codeowners": [] +} diff --git a/homeassistant/components/media_player/manifest.json b/homeassistant/components/media_player/manifest.json new file mode 100644 index 00000000000..bf6f8fabafa --- /dev/null +++ b/homeassistant/components/media_player/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "media_player", + "name": "Media player", + "documentation": "https://www.home-assistant.io/components/media_player", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/mediaroom/manifest.json b/homeassistant/components/mediaroom/manifest.json new file mode 100644 index 00000000000..134d85fa171 --- /dev/null +++ b/homeassistant/components/mediaroom/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "mediaroom", + "name": "Mediaroom", + "documentation": "https://www.home-assistant.io/components/mediaroom", + "requirements": [ + "pymediaroom==0.6.4" + ], + "dependencies": [], + "codeowners": [ + "@dgomes" + ] +} diff --git a/homeassistant/components/melissa/manifest.json b/homeassistant/components/melissa/manifest.json new file mode 100644 index 00000000000..f9fa1cab502 --- /dev/null +++ b/homeassistant/components/melissa/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "melissa", + "name": "Melissa", + "documentation": "https://www.home-assistant.io/components/melissa", + "requirements": [ + "py-melissa-climate==2.0.0" + ], + "dependencies": [], + "codeowners": [ + "@kennedyshead" + ] +} diff --git a/homeassistant/components/meraki/manifest.json b/homeassistant/components/meraki/manifest.json new file mode 100644 index 00000000000..d17e7c60525 --- /dev/null +++ b/homeassistant/components/meraki/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "meraki", + "name": "Meraki", + "documentation": "https://www.home-assistant.io/components/meraki", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/message_bird/manifest.json b/homeassistant/components/message_bird/manifest.json new file mode 100644 index 00000000000..a6c49b3c396 --- /dev/null +++ b/homeassistant/components/message_bird/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "message_bird", + "name": "Message bird", + "documentation": "https://www.home-assistant.io/components/message_bird", + "requirements": [ + "messagebird==1.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/met/manifest.json b/homeassistant/components/met/manifest.json new file mode 100644 index 00000000000..b2ef166be50 --- /dev/null +++ b/homeassistant/components/met/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "met", + "name": "Met", + "documentation": "https://www.home-assistant.io/components/met", + "requirements": [ + "pyMetno==0.4.6" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen" + ] +} diff --git a/homeassistant/components/meteo_france/manifest.json b/homeassistant/components/meteo_france/manifest.json new file mode 100644 index 00000000000..20ad5e46fe6 --- /dev/null +++ b/homeassistant/components/meteo_france/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "meteo_france", + "name": "Meteo france", + "documentation": "https://www.home-assistant.io/components/meteo_france", + "requirements": [ + "meteofrance==0.3.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/metoffice/manifest.json b/homeassistant/components/metoffice/manifest.json new file mode 100644 index 00000000000..f5d358854f6 --- /dev/null +++ b/homeassistant/components/metoffice/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "metoffice", + "name": "Metoffice", + "documentation": "https://www.home-assistant.io/components/metoffice", + "requirements": [ + "datapoint==0.4.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mfi/manifest.json b/homeassistant/components/mfi/manifest.json new file mode 100644 index 00000000000..1e84b39a366 --- /dev/null +++ b/homeassistant/components/mfi/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mfi", + "name": "Mfi", + "documentation": "https://www.home-assistant.io/components/mfi", + "requirements": [ + "mficlient==0.3.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mhz19/manifest.json b/homeassistant/components/mhz19/manifest.json new file mode 100644 index 00000000000..8545db90e27 --- /dev/null +++ b/homeassistant/components/mhz19/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mhz19", + "name": "Mhz19", + "documentation": "https://www.home-assistant.io/components/mhz19", + "requirements": [ + "pmsensor==0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/microsoft/manifest.json b/homeassistant/components/microsoft/manifest.json new file mode 100644 index 00000000000..827d961a093 --- /dev/null +++ b/homeassistant/components/microsoft/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "microsoft", + "name": "Microsoft", + "documentation": "https://www.home-assistant.io/components/microsoft", + "requirements": [ + "pycsspeechtts==1.0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/microsoft_face/manifest.json b/homeassistant/components/microsoft_face/manifest.json new file mode 100644 index 00000000000..7f6c4fbd935 --- /dev/null +++ b/homeassistant/components/microsoft_face/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "microsoft_face", + "name": "Microsoft face", + "documentation": "https://www.home-assistant.io/components/microsoft_face", + "requirements": [], + "dependencies": [ + "camera" + ], + "codeowners": [] +} diff --git a/homeassistant/components/microsoft_face_detect/manifest.json b/homeassistant/components/microsoft_face_detect/manifest.json new file mode 100644 index 00000000000..955b67a0a76 --- /dev/null +++ b/homeassistant/components/microsoft_face_detect/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "microsoft_face_detect", + "name": "Microsoft face detect", + "documentation": "https://www.home-assistant.io/components/microsoft_face_detect", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/microsoft_face_identify/manifest.json b/homeassistant/components/microsoft_face_identify/manifest.json new file mode 100644 index 00000000000..f32b9220b3d --- /dev/null +++ b/homeassistant/components/microsoft_face_identify/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "microsoft_face_identify", + "name": "Microsoft face identify", + "documentation": "https://www.home-assistant.io/components/microsoft_face_identify", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/miflora/manifest.json b/homeassistant/components/miflora/manifest.json new file mode 100644 index 00000000000..d4e7a333acf --- /dev/null +++ b/homeassistant/components/miflora/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "miflora", + "name": "Miflora", + "documentation": "https://www.home-assistant.io/components/miflora", + "requirements": [ + "miflora==0.4.0" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen", + "@ChristianKuehnel" + ] +} diff --git a/homeassistant/components/mikrotik/manifest.json b/homeassistant/components/mikrotik/manifest.json new file mode 100644 index 00000000000..caa9733f241 --- /dev/null +++ b/homeassistant/components/mikrotik/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mikrotik", + "name": "Mikrotik", + "documentation": "https://www.home-assistant.io/components/mikrotik", + "requirements": [ + "librouteros==2.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mill/manifest.json b/homeassistant/components/mill/manifest.json new file mode 100644 index 00000000000..05efb845c12 --- /dev/null +++ b/homeassistant/components/mill/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "mill", + "name": "Mill", + "documentation": "https://www.home-assistant.io/components/mill", + "requirements": [ + "millheater==0.3.4" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen" + ] +} diff --git a/homeassistant/components/min_max/manifest.json b/homeassistant/components/min_max/manifest.json new file mode 100644 index 00000000000..ea6befe498b --- /dev/null +++ b/homeassistant/components/min_max/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "min_max", + "name": "Min max", + "documentation": "https://www.home-assistant.io/components/min_max", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/mitemp_bt/manifest.json b/homeassistant/components/mitemp_bt/manifest.json new file mode 100644 index 00000000000..2324a861b38 --- /dev/null +++ b/homeassistant/components/mitemp_bt/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mitemp_bt", + "name": "Mitemp bt", + "documentation": "https://www.home-assistant.io/components/mitemp_bt", + "requirements": [ + "mitemp_bt==0.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mjpeg/manifest.json b/homeassistant/components/mjpeg/manifest.json new file mode 100644 index 00000000000..2ecd66910be --- /dev/null +++ b/homeassistant/components/mjpeg/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "mjpeg", + "name": "Mjpeg", + "documentation": "https://www.home-assistant.io/components/mjpeg", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mobile_app/manifest.json b/homeassistant/components/mobile_app/manifest.json new file mode 100644 index 00000000000..9c21858df1d --- /dev/null +++ b/homeassistant/components/mobile_app/manifest.json @@ -0,0 +1,16 @@ +{ + "domain": "mobile_app", + "name": "Home Assistant Mobile App Support", + "documentation": "https://www.home-assistant.io/components/mobile_app", + "requirements": [ + "PyNaCl==1.3.0" + ], + "dependencies": [ + "device_tracker", + "http", + "webhook" + ], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/mochad/manifest.json b/homeassistant/components/mochad/manifest.json new file mode 100644 index 00000000000..0e5c4dd1ff3 --- /dev/null +++ b/homeassistant/components/mochad/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mochad", + "name": "Mochad", + "documentation": "https://www.home-assistant.io/components/mochad", + "requirements": [ + "pymochad==0.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/modbus/manifest.json b/homeassistant/components/modbus/manifest.json new file mode 100644 index 00000000000..e27f594b0af --- /dev/null +++ b/homeassistant/components/modbus/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "modbus", + "name": "Modbus", + "documentation": "https://www.home-assistant.io/components/modbus", + "requirements": [ + "pymodbus==1.5.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/modem_callerid/manifest.json b/homeassistant/components/modem_callerid/manifest.json new file mode 100644 index 00000000000..e3d6d19b803 --- /dev/null +++ b/homeassistant/components/modem_callerid/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "modem_callerid", + "name": "Modem callerid", + "documentation": "https://www.home-assistant.io/components/modem_callerid", + "requirements": [ + "basicmodem==0.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mold_indicator/manifest.json b/homeassistant/components/mold_indicator/manifest.json new file mode 100644 index 00000000000..de4680927a4 --- /dev/null +++ b/homeassistant/components/mold_indicator/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "mold_indicator", + "name": "Mold indicator", + "documentation": "https://www.home-assistant.io/components/mold_indicator", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/monoprice/manifest.json b/homeassistant/components/monoprice/manifest.json new file mode 100644 index 00000000000..aa07911a697 --- /dev/null +++ b/homeassistant/components/monoprice/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "monoprice", + "name": "Monoprice", + "documentation": "https://www.home-assistant.io/components/monoprice", + "requirements": [ + "pymonoprice==0.3" + ], + "dependencies": [], + "codeowners": [ + "@etsinko" + ] +} diff --git a/homeassistant/components/moon/manifest.json b/homeassistant/components/moon/manifest.json new file mode 100644 index 00000000000..50a93fce20a --- /dev/null +++ b/homeassistant/components/moon/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "moon", + "name": "Moon", + "documentation": "https://www.home-assistant.io/components/moon", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/mopar/manifest.json b/homeassistant/components/mopar/manifest.json new file mode 100644 index 00000000000..5acd5bbdcdb --- /dev/null +++ b/homeassistant/components/mopar/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mopar", + "name": "Mopar", + "documentation": "https://www.home-assistant.io/components/mopar", + "requirements": [ + "motorparts==1.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mpchc/manifest.json b/homeassistant/components/mpchc/manifest.json new file mode 100644 index 00000000000..e874ca28891 --- /dev/null +++ b/homeassistant/components/mpchc/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "mpchc", + "name": "Mpchc", + "documentation": "https://www.home-assistant.io/components/mpchc", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mpd/manifest.json b/homeassistant/components/mpd/manifest.json new file mode 100644 index 00000000000..beee3137ef5 --- /dev/null +++ b/homeassistant/components/mpd/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "mpd", + "name": "Mpd", + "documentation": "https://www.home-assistant.io/components/mpd", + "requirements": [ + "python-mpd2==1.0.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/mqtt/manifest.json b/homeassistant/components/mqtt/manifest.json new file mode 100644 index 00000000000..deed878711a --- /dev/null +++ b/homeassistant/components/mqtt/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "mqtt", + "name": "MQTT", + "documentation": "https://www.home-assistant.io/components/mqtt", + "requirements": [ + "hbmqtt==0.9.4", + "paho-mqtt==1.4.0" + ], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/mqtt_eventstream/manifest.json b/homeassistant/components/mqtt_eventstream/manifest.json new file mode 100644 index 00000000000..e795c8aaf18 --- /dev/null +++ b/homeassistant/components/mqtt_eventstream/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mqtt_eventstream", + "name": "Mqtt eventstream", + "documentation": "https://www.home-assistant.io/components/mqtt_eventstream", + "requirements": [], + "dependencies": [ + "mqtt" + ], + "codeowners": [] +} diff --git a/homeassistant/components/mqtt_json/manifest.json b/homeassistant/components/mqtt_json/manifest.json new file mode 100644 index 00000000000..96a0a187e65 --- /dev/null +++ b/homeassistant/components/mqtt_json/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "mqtt_json", + "name": "Mqtt json", + "documentation": "https://www.home-assistant.io/components/mqtt_json", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mqtt_room/manifest.json b/homeassistant/components/mqtt_room/manifest.json new file mode 100644 index 00000000000..e7b37aec50d --- /dev/null +++ b/homeassistant/components/mqtt_room/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "mqtt_room", + "name": "Mqtt room", + "documentation": "https://www.home-assistant.io/components/mqtt_room", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mqtt_statestream/manifest.json b/homeassistant/components/mqtt_statestream/manifest.json new file mode 100644 index 00000000000..5fa99363729 --- /dev/null +++ b/homeassistant/components/mqtt_statestream/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mqtt_statestream", + "name": "Mqtt statestream", + "documentation": "https://www.home-assistant.io/components/mqtt_statestream", + "requirements": [], + "dependencies": [ + "mqtt" + ], + "codeowners": [] +} diff --git a/homeassistant/components/mvglive/manifest.json b/homeassistant/components/mvglive/manifest.json new file mode 100644 index 00000000000..5626e244484 --- /dev/null +++ b/homeassistant/components/mvglive/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mvglive", + "name": "Mvglive", + "documentation": "https://www.home-assistant.io/components/mvglive", + "requirements": [ + "PyMVGLive==1.1.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mychevy/manifest.json b/homeassistant/components/mychevy/manifest.json new file mode 100644 index 00000000000..1ff997372ed --- /dev/null +++ b/homeassistant/components/mychevy/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mychevy", + "name": "Mychevy", + "documentation": "https://www.home-assistant.io/components/mychevy", + "requirements": [ + "mychevy==1.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mycroft/manifest.json b/homeassistant/components/mycroft/manifest.json new file mode 100644 index 00000000000..77e5a524aac --- /dev/null +++ b/homeassistant/components/mycroft/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mycroft", + "name": "Mycroft", + "documentation": "https://www.home-assistant.io/components/mycroft", + "requirements": [ + "mycroftapi==2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/myq/manifest.json b/homeassistant/components/myq/manifest.json new file mode 100644 index 00000000000..3dbabd4260d --- /dev/null +++ b/homeassistant/components/myq/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "myq", + "name": "Myq", + "documentation": "https://www.home-assistant.io/components/myq", + "requirements": [ + "pymyq==1.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mysensors/manifest.json b/homeassistant/components/mysensors/manifest.json new file mode 100644 index 00000000000..2b94c2678aa --- /dev/null +++ b/homeassistant/components/mysensors/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mysensors", + "name": "Mysensors", + "documentation": "https://www.home-assistant.io/components/mysensors", + "requirements": [ + "pymysensors==0.18.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/mystrom/manifest.json b/homeassistant/components/mystrom/manifest.json new file mode 100644 index 00000000000..a3744baccb1 --- /dev/null +++ b/homeassistant/components/mystrom/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "mystrom", + "name": "Mystrom", + "documentation": "https://www.home-assistant.io/components/mystrom", + "requirements": [ + "python-mystrom==0.5.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/mythicbeastsdns/manifest.json b/homeassistant/components/mythicbeastsdns/manifest.json new file mode 100644 index 00000000000..4e37544a99a --- /dev/null +++ b/homeassistant/components/mythicbeastsdns/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "mythicbeastsdns", + "name": "Mythicbeastsdns", + "documentation": "https://www.home-assistant.io/components/mythicbeastsdns", + "requirements": [ + "mbddns==0.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nad/manifest.json b/homeassistant/components/nad/manifest.json new file mode 100644 index 00000000000..c624acd73da --- /dev/null +++ b/homeassistant/components/nad/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nad", + "name": "Nad", + "documentation": "https://www.home-assistant.io/components/nad", + "requirements": [ + "nad_receiver==0.0.11" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/namecheapdns/manifest.json b/homeassistant/components/namecheapdns/manifest.json new file mode 100644 index 00000000000..c5c46b92166 --- /dev/null +++ b/homeassistant/components/namecheapdns/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "namecheapdns", + "name": "Namecheapdns", + "documentation": "https://www.home-assistant.io/components/namecheapdns", + "requirements": [ + "defusedxml==0.5.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nanoleaf/manifest.json b/homeassistant/components/nanoleaf/manifest.json new file mode 100644 index 00000000000..a59a6352af2 --- /dev/null +++ b/homeassistant/components/nanoleaf/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nanoleaf", + "name": "Nanoleaf", + "documentation": "https://www.home-assistant.io/components/nanoleaf", + "requirements": [ + "pynanoleaf==0.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/neato/manifest.json b/homeassistant/components/neato/manifest.json new file mode 100644 index 00000000000..042d7dcef09 --- /dev/null +++ b/homeassistant/components/neato/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "neato", + "name": "Neato", + "documentation": "https://www.home-assistant.io/components/neato", + "requirements": [ + "pybotvac==0.0.13" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nederlandse_spoorwegen/manifest.json b/homeassistant/components/nederlandse_spoorwegen/manifest.json new file mode 100644 index 00000000000..baa6551cc7c --- /dev/null +++ b/homeassistant/components/nederlandse_spoorwegen/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nederlandse_spoorwegen", + "name": "Nederlandse spoorwegen", + "documentation": "https://www.home-assistant.io/components/nederlandse_spoorwegen", + "requirements": [ + "nsapi==2.7.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nello/manifest.json b/homeassistant/components/nello/manifest.json new file mode 100644 index 00000000000..0caafd7e27a --- /dev/null +++ b/homeassistant/components/nello/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "nello", + "name": "Nello", + "documentation": "https://www.home-assistant.io/components/nello", + "requirements": [ + "pynello==2.0.2" + ], + "dependencies": [], + "codeowners": [ + "@pschmitt" + ] +} diff --git a/homeassistant/components/ness_alarm/manifest.json b/homeassistant/components/ness_alarm/manifest.json new file mode 100644 index 00000000000..93b19470ac4 --- /dev/null +++ b/homeassistant/components/ness_alarm/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "ness_alarm", + "name": "Ness alarm", + "documentation": "https://www.home-assistant.io/components/ness_alarm", + "requirements": [ + "nessclient==0.9.15" + ], + "dependencies": [], + "codeowners": [ + "@nickw444" + ] +} diff --git a/homeassistant/components/nest/manifest.json b/homeassistant/components/nest/manifest.json new file mode 100644 index 00000000000..9f2e4202f93 --- /dev/null +++ b/homeassistant/components/nest/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "nest", + "name": "Nest", + "documentation": "https://www.home-assistant.io/components/nest", + "requirements": [ + "python-nest==4.1.0" + ], + "dependencies": [], + "codeowners": [ + "@awarecan" + ] +} diff --git a/homeassistant/components/netatmo/manifest.json b/homeassistant/components/netatmo/manifest.json new file mode 100644 index 00000000000..fa6789b81e6 --- /dev/null +++ b/homeassistant/components/netatmo/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "netatmo", + "name": "Netatmo", + "documentation": "https://www.home-assistant.io/components/netatmo", + "requirements": [ + "pyatmo==1.9" + ], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/netatmo_public/manifest.json b/homeassistant/components/netatmo_public/manifest.json new file mode 100644 index 00000000000..4327db3f298 --- /dev/null +++ b/homeassistant/components/netatmo_public/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "netatmo_public", + "name": "Netatmo public", + "documentation": "https://www.home-assistant.io/components/netatmo_public", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/netdata/manifest.json b/homeassistant/components/netdata/manifest.json new file mode 100644 index 00000000000..9c3b8ad33d2 --- /dev/null +++ b/homeassistant/components/netdata/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "netdata", + "name": "Netdata", + "documentation": "https://www.home-assistant.io/components/netdata", + "requirements": [ + "netdata==0.1.2" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/netgear/manifest.json b/homeassistant/components/netgear/manifest.json new file mode 100644 index 00000000000..8fbf185c6af --- /dev/null +++ b/homeassistant/components/netgear/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "netgear", + "name": "Netgear", + "documentation": "https://www.home-assistant.io/components/netgear", + "requirements": [ + "pynetgear==0.5.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/netgear_lte/manifest.json b/homeassistant/components/netgear_lte/manifest.json new file mode 100644 index 00000000000..c35895c8c0f --- /dev/null +++ b/homeassistant/components/netgear_lte/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "netgear_lte", + "name": "Netgear lte", + "documentation": "https://www.home-assistant.io/components/netgear_lte", + "requirements": [ + "eternalegypt==0.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/netio/manifest.json b/homeassistant/components/netio/manifest.json new file mode 100644 index 00000000000..75649c66abb --- /dev/null +++ b/homeassistant/components/netio/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "netio", + "name": "Netio", + "documentation": "https://www.home-assistant.io/components/netio", + "requirements": [ + "pynetio==0.1.9.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/neurio_energy/manifest.json b/homeassistant/components/neurio_energy/manifest.json new file mode 100644 index 00000000000..04420d5c4f2 --- /dev/null +++ b/homeassistant/components/neurio_energy/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "neurio_energy", + "name": "Neurio energy", + "documentation": "https://www.home-assistant.io/components/neurio_energy", + "requirements": [ + "neurio==0.3.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nfandroidtv/manifest.json b/homeassistant/components/nfandroidtv/manifest.json new file mode 100644 index 00000000000..8f3d88b58ee --- /dev/null +++ b/homeassistant/components/nfandroidtv/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "nfandroidtv", + "name": "Nfandroidtv", + "documentation": "https://www.home-assistant.io/components/nfandroidtv", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/niko_home_control/manifest.json b/homeassistant/components/niko_home_control/manifest.json new file mode 100644 index 00000000000..6f5ce87d8e1 --- /dev/null +++ b/homeassistant/components/niko_home_control/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "niko_home_control", + "name": "Niko home control", + "documentation": "https://www.home-assistant.io/components/niko_home_control", + "requirements": [ + "niko-home-control==0.1.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nilu/manifest.json b/homeassistant/components/nilu/manifest.json new file mode 100644 index 00000000000..ee7645653e6 --- /dev/null +++ b/homeassistant/components/nilu/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nilu", + "name": "Nilu", + "documentation": "https://www.home-assistant.io/components/nilu", + "requirements": [ + "niluclient==0.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nissan_leaf/manifest.json b/homeassistant/components/nissan_leaf/manifest.json new file mode 100644 index 00000000000..ab94c01b7c1 --- /dev/null +++ b/homeassistant/components/nissan_leaf/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "nissan_leaf", + "name": "Nissan leaf", + "documentation": "https://www.home-assistant.io/components/nissan_leaf", + "requirements": [ + "pycarwings2==2.8" + ], + "dependencies": [], + "codeowners": [ + "@filcole" + ] +} diff --git a/homeassistant/components/nmap_tracker/manifest.json b/homeassistant/components/nmap_tracker/manifest.json new file mode 100644 index 00000000000..f4c4d33f036 --- /dev/null +++ b/homeassistant/components/nmap_tracker/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nmap_tracker", + "name": "Nmap tracker", + "documentation": "https://www.home-assistant.io/components/nmap_tracker", + "requirements": [ + "python-nmap==0.6.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nmbs/manifest.json b/homeassistant/components/nmbs/manifest.json new file mode 100644 index 00000000000..1a2fa055688 --- /dev/null +++ b/homeassistant/components/nmbs/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "nmbs", + "name": "Nmbs", + "documentation": "https://www.home-assistant.io/components/nmbs", + "requirements": [ + "pyrail==0.0.3" + ], + "dependencies": [], + "codeowners": [ + "@thibmaek" + ] +} diff --git a/homeassistant/components/no_ip/manifest.json b/homeassistant/components/no_ip/manifest.json new file mode 100644 index 00000000000..12581599532 --- /dev/null +++ b/homeassistant/components/no_ip/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "no_ip", + "name": "No ip", + "documentation": "https://www.home-assistant.io/components/no_ip", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/noaa_tides/manifest.json b/homeassistant/components/noaa_tides/manifest.json new file mode 100644 index 00000000000..9ffc0215fd1 --- /dev/null +++ b/homeassistant/components/noaa_tides/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "noaa_tides", + "name": "Noaa tides", + "documentation": "https://www.home-assistant.io/components/noaa_tides", + "requirements": [ + "py_noaa==0.3.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/norway_air/manifest.json b/homeassistant/components/norway_air/manifest.json new file mode 100644 index 00000000000..08c9932c36f --- /dev/null +++ b/homeassistant/components/norway_air/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "norway_air", + "name": "Norway air", + "documentation": "https://www.home-assistant.io/components/norway_air", + "requirements": [ + "pyMetno==0.4.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/notify/manifest.json b/homeassistant/components/notify/manifest.json new file mode 100644 index 00000000000..22c85723cb8 --- /dev/null +++ b/homeassistant/components/notify/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "notify", + "name": "Notify", + "documentation": "https://www.home-assistant.io/components/notify", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@flowolf" + ] +} diff --git a/homeassistant/components/nsw_fuel_station/manifest.json b/homeassistant/components/nsw_fuel_station/manifest.json new file mode 100644 index 00000000000..6be24fb5a2c --- /dev/null +++ b/homeassistant/components/nsw_fuel_station/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "nsw_fuel_station", + "name": "Nsw fuel station", + "documentation": "https://www.home-assistant.io/components/nsw_fuel_station", + "requirements": [ + "nsw-fuel-api-client==1.0.10" + ], + "dependencies": [], + "codeowners": [ + "@nickw444" + ] +} diff --git a/homeassistant/components/nsw_rural_fire_service_feed/manifest.json b/homeassistant/components/nsw_rural_fire_service_feed/manifest.json new file mode 100644 index 00000000000..dd0ba048a34 --- /dev/null +++ b/homeassistant/components/nsw_rural_fire_service_feed/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nsw_rural_fire_service_feed", + "name": "Nsw rural fire service feed", + "documentation": "https://www.home-assistant.io/components/nsw_rural_fire_service_feed", + "requirements": [ + "geojson_client==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nuheat/manifest.json b/homeassistant/components/nuheat/manifest.json new file mode 100644 index 00000000000..c9e69c44ec2 --- /dev/null +++ b/homeassistant/components/nuheat/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nuheat", + "name": "Nuheat", + "documentation": "https://www.home-assistant.io/components/nuheat", + "requirements": [ + "nuheat==0.3.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nuimo_controller/manifest.json b/homeassistant/components/nuimo_controller/manifest.json new file mode 100644 index 00000000000..9f18d2849f8 --- /dev/null +++ b/homeassistant/components/nuimo_controller/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nuimo_controller", + "name": "Nuimo controller", + "documentation": "https://www.home-assistant.io/components/nuimo_controller", + "requirements": [ + "--only-binary=all nuimo==0.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nuki/manifest.json b/homeassistant/components/nuki/manifest.json new file mode 100644 index 00000000000..d031cf6ce5f --- /dev/null +++ b/homeassistant/components/nuki/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "nuki", + "name": "Nuki", + "documentation": "https://www.home-assistant.io/components/nuki", + "requirements": [ + "pynuki==1.3.2" + ], + "dependencies": [], + "codeowners": [ + "@pschmitt" + ] +} diff --git a/homeassistant/components/nut/manifest.json b/homeassistant/components/nut/manifest.json new file mode 100644 index 00000000000..920e56fba7c --- /dev/null +++ b/homeassistant/components/nut/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nut", + "name": "Nut", + "documentation": "https://www.home-assistant.io/components/nut", + "requirements": [ + "pynut2==2.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nx584/manifest.json b/homeassistant/components/nx584/manifest.json new file mode 100644 index 00000000000..67b5b0e2eeb --- /dev/null +++ b/homeassistant/components/nx584/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "nx584", + "name": "Nx584", + "documentation": "https://www.home-assistant.io/components/nx584", + "requirements": [ + "pynx584==0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/nzbget/manifest.json b/homeassistant/components/nzbget/manifest.json new file mode 100644 index 00000000000..69293ede516 --- /dev/null +++ b/homeassistant/components/nzbget/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "nzbget", + "name": "Nzbget", + "documentation": "https://www.home-assistant.io/components/nzbget", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/octoprint/manifest.json b/homeassistant/components/octoprint/manifest.json new file mode 100644 index 00000000000..c34e1458e4b --- /dev/null +++ b/homeassistant/components/octoprint/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "octoprint", + "name": "Octoprint", + "documentation": "https://www.home-assistant.io/components/octoprint", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/oem/manifest.json b/homeassistant/components/oem/manifest.json new file mode 100644 index 00000000000..d23b07b2756 --- /dev/null +++ b/homeassistant/components/oem/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "oem", + "name": "Oem", + "documentation": "https://www.home-assistant.io/components/oem", + "requirements": [ + "oemthermostat==1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ohmconnect/manifest.json b/homeassistant/components/ohmconnect/manifest.json new file mode 100644 index 00000000000..a163a7d673a --- /dev/null +++ b/homeassistant/components/ohmconnect/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "ohmconnect", + "name": "Ohmconnect", + "documentation": "https://www.home-assistant.io/components/ohmconnect", + "requirements": [ + "defusedxml==0.5.0" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/onboarding/manifest.json b/homeassistant/components/onboarding/manifest.json new file mode 100644 index 00000000000..ffb01bd5602 --- /dev/null +++ b/homeassistant/components/onboarding/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "onboarding", + "name": "Onboarding", + "documentation": "https://www.home-assistant.io/components/onboarding", + "requirements": [], + "dependencies": [ + "auth", + "http" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/onewire/manifest.json b/homeassistant/components/onewire/manifest.json new file mode 100644 index 00000000000..00075d4485f --- /dev/null +++ b/homeassistant/components/onewire/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "onewire", + "name": "Onewire", + "documentation": "https://www.home-assistant.io/components/onewire", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/onkyo/manifest.json b/homeassistant/components/onkyo/manifest.json new file mode 100644 index 00000000000..7fd27dd7edf --- /dev/null +++ b/homeassistant/components/onkyo/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "onkyo", + "name": "Onkyo", + "documentation": "https://www.home-assistant.io/components/onkyo", + "requirements": [ + "onkyo-eiscp==1.2.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/onvif/manifest.json b/homeassistant/components/onvif/manifest.json new file mode 100644 index 00000000000..6d5ad256f16 --- /dev/null +++ b/homeassistant/components/onvif/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "onvif", + "name": "Onvif", + "documentation": "https://www.home-assistant.io/components/onvif", + "requirements": [ + "onvif-py3==0.1.3", + "suds-passworddigest-homeassistant==0.1.2a0.dev0", + "suds-py3==1.3.3.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/openalpr_cloud/manifest.json b/homeassistant/components/openalpr_cloud/manifest.json new file mode 100644 index 00000000000..f0421295836 --- /dev/null +++ b/homeassistant/components/openalpr_cloud/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "openalpr_cloud", + "name": "Openalpr cloud", + "documentation": "https://www.home-assistant.io/components/openalpr_cloud", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/openalpr_local/manifest.json b/homeassistant/components/openalpr_local/manifest.json new file mode 100644 index 00000000000..3c92e840f43 --- /dev/null +++ b/homeassistant/components/openalpr_local/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "openalpr_local", + "name": "Openalpr local", + "documentation": "https://www.home-assistant.io/components/openalpr_local", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/opencv/manifest.json b/homeassistant/components/opencv/manifest.json new file mode 100644 index 00000000000..b49e5b73554 --- /dev/null +++ b/homeassistant/components/opencv/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "opencv", + "name": "Opencv", + "documentation": "https://www.home-assistant.io/components/opencv", + "requirements": [ + "numpy==1.16.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/openevse/manifest.json b/homeassistant/components/openevse/manifest.json new file mode 100644 index 00000000000..f37c769d20e --- /dev/null +++ b/homeassistant/components/openevse/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "openevse", + "name": "Openevse", + "documentation": "https://www.home-assistant.io/components/openevse", + "requirements": [ + "openevsewifi==0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/openexchangerates/manifest.json b/homeassistant/components/openexchangerates/manifest.json new file mode 100644 index 00000000000..ffb86d4a5e2 --- /dev/null +++ b/homeassistant/components/openexchangerates/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "openexchangerates", + "name": "Openexchangerates", + "documentation": "https://www.home-assistant.io/components/openexchangerates", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/opengarage/manifest.json b/homeassistant/components/opengarage/manifest.json new file mode 100644 index 00000000000..95f944b7087 --- /dev/null +++ b/homeassistant/components/opengarage/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "opengarage", + "name": "Opengarage", + "documentation": "https://www.home-assistant.io/components/opengarage", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/openhardwaremonitor/manifest.json b/homeassistant/components/openhardwaremonitor/manifest.json new file mode 100644 index 00000000000..d9281f08eda --- /dev/null +++ b/homeassistant/components/openhardwaremonitor/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "openhardwaremonitor", + "name": "Openhardwaremonitor", + "documentation": "https://www.home-assistant.io/components/openhardwaremonitor", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/openhome/manifest.json b/homeassistant/components/openhome/manifest.json new file mode 100644 index 00000000000..276346ae79b --- /dev/null +++ b/homeassistant/components/openhome/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "openhome", + "name": "Openhome", + "documentation": "https://www.home-assistant.io/components/openhome", + "requirements": [ + "openhomedevice==0.4.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/opensensemap/manifest.json b/homeassistant/components/opensensemap/manifest.json new file mode 100644 index 00000000000..ab03f1cf7c6 --- /dev/null +++ b/homeassistant/components/opensensemap/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "opensensemap", + "name": "Opensensemap", + "documentation": "https://www.home-assistant.io/components/opensensemap", + "requirements": [ + "opensensemap-api==0.1.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/opensky/manifest.json b/homeassistant/components/opensky/manifest.json new file mode 100644 index 00000000000..dd58cdd4168 --- /dev/null +++ b/homeassistant/components/opensky/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "opensky", + "name": "Opensky", + "documentation": "https://www.home-assistant.io/components/opensky", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/opentherm_gw/manifest.json b/homeassistant/components/opentherm_gw/manifest.json new file mode 100644 index 00000000000..50bfa4d1122 --- /dev/null +++ b/homeassistant/components/opentherm_gw/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "opentherm_gw", + "name": "Opentherm gw", + "documentation": "https://www.home-assistant.io/components/opentherm_gw", + "requirements": [ + "pyotgw==0.4b3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/openuv/manifest.json b/homeassistant/components/openuv/manifest.json new file mode 100644 index 00000000000..b94a409aa71 --- /dev/null +++ b/homeassistant/components/openuv/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "openuv", + "name": "Openuv", + "documentation": "https://www.home-assistant.io/components/openuv", + "requirements": [ + "pyopenuv==1.0.9" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/openweathermap/manifest.json b/homeassistant/components/openweathermap/manifest.json new file mode 100644 index 00000000000..d24b23f64bb --- /dev/null +++ b/homeassistant/components/openweathermap/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "openweathermap", + "name": "Openweathermap", + "documentation": "https://www.home-assistant.io/components/openweathermap", + "requirements": [ + "pyowm==2.10.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/opple/manifest.json b/homeassistant/components/opple/manifest.json new file mode 100644 index 00000000000..c10be48f3fa --- /dev/null +++ b/homeassistant/components/opple/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "opple", + "name": "Opple", + "documentation": "https://www.home-assistant.io/components/opple", + "requirements": [ + "pyoppleio==1.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/orvibo/manifest.json b/homeassistant/components/orvibo/manifest.json new file mode 100644 index 00000000000..73f4eaed7da --- /dev/null +++ b/homeassistant/components/orvibo/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "orvibo", + "name": "Orvibo", + "documentation": "https://www.home-assistant.io/components/orvibo", + "requirements": [ + "orvibo==1.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/osramlightify/manifest.json b/homeassistant/components/osramlightify/manifest.json new file mode 100644 index 00000000000..0b158b96742 --- /dev/null +++ b/homeassistant/components/osramlightify/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "osramlightify", + "name": "Osramlightify", + "documentation": "https://www.home-assistant.io/components/osramlightify", + "requirements": [ + "lightify==1.0.7.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/otp/manifest.json b/homeassistant/components/otp/manifest.json new file mode 100644 index 00000000000..3eb24e0f1c6 --- /dev/null +++ b/homeassistant/components/otp/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "otp", + "name": "Otp", + "documentation": "https://www.home-assistant.io/components/otp", + "requirements": [ + "pyotp==2.2.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/owlet/manifest.json b/homeassistant/components/owlet/manifest.json new file mode 100644 index 00000000000..edc51dcc533 --- /dev/null +++ b/homeassistant/components/owlet/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "owlet", + "name": "Owlet", + "documentation": "https://www.home-assistant.io/components/owlet", + "requirements": [ + "pyowlet==1.0.2" + ], + "dependencies": [], + "codeowners": [ + "@oblogic7" + ] +} diff --git a/homeassistant/components/owntracks/manifest.json b/homeassistant/components/owntracks/manifest.json new file mode 100644 index 00000000000..3646f32093a --- /dev/null +++ b/homeassistant/components/owntracks/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "owntracks", + "name": "Owntracks", + "documentation": "https://www.home-assistant.io/components/owntracks", + "requirements": [ + "PyNaCl==1.3.0" + ], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/panasonic_bluray/manifest.json b/homeassistant/components/panasonic_bluray/manifest.json new file mode 100644 index 00000000000..fe2387744ab --- /dev/null +++ b/homeassistant/components/panasonic_bluray/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "panasonic_bluray", + "name": "Panasonic bluray", + "documentation": "https://www.home-assistant.io/components/panasonic_bluray", + "requirements": [ + "panacotta==0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/panasonic_viera/manifest.json b/homeassistant/components/panasonic_viera/manifest.json new file mode 100644 index 00000000000..432e729ef20 --- /dev/null +++ b/homeassistant/components/panasonic_viera/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "panasonic_viera", + "name": "Panasonic viera", + "documentation": "https://www.home-assistant.io/components/panasonic_viera", + "requirements": [ + "panasonic_viera==0.3.2", + "wakeonlan==1.1.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pandora/manifest.json b/homeassistant/components/pandora/manifest.json new file mode 100644 index 00000000000..68e8337a33d --- /dev/null +++ b/homeassistant/components/pandora/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pandora", + "name": "Pandora", + "documentation": "https://www.home-assistant.io/components/pandora", + "requirements": [ + "pexpect==4.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/panel_custom/manifest.json b/homeassistant/components/panel_custom/manifest.json new file mode 100644 index 00000000000..5fb7adb2a4a --- /dev/null +++ b/homeassistant/components/panel_custom/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "panel_custom", + "name": "Panel custom", + "documentation": "https://www.home-assistant.io/components/panel_custom", + "requirements": [], + "dependencies": [ + "frontend" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/panel_iframe/manifest.json b/homeassistant/components/panel_iframe/manifest.json new file mode 100644 index 00000000000..127ff3caa4d --- /dev/null +++ b/homeassistant/components/panel_iframe/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "panel_iframe", + "name": "Panel iframe", + "documentation": "https://www.home-assistant.io/components/panel_iframe", + "requirements": [], + "dependencies": [ + "frontend" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/pencom/manifest.json b/homeassistant/components/pencom/manifest.json new file mode 100644 index 00000000000..186e071d25b --- /dev/null +++ b/homeassistant/components/pencom/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pencom", + "name": "Pencom", + "documentation": "https://www.home-assistant.io/components/pencom", + "requirements": [ + "pencompy==0.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/persistent_notification/manifest.json b/homeassistant/components/persistent_notification/manifest.json new file mode 100644 index 00000000000..8bc343e1f08 --- /dev/null +++ b/homeassistant/components/persistent_notification/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "persistent_notification", + "name": "Persistent notification", + "documentation": "https://www.home-assistant.io/components/persistent_notification", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/person/manifest.json b/homeassistant/components/person/manifest.json new file mode 100644 index 00000000000..d2cba929259 --- /dev/null +++ b/homeassistant/components/person/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "person", + "name": "Person", + "documentation": "https://www.home-assistant.io/components/person", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/philips_js/manifest.json b/homeassistant/components/philips_js/manifest.json new file mode 100644 index 00000000000..18ddcf1f5ff --- /dev/null +++ b/homeassistant/components/philips_js/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "philips_js", + "name": "Philips js", + "documentation": "https://www.home-assistant.io/components/philips_js", + "requirements": [ + "ha-philipsjs==0.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pi_hole/manifest.json b/homeassistant/components/pi_hole/manifest.json new file mode 100644 index 00000000000..c47d8811e68 --- /dev/null +++ b/homeassistant/components/pi_hole/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "pi_hole", + "name": "Pi hole", + "documentation": "https://www.home-assistant.io/components/pi_hole", + "requirements": [ + "hole==0.3.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/picotts/manifest.json b/homeassistant/components/picotts/manifest.json new file mode 100644 index 00000000000..bfe7f449ca0 --- /dev/null +++ b/homeassistant/components/picotts/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "picotts", + "name": "Picotts", + "documentation": "https://www.home-assistant.io/components/picotts", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/piglow/manifest.json b/homeassistant/components/piglow/manifest.json new file mode 100644 index 00000000000..67b1033c51e --- /dev/null +++ b/homeassistant/components/piglow/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "piglow", + "name": "Piglow", + "documentation": "https://www.home-assistant.io/components/piglow", + "requirements": [ + "piglow==1.2.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pilight/manifest.json b/homeassistant/components/pilight/manifest.json new file mode 100644 index 00000000000..dfe4952e1a1 --- /dev/null +++ b/homeassistant/components/pilight/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pilight", + "name": "Pilight", + "documentation": "https://www.home-assistant.io/components/pilight", + "requirements": [ + "pilight==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ping/manifest.json b/homeassistant/components/ping/manifest.json new file mode 100644 index 00000000000..d98adef87a7 --- /dev/null +++ b/homeassistant/components/ping/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "ping", + "name": "Ping", + "documentation": "https://www.home-assistant.io/components/ping", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pioneer/manifest.json b/homeassistant/components/pioneer/manifest.json new file mode 100644 index 00000000000..b06874149ed --- /dev/null +++ b/homeassistant/components/pioneer/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "pioneer", + "name": "Pioneer", + "documentation": "https://www.home-assistant.io/components/pioneer", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pjlink/manifest.json b/homeassistant/components/pjlink/manifest.json new file mode 100644 index 00000000000..6901847bd8d --- /dev/null +++ b/homeassistant/components/pjlink/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pjlink", + "name": "Pjlink", + "documentation": "https://www.home-assistant.io/components/pjlink", + "requirements": [ + "pypjlink2==1.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/plant/manifest.json b/homeassistant/components/plant/manifest.json new file mode 100644 index 00000000000..cbde894173b --- /dev/null +++ b/homeassistant/components/plant/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "plant", + "name": "Plant", + "documentation": "https://www.home-assistant.io/components/plant", + "requirements": [], + "dependencies": [ + "group", + "zone" + ], + "codeowners": [ + "@ChristianKuehnel" + ] +} diff --git a/homeassistant/components/plex/manifest.json b/homeassistant/components/plex/manifest.json new file mode 100644 index 00000000000..ae8e1b684ed --- /dev/null +++ b/homeassistant/components/plex/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "plex", + "name": "Plex", + "documentation": "https://www.home-assistant.io/components/plex", + "requirements": [ + "plexapi==3.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/plum_lightpad/manifest.json b/homeassistant/components/plum_lightpad/manifest.json new file mode 100644 index 00000000000..389eca09c42 --- /dev/null +++ b/homeassistant/components/plum_lightpad/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "plum_lightpad", + "name": "Plum lightpad", + "documentation": "https://www.home-assistant.io/components/plum_lightpad", + "requirements": [ + "plumlightpad==0.0.11" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pocketcasts/manifest.json b/homeassistant/components/pocketcasts/manifest.json new file mode 100644 index 00000000000..11c20236324 --- /dev/null +++ b/homeassistant/components/pocketcasts/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pocketcasts", + "name": "Pocketcasts", + "documentation": "https://www.home-assistant.io/components/pocketcasts", + "requirements": [ + "pocketcasts==0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/point/manifest.json b/homeassistant/components/point/manifest.json new file mode 100644 index 00000000000..8b888a3647a --- /dev/null +++ b/homeassistant/components/point/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "point", + "name": "Point", + "documentation": "https://www.home-assistant.io/components/point", + "requirements": [ + "pypoint==1.1.1" + ], + "dependencies": [ + "webhook" + ], + "codeowners": [ + "@fredrike" + ] +} diff --git a/homeassistant/components/pollen/manifest.json b/homeassistant/components/pollen/manifest.json new file mode 100644 index 00000000000..2edf83a0d1f --- /dev/null +++ b/homeassistant/components/pollen/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "pollen", + "name": "Pollen", + "documentation": "https://www.home-assistant.io/components/pollen", + "requirements": [ + "numpy==1.16.2", + "pypollencom==2.2.3" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/postnl/manifest.json b/homeassistant/components/postnl/manifest.json new file mode 100644 index 00000000000..9746cb168aa --- /dev/null +++ b/homeassistant/components/postnl/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "postnl", + "name": "Postnl", + "documentation": "https://www.home-assistant.io/components/postnl", + "requirements": [ + "postnl_api==1.0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/prezzibenzina/manifest.json b/homeassistant/components/prezzibenzina/manifest.json new file mode 100644 index 00000000000..2427ebbfdb0 --- /dev/null +++ b/homeassistant/components/prezzibenzina/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "prezzibenzina", + "name": "Prezzibenzina", + "documentation": "https://www.home-assistant.io/components/prezzibenzina", + "requirements": [ + "prezzibenzina-py==1.1.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/proliphix/manifest.json b/homeassistant/components/proliphix/manifest.json new file mode 100644 index 00000000000..3aa356823c1 --- /dev/null +++ b/homeassistant/components/proliphix/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "proliphix", + "name": "Proliphix", + "documentation": "https://www.home-assistant.io/components/proliphix", + "requirements": [ + "proliphix==0.4.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/prometheus/manifest.json b/homeassistant/components/prometheus/manifest.json new file mode 100644 index 00000000000..d9699be6bf7 --- /dev/null +++ b/homeassistant/components/prometheus/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "prometheus", + "name": "Prometheus", + "documentation": "https://www.home-assistant.io/components/prometheus", + "requirements": [ + "prometheus_client==0.2.0" + ], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/prowl/manifest.json b/homeassistant/components/prowl/manifest.json new file mode 100644 index 00000000000..a8b4893c995 --- /dev/null +++ b/homeassistant/components/prowl/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "prowl", + "name": "Prowl", + "documentation": "https://www.home-assistant.io/components/prowl", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/proximity/manifest.json b/homeassistant/components/proximity/manifest.json new file mode 100644 index 00000000000..335bea82fc9 --- /dev/null +++ b/homeassistant/components/proximity/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "proximity", + "name": "Proximity", + "documentation": "https://www.home-assistant.io/components/proximity", + "requirements": [], + "dependencies": [ + "device_tracker", + "zone" + ], + "codeowners": [] +} diff --git a/homeassistant/components/proxy/manifest.json b/homeassistant/components/proxy/manifest.json new file mode 100644 index 00000000000..a4a33efa2cd --- /dev/null +++ b/homeassistant/components/proxy/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "proxy", + "name": "Proxy", + "documentation": "https://www.home-assistant.io/components/proxy", + "requirements": [ + "pillow==5.4.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ps4/manifest.json b/homeassistant/components/ps4/manifest.json new file mode 100644 index 00000000000..605dd3f530c --- /dev/null +++ b/homeassistant/components/ps4/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ps4", + "name": "Ps4", + "documentation": "https://www.home-assistant.io/components/ps4", + "requirements": [ + "pyps4-homeassistant==0.5.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pulseaudio_loopback/manifest.json b/homeassistant/components/pulseaudio_loopback/manifest.json new file mode 100644 index 00000000000..58a2871e027 --- /dev/null +++ b/homeassistant/components/pulseaudio_loopback/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "pulseaudio_loopback", + "name": "Pulseaudio loopback", + "documentation": "https://www.home-assistant.io/components/pulseaudio_loopback", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/push/manifest.json b/homeassistant/components/push/manifest.json new file mode 100644 index 00000000000..96b9e647e14 --- /dev/null +++ b/homeassistant/components/push/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "push", + "name": "Push", + "documentation": "https://www.home-assistant.io/components/push", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@dgomes" + ] +} diff --git a/homeassistant/components/pushbullet/manifest.json b/homeassistant/components/pushbullet/manifest.json new file mode 100644 index 00000000000..51e77959d7a --- /dev/null +++ b/homeassistant/components/pushbullet/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pushbullet", + "name": "Pushbullet", + "documentation": "https://www.home-assistant.io/components/pushbullet", + "requirements": [ + "pushbullet.py==0.11.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pushetta/manifest.json b/homeassistant/components/pushetta/manifest.json new file mode 100644 index 00000000000..b42180c7268 --- /dev/null +++ b/homeassistant/components/pushetta/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pushetta", + "name": "Pushetta", + "documentation": "https://www.home-assistant.io/components/pushetta", + "requirements": [ + "pushetta==1.0.15" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pushover/manifest.json b/homeassistant/components/pushover/manifest.json new file mode 100644 index 00000000000..30dd35720de --- /dev/null +++ b/homeassistant/components/pushover/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pushover", + "name": "Pushover", + "documentation": "https://www.home-assistant.io/components/pushover", + "requirements": [ + "python-pushover==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pushsafer/manifest.json b/homeassistant/components/pushsafer/manifest.json new file mode 100644 index 00000000000..300d0ead4a5 --- /dev/null +++ b/homeassistant/components/pushsafer/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "pushsafer", + "name": "Pushsafer", + "documentation": "https://www.home-assistant.io/components/pushsafer", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/pvoutput/manifest.json b/homeassistant/components/pvoutput/manifest.json new file mode 100644 index 00000000000..b61c7100828 --- /dev/null +++ b/homeassistant/components/pvoutput/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "pvoutput", + "name": "Pvoutput", + "documentation": "https://www.home-assistant.io/components/pvoutput", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/pyload/manifest.json b/homeassistant/components/pyload/manifest.json new file mode 100644 index 00000000000..437bd3bc4d2 --- /dev/null +++ b/homeassistant/components/pyload/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "pyload", + "name": "Pyload", + "documentation": "https://www.home-assistant.io/components/pyload", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/python_script/manifest.json b/homeassistant/components/python_script/manifest.json new file mode 100644 index 00000000000..0f88513bb45 --- /dev/null +++ b/homeassistant/components/python_script/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "python_script", + "name": "Python script", + "documentation": "https://www.home-assistant.io/components/python_script", + "requirements": [ + "restrictedpython==4.0b8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/qbittorrent/manifest.json b/homeassistant/components/qbittorrent/manifest.json new file mode 100644 index 00000000000..5fb850739d8 --- /dev/null +++ b/homeassistant/components/qbittorrent/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "qbittorrent", + "name": "Qbittorrent", + "documentation": "https://www.home-assistant.io/components/qbittorrent", + "requirements": [ + "python-qbittorrent==0.3.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/qnap/manifest.json b/homeassistant/components/qnap/manifest.json new file mode 100644 index 00000000000..f02d416c7e6 --- /dev/null +++ b/homeassistant/components/qnap/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "qnap", + "name": "Qnap", + "documentation": "https://www.home-assistant.io/components/qnap", + "requirements": [ + "qnapstats==0.2.7" + ], + "dependencies": [], + "codeowners": [ + "@colinodell" + ] +} diff --git a/homeassistant/components/qrcode/manifest.json b/homeassistant/components/qrcode/manifest.json new file mode 100644 index 00000000000..96a351ac453 --- /dev/null +++ b/homeassistant/components/qrcode/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "qrcode", + "name": "Qrcode", + "documentation": "https://www.home-assistant.io/components/qrcode", + "requirements": [ + "pillow==5.4.1", + "pyzbar==0.1.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/quantum_gateway/manifest.json b/homeassistant/components/quantum_gateway/manifest.json new file mode 100644 index 00000000000..9c062482a4c --- /dev/null +++ b/homeassistant/components/quantum_gateway/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "quantum_gateway", + "name": "Quantum gateway", + "documentation": "https://www.home-assistant.io/components/quantum_gateway", + "requirements": [ + "quantum-gateway==0.0.5" + ], + "dependencies": [], + "codeowners": [ + "@cisasteelersfan" + ] +} diff --git a/homeassistant/components/qwikswitch/manifest.json b/homeassistant/components/qwikswitch/manifest.json new file mode 100644 index 00000000000..4907cb462b6 --- /dev/null +++ b/homeassistant/components/qwikswitch/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "qwikswitch", + "name": "Qwikswitch", + "documentation": "https://www.home-assistant.io/components/qwikswitch", + "requirements": [ + "pyqwikswitch==0.93" + ], + "dependencies": [], + "codeowners": [ + "@kellerza" + ] +} diff --git a/homeassistant/components/rachio/manifest.json b/homeassistant/components/rachio/manifest.json new file mode 100644 index 00000000000..30bde9a297d --- /dev/null +++ b/homeassistant/components/rachio/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rachio", + "name": "Rachio", + "documentation": "https://www.home-assistant.io/components/rachio", + "requirements": [ + "rachiopy==0.1.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/radarr/manifest.json b/homeassistant/components/radarr/manifest.json new file mode 100644 index 00000000000..f12fcf4220c --- /dev/null +++ b/homeassistant/components/radarr/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "radarr", + "name": "Radarr", + "documentation": "https://www.home-assistant.io/components/radarr", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/radiotherm/manifest.json b/homeassistant/components/radiotherm/manifest.json new file mode 100644 index 00000000000..002fdb63273 --- /dev/null +++ b/homeassistant/components/radiotherm/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "radiotherm", + "name": "Radiotherm", + "documentation": "https://www.home-assistant.io/components/radiotherm", + "requirements": [ + "radiotherm==2.0.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rainbird/manifest.json b/homeassistant/components/rainbird/manifest.json new file mode 100644 index 00000000000..24113d62534 --- /dev/null +++ b/homeassistant/components/rainbird/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rainbird", + "name": "Rainbird", + "documentation": "https://www.home-assistant.io/components/rainbird", + "requirements": [ + "pyrainbird==0.1.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/raincloud/manifest.json b/homeassistant/components/raincloud/manifest.json new file mode 100644 index 00000000000..2befec24b91 --- /dev/null +++ b/homeassistant/components/raincloud/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "raincloud", + "name": "Raincloud", + "documentation": "https://www.home-assistant.io/components/raincloud", + "requirements": [ + "raincloudy==0.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rainmachine/manifest.json b/homeassistant/components/rainmachine/manifest.json new file mode 100644 index 00000000000..ad7bdada321 --- /dev/null +++ b/homeassistant/components/rainmachine/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "rainmachine", + "name": "Rainmachine", + "documentation": "https://www.home-assistant.io/components/rainmachine", + "requirements": [ + "regenmaschine==1.4.0" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/random/manifest.json b/homeassistant/components/random/manifest.json new file mode 100644 index 00000000000..c184f35734c --- /dev/null +++ b/homeassistant/components/random/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "random", + "name": "Random", + "documentation": "https://www.home-assistant.io/components/random", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/raspihats/manifest.json b/homeassistant/components/raspihats/manifest.json new file mode 100644 index 00000000000..8f5040152a2 --- /dev/null +++ b/homeassistant/components/raspihats/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "raspihats", + "name": "Raspihats", + "documentation": "https://www.home-assistant.io/components/raspihats", + "requirements": [ + "raspihats==2.2.3", + "smbus-cffi==0.5.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/raspyrfm/manifest.json b/homeassistant/components/raspyrfm/manifest.json new file mode 100644 index 00000000000..fee815a7e6b --- /dev/null +++ b/homeassistant/components/raspyrfm/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "raspyrfm", + "name": "Raspyrfm", + "documentation": "https://www.home-assistant.io/components/raspyrfm", + "requirements": [ + "raspyrfm-client==1.2.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/recollect_waste/manifest.json b/homeassistant/components/recollect_waste/manifest.json new file mode 100644 index 00000000000..2cccf32f298 --- /dev/null +++ b/homeassistant/components/recollect_waste/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "recollect_waste", + "name": "Recollect waste", + "documentation": "https://www.home-assistant.io/components/recollect_waste", + "requirements": [ + "recollect-waste==1.0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/recorder/manifest.json b/homeassistant/components/recorder/manifest.json new file mode 100644 index 00000000000..c466d35e23f --- /dev/null +++ b/homeassistant/components/recorder/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "recorder", + "name": "Recorder", + "documentation": "https://www.home-assistant.io/components/recorder", + "requirements": [ + "sqlalchemy==1.3.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/recswitch/manifest.json b/homeassistant/components/recswitch/manifest.json new file mode 100644 index 00000000000..af8e802c5ec --- /dev/null +++ b/homeassistant/components/recswitch/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "recswitch", + "name": "Recswitch", + "documentation": "https://www.home-assistant.io/components/recswitch", + "requirements": [ + "pyrecswitch==1.0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/reddit/manifest.json b/homeassistant/components/reddit/manifest.json new file mode 100644 index 00000000000..72ee7a42ca4 --- /dev/null +++ b/homeassistant/components/reddit/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "reddit", + "name": "Reddit", + "documentation": "https://www.home-assistant.io/components/reddit", + "requirements": [ + "praw==6.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rejseplanen/manifest.json b/homeassistant/components/rejseplanen/manifest.json new file mode 100644 index 00000000000..72562399330 --- /dev/null +++ b/homeassistant/components/rejseplanen/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rejseplanen", + "name": "Rejseplanen", + "documentation": "https://www.home-assistant.io/components/rejseplanen", + "requirements": [ + "rjpl==0.3.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/remember_the_milk/manifest.json b/homeassistant/components/remember_the_milk/manifest.json new file mode 100644 index 00000000000..a2076eb5800 --- /dev/null +++ b/homeassistant/components/remember_the_milk/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "remember_the_milk", + "name": "Remember the milk", + "documentation": "https://www.home-assistant.io/components/remember_the_milk", + "requirements": [ + "RtmAPI==0.7.0", + "httplib2==0.10.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/remote/manifest.json b/homeassistant/components/remote/manifest.json new file mode 100644 index 00000000000..5fe585dcd83 --- /dev/null +++ b/homeassistant/components/remote/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "remote", + "name": "Remote", + "documentation": "https://www.home-assistant.io/components/remote", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [] +} diff --git a/homeassistant/components/rest/manifest.json b/homeassistant/components/rest/manifest.json new file mode 100644 index 00000000000..999f5740715 --- /dev/null +++ b/homeassistant/components/rest/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "rest", + "name": "Rest", + "documentation": "https://www.home-assistant.io/components/rest", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rest_command/manifest.json b/homeassistant/components/rest_command/manifest.json new file mode 100644 index 00000000000..ced930fc64f --- /dev/null +++ b/homeassistant/components/rest_command/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "rest_command", + "name": "Rest command", + "documentation": "https://www.home-assistant.io/components/rest_command", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rflink/manifest.json b/homeassistant/components/rflink/manifest.json new file mode 100644 index 00000000000..a3b81f39c55 --- /dev/null +++ b/homeassistant/components/rflink/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rflink", + "name": "Rflink", + "documentation": "https://www.home-assistant.io/components/rflink", + "requirements": [ + "rflink==0.0.37" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rfxtrx/manifest.json b/homeassistant/components/rfxtrx/manifest.json new file mode 100644 index 00000000000..5d6cd4b038c --- /dev/null +++ b/homeassistant/components/rfxtrx/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "rfxtrx", + "name": "Rfxtrx", + "documentation": "https://www.home-assistant.io/components/rfxtrx", + "requirements": [ + "pyRFXtrx==0.23" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen" + ] +} diff --git a/homeassistant/components/ring/manifest.json b/homeassistant/components/ring/manifest.json new file mode 100644 index 00000000000..4d1fc629035 --- /dev/null +++ b/homeassistant/components/ring/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ring", + "name": "Ring", + "documentation": "https://www.home-assistant.io/components/ring", + "requirements": [ + "ring_doorbell==0.2.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ripple/manifest.json b/homeassistant/components/ripple/manifest.json new file mode 100644 index 00000000000..fe93bf02445 --- /dev/null +++ b/homeassistant/components/ripple/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ripple", + "name": "Ripple", + "documentation": "https://www.home-assistant.io/components/ripple", + "requirements": [ + "python-ripple-api==0.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ritassist/manifest.json b/homeassistant/components/ritassist/manifest.json new file mode 100644 index 00000000000..af8464e4e93 --- /dev/null +++ b/homeassistant/components/ritassist/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ritassist", + "name": "Ritassist", + "documentation": "https://www.home-assistant.io/components/ritassist", + "requirements": [ + "ritassist==0.9.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rmvtransport/manifest.json b/homeassistant/components/rmvtransport/manifest.json new file mode 100644 index 00000000000..3f32a61c081 --- /dev/null +++ b/homeassistant/components/rmvtransport/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "rmvtransport", + "name": "Rmvtransport", + "documentation": "https://www.home-assistant.io/components/rmvtransport", + "requirements": [ + "PyRMVtransport==0.1.3" + ], + "dependencies": [], + "codeowners": [ + "@cgtobi" + ] +} diff --git a/homeassistant/components/rocketchat/manifest.json b/homeassistant/components/rocketchat/manifest.json new file mode 100644 index 00000000000..3a8959f1be6 --- /dev/null +++ b/homeassistant/components/rocketchat/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rocketchat", + "name": "Rocketchat", + "documentation": "https://www.home-assistant.io/components/rocketchat", + "requirements": [ + "rocketchat-API==0.6.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/roku/manifest.json b/homeassistant/components/roku/manifest.json new file mode 100644 index 00000000000..7f7befbe418 --- /dev/null +++ b/homeassistant/components/roku/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "roku", + "name": "Roku", + "documentation": "https://www.home-assistant.io/components/roku", + "requirements": [ + "python-roku==3.1.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/roomba/manifest.json b/homeassistant/components/roomba/manifest.json new file mode 100644 index 00000000000..058ad0c5e81 --- /dev/null +++ b/homeassistant/components/roomba/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "roomba", + "name": "Roomba", + "documentation": "https://www.home-assistant.io/components/roomba", + "requirements": [ + "roombapy==1.3.1" + ], + "dependencies": [], + "codeowners": [ + "@pschmitt" + ] +} diff --git a/homeassistant/components/route53/manifest.json b/homeassistant/components/route53/manifest.json new file mode 100644 index 00000000000..d377ca7dca0 --- /dev/null +++ b/homeassistant/components/route53/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "route53", + "name": "Route53", + "documentation": "https://www.home-assistant.io/components/route53", + "requirements": [ + "boto3==1.9.16", + "ipify==1.0.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rova/manifest.json b/homeassistant/components/rova/manifest.json new file mode 100644 index 00000000000..71ec8fcbc9b --- /dev/null +++ b/homeassistant/components/rova/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rova", + "name": "Rova", + "documentation": "https://www.home-assistant.io/components/rova", + "requirements": [ + "rova==0.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rpi_camera/manifest.json b/homeassistant/components/rpi_camera/manifest.json new file mode 100644 index 00000000000..1f905b103fe --- /dev/null +++ b/homeassistant/components/rpi_camera/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "rpi_camera", + "name": "Rpi camera", + "documentation": "https://www.home-assistant.io/components/rpi_camera", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rpi_gpio/manifest.json b/homeassistant/components/rpi_gpio/manifest.json new file mode 100644 index 00000000000..88322708b27 --- /dev/null +++ b/homeassistant/components/rpi_gpio/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rpi_gpio", + "name": "Rpi gpio", + "documentation": "https://www.home-assistant.io/components/rpi_gpio", + "requirements": [ + "RPi.GPIO==0.6.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rpi_gpio_pwm/manifest.json b/homeassistant/components/rpi_gpio_pwm/manifest.json new file mode 100644 index 00000000000..d2ed380d68a --- /dev/null +++ b/homeassistant/components/rpi_gpio_pwm/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rpi_gpio_pwm", + "name": "Rpi gpio pwm", + "documentation": "https://www.home-assistant.io/components/rpi_gpio_pwm", + "requirements": [ + "pwmled==1.4.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rpi_pfio/manifest.json b/homeassistant/components/rpi_pfio/manifest.json new file mode 100644 index 00000000000..7fc724bf90a --- /dev/null +++ b/homeassistant/components/rpi_pfio/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "rpi_pfio", + "name": "Rpi pfio", + "documentation": "https://www.home-assistant.io/components/rpi_pfio", + "requirements": [ + "pifacecommon==4.2.2", + "pifacedigitalio==3.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rpi_rf/manifest.json b/homeassistant/components/rpi_rf/manifest.json new file mode 100644 index 00000000000..e5fffee131e --- /dev/null +++ b/homeassistant/components/rpi_rf/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rpi_rf", + "name": "Rpi rf", + "documentation": "https://www.home-assistant.io/components/rpi_rf", + "requirements": [ + "rpi-rf==0.9.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/rss_feed_template/manifest.json b/homeassistant/components/rss_feed_template/manifest.json new file mode 100644 index 00000000000..c92f6b2a0ba --- /dev/null +++ b/homeassistant/components/rss_feed_template/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "rss_feed_template", + "name": "Rss feed template", + "documentation": "https://www.home-assistant.io/components/rss_feed_template", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/rtorrent/manifest.json b/homeassistant/components/rtorrent/manifest.json new file mode 100644 index 00000000000..ce2dca9e085 --- /dev/null +++ b/homeassistant/components/rtorrent/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "rtorrent", + "name": "Rtorrent", + "documentation": "https://www.home-assistant.io/components/rtorrent", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/russound_rio/manifest.json b/homeassistant/components/russound_rio/manifest.json new file mode 100644 index 00000000000..af81d9c031a --- /dev/null +++ b/homeassistant/components/russound_rio/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "russound_rio", + "name": "Russound rio", + "documentation": "https://www.home-assistant.io/components/russound_rio", + "requirements": [ + "russound_rio==0.1.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/russound_rnet/manifest.json b/homeassistant/components/russound_rnet/manifest.json new file mode 100644 index 00000000000..716f383040f --- /dev/null +++ b/homeassistant/components/russound_rnet/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "russound_rnet", + "name": "Russound rnet", + "documentation": "https://www.home-assistant.io/components/russound_rnet", + "requirements": [ + "russound==0.1.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ruter/manifest.json b/homeassistant/components/ruter/manifest.json new file mode 100644 index 00000000000..57688d0e025 --- /dev/null +++ b/homeassistant/components/ruter/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "ruter", + "name": "Ruter", + "documentation": "https://www.home-assistant.io/components/ruter", + "requirements": [ + "pyruter==1.1.0" + ], + "dependencies": [], + "codeowners": [ + "@ludeeus" + ] +} diff --git a/homeassistant/components/sabnzbd/manifest.json b/homeassistant/components/sabnzbd/manifest.json new file mode 100644 index 00000000000..ae03895f415 --- /dev/null +++ b/homeassistant/components/sabnzbd/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sabnzbd", + "name": "Sabnzbd", + "documentation": "https://www.home-assistant.io/components/sabnzbd", + "requirements": [ + "pysabnzbd==1.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/samsungtv/manifest.json b/homeassistant/components/samsungtv/manifest.json new file mode 100644 index 00000000000..c8825f4ac3f --- /dev/null +++ b/homeassistant/components/samsungtv/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "samsungtv", + "name": "Samsungtv", + "documentation": "https://www.home-assistant.io/components/samsungtv", + "requirements": [ + "samsungctl[websocket]==0.7.1", + "wakeonlan==1.1.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/satel_integra/manifest.json b/homeassistant/components/satel_integra/manifest.json new file mode 100644 index 00000000000..8df19ed90de --- /dev/null +++ b/homeassistant/components/satel_integra/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "satel_integra", + "name": "Satel integra", + "documentation": "https://www.home-assistant.io/components/satel_integra", + "requirements": [ + "satel_integra==0.3.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/scene/manifest.json b/homeassistant/components/scene/manifest.json new file mode 100644 index 00000000000..e1becfd1936 --- /dev/null +++ b/homeassistant/components/scene/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "scene", + "name": "Scene", + "documentation": "https://www.home-assistant.io/components/scene", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/scrape/manifest.json b/homeassistant/components/scrape/manifest.json new file mode 100644 index 00000000000..c7e60140dbf --- /dev/null +++ b/homeassistant/components/scrape/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "scrape", + "name": "Scrape", + "documentation": "https://www.home-assistant.io/components/scrape", + "requirements": [ + "beautifulsoup4==4.7.1" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/script/manifest.json b/homeassistant/components/script/manifest.json new file mode 100644 index 00000000000..56a3c39b7b6 --- /dev/null +++ b/homeassistant/components/script/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "script", + "name": "Script", + "documentation": "https://www.home-assistant.io/components/script", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/scsgate/manifest.json b/homeassistant/components/scsgate/manifest.json new file mode 100644 index 00000000000..d565a5d336d --- /dev/null +++ b/homeassistant/components/scsgate/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "scsgate", + "name": "Scsgate", + "documentation": "https://www.home-assistant.io/components/scsgate", + "requirements": [ + "scsgate==0.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/season/manifest.json b/homeassistant/components/season/manifest.json new file mode 100644 index 00000000000..74bdb3d8b88 --- /dev/null +++ b/homeassistant/components/season/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "season", + "name": "Season", + "documentation": "https://www.home-assistant.io/components/season", + "requirements": [ + "ephem==3.7.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sendgrid/manifest.json b/homeassistant/components/sendgrid/manifest.json new file mode 100644 index 00000000000..47372d861f1 --- /dev/null +++ b/homeassistant/components/sendgrid/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sendgrid", + "name": "Sendgrid", + "documentation": "https://www.home-assistant.io/components/sendgrid", + "requirements": [ + "sendgrid==5.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sense/manifest.json b/homeassistant/components/sense/manifest.json new file mode 100644 index 00000000000..272a4a58f33 --- /dev/null +++ b/homeassistant/components/sense/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sense", + "name": "Sense", + "documentation": "https://www.home-assistant.io/components/sense", + "requirements": [ + "sense_energy==0.7.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sensehat/manifest.json b/homeassistant/components/sensehat/manifest.json new file mode 100644 index 00000000000..cb148c92198 --- /dev/null +++ b/homeassistant/components/sensehat/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sensehat", + "name": "Sensehat", + "documentation": "https://www.home-assistant.io/components/sensehat", + "requirements": [ + "sense-hat==2.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sensibo/manifest.json b/homeassistant/components/sensibo/manifest.json new file mode 100644 index 00000000000..776b8444b82 --- /dev/null +++ b/homeassistant/components/sensibo/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "sensibo", + "name": "Sensibo", + "documentation": "https://www.home-assistant.io/components/sensibo", + "requirements": [ + "pysensibo==1.0.3" + ], + "dependencies": [], + "codeowners": [ + "@andrey-git" + ] +} diff --git a/homeassistant/components/sensor/manifest.json b/homeassistant/components/sensor/manifest.json new file mode 100644 index 00000000000..813bcc27aca --- /dev/null +++ b/homeassistant/components/sensor/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "sensor", + "name": "Sensor", + "documentation": "https://www.home-assistant.io/components/sensor", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/serial/manifest.json b/homeassistant/components/serial/manifest.json new file mode 100644 index 00000000000..945464dbdec --- /dev/null +++ b/homeassistant/components/serial/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "serial", + "name": "Serial", + "documentation": "https://www.home-assistant.io/components/serial", + "requirements": [ + "pyserial-asyncio==0.4" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/serial_pm/manifest.json b/homeassistant/components/serial_pm/manifest.json new file mode 100644 index 00000000000..b2a645c88f3 --- /dev/null +++ b/homeassistant/components/serial_pm/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "serial_pm", + "name": "Serial pm", + "documentation": "https://www.home-assistant.io/components/serial_pm", + "requirements": [ + "pmsensor==0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sesame/manifest.json b/homeassistant/components/sesame/manifest.json new file mode 100644 index 00000000000..9aed47462fe --- /dev/null +++ b/homeassistant/components/sesame/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sesame", + "name": "Sesame", + "documentation": "https://www.home-assistant.io/components/sesame", + "requirements": [ + "pysesame==0.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/seven_segments/manifest.json b/homeassistant/components/seven_segments/manifest.json new file mode 100644 index 00000000000..45ce2f6a7a0 --- /dev/null +++ b/homeassistant/components/seven_segments/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "seven_segments", + "name": "Seven segments", + "documentation": "https://www.home-assistant.io/components/seven_segments", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/seventeentrack/manifest.json b/homeassistant/components/seventeentrack/manifest.json new file mode 100644 index 00000000000..47b36c12291 --- /dev/null +++ b/homeassistant/components/seventeentrack/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "seventeentrack", + "name": "Seventeentrack", + "documentation": "https://www.home-assistant.io/components/seventeentrack", + "requirements": [ + "py17track==2.2.2" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/shell_command/manifest.json b/homeassistant/components/shell_command/manifest.json new file mode 100644 index 00000000000..dfe9a8e8e6f --- /dev/null +++ b/homeassistant/components/shell_command/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "shell_command", + "name": "Shell command", + "documentation": "https://www.home-assistant.io/components/shell_command", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/shiftr/manifest.json b/homeassistant/components/shiftr/manifest.json new file mode 100644 index 00000000000..02718396e5e --- /dev/null +++ b/homeassistant/components/shiftr/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "shiftr", + "name": "Shiftr", + "documentation": "https://www.home-assistant.io/components/shiftr", + "requirements": [ + "paho-mqtt==1.4.0" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/shodan/manifest.json b/homeassistant/components/shodan/manifest.json new file mode 100644 index 00000000000..8898b7976b5 --- /dev/null +++ b/homeassistant/components/shodan/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "shodan", + "name": "Shodan", + "documentation": "https://www.home-assistant.io/components/shodan", + "requirements": [ + "shodan==1.11.1" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/shopping_list/manifest.json b/homeassistant/components/shopping_list/manifest.json new file mode 100644 index 00000000000..b4ea3c2d388 --- /dev/null +++ b/homeassistant/components/shopping_list/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "shopping_list", + "name": "Shopping list", + "documentation": "https://www.home-assistant.io/components/shopping_list", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/sht31/manifest.json b/homeassistant/components/sht31/manifest.json new file mode 100644 index 00000000000..dfa22fc6e23 --- /dev/null +++ b/homeassistant/components/sht31/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "sht31", + "name": "Sht31", + "documentation": "https://www.home-assistant.io/components/sht31", + "requirements": [ + "Adafruit-GPIO==1.0.3", + "Adafruit-SHT31==1.0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sigfox/manifest.json b/homeassistant/components/sigfox/manifest.json new file mode 100644 index 00000000000..1dc8f5255ce --- /dev/null +++ b/homeassistant/components/sigfox/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "sigfox", + "name": "Sigfox", + "documentation": "https://www.home-assistant.io/components/sigfox", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/simplepush/manifest.json b/homeassistant/components/simplepush/manifest.json new file mode 100644 index 00000000000..cbf2833a4f7 --- /dev/null +++ b/homeassistant/components/simplepush/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "simplepush", + "name": "Simplepush", + "documentation": "https://www.home-assistant.io/components/simplepush", + "requirements": [ + "simplepush==1.1.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/simplisafe/manifest.json b/homeassistant/components/simplisafe/manifest.json new file mode 100644 index 00000000000..eac586b355d --- /dev/null +++ b/homeassistant/components/simplisafe/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "simplisafe", + "name": "Simplisafe", + "documentation": "https://www.home-assistant.io/components/simplisafe", + "requirements": [ + "simplisafe-python==3.4.1" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/simulated/manifest.json b/homeassistant/components/simulated/manifest.json new file mode 100644 index 00000000000..b972152aea4 --- /dev/null +++ b/homeassistant/components/simulated/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "simulated", + "name": "Simulated", + "documentation": "https://www.home-assistant.io/components/simulated", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sisyphus/manifest.json b/homeassistant/components/sisyphus/manifest.json new file mode 100644 index 00000000000..b1809e7a572 --- /dev/null +++ b/homeassistant/components/sisyphus/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sisyphus", + "name": "Sisyphus", + "documentation": "https://www.home-assistant.io/components/sisyphus", + "requirements": [ + "sisyphus-control==2.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sky_hub/manifest.json b/homeassistant/components/sky_hub/manifest.json new file mode 100644 index 00000000000..46337918f84 --- /dev/null +++ b/homeassistant/components/sky_hub/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "sky_hub", + "name": "Sky hub", + "documentation": "https://www.home-assistant.io/components/sky_hub", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/skybeacon/manifest.json b/homeassistant/components/skybeacon/manifest.json new file mode 100644 index 00000000000..8d2f758aed2 --- /dev/null +++ b/homeassistant/components/skybeacon/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "skybeacon", + "name": "Skybeacon", + "documentation": "https://www.home-assistant.io/components/skybeacon", + "requirements": [ + "pygatt[GATTTOOL]==3.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/skybell/manifest.json b/homeassistant/components/skybell/manifest.json new file mode 100644 index 00000000000..6a22a698b4c --- /dev/null +++ b/homeassistant/components/skybell/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "skybell", + "name": "Skybell", + "documentation": "https://www.home-assistant.io/components/skybell", + "requirements": [ + "skybellpy==0.3.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/slack/manifest.json b/homeassistant/components/slack/manifest.json new file mode 100644 index 00000000000..3b6e764f814 --- /dev/null +++ b/homeassistant/components/slack/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "slack", + "name": "Slack", + "documentation": "https://www.home-assistant.io/components/slack", + "requirements": [ + "slacker==0.12.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sleepiq/manifest.json b/homeassistant/components/sleepiq/manifest.json new file mode 100644 index 00000000000..339685d32e1 --- /dev/null +++ b/homeassistant/components/sleepiq/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sleepiq", + "name": "Sleepiq", + "documentation": "https://www.home-assistant.io/components/sleepiq", + "requirements": [ + "sleepyq==0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sma/manifest.json b/homeassistant/components/sma/manifest.json new file mode 100644 index 00000000000..e5e7a5bf446 --- /dev/null +++ b/homeassistant/components/sma/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "sma", + "name": "Sma", + "documentation": "https://www.home-assistant.io/components/sma", + "requirements": [ + "pysma==0.3.1" + ], + "dependencies": [], + "codeowners": [ + "@kellerza" + ] +} diff --git a/homeassistant/components/smappee/manifest.json b/homeassistant/components/smappee/manifest.json new file mode 100644 index 00000000000..361802f312e --- /dev/null +++ b/homeassistant/components/smappee/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "smappee", + "name": "Smappee", + "documentation": "https://www.home-assistant.io/components/smappee", + "requirements": [ + "smappy==0.2.16" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/smartthings/manifest.json b/homeassistant/components/smartthings/manifest.json new file mode 100644 index 00000000000..d4baf69b108 --- /dev/null +++ b/homeassistant/components/smartthings/manifest.json @@ -0,0 +1,15 @@ +{ + "domain": "smartthings", + "name": "Smartthings", + "documentation": "https://www.home-assistant.io/components/smartthings", + "requirements": [ + "pysmartapp==0.3.2", + "pysmartthings==0.6.7" + ], + "dependencies": [ + "webhook" + ], + "codeowners": [ + "@andrewsayre" + ] +} diff --git a/homeassistant/components/smhi/manifest.json b/homeassistant/components/smhi/manifest.json new file mode 100644 index 00000000000..e4ad478e033 --- /dev/null +++ b/homeassistant/components/smhi/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "smhi", + "name": "Smhi", + "documentation": "https://www.home-assistant.io/components/smhi", + "requirements": [ + "smhi-pkg==1.0.10" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/smtp/manifest.json b/homeassistant/components/smtp/manifest.json new file mode 100644 index 00000000000..2e1a8d826ce --- /dev/null +++ b/homeassistant/components/smtp/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "smtp", + "name": "Smtp", + "documentation": "https://www.home-assistant.io/components/smtp", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/snapcast/manifest.json b/homeassistant/components/snapcast/manifest.json new file mode 100644 index 00000000000..70c9db7dada --- /dev/null +++ b/homeassistant/components/snapcast/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "snapcast", + "name": "Snapcast", + "documentation": "https://www.home-assistant.io/components/snapcast", + "requirements": [ + "snapcast==2.0.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/snips/manifest.json b/homeassistant/components/snips/manifest.json new file mode 100644 index 00000000000..58fddb7a3f4 --- /dev/null +++ b/homeassistant/components/snips/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "snips", + "name": "Snips", + "documentation": "https://www.home-assistant.io/components/snips", + "requirements": [], + "dependencies": [ + "mqtt" + ], + "codeowners": [] +} diff --git a/homeassistant/components/snmp/manifest.json b/homeassistant/components/snmp/manifest.json new file mode 100644 index 00000000000..aeaa3451683 --- /dev/null +++ b/homeassistant/components/snmp/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "snmp", + "name": "Snmp", + "documentation": "https://www.home-assistant.io/components/snmp", + "requirements": [ + "pysnmp==4.4.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sochain/manifest.json b/homeassistant/components/sochain/manifest.json new file mode 100644 index 00000000000..23fad3683cb --- /dev/null +++ b/homeassistant/components/sochain/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sochain", + "name": "Sochain", + "documentation": "https://www.home-assistant.io/components/sochain", + "requirements": [ + "python-sochain-api==0.0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/socialblade/manifest.json b/homeassistant/components/socialblade/manifest.json new file mode 100644 index 00000000000..e800bd7266a --- /dev/null +++ b/homeassistant/components/socialblade/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "socialblade", + "name": "Socialblade", + "documentation": "https://www.home-assistant.io/components/socialblade", + "requirements": [ + "socialbladeclient==0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/solaredge/manifest.json b/homeassistant/components/solaredge/manifest.json new file mode 100644 index 00000000000..b2707a0a937 --- /dev/null +++ b/homeassistant/components/solaredge/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "solaredge", + "name": "Solaredge", + "documentation": "https://www.home-assistant.io/components/solaredge", + "requirements": [ + "solaredge==0.0.2", + "stringcase==1.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sonarr/manifest.json b/homeassistant/components/sonarr/manifest.json new file mode 100644 index 00000000000..bc0235ec5b3 --- /dev/null +++ b/homeassistant/components/sonarr/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "sonarr", + "name": "Sonarr", + "documentation": "https://www.home-assistant.io/components/sonarr", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/songpal/manifest.json b/homeassistant/components/songpal/manifest.json new file mode 100644 index 00000000000..0d1af7053b2 --- /dev/null +++ b/homeassistant/components/songpal/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "songpal", + "name": "Songpal", + "documentation": "https://www.home-assistant.io/components/songpal", + "requirements": [ + "python-songpal==0.0.9.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sonos/manifest.json b/homeassistant/components/sonos/manifest.json new file mode 100644 index 00000000000..3fa5ac0354a --- /dev/null +++ b/homeassistant/components/sonos/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "sonos", + "name": "Sonos", + "documentation": "https://www.home-assistant.io/components/sonos", + "requirements": [ + "pysonos==0.0.8" + ], + "dependencies": [], + "codeowners": [ + "@amelchio" + ] +} diff --git a/homeassistant/components/sony_projector/manifest.json b/homeassistant/components/sony_projector/manifest.json new file mode 100644 index 00000000000..1cc25d93f59 --- /dev/null +++ b/homeassistant/components/sony_projector/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sony_projector", + "name": "Sony projector", + "documentation": "https://www.home-assistant.io/components/sony_projector", + "requirements": [ + "pysdcp==1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/soundtouch/manifest.json b/homeassistant/components/soundtouch/manifest.json new file mode 100644 index 00000000000..eba60bc6e34 --- /dev/null +++ b/homeassistant/components/soundtouch/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "soundtouch", + "name": "Soundtouch", + "documentation": "https://www.home-assistant.io/components/soundtouch", + "requirements": [ + "libsoundtouch==0.7.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/spaceapi/manifest.json b/homeassistant/components/spaceapi/manifest.json new file mode 100644 index 00000000000..03aa5c0a1f7 --- /dev/null +++ b/homeassistant/components/spaceapi/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "spaceapi", + "name": "Spaceapi", + "documentation": "https://www.home-assistant.io/components/spaceapi", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/spc/manifest.json b/homeassistant/components/spc/manifest.json new file mode 100644 index 00000000000..572d4b04b87 --- /dev/null +++ b/homeassistant/components/spc/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "spc", + "name": "Spc", + "documentation": "https://www.home-assistant.io/components/spc", + "requirements": [ + "pyspcwebgw==0.4.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/speedtestdotnet/manifest.json b/homeassistant/components/speedtestdotnet/manifest.json new file mode 100644 index 00000000000..91b7e7c5c0f --- /dev/null +++ b/homeassistant/components/speedtestdotnet/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "speedtestdotnet", + "name": "Speedtestdotnet", + "documentation": "https://www.home-assistant.io/components/speedtestdotnet", + "requirements": [ + "speedtest-cli==2.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/spider/manifest.json b/homeassistant/components/spider/manifest.json new file mode 100644 index 00000000000..4cd7a467737 --- /dev/null +++ b/homeassistant/components/spider/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "spider", + "name": "Spider", + "documentation": "https://www.home-assistant.io/components/spider", + "requirements": [ + "spiderpy==1.3.1" + ], + "dependencies": [], + "codeowners": [ + "@peternijssen" + ] +} diff --git a/homeassistant/components/splunk/manifest.json b/homeassistant/components/splunk/manifest.json new file mode 100644 index 00000000000..2e81da3409a --- /dev/null +++ b/homeassistant/components/splunk/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "splunk", + "name": "Splunk", + "documentation": "https://www.home-assistant.io/components/splunk", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/spotcrime/manifest.json b/homeassistant/components/spotcrime/manifest.json new file mode 100644 index 00000000000..49b8742c53e --- /dev/null +++ b/homeassistant/components/spotcrime/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "spotcrime", + "name": "Spotcrime", + "documentation": "https://www.home-assistant.io/components/spotcrime", + "requirements": [ + "spotcrime==1.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/spotify/manifest.json b/homeassistant/components/spotify/manifest.json new file mode 100644 index 00000000000..8c2c72e4d2a --- /dev/null +++ b/homeassistant/components/spotify/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "spotify", + "name": "Spotify", + "documentation": "https://www.home-assistant.io/components/spotify", + "requirements": [ + "spotipy-homeassistant==2.4.4.dev1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sql/manifest.json b/homeassistant/components/sql/manifest.json new file mode 100644 index 00000000000..9a26e676018 --- /dev/null +++ b/homeassistant/components/sql/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "sql", + "name": "Sql", + "documentation": "https://www.home-assistant.io/components/sql", + "requirements": [ + "sqlalchemy==1.3.0" + ], + "dependencies": [], + "codeowners": [ + "@dgomes" + ] +} diff --git a/homeassistant/components/squeezebox/manifest.json b/homeassistant/components/squeezebox/manifest.json new file mode 100644 index 00000000000..ae124d6c03d --- /dev/null +++ b/homeassistant/components/squeezebox/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "squeezebox", + "name": "Squeezebox", + "documentation": "https://www.home-assistant.io/components/squeezebox", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/srp_energy/manifest.json b/homeassistant/components/srp_energy/manifest.json new file mode 100644 index 00000000000..050a78223c1 --- /dev/null +++ b/homeassistant/components/srp_energy/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "srp_energy", + "name": "Srp energy", + "documentation": "https://www.home-assistant.io/components/srp_energy", + "requirements": [ + "srpenergy==1.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/starlingbank/manifest.json b/homeassistant/components/starlingbank/manifest.json new file mode 100644 index 00000000000..1314fda5099 --- /dev/null +++ b/homeassistant/components/starlingbank/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "starlingbank", + "name": "Starlingbank", + "documentation": "https://www.home-assistant.io/components/starlingbank", + "requirements": [ + "starlingbank==3.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/startca/manifest.json b/homeassistant/components/startca/manifest.json new file mode 100644 index 00000000000..1d13936f592 --- /dev/null +++ b/homeassistant/components/startca/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "startca", + "name": "Startca", + "documentation": "https://www.home-assistant.io/components/startca", + "requirements": [ + "xmltodict==0.11.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/statistics/manifest.json b/homeassistant/components/statistics/manifest.json new file mode 100644 index 00000000000..49e476a6876 --- /dev/null +++ b/homeassistant/components/statistics/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "statistics", + "name": "Statistics", + "documentation": "https://www.home-assistant.io/components/statistics", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/statsd/manifest.json b/homeassistant/components/statsd/manifest.json new file mode 100644 index 00000000000..20f4cc7f544 --- /dev/null +++ b/homeassistant/components/statsd/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "statsd", + "name": "Statsd", + "documentation": "https://www.home-assistant.io/components/statsd", + "requirements": [ + "statsd==3.2.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/steam_online/manifest.json b/homeassistant/components/steam_online/manifest.json new file mode 100644 index 00000000000..735a1869c34 --- /dev/null +++ b/homeassistant/components/steam_online/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "steam_online", + "name": "Steam online", + "documentation": "https://www.home-assistant.io/components/steam_online", + "requirements": [ + "steamodd==4.21" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/stream/manifest.json b/homeassistant/components/stream/manifest.json new file mode 100644 index 00000000000..9020ffb5b2b --- /dev/null +++ b/homeassistant/components/stream/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "stream", + "name": "Stream", + "documentation": "https://www.home-assistant.io/components/stream", + "requirements": [ + "av==6.1.2" + ], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/stride/manifest.json b/homeassistant/components/stride/manifest.json new file mode 100644 index 00000000000..307f4c929cf --- /dev/null +++ b/homeassistant/components/stride/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "stride", + "name": "Stride", + "documentation": "https://www.home-assistant.io/components/stride", + "requirements": [ + "pystride==0.1.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sun/manifest.json b/homeassistant/components/sun/manifest.json new file mode 100644 index 00000000000..2ef89da8f69 --- /dev/null +++ b/homeassistant/components/sun/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "sun", + "name": "Sun", + "documentation": "https://www.home-assistant.io/components/sun", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/supervisord/manifest.json b/homeassistant/components/supervisord/manifest.json new file mode 100644 index 00000000000..1fc849165ef --- /dev/null +++ b/homeassistant/components/supervisord/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "supervisord", + "name": "Supervisord", + "documentation": "https://www.home-assistant.io/components/supervisord", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/swiss_hydrological_data/manifest.json b/homeassistant/components/swiss_hydrological_data/manifest.json new file mode 100644 index 00000000000..d6b18d6cba8 --- /dev/null +++ b/homeassistant/components/swiss_hydrological_data/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "swiss_hydrological_data", + "name": "Swiss hydrological data", + "documentation": "https://www.home-assistant.io/components/swiss_hydrological_data", + "requirements": [ + "swisshydrodata==0.0.3" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/swiss_public_transport/manifest.json b/homeassistant/components/swiss_public_transport/manifest.json new file mode 100644 index 00000000000..99dcdbd0c88 --- /dev/null +++ b/homeassistant/components/swiss_public_transport/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "swiss_public_transport", + "name": "Swiss public transport", + "documentation": "https://www.home-assistant.io/components/swiss_public_transport", + "requirements": [ + "python_opendata_transport==0.1.4" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/swisscom/manifest.json b/homeassistant/components/swisscom/manifest.json new file mode 100644 index 00000000000..e52fda34083 --- /dev/null +++ b/homeassistant/components/swisscom/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "swisscom", + "name": "Swisscom", + "documentation": "https://www.home-assistant.io/components/swisscom", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/switch/manifest.json b/homeassistant/components/switch/manifest.json new file mode 100644 index 00000000000..0f287251582 --- /dev/null +++ b/homeassistant/components/switch/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "switch", + "name": "Switch", + "documentation": "https://www.home-assistant.io/components/switch", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [] +} diff --git a/homeassistant/components/switchbot/manifest.json b/homeassistant/components/switchbot/manifest.json new file mode 100644 index 00000000000..0143855db37 --- /dev/null +++ b/homeassistant/components/switchbot/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "switchbot", + "name": "Switchbot", + "documentation": "https://www.home-assistant.io/components/switchbot", + "requirements": [ + "PySwitchbot==0.5" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen" + ] +} diff --git a/homeassistant/components/switchmate/manifest.json b/homeassistant/components/switchmate/manifest.json new file mode 100644 index 00000000000..9461c776d6d --- /dev/null +++ b/homeassistant/components/switchmate/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "switchmate", + "name": "Switchmate", + "documentation": "https://www.home-assistant.io/components/switchmate", + "requirements": [ + "pySwitchmate==0.4.5" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen" + ] +} diff --git a/homeassistant/components/syncthru/manifest.json b/homeassistant/components/syncthru/manifest.json new file mode 100644 index 00000000000..1aadeb54909 --- /dev/null +++ b/homeassistant/components/syncthru/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "syncthru", + "name": "Syncthru", + "documentation": "https://www.home-assistant.io/components/syncthru", + "requirements": [ + "pysyncthru==0.3.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/synology/manifest.json b/homeassistant/components/synology/manifest.json new file mode 100644 index 00000000000..a108f5fa983 --- /dev/null +++ b/homeassistant/components/synology/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "synology", + "name": "Synology", + "documentation": "https://www.home-assistant.io/components/synology", + "requirements": [ + "py-synology==0.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/synology_chat/manifest.json b/homeassistant/components/synology_chat/manifest.json new file mode 100644 index 00000000000..d35b1d8c902 --- /dev/null +++ b/homeassistant/components/synology_chat/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "synology_chat", + "name": "Synology chat", + "documentation": "https://www.home-assistant.io/components/synology_chat", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/synology_srm/manifest.json b/homeassistant/components/synology_srm/manifest.json new file mode 100644 index 00000000000..fa89577f26e --- /dev/null +++ b/homeassistant/components/synology_srm/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "synology_srm", + "name": "Synology srm", + "documentation": "https://www.home-assistant.io/components/synology_srm", + "requirements": [ + "synology-srm==0.0.6" + ], + "dependencies": [], + "codeowners": [ + "@aerialls" + ] +} diff --git a/homeassistant/components/synologydsm/manifest.json b/homeassistant/components/synologydsm/manifest.json new file mode 100644 index 00000000000..fcce2e52a21 --- /dev/null +++ b/homeassistant/components/synologydsm/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "synologydsm", + "name": "Synologydsm", + "documentation": "https://www.home-assistant.io/components/synologydsm", + "requirements": [ + "python-synology==0.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/syslog/manifest.json b/homeassistant/components/syslog/manifest.json new file mode 100644 index 00000000000..19836ffa67f --- /dev/null +++ b/homeassistant/components/syslog/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "syslog", + "name": "Syslog", + "documentation": "https://www.home-assistant.io/components/syslog", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/system_health/manifest.json b/homeassistant/components/system_health/manifest.json new file mode 100644 index 00000000000..9c2b7bcae39 --- /dev/null +++ b/homeassistant/components/system_health/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "system_health", + "name": "System health", + "documentation": "https://www.home-assistant.io/components/system_health", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/system_log/manifest.json b/homeassistant/components/system_log/manifest.json new file mode 100644 index 00000000000..01f70af4a15 --- /dev/null +++ b/homeassistant/components/system_log/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "system_log", + "name": "System log", + "documentation": "https://www.home-assistant.io/components/system_log", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/systemmonitor/manifest.json b/homeassistant/components/systemmonitor/manifest.json new file mode 100644 index 00000000000..591e710a871 --- /dev/null +++ b/homeassistant/components/systemmonitor/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "systemmonitor", + "name": "Systemmonitor", + "documentation": "https://www.home-assistant.io/components/systemmonitor", + "requirements": [ + "psutil==5.6.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/sytadin/manifest.json b/homeassistant/components/sytadin/manifest.json new file mode 100644 index 00000000000..0efc84fc552 --- /dev/null +++ b/homeassistant/components/sytadin/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "sytadin", + "name": "Sytadin", + "documentation": "https://www.home-assistant.io/components/sytadin", + "requirements": [ + "beautifulsoup4==4.7.1" + ], + "dependencies": [], + "codeowners": [ + "@gautric" + ] +} diff --git a/homeassistant/components/tado/manifest.json b/homeassistant/components/tado/manifest.json new file mode 100644 index 00000000000..8d42cde1c05 --- /dev/null +++ b/homeassistant/components/tado/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "tado", + "name": "Tado", + "documentation": "https://www.home-assistant.io/components/tado", + "requirements": [ + "python-tado==0.2.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tahoma/manifest.json b/homeassistant/components/tahoma/manifest.json new file mode 100644 index 00000000000..ca3ab0bc882 --- /dev/null +++ b/homeassistant/components/tahoma/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "tahoma", + "name": "Tahoma", + "documentation": "https://www.home-assistant.io/components/tahoma", + "requirements": [ + "tahoma-api==0.0.14" + ], + "dependencies": [], + "codeowners": [ + "@philklei" + ] +} diff --git a/homeassistant/components/tank_utility/manifest.json b/homeassistant/components/tank_utility/manifest.json new file mode 100644 index 00000000000..04ffb48f396 --- /dev/null +++ b/homeassistant/components/tank_utility/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "tank_utility", + "name": "Tank utility", + "documentation": "https://www.home-assistant.io/components/tank_utility", + "requirements": [ + "tank_utility==1.4.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tapsaff/manifest.json b/homeassistant/components/tapsaff/manifest.json new file mode 100644 index 00000000000..6008ef38cc6 --- /dev/null +++ b/homeassistant/components/tapsaff/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "tapsaff", + "name": "Tapsaff", + "documentation": "https://www.home-assistant.io/components/tapsaff", + "requirements": [ + "tapsaff==0.2.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tautulli/manifest.json b/homeassistant/components/tautulli/manifest.json new file mode 100644 index 00000000000..d49b5280181 --- /dev/null +++ b/homeassistant/components/tautulli/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "tautulli", + "name": "Tautulli", + "documentation": "https://www.home-assistant.io/components/tautulli", + "requirements": [ + "pytautulli==0.5.0" + ], + "dependencies": [], + "codeowners": [ + "@ludeeus" + ] +} diff --git a/homeassistant/components/tcp/manifest.json b/homeassistant/components/tcp/manifest.json new file mode 100644 index 00000000000..2ff29a27f31 --- /dev/null +++ b/homeassistant/components/tcp/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "tcp", + "name": "Tcp", + "documentation": "https://www.home-assistant.io/components/tcp", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ted5000/manifest.json b/homeassistant/components/ted5000/manifest.json new file mode 100644 index 00000000000..cf0439345dc --- /dev/null +++ b/homeassistant/components/ted5000/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ted5000", + "name": "Ted5000", + "documentation": "https://www.home-assistant.io/components/ted5000", + "requirements": [ + "xmltodict==0.11.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/teksavvy/manifest.json b/homeassistant/components/teksavvy/manifest.json new file mode 100644 index 00000000000..14afdec3b71 --- /dev/null +++ b/homeassistant/components/teksavvy/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "teksavvy", + "name": "Teksavvy", + "documentation": "https://www.home-assistant.io/components/teksavvy", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/telegram/manifest.json b/homeassistant/components/telegram/manifest.json new file mode 100644 index 00000000000..6ace3cd5aa0 --- /dev/null +++ b/homeassistant/components/telegram/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "telegram", + "name": "Telegram", + "documentation": "https://www.home-assistant.io/components/telegram", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/telegram_bot/manifest.json b/homeassistant/components/telegram_bot/manifest.json new file mode 100644 index 00000000000..ba52cd4e935 --- /dev/null +++ b/homeassistant/components/telegram_bot/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "telegram_bot", + "name": "Telegram bot", + "documentation": "https://www.home-assistant.io/components/telegram_bot", + "requirements": [ + "python-telegram-bot==11.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tellduslive/manifest.json b/homeassistant/components/tellduslive/manifest.json new file mode 100644 index 00000000000..2e6233f426c --- /dev/null +++ b/homeassistant/components/tellduslive/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "tellduslive", + "name": "Tellduslive", + "documentation": "https://www.home-assistant.io/components/tellduslive", + "requirements": [ + "tellduslive==0.10.10" + ], + "dependencies": [], + "codeowners": [ + "@fredrike" + ] +} diff --git a/homeassistant/components/tellstick/manifest.json b/homeassistant/components/tellstick/manifest.json new file mode 100644 index 00000000000..c50ba514f2a --- /dev/null +++ b/homeassistant/components/tellstick/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "tellstick", + "name": "Tellstick", + "documentation": "https://www.home-assistant.io/components/tellstick", + "requirements": [ + "tellcore-net==0.4", + "tellcore-py==1.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/telnet/manifest.json b/homeassistant/components/telnet/manifest.json new file mode 100644 index 00000000000..58f5e15cc1a --- /dev/null +++ b/homeassistant/components/telnet/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "telnet", + "name": "Telnet", + "documentation": "https://www.home-assistant.io/components/telnet", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/temper/manifest.json b/homeassistant/components/temper/manifest.json new file mode 100644 index 00000000000..0e60c957d9d --- /dev/null +++ b/homeassistant/components/temper/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "temper", + "name": "Temper", + "documentation": "https://www.home-assistant.io/components/temper", + "requirements": [ + "temperusb==1.5.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/template/manifest.json b/homeassistant/components/template/manifest.json new file mode 100644 index 00000000000..c8406c9d084 --- /dev/null +++ b/homeassistant/components/template/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "template", + "name": "Template", + "documentation": "https://www.home-assistant.io/components/template", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@PhracturedBlue" + ] +} diff --git a/homeassistant/components/tensorflow/manifest.json b/homeassistant/components/tensorflow/manifest.json new file mode 100644 index 00000000000..e9643f36b67 --- /dev/null +++ b/homeassistant/components/tensorflow/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "tensorflow", + "name": "Tensorflow", + "documentation": "https://www.home-assistant.io/components/tensorflow", + "requirements": [ + "numpy==1.16.2", + "pillow==5.4.1", + "protobuf==3.6.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tesla/manifest.json b/homeassistant/components/tesla/manifest.json new file mode 100644 index 00000000000..ab32a64e670 --- /dev/null +++ b/homeassistant/components/tesla/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "tesla", + "name": "Tesla", + "documentation": "https://www.home-assistant.io/components/tesla", + "requirements": [ + "teslajsonpy==0.0.25" + ], + "dependencies": [], + "codeowners": [ + "@zabuldon" + ] +} diff --git a/homeassistant/components/tfiac/manifest.json b/homeassistant/components/tfiac/manifest.json new file mode 100644 index 00000000000..9997ae00f0a --- /dev/null +++ b/homeassistant/components/tfiac/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "tfiac", + "name": "Tfiac", + "documentation": "https://www.home-assistant.io/components/tfiac", + "requirements": [ + "pytfiac==0.3" + ], + "dependencies": [], + "codeowners": [ + "@fredrike", + "@mellado" + ] +} diff --git a/homeassistant/components/thermoworks_smoke/manifest.json b/homeassistant/components/thermoworks_smoke/manifest.json new file mode 100644 index 00000000000..fab670627ba --- /dev/null +++ b/homeassistant/components/thermoworks_smoke/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "thermoworks_smoke", + "name": "Thermoworks smoke", + "documentation": "https://www.home-assistant.io/components/thermoworks_smoke", + "requirements": [ + "stringcase==1.2.0", + "thermoworks_smoke==0.1.8" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/thethingsnetwork/manifest.json b/homeassistant/components/thethingsnetwork/manifest.json new file mode 100644 index 00000000000..8d6082d74bf --- /dev/null +++ b/homeassistant/components/thethingsnetwork/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "thethingsnetwork", + "name": "Thethingsnetwork", + "documentation": "https://www.home-assistant.io/components/thethingsnetwork", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/thingspeak/manifest.json b/homeassistant/components/thingspeak/manifest.json new file mode 100644 index 00000000000..482bb94ac2a --- /dev/null +++ b/homeassistant/components/thingspeak/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "thingspeak", + "name": "Thingspeak", + "documentation": "https://www.home-assistant.io/components/thingspeak", + "requirements": [ + "thingspeak==0.4.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/thinkingcleaner/manifest.json b/homeassistant/components/thinkingcleaner/manifest.json new file mode 100644 index 00000000000..4e43270a5e0 --- /dev/null +++ b/homeassistant/components/thinkingcleaner/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "thinkingcleaner", + "name": "Thinkingcleaner", + "documentation": "https://www.home-assistant.io/components/thinkingcleaner", + "requirements": [ + "pythinkingcleaner==0.0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/thomson/manifest.json b/homeassistant/components/thomson/manifest.json new file mode 100644 index 00000000000..063c84d4ff7 --- /dev/null +++ b/homeassistant/components/thomson/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "thomson", + "name": "Thomson", + "documentation": "https://www.home-assistant.io/components/thomson", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/threshold/manifest.json b/homeassistant/components/threshold/manifest.json new file mode 100644 index 00000000000..107b4351505 --- /dev/null +++ b/homeassistant/components/threshold/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "threshold", + "name": "Threshold", + "documentation": "https://www.home-assistant.io/components/threshold", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/tibber/manifest.json b/homeassistant/components/tibber/manifest.json new file mode 100644 index 00000000000..8c6982f9764 --- /dev/null +++ b/homeassistant/components/tibber/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "tibber", + "name": "Tibber", + "documentation": "https://www.home-assistant.io/components/tibber", + "requirements": [ + "pyTibber==0.10.1" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen" + ] +} diff --git a/homeassistant/components/tikteck/manifest.json b/homeassistant/components/tikteck/manifest.json new file mode 100644 index 00000000000..7edaf9ba978 --- /dev/null +++ b/homeassistant/components/tikteck/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "tikteck", + "name": "Tikteck", + "documentation": "https://www.home-assistant.io/components/tikteck", + "requirements": [ + "tikteck==0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tile/manifest.json b/homeassistant/components/tile/manifest.json new file mode 100644 index 00000000000..3d26e8315ae --- /dev/null +++ b/homeassistant/components/tile/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "tile", + "name": "Tile", + "documentation": "https://www.home-assistant.io/components/tile", + "requirements": [ + "pytile==2.0.6" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/time_date/manifest.json b/homeassistant/components/time_date/manifest.json new file mode 100644 index 00000000000..bd620d4a18f --- /dev/null +++ b/homeassistant/components/time_date/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "time_date", + "name": "Time date", + "documentation": "https://www.home-assistant.io/components/time_date", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/timer/manifest.json b/homeassistant/components/timer/manifest.json new file mode 100644 index 00000000000..76a506faee8 --- /dev/null +++ b/homeassistant/components/timer/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "timer", + "name": "Timer", + "documentation": "https://www.home-assistant.io/components/timer", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tod/manifest.json b/homeassistant/components/tod/manifest.json new file mode 100644 index 00000000000..ff67748d64c --- /dev/null +++ b/homeassistant/components/tod/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "tod", + "name": "Tod", + "documentation": "https://www.home-assistant.io/components/tod", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/todoist/manifest.json b/homeassistant/components/todoist/manifest.json new file mode 100644 index 00000000000..7a6b4e2efab --- /dev/null +++ b/homeassistant/components/todoist/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "todoist", + "name": "Todoist", + "documentation": "https://www.home-assistant.io/components/todoist", + "requirements": [ + "todoist-python==7.0.17" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tof/manifest.json b/homeassistant/components/tof/manifest.json new file mode 100644 index 00000000000..4e1857379c0 --- /dev/null +++ b/homeassistant/components/tof/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "tof", + "name": "Tof", + "documentation": "https://www.home-assistant.io/components/tof", + "requirements": [ + "VL53L1X2==0.1.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tomato/manifest.json b/homeassistant/components/tomato/manifest.json new file mode 100644 index 00000000000..615ea9ecd7e --- /dev/null +++ b/homeassistant/components/tomato/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "tomato", + "name": "Tomato", + "documentation": "https://www.home-assistant.io/components/tomato", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/toon/manifest.json b/homeassistant/components/toon/manifest.json new file mode 100644 index 00000000000..7dbf6768db6 --- /dev/null +++ b/homeassistant/components/toon/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "toon", + "name": "Toon", + "documentation": "https://www.home-assistant.io/components/toon", + "requirements": [ + "toonapilib==3.2.2" + ], + "dependencies": [], + "codeowners": [ + "@frenck" + ] +} diff --git a/homeassistant/components/torque/manifest.json b/homeassistant/components/torque/manifest.json new file mode 100644 index 00000000000..3e69cb62e68 --- /dev/null +++ b/homeassistant/components/torque/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "torque", + "name": "Torque", + "documentation": "https://www.home-assistant.io/components/torque", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json new file mode 100644 index 00000000000..adb60599ae5 --- /dev/null +++ b/homeassistant/components/totalconnect/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "totalconnect", + "name": "Totalconnect", + "documentation": "https://www.home-assistant.io/components/totalconnect", + "requirements": [ + "total_connect_client==0.25" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/touchline/manifest.json b/homeassistant/components/touchline/manifest.json new file mode 100644 index 00000000000..5b8b4f521ee --- /dev/null +++ b/homeassistant/components/touchline/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "touchline", + "name": "Touchline", + "documentation": "https://www.home-assistant.io/components/touchline", + "requirements": [ + "pytouchline==0.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tplink/manifest.json b/homeassistant/components/tplink/manifest.json new file mode 100644 index 00000000000..c2a9ee2ee41 --- /dev/null +++ b/homeassistant/components/tplink/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "tplink", + "name": "Tplink", + "documentation": "https://www.home-assistant.io/components/tplink", + "requirements": [ + "pyHS100==0.3.4", + "tplink==0.2.1" + ], + "dependencies": [], + "codeowners": [ + "@rytilahti" + ] +} diff --git a/homeassistant/components/tplink_lte/manifest.json b/homeassistant/components/tplink_lte/manifest.json new file mode 100644 index 00000000000..e3efd8c8331 --- /dev/null +++ b/homeassistant/components/tplink_lte/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "tplink_lte", + "name": "Tplink lte", + "documentation": "https://www.home-assistant.io/components/tplink_lte", + "requirements": [ + "tp-connected==0.0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/traccar/manifest.json b/homeassistant/components/traccar/manifest.json new file mode 100644 index 00000000000..57bd1383363 --- /dev/null +++ b/homeassistant/components/traccar/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "traccar", + "name": "Traccar", + "documentation": "https://www.home-assistant.io/components/traccar", + "requirements": [ + "pytraccar==0.5.0", + "stringcase==1.2.0" + ], + "dependencies": [], + "codeowners": [ + "@ludeeus" + ] +} diff --git a/homeassistant/components/trackr/manifest.json b/homeassistant/components/trackr/manifest.json new file mode 100644 index 00000000000..6ad348176ba --- /dev/null +++ b/homeassistant/components/trackr/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "trackr", + "name": "Trackr", + "documentation": "https://www.home-assistant.io/components/trackr", + "requirements": [ + "pytrackr==0.0.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tradfri/manifest.json b/homeassistant/components/tradfri/manifest.json new file mode 100644 index 00000000000..19e8348e987 --- /dev/null +++ b/homeassistant/components/tradfri/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "tradfri", + "name": "Tradfri", + "documentation": "https://www.home-assistant.io/components/tradfri", + "requirements": [ + "pytradfri[async]==6.0.1" + ], + "dependencies": [], + "codeowners": [ + "@ggravlingen" + ] +} diff --git a/homeassistant/components/trafikverket_weatherstation/manifest.json b/homeassistant/components/trafikverket_weatherstation/manifest.json new file mode 100644 index 00000000000..9bd734fe094 --- /dev/null +++ b/homeassistant/components/trafikverket_weatherstation/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "trafikverket_weatherstation", + "name": "Trafikverket weatherstation", + "documentation": "https://www.home-assistant.io/components/trafikverket_weatherstation", + "requirements": [ + "pytrafikverket==0.1.5.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/transmission/manifest.json b/homeassistant/components/transmission/manifest.json new file mode 100644 index 00000000000..bc5da64fcac --- /dev/null +++ b/homeassistant/components/transmission/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "transmission", + "name": "Transmission", + "documentation": "https://www.home-assistant.io/components/transmission", + "requirements": [ + "transmissionrpc==0.11" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/transport_nsw/manifest.json b/homeassistant/components/transport_nsw/manifest.json new file mode 100644 index 00000000000..491cce7407f --- /dev/null +++ b/homeassistant/components/transport_nsw/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "transport_nsw", + "name": "Transport nsw", + "documentation": "https://www.home-assistant.io/components/transport_nsw", + "requirements": [ + "PyTransportNSW==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/travisci/manifest.json b/homeassistant/components/travisci/manifest.json new file mode 100644 index 00000000000..eb553fbe73c --- /dev/null +++ b/homeassistant/components/travisci/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "travisci", + "name": "Travisci", + "documentation": "https://www.home-assistant.io/components/travisci", + "requirements": [ + "TravisPy==0.3.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/trend/manifest.json b/homeassistant/components/trend/manifest.json new file mode 100644 index 00000000000..865d7064db2 --- /dev/null +++ b/homeassistant/components/trend/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "trend", + "name": "Trend", + "documentation": "https://www.home-assistant.io/components/trend", + "requirements": [ + "numpy==1.16.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/tts/manifest.json b/homeassistant/components/tts/manifest.json new file mode 100644 index 00000000000..ce600473cc5 --- /dev/null +++ b/homeassistant/components/tts/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "tts", + "name": "Tts", + "documentation": "https://www.home-assistant.io/components/tts", + "requirements": [ + "mutagen==1.42.0" + ], + "dependencies": [ + "http" + ], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/tuya/manifest.json b/homeassistant/components/tuya/manifest.json new file mode 100644 index 00000000000..f4361c89909 --- /dev/null +++ b/homeassistant/components/tuya/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "tuya", + "name": "Tuya", + "documentation": "https://www.home-assistant.io/components/tuya", + "requirements": [ + "tuyapy==0.1.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/twilio/manifest.json b/homeassistant/components/twilio/manifest.json new file mode 100644 index 00000000000..dfb7dd4b14d --- /dev/null +++ b/homeassistant/components/twilio/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "twilio", + "name": "Twilio", + "documentation": "https://www.home-assistant.io/components/twilio", + "requirements": [ + "twilio==6.19.1" + ], + "dependencies": [ + "webhook" + ], + "codeowners": [] +} diff --git a/homeassistant/components/twilio_call/manifest.json b/homeassistant/components/twilio_call/manifest.json new file mode 100644 index 00000000000..85545084c7b --- /dev/null +++ b/homeassistant/components/twilio_call/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "twilio_call", + "name": "Twilio call", + "documentation": "https://www.home-assistant.io/components/twilio_call", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/twilio_sms/manifest.json b/homeassistant/components/twilio_sms/manifest.json new file mode 100644 index 00000000000..25cee38dbc8 --- /dev/null +++ b/homeassistant/components/twilio_sms/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "twilio_sms", + "name": "Twilio sms", + "documentation": "https://www.home-assistant.io/components/twilio_sms", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/twitch/manifest.json b/homeassistant/components/twitch/manifest.json new file mode 100644 index 00000000000..80bc795b536 --- /dev/null +++ b/homeassistant/components/twitch/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "twitch", + "name": "Twitch", + "documentation": "https://www.home-assistant.io/components/twitch", + "requirements": [ + "python-twitch-client==0.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/twitter/manifest.json b/homeassistant/components/twitter/manifest.json new file mode 100644 index 00000000000..e721bb669ed --- /dev/null +++ b/homeassistant/components/twitter/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "twitter", + "name": "Twitter", + "documentation": "https://www.home-assistant.io/components/twitter", + "requirements": [ + "TwitterAPI==2.5.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ubee/manifest.json b/homeassistant/components/ubee/manifest.json new file mode 100644 index 00000000000..c19c72e8686 --- /dev/null +++ b/homeassistant/components/ubee/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ubee", + "name": "Ubee", + "documentation": "https://www.home-assistant.io/components/ubee", + "requirements": [ + "pyubee==0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/uber/manifest.json b/homeassistant/components/uber/manifest.json new file mode 100644 index 00000000000..a7db237ab91 --- /dev/null +++ b/homeassistant/components/uber/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "uber", + "name": "Uber", + "documentation": "https://www.home-assistant.io/components/uber", + "requirements": [ + "uber_rides==0.6.0" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/ubus/manifest.json b/homeassistant/components/ubus/manifest.json new file mode 100644 index 00000000000..f886e84254b --- /dev/null +++ b/homeassistant/components/ubus/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "ubus", + "name": "Ubus", + "documentation": "https://www.home-assistant.io/components/ubus", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ue_smart_radio/manifest.json b/homeassistant/components/ue_smart_radio/manifest.json new file mode 100644 index 00000000000..189ac690758 --- /dev/null +++ b/homeassistant/components/ue_smart_radio/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "ue_smart_radio", + "name": "Ue smart radio", + "documentation": "https://www.home-assistant.io/components/ue_smart_radio", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/uk_transport/manifest.json b/homeassistant/components/uk_transport/manifest.json new file mode 100644 index 00000000000..be44a9d8cc8 --- /dev/null +++ b/homeassistant/components/uk_transport/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "uk_transport", + "name": "Uk transport", + "documentation": "https://www.home-assistant.io/components/uk_transport", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/unifi/manifest.json b/homeassistant/components/unifi/manifest.json new file mode 100644 index 00000000000..85a84539663 --- /dev/null +++ b/homeassistant/components/unifi/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "unifi", + "name": "Unifi", + "documentation": "https://www.home-assistant.io/components/unifi", + "requirements": [ + "aiounifi==4", + "pyunifi==2.16" + ], + "dependencies": [], + "codeowners": [ + "@kane610" + ] +} diff --git a/homeassistant/components/unifi_direct/manifest.json b/homeassistant/components/unifi_direct/manifest.json new file mode 100644 index 00000000000..515bd68d011 --- /dev/null +++ b/homeassistant/components/unifi_direct/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "unifi_direct", + "name": "Unifi direct", + "documentation": "https://www.home-assistant.io/components/unifi_direct", + "requirements": [ + "pexpect==4.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/universal/manifest.json b/homeassistant/components/universal/manifest.json new file mode 100644 index 00000000000..ac72d10f07f --- /dev/null +++ b/homeassistant/components/universal/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "universal", + "name": "Universal", + "documentation": "https://www.home-assistant.io/components/universal", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/upc_connect/manifest.json b/homeassistant/components/upc_connect/manifest.json new file mode 100644 index 00000000000..926fb9acf88 --- /dev/null +++ b/homeassistant/components/upc_connect/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "upc_connect", + "name": "Upc connect", + "documentation": "https://www.home-assistant.io/components/upc_connect", + "requirements": [ + "defusedxml==0.5.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/upcloud/manifest.json b/homeassistant/components/upcloud/manifest.json new file mode 100644 index 00000000000..3a58d80f64a --- /dev/null +++ b/homeassistant/components/upcloud/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "upcloud", + "name": "Upcloud", + "documentation": "https://www.home-assistant.io/components/upcloud", + "requirements": [ + "upcloud-api==0.4.3" + ], + "dependencies": [], + "codeowners": [ + "@scop" + ] +} diff --git a/homeassistant/components/updater/manifest.json b/homeassistant/components/updater/manifest.json new file mode 100644 index 00000000000..9275ef34968 --- /dev/null +++ b/homeassistant/components/updater/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "updater", + "name": "Updater", + "documentation": "https://www.home-assistant.io/components/updater", + "requirements": [ + "distro==1.4.0" + ], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/upnp/manifest.json b/homeassistant/components/upnp/manifest.json new file mode 100644 index 00000000000..75213ecc9b9 --- /dev/null +++ b/homeassistant/components/upnp/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "upnp", + "name": "Upnp", + "documentation": "https://www.home-assistant.io/components/upnp", + "requirements": [ + "async-upnp-client==0.14.7" + ], + "dependencies": [], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/ups/manifest.json b/homeassistant/components/ups/manifest.json new file mode 100644 index 00000000000..98db00c3094 --- /dev/null +++ b/homeassistant/components/ups/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ups", + "name": "Ups", + "documentation": "https://www.home-assistant.io/components/ups", + "requirements": [ + "upsmychoice==1.0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/uptime/manifest.json b/homeassistant/components/uptime/manifest.json new file mode 100644 index 00000000000..10197178381 --- /dev/null +++ b/homeassistant/components/uptime/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "uptime", + "name": "Uptime", + "documentation": "https://www.home-assistant.io/components/uptime", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/uptimerobot/manifest.json b/homeassistant/components/uptimerobot/manifest.json new file mode 100644 index 00000000000..375baf12565 --- /dev/null +++ b/homeassistant/components/uptimerobot/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "uptimerobot", + "name": "Uptimerobot", + "documentation": "https://www.home-assistant.io/components/uptimerobot", + "requirements": [ + "pyuptimerobot==0.0.5" + ], + "dependencies": [], + "codeowners": [ + "@ludeeus" + ] +} diff --git a/homeassistant/components/uscis/manifest.json b/homeassistant/components/uscis/manifest.json new file mode 100644 index 00000000000..f2ffcfbf8a3 --- /dev/null +++ b/homeassistant/components/uscis/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "uscis", + "name": "Uscis", + "documentation": "https://www.home-assistant.io/components/uscis", + "requirements": [ + "uscisstatus==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/usgs_earthquakes_feed/manifest.json b/homeassistant/components/usgs_earthquakes_feed/manifest.json new file mode 100644 index 00000000000..0b3848dbde6 --- /dev/null +++ b/homeassistant/components/usgs_earthquakes_feed/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "usgs_earthquakes_feed", + "name": "Usgs earthquakes feed", + "documentation": "https://www.home-assistant.io/components/usgs_earthquakes_feed", + "requirements": [ + "geojson_client==0.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/usps/manifest.json b/homeassistant/components/usps/manifest.json new file mode 100644 index 00000000000..9e2f8886d3a --- /dev/null +++ b/homeassistant/components/usps/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "usps", + "name": "Usps", + "documentation": "https://www.home-assistant.io/components/usps", + "requirements": [ + "myusps==1.3.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/utility_meter/manifest.json b/homeassistant/components/utility_meter/manifest.json new file mode 100644 index 00000000000..59f4d1ca21b --- /dev/null +++ b/homeassistant/components/utility_meter/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "utility_meter", + "name": "Utility meter", + "documentation": "https://www.home-assistant.io/components/utility_meter", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@dgomes" + ] +} diff --git a/homeassistant/components/uvc/manifest.json b/homeassistant/components/uvc/manifest.json new file mode 100644 index 00000000000..5c77f9ecc70 --- /dev/null +++ b/homeassistant/components/uvc/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "uvc", + "name": "Uvc", + "documentation": "https://www.home-assistant.io/components/uvc", + "requirements": [ + "uvcclient==0.11.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/vacuum/manifest.json b/homeassistant/components/vacuum/manifest.json new file mode 100644 index 00000000000..8dfbb8ed968 --- /dev/null +++ b/homeassistant/components/vacuum/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "vacuum", + "name": "Vacuum", + "documentation": "https://www.home-assistant.io/components/vacuum", + "requirements": [], + "dependencies": [ + "group" + ], + "codeowners": [] +} diff --git a/homeassistant/components/vasttrafik/manifest.json b/homeassistant/components/vasttrafik/manifest.json new file mode 100644 index 00000000000..47153dcf17f --- /dev/null +++ b/homeassistant/components/vasttrafik/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "vasttrafik", + "name": "Vasttrafik", + "documentation": "https://www.home-assistant.io/components/vasttrafik", + "requirements": [ + "vtjp==0.1.14" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/velbus/manifest.json b/homeassistant/components/velbus/manifest.json new file mode 100644 index 00000000000..4df9fe32dd9 --- /dev/null +++ b/homeassistant/components/velbus/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "velbus", + "name": "Velbus", + "documentation": "https://www.home-assistant.io/components/velbus", + "requirements": [ + "python-velbus==2.0.22" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/velux/manifest.json b/homeassistant/components/velux/manifest.json new file mode 100644 index 00000000000..bac2587cdc9 --- /dev/null +++ b/homeassistant/components/velux/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "velux", + "name": "Velux", + "documentation": "https://www.home-assistant.io/components/velux", + "requirements": [ + "pyvlx==0.2.10" + ], + "dependencies": [], + "codeowners": [ + "@Julius2342" + ] +} diff --git a/homeassistant/components/venstar/manifest.json b/homeassistant/components/venstar/manifest.json new file mode 100644 index 00000000000..e8b9158f721 --- /dev/null +++ b/homeassistant/components/venstar/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "venstar", + "name": "Venstar", + "documentation": "https://www.home-assistant.io/components/venstar", + "requirements": [ + "venstarcolortouch==0.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/vera/manifest.json b/homeassistant/components/vera/manifest.json new file mode 100644 index 00000000000..7b475c437c3 --- /dev/null +++ b/homeassistant/components/vera/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "vera", + "name": "Vera", + "documentation": "https://www.home-assistant.io/components/vera", + "requirements": [ + "pyvera==0.2.45" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/verisure/manifest.json b/homeassistant/components/verisure/manifest.json new file mode 100644 index 00000000000..7c895233f77 --- /dev/null +++ b/homeassistant/components/verisure/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "verisure", + "name": "Verisure", + "documentation": "https://www.home-assistant.io/components/verisure", + "requirements": [ + "jsonpath==0.75", + "vsure==1.5.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/version/manifest.json b/homeassistant/components/version/manifest.json new file mode 100644 index 00000000000..34f984f953a --- /dev/null +++ b/homeassistant/components/version/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "version", + "name": "Version", + "documentation": "https://www.home-assistant.io/components/version", + "requirements": [ + "pyhaversion==2.0.3" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/vesync/manifest.json b/homeassistant/components/vesync/manifest.json new file mode 100644 index 00000000000..bba754d135f --- /dev/null +++ b/homeassistant/components/vesync/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "vesync", + "name": "Vesync", + "documentation": "https://www.home-assistant.io/components/vesync", + "requirements": [ + "pyvesync_v2==0.9.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/viaggiatreno/manifest.json b/homeassistant/components/viaggiatreno/manifest.json new file mode 100644 index 00000000000..e145b26b0c9 --- /dev/null +++ b/homeassistant/components/viaggiatreno/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "viaggiatreno", + "name": "Viaggiatreno", + "documentation": "https://www.home-assistant.io/components/viaggiatreno", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/vizio/manifest.json b/homeassistant/components/vizio/manifest.json new file mode 100644 index 00000000000..ac589de841a --- /dev/null +++ b/homeassistant/components/vizio/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "vizio", + "name": "Vizio", + "documentation": "https://www.home-assistant.io/components/vizio", + "requirements": [ + "pyvizio==0.0.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/vlc/manifest.json b/homeassistant/components/vlc/manifest.json new file mode 100644 index 00000000000..a40b0e8c7d6 --- /dev/null +++ b/homeassistant/components/vlc/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "vlc", + "name": "Vlc", + "documentation": "https://www.home-assistant.io/components/vlc", + "requirements": [ + "python-vlc==1.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/voicerss/manifest.json b/homeassistant/components/voicerss/manifest.json new file mode 100644 index 00000000000..6f0b4ae5fd2 --- /dev/null +++ b/homeassistant/components/voicerss/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "voicerss", + "name": "Voicerss", + "documentation": "https://www.home-assistant.io/components/voicerss", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/volkszaehler/manifest.json b/homeassistant/components/volkszaehler/manifest.json new file mode 100644 index 00000000000..db068e35056 --- /dev/null +++ b/homeassistant/components/volkszaehler/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "volkszaehler", + "name": "Volkszaehler", + "documentation": "https://www.home-assistant.io/components/volkszaehler", + "requirements": [ + "volkszaehler==0.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/volumio/manifest.json b/homeassistant/components/volumio/manifest.json new file mode 100644 index 00000000000..e7c4bac4abd --- /dev/null +++ b/homeassistant/components/volumio/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "volumio", + "name": "Volumio", + "documentation": "https://www.home-assistant.io/components/volumio", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/volvooncall/manifest.json b/homeassistant/components/volvooncall/manifest.json new file mode 100644 index 00000000000..aa691d7766c --- /dev/null +++ b/homeassistant/components/volvooncall/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "volvooncall", + "name": "Volvooncall", + "documentation": "https://www.home-assistant.io/components/volvooncall", + "requirements": [ + "volvooncall==0.8.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/vultr/manifest.json b/homeassistant/components/vultr/manifest.json new file mode 100644 index 00000000000..5f5461f2d63 --- /dev/null +++ b/homeassistant/components/vultr/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "vultr", + "name": "Vultr", + "documentation": "https://www.home-assistant.io/components/vultr", + "requirements": [ + "vultr==0.1.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/w800rf32/manifest.json b/homeassistant/components/w800rf32/manifest.json new file mode 100644 index 00000000000..920ee1120a7 --- /dev/null +++ b/homeassistant/components/w800rf32/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "w800rf32", + "name": "W800rf32", + "documentation": "https://www.home-assistant.io/components/w800rf32", + "requirements": [ + "pyW800rf32==0.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/wake_on_lan/manifest.json b/homeassistant/components/wake_on_lan/manifest.json new file mode 100644 index 00000000000..dc689f8d617 --- /dev/null +++ b/homeassistant/components/wake_on_lan/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "wake_on_lan", + "name": "Wake on lan", + "documentation": "https://www.home-assistant.io/components/wake_on_lan", + "requirements": [ + "wakeonlan==1.1.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/waqi/manifest.json b/homeassistant/components/waqi/manifest.json new file mode 100644 index 00000000000..4b692c669d1 --- /dev/null +++ b/homeassistant/components/waqi/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "waqi", + "name": "Waqi", + "documentation": "https://www.home-assistant.io/components/waqi", + "requirements": [ + "waqiasync==1.0.0" + ], + "dependencies": [], + "codeowners": [ + "@andrey-git" + ] +} diff --git a/homeassistant/components/water_heater/manifest.json b/homeassistant/components/water_heater/manifest.json new file mode 100644 index 00000000000..e291777483e --- /dev/null +++ b/homeassistant/components/water_heater/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "water_heater", + "name": "Water heater", + "documentation": "https://www.home-assistant.io/components/water_heater", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/waterfurnace/manifest.json b/homeassistant/components/waterfurnace/manifest.json new file mode 100644 index 00000000000..57aa663a348 --- /dev/null +++ b/homeassistant/components/waterfurnace/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "waterfurnace", + "name": "Waterfurnace", + "documentation": "https://www.home-assistant.io/components/waterfurnace", + "requirements": [ + "waterfurnace==1.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/watson_iot/manifest.json b/homeassistant/components/watson_iot/manifest.json new file mode 100644 index 00000000000..8896f34f976 --- /dev/null +++ b/homeassistant/components/watson_iot/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "watson_iot", + "name": "Watson iot", + "documentation": "https://www.home-assistant.io/components/watson_iot", + "requirements": [ + "ibmiotf==0.3.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/waze_travel_time/manifest.json b/homeassistant/components/waze_travel_time/manifest.json new file mode 100644 index 00000000000..64b384356ce --- /dev/null +++ b/homeassistant/components/waze_travel_time/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "waze_travel_time", + "name": "Waze travel time", + "documentation": "https://www.home-assistant.io/components/waze_travel_time", + "requirements": [ + "WazeRouteCalculator==0.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/weather/manifest.json b/homeassistant/components/weather/manifest.json new file mode 100644 index 00000000000..7008c033f95 --- /dev/null +++ b/homeassistant/components/weather/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "weather", + "name": "Weather", + "documentation": "https://www.home-assistant.io/components/weather", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/webhook/manifest.json b/homeassistant/components/webhook/manifest.json new file mode 100644 index 00000000000..384e61aed2a --- /dev/null +++ b/homeassistant/components/webhook/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "webhook", + "name": "Webhook", + "documentation": "https://www.home-assistant.io/components/webhook", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [] +} diff --git a/homeassistant/components/weblink/manifest.json b/homeassistant/components/weblink/manifest.json new file mode 100644 index 00000000000..7c30ad6c5d3 --- /dev/null +++ b/homeassistant/components/weblink/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "weblink", + "name": "Weblink", + "documentation": "https://www.home-assistant.io/components/weblink", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/webostv/manifest.json b/homeassistant/components/webostv/manifest.json new file mode 100644 index 00000000000..0673c36e91f --- /dev/null +++ b/homeassistant/components/webostv/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "webostv", + "name": "Webostv", + "documentation": "https://www.home-assistant.io/components/webostv", + "requirements": [ + "pylgtv==0.1.9", + "websockets==6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/websocket_api/manifest.json b/homeassistant/components/websocket_api/manifest.json new file mode 100644 index 00000000000..bc630b2947f --- /dev/null +++ b/homeassistant/components/websocket_api/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "websocket_api", + "name": "Websocket api", + "documentation": "https://www.home-assistant.io/components/websocket_api", + "requirements": [], + "dependencies": [ + "http" + ], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/wemo/manifest.json b/homeassistant/components/wemo/manifest.json new file mode 100644 index 00000000000..238be891886 --- /dev/null +++ b/homeassistant/components/wemo/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "wemo", + "name": "Wemo", + "documentation": "https://www.home-assistant.io/components/wemo", + "requirements": [ + "pywemo==0.4.34" + ], + "dependencies": [], + "codeowners": [ + "@sqldiablo" + ] +} diff --git a/homeassistant/components/whois/manifest.json b/homeassistant/components/whois/manifest.json new file mode 100644 index 00000000000..dec3e78a503 --- /dev/null +++ b/homeassistant/components/whois/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "whois", + "name": "Whois", + "documentation": "https://www.home-assistant.io/components/whois", + "requirements": [ + "python-whois==0.7.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/wink/manifest.json b/homeassistant/components/wink/manifest.json new file mode 100644 index 00000000000..6ad6fa2b940 --- /dev/null +++ b/homeassistant/components/wink/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "wink", + "name": "Wink", + "documentation": "https://www.home-assistant.io/components/wink", + "requirements": [ + "pubnubsub-handler==1.0.3", + "python-wink==1.10.3" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/wirelesstag/manifest.json b/homeassistant/components/wirelesstag/manifest.json new file mode 100644 index 00000000000..c3da00ce951 --- /dev/null +++ b/homeassistant/components/wirelesstag/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "wirelesstag", + "name": "Wirelesstag", + "documentation": "https://www.home-assistant.io/components/wirelesstag", + "requirements": [ + "wirelesstagpy==0.4.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/workday/manifest.json b/homeassistant/components/workday/manifest.json new file mode 100644 index 00000000000..889ce4059be --- /dev/null +++ b/homeassistant/components/workday/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "workday", + "name": "Workday", + "documentation": "https://www.home-assistant.io/components/workday", + "requirements": [ + "holidays==0.9.10" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/worldclock/manifest.json b/homeassistant/components/worldclock/manifest.json new file mode 100644 index 00000000000..2da33f942b8 --- /dev/null +++ b/homeassistant/components/worldclock/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "worldclock", + "name": "Worldclock", + "documentation": "https://www.home-assistant.io/components/worldclock", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/worldtidesinfo/manifest.json b/homeassistant/components/worldtidesinfo/manifest.json new file mode 100644 index 00000000000..dfc116c97db --- /dev/null +++ b/homeassistant/components/worldtidesinfo/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "worldtidesinfo", + "name": "Worldtidesinfo", + "documentation": "https://www.home-assistant.io/components/worldtidesinfo", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/worxlandroid/manifest.json b/homeassistant/components/worxlandroid/manifest.json new file mode 100644 index 00000000000..3e7c626ddd0 --- /dev/null +++ b/homeassistant/components/worxlandroid/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "worxlandroid", + "name": "Worxlandroid", + "documentation": "https://www.home-assistant.io/components/worxlandroid", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/wsdot/manifest.json b/homeassistant/components/wsdot/manifest.json new file mode 100644 index 00000000000..c778ed1049f --- /dev/null +++ b/homeassistant/components/wsdot/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "wsdot", + "name": "Wsdot", + "documentation": "https://www.home-assistant.io/components/wsdot", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/wunderground/manifest.json b/homeassistant/components/wunderground/manifest.json new file mode 100644 index 00000000000..d14c9db419a --- /dev/null +++ b/homeassistant/components/wunderground/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "wunderground", + "name": "Wunderground", + "documentation": "https://www.home-assistant.io/components/wunderground", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/wunderlist/manifest.json b/homeassistant/components/wunderlist/manifest.json new file mode 100644 index 00000000000..505447f454c --- /dev/null +++ b/homeassistant/components/wunderlist/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "wunderlist", + "name": "Wunderlist", + "documentation": "https://www.home-assistant.io/components/wunderlist", + "requirements": [ + "wunderpy2==0.1.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/x10/manifest.json b/homeassistant/components/x10/manifest.json new file mode 100644 index 00000000000..2fbe16a6e7a --- /dev/null +++ b/homeassistant/components/x10/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "x10", + "name": "X10", + "documentation": "https://www.home-assistant.io/components/x10", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/xbox_live/manifest.json b/homeassistant/components/xbox_live/manifest.json new file mode 100644 index 00000000000..0d80ce770ce --- /dev/null +++ b/homeassistant/components/xbox_live/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "xbox_live", + "name": "Xbox live", + "documentation": "https://www.home-assistant.io/components/xbox_live", + "requirements": [ + "xboxapi==0.1.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/xeoma/manifest.json b/homeassistant/components/xeoma/manifest.json new file mode 100644 index 00000000000..ee8ed2f6de3 --- /dev/null +++ b/homeassistant/components/xeoma/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "xeoma", + "name": "Xeoma", + "documentation": "https://www.home-assistant.io/components/xeoma", + "requirements": [ + "pyxeoma==1.4.1" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/xfinity/manifest.json b/homeassistant/components/xfinity/manifest.json new file mode 100644 index 00000000000..71750ccf088 --- /dev/null +++ b/homeassistant/components/xfinity/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "xfinity", + "name": "Xfinity", + "documentation": "https://www.home-assistant.io/components/xfinity", + "requirements": [ + "xfinity-gateway==0.0.4" + ], + "dependencies": [], + "codeowners": [ + "@cisasteelersfan" + ] +} diff --git a/homeassistant/components/xiaomi/manifest.json b/homeassistant/components/xiaomi/manifest.json new file mode 100644 index 00000000000..158a2e9b2fc --- /dev/null +++ b/homeassistant/components/xiaomi/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "xiaomi", + "name": "Xiaomi", + "documentation": "https://www.home-assistant.io/components/xiaomi", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/xiaomi_aqara/manifest.json b/homeassistant/components/xiaomi_aqara/manifest.json new file mode 100644 index 00000000000..a79f2960497 --- /dev/null +++ b/homeassistant/components/xiaomi_aqara/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "xiaomi_aqara", + "name": "Xiaomi aqara", + "documentation": "https://www.home-assistant.io/components/xiaomi_aqara", + "requirements": [ + "PyXiaomiGateway==0.12.2" + ], + "dependencies": [], + "codeowners": [ + "@danielhiversen", + "@syssi" + ] +} diff --git a/homeassistant/components/xiaomi_miio/manifest.json b/homeassistant/components/xiaomi_miio/manifest.json new file mode 100644 index 00000000000..d7e0d0d732e --- /dev/null +++ b/homeassistant/components/xiaomi_miio/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "xiaomi_miio", + "name": "Xiaomi miio", + "documentation": "https://www.home-assistant.io/components/xiaomi_miio", + "requirements": [ + "construct==2.9.45", + "python-miio==0.4.5" + ], + "dependencies": [], + "codeowners": [ + "@rytilahti", + "@syssi" + ] +} diff --git a/homeassistant/components/xiaomi_tv/manifest.json b/homeassistant/components/xiaomi_tv/manifest.json new file mode 100644 index 00000000000..221532c1c8d --- /dev/null +++ b/homeassistant/components/xiaomi_tv/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "xiaomi_tv", + "name": "Xiaomi tv", + "documentation": "https://www.home-assistant.io/components/xiaomi_tv", + "requirements": [ + "pymitv==1.4.3" + ], + "dependencies": [], + "codeowners": [ + "@fattdev" + ] +} diff --git a/homeassistant/components/xmpp/manifest.json b/homeassistant/components/xmpp/manifest.json new file mode 100644 index 00000000000..d8e4e5c4da6 --- /dev/null +++ b/homeassistant/components/xmpp/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "xmpp", + "name": "Xmpp", + "documentation": "https://www.home-assistant.io/components/xmpp", + "requirements": [ + "slixmpp==1.4.2" + ], + "dependencies": [], + "codeowners": [ + "@fabaff" + ] +} diff --git a/homeassistant/components/xs1/manifest.json b/homeassistant/components/xs1/manifest.json new file mode 100644 index 00000000000..4ee13acf647 --- /dev/null +++ b/homeassistant/components/xs1/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "xs1", + "name": "Xs1", + "documentation": "https://www.home-assistant.io/components/xs1", + "requirements": [ + "xs1-api-client==2.3.5" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/yale_smart_alarm/manifest.json b/homeassistant/components/yale_smart_alarm/manifest.json new file mode 100644 index 00000000000..7b786c7bf7c --- /dev/null +++ b/homeassistant/components/yale_smart_alarm/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "yale_smart_alarm", + "name": "Yale smart alarm", + "documentation": "https://www.home-assistant.io/components/yale_smart_alarm", + "requirements": [ + "yalesmartalarmclient==0.1.6" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/yamaha/manifest.json b/homeassistant/components/yamaha/manifest.json new file mode 100644 index 00000000000..5a277fc7ce8 --- /dev/null +++ b/homeassistant/components/yamaha/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "yamaha", + "name": "Yamaha", + "documentation": "https://www.home-assistant.io/components/yamaha", + "requirements": [ + "rxv==0.6.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/yamaha_musiccast/manifest.json b/homeassistant/components/yamaha_musiccast/manifest.json new file mode 100644 index 00000000000..7769026e092 --- /dev/null +++ b/homeassistant/components/yamaha_musiccast/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "yamaha_musiccast", + "name": "Yamaha musiccast", + "documentation": "https://www.home-assistant.io/components/yamaha_musiccast", + "requirements": [ + "pymusiccast==0.1.6" + ], + "dependencies": [], + "codeowners": [ + "@jalmeroth" + ] +} diff --git a/homeassistant/components/yandextts/manifest.json b/homeassistant/components/yandextts/manifest.json new file mode 100644 index 00000000000..7f622a1e25f --- /dev/null +++ b/homeassistant/components/yandextts/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "yandextts", + "name": "Yandextts", + "documentation": "https://www.home-assistant.io/components/yandextts", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/yeelight/manifest.json b/homeassistant/components/yeelight/manifest.json new file mode 100644 index 00000000000..f734f092a1a --- /dev/null +++ b/homeassistant/components/yeelight/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "yeelight", + "name": "Yeelight", + "documentation": "https://www.home-assistant.io/components/yeelight", + "requirements": [ + "yeelight==0.4.4" + ], + "dependencies": [], + "codeowners": [ + "@rytilahti", + "@zewelor" + ] +} diff --git a/homeassistant/components/yeelightsunflower/manifest.json b/homeassistant/components/yeelightsunflower/manifest.json new file mode 100644 index 00000000000..1a75472b801 --- /dev/null +++ b/homeassistant/components/yeelightsunflower/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "yeelightsunflower", + "name": "Yeelightsunflower", + "documentation": "https://www.home-assistant.io/components/yeelightsunflower", + "requirements": [ + "yeelightsunflower==0.0.10" + ], + "dependencies": [], + "codeowners": [ + "@lindsaymarkward" + ] +} diff --git a/homeassistant/components/yessssms/manifest.json b/homeassistant/components/yessssms/manifest.json new file mode 100644 index 00000000000..103a9fce31e --- /dev/null +++ b/homeassistant/components/yessssms/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "yessssms", + "name": "Yessssms", + "documentation": "https://www.home-assistant.io/components/yessssms", + "requirements": [ + "YesssSMS==0.2.3" + ], + "dependencies": [], + "codeowners": [ + "@flowolf" + ] +} diff --git a/homeassistant/components/yi/manifest.json b/homeassistant/components/yi/manifest.json new file mode 100644 index 00000000000..0a1a6aabc57 --- /dev/null +++ b/homeassistant/components/yi/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "yi", + "name": "Yi", + "documentation": "https://www.home-assistant.io/components/yi", + "requirements": [ + "aioftp==0.12.0" + ], + "dependencies": [], + "codeowners": [ + "@bachya" + ] +} diff --git a/homeassistant/components/yr/manifest.json b/homeassistant/components/yr/manifest.json new file mode 100644 index 00000000000..ec12f6cdac4 --- /dev/null +++ b/homeassistant/components/yr/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "yr", + "name": "Yr", + "documentation": "https://www.home-assistant.io/components/yr", + "requirements": [ + "xmltodict==0.11.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/yweather/manifest.json b/homeassistant/components/yweather/manifest.json new file mode 100644 index 00000000000..c3048601595 --- /dev/null +++ b/homeassistant/components/yweather/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "yweather", + "name": "Yweather", + "documentation": "https://www.home-assistant.io/components/yweather", + "requirements": [ + "yahooweather==0.10" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/zabbix/manifest.json b/homeassistant/components/zabbix/manifest.json new file mode 100644 index 00000000000..c0f100fa62f --- /dev/null +++ b/homeassistant/components/zabbix/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "zabbix", + "name": "Zabbix", + "documentation": "https://www.home-assistant.io/components/zabbix", + "requirements": [ + "pyzabbix==0.7.4" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/zamg/manifest.json b/homeassistant/components/zamg/manifest.json new file mode 100644 index 00000000000..ce16e1b523c --- /dev/null +++ b/homeassistant/components/zamg/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "zamg", + "name": "Zamg", + "documentation": "https://www.home-assistant.io/components/zamg", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/zengge/manifest.json b/homeassistant/components/zengge/manifest.json new file mode 100644 index 00000000000..b846c95f5fa --- /dev/null +++ b/homeassistant/components/zengge/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "zengge", + "name": "Zengge", + "documentation": "https://www.home-assistant.io/components/zengge", + "requirements": [ + "zengge==0.2" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/zeroconf/manifest.json b/homeassistant/components/zeroconf/manifest.json new file mode 100644 index 00000000000..bd7cf3ec0d6 --- /dev/null +++ b/homeassistant/components/zeroconf/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "zeroconf", + "name": "Zeroconf", + "documentation": "https://www.home-assistant.io/components/zeroconf", + "requirements": [ + "zeroconf==0.21.3" + ], + "dependencies": [ + "api" + ], + "codeowners": [ + "@robbiet480" + ] +} diff --git a/homeassistant/components/zestimate/manifest.json b/homeassistant/components/zestimate/manifest.json new file mode 100644 index 00000000000..1d67ddbd581 --- /dev/null +++ b/homeassistant/components/zestimate/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "zestimate", + "name": "Zestimate", + "documentation": "https://www.home-assistant.io/components/zestimate", + "requirements": [ + "xmltodict==0.11.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json new file mode 100644 index 00000000000..e2b2c54fd93 --- /dev/null +++ b/homeassistant/components/zha/manifest.json @@ -0,0 +1,17 @@ +{ + "domain": "zha", + "name": "Zigbee Home Automation", + "documentation": "https://www.home-assistant.io/components/zha", + "requirements": [ + "bellows-homeassistant==0.7.2", + "zha-quirks==0.0.7", + "zigpy-deconz==0.1.3", + "zigpy-homeassistant==0.3.1", + "zigpy-xbee-homeassistant==0.1.3" + ], + "dependencies": [], + "codeowners": [ + "@dmulcahey", + "@adminiuga" + ] +} diff --git a/homeassistant/components/zhong_hong/manifest.json b/homeassistant/components/zhong_hong/manifest.json new file mode 100644 index 00000000000..6382a830dcf --- /dev/null +++ b/homeassistant/components/zhong_hong/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "zhong_hong", + "name": "Zhong hong", + "documentation": "https://www.home-assistant.io/components/zhong_hong", + "requirements": [ + "zhong_hong_hvac==1.0.9" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/zigbee/manifest.json b/homeassistant/components/zigbee/manifest.json new file mode 100644 index 00000000000..1e4076b8439 --- /dev/null +++ b/homeassistant/components/zigbee/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "zigbee", + "name": "Zigbee", + "documentation": "https://www.home-assistant.io/components/zigbee", + "requirements": [ + "xbee-helper==0.0.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/ziggo_mediabox_xl/manifest.json b/homeassistant/components/ziggo_mediabox_xl/manifest.json new file mode 100644 index 00000000000..9e587137922 --- /dev/null +++ b/homeassistant/components/ziggo_mediabox_xl/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "ziggo_mediabox_xl", + "name": "Ziggo mediabox xl", + "documentation": "https://www.home-assistant.io/components/ziggo_mediabox_xl", + "requirements": [ + "ziggo-mediabox-xl==1.1.0" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/zone/manifest.json b/homeassistant/components/zone/manifest.json new file mode 100644 index 00000000000..897908b61da --- /dev/null +++ b/homeassistant/components/zone/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "zone", + "name": "Zone", + "documentation": "https://www.home-assistant.io/components/zone", + "requirements": [], + "dependencies": [], + "codeowners": [ + "@home-assistant/core" + ] +} diff --git a/homeassistant/components/zoneminder/manifest.json b/homeassistant/components/zoneminder/manifest.json new file mode 100644 index 00000000000..9d371fbabf7 --- /dev/null +++ b/homeassistant/components/zoneminder/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "zoneminder", + "name": "Zoneminder", + "documentation": "https://www.home-assistant.io/components/zoneminder", + "requirements": [ + "zm-py==0.3.3" + ], + "dependencies": [], + "codeowners": [ + "@rohankapoorcom" + ] +} diff --git a/homeassistant/components/zwave/manifest.json b/homeassistant/components/zwave/manifest.json new file mode 100644 index 00000000000..ac7e327f19a --- /dev/null +++ b/homeassistant/components/zwave/manifest.json @@ -0,0 +1,13 @@ +{ + "domain": "zwave", + "name": "Z-Wave", + "documentation": "https://www.home-assistant.io/components/zwave", + "requirements": [ + "homeassistant-pyozw==0.1.3", + "pydispatcher==2.0.5" + ], + "dependencies": [], + "codeowners": [ + "@home-assistant/z-wave" + ] +} From d81a627739b8c2fc97cbb36540ec63e2a256b0ac Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Wed, 3 Apr 2019 21:44:15 -0700 Subject: [PATCH 076/167] Add a .codecov.yml to control coverage statuses and enable notifications (#22707) * Add a .codecov.yml to control coverage statuses and enable notifications * Comment about Slack/Discord notification --- .codecov.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .codecov.yml diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 00000000000..96a39e7319b --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,13 @@ +codecov: + branch: dev +coverage: + status: + project: + default: + target: 90 + threshold: 0.09 + notify: + # Notify codecov room in Discord. The webhook URL (encrypted below) ends in /slack which is why we configure a Slack notification. + slack: + default: + url: "secret:TgWDUM4Jw0w7wMJxuxNF/yhSOHglIo1fGwInJnRLEVPy2P2aLimkoK1mtKCowH5TFw+baUXVXT3eAqefbdvIuM8BjRR4aRji95C6CYyD0QHy4N8i7nn1SQkWDPpS8IthYTg07rUDF7s5guurkKv2RrgoCdnnqjAMSzHoExMOF7xUmblMdhBTWJgBpWEhASJy85w/xxjlsE1xoTkzeJu9Q67pTXtRcn+5kb5/vIzPSYg=" From a5a926bcc692027af8e5a4e9bb2812ab7665d864 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Thu, 4 Apr 2019 00:51:01 -0400 Subject: [PATCH 077/167] Raise ConfigEntryNotReady for MQTT connection exception (#22540) * Raise ConfigEntryNotReady for connection exception Raise ConfigEntryNotReady for the connection exception like if the MQTT Server container/device is being restarted or was unavailable on boot. * Add new exception * grammar fix * Possibly resolve hound comments * raise `ConfigEntryNotReady` for mqtt connection error * revert exceptions.py * Update exceptions.py * modify test to handle exception * use constants to control exception scope * Raise ConfigEntryNotReady for connection exception Raise ConfigEntryNotReady for the connection exception like if the MQTT Server container/device is being restarted or was unavailable on boot. * Add new exception * Add new exception * grammar fix * Possibly resolve hound comments * raise `ConfigEntryNotReady` for mqtt connection error * revert exceptions.py * Update exceptions.py * modify test to handle exception * use constants to control exception scope * revert test change as it's not the same thing * Update test_init.py * Add test for MQTT OSError * revert file changes from a bad rebase * Rewrite test with valid syntax * rewrite test to be less ambiguous * add empty line * add back 'axis' * Remove empty line * Update tests and undo merge from earlier * correctly restore test for no connect broker * fix test mock correctly * line was too long. hit enter. --- homeassistant/components/mqtt/__init__.py | 22 +++++++++++++++------- tests/components/mqtt/test_init.py | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 3f1f8617689..81d2dd8ea03 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -23,7 +23,8 @@ from homeassistant.const import ( CONF_PROTOCOL, CONF_USERNAME, CONF_VALUE_TEMPLATE, EVENT_HOMEASSISTANT_STOP) from homeassistant.core import Event, ServiceCall, callback -from homeassistant.exceptions import HomeAssistantError, Unauthorized +from homeassistant.exceptions import ( + HomeAssistantError, Unauthorized, ConfigEntryNotReady) from homeassistant.helpers import config_validation as cv, template from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import ( @@ -104,6 +105,10 @@ ATTR_DISCOVERY_HASH = 'discovery_hash' MAX_RECONNECT_WAIT = 300 # seconds +CONNECTION_SUCCESS = 'connection_success' +CONNECTION_FAILED = 'connection_failed' +CONNECTION_FAILED_RECOVERABLE = 'connection_failed_recoverable' + def valid_topic(value: Any) -> str: """Validate that this is a valid topic name/filter.""" @@ -569,11 +574,14 @@ async def async_setup_entry(hass, entry): tls_version=tls_version, ) - success = await hass.data[DATA_MQTT].async_connect() # type: bool + result = await hass.data[DATA_MQTT].async_connect() # type: str - if not success: + if result == CONNECTION_FAILED: return False + if result == CONNECTION_FAILED_RECOVERABLE: + raise ConfigEntryNotReady + async def async_stop_mqtt(event: Event): """Stop MQTT component.""" await hass.data[DATA_MQTT].async_disconnect() @@ -685,7 +693,7 @@ class MQTT: await self.hass.async_add_job( self._mqttc.publish, topic, payload, qos, retain) - async def async_connect(self) -> bool: + async def async_connect(self) -> str: """Connect to the host. Does process messages yet. This method is a coroutine. @@ -696,15 +704,15 @@ class MQTT: self._mqttc.connect, self.broker, self.port, self.keepalive) except OSError as err: _LOGGER.error("Failed to connect due to exception: %s", err) - return False + return CONNECTION_FAILED_RECOVERABLE if result != 0: import paho.mqtt.client as mqtt _LOGGER.error("Failed to connect: %s", mqtt.error_string(result)) - return False + return CONNECTION_FAILED self._mqttc.loop_start() - return True + return CONNECTION_SUCCESS @callback def async_disconnect(self): diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index 5c441a68bea..144ee9c43d8 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -12,6 +12,7 @@ from homeassistant.const import ( ATTR_DOMAIN, ATTR_SERVICE, EVENT_CALL_SERVICE, EVENT_HOMEASSISTANT_STOP) from homeassistant.core import callback from homeassistant.setup import async_setup_component +from homeassistant.exceptions import ConfigEntryNotReady from tests.common import ( MockConfigEntry, async_fire_mqtt_message, async_mock_mqtt_component, @@ -621,6 +622,19 @@ async def test_setup_fails_if_no_connect_broker(hass): assert not await mqtt.async_setup_entry(hass, entry) +async def test_setup_raises_ConfigEntryNotReady_if_no_connect_broker(hass): + """Test for setup failure if connection to broker is missing.""" + entry = MockConfigEntry(domain=mqtt.DOMAIN, data={ + mqtt.CONF_BROKER: 'test-broker' + }) + + with mock.patch('paho.mqtt.client.Client') as mock_client: + mock_client().connect = mock.Mock( + side_effect=OSError("Connection error")) + with pytest.raises(ConfigEntryNotReady): + await mqtt.async_setup_entry(hass, entry) + + async def test_setup_uses_certificate_on_certificate_set_to_auto( hass, mock_MQTT): """Test setup uses bundled certs when certificate is set to auto.""" From 8e39939b7ec924296e42f6554bbb1fb5ae4716c5 Mon Sep 17 00:00:00 2001 From: Markus Jankowski Date: Thu, 4 Apr 2019 06:52:23 +0200 Subject: [PATCH 078/167] Add device_class_power to sensor (#22691) * Add device_class_power to sensor * Fix comment --- homeassistant/components/homematicip_cloud/sensor.py | 9 +++++++-- homeassistant/components/sensor/__init__.py | 10 ++++++---- homeassistant/const.py | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/sensor.py b/homeassistant/components/homematicip_cloud/sensor.py index e053c191c6b..2038433df4f 100644 --- a/homeassistant/components/homematicip_cloud/sensor.py +++ b/homeassistant/components/homematicip_cloud/sensor.py @@ -2,8 +2,8 @@ import logging from homeassistant.const import ( - DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE, - POWER_WATT, TEMP_CELSIUS) + DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_POWER, + DEVICE_CLASS_TEMPERATURE, POWER_WATT, TEMP_CELSIUS) from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice @@ -238,6 +238,11 @@ class HomematicipPowerSensor(HomematicipGenericDevice): """Initialize the device.""" super().__init__(home, device, 'Power') + @property + def device_class(self): + """Return the device class of the sensor.""" + return DEVICE_CLASS_POWER + @property def state(self): """Represenation of the HomematicIP power comsumption value.""" diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index 031657066cb..e11ace9749c 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -5,12 +5,13 @@ import logging import voluptuous as vol -from homeassistant.helpers.entity_component import EntityComponent -from homeassistant.helpers.config_validation import ( # noqa - PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE) from homeassistant.const import ( DEVICE_CLASS_BATTERY, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, - DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_PRESSURE) + DEVICE_CLASS_POWER, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_TIMESTAMP) +from homeassistant.helpers.config_validation import ( # noqa + PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE) +from homeassistant.helpers.entity_component import EntityComponent _LOGGER = logging.getLogger(__name__) @@ -26,6 +27,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_TEMPERATURE, # temperature (C/F) DEVICE_CLASS_TIMESTAMP, # timestamp (ISO8601) DEVICE_CLASS_PRESSURE, # pressure (hPa/mbar) + DEVICE_CLASS_POWER, # power (W/kW) ] DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.In(DEVICE_CLASSES)) diff --git a/homeassistant/const.py b/homeassistant/const.py index 9987e0f8e99..e0130f3ccef 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -188,6 +188,7 @@ DEVICE_CLASS_ILLUMINANCE = 'illuminance' DEVICE_CLASS_TEMPERATURE = 'temperature' DEVICE_CLASS_TIMESTAMP = 'timestamp' DEVICE_CLASS_PRESSURE = 'pressure' +DEVICE_CLASS_POWER = 'power' # #### STATES #### STATE_ON = 'on' From afac09932ff9b1a931b4958ebc7266a52e542ef4 Mon Sep 17 00:00:00 2001 From: Rohan Kapoor Date: Wed, 3 Apr 2019 23:31:55 -0700 Subject: [PATCH 079/167] Remove all config deprecations invalidated in 0.91 (#22704) * Remove all config deprecations invalidated in 0.91 * Fix lint --- homeassistant/components/broadlink/sensor.py | 33 ++++------ homeassistant/components/darksky/sensor.py | 65 ++++++++----------- .../components/fastdotcom/__init__.py | 23 ++----- homeassistant/components/fedex/sensor.py | 30 +++------ homeassistant/components/freedns/__init__.py | 30 +++------ .../components/mythicbeastsdns/__init__.py | 31 +++------ .../components/speedtestdotnet/__init__.py | 37 ++++------- .../components/tellduslive/__init__.py | 31 +++------ .../components/tplink_lte/__init__.py | 26 ++------ homeassistant/components/ups/sensor.py | 39 ++++------- .../components/volvooncall/__init__.py | 57 +++++++--------- homeassistant/const.py | 5 -- 12 files changed, 140 insertions(+), 267 deletions(-) diff --git a/homeassistant/components/broadlink/sensor.py b/homeassistant/components/broadlink/sensor.py index 60f1ed5c6bc..b3ce245a979 100644 --- a/homeassistant/components/broadlink/sensor.py +++ b/homeassistant/components/broadlink/sensor.py @@ -1,19 +1,18 @@ """Support for the Broadlink RM2 Pro (only temperature) and A1 devices.""" -from datetime import timedelta import binascii import logging import socket +from datetime import timedelta import voluptuous as vol +import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( CONF_HOST, CONF_MAC, CONF_MONITORED_CONDITIONS, CONF_NAME, TEMP_CELSIUS, - CONF_TIMEOUT, CONF_UPDATE_INTERVAL, CONF_SCAN_INTERVAL, - CONF_UPDATE_INTERVAL_INVALIDATION_VERSION) + CONF_TIMEOUT, CONF_SCAN_INTERVAL) from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle -import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['broadlink==0.9.0'] @@ -31,24 +30,14 @@ SENSOR_TYPES = { 'noise': ['Noise', ' '], } -PLATFORM_SCHEMA = vol.All( - PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_NAME, default=DEVICE_DEFAULT_NAME): vol.Coerce(str), - vol.Optional(CONF_MONITORED_CONDITIONS, default=[]): - vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - vol.Required(CONF_HOST): cv.string, - vol.Required(CONF_MAC): cv.string, - vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=SCAN_INTERVAL - ) -) +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=DEVICE_DEFAULT_NAME): vol.Coerce(str), + vol.Optional(CONF_MONITORED_CONDITIONS, default=[]): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_MAC): cv.string, + vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int +}) def setup_platform(hass, config, add_entities, discovery_info=None): diff --git a/homeassistant/components/darksky/sensor.py b/homeassistant/components/darksky/sensor.py index 70b07ee773f..0e87593b25c 100644 --- a/homeassistant/components/darksky/sensor.py +++ b/homeassistant/components/darksky/sensor.py @@ -1,17 +1,16 @@ """Support for Dark Sky weather service.""" -from datetime import timedelta import logging +from datetime import timedelta +import voluptuous as vol from requests.exceptions import ( ConnectionError as ConnectError, HTTPError, Timeout) -import voluptuous as vol +import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( ATTR_ATTRIBUTION, CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, - CONF_MONITORED_CONDITIONS, CONF_NAME, UNIT_UV_INDEX, CONF_UPDATE_INTERVAL, - CONF_SCAN_INTERVAL, CONF_UPDATE_INTERVAL_INVALIDATION_VERSION) -import homeassistant.helpers.config_validation as cv + CONF_MONITORED_CONDITIONS, CONF_NAME, UNIT_UV_INDEX, CONF_SCAN_INTERVAL) from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle @@ -166,39 +165,29 @@ LANGUAGE_CODES = [ ALLOWED_UNITS = ['auto', 'si', 'us', 'ca', 'uk', 'uk2'] -PLATFORM_SCHEMA = vol.All( - PLATFORM_SCHEMA.extend({ - vol.Required(CONF_MONITORED_CONDITIONS): - vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), - vol.Required(CONF_API_KEY): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_UNITS): vol.In(ALLOWED_UNITS), - vol.Optional(CONF_LANGUAGE, - default=DEFAULT_LANGUAGE): vol.In(LANGUAGE_CODES), - vol.Inclusive( - CONF_LATITUDE, - 'coordinates', - 'Latitude and longitude must exist together' - ): cv.latitude, - vol.Inclusive( - CONF_LONGITUDE, - 'coordinates', - 'Latitude and longitude must exist together' - ): cv.longitude, - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_FORECAST): - vol.All(cv.ensure_list, [vol.Range(min=0, max=7)]), - vol.Optional(CONF_HOURLY_FORECAST): - vol.All(cv.ensure_list, [vol.Range(min=0, max=48)]), - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=SCAN_INTERVAL - ) -) +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_MONITORED_CONDITIONS): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), + vol.Required(CONF_API_KEY): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_UNITS): vol.In(ALLOWED_UNITS), + vol.Optional(CONF_LANGUAGE, + default=DEFAULT_LANGUAGE): vol.In(LANGUAGE_CODES), + vol.Inclusive( + CONF_LATITUDE, + 'coordinates', + 'Latitude and longitude must exist together' + ): cv.latitude, + vol.Inclusive( + CONF_LONGITUDE, + 'coordinates', + 'Latitude and longitude must exist together' + ): cv.longitude, + vol.Optional(CONF_FORECAST): + vol.All(cv.ensure_list, [vol.Range(min=0, max=7)]), + vol.Optional(CONF_HOURLY_FORECAST): + vol.All(cv.ensure_list, [vol.Range(min=0, max=48)]), +}) def setup_platform(hass, config, add_entities, discovery_info=None): diff --git a/homeassistant/components/fastdotcom/__init__.py b/homeassistant/components/fastdotcom/__init__.py index 2e092e527c5..973cc8e3659 100644 --- a/homeassistant/components/fastdotcom/__init__.py +++ b/homeassistant/components/fastdotcom/__init__.py @@ -5,8 +5,7 @@ from datetime import timedelta import voluptuous as vol import homeassistant.helpers.config_validation as cv -from homeassistant.const import CONF_UPDATE_INTERVAL, CONF_SCAN_INTERVAL, \ - CONF_UPDATE_INTERVAL_INVALIDATION_VERSION +from homeassistant.const import CONF_SCAN_INTERVAL from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.dispatcher import dispatcher_send from homeassistant.helpers.event import async_track_time_interval @@ -23,21 +22,11 @@ CONF_MANUAL = 'manual' DEFAULT_INTERVAL = timedelta(hours=1) CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.All( - vol.Schema({ - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_MANUAL, default=False): cv.boolean, - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=DEFAULT_INTERVAL - ) - ) + DOMAIN: vol.Schema({ + vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): + vol.All(cv.time_period, cv.positive_timedelta), + vol.Optional(CONF_MANUAL, default=False): cv.boolean, + }) }, extra=vol.ALLOW_EXTRA) diff --git a/homeassistant/components/fedex/sensor.py b/homeassistant/components/fedex/sensor.py index f535195bd07..74ad4f7d0e5 100644 --- a/homeassistant/components/fedex/sensor.py +++ b/homeassistant/components/fedex/sensor.py @@ -1,20 +1,18 @@ """Sensor for Fedex packages.""" -from collections import defaultdict import logging +from collections import defaultdict from datetime import timedelta import voluptuous as vol +import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import (CONF_NAME, CONF_USERNAME, CONF_PASSWORD, - ATTR_ATTRIBUTION, CONF_UPDATE_INTERVAL, - CONF_SCAN_INTERVAL, - CONF_UPDATE_INTERVAL_INVALIDATION_VERSION) + ATTR_ATTRIBUTION, CONF_SCAN_INTERVAL) from homeassistant.helpers.entity import Entity -from homeassistant.util import slugify from homeassistant.util import Throttle +from homeassistant.util import slugify from homeassistant.util.dt import now, parse_date -import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['fedexdeliverymanager==1.0.6'] @@ -30,21 +28,11 @@ STATUS_DELIVERED = 'delivered' SCAN_INTERVAL = timedelta(seconds=1800) -PLATFORM_SCHEMA = vol.All( - PLATFORM_SCHEMA.extend({ - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=SCAN_INTERVAL - ) -) +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_NAME): cv.string, +}) def setup_platform(hass, config, add_entities, discovery_info=None): diff --git a/homeassistant/components/freedns/__init__.py b/homeassistant/components/freedns/__init__.py index a0b14757745..1986c932e22 100644 --- a/homeassistant/components/freedns/__init__.py +++ b/homeassistant/components/freedns/__init__.py @@ -1,16 +1,16 @@ """Integrate with FreeDNS Dynamic DNS service at freedns.afraid.org.""" import asyncio -from datetime import timedelta import logging +from datetime import timedelta import aiohttp import async_timeout import voluptuous as vol -from homeassistant.const import (CONF_URL, CONF_ACCESS_TOKEN, - CONF_UPDATE_INTERVAL, CONF_SCAN_INTERVAL, - CONF_UPDATE_INTERVAL_INVALIDATION_VERSION) import homeassistant.helpers.config_validation as cv +from homeassistant.const import ( + CONF_ACCESS_TOKEN, CONF_SCAN_INTERVAL, CONF_URL +) _LOGGER = logging.getLogger(__name__) @@ -22,22 +22,12 @@ TIMEOUT = 10 UPDATE_URL = 'https://freedns.afraid.org/dynamic/update.php' CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.All( - vol.Schema({ - vol.Exclusive(CONF_URL, DOMAIN): cv.string, - vol.Exclusive(CONF_ACCESS_TOKEN, DOMAIN): cv.string, - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=DEFAULT_INTERVAL - ) - ) + DOMAIN: vol.Schema({ + vol.Exclusive(CONF_URL, DOMAIN): cv.string, + vol.Exclusive(CONF_ACCESS_TOKEN, DOMAIN): cv.string, + vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): + vol.All(cv.time_period, cv.positive_timedelta), + }), }, extra=vol.ALLOW_EXTRA) diff --git a/homeassistant/components/mythicbeastsdns/__init__.py b/homeassistant/components/mythicbeastsdns/__init__.py index 3d0d250557b..4db53bf0407 100644 --- a/homeassistant/components/mythicbeastsdns/__init__.py +++ b/homeassistant/components/mythicbeastsdns/__init__.py @@ -1,15 +1,14 @@ """Support for Mythic Beasts Dynamic DNS service.""" -from datetime import timedelta import logging +from datetime import timedelta import voluptuous as vol +import homeassistant.helpers.config_validation as cv from homeassistant.const import ( - CONF_HOST, CONF_DOMAIN, CONF_PASSWORD, CONF_UPDATE_INTERVAL, - CONF_SCAN_INTERVAL, CONF_UPDATE_INTERVAL_INVALIDATION_VERSION + CONF_DOMAIN, CONF_HOST, CONF_PASSWORD, CONF_SCAN_INTERVAL ) from homeassistant.helpers.aiohttp_client import async_get_clientsession -import homeassistant.helpers.config_validation as cv from homeassistant.helpers.event import async_track_time_interval REQUIREMENTS = ['mbddns==0.1.2'] @@ -21,23 +20,13 @@ DOMAIN = 'mythicbeastsdns' DEFAULT_INTERVAL = timedelta(minutes=10) CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.All( - vol.Schema({ - vol.Required(CONF_DOMAIN): cv.string, - vol.Required(CONF_HOST): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=DEFAULT_INTERVAL - ) - ) + DOMAIN: vol.Schema({ + vol.Required(CONF_DOMAIN): cv.string, + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): + vol.All(cv.time_period, cv.positive_timedelta), + }) }, extra=vol.ALLOW_EXTRA) diff --git a/homeassistant/components/speedtestdotnet/__init__.py b/homeassistant/components/speedtestdotnet/__init__.py index f140f881ef4..48953874e8c 100644 --- a/homeassistant/components/speedtestdotnet/__init__.py +++ b/homeassistant/components/speedtestdotnet/__init__.py @@ -1,18 +1,17 @@ """Support for testing internet speed via Speedtest.net.""" -from datetime import timedelta import logging +from datetime import timedelta import voluptuous as vol +import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.const import ( - CONF_MONITORED_CONDITIONS, CONF_SCAN_INTERVAL, CONF_UPDATE_INTERVAL, - CONF_UPDATE_INTERVAL_INVALIDATION_VERSION) -import homeassistant.helpers.config_validation as cv + CONF_MONITORED_CONDITIONS, CONF_SCAN_INTERVAL +) from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.dispatcher import dispatcher_send from homeassistant.helpers.event import async_track_time_interval - from .const import DATA_UPDATED, DOMAIN, SENSOR_TYPES REQUIREMENTS = ['speedtest-cli==2.1.1'] @@ -25,25 +24,15 @@ CONF_MANUAL = 'manual' DEFAULT_INTERVAL = timedelta(hours=1) CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.All( - vol.Schema({ - vol.Optional(CONF_SERVER_ID): cv.positive_int, - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): - vol.All(cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_MANUAL, default=False): cv.boolean, - vol.Optional( - CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES) - ): vol.All(cv.ensure_list, [vol.In(list(SENSOR_TYPES))]) - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=DEFAULT_INTERVAL - ) - ) + DOMAIN: vol.Schema({ + vol.Optional(CONF_SERVER_ID): cv.positive_int, + vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): + vol.All(cv.time_period, cv.positive_timedelta), + vol.Optional(CONF_MANUAL, default=False): cv.boolean, + vol.Optional( + CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES) + ): vol.All(cv.ensure_list, [vol.In(list(SENSOR_TYPES))]) + }) }, extra=vol.ALLOW_EXTRA) diff --git a/homeassistant/components/tellduslive/__init__.py b/homeassistant/components/tellduslive/__init__.py index 6a6b18557b0..64f4a0102a1 100644 --- a/homeassistant/components/tellduslive/__init__.py +++ b/homeassistant/components/tellduslive/__init__.py @@ -1,22 +1,21 @@ """Support for Telldus Live.""" import asyncio -from functools import partial import logging +from functools import partial import voluptuous as vol -from homeassistant import config_entries -from homeassistant.const import CONF_UPDATE_INTERVAL, CONF_SCAN_INTERVAL, \ - CONF_UPDATE_INTERVAL_INVALIDATION_VERSION import homeassistant.helpers.config_validation as cv +from homeassistant import config_entries +from homeassistant.const import CONF_SCAN_INTERVAL from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.event import async_call_later - from . import config_flow # noqa pylint_disable=unused-import from .const import ( CONF_HOST, DOMAIN, KEY_SCAN_INTERVAL, KEY_SESSION, MIN_UPDATE_INTERVAL, NOT_SO_PRIVATE_KEY, PUBLIC_KEY, SCAN_INTERVAL, - SIGNAL_UPDATE_ENTITY, TELLDUS_DISCOVERY_NEW) + SIGNAL_UPDATE_ENTITY, TELLDUS_DISCOVERY_NEW +) APPLICATION_NAME = 'Home Assistant' @@ -25,21 +24,11 @@ REQUIREMENTS = ['tellduslive==0.10.10'] _LOGGER = logging.getLogger(__name__) CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.All( - vol.Schema({ - vol.Optional(CONF_HOST, default=DOMAIN): cv.string, - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL)), - vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): - vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL)), - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=SCAN_INTERVAL - ) - ) + DOMAIN: vol.Schema({ + vol.Optional(CONF_HOST, default=DOMAIN): cv.string, + vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): + vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL)), + }) }, extra=vol.ALLOW_EXTRA) DATA_CONFIG_ENTRY_LOCK = 'tellduslive_config_entry_lock' diff --git a/homeassistant/components/tplink_lte/__init__.py b/homeassistant/components/tplink_lte/__init__.py index d0f6e600a0d..ae0b73d1c7c 100644 --- a/homeassistant/components/tplink_lte/__init__.py +++ b/homeassistant/components/tplink_lte/__init__.py @@ -6,10 +6,10 @@ import aiohttp import attr import voluptuous as vol -from homeassistant.components.notify import ATTR_TARGET from homeassistant.const import ( - CONF_HOST, CONF_NAME, CONF_PASSWORD, EVENT_HOMEASSISTANT_STOP, - CONF_RECIPIENT) + CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_RECIPIENT, + EVENT_HOMEASSISTANT_STOP +) from homeassistant.core import callback from homeassistant.helpers import config_validation as cv, discovery from homeassistant.helpers.aiohttp_client import async_create_clientsession @@ -23,22 +23,10 @@ DATA_KEY = 'tplink_lte' CONF_NOTIFY = 'notify' -# Deprecated in 0.88.0, invalidated in 0.91.0, remove in 0.92.0 -ATTR_TARGET_INVALIDATION_VERSION = '0.91.0' - -_NOTIFY_SCHEMA = vol.All( - vol.Schema({ - vol.Optional(CONF_NAME): cv.string, - vol.Optional(ATTR_TARGET): vol.All(cv.ensure_list, [cv.string]), - vol.Optional(CONF_RECIPIENT): vol.All(cv.ensure_list, [cv.string]) - }), - cv.deprecated( - ATTR_TARGET, - replacement_key=CONF_RECIPIENT, - invalidation_version=ATTR_TARGET_INVALIDATION_VERSION - ), - cv.has_at_least_one_key(CONF_RECIPIENT), -) +_NOTIFY_SCHEMA = vol.Schema({ + vol.Optional(CONF_NAME): cv.string, + vol.Optional(CONF_RECIPIENT): vol.All(cv.ensure_list, [cv.string]) +}) CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.All(cv.ensure_list, [vol.Schema({ diff --git a/homeassistant/components/ups/sensor.py b/homeassistant/components/ups/sensor.py index f338e990b00..3ed82de41db 100644 --- a/homeassistant/components/ups/sensor.py +++ b/homeassistant/components/ups/sensor.py @@ -1,20 +1,19 @@ """Sensor for UPS packages.""" -from collections import defaultdict import logging +from collections import defaultdict from datetime import timedelta import voluptuous as vol -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import (CONF_NAME, CONF_USERNAME, CONF_PASSWORD, - ATTR_ATTRIBUTION, CONF_UPDATE_INTERVAL, - CONF_SCAN_INTERVAL, - CONF_UPDATE_INTERVAL_INVALIDATION_VERSION) -from homeassistant.helpers.entity import Entity -from homeassistant.util import slugify -from homeassistant.util import Throttle -from homeassistant.util.dt import now, parse_date import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ( + ATTR_ATTRIBUTION, CONF_NAME, CONF_PASSWORD, CONF_SCAN_INTERVAL, + CONF_USERNAME +) +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle, slugify +from homeassistant.util.dt import now, parse_date REQUIREMENTS = ['upsmychoice==1.0.6'] @@ -27,21 +26,11 @@ STATUS_DELIVERED = 'delivered' SCAN_INTERVAL = timedelta(seconds=1800) -PLATFORM_SCHEMA = vol.All( - PLATFORM_SCHEMA.extend({ - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_UPDATE_INTERVAL): ( - vol.All(cv.time_period, cv.positive_timedelta)), - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=SCAN_INTERVAL - ) -) +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_NAME): cv.string, +}) def setup_platform(hass, config, add_entities, discovery_info=None): diff --git a/homeassistant/components/volvooncall/__init__.py b/homeassistant/components/volvooncall/__init__.py index 7e72607c2f3..36e3959338e 100644 --- a/homeassistant/components/volvooncall/__init__.py +++ b/homeassistant/components/volvooncall/__init__.py @@ -1,21 +1,20 @@ """Support for Volvo On Call.""" -from datetime import timedelta import logging +from datetime import timedelta import voluptuous as vol -from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, - CONF_NAME, CONF_RESOURCES, - CONF_UPDATE_INTERVAL, CONF_SCAN_INTERVAL, - CONF_UPDATE_INTERVAL_INVALIDATION_VERSION) -from homeassistant.helpers import discovery import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.event import async_track_point_in_utc_time +from homeassistant.const import ( + CONF_NAME, CONF_PASSWORD, CONF_RESOURCES, CONF_SCAN_INTERVAL, CONF_USERNAME +) +from homeassistant.helpers import discovery from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.dispatcher import ( - async_dispatcher_send, - async_dispatcher_connect) + async_dispatcher_connect, async_dispatcher_send +) +from homeassistant.helpers.entity import Entity +from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.util.dt import utcnow DOMAIN = 'volvooncall' @@ -84,30 +83,20 @@ RESOURCES = [ ] CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.All( - vol.Schema({ - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - vol.Optional(CONF_UPDATE_INTERVAL): - vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL)), - vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_UPDATE_INTERVAL): - vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL)), - vol.Optional(CONF_NAME, default={}): - cv.schema_with_slug_keys(cv.string), - vol.Optional(CONF_RESOURCES): vol.All( - cv.ensure_list, [vol.In(RESOURCES)]), - vol.Optional(CONF_REGION): cv.string, - vol.Optional(CONF_SERVICE_URL): cv.string, - vol.Optional(CONF_MUTABLE, default=True): cv.boolean, - vol.Optional(CONF_SCANDINAVIAN_MILES, default=False): cv.boolean, - }), - cv.deprecated( - CONF_UPDATE_INTERVAL, - replacement_key=CONF_SCAN_INTERVAL, - invalidation_version=CONF_UPDATE_INTERVAL_INVALIDATION_VERSION, - default=DEFAULT_UPDATE_INTERVAL - ) - ) + DOMAIN: vol.Schema({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_UPDATE_INTERVAL): + vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL)), + vol.Optional(CONF_NAME, default={}): + cv.schema_with_slug_keys(cv.string), + vol.Optional(CONF_RESOURCES): vol.All( + cv.ensure_list, [vol.In(RESOURCES)]), + vol.Optional(CONF_REGION): cv.string, + vol.Optional(CONF_SERVICE_URL): cv.string, + vol.Optional(CONF_MUTABLE, default=True): cv.boolean, + vol.Optional(CONF_SCANDINAVIAN_MILES, default=False): cv.boolean, + }) }, extra=vol.ALLOW_EXTRA) diff --git a/homeassistant/const.py b/homeassistant/const.py index e0130f3ccef..295a73a0e6c 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -147,11 +147,6 @@ CONF_TTL = 'ttl' CONF_TYPE = 'type' CONF_UNIT_OF_MEASUREMENT = 'unit_of_measurement' CONF_UNIT_SYSTEM = 'unit_system' - -# Deprecated in 0.88.0, invalidated in 0.91.0, remove in 0.92.0 -CONF_UPDATE_INTERVAL = 'update_interval' -CONF_UPDATE_INTERVAL_INVALIDATION_VERSION = '0.91.0' - CONF_URL = 'url' CONF_USERNAME = 'username' CONF_VALUE_TEMPLATE = 'value_template' From 0c284161eb0d26120816c4909ac8230ee555ad1c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 3 Apr 2019 23:45:09 -0700 Subject: [PATCH 080/167] Validate manifests in CI (#22708) * Validate manifests * Fix mode * Activate venv * Validate manifests after installing HA which includes voluptuous --- .circleci/config.yml | 7 +++ script/manifest/validate.py | 86 +++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100755 script/manifest/validate.py diff --git a/.circleci/config.yml b/.circleci/config.yml index b1fdc2be93b..d31fd512abd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,6 +99,13 @@ jobs: mypy $TYPING_FILES - install + + - run: + name: validate manifests + command: | + . venv/bin/activate + python script/manifest/validate.py + - run: name: run gen_requirements_all command: | diff --git a/script/manifest/validate.py b/script/manifest/validate.py new file mode 100755 index 00000000000..d0d59529d20 --- /dev/null +++ b/script/manifest/validate.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +"""Validate all integrations have manifests and that they are valid.""" +import json +import pathlib +import sys + +import voluptuous as vol +from voluptuous.humanize import humanize_error + + +MANIFEST_SCHEMA = vol.Schema({ + vol.Required('domain'): str, + vol.Required('name'): str, + vol.Required('documentation'): str, + vol.Required('requirements'): [str], + vol.Required('dependencies'): [str], + vol.Required('codeowners'): [str], +}) + + +components_path = pathlib.Path('homeassistant/components') + + +def validate_integration(path): + """Validate that an integrations has a valid manifest.""" + errors = [] + path = pathlib.Path(path) + + manifest_path = path / 'manifest.json' + + if not manifest_path.is_file(): + errors.append('File manifest.json not found') + return errors # Fatal error + + try: + manifest = json.loads(manifest_path.read_text()) + except ValueError as err: + errors.append("Manifest contains invalid JSON: {}".format(err)) + return errors # Fatal error + + try: + MANIFEST_SCHEMA(manifest) + except vol.Invalid as err: + errors.append(humanize_error(manifest, err)) + + if manifest['domain'] != path.name: + errors.append('Domain does not match dir name') + + for dep in manifest['dependencies']: + dep_manifest = path.parent / dep / 'manifest.json' + if not dep_manifest.is_file(): + errors.append("Unable to find dependency {}".format(dep)) + + return errors + + +def validate_all(): + """Validate all integrations.""" + invalid = [] + + for fil in components_path.iterdir(): + if fil.is_file() or fil.name == '__pycache__': + continue + + errors = validate_integration(fil) + + if errors: + invalid.append((fil, errors)) + + if not invalid: + return 0 + + print("Found invalid manifests") + print() + + for integration, errors in invalid: + print(integration) + for error in errors: + print("*", error) + print() + + return 1 + + +if __name__ == '__main__': + sys.exit(validate_all()) From d5307c03d89df3d100198ab7214444199ae091ea Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 3 Apr 2019 23:46:06 -0700 Subject: [PATCH 081/167] Generate codeowners based on manifests (#22705) * Gen codeowners * Update manifest_helper.py --- .circleci/config.yml | 6 + CODEOWNERS | 382 +++++++++++++---------------- script/manifest/codeowners.py | 66 +++++ script/manifest/manifest_helper.py | 15 ++ 4 files changed, 253 insertions(+), 216 deletions(-) create mode 100755 script/manifest/codeowners.py create mode 100644 script/manifest/manifest_helper.py diff --git a/.circleci/config.yml b/.circleci/config.yml index d31fd512abd..70d2f7af3a3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -91,6 +91,12 @@ jobs: . venv/bin/activate flake8 + - run: + name: validate CODEOWNERS + command: | + . venv/bin/activate + python script/manifest/codeowners.py validate + - run: name: run static type check command: | diff --git a/CODEOWNERS b/CODEOWNERS index 5be5610a5c7..ae5bcb452cb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,4 @@ +# This file is generated by script/manifest/codeowners.py # People marked here will be automatically requested for a review # when the code that they own is touched. # https://github.com/blog/2392-introducing-code-owners @@ -7,288 +8,237 @@ setup.py @home-assistant/core homeassistant/*.py @home-assistant/core homeassistant/helpers/* @home-assistant/core homeassistant/util/* @home-assistant/core + +# Virtualization +Dockerfile @home-assistant/docker +virtualization/Docker/* @home-assistant/docker + +# Other code +homeassistant/scripts/check_config.py @kellerza + +# Integrations +homeassistant/components/airvisual/* @bachya +homeassistant/components/alarm_control_panel/* @colinodell +homeassistant/components/alpha_vantage/* @fabaff +homeassistant/components/amazon_polly/* @robbiet480 +homeassistant/components/ambient_station/* @bachya homeassistant/components/api/* @home-assistant/core +homeassistant/components/arduino/* @fabaff +homeassistant/components/arest/* @fabaff +homeassistant/components/asuswrt/* @kennedyshead homeassistant/components/auth/* @home-assistant/core +homeassistant/components/automatic/* @armills homeassistant/components/automation/* @home-assistant/core +homeassistant/components/aws/* @awarecan @robbiet480 +homeassistant/components/axis/* @kane610 +homeassistant/components/bitcoin/* @fabaff +homeassistant/components/blink/* @fronzbot +homeassistant/components/bmw_connected_drive/* @ChristianKuehnel +homeassistant/components/braviatv/* @robbiet480 +homeassistant/components/broadlink/* @danielhiversen +homeassistant/components/brunt/* @eavanvalkenburg +homeassistant/components/bt_smarthub/* @jxwolstenholme homeassistant/components/cloud/* @home-assistant/core +homeassistant/components/cloudflare/* @ludeeus homeassistant/components/config/* @home-assistant/core homeassistant/components/configurator/* @home-assistant/core homeassistant/components/conversation/* @home-assistant/core +homeassistant/components/coolmaster/* @OnFreund +homeassistant/components/counter/* @fabaff +homeassistant/components/cover/* @cdce8p +homeassistant/components/cpuspeed/* @fabaff +homeassistant/components/cups/* @fabaff +homeassistant/components/daikin/* @fredrike @rofrantz +homeassistant/components/darksky/* @fabaff +homeassistant/components/deconz/* @kane610 +homeassistant/components/demo/* @fabaff +homeassistant/components/digital_ocean/* @fabaff +homeassistant/components/discogs/* @thibmaek +homeassistant/components/doorbird/* @oblogic7 +homeassistant/components/dweet/* @fabaff +homeassistant/components/ecovacs/* @OverloadUT +homeassistant/components/edp_redy/* @abmantis +homeassistant/components/egardia/* @jeroenterheerdt +homeassistant/components/eight_sleep/* @mezz64 +homeassistant/components/emby/* @mezz64 +homeassistant/components/ephember/* @ttroy50 +homeassistant/components/eq3btsmart/* @rytilahti +homeassistant/components/esphome/* @OttoWinter +homeassistant/components/file/* @fabaff +homeassistant/components/filter/* @dgomes +homeassistant/components/fitbit/* @robbiet480 +homeassistant/components/fixer/* @fabaff +homeassistant/components/flock/* @fabaff +homeassistant/components/flunearyou/* @bachya +homeassistant/components/foursquare/* @robbiet480 +homeassistant/components/freebox/* @snoof85 homeassistant/components/frontend/* @home-assistant/core +homeassistant/components/gearbest/* @HerrHofrat +homeassistant/components/gitter/* @fabaff +homeassistant/components/glances/* @fabaff +homeassistant/components/gntp/* @robbiet480 +homeassistant/components/google_travel_time/* @robbiet480 +homeassistant/components/googlehome/* @ludeeus +homeassistant/components/gpsd/* @fabaff homeassistant/components/group/* @home-assistant/core +homeassistant/components/gtfs/* @robbiet480 +homeassistant/components/harmony/* @ehendrix23 +homeassistant/components/hassio/* @home-assistant/hassio +homeassistant/components/heos/* @andrewsayre +homeassistant/components/hikvision/* @mezz64 homeassistant/components/history/* @home-assistant/core +homeassistant/components/history_graph/* @andrey-git +homeassistant/components/hive/* @Rendili @KJonline +homeassistant/components/homeassistant/* @home-assistant/core +homeassistant/components/homekit/* @cdce8p +homeassistant/components/html5/* @robbiet480 homeassistant/components/http/* @home-assistant/core +homeassistant/components/huawei_lte/* @scop +homeassistant/components/huawei_router/* @abmantis +homeassistant/components/hue/* @balloob +homeassistant/components/influxdb/* @fabaff homeassistant/components/input_boolean/* @home-assistant/core homeassistant/components/input_datetime/* @home-assistant/core homeassistant/components/input_number/* @home-assistant/core homeassistant/components/input_select/* @home-assistant/core homeassistant/components/input_text/* @home-assistant/core +homeassistant/components/integration/* @dgomes homeassistant/components/introduction/* @home-assistant/core -homeassistant/components/logger/* @home-assistant/core -homeassistant/components/lovelace/* @home-assistant/core -homeassistant/components/mqtt/* @home-assistant/core -homeassistant/components/panel_custom/* @home-assistant/core -homeassistant/components/panel_iframe/* @home-assistant/core -homeassistant/components/onboarding/* @home-assistant/core -homeassistant/components/persistent_notification/* @home-assistant/core -homeassistant/components/scene/__init__.py @home-assistant/core -homeassistant/components/scene/homeassistant.py @home-assistant/core -homeassistant/components/script/* @home-assistant/core -homeassistant/components/shell_command/* @home-assistant/core -homeassistant/components/sun/* @home-assistant/core -homeassistant/components/updater/* @home-assistant/core -homeassistant/components/weblink/* @home-assistant/core -homeassistant/components/websocket_api/* @home-assistant/core -homeassistant/components/zone/* @home-assistant/core - -# Home Assistant Developer Teams -Dockerfile @home-assistant/docker -virtualization/Docker/* @home-assistant/docker - -homeassistant/components/zwave/* @home-assistant/z-wave - -homeassistant/components/hassio/* @home-assistant/hassio - -# Individual platforms - -# A -homeassistant/components/airvisual/sensor.py @bachya -homeassistant/components/alarm_control_panel/manual_mqtt.py @colinodell -homeassistant/components/alpha_vantage/sensor.py @fabaff -homeassistant/components/amazon_polly/* @robbiet480 -homeassistant/components/ambient_station/* @bachya -homeassistant/components/arduino/* @fabaff -homeassistant/components/arest/* @fabaff -homeassistant/components/asuswrt/device_tracker.py @kennedyshead -homeassistant/components/automatic/device_tracker.py @armills -homeassistant/components/aws/* @awarecan @robbiet480 -homeassistant/components/axis/* @kane610 - -# B -homeassistant/components/bitcoin/sensor.py @fabaff -homeassistant/components/blink/* @fronzbot -homeassistant/components/bmw_connected_drive/* @ChristianKuehnel -homeassistant/components/braviatv/media_player.py @robbiet480 -homeassistant/components/broadlink/* @danielhiversen -homeassistant/components/brunt/cover.py @eavanvalkenburg -homeassistant/components/bt_smarthub/device_tracker.py @jxwolstenholme - -# C -homeassistant/components/cloudflare/* @ludeeus -homeassistant/components/coolmaster/climate.py @OnFreund -homeassistant/components/counter/* @fabaff -homeassistant/components/cover/group.py @cdce8p -homeassistant/components/cpuspeed/sensor.py @fabaff -homeassistant/components/cups/sensor.py @fabaff - -# D -homeassistant/components/daikin/* @fredrike @rofrantz -homeassistant/components/darksky/* @fabaff -homeassistant/components/discogs/sensor.py @thibmaek -homeassistant/components/deconz/* @kane610 -homeassistant/components/demo/weather.py @fabaff -homeassistant/components/digital_ocean/* @fabaff -homeassistant/components/doorbird/* @oblogic7 -homeassistant/components/dweet/* @fabaff - -# E -homeassistant/components/ecovacs/* @OverloadUT -homeassistant/components/edp_redy/* @abmantis -homeassistant/components/eight_sleep/* @mezz64 -homeassistant/components/egardia/* @jeroenterheerdt -homeassistant/components/emby/media_player.py @mezz64 -homeassistant/components/ephember/climate.py @ttroy50 -homeassistant/components/eq3btsmart/climate.py @rytilahti -homeassistant/components/esphome/* @OttoWinter - -# F -homeassistant/components/file/* @fabaff -homeassistant/components/filter/sensor.py @dgomes -homeassistant/components/fitbit/sensor.py @robbiet480 -homeassistant/components/fixer/sensor.py @fabaff -homeassistant/components/flock/notify.py @fabaff -homeassistant/components/flunearyou/sensor.py @bachya -homeassistant/components/foursquare/* @robbiet480 -homeassistant/components/freebox/* @snoof85 - -# G -homeassistant/components/gearbest/sensor.py @HerrHofrat -homeassistant/components/gitter/sensor.py @fabaff -homeassistant/components/glances/sensor.py @fabaff -homeassistant/components/gntp/notify.py @robbiet480 -homeassistant/components/google_travel_time/sensor.py @robbiet480 -homeassistant/components/googlehome/* @ludeeus -homeassistant/components/gpsd/sensor.py @fabaff -homeassistant/components/gtfs/sensor.py @robbiet480 - -# H -homeassistant/components/harmony/* @ehendrix23 -homeassistant/components/heos/* @andrewsayre -homeassistant/components/hikvision/binary_sensor.py @mezz64 -homeassistant/components/history_graph/* @andrey-git -homeassistant/components/hive/* @Rendili @KJonline -homeassistant/components/homekit/* @cdce8p -homeassistant/components/html5/notify.py @robbiet480 -homeassistant/components/huawei_lte/* @scop -homeassistant/components/huawei_router/device_tracker.py @abmantis - -# I -homeassistant/components/influxdb/* @fabaff -homeassistant/components/integration/sensor.py @dgomes homeassistant/components/ios/* @robbiet480 homeassistant/components/ipma/* @dgomes -homeassistant/components/irish_rail_transport/sensor.py @ttroy50 - -# J -homeassistant/components/jewish_calendar/sensor.py @tsvi - -# K +homeassistant/components/irish_rail_transport/* @ttroy50 +homeassistant/components/jewish_calendar/* @tsvi homeassistant/components/knx/* @Julius2342 -homeassistant/components/kodi/media_player.py @armills +homeassistant/components/kodi/* @armills homeassistant/components/konnected/* @heythisisnate - -# L -homeassistant/components/lametric/notify.py @robbiet480 -homeassistant/components/launch_library/sensor.py @ludeeus +homeassistant/components/lametric/* @robbiet480 +homeassistant/components/launch_library/* @ludeeus homeassistant/components/lifx/* @amelchio -homeassistant/components/lifx_cloud/scene.py @amelchio -homeassistant/components/lifx_legacy/light.py @amelchio -homeassistant/components/linux_battery/sensor.py @fabaff -homeassistant/components/liveboxplaytv/media_player.py @pschmitt +homeassistant/components/lifx_cloud/* @amelchio +homeassistant/components/lifx_legacy/* @amelchio +homeassistant/components/linux_battery/* @fabaff +homeassistant/components/liveboxplaytv/* @pschmitt +homeassistant/components/logger/* @home-assistant/core +homeassistant/components/lovelace/* @home-assistant/core homeassistant/components/luftdaten/* @fabaff - -# M -homeassistant/components/mastodon/notify.py @fabaff +homeassistant/components/mastodon/* @fabaff homeassistant/components/matrix/* @tinloaf -homeassistant/components/mediaroom/media_player.py @dgomes +homeassistant/components/mediaroom/* @dgomes homeassistant/components/melissa/* @kennedyshead -homeassistant/components/met/weather.py @danielhiversen -homeassistant/components/miflora/sensor.py @danielhiversen @ChristianKuehnel -homeassistant/components/mill/climate.py @danielhiversen -homeassistant/components/min_max/sensor.py @fabaff +homeassistant/components/met/* @danielhiversen +homeassistant/components/miflora/* @danielhiversen @ChristianKuehnel +homeassistant/components/mill/* @danielhiversen +homeassistant/components/min_max/* @fabaff homeassistant/components/mobile_app/* @robbiet480 -homeassistant/components/monoprice/media_player.py @etsinko -homeassistant/components/moon/sensor.py @fabaff -homeassistant/components/mpd/media_player.py @fabaff +homeassistant/components/monoprice/* @etsinko +homeassistant/components/moon/* @fabaff +homeassistant/components/mpd/* @fabaff +homeassistant/components/mqtt/* @home-assistant/core homeassistant/components/mystrom/* @fabaff - -# N -homeassistant/components/nello/lock.py @pschmitt +homeassistant/components/nello/* @pschmitt homeassistant/components/ness_alarm/* @nickw444 homeassistant/components/nest/* @awarecan -homeassistant/components/netdata/sensor.py @fabaff +homeassistant/components/netdata/* @fabaff homeassistant/components/nissan_leaf/* @filcole -homeassistant/components/nmbs/sensor.py @thibmaek +homeassistant/components/nmbs/* @thibmaek homeassistant/components/no_ip/* @fabaff -homeassistant/components/nuki/lock.py @pschmitt -homeassistant/components/nsw_fuel_station/sensor.py @nickw444 - -# O -homeassistant/components/ohmconnect/sensor.py @robbiet480 +homeassistant/components/notify/* @flowolf +homeassistant/components/nsw_fuel_station/* @nickw444 +homeassistant/components/nuki/* @pschmitt +homeassistant/components/ohmconnect/* @robbiet480 +homeassistant/components/onboarding/* @home-assistant/core homeassistant/components/openuv/* @bachya -homeassistant/components/openweathermap/weather.py @fabaff +homeassistant/components/openweathermap/* @fabaff homeassistant/components/owlet/* @oblogic7 - -# P -homeassistant/components/pi_hole/sensor.py @fabaff +homeassistant/components/panel_custom/* @home-assistant/core +homeassistant/components/panel_iframe/* @home-assistant/core +homeassistant/components/persistent_notification/* @home-assistant/core +homeassistant/components/pi_hole/* @fabaff homeassistant/components/plant/* @ChristianKuehnel homeassistant/components/point/* @fredrike -homeassistant/components/pollen/sensor.py @bachya -homeassistant/components/push/camera.py @dgomes -homeassistant/components/pvoutput/sensor.py @fabaff - -# Q -homeassistant/components/qnap/sensor.py @colinodell -homeassistant/components/quantum_gateway/device_tracker.py @cisasteelersfan +homeassistant/components/pollen/* @bachya +homeassistant/components/push/* @dgomes +homeassistant/components/pvoutput/* @fabaff +homeassistant/components/qnap/* @colinodell +homeassistant/components/quantum_gateway/* @cisasteelersfan homeassistant/components/qwikswitch/* @kellerza - -# R homeassistant/components/rainmachine/* @bachya homeassistant/components/random/* @fabaff homeassistant/components/rfxtrx/* @danielhiversen homeassistant/components/rmvtransport/* @cgtobi -homeassistant/components/roomba/vacuum.py @pschmitt -homeassistant/components/ruter/sensor.py @ludeeus - -# S -homeassistant/components/scrape/sensor.py @fabaff -homeassistant/components/sensibo/climate.py @andrey-git -homeassistant/components/serial/sensor.py @fabaff -homeassistant/components/seventeentrack/sensor.py @bachya +homeassistant/components/roomba/* @pschmitt +homeassistant/components/ruter/* @ludeeus +homeassistant/components/scene/* @home-assistant/core +homeassistant/components/scrape/* @fabaff +homeassistant/components/script/* @home-assistant/core +homeassistant/components/sensibo/* @andrey-git +homeassistant/components/serial/* @fabaff +homeassistant/components/seventeentrack/* @bachya +homeassistant/components/shell_command/* @home-assistant/core homeassistant/components/shiftr/* @fabaff -homeassistant/components/shodan/sensor.py @fabaff +homeassistant/components/shodan/* @fabaff homeassistant/components/simplisafe/* @bachya -homeassistant/components/sma/sensor.py @kellerza +homeassistant/components/sma/* @kellerza homeassistant/components/smartthings/* @andrewsayre -homeassistant/components/smtp/notify.py @fabaff +homeassistant/components/smtp/* @fabaff homeassistant/components/sonos/* @amelchio homeassistant/components/spaceapi/* @fabaff homeassistant/components/spider/* @peternijssen -homeassistant/components/sql/sensor.py @dgomes -homeassistant/components/statistics/sensor.py @fabaff -homeassistant/components/swiss_public_transport/* @fabaff +homeassistant/components/sql/* @dgomes +homeassistant/components/statistics/* @fabaff +homeassistant/components/sun/* @home-assistant/core homeassistant/components/swiss_hydrological_data/* @fabaff -homeassistant/components/switchbot/switch.py @danielhiversen -homeassistant/components/switchmate/switch.py @danielhiversen -homeassistant/components/synology_srm/device_tracker.py @aerialls -homeassistant/components/syslog/notify.py @fabaff -homeassistant/components/sytadin/sensor.py @gautric - -# T +homeassistant/components/swiss_public_transport/* @fabaff +homeassistant/components/switchbot/* @danielhiversen +homeassistant/components/switchmate/* @danielhiversen +homeassistant/components/synology_srm/* @aerialls +homeassistant/components/syslog/* @fabaff +homeassistant/components/sytadin/* @gautric homeassistant/components/tahoma/* @philklei -homeassistant/components/tautulli/sensor.py @ludeeus +homeassistant/components/tautulli/* @ludeeus homeassistant/components/tellduslive/* @fredrike -homeassistant/components/template/cover.py @PhracturedBlue +homeassistant/components/template/* @PhracturedBlue homeassistant/components/tesla/* @zabuldon homeassistant/components/tfiac/* @fredrike @mellado homeassistant/components/thethingsnetwork/* @fabaff -homeassistant/components/threshold/binary_sensor.py @fabaff +homeassistant/components/threshold/* @fabaff homeassistant/components/tibber/* @danielhiversen -homeassistant/components/tile/device_tracker.py @bachya -homeassistant/components/time_date/sensor.py @fabaff +homeassistant/components/tile/* @bachya +homeassistant/components/time_date/* @fabaff homeassistant/components/toon/* @frenck homeassistant/components/tplink/* @rytilahti -homeassistant/components/traccar/device_tracker.py @ludeeus +homeassistant/components/traccar/* @ludeeus homeassistant/components/tradfri/* @ggravlingen -homeassistant/components/twilio_call/notify.py @robbiet480 -homeassistant/components/twilio_sms/notify.py @robbiet480 - -# U -homeassistant/components/uber/sensor.py @robbiet480 +homeassistant/components/tts/* @robbiet480 +homeassistant/components/twilio_call/* @robbiet480 +homeassistant/components/twilio_sms/* @robbiet480 +homeassistant/components/uber/* @robbiet480 homeassistant/components/unifi/* @kane610 homeassistant/components/upcloud/* @scop +homeassistant/components/updater/* @home-assistant/core homeassistant/components/upnp/* @robbiet480 -homeassistant/components/uptimerobot/binary_sensor.py @ludeeus +homeassistant/components/uptimerobot/* @ludeeus homeassistant/components/utility_meter/* @dgomes - -# V homeassistant/components/velux/* @Julius2342 -homeassistant/components/version/sensor.py @fabaff - -# W -homeassistant/components/waqi/sensor.py @andrey-git -homeassistant/components/weather/__init__.py @fabaff +homeassistant/components/version/* @fabaff +homeassistant/components/waqi/* @andrey-git +homeassistant/components/weather/* @fabaff +homeassistant/components/weblink/* @home-assistant/core +homeassistant/components/websocket_api/* @home-assistant/core homeassistant/components/wemo/* @sqldiablo -homeassistant/components/worldclock/sensor.py @fabaff - -# X -homeassistant/components/xfinity/device_tracker.py @cisasteelersfan +homeassistant/components/worldclock/* @fabaff +homeassistant/components/xfinity/* @cisasteelersfan homeassistant/components/xiaomi_aqara/* @danielhiversen @syssi homeassistant/components/xiaomi_miio/* @rytilahti @syssi -homeassistant/components/xiaomi_tv/media_player.py @fattdev -homeassistant/components/xmpp/notify.py @fabaff - -# Y +homeassistant/components/xiaomi_tv/* @fattdev +homeassistant/components/xmpp/* @fabaff homeassistant/components/yamaha_musiccast/* @jalmeroth homeassistant/components/yeelight/* @rytilahti @zewelor -homeassistant/components/yeelightsunflower/light.py @lindsaymarkward -homeassistant/components/yessssms/notify.py @flowolf -homeassistant/components/yi/camera.py @bachya - -# Z +homeassistant/components/yeelightsunflower/* @lindsaymarkward +homeassistant/components/yessssms/* @flowolf +homeassistant/components/yi/* @bachya homeassistant/components/zeroconf/* @robbiet480 homeassistant/components/zha/* @dmulcahey @adminiuga +homeassistant/components/zone/* @home-assistant/core homeassistant/components/zoneminder/* @rohankapoorcom - -# Other code -homeassistant/scripts/check_config.py @kellerza +homeassistant/components/zwave/* @home-assistant/z-wave diff --git a/script/manifest/codeowners.py b/script/manifest/codeowners.py new file mode 100755 index 00000000000..9745f3b82f2 --- /dev/null +++ b/script/manifest/codeowners.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""Generate CODEOWNERS.""" +import os +import sys + +from manifest_helper import iter_manifests + +BASE = """ +# This file is generated by script/manifest/codeowners.py +# People marked here will be automatically requested for a review +# when the code that they own is touched. +# https://github.com/blog/2392-introducing-code-owners + +# Home Assistant Core +setup.py @home-assistant/core +homeassistant/*.py @home-assistant/core +homeassistant/helpers/* @home-assistant/core +homeassistant/util/* @home-assistant/core + +# Virtualization +Dockerfile @home-assistant/docker +virtualization/Docker/* @home-assistant/docker + +# Other code +homeassistant/scripts/check_config.py @kellerza + +# Integrations +""" + + +def generate(): + """Generate CODEOWNERS.""" + parts = [BASE.strip()] + + for manifest in iter_manifests(): + if not manifest['codeowners']: + continue + + parts.append("homeassistant/components/{}/* {}".format( + manifest['domain'], ' '.join(manifest['codeowners']))) + + return '\n'.join(parts) + + +def main(validate): + """Runner for CODEOWNERS gen.""" + if not os.path.isfile('requirements_all.txt'): + print('Run this from HA root dir') + return 1 + + content = generate() + + if validate: + with open('CODEOWNERS', 'r') as fp: + if fp.read().strip() != content: + print("CODEOWNERS is not up to date. " + "Run python script/manifest/codeowners.py") + return 1 + return 0 + + with open('CODEOWNERS', 'w') as fp: + fp.write(content + '\n') + + +if __name__ == '__main__': + sys.exit(main(sys.argv[-1] == 'validate')) diff --git a/script/manifest/manifest_helper.py b/script/manifest/manifest_helper.py new file mode 100644 index 00000000000..3b4cfa11796 --- /dev/null +++ b/script/manifest/manifest_helper.py @@ -0,0 +1,15 @@ +"""Helpers to deal with manifests.""" +import json +import pathlib + + +component_dir = pathlib.Path('homeassistant/components') + + +def iter_manifests(): + """Iterate over all available manifests.""" + manifests = [ + json.loads(fil.read_text()) + for fil in component_dir.glob('*/manifest.json') + ] + return sorted(manifests, key=lambda man: man['domain']) From f9564400e8c3cbd00d4dd9ad68ce9076316763c9 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Wed, 3 Apr 2019 23:53:17 -0700 Subject: [PATCH 082/167] Activate codeowners-mention via GitHub actions --- .github/main.workflow | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/main.workflow diff --git a/.github/main.workflow b/.github/main.workflow new file mode 100644 index 00000000000..62336ebf126 --- /dev/null +++ b/.github/main.workflow @@ -0,0 +1,14 @@ +workflow "Mention CODEOWNERS of integrations when integration label is added to an issue" { + on = "issues" + resolves = "codeowners-mention" +} + +workflow "Mention CODEOWNERS of integrations when integration label is added to an PRs" { + on = "pull_request" + resolves = "codeowners-mention" +} + +action "codeowners-mention" { + uses = "home-assistant/codeowners-mention@master" + secrets = ["GITHUB_TOKEN"] +} From 704983a64f4d11dceff4180d084da8d00e71421a Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Thu, 4 Apr 2019 00:34:34 -0700 Subject: [PATCH 083/167] Fix hassio CODEOWNER to be the actual team name, hass-io --- CODEOWNERS | 2 +- homeassistant/components/hassio/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index ae5bcb452cb..5adc4d071c2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -83,7 +83,7 @@ homeassistant/components/gpsd/* @fabaff homeassistant/components/group/* @home-assistant/core homeassistant/components/gtfs/* @robbiet480 homeassistant/components/harmony/* @ehendrix23 -homeassistant/components/hassio/* @home-assistant/hassio +homeassistant/components/hassio/* @home-assistant/hass-io homeassistant/components/heos/* @andrewsayre homeassistant/components/hikvision/* @mezz64 homeassistant/components/history/* @home-assistant/core diff --git a/homeassistant/components/hassio/manifest.json b/homeassistant/components/hassio/manifest.json index e412f587abd..be345fb5adb 100644 --- a/homeassistant/components/hassio/manifest.json +++ b/homeassistant/components/hassio/manifest.json @@ -7,6 +7,6 @@ "http" ], "codeowners": [ - "@home-assistant/hassio" + "@home-assistant/hass-io" ] } From d231d598963a79ad77863abb4ee36681447bd0b2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 4 Apr 2019 00:46:20 -0700 Subject: [PATCH 084/167] Remove deprecated Insteon components (#22710) --- .../components/insteon_local/__init__.py | 23 ------------------- .../components/insteon_local/manifest.json | 8 ------- .../components/insteon_plm/__init__.py | 23 ------------------- .../components/insteon_plm/manifest.json | 8 ------- 4 files changed, 62 deletions(-) delete mode 100644 homeassistant/components/insteon_local/__init__.py delete mode 100644 homeassistant/components/insteon_local/manifest.json delete mode 100644 homeassistant/components/insteon_plm/__init__.py delete mode 100644 homeassistant/components/insteon_plm/manifest.json diff --git a/homeassistant/components/insteon_local/__init__.py b/homeassistant/components/insteon_local/__init__.py deleted file mode 100644 index f73c46746f0..00000000000 --- a/homeassistant/components/insteon_local/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Local support for Insteon.""" -import logging - -_LOGGER = logging.getLogger(__name__) - - -def setup(hass, config): - """Set up the insteon_local component. - - This component is deprecated as of release 0.77 and should be removed in - release 0.90. - """ - _LOGGER.warning('The insteon_local component has been replaced by ' - 'the insteon component') - _LOGGER.warning('Please see https://home-assistant.io/components/insteon') - - hass.components.persistent_notification.create( - 'insteon_local has been replaced by the insteon component.
' - 'Please see https://home-assistant.io/components/insteon', - title='insteon_local Component Deactivated', - notification_id='insteon_local') - - return False diff --git a/homeassistant/components/insteon_local/manifest.json b/homeassistant/components/insteon_local/manifest.json deleted file mode 100644 index 64b6bccdba6..00000000000 --- a/homeassistant/components/insteon_local/manifest.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "domain": "insteon_local", - "name": "Insteon local", - "documentation": "https://www.home-assistant.io/components/insteon_local", - "requirements": [], - "dependencies": [], - "codeowners": [] -} diff --git a/homeassistant/components/insteon_plm/__init__.py b/homeassistant/components/insteon_plm/__init__.py deleted file mode 100644 index 5ff492b6f6c..00000000000 --- a/homeassistant/components/insteon_plm/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Support for INSTEON PowerLinc Modem.""" -import logging - -_LOGGER = logging.getLogger(__name__) - - -async def async_setup(hass, config): - """Set up the insteon_plm component. - - This component is deprecated as of release 0.77 and should be removed in - release 0.90. - """ - _LOGGER.warning('The insteon_plm component has been replaced by ' - 'the insteon component') - _LOGGER.warning('Please see https://home-assistant.io/components/insteon') - - hass.components.persistent_notification.create( - 'insteon_plm has been replaced by the insteon component.
' - 'Please see https://home-assistant.io/components/insteon', - title='insteon_plm Component Deactivated', - notification_id='insteon_plm') - - return False diff --git a/homeassistant/components/insteon_plm/manifest.json b/homeassistant/components/insteon_plm/manifest.json deleted file mode 100644 index fa382dd2df0..00000000000 --- a/homeassistant/components/insteon_plm/manifest.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "domain": "insteon_plm", - "name": "Insteon plm", - "documentation": "https://www.home-assistant.io/components/insteon_plm", - "requirements": [], - "dependencies": [], - "codeowners": [] -} From beb6ddfa68e6f1c1ef836af863f2c1a168d632b7 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 4 Apr 2019 11:10:44 +0200 Subject: [PATCH 085/167] Change URL handling (#22713) --- homeassistant/components/hassio/ingress.py | 28 +++++++++++----------- tests/components/hassio/test_ingress.py | 10 ++++---- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/hassio/ingress.py b/homeassistant/components/hassio/ingress.py index 04241f53de9..9b62bb89c94 100644 --- a/homeassistant/components/hassio/ingress.py +++ b/homeassistant/components/hassio/ingress.py @@ -30,7 +30,7 @@ class HassIOIngress(HomeAssistantView): """Hass.io view to handle base part.""" name = "api:hassio:ingress" - url = "/api/hassio_ingress/{addon}/{path:.+}" + url = "/api/hassio_ingress/{token}/{path:.+}" requires_auth = False def __init__(self, host: str, websession: aiohttp.ClientSession): @@ -38,21 +38,21 @@ class HassIOIngress(HomeAssistantView): self._host = host self._websession = websession - def _create_url(self, addon: str, path: str) -> str: + def _create_url(self, token: str, path: str) -> str: """Create URL to service.""" - return "http://{}/addons/{}/web/{}".format(self._host, addon, path) + return "http://{}/ingress/{}/{}".format(self._host, token, path) async def _handle( - self, request: web.Request, addon: str, path: str + self, request: web.Request, token: str, path: str ) -> Union[web.Response, web.StreamResponse, web.WebSocketResponse]: """Route data to Hass.io ingress service.""" try: # Websocket if _is_websocket(request): - return await self._handle_websocket(request, addon, path) + return await self._handle_websocket(request, token, path) # Request - return await self._handle_request(request, addon, path) + return await self._handle_request(request, token, path) except aiohttp.ClientError: pass @@ -65,15 +65,15 @@ class HassIOIngress(HomeAssistantView): delete = _handle async def _handle_websocket( - self, request: web.Request, addon: str, path: str + self, request: web.Request, token: str, path: str ) -> web.WebSocketResponse: """Ingress route for websocket.""" ws_server = web.WebSocketResponse() await ws_server.prepare(request) # Preparing - url = self._create_url(addon, path) - source_header = _init_header(request, addon) + url = self._create_url(token, path) + source_header = _init_header(request, token) # Support GET query if request.query_string: @@ -95,12 +95,12 @@ class HassIOIngress(HomeAssistantView): return ws_server async def _handle_request( - self, request: web.Request, addon: str, path: str + self, request: web.Request, token: str, path: str ) -> Union[web.Response, web.StreamResponse]: """Ingress route for request.""" - url = self._create_url(addon, path) + url = self._create_url(token, path) data = await request.read() - source_header = _init_header(request, addon) + source_header = _init_header(request, token) async with self._websession.request( request.method, url, headers=source_header, @@ -136,7 +136,7 @@ class HassIOIngress(HomeAssistantView): def _init_header( - request: web.Request, addon: str + request: web.Request, token: str ) -> Union[CIMultiDict, Dict[str, str]]: """Create initial header.""" headers = {} @@ -151,7 +151,7 @@ def _init_header( headers[X_HASSIO] = os.environ.get('HASSIO_TOKEN', "") # Ingress information - headers[X_INGRESS_PATH] = "/api/hassio_ingress/{}".format(addon) + headers[X_INGRESS_PATH] = "/api/hassio_ingress/{}".format(token) # Set X-Forwarded-For forward_for = request.headers.get(hdrs.X_FORWARDED_FOR) diff --git a/tests/components/hassio/test_ingress.py b/tests/components/hassio/test_ingress.py index 4b72eda4c25..0dda69b2b17 100644 --- a/tests/components/hassio/test_ingress.py +++ b/tests/components/hassio/test_ingress.py @@ -13,7 +13,7 @@ import pytest async def test_ingress_request_get( hassio_client, build_type, aioclient_mock): """Test no auth needed for .""" - aioclient_mock.get("http://127.0.0.1/addons/{}/web/{}".format( + aioclient_mock.get("http://127.0.0.1/ingress/{}/{}".format( build_type[0], build_type[1]), text="test") resp = await hassio_client.get( @@ -45,7 +45,7 @@ async def test_ingress_request_get( async def test_ingress_request_post( hassio_client, build_type, aioclient_mock): """Test no auth needed for .""" - aioclient_mock.post("http://127.0.0.1/addons/{}/web/{}".format( + aioclient_mock.post("http://127.0.0.1/ingress/{}/{}".format( build_type[0], build_type[1]), text="test") resp = await hassio_client.post( @@ -77,7 +77,7 @@ async def test_ingress_request_post( async def test_ingress_request_put( hassio_client, build_type, aioclient_mock): """Test no auth needed for .""" - aioclient_mock.put("http://127.0.0.1/addons/{}/web/{}".format( + aioclient_mock.put("http://127.0.0.1/ingress/{}/{}".format( build_type[0], build_type[1]), text="test") resp = await hassio_client.put( @@ -109,7 +109,7 @@ async def test_ingress_request_put( async def test_ingress_request_delete( hassio_client, build_type, aioclient_mock): """Test no auth needed for .""" - aioclient_mock.delete("http://127.0.0.1/addons/{}/web/{}".format( + aioclient_mock.delete("http://127.0.0.1/ingress/{}/{}".format( build_type[0], build_type[1]), text="test") resp = await hassio_client.delete( @@ -142,7 +142,7 @@ async def test_ingress_request_delete( async def test_ingress_websocket( hassio_client, build_type, aioclient_mock): """Test no auth needed for .""" - aioclient_mock.get("http://127.0.0.1/addons/{}/web/{}".format( + aioclient_mock.get("http://127.0.0.1/ingress/{}/{}".format( build_type[0], build_type[1])) # Ignore error because we can setup a full IO infrastructure From 754c4d205bdf830bb9240a8973f3fb8ddec8f8d2 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Thu, 4 Apr 2019 02:15:20 -0700 Subject: [PATCH 086/167] Allow users to set encoding of mikrotik connection (#22715) ## Description: Mikrotik does some stupid stuff with character encoding that can screw up the DHCP responses. See #15257 for more detail. **Related issue (if applicable):** fixes #15257 ## Checklist: - [x] The code change is tested and works locally. - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass** - [x] There is no commented out code in this PR. --- homeassistant/components/mikrotik/device_tracker.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/mikrotik/device_tracker.py b/homeassistant/components/mikrotik/device_tracker.py index ed0734588ef..7d376b431bb 100644 --- a/homeassistant/components/mikrotik/device_tracker.py +++ b/homeassistant/components/mikrotik/device_tracker.py @@ -18,13 +18,17 @@ _LOGGER = logging.getLogger(__name__) MTK_DEFAULT_API_PORT = '8728' MTK_DEFAULT_API_SSL_PORT = '8729' +CONF_ENCODING = 'encoding' +DEFAULT_ENCODING = 'utf-8' + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_METHOD): cv.string, vol.Optional(CONF_PORT): cv.port, - vol.Optional(CONF_SSL, default=False): cv.boolean + vol.Optional(CONF_SSL, default=False): cv.boolean, + vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): cv.string, }) @@ -59,6 +63,7 @@ class MikrotikScanner(DeviceScanner): self.client = None self.wireless_exist = None self.success_init = self.connect_to_device() + self.encoding = config[CONF_ENCODING] if self.success_init: _LOGGER.info("Start polling Mikrotik (%s) router...", self.host) @@ -72,7 +77,7 @@ class MikrotikScanner(DeviceScanner): try: kwargs = { 'port': self.port, - 'encoding': 'utf-8' + 'encoding': self.encoding } if self.ssl: ssl_context = ssl.create_default_context() From 5d7c29dee24c341e16ddf5907ae50697d442b914 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Thu, 4 Apr 2019 13:01:56 +0200 Subject: [PATCH 087/167] Only post coverage comment if coverage changes (#22721) --- .codecov.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.codecov.yml b/.codecov.yml index 96a39e7319b..9ad9083506d 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -11,3 +11,5 @@ coverage: slack: default: url: "secret:TgWDUM4Jw0w7wMJxuxNF/yhSOHglIo1fGwInJnRLEVPy2P2aLimkoK1mtKCowH5TFw+baUXVXT3eAqefbdvIuM8BjRR4aRji95C6CYyD0QHy4N8i7nn1SQkWDPpS8IthYTg07rUDF7s5guurkKv2RrgoCdnnqjAMSzHoExMOF7xUmblMdhBTWJgBpWEhASJy85w/xxjlsE1xoTkzeJu9Q67pTXtRcn+5kb5/vIzPSYg=" +comment: + require_changes: yes From 172ede217afd2c83cd2be49de89ce773a95691dc Mon Sep 17 00:00:00 2001 From: Eliran Turgeman Date: Thu, 4 Apr 2019 15:23:31 +0300 Subject: [PATCH 088/167] Add 10 additional language options to DarkSky (#22719) --- homeassistant/components/darksky/sensor.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/darksky/sensor.py b/homeassistant/components/darksky/sensor.py index 0e87593b25c..6aee3457acb 100644 --- a/homeassistant/components/darksky/sensor.py +++ b/homeassistant/components/darksky/sensor.py @@ -157,10 +157,11 @@ CONDITION_PICTURES = { # Language Supported Codes LANGUAGE_CODES = [ - 'ar', 'az', 'be', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'el', 'en', 'es', - 'et', 'fi', 'fr', 'he', 'hr', 'hu', 'id', 'is', 'it', 'ja', 'ka', 'ko', - 'kw', 'lv', 'nb', 'nl', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv', - 'tet', 'tr', 'uk', 'x-pig-latin', 'zh', 'zh-tw', + 'ar', 'az', 'be', 'bg', 'bn', 'bs', 'ca', 'cs', 'da', 'de', 'el', 'en', + 'ja', 'ka', 'kn', 'ko', 'eo', 'es', 'et', 'fi', 'fr', 'he', 'hi', 'hr', + 'hu', 'id', 'is', 'it', 'kw', 'lv', 'ml', 'mr', 'nb', 'nl', 'pa', 'pl', + 'pt', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv', 'ta', 'te', 'tet', 'tr', 'uk', + 'ur', 'x-pig-latin', 'zh', 'zh-tw', ] ALLOWED_UNITS = ['auto', 'si', 'us', 'ca', 'uk', 'uk2'] From e29eb4fa23fd1f2b257fe660efea4602f7d5703a Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Thu, 4 Apr 2019 09:06:54 -0400 Subject: [PATCH 089/167] fix device class lookup for binary sensors (#22724) --- homeassistant/components/zha/core/const.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 02f43a4bbf6..193780c9124 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -76,7 +76,6 @@ ELECTRICAL_MEASUREMENT = 'electrical_measurement' GENERIC = 'generic' UNKNOWN = 'unknown' OPENING = 'opening' -ZONE = 'zone' OCCUPANCY = 'occupancy' ACCELERATION = 'acceleration' @@ -89,7 +88,7 @@ BASIC_CHANNEL = 'basic' COLOR_CHANNEL = 'light_color' FAN_CHANNEL = 'fan' LEVEL_CHANNEL = ATTR_LEVEL -ZONE_CHANNEL = 'ias_zone' +ZONE_CHANNEL = ZONE = 'ias_zone' ELECTRICAL_MEASUREMENT_CHANNEL = 'electrical_measurement' POWER_CONFIGURATION_CHANNEL = 'power' EVENT_RELAY_CHANNEL = 'event_relay' From 9bb88a6143c2cab5c58fb4f176947bc74673be99 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 4 Apr 2019 17:43:18 +0200 Subject: [PATCH 090/167] Fix ingress routing with / (#22728) --- homeassistant/components/hassio/ingress.py | 2 +- tests/components/hassio/test_ingress.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/hassio/ingress.py b/homeassistant/components/hassio/ingress.py index 9b62bb89c94..49e949c5789 100644 --- a/homeassistant/components/hassio/ingress.py +++ b/homeassistant/components/hassio/ingress.py @@ -30,7 +30,7 @@ class HassIOIngress(HomeAssistantView): """Hass.io view to handle base part.""" name = "api:hassio:ingress" - url = "/api/hassio_ingress/{token}/{path:.+}" + url = "/api/hassio_ingress/{token}/{path:.*}" requires_auth = False def __init__(self, host: str, websession: aiohttp.ClientSession): diff --git a/tests/components/hassio/test_ingress.py b/tests/components/hassio/test_ingress.py index 0dda69b2b17..343068375de 100644 --- a/tests/components/hassio/test_ingress.py +++ b/tests/components/hassio/test_ingress.py @@ -8,7 +8,8 @@ import pytest @pytest.mark.parametrize( 'build_type', [ ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), - ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5") + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5"), + ("fsadjf10312", "") ]) async def test_ingress_request_get( hassio_client, build_type, aioclient_mock): @@ -40,7 +41,8 @@ async def test_ingress_request_get( @pytest.mark.parametrize( 'build_type', [ ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), - ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5") + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5"), + ("fsadjf10312", "") ]) async def test_ingress_request_post( hassio_client, build_type, aioclient_mock): @@ -72,7 +74,8 @@ async def test_ingress_request_post( @pytest.mark.parametrize( 'build_type', [ ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), - ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5") + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5"), + ("fsadjf10312", "") ]) async def test_ingress_request_put( hassio_client, build_type, aioclient_mock): @@ -104,7 +107,8 @@ async def test_ingress_request_put( @pytest.mark.parametrize( 'build_type', [ ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), - ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5") + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5"), + ("fsadjf10312", "") ]) async def test_ingress_request_delete( hassio_client, build_type, aioclient_mock): From 07d739c14e21d09b157ff0fcc7418308dd8ad5a8 Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Thu, 4 Apr 2019 19:18:54 +0200 Subject: [PATCH 091/167] Add N26 component (#22684) * upgraded n26 dependency removed card_id config parameter (unnecessary) get_token is now a public method inside n26 dependency * Add manifest.json --- .coveragerc | 1 + homeassistant/components/n26/__init__.py | 153 +++++++++++++ homeassistant/components/n26/const.py | 7 + homeassistant/components/n26/manifest.json | 10 + homeassistant/components/n26/sensor.py | 248 +++++++++++++++++++++ homeassistant/components/n26/switch.py | 64 ++++++ requirements_all.txt | 3 + 7 files changed, 486 insertions(+) create mode 100644 homeassistant/components/n26/__init__.py create mode 100644 homeassistant/components/n26/const.py create mode 100644 homeassistant/components/n26/manifest.json create mode 100644 homeassistant/components/n26/sensor.py create mode 100644 homeassistant/components/n26/switch.py diff --git a/.coveragerc b/.coveragerc index f8d8b0fc521..957b3402c46 100644 --- a/.coveragerc +++ b/.coveragerc @@ -366,6 +366,7 @@ omit = homeassistant/components/mystrom/binary_sensor.py homeassistant/components/mystrom/light.py homeassistant/components/mystrom/switch.py + homeassistant/components/n26/* homeassistant/components/nad/media_player.py homeassistant/components/nadtcp/media_player.py homeassistant/components/nanoleaf/light.py diff --git a/homeassistant/components/n26/__init__.py b/homeassistant/components/n26/__init__.py new file mode 100644 index 00000000000..8f4ade9c87f --- /dev/null +++ b/homeassistant/components/n26/__init__.py @@ -0,0 +1,153 @@ +"""Support for N26 bank accounts.""" +from datetime import datetime, timedelta, timezone +import logging + +import voluptuous as vol + +from homeassistant.const import ( + CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_USERNAME) +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.discovery import load_platform +from homeassistant.util import Throttle + +from .const import DATA, DOMAIN + +REQUIREMENTS = ['n26==0.2.7'] + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_SCAN_INTERVAL = timedelta(minutes=30) + +# define configuration parameters +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=DEFAULT_SCAN_INTERVAL): cv.time_period, + }), +}, extra=vol.ALLOW_EXTRA) + +N26_COMPONENTS = [ + 'sensor', + 'switch' +] + + +def setup(hass, config): + """Set up N26 Component.""" + user = config[DOMAIN][CONF_USERNAME] + password = config[DOMAIN][CONF_PASSWORD] + + from n26 import api, config as api_config + api = api.Api(api_config.Config(user, password)) + + from requests import HTTPError + try: + api.get_token() + except HTTPError as err: + _LOGGER.error(str(err)) + return False + + api_data = N26Data(api) + api_data.update() + + hass.data[DOMAIN] = {} + hass.data[DOMAIN][DATA] = api_data + + # Load components for supported devices + for component in N26_COMPONENTS: + load_platform(hass, component, DOMAIN, {}, config) + + return True + + +def timestamp_ms_to_date(epoch_ms) -> datetime or None: + """Convert millisecond timestamp to datetime.""" + if epoch_ms: + return datetime.fromtimestamp(epoch_ms / 1000, timezone.utc) + + +class N26Data: + """Handle N26 API object and limit updates.""" + + def __init__(self, api): + """Initialize the data object.""" + self._api = api + + self._account_info = {} + self._balance = {} + self._limits = {} + self._account_statuses = {} + + self._cards = {} + self._spaces = {} + + @property + def api(self): + """Return N26 api client.""" + return self._api + + @property + def account_info(self): + """Return N26 account info.""" + return self._account_info + + @property + def balance(self): + """Return N26 account balance.""" + return self._balance + + @property + def limits(self): + """Return N26 account limits.""" + return self._limits + + @property + def account_statuses(self): + """Return N26 account statuses.""" + return self._account_statuses + + @property + def cards(self): + """Return N26 cards.""" + return self._cards + + def card(self, card_id: str, default: dict = None): + """Return a card by its id or the given default.""" + return next((card for card in self.cards if card["id"] == card_id), + default) + + @property + def spaces(self): + """Return N26 spaces.""" + return self._spaces + + def space(self, space_id: str, default: dict = None): + """Return a space by its id or the given default.""" + return next((space for space in self.spaces["spaces"] + if space["id"] == space_id), default) + + @Throttle(min_time=DEFAULT_SCAN_INTERVAL * 0.8) + def update_account(self): + """Get the latest account data from N26.""" + self._account_info = self._api.get_account_info() + self._balance = self._api.get_balance() + self._limits = self._api.get_account_limits() + self._account_statuses = self._api.get_account_statuses() + + @Throttle(min_time=DEFAULT_SCAN_INTERVAL * 0.8) + def update_cards(self): + """Get the latest cards data from N26.""" + self._cards = self._api.get_cards() + + @Throttle(min_time=DEFAULT_SCAN_INTERVAL * 0.8) + def update_spaces(self): + """Get the latest spaces data from N26.""" + self._spaces = self._api.get_spaces() + + def update(self): + """Get the latest data from N26.""" + self.update_account() + self.update_cards() + self.update_spaces() diff --git a/homeassistant/components/n26/const.py b/homeassistant/components/n26/const.py new file mode 100644 index 00000000000..0a640d0f34e --- /dev/null +++ b/homeassistant/components/n26/const.py @@ -0,0 +1,7 @@ +"""Provides the constants needed for component.""" +DOMAIN = "n26" + +DATA = "data" + +CARD_STATE_ACTIVE = "M_ACTIVE" +CARD_STATE_BLOCKED = "M_DISABLED" diff --git a/homeassistant/components/n26/manifest.json b/homeassistant/components/n26/manifest.json new file mode 100644 index 00000000000..b49932887d5 --- /dev/null +++ b/homeassistant/components/n26/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "n26", + "name": "N26", + "documentation": "https://www.home-assistant.io/components/n26", + "requirements": [ + "n26==0.2.7" + ], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/n26/sensor.py b/homeassistant/components/n26/sensor.py new file mode 100644 index 00000000000..682cd5dae68 --- /dev/null +++ b/homeassistant/components/n26/sensor.py @@ -0,0 +1,248 @@ +"""Support for N26 bank account sensors.""" +import logging + +from homeassistant.helpers.entity import Entity + +from . import DEFAULT_SCAN_INTERVAL, DOMAIN, timestamp_ms_to_date +from .const import DATA + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['n26'] + +SCAN_INTERVAL = DEFAULT_SCAN_INTERVAL + +ATTR_IBAN = "account" +ATTR_USABLE_BALANCE = "usable_balance" +ATTR_BANK_BALANCE = "bank_balance" + +ATTR_ACC_OWNER_TITLE = "owner_title" +ATTR_ACC_OWNER_FIRST_NAME = "owner_first_name" +ATTR_ACC_OWNER_LAST_NAME = "owner_last_name" +ATTR_ACC_OWNER_GENDER = "owner_gender" +ATTR_ACC_OWNER_BIRTH_DATE = "owner_birth_date" +ATTR_ACC_OWNER_EMAIL = "owner_email" +ATTR_ACC_OWNER_PHONE_NUMBER = "owner_phone_number" + +ICON_ACCOUNT = 'mdi:currency-eur' +ICON_CARD = 'mdi:credit-card' +ICON_SPACE = 'mdi:crop-square' + + +def setup_platform( + hass, config, add_entities, discovery_info=None): + """Set up the N26 sensor platform.""" + api_data = hass.data[DOMAIN][DATA] + + sensor_entities = [N26Account(api_data)] + + for card in api_data.cards: + sensor_entities.append(N26Card(api_data, card)) + + for space in api_data.spaces["spaces"]: + sensor_entities.append(N26Space(api_data, space)) + + add_entities(sensor_entities) + + +class N26Account(Entity): + """Sensor for a N26 balance account. + + A balance account contains an amount of money (=balance). The amount may + also be negative. + """ + + def __init__(self, api_data) -> None: + """Initialize a N26 balance account.""" + self._data = api_data + self._iban = self._data.balance["iban"] + + def update(self) -> None: + """Get the current balance and currency for the account.""" + self._data.update_account() + + @property + def unique_id(self): + """Return the unique ID of the entity.""" + return self._iban[-4:] + + @property + def name(self) -> str: + """Friendly name of the sensor.""" + return "n26_{}".format(self._iban[-4:]) + + @property + def state(self) -> float: + """Return the balance of the account as state.""" + if self._data.balance is None: + return None + + return self._data.balance.get("availableBalance") + + @property + def unit_of_measurement(self) -> str: + """Use the currency as unit of measurement.""" + if self._data.balance is None: + return None + + return self._data.balance.get("currency") + + @property + def device_state_attributes(self) -> dict: + """Additional attributes of the sensor.""" + attributes = { + ATTR_IBAN: self._data.balance.get("iban"), + ATTR_BANK_BALANCE: self._data.balance.get("bankBalance"), + ATTR_USABLE_BALANCE: self._data.balance.get("usableBalance"), + ATTR_ACC_OWNER_TITLE: self._data.account_info.get("title"), + ATTR_ACC_OWNER_FIRST_NAME: + self._data.account_info.get("kycFirstName"), + ATTR_ACC_OWNER_LAST_NAME: + self._data.account_info.get("kycLastName"), + ATTR_ACC_OWNER_GENDER: self._data.account_info.get("gender"), + ATTR_ACC_OWNER_BIRTH_DATE: timestamp_ms_to_date( + self._data.account_info.get("birthDate")), + ATTR_ACC_OWNER_EMAIL: self._data.account_info.get("email"), + ATTR_ACC_OWNER_PHONE_NUMBER: + self._data.account_info.get("mobilePhoneNumber"), + } + + for limit in self._data.limits: + limit_attr_name = "limit_{}".format(limit["limit"].lower()) + attributes[limit_attr_name] = limit["amount"] + + return attributes + + @property + def icon(self) -> str: + """Set the icon for the sensor.""" + return ICON_ACCOUNT + + +class N26Card(Entity): + """Sensor for a N26 card.""" + + def __init__(self, api_data, card) -> None: + """Initialize a N26 card.""" + self._data = api_data + self._account_name = api_data.balance["iban"][-4:] + self._card = card + + def update(self) -> None: + """Get the current balance and currency for the account.""" + self._data.update_cards() + self._card = self._data.card(self._card["id"], self._card) + + @property + def unique_id(self): + """Return the unique ID of the entity.""" + return self._card["id"] + + @property + def name(self) -> str: + """Friendly name of the sensor.""" + return "{}_card_{}".format( + self._account_name.lower(), self._card["id"]) + + @property + def state(self) -> float: + """Return the balance of the account as state.""" + return self._card["status"] + + @property + def device_state_attributes(self) -> dict: + """Additional attributes of the sensor.""" + attributes = { + "apple_pay_eligible": self._card.get("applePayEligible"), + "card_activated": timestamp_ms_to_date( + self._card.get("cardActivated")), + "card_product": self._card.get("cardProduct"), + "card_product_type": self._card.get("cardProductType"), + "card_settings_id": self._card.get("cardSettingsId"), + "card_Type": self._card.get("cardType"), + "design": self._card.get("design"), + "exceet_actual_delivery_date": + self._card.get("exceetActualDeliveryDate"), + "exceet_card_status": self._card.get("exceetCardStatus"), + "exceet_expected_delivery_date": + self._card.get("exceetExpectedDeliveryDate"), + "exceet_express_card_delivery": + self._card.get("exceetExpressCardDelivery"), + "exceet_express_card_delivery_email_sent": + self._card.get("exceetExpressCardDeliveryEmailSent"), + "exceet_express_card_delivery_tracking_id": + self._card.get("exceetExpressCardDeliveryTrackingId"), + "expiration_date": timestamp_ms_to_date( + self._card.get("expirationDate")), + "google_pay_eligible": self._card.get("googlePayEligible"), + "masked_pan": self._card.get("maskedPan"), + "membership": self._card.get("membership"), + "mpts_card": self._card.get("mptsCard"), + "pan": self._card.get("pan"), + "pin_defined": timestamp_ms_to_date(self._card.get("pinDefined")), + "username_on_card": self._card.get("usernameOnCard"), + } + return attributes + + @property + def icon(self) -> str: + """Set the icon for the sensor.""" + return ICON_CARD + + +class N26Space(Entity): + """Sensor for a N26 space.""" + + def __init__(self, api_data, space) -> None: + """Initialize a N26 space.""" + self._data = api_data + self._space = space + + def update(self) -> None: + """Get the current balance and currency for the account.""" + self._data.update_spaces() + self._space = self._data.space(self._space["id"], self._space) + + @property + def unique_id(self): + """Return the unique ID of the entity.""" + return "space_{}".format(self._space["name"].lower()) + + @property + def name(self) -> str: + """Friendly name of the sensor.""" + return self._space["name"] + + @property + def state(self) -> float: + """Return the balance of the account as state.""" + return self._space["balance"]["availableBalance"] + + @property + def unit_of_measurement(self) -> str: + """Use the currency as unit of measurement.""" + return self._space["balance"]["currency"] + + @property + def device_state_attributes(self) -> dict: + """Additional attributes of the sensor.""" + goal_value = "" + if "goal" in self._space: + goal_value = self._space.get("goal").get("amount") + + attributes = { + "name": self._space.get("name"), + "goal": goal_value, + "background_image_url": self._space.get("backgroundImageUrl"), + "image_url": self._space.get("imageUrl"), + "is_card_attached": self._space.get("isCardAttached"), + "is_hidden_from_balance": self._space.get("isHiddenFromBalance"), + "is_locked": self._space.get("isLocked"), + "is_primary": self._space.get("isPrimary"), + } + return attributes + + @property + def icon(self) -> str: + """Set the icon for the sensor.""" + return ICON_SPACE diff --git a/homeassistant/components/n26/switch.py b/homeassistant/components/n26/switch.py new file mode 100644 index 00000000000..0e7455ea703 --- /dev/null +++ b/homeassistant/components/n26/switch.py @@ -0,0 +1,64 @@ +"""Support for N26 switches.""" +import logging + +from homeassistant.components.switch import SwitchDevice + +from . import DEFAULT_SCAN_INTERVAL, DOMAIN +from .const import CARD_STATE_ACTIVE, CARD_STATE_BLOCKED, DATA + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['n26'] + +SCAN_INTERVAL = DEFAULT_SCAN_INTERVAL + + +def setup_platform( + hass, config, add_entities, discovery_info=None): + """Set up the N26 switch platform.""" + api_data = hass.data[DOMAIN][DATA] + + switch_entities = [] + for card in api_data.cards: + switch_entities.append(N26CardSwitch(api_data, card)) + + add_entities(switch_entities) + + +class N26CardSwitch(SwitchDevice): + """Representation of a N26 card block/unblock switch.""" + + def __init__(self, api_data, card: dict): + """Initialize the N26 card block/unblock switch.""" + self._data = api_data + self._card = card + + @property + def unique_id(self): + """Return the unique ID of the entity.""" + return self._card["id"] + + @property + def name(self) -> str: + """Friendly name of the sensor.""" + return "card_{}".format(self._card["id"]) + + @property + def is_on(self): + """Return true if switch is on.""" + return self._card["status"] == CARD_STATE_ACTIVE + + def turn_on(self, **kwargs): + """Block the card.""" + self._data.api.unblock_card(self._card["id"]) + self._card["status"] = CARD_STATE_ACTIVE + + def turn_off(self, **kwargs): + """Unblock the card.""" + self._data.api.block_card(self._card["id"]) + self._card["status"] = CARD_STATE_BLOCKED + + def update(self): + """Update the switch state.""" + self._data.update_cards() + self._card = self._data.card(self._card["id"], self._card) diff --git a/requirements_all.txt b/requirements_all.txt index 69430c8cf98..052f8990c20 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -725,6 +725,9 @@ mycroftapi==2.0 # homeassistant.components.usps myusps==1.3.2 +# homeassistant.components.n26 +n26==0.2.7 + # homeassistant.components.nad.media_player nad_receiver==0.0.11 From 0438dffe25b1850e60ae365adab32539190f3b7a Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Thu, 4 Apr 2019 13:43:21 -0600 Subject: [PATCH 092/167] Bump aioambient to 0.2.0 (#22736) --- homeassistant/components/ambient_station/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/ambient_station/__init__.py b/homeassistant/components/ambient_station/__init__.py index 2383d011945..ff94e4fd5e5 100644 --- a/homeassistant/components/ambient_station/__init__.py +++ b/homeassistant/components/ambient_station/__init__.py @@ -20,7 +20,7 @@ from .const import ( ATTR_LAST_DATA, CONF_APP_KEY, DATA_CLIENT, DOMAIN, TOPIC_UPDATE, TYPE_BINARY_SENSOR, TYPE_SENSOR) -REQUIREMENTS = ['aioambient==0.1.3'] +REQUIREMENTS = ['aioambient==0.2.0'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 052f8990c20..e32e9512957 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -97,7 +97,7 @@ abodepy==0.15.0 afsapi==0.0.4 # homeassistant.components.ambient_station -aioambient==0.1.3 +aioambient==0.2.0 # homeassistant.components.asuswrt aioasuswrt==1.1.21 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e08255c246d..c6838f2dd19 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -36,7 +36,7 @@ PyTransportNSW==0.1.1 YesssSMS==0.2.3 # homeassistant.components.ambient_station -aioambient==0.1.3 +aioambient==0.2.0 # homeassistant.components.automatic.device_tracker aioautomatic==0.6.5 From 96adbfdc369c71a3612386285ad6f81f98874a2e Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Thu, 4 Apr 2019 13:50:10 -0600 Subject: [PATCH 093/167] Fix incorrect "Unavailable" Ambient sensors (#22734) * Fix incorrect "Unavailable" Ambient sensors * Removed unnecessary cast --- homeassistant/components/ambient_station/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/ambient_station/__init__.py b/homeassistant/components/ambient_station/__init__.py index ff94e4fd5e5..cb0a2067d9f 100644 --- a/homeassistant/components/ambient_station/__init__.py +++ b/homeassistant/components/ambient_station/__init__.py @@ -417,9 +417,8 @@ class AmbientWeatherEntity(Entity): @property def available(self): """Return True if entity is available.""" - return bool( - self._ambient.stations[self._mac_address][ATTR_LAST_DATA].get( - self._sensor_type)) + return self._ambient.stations[self._mac_address][ATTR_LAST_DATA].get( + self._sensor_type) is not None @property def device_info(self): From b9ec623ad905fd8b1526c0e7c5367abf4a91be71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Osb=C3=A4ck?= Date: Thu, 4 Apr 2019 23:19:29 +0200 Subject: [PATCH 094/167] Bump pywebpush to latest 1.9.2 (#22737) --- homeassistant/components/html5/notify.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/html5/notify.py b/homeassistant/components/html5/notify.py index f7b220ff138..fa7bf660b79 100644 --- a/homeassistant/components/html5/notify.py +++ b/homeassistant/components/html5/notify.py @@ -24,7 +24,7 @@ from homeassistant.components.notify import ( ATTR_DATA, ATTR_TARGET, ATTR_TITLE, ATTR_TITLE_DEFAULT, DOMAIN, PLATFORM_SCHEMA, BaseNotificationService) -REQUIREMENTS = ['pywebpush==1.6.0'] +REQUIREMENTS = ['pywebpush==1.9.2'] DEPENDENCIES = ['frontend'] diff --git a/requirements_all.txt b/requirements_all.txt index e32e9512957..1351a640008 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1472,7 +1472,7 @@ pyvizio==0.0.4 pyvlx==0.2.10 # homeassistant.components.html5.notify -pywebpush==1.6.0 +pywebpush==1.9.2 # homeassistant.components.wemo pywemo==0.4.34 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index c6838f2dd19..73fbae3aadb 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -265,7 +265,7 @@ pytradfri[async]==6.0.1 pyunifi==2.16 # homeassistant.components.html5.notify -pywebpush==1.6.0 +pywebpush==1.9.2 # homeassistant.components.rainmachine regenmaschine==1.4.0 From b50afec5f11e07352f40f9bdbbaf5bff7a6b11ff Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 5 Apr 2019 02:48:24 +0200 Subject: [PATCH 095/167] Support multiple deCONZ gateways (#22449) * Store gateways inside a dict in deconz domain * Make reachable events gateway specific * Gateway shall always exist * Adapt new device signalling to support multiple gateways * Services follow gateway master * Working on unload entry * Make unload and master handover work Improve tests for init * Fix config flow * Fix linting * Clean up init tests * Clean up hassio discovery to fit with the rest * Store gateways inside a dict in deconz domain * Make reachable events gateway specific * Gateway shall always exist * Adapt new device signalling to support multiple gateways * Services follow gateway master * Working on unload entry * Make unload and master handover work Improve tests for init * Fix config flow * Fix linting * Clean up init tests * Clean up hassio discovery to fit with the rest * Add support for services to specify bridgeid --- homeassistant/components/deconz/__init__.py | 96 +++++--- .../components/deconz/binary_sensor.py | 19 +- homeassistant/components/deconz/climate.py | 19 +- .../components/deconz/config_flow.py | 115 ++++------ homeassistant/components/deconz/const.py | 19 +- homeassistant/components/deconz/cover.py | 14 +- .../components/deconz/deconz_device.py | 5 +- homeassistant/components/deconz/gateway.py | 73 +++++- homeassistant/components/deconz/light.py | 22 +- homeassistant/components/deconz/scene.py | 12 +- homeassistant/components/deconz/sensor.py | 20 +- homeassistant/components/deconz/services.yaml | 8 +- homeassistant/components/deconz/switch.py | 13 +- tests/components/deconz/test_binary_sensor.py | 35 +-- tests/components/deconz/test_climate.py | 47 ++-- tests/components/deconz/test_config_flow.py | 73 ++---- tests/components/deconz/test_cover.py | 24 +- tests/components/deconz/test_init.py | 208 ++++++++++++------ tests/components/deconz/test_light.py | 49 +++-- tests/components/deconz/test_scene.py | 15 +- tests/components/deconz/test_sensor.py | 47 ++-- tests/components/deconz/test_switch.py | 28 +-- 22 files changed, 535 insertions(+), 426 deletions(-) diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index 8bdd946e2ef..ff1ee2bf06e 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -4,12 +4,14 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.const import ( CONF_API_KEY, CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP) +from homeassistant.core import callback from homeassistant.helpers import config_validation as cv -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC # Loading the config flow file will register the flow -from .config_flow import configured_hosts -from .const import DEFAULT_PORT, DOMAIN, _LOGGER +from .config_flow import get_master_gateway +from .const import ( + CONF_ALLOW_CLIP_SENSOR, CONF_ALLOW_DECONZ_GROUPS, CONF_BRIDGEID, + CONF_MASTER_GATEWAY, DEFAULT_PORT, DOMAIN, _LOGGER) from .gateway import DeconzGateway REQUIREMENTS = ['pydeconz==54'] @@ -32,26 +34,27 @@ SERVICE_SCHEMA = vol.All(vol.Schema({ vol.Optional(SERVICE_ENTITY): cv.entity_id, vol.Optional(SERVICE_FIELD): cv.matches_regex('/.*'), vol.Required(SERVICE_DATA): dict, + vol.Optional(CONF_BRIDGEID): str }), cv.has_at_least_one_key(SERVICE_ENTITY, SERVICE_FIELD)) SERVICE_DEVICE_REFRESH = 'device_refresh' +SERVICE_DEVICE_REFRESCH_SCHEMA = vol.All(vol.Schema({ + vol.Optional(CONF_BRIDGEID): str +})) + async def async_setup(hass, config): """Load configuration for deCONZ component. Discovery has loaded the component if DOMAIN is not present in config. """ - if DOMAIN in config: - deconz_config = None - if CONF_HOST in config[DOMAIN]: - deconz_config = config[DOMAIN] - if deconz_config and not configured_hosts(hass): - hass.async_add_job(hass.config_entries.flow.async_init( - DOMAIN, - context={'source': config_entries.SOURCE_IMPORT}, - data=deconz_config - )) + if not hass.config_entries.async_entries(DOMAIN) and DOMAIN in config: + deconz_config = config[DOMAIN] + hass.async_add_job(hass.config_entries.flow.async_init( + DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, + data=deconz_config + )) return True @@ -61,26 +64,20 @@ async def async_setup_entry(hass, config_entry): Load config, group, light and sensor data for server information. Start websocket for push notification of state changes from deCONZ. """ - if DOMAIN in hass.data: - _LOGGER.error( - "Config entry failed since one deCONZ instance already exists") - return False + if DOMAIN not in hass.data: + hass.data[DOMAIN] = {} + + if not config_entry.options: + await async_populate_options(hass, config_entry) gateway = DeconzGateway(hass, config_entry) if not await gateway.async_setup(): return False - hass.data[DOMAIN] = gateway + hass.data[DOMAIN][gateway.bridgeid] = gateway - device_registry = await \ - hass.helpers.device_registry.async_get_registry() - device_registry.async_get_or_create( - config_entry_id=config_entry.entry_id, - connections={(CONNECTION_NETWORK_MAC, gateway.api.config.mac)}, - identifiers={(DOMAIN, gateway.api.config.bridgeid)}, - manufacturer='Dresden Elektronik', model=gateway.api.config.modelid, - name=gateway.api.config.name, sw_version=gateway.api.config.swversion) + await gateway.async_update_device_registry() async def async_configure(call): """Set attribute of device in deCONZ. @@ -100,8 +97,11 @@ async def async_setup_entry(hass, config_entry): """ field = call.data.get(SERVICE_FIELD, '') entity_id = call.data.get(SERVICE_ENTITY) - data = call.data.get(SERVICE_DATA) - gateway = hass.data[DOMAIN] + data = call.data[SERVICE_DATA] + + gateway = get_master_gateway(hass) + if CONF_BRIDGEID in call.data: + gateway = hass.data[DOMAIN][call.data[CONF_BRIDGEID]] if entity_id: try: @@ -117,7 +117,9 @@ async def async_setup_entry(hass, config_entry): async def async_refresh_devices(call): """Refresh available devices from deCONZ.""" - gateway = hass.data[DOMAIN] + gateway = get_master_gateway(hass) + if CONF_BRIDGEID in call.data: + gateway = hass.data[DOMAIN][call.data[CONF_BRIDGEID]] groups = set(gateway.api.groups.keys()) lights = set(gateway.api.lights.keys()) @@ -151,7 +153,8 @@ async def async_setup_entry(hass, config_entry): ) hass.services.async_register( - DOMAIN, SERVICE_DEVICE_REFRESH, async_refresh_devices) + DOMAIN, SERVICE_DEVICE_REFRESH, async_refresh_devices, + schema=SERVICE_DEVICE_REFRESCH_SCHEMA) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gateway.shutdown) return True @@ -159,7 +162,34 @@ async def async_setup_entry(hass, config_entry): async def async_unload_entry(hass, config_entry): """Unload deCONZ config entry.""" - gateway = hass.data.pop(DOMAIN) - hass.services.async_remove(DOMAIN, SERVICE_DECONZ) - hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH) + gateway = hass.data[DOMAIN].pop(config_entry.data[CONF_BRIDGEID]) + + if not hass.data[DOMAIN]: + hass.services.async_remove(DOMAIN, SERVICE_DECONZ) + hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH) + elif gateway.master: + await async_populate_options(hass, config_entry) + new_master_gateway = next(iter(hass.data[DOMAIN].values())) + await async_populate_options(hass, new_master_gateway.config_entry) + return await gateway.async_reset() + + +@callback +async def async_populate_options(hass, config_entry): + """Populate default options for gateway. + + Called by setup_entry and unload_entry. + Makes sure there is always one master available. + """ + master = not get_master_gateway(hass) + + options = { + CONF_MASTER_GATEWAY: master, + CONF_ALLOW_CLIP_SENSOR: config_entry.data.get( + CONF_ALLOW_CLIP_SENSOR, False), + CONF_ALLOW_DECONZ_GROUPS: config_entry.data.get( + CONF_ALLOW_DECONZ_GROUPS, True) + } + + hass.config_entries.async_update_entry(config_entry, options=options) diff --git a/homeassistant/components/deconz/binary_sensor.py b/homeassistant/components/deconz/binary_sensor.py index 2b0c2037248..70de1fd7cf4 100644 --- a/homeassistant/components/deconz/binary_sensor.py +++ b/homeassistant/components/deconz/binary_sensor.py @@ -4,10 +4,9 @@ from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import ( - ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DOMAIN as DECONZ_DOMAIN, - NEW_SENSOR) +from .const import ATTR_DARK, ATTR_ON, NEW_SENSOR from .deconz_device import DeconzDevice +from .gateway import get_gateway_from_config_entry DEPENDENCIES = ['deconz'] @@ -24,22 +23,26 @@ async def async_setup_platform( async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the deCONZ binary sensor.""" - gateway = hass.data[DECONZ_DOMAIN] + gateway = get_gateway_from_config_entry(hass, config_entry) @callback def async_add_sensor(sensors): """Add binary sensor from deCONZ.""" from pydeconz.sensor import DECONZ_BINARY_SENSOR entities = [] - allow_clip_sensor = config_entry.data.get(CONF_ALLOW_CLIP_SENSOR, True) + for sensor in sensors: + if sensor.type in DECONZ_BINARY_SENSOR and \ - not (not allow_clip_sensor and sensor.type.startswith('CLIP')): + not (not gateway.allow_clip_sensor and + sensor.type.startswith('CLIP')): + entities.append(DeconzBinarySensor(sensor, gateway)) + async_add_entities(entities, True) - gateway.listeners.append( - async_dispatcher_connect(hass, NEW_SENSOR, async_add_sensor)) + gateway.listeners.append(async_dispatcher_connect( + hass, gateway.async_event_new_device(NEW_SENSOR), async_add_sensor)) async_add_sensor(gateway.api.sensors.values()) diff --git a/homeassistant/components/deconz/climate.py b/homeassistant/components/deconz/climate.py index 1f39b8705c7..c4327d3c497 100644 --- a/homeassistant/components/deconz/climate.py +++ b/homeassistant/components/deconz/climate.py @@ -7,10 +7,9 @@ from homeassistant.const import ( from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import ( - ATTR_OFFSET, ATTR_VALVE, CONF_ALLOW_CLIP_SENSOR, - DOMAIN as DECONZ_DOMAIN, NEW_SENSOR) +from .const import ATTR_OFFSET, ATTR_VALVE, NEW_SENSOR from .deconz_device import DeconzDevice +from .gateway import get_gateway_from_config_entry DEPENDENCIES = ['deconz'] @@ -20,22 +19,26 @@ async def async_setup_entry(hass, config_entry, async_add_entities): Thermostats are based on the same device class as sensors in deCONZ. """ - gateway = hass.data[DECONZ_DOMAIN] + gateway = get_gateway_from_config_entry(hass, config_entry) @callback def async_add_climate(sensors): """Add climate devices from deCONZ.""" from pydeconz.sensor import THERMOSTAT entities = [] - allow_clip_sensor = config_entry.data.get(CONF_ALLOW_CLIP_SENSOR, True) + for sensor in sensors: + if sensor.type in THERMOSTAT and \ - not (not allow_clip_sensor and sensor.type.startswith('CLIP')): + not (not gateway.allow_clip_sensor and + sensor.type.startswith('CLIP')): + entities.append(DeconzThermostat(sensor, gateway)) + async_add_entities(entities, True) - gateway.listeners.append( - async_dispatcher_connect(hass, NEW_SENSOR, async_add_climate)) + gateway.listeners.append(async_dispatcher_connect( + hass, gateway.async_event_new_device(NEW_SENSOR), async_add_climate)) async_add_climate(gateway.api.sensors.values()) diff --git a/homeassistant/components/deconz/config_flow.py b/homeassistant/components/deconz/config_flow.py index 38849fb37b3..1ecfee7ada5 100644 --- a/homeassistant/components/deconz/config_flow.py +++ b/homeassistant/components/deconz/config_flow.py @@ -9,10 +9,7 @@ from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT from homeassistant.core import callback from homeassistant.helpers import aiohttp_client -from .const import ( - CONF_ALLOW_CLIP_SENSOR, CONF_ALLOW_DECONZ_GROUPS, CONF_BRIDGEID, - DEFAULT_ALLOW_CLIP_SENSOR, DEFAULT_ALLOW_DECONZ_GROUPS, DEFAULT_PORT, - DOMAIN) +from .const import CONF_BRIDGEID, DEFAULT_PORT, DOMAIN @callback @@ -22,6 +19,14 @@ def configured_hosts(hass): in hass.config_entries.async_entries(DOMAIN)) +@callback +def get_master_gateway(hass): + """Return a bool telling if this is the master gateway.""" + for gateway in hass.data[DOMAIN].values(): + if gateway.master: + return gateway + + @config_entries.HANDLERS.register(DOMAIN) class DeconzFlowHandler(config_entries.ConfigFlow): """Handle a deCONZ config flow.""" @@ -39,16 +44,12 @@ class DeconzFlowHandler(config_entries.ConfigFlow): async def async_step_user(self, user_input=None): """Handle a deCONZ config flow start. - Only allows one instance to be set up. If only one bridge is found go to link step. If more than one bridge is found let user choose bridge to link. If no bridge is found allow user to manually input configuration. """ from pydeconz.utils import async_discovery - if configured_hosts(self.hass): - return self.async_abort(reason='one_instance_only') - if user_input is not None: for bridge in self.bridges: if bridge[CONF_HOST] == user_input[CONF_HOST]: @@ -99,9 +100,6 @@ class DeconzFlowHandler(config_entries.ConfigFlow): errors = {} if user_input is not None: - if configured_hosts(self.hass): - return self.async_abort(reason='one_instance_only') - session = aiohttp_client.async_get_clientsession(self.hass) try: @@ -114,51 +112,32 @@ class DeconzFlowHandler(config_entries.ConfigFlow): else: self.deconz_config[CONF_API_KEY] = api_key - return await self.async_step_options() + return await self._create_entry() return self.async_show_form( step_id='link', errors=errors, ) - async def async_step_options(self, user_input=None): - """Extra options for deCONZ. - - CONF_CLIP_SENSOR -- Allow user to choose if they want clip sensors. - CONF_DECONZ_GROUPS -- Allow user to choose if they want deCONZ groups. - """ + async def _create_entry(self): + """Create entry for gateway.""" from pydeconz.utils import async_get_bridgeid - if user_input is not None: - self.deconz_config[CONF_ALLOW_CLIP_SENSOR] = \ - user_input[CONF_ALLOW_CLIP_SENSOR] - self.deconz_config[CONF_ALLOW_DECONZ_GROUPS] = \ - user_input[CONF_ALLOW_DECONZ_GROUPS] + if CONF_BRIDGEID not in self.deconz_config: + session = aiohttp_client.async_get_clientsession(self.hass) - if CONF_BRIDGEID not in self.deconz_config: - session = aiohttp_client.async_get_clientsession(self.hass) - try: - with async_timeout.timeout(10): - self.deconz_config[CONF_BRIDGEID] = \ - await async_get_bridgeid( - session, **self.deconz_config) + try: + with async_timeout.timeout(10): + self.deconz_config[CONF_BRIDGEID] = \ + await async_get_bridgeid( + session, **self.deconz_config) - except asyncio.TimeoutError: - return self.async_abort(reason='no_bridges') + except asyncio.TimeoutError: + return self.async_abort(reason='no_bridges') - return self.async_create_entry( - title='deCONZ-' + self.deconz_config[CONF_BRIDGEID], - data=self.deconz_config - ) - - return self.async_show_form( - step_id='options', - data_schema=vol.Schema({ - vol.Optional(CONF_ALLOW_CLIP_SENSOR, - default=DEFAULT_ALLOW_CLIP_SENSOR): bool, - vol.Optional(CONF_ALLOW_DECONZ_GROUPS, - default=DEFAULT_ALLOW_DECONZ_GROUPS): bool, - }), + return self.async_create_entry( + title='deCONZ-' + self.deconz_config[CONF_BRIDGEID], + data=self.deconz_config ) async def async_step_discovery(self, discovery_info): @@ -166,10 +145,14 @@ class DeconzFlowHandler(config_entries.ConfigFlow): This flow is triggered by the discovery component. """ - deconz_config = {} - deconz_config[CONF_HOST] = discovery_info.get(CONF_HOST) - deconz_config[CONF_PORT] = discovery_info.get(CONF_PORT) - deconz_config[CONF_BRIDGEID] = discovery_info.get('serial') + deconz_config = { + CONF_HOST: discovery_info[CONF_HOST], + CONF_PORT: discovery_info[CONF_PORT], + CONF_BRIDGEID: discovery_info['serial'] + } + + if deconz_config[CONF_HOST] in configured_hosts(self.hass): + return self.async_abort(reason='one_instance_only') return await self.async_step_import(deconz_config) @@ -186,16 +169,11 @@ class DeconzFlowHandler(config_entries.ConfigFlow): Otherwise we will delegate to `link` step which will ask user to link the bridge. """ - if configured_hosts(self.hass): - return self.async_abort(reason='one_instance_only') - self.deconz_config = import_config if CONF_API_KEY not in import_config: return await self.async_step_link() - user_input = {CONF_ALLOW_CLIP_SENSOR: True, - CONF_ALLOW_DECONZ_GROUPS: True} - return await self.async_step_options(user_input=user_input) + return await self._create_entry() async def async_step_hassio(self, user_input=None): """Prepare configuration for a Hass.io deCONZ bridge. @@ -212,29 +190,18 @@ class DeconzFlowHandler(config_entries.ConfigFlow): async def async_step_hassio_confirm(self, user_input=None): """Confirm a Hass.io discovery.""" if user_input is not None: - data = self._hassio_discovery + self.deconz_config = { + CONF_HOST: self._hassio_discovery[CONF_HOST], + CONF_PORT: self._hassio_discovery[CONF_PORT], + CONF_BRIDGEID: self._hassio_discovery['serial'], + CONF_API_KEY: self._hassio_discovery[CONF_API_KEY] + } - return self.async_create_entry( - title=data['addon'], data={ - CONF_HOST: data[CONF_HOST], - CONF_PORT: data[CONF_PORT], - CONF_BRIDGEID: data['serial'], - CONF_API_KEY: data[CONF_API_KEY], - CONF_ALLOW_CLIP_SENSOR: - user_input[CONF_ALLOW_CLIP_SENSOR], - CONF_ALLOW_DECONZ_GROUPS: - user_input[CONF_ALLOW_DECONZ_GROUPS], - }) + return await self._create_entry() return self.async_show_form( step_id='hassio_confirm', description_placeholders={ 'addon': self._hassio_discovery['addon'] - }, - data_schema=vol.Schema({ - vol.Optional(CONF_ALLOW_CLIP_SENSOR, - default=DEFAULT_ALLOW_CLIP_SENSOR): bool, - vol.Optional(CONF_ALLOW_DECONZ_GROUPS, - default=DEFAULT_ALLOW_DECONZ_GROUPS): bool, - }) + } ) diff --git a/homeassistant/components/deconz/const.py b/homeassistant/components/deconz/const.py index b26fddd9147..bf0f5884073 100644 --- a/homeassistant/components/deconz/const.py +++ b/homeassistant/components/deconz/const.py @@ -12,22 +12,21 @@ DEFAULT_ALLOW_DECONZ_GROUPS = False CONF_ALLOW_CLIP_SENSOR = 'allow_clip_sensor' CONF_ALLOW_DECONZ_GROUPS = 'allow_deconz_groups' CONF_BRIDGEID = 'bridgeid' +CONF_MASTER_GATEWAY = 'master' SUPPORTED_PLATFORMS = ['binary_sensor', 'climate', 'cover', 'light', 'scene', 'sensor', 'switch'] -DECONZ_REACHABLE = 'deconz_reachable' - -NEW_GROUP = 'deconz_new_group' -NEW_LIGHT = 'deconz_new_light' -NEW_SCENE = 'deconz_new_scene' -NEW_SENSOR = 'deconz_new_sensor' +NEW_GROUP = 'group' +NEW_LIGHT = 'light' +NEW_SCENE = 'scene' +NEW_SENSOR = 'sensor' NEW_DEVICE = { - 'group': NEW_GROUP, - 'light': NEW_LIGHT, - 'scene': NEW_SCENE, - 'sensor': NEW_SENSOR + NEW_GROUP: 'deconz_new_group_{}', + NEW_LIGHT: 'deconz_new_light_{}', + NEW_SCENE: 'deconz_new_scene_{}', + NEW_SENSOR: 'deconz_new_sensor_{}' } ATTR_DARK = 'dark' diff --git a/homeassistant/components/deconz/cover.py b/homeassistant/components/deconz/cover.py index fda4fe4309c..903c1160eb8 100644 --- a/homeassistant/components/deconz/cover.py +++ b/homeassistant/components/deconz/cover.py @@ -5,9 +5,9 @@ from homeassistant.components.cover import ( from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import ( - COVER_TYPES, DAMPERS, DOMAIN as DECONZ_DOMAIN, NEW_LIGHT, WINDOW_COVERS) +from .const import COVER_TYPES, DAMPERS, NEW_LIGHT, WINDOW_COVERS from .deconz_device import DeconzDevice +from .gateway import get_gateway_from_config_entry DEPENDENCIES = ['deconz'] @@ -25,22 +25,26 @@ async def async_setup_entry(hass, config_entry, async_add_entities): Covers are based on same device class as lights in deCONZ. """ - gateway = hass.data[DECONZ_DOMAIN] + gateway = get_gateway_from_config_entry(hass, config_entry) @callback def async_add_cover(lights): """Add cover from deCONZ.""" entities = [] + for light in lights: + if light.type in COVER_TYPES: if light.modelid in ZIGBEE_SPEC: entities.append(DeconzCoverZigbeeSpec(light, gateway)) + else: entities.append(DeconzCover(light, gateway)) + async_add_entities(entities, True) - gateway.listeners.append( - async_dispatcher_connect(hass, NEW_LIGHT, async_add_cover)) + gateway.listeners.append(async_dispatcher_connect( + hass, gateway.async_event_new_device(NEW_LIGHT), async_add_cover)) async_add_cover(gateway.api.lights.values()) diff --git a/homeassistant/components/deconz/deconz_device.py b/homeassistant/components/deconz/deconz_device.py index bfcbd158b9f..0c5cbeef1fb 100644 --- a/homeassistant/components/deconz/deconz_device.py +++ b/homeassistant/components/deconz/deconz_device.py @@ -4,7 +4,7 @@ from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import Entity -from .const import DECONZ_REACHABLE, DOMAIN as DECONZ_DOMAIN +from .const import DOMAIN as DECONZ_DOMAIN class DeconzDevice(Entity): @@ -21,7 +21,8 @@ class DeconzDevice(Entity): self._device.register_async_callback(self.async_update_callback) self.gateway.deconz_ids[self.entity_id] = self._device.deconz_id self.unsub_dispatcher = async_dispatcher_connect( - self.hass, DECONZ_REACHABLE, self.async_update_callback) + self.hass, self.gateway.event_reachable, + self.async_update_callback) async def async_will_remove_from_hass(self) -> None: """Disconnect device object when removed.""" diff --git a/homeassistant/components/deconz/gateway.py b/homeassistant/components/deconz/gateway.py index 11fb247a6f4..4d9e1503902 100644 --- a/homeassistant/components/deconz/gateway.py +++ b/homeassistant/components/deconz/gateway.py @@ -6,16 +6,23 @@ from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.const import CONF_EVENT, CONF_HOST, CONF_ID from homeassistant.core import EventOrigin, callback from homeassistant.helpers import aiohttp_client +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.dispatcher import ( async_dispatcher_connect, async_dispatcher_send) from homeassistant.util import slugify from .const import ( - _LOGGER, DECONZ_REACHABLE, CONF_ALLOW_CLIP_SENSOR, NEW_DEVICE, NEW_SENSOR, - SUPPORTED_PLATFORMS) + _LOGGER, CONF_ALLOW_CLIP_SENSOR, CONF_ALLOW_DECONZ_GROUPS, CONF_BRIDGEID, + CONF_MASTER_GATEWAY, DOMAIN, NEW_DEVICE, NEW_SENSOR, SUPPORTED_PLATFORMS) from .errors import AuthenticationRequired, CannotConnect +@callback +def get_gateway_from_config_entry(hass, config_entry): + """Return gateway with a matching bridge id.""" + return hass.data[DOMAIN][config_entry.data[CONF_BRIDGEID]] + + class DeconzGateway: """Manages a single deCONZ gateway.""" @@ -30,6 +37,40 @@ class DeconzGateway: self.events = [] self.listeners = [] + @property + def bridgeid(self) -> str: + """Return the unique identifier of the gateway.""" + return self.config_entry.data[CONF_BRIDGEID] + + @property + def master(self) -> bool: + """Gateway which is used with deCONZ services without defining id.""" + return self.config_entry.options[CONF_MASTER_GATEWAY] + + @property + def allow_clip_sensor(self) -> bool: + """Allow loading clip sensor from gateway.""" + return self.config_entry.data.get(CONF_ALLOW_CLIP_SENSOR, True) + + @property + def allow_deconz_groups(self) -> bool: + """Allow loading deCONZ groups from gateway.""" + return self.config_entry.data.get(CONF_ALLOW_DECONZ_GROUPS, True) + + async def async_update_device_registry(self): + """Update device registry.""" + device_registry = await \ + self.hass.helpers.device_registry.async_get_registry() + device_registry.async_get_or_create( + config_entry_id=self.config_entry.entry_id, + connections={(CONNECTION_NETWORK_MAC, self.api.config.mac)}, + identifiers={(DOMAIN, self.api.config.bridgeid)}, + manufacturer='Dresden Elektronik', + model=self.api.config.modelid, + name=self.api.config.name, + sw_version=self.api.config.swversion + ) + async def async_setup(self): """Set up a deCONZ gateway.""" hass = self.hass @@ -52,9 +93,9 @@ class DeconzGateway: hass.config_entries.async_forward_entry_setup( self.config_entry, component)) - self.listeners.append( - async_dispatcher_connect( - hass, NEW_SENSOR, self.async_add_remote)) + self.listeners.append(async_dispatcher_connect( + hass, self.async_event_new_device(NEW_SENSOR), + self.async_add_remote)) self.async_add_remote(self.api.sensors.values()) @@ -62,29 +103,39 @@ class DeconzGateway: return True + @property + def event_reachable(self): + """Gateway specific event to signal a change in connection status.""" + return 'deconz_reachable_{}'.format(self.bridgeid) + @callback def async_connection_status_callback(self, available): """Handle signals of gateway connection status.""" self.available = available - async_dispatcher_send( - self.hass, DECONZ_REACHABLE, {'state': True, 'attr': 'reachable'}) + async_dispatcher_send(self.hass, self.event_reachable, + {'state': True, 'attr': 'reachable'}) + + @callback + def async_event_new_device(self, device_type): + """Gateway specific event to signal new device.""" + return NEW_DEVICE[device_type].format(self.bridgeid) @callback def async_add_device_callback(self, device_type, device): """Handle event of new device creation in deCONZ.""" if not isinstance(device, list): device = [device] - async_dispatcher_send(self.hass, NEW_DEVICE[device_type], device) + async_dispatcher_send( + self.hass, self.async_event_new_device(device_type), device) @callback def async_add_remote(self, sensors): """Set up remote from deCONZ.""" from pydeconz.sensor import SWITCH as DECONZ_REMOTE - allow_clip_sensor = self.config_entry.data.get( - CONF_ALLOW_CLIP_SENSOR, True) for sensor in sensors: if sensor.type in DECONZ_REMOTE and \ - not (not allow_clip_sensor and sensor.type.startswith('CLIP')): + not (not self.allow_clip_sensor and + sensor.type.startswith('CLIP')): self.events.append(DeconzEvent(self.hass, sensor)) @callback diff --git a/homeassistant/components/deconz/light.py b/homeassistant/components/deconz/light.py index 3b63da8d9f8..b5a2b075f75 100644 --- a/homeassistant/components/deconz/light.py +++ b/homeassistant/components/deconz/light.py @@ -8,10 +8,9 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect import homeassistant.util.color as color_util -from .const import ( - CONF_ALLOW_DECONZ_GROUPS, DOMAIN as DECONZ_DOMAIN, COVER_TYPES, NEW_GROUP, - NEW_LIGHT, SWITCH_TYPES) +from .const import COVER_TYPES, NEW_GROUP, NEW_LIGHT, SWITCH_TYPES from .deconz_device import DeconzDevice +from .gateway import get_gateway_from_config_entry DEPENDENCIES = ['deconz'] @@ -24,32 +23,35 @@ async def async_setup_platform( async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the deCONZ lights and groups from a config entry.""" - gateway = hass.data[DECONZ_DOMAIN] + gateway = get_gateway_from_config_entry(hass, config_entry) @callback def async_add_light(lights): """Add light from deCONZ.""" entities = [] + for light in lights: if light.type not in COVER_TYPES + SWITCH_TYPES: entities.append(DeconzLight(light, gateway)) + async_add_entities(entities, True) - gateway.listeners.append( - async_dispatcher_connect(hass, NEW_LIGHT, async_add_light)) + gateway.listeners.append(async_dispatcher_connect( + hass, gateway.async_event_new_device(NEW_LIGHT), async_add_light)) @callback def async_add_group(groups): """Add group from deCONZ.""" entities = [] - allow_group = config_entry.data.get(CONF_ALLOW_DECONZ_GROUPS, True) + for group in groups: - if group.lights and allow_group: + if group.lights and gateway.allow_deconz_groups: entities.append(DeconzLight(group, gateway)) + async_add_entities(entities, True) - gateway.listeners.append( - async_dispatcher_connect(hass, NEW_GROUP, async_add_group)) + gateway.listeners.append(async_dispatcher_connect( + hass, gateway.async_event_new_device(NEW_GROUP), async_add_group)) async_add_light(gateway.api.lights.values()) async_add_group(gateway.api.groups.values()) diff --git a/homeassistant/components/deconz/scene.py b/homeassistant/components/deconz/scene.py index 22b4c47f2ab..1ae1e079daa 100644 --- a/homeassistant/components/deconz/scene.py +++ b/homeassistant/components/deconz/scene.py @@ -3,7 +3,8 @@ from homeassistant.components.scene import Scene from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import DOMAIN as DECONZ_DOMAIN, NEW_SCENE +from .const import NEW_SCENE +from .gateway import get_gateway_from_config_entry DEPENDENCIES = ['deconz'] @@ -16,17 +17,20 @@ async def async_setup_platform( async def async_setup_entry(hass, config_entry, async_add_entities): """Set up scenes for deCONZ component.""" - gateway = hass.data[DECONZ_DOMAIN] + gateway = get_gateway_from_config_entry(hass, config_entry) @callback def async_add_scene(scenes): """Add scene from deCONZ.""" entities = [] + for scene in scenes: entities.append(DeconzScene(scene, gateway)) + async_add_entities(entities) - gateway.listeners.append( - async_dispatcher_connect(hass, NEW_SCENE, async_add_scene)) + + gateway.listeners.append(async_dispatcher_connect( + hass, gateway.async_event_new_device(NEW_SCENE), async_add_scene)) async_add_scene(gateway.api.scenes.values()) diff --git a/homeassistant/components/deconz/sensor.py b/homeassistant/components/deconz/sensor.py index e6b033906e7..7c3109e1f59 100644 --- a/homeassistant/components/deconz/sensor.py +++ b/homeassistant/components/deconz/sensor.py @@ -5,10 +5,9 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.util import slugify -from .const import ( - ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DOMAIN as DECONZ_DOMAIN, - NEW_SENSOR) +from .const import ATTR_DARK, ATTR_ON, NEW_SENSOR from .deconz_device import DeconzDevice +from .gateway import get_gateway_from_config_entry DEPENDENCIES = ['deconz'] @@ -25,7 +24,7 @@ async def async_setup_platform( async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the deCONZ sensors.""" - gateway = hass.data[DECONZ_DOMAIN] + gateway = get_gateway_from_config_entry(hass, config_entry) @callback def async_add_sensor(sensors): @@ -33,19 +32,24 @@ async def async_setup_entry(hass, config_entry, async_add_entities): from pydeconz.sensor import ( DECONZ_SENSOR, SWITCH as DECONZ_REMOTE) entities = [] - allow_clip_sensor = config_entry.data.get(CONF_ALLOW_CLIP_SENSOR, True) + for sensor in sensors: + if sensor.type in DECONZ_SENSOR and \ - not (not allow_clip_sensor and sensor.type.startswith('CLIP')): + not (not gateway.allow_clip_sensor and + sensor.type.startswith('CLIP')): + if sensor.type in DECONZ_REMOTE: if sensor.battery: entities.append(DeconzBattery(sensor, gateway)) + else: entities.append(DeconzSensor(sensor, gateway)) + async_add_entities(entities, True) - gateway.listeners.append( - async_dispatcher_connect(hass, NEW_SENSOR, async_add_sensor)) + gateway.listeners.append(async_dispatcher_connect( + hass, gateway.async_event_new_device(NEW_SENSOR), async_add_sensor)) async_add_sensor(gateway.api.sensors.values()) diff --git a/homeassistant/components/deconz/services.yaml b/homeassistant/components/deconz/services.yaml index cde7ac79f4c..a39bbc01ea1 100644 --- a/homeassistant/components/deconz/services.yaml +++ b/homeassistant/components/deconz/services.yaml @@ -13,6 +13,12 @@ configure: data: description: Data is a json object with what data you want to alter. example: '{"on": true}' + bridgeid: + description: (Optional) Bridgeid is a string unique for each deCONZ hardware. It can be found as part of the integration name. + example: '00212EFFFF012345' device_refresh: - description: Refresh device lists from deCONZ. \ No newline at end of file + description: Refresh device lists from deCONZ. + bridgeid: + description: (Optional) Bridgeid is a string unique for each deCONZ hardware. It can be found as part of the integration name. + example: '00212EFFFF012345' \ No newline at end of file diff --git a/homeassistant/components/deconz/switch.py b/homeassistant/components/deconz/switch.py index 56d37d504cb..b9f959766fc 100644 --- a/homeassistant/components/deconz/switch.py +++ b/homeassistant/components/deconz/switch.py @@ -3,8 +3,9 @@ from homeassistant.components.switch import SwitchDevice from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import DOMAIN as DECONZ_DOMAIN, NEW_LIGHT, POWER_PLUGS, SIRENS +from .const import NEW_LIGHT, POWER_PLUGS, SIRENS from .deconz_device import DeconzDevice +from .gateway import get_gateway_from_config_entry DEPENDENCIES = ['deconz'] @@ -20,21 +21,25 @@ async def async_setup_entry(hass, config_entry, async_add_entities): Switches are based same device class as lights in deCONZ. """ - gateway = hass.data[DECONZ_DOMAIN] + gateway = get_gateway_from_config_entry(hass, config_entry) @callback def async_add_switch(lights): """Add switch from deCONZ.""" entities = [] + for light in lights: + if light.type in POWER_PLUGS: entities.append(DeconzPowerPlug(light, gateway)) + elif light.type in SIRENS: entities.append(DeconzSiren(light, gateway)) + async_add_entities(entities, True) - gateway.listeners.append( - async_dispatcher_connect(hass, NEW_LIGHT, async_add_switch)) + gateway.listeners.append(async_dispatcher_connect( + hass, gateway.async_event_new_device(NEW_LIGHT), async_add_switch)) async_add_switch(gateway.api.lights.values()) diff --git a/tests/components/deconz/test_binary_sensor.py b/tests/components/deconz/test_binary_sensor.py index ba39afa0e88..1aee53f43c2 100644 --- a/tests/components/deconz/test_binary_sensor.py +++ b/tests/components/deconz/test_binary_sensor.py @@ -54,7 +54,7 @@ async def setup_gateway(hass, data, allow_clip_sensor=True): gateway = deconz.DeconzGateway(hass, config_entry) gateway.api = DeconzSession(loop, session, **config_entry.data) gateway.api.config = Mock() - hass.data[deconz.DOMAIN] = gateway + hass.data[deconz.DOMAIN] = {gateway.bridgeid: gateway} with patch('pydeconz.DeconzSession.async_get_state', return_value=mock_coro(data)): @@ -64,6 +64,7 @@ async def setup_gateway(hass, data, allow_clip_sensor=True): config_entry, 'binary_sensor') # To flush out the service call to update the group await hass.async_block_till_done() + return gateway async def test_platform_manually_configured(hass): @@ -79,56 +80,56 @@ async def test_platform_manually_configured(hass): async def test_no_binary_sensors(hass): """Test that no sensors in deconz results in no sensor entities.""" data = {} - await setup_gateway(hass, data) - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + gateway = await setup_gateway(hass, data) + assert len(hass.data[deconz.DOMAIN][gateway.bridgeid].deconz_ids) == 0 assert len(hass.states.async_all()) == 0 async def test_binary_sensors(hass): """Test successful creation of binary sensor entities.""" data = {"sensors": SENSOR} - await setup_gateway(hass, data) - assert "binary_sensor.sensor_1_name" in \ - hass.data[deconz.DOMAIN].deconz_ids - assert "binary_sensor.sensor_2_name" not in \ - hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway(hass, data) + assert "binary_sensor.sensor_1_name" in gateway.deconz_ids + assert "binary_sensor.sensor_2_name" not in gateway.deconz_ids assert len(hass.states.async_all()) == 1 - hass.data[deconz.DOMAIN].api.sensors['1'].async_update( + hass.data[deconz.DOMAIN][gateway.bridgeid].api.sensors['1'].async_update( {'state': {'on': False}}) async def test_add_new_sensor(hass): """Test successful creation of sensor entities.""" data = {} - await setup_gateway(hass, data) + gateway = await setup_gateway(hass, data) sensor = Mock() sensor.name = 'name' sensor.type = 'ZHAPresence' sensor.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_sensor', [sensor]) + async_dispatcher_send( + hass, gateway.async_event_new_device('sensor'), [sensor]) await hass.async_block_till_done() - assert "binary_sensor.name" in hass.data[deconz.DOMAIN].deconz_ids + assert "binary_sensor.name" in gateway.deconz_ids async def test_do_not_allow_clip_sensor(hass): """Test that clip sensors can be ignored.""" data = {} - await setup_gateway(hass, data, allow_clip_sensor=False) + gateway = await setup_gateway(hass, data, allow_clip_sensor=False) sensor = Mock() sensor.name = 'name' sensor.type = 'CLIPPresence' sensor.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_sensor', [sensor]) + async_dispatcher_send( + hass, gateway.async_event_new_device('sensor'), [sensor]) await hass.async_block_till_done() - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + assert len(gateway.deconz_ids) == 0 async def test_unload_switch(hass): """Test that it works to unload switch entities.""" data = {"sensors": SENSOR} - await setup_gateway(hass, data) + gateway = await setup_gateway(hass, data) - await hass.data[deconz.DOMAIN].async_reset() + await gateway.async_reset() assert len(hass.states.async_all()) == 0 diff --git a/tests/components/deconz/test_climate.py b/tests/components/deconz/test_climate.py index 953bb776419..a5f4d2bb79b 100644 --- a/tests/components/deconz/test_climate.py +++ b/tests/components/deconz/test_climate.py @@ -65,7 +65,7 @@ async def setup_gateway(hass, data, allow_clip_sensor=True): gateway = deconz.DeconzGateway(hass, config_entry) gateway.api = DeconzSession(hass.loop, session, **config_entry.data) gateway.api.config = Mock() - hass.data[deconz.DOMAIN] = gateway + hass.data[deconz.DOMAIN] = {gateway.bridgeid: gateway} with patch('pydeconz.DeconzSession.async_get_state', return_value=mock_coro(data)): @@ -75,6 +75,7 @@ async def setup_gateway(hass, data, allow_clip_sensor=True): config_entry, 'climate') # To flush out the service call to update the group await hass.async_block_till_done() + return gateway async def test_platform_manually_configured(hass): @@ -89,26 +90,26 @@ async def test_platform_manually_configured(hass): async def test_no_sensors(hass): """Test that no sensors in deconz results in no climate entities.""" - await setup_gateway(hass, {}) - assert not hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway(hass, {}) + assert not hass.data[deconz.DOMAIN][gateway.bridgeid].deconz_ids assert not hass.states.async_all() async def test_climate_devices(hass): """Test successful creation of sensor entities.""" - await setup_gateway(hass, {"sensors": SENSOR}) - assert "climate.climate_1_name" in hass.data[deconz.DOMAIN].deconz_ids - assert "sensor.sensor_2_name" not in hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway(hass, {"sensors": SENSOR}) + assert "climate.climate_1_name" in gateway.deconz_ids + assert "sensor.sensor_2_name" not in gateway.deconz_ids assert len(hass.states.async_all()) == 1 - hass.data[deconz.DOMAIN].api.sensors['1'].async_update( + gateway.api.sensors['1'].async_update( {'state': {'on': False}}) await hass.services.async_call( 'climate', 'turn_on', {'entity_id': 'climate.climate_1_name'}, blocking=True ) - hass.data[deconz.DOMAIN].api.session.put.assert_called_with( + gateway.api.session.put.assert_called_with( 'http://1.2.3.4:80/api/ABCDEF/sensors/1/config', data='{"mode": "auto"}' ) @@ -117,7 +118,7 @@ async def test_climate_devices(hass): 'climate', 'turn_off', {'entity_id': 'climate.climate_1_name'}, blocking=True ) - hass.data[deconz.DOMAIN].api.session.put.assert_called_with( + gateway.api.session.put.assert_called_with( 'http://1.2.3.4:80/api/ABCDEF/sensors/1/config', data='{"mode": "off"}' ) @@ -127,18 +128,18 @@ async def test_climate_devices(hass): {'entity_id': 'climate.climate_1_name', 'temperature': 20}, blocking=True ) - hass.data[deconz.DOMAIN].api.session.put.assert_called_with( + gateway.api.session.put.assert_called_with( 'http://1.2.3.4:80/api/ABCDEF/sensors/1/config', data='{"heatsetpoint": 2000.0}' ) - assert len(hass.data[deconz.DOMAIN].api.session.put.mock_calls) == 3 + assert len(gateway.api.session.put.mock_calls) == 3 async def test_verify_state_update(hass): """Test that state update properly.""" - await setup_gateway(hass, {"sensors": SENSOR}) - assert "climate.climate_1_name" in hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway(hass, {"sensors": SENSOR}) + assert "climate.climate_1_name" in gateway.deconz_ids thermostat = hass.states.get('climate.climate_1_name') assert thermostat.state == 'on' @@ -150,7 +151,7 @@ async def test_verify_state_update(hass): "id": "1", "config": {"on": False} } - hass.data[deconz.DOMAIN].api.async_event_handler(state_update) + gateway.api.async_event_handler(state_update) await hass.async_block_till_done() assert len(hass.states.async_all()) == 1 @@ -161,32 +162,34 @@ async def test_verify_state_update(hass): async def test_add_new_climate_device(hass): """Test successful creation of climate entities.""" - await setup_gateway(hass, {}) + gateway = await setup_gateway(hass, {}) sensor = Mock() sensor.name = 'name' sensor.type = 'ZHAThermostat' sensor.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_sensor', [sensor]) + async_dispatcher_send( + hass, gateway.async_event_new_device('sensor'), [sensor]) await hass.async_block_till_done() - assert "climate.name" in hass.data[deconz.DOMAIN].deconz_ids + assert "climate.name" in gateway.deconz_ids async def test_do_not_allow_clipsensor(hass): """Test that clip sensors can be ignored.""" - await setup_gateway(hass, {}, allow_clip_sensor=False) + gateway = await setup_gateway(hass, {}, allow_clip_sensor=False) sensor = Mock() sensor.name = 'name' sensor.type = 'CLIPThermostat' sensor.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_sensor', [sensor]) + async_dispatcher_send( + hass, gateway.async_event_new_device('sensor'), [sensor]) await hass.async_block_till_done() - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + assert len(gateway.deconz_ids) == 0 async def test_unload_sensor(hass): """Test that it works to unload sensor entities.""" - await setup_gateway(hass, {"sensors": SENSOR}) + gateway = await setup_gateway(hass, {"sensors": SENSOR}) - await hass.data[deconz.DOMAIN].async_reset() + await gateway.async_reset() assert len(hass.states.async_all()) == 0 diff --git a/tests/components/deconz/test_config_flow.py b/tests/components/deconz/test_config_flow.py index 863e4e93fc5..09510b136c4 100644 --- a/tests/components/deconz/test_config_flow.py +++ b/tests/components/deconz/test_config_flow.py @@ -22,10 +22,7 @@ async def test_flow_works(hass, aioclient_mock): flow.hass = hass await flow.async_step_user() - await flow.async_step_link(user_input={}) - - result = await flow.async_step_options( - user_input={'allow_clip_sensor': True, 'allow_deconz_groups': True}) + result = await flow.async_step_link(user_input={}) assert result['type'] == 'create_entry' assert result['title'] == 'deCONZ-id' @@ -33,25 +30,10 @@ async def test_flow_works(hass, aioclient_mock): 'bridgeid': 'id', 'host': '1.2.3.4', 'port': 80, - 'api_key': '1234567890ABCDEF', - 'allow_clip_sensor': True, - 'allow_deconz_groups': True + 'api_key': '1234567890ABCDEF' } -async def test_flow_already_registered_bridge(hass): - """Test config flow don't allow more than one bridge to be registered.""" - MockConfigEntry(domain='deconz', data={ - 'host': '1.2.3.4' - }).add_to_hass(hass) - - flow = config_flow.DeconzFlowHandler() - flow.hass = hass - - result = await flow.async_step_user() - assert result['type'] == 'abort' - - async def test_flow_bridge_discovery_fails(hass, aioclient_mock): """Test config flow works when discovery fails.""" flow = config_flow.DeconzFlowHandler() @@ -153,24 +135,6 @@ async def test_link_no_api_key(hass): assert result['errors'] == {'base': 'no_key'} -async def test_link_already_registered_bridge(hass): - """Test that link verifies to only allow one config entry to complete. - - This is possible with discovery which will allow the user to complete - a second config entry and then complete the discovered config entry. - """ - MockConfigEntry(domain='deconz', data={ - 'host': '1.2.3.4' - }).add_to_hass(hass) - - flow = config_flow.DeconzFlowHandler() - flow.hass = hass - flow.deconz_config = {'host': '1.2.3.4', 'port': 80} - - result = await flow.async_step_link(user_input={}) - assert result['type'] == 'abort' - - async def test_bridge_discovery(hass): """Test a bridge being discovered.""" flow = config_flow.DeconzFlowHandler() @@ -197,6 +161,7 @@ async def test_bridge_discovery_already_configured(hass): result = await flow.async_step_discovery({ 'host': '1.2.3.4', + 'port': 80, 'serial': 'id' }) @@ -234,14 +199,12 @@ async def test_import_with_api_key(hass): 'bridgeid': 'id', 'host': '1.2.3.4', 'port': 80, - 'api_key': '1234567890ABCDEF', - 'allow_clip_sensor': True, - 'allow_deconz_groups': True + 'api_key': '1234567890ABCDEF' } -async def test_options(hass, aioclient_mock): - """Test that options work and that bridgeid can be requested.""" +async def test_create_entry(hass, aioclient_mock): + """Test that _create_entry work and that bridgeid can be requested.""" aioclient_mock.get('http://1.2.3.4:80/api/1234567890ABCDEF/config', json={"bridgeid": "id"}, headers={'content-type': 'application/json'}) @@ -252,8 +215,7 @@ async def test_options(hass, aioclient_mock): 'port': 80, 'api_key': '1234567890ABCDEF'} - result = await flow.async_step_options( - user_input={'allow_clip_sensor': False, 'allow_deconz_groups': False}) + result = await flow._create_entry() assert result['type'] == 'create_entry' assert result['title'] == 'deCONZ-id' @@ -261,9 +223,7 @@ async def test_options(hass, aioclient_mock): 'bridgeid': 'id', 'host': '1.2.3.4', 'port': 80, - 'api_key': '1234567890ABCDEF', - 'allow_clip_sensor': False, - 'allow_deconz_groups': False + 'api_key': '1234567890ABCDEF' } @@ -286,8 +246,8 @@ async def test_hassio_confirm(hass): data={ 'addon': 'Mock Addon', 'host': 'mock-deconz', - 'port': 8080, - 'serial': 'aa:bb', + 'port': 80, + 'serial': 'id', 'api_key': '1234567890ABCDEF', }, context={'source': 'hassio'} @@ -299,18 +259,13 @@ async def test_hassio_confirm(hass): } result = await hass.config_entries.flow.async_configure( - result['flow_id'], { - 'allow_clip_sensor': True, - 'allow_deconz_groups': True, - } + result['flow_id'], user_input={} ) assert result['type'] == 'create_entry' assert result['result'].data == { 'host': 'mock-deconz', - 'port': 8080, - 'bridgeid': 'aa:bb', - 'api_key': '1234567890ABCDEF', - 'allow_clip_sensor': True, - 'allow_deconz_groups': True, + 'port': 80, + 'bridgeid': 'id', + 'api_key': '1234567890ABCDEF' } diff --git a/tests/components/deconz/test_cover.py b/tests/components/deconz/test_cover.py index b021bcb8d51..73e3d411958 100644 --- a/tests/components/deconz/test_cover.py +++ b/tests/components/deconz/test_cover.py @@ -61,7 +61,7 @@ async def setup_gateway(hass, data): gateway = deconz.DeconzGateway(hass, config_entry) gateway.api = DeconzSession(loop, session, **config_entry.data) gateway.api.config = Mock() - hass.data[deconz.DOMAIN] = gateway + hass.data[deconz.DOMAIN] = {gateway.bridgeid: gateway} with patch('pydeconz.DeconzSession.async_get_state', return_value=mock_coro(data)): @@ -70,6 +70,7 @@ async def setup_gateway(hass, data): await hass.config_entries.async_forward_entry_setup(config_entry, 'cover') # To flush out the service call to update the group await hass.async_block_till_done() + return gateway async def test_platform_manually_configured(hass): @@ -84,8 +85,8 @@ async def test_platform_manually_configured(hass): async def test_no_covers(hass): """Test that no cover entities are created.""" - await setup_gateway(hass, {}) - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + gateway = await setup_gateway(hass, {}) + assert not hass.data[deconz.DOMAIN][gateway.bridgeid].deconz_ids assert len(hass.states.async_all()) == 0 @@ -93,8 +94,8 @@ async def test_cover(hass): """Test that all supported cover entities are created.""" with patch('pydeconz.DeconzSession.async_put_state', return_value=mock_coro(True)): - await setup_gateway(hass, {"lights": SUPPORTED_COVERS}) - assert "cover.cover_1_name" in hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway(hass, {"lights": SUPPORTED_COVERS}) + assert "cover.cover_1_name" in gateway.deconz_ids assert len(SUPPORTED_COVERS) == len(COVER_TYPES) assert len(hass.states.async_all()) == 3 @@ -102,7 +103,7 @@ async def test_cover(hass): assert cover_1 is not None assert cover_1.state == 'closed' - hass.data[deconz.DOMAIN].api.lights['1'].async_update({}) + gateway.api.lights['1'].async_update({}) await hass.services.async_call('cover', 'open_cover', { 'entity_id': 'cover.cover_1_name' @@ -122,14 +123,15 @@ async def test_cover(hass): async def test_add_new_cover(hass): """Test successful creation of cover entity.""" data = {} - await setup_gateway(hass, data) + gateway = await setup_gateway(hass, data) cover = Mock() cover.name = 'name' cover.type = "Level controllable output" cover.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_light', [cover]) + async_dispatcher_send( + hass, gateway.async_event_new_device('light'), [cover]) await hass.async_block_till_done() - assert "cover.name" in hass.data[deconz.DOMAIN].deconz_ids + assert "cover.name" in gateway.deconz_ids async def test_unsupported_cover(hass): @@ -140,8 +142,8 @@ async def test_unsupported_cover(hass): async def test_unload_cover(hass): """Test that it works to unload switch entities.""" - await setup_gateway(hass, {"lights": SUPPORTED_COVERS}) + gateway = await setup_gateway(hass, {"lights": SUPPORTED_COVERS}) - await hass.data[deconz.DOMAIN].async_reset() + await gateway.async_reset() assert len(hass.states.async_all()) == 1 diff --git a/tests/components/deconz/test_init.py b/tests/components/deconz/test_init.py index e0afadccc81..da37f4a9652 100644 --- a/tests/components/deconz/test_init.py +++ b/tests/components/deconz/test_init.py @@ -11,56 +11,62 @@ from homeassistant.components import deconz from tests.common import mock_coro, MockConfigEntry +ENTRY1_HOST = '1.2.3.4' +ENTRY1_PORT = 80 +ENTRY1_API_KEY = '1234567890ABCDEF' +ENTRY1_BRIDGEID = '12345ABC' -CONFIG = { - "config": { - "bridgeid": "0123456789ABCDEF", - "mac": "12:34:56:78:90:ab", - "modelid": "deCONZ", - "name": "Phoscon", - "swversion": "2.05.35" - } -} +ENTRY2_HOST = '2.3.4.5' +ENTRY2_PORT = 80 +ENTRY2_API_KEY = '1234567890ABCDEF' +ENTRY2_BRIDGEID = '23456DEF' + + +async def setup_entry(hass, entry): + """Test that setup entry works.""" + with patch.object(deconz.DeconzGateway, 'async_setup', + return_value=mock_coro(True)), \ + patch.object(deconz.DeconzGateway, 'async_update_device_registry', + return_value=mock_coro(True)): + assert await deconz.async_setup_entry(hass, entry) is True async def test_config_with_host_passed_to_config_entry(hass): """Test that configured options for a host are loaded via config entry.""" - with patch.object(hass, 'config_entries') as mock_config_entries, \ - patch.object(deconz, 'configured_hosts', return_value=[]): + with patch.object(hass.config_entries, 'flow') as mock_config_flow: assert await async_setup_component(hass, deconz.DOMAIN, { deconz.DOMAIN: { - deconz.CONF_HOST: '1.2.3.4', - deconz.CONF_PORT: 80 + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT } }) is True # Import flow started - assert len(mock_config_entries.flow.mock_calls) == 2 + assert len(mock_config_flow.mock_calls) == 2 async def test_config_without_host_not_passed_to_config_entry(hass): """Test that a configuration without a host does not initiate an import.""" - with patch.object(hass, 'config_entries') as mock_config_entries, \ - patch.object(deconz, 'configured_hosts', return_value=[]): + MockConfigEntry(domain=deconz.DOMAIN, data={}).add_to_hass(hass) + with patch.object(hass.config_entries, 'flow') as mock_config_flow: assert await async_setup_component(hass, deconz.DOMAIN, { deconz.DOMAIN: {} }) is True # No flow started - assert len(mock_config_entries.flow.mock_calls) == 0 + assert len(mock_config_flow.mock_calls) == 0 -async def test_config_already_registered_not_passed_to_config_entry(hass): +async def test_config_import_entry_fails_when_entries_exist(hass): """Test that an already registered host does not initiate an import.""" - with patch.object(hass, 'config_entries') as mock_config_entries, \ - patch.object(deconz, 'configured_hosts', - return_value=['1.2.3.4']): + MockConfigEntry(domain=deconz.DOMAIN, data={}).add_to_hass(hass) + with patch.object(hass.config_entries, 'flow') as mock_config_flow: assert await async_setup_component(hass, deconz.DOMAIN, { deconz.DOMAIN: { - deconz.CONF_HOST: '1.2.3.4', - deconz.CONF_PORT: 80 + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT } }) is True # No flow started - assert len(mock_config_entries.flow.mock_calls) == 0 + assert len(mock_config_flow.mock_calls) == 0 async def test_config_discovery(hass): @@ -71,16 +77,14 @@ async def test_config_discovery(hass): assert len(mock_config_entries.flow.mock_calls) == 0 -async def test_setup_entry_already_registered_bridge(hass): - """Test setup entry doesn't allow more than one instance of deCONZ.""" - hass.data[deconz.DOMAIN] = True - assert await deconz.async_setup_entry(hass, {}) is False - - async def test_setup_entry_fails(hass): """Test setup entry fails if deCONZ is not available.""" entry = Mock() - entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'} + entry.data = { + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT, + deconz.CONF_API_KEY: ENTRY1_API_KEY + } with patch('pydeconz.DeconzSession.async_load_parameters', side_effect=Exception): await deconz.async_setup_entry(hass, entry) @@ -89,61 +93,121 @@ async def test_setup_entry_fails(hass): async def test_setup_entry_no_available_bridge(hass): """Test setup entry fails if deCONZ is not available.""" entry = Mock() - entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'} - with patch( - 'pydeconz.DeconzSession.async_load_parameters', - side_effect=asyncio.TimeoutError - ), pytest.raises(ConfigEntryNotReady): + entry.data = { + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT, + deconz.CONF_API_KEY: ENTRY1_API_KEY + } + with patch('pydeconz.DeconzSession.async_load_parameters', + side_effect=asyncio.TimeoutError),\ + pytest.raises(ConfigEntryNotReady): await deconz.async_setup_entry(hass, entry) async def test_setup_entry_successful(hass): """Test setup entry is successful.""" entry = MockConfigEntry(domain=deconz.DOMAIN, data={ - 'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF' + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT, + deconz.CONF_API_KEY: ENTRY1_API_KEY, + deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID }) entry.add_to_hass(hass) - mock_registry = Mock() - with patch.object(deconz, 'DeconzGateway') as mock_gateway, \ - patch('homeassistant.helpers.device_registry.async_get_registry', - return_value=mock_coro(mock_registry)): - mock_gateway.return_value.async_setup.return_value = mock_coro(True) - assert await deconz.async_setup_entry(hass, entry) is True - assert hass.data[deconz.DOMAIN] + + await setup_entry(hass, entry) + + assert ENTRY1_BRIDGEID in hass.data[deconz.DOMAIN] + assert hass.data[deconz.DOMAIN][ENTRY1_BRIDGEID].master + + +async def test_setup_entry_multiple_gateways(hass): + """Test setup entry is successful with multiple gateways.""" + entry = MockConfigEntry(domain=deconz.DOMAIN, data={ + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT, + deconz.CONF_API_KEY: ENTRY1_API_KEY, + deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID + }) + entry.add_to_hass(hass) + + entry2 = MockConfigEntry(domain=deconz.DOMAIN, data={ + deconz.CONF_HOST: ENTRY2_HOST, + deconz.CONF_PORT: ENTRY2_PORT, + deconz.CONF_API_KEY: ENTRY2_API_KEY, + deconz.CONF_BRIDGEID: ENTRY2_BRIDGEID + }) + entry2.add_to_hass(hass) + + await setup_entry(hass, entry) + await setup_entry(hass, entry2) + + assert ENTRY1_BRIDGEID in hass.data[deconz.DOMAIN] + assert hass.data[deconz.DOMAIN][ENTRY1_BRIDGEID].master + assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN] + assert not hass.data[deconz.DOMAIN][ENTRY2_BRIDGEID].master async def test_unload_entry(hass): """Test being able to unload an entry.""" entry = MockConfigEntry(domain=deconz.DOMAIN, data={ - 'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF' + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT, + deconz.CONF_API_KEY: ENTRY1_API_KEY, + deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID }) entry.add_to_hass(hass) - mock_registry = Mock() - with patch.object(deconz, 'DeconzGateway') as mock_gateway, \ - patch('homeassistant.helpers.device_registry.async_get_registry', - return_value=mock_coro(mock_registry)): - mock_gateway.return_value.async_setup.return_value = mock_coro(True) - assert await deconz.async_setup_entry(hass, entry) is True - mock_gateway.return_value.async_reset.return_value = mock_coro(True) - assert await deconz.async_unload_entry(hass, entry) - assert deconz.DOMAIN not in hass.data + await setup_entry(hass, entry) + + with patch.object(deconz.DeconzGateway, 'async_reset', + return_value=mock_coro(True)): + assert await deconz.async_unload_entry(hass, entry) + + assert not hass.data[deconz.DOMAIN] + + +async def test_unload_entry_multiple_gateways(hass): + """Test being able to unload an entry and master gateway gets moved.""" + entry = MockConfigEntry(domain=deconz.DOMAIN, data={ + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT, + deconz.CONF_API_KEY: ENTRY1_API_KEY, + deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID + }) + entry.add_to_hass(hass) + + entry2 = MockConfigEntry(domain=deconz.DOMAIN, data={ + deconz.CONF_HOST: ENTRY2_HOST, + deconz.CONF_PORT: ENTRY2_PORT, + deconz.CONF_API_KEY: ENTRY2_API_KEY, + deconz.CONF_BRIDGEID: ENTRY2_BRIDGEID + }) + entry2.add_to_hass(hass) + + await setup_entry(hass, entry) + await setup_entry(hass, entry2) + + with patch.object(deconz.DeconzGateway, 'async_reset', + return_value=mock_coro(True)): + assert await deconz.async_unload_entry(hass, entry) + + assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN] + assert hass.data[deconz.DOMAIN][ENTRY2_BRIDGEID].master async def test_service_configure(hass): """Test that service invokes pydeconz with the correct path and data.""" entry = MockConfigEntry(domain=deconz.DOMAIN, data={ - 'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF' + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT, + deconz.CONF_API_KEY: ENTRY1_API_KEY, + deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID }) entry.add_to_hass(hass) - mock_registry = Mock() - with patch.object(deconz, 'DeconzGateway') as mock_gateway, \ - patch('homeassistant.helpers.device_registry.async_get_registry', - return_value=mock_coro(mock_registry)): - mock_gateway.return_value.async_setup.return_value = mock_coro(True) - assert await deconz.async_setup_entry(hass, entry) is True - hass.data[deconz.DOMAIN].deconz_ids = { + await setup_entry(hass, entry) + + hass.data[deconz.DOMAIN][ENTRY1_BRIDGEID].deconz_ids = { 'light.test': '/light/1' } data = {'on': True, 'attr1': 10, 'attr2': 20} @@ -191,25 +255,23 @@ async def test_service_configure(hass): async def test_service_refresh_devices(hass): """Test that service can refresh devices.""" entry = MockConfigEntry(domain=deconz.DOMAIN, data={ - 'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF' + deconz.CONF_HOST: ENTRY1_HOST, + deconz.CONF_PORT: ENTRY1_PORT, + deconz.CONF_API_KEY: ENTRY1_API_KEY, + deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID }) entry.add_to_hass(hass) - mock_registry = Mock() - with patch.object(deconz, 'DeconzGateway') as mock_gateway, \ - patch('homeassistant.helpers.device_registry.async_get_registry', - return_value=mock_coro(mock_registry)): - mock_gateway.return_value.async_setup.return_value = mock_coro(True) - assert await deconz.async_setup_entry(hass, entry) is True + await setup_entry(hass, entry) - with patch.object(hass.data[deconz.DOMAIN].api, 'async_load_parameters', - return_value=mock_coro(True)): + with patch('pydeconz.DeconzSession.async_load_parameters', + return_value=mock_coro(True)): await hass.services.async_call( 'deconz', 'device_refresh', service_data={}) await hass.async_block_till_done() - with patch.object(hass.data[deconz.DOMAIN].api, 'async_load_parameters', - return_value=mock_coro(False)): + with patch('pydeconz.DeconzSession.async_load_parameters', + return_value=mock_coro(False)): await hass.services.async_call( 'deconz', 'device_refresh', service_data={}) await hass.async_block_till_done() diff --git a/tests/components/deconz/test_light.py b/tests/components/deconz/test_light.py index 49c3f280d8a..d9f6927fe2c 100644 --- a/tests/components/deconz/test_light.py +++ b/tests/components/deconz/test_light.py @@ -87,7 +87,7 @@ async def setup_gateway(hass, data, allow_deconz_groups=True): gateway = deconz.DeconzGateway(hass, config_entry) gateway.api = DeconzSession(loop, session, **config_entry.data) gateway.api.config = Mock() - hass.data[deconz.DOMAIN] = gateway + hass.data[deconz.DOMAIN] = {gateway.bridgeid: gateway} with patch('pydeconz.DeconzSession.async_get_state', return_value=mock_coro(data)): @@ -96,6 +96,7 @@ async def setup_gateway(hass, data, allow_deconz_groups=True): await hass.config_entries.async_forward_entry_setup(config_entry, 'light') # To flush out the service call to update the group await hass.async_block_till_done() + return gateway async def test_platform_manually_configured(hass): @@ -110,8 +111,8 @@ async def test_platform_manually_configured(hass): async def test_no_lights_or_groups(hass): """Test that no lights or groups entities are created.""" - await setup_gateway(hass, {}) - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + gateway = await setup_gateway(hass, {}) + assert not hass.data[deconz.DOMAIN][gateway.bridgeid].deconz_ids assert len(hass.states.async_all()) == 0 @@ -119,11 +120,12 @@ async def test_lights_and_groups(hass): """Test that lights or groups entities are created.""" with patch('pydeconz.DeconzSession.async_put_state', return_value=mock_coro(True)): - await setup_gateway(hass, {"lights": LIGHT, "groups": GROUP}) - assert "light.light_1_name" in hass.data[deconz.DOMAIN].deconz_ids - assert "light.light_2_name" in hass.data[deconz.DOMAIN].deconz_ids - assert "light.group_1_name" in hass.data[deconz.DOMAIN].deconz_ids - assert "light.group_2_name" not in hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway( + hass, {"lights": LIGHT, "groups": GROUP}) + assert "light.light_1_name" in gateway.deconz_ids + assert "light.light_2_name" in gateway.deconz_ids + assert "light.group_1_name" in gateway.deconz_ids + assert "light.group_2_name" not in gateway.deconz_ids assert len(hass.states.async_all()) == 4 lamp_1 = hass.states.get('light.light_1_name') @@ -137,7 +139,7 @@ async def test_lights_and_groups(hass): assert light_2.state == 'on' assert light_2.attributes['color_temp'] == 2500 - hass.data[deconz.DOMAIN].api.lights['1'].async_update({}) + gateway.api.lights['1'].async_update({}) await hass.services.async_call('light', 'turn_on', { 'entity_id': 'light.light_1_name', @@ -166,49 +168,52 @@ async def test_lights_and_groups(hass): async def test_add_new_light(hass): """Test successful creation of light entities.""" - await setup_gateway(hass, {}) + gateway = await setup_gateway(hass, {}) light = Mock() light.name = 'name' light.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_light', [light]) + async_dispatcher_send( + hass, gateway.async_event_new_device('light'), [light]) await hass.async_block_till_done() - assert "light.name" in hass.data[deconz.DOMAIN].deconz_ids + assert "light.name" in gateway.deconz_ids async def test_add_new_group(hass): """Test successful creation of group entities.""" - await setup_gateway(hass, {}) + gateway = await setup_gateway(hass, {}) group = Mock() group.name = 'name' group.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_group', [group]) + async_dispatcher_send( + hass, gateway.async_event_new_device('group'), [group]) await hass.async_block_till_done() - assert "light.name" in hass.data[deconz.DOMAIN].deconz_ids + assert "light.name" in gateway.deconz_ids async def test_do_not_add_deconz_groups(hass): """Test that clip sensors can be ignored.""" - await setup_gateway(hass, {}, allow_deconz_groups=False) + gateway = await setup_gateway(hass, {}, allow_deconz_groups=False) group = Mock() group.name = 'name' group.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_group', [group]) + async_dispatcher_send( + hass, gateway.async_event_new_device('group'), [group]) await hass.async_block_till_done() - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + assert len(gateway.deconz_ids) == 0 async def test_no_switch(hass): """Test that a switch doesn't get created as a light entity.""" - await setup_gateway(hass, {"lights": SWITCH}) - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + gateway = await setup_gateway(hass, {"lights": SWITCH}) + assert len(gateway.deconz_ids) == 0 assert len(hass.states.async_all()) == 0 async def test_unload_light(hass): """Test that it works to unload switch entities.""" - await setup_gateway(hass, {"lights": LIGHT, "groups": GROUP}) + gateway = await setup_gateway(hass, {"lights": LIGHT, "groups": GROUP}) - await hass.data[deconz.DOMAIN].async_reset() + await gateway.async_reset() # Group.all_lights will not be removed assert len(hass.states.async_all()) == 1 diff --git a/tests/components/deconz/test_scene.py b/tests/components/deconz/test_scene.py index 963f1064b35..0feac24f22a 100644 --- a/tests/components/deconz/test_scene.py +++ b/tests/components/deconz/test_scene.py @@ -47,7 +47,7 @@ async def setup_gateway(hass, data): gateway = deconz.DeconzGateway(hass, config_entry) gateway.api = DeconzSession(loop, session, **config_entry.data) gateway.api.config = Mock() - hass.data[deconz.DOMAIN] = gateway + hass.data[deconz.DOMAIN] = {gateway.bridgeid: gateway} with patch('pydeconz.DeconzSession.async_get_state', return_value=mock_coro(data)): @@ -56,6 +56,7 @@ async def setup_gateway(hass, data): await hass.config_entries.async_forward_entry_setup(config_entry, 'scene') # To flush out the service call to update the group await hass.async_block_till_done() + return gateway async def test_platform_manually_configured(hass): @@ -70,8 +71,8 @@ async def test_platform_manually_configured(hass): async def test_no_scenes(hass): """Test that scenes can be loaded without scenes being available.""" - await setup_gateway(hass, {}) - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + gateway = await setup_gateway(hass, {}) + assert not hass.data[deconz.DOMAIN][gateway.bridgeid].deconz_ids assert len(hass.states.async_all()) == 0 @@ -79,8 +80,8 @@ async def test_scenes(hass): """Test that scenes works.""" with patch('pydeconz.DeconzSession.async_put_state', return_value=mock_coro(True)): - await setup_gateway(hass, {"groups": GROUP}) - assert "scene.group_1_name_scene_1" in hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway(hass, {"groups": GROUP}) + assert "scene.group_1_name_scene_1" in gateway.deconz_ids assert len(hass.states.async_all()) == 1 await hass.services.async_call('scene', 'turn_on', { @@ -90,8 +91,8 @@ async def test_scenes(hass): async def test_unload_scene(hass): """Test that it works to unload scene entities.""" - await setup_gateway(hass, {"groups": GROUP}) + gateway = await setup_gateway(hass, {"groups": GROUP}) - await hass.data[deconz.DOMAIN].async_reset() + await gateway.async_reset() assert len(hass.states.async_all()) == 0 diff --git a/tests/components/deconz/test_sensor.py b/tests/components/deconz/test_sensor.py index f5cfbe2c183..41bb7b362f5 100644 --- a/tests/components/deconz/test_sensor.py +++ b/tests/components/deconz/test_sensor.py @@ -91,7 +91,7 @@ async def setup_gateway(hass, data, allow_clip_sensor=True): gateway = deconz.DeconzGateway(hass, config_entry) gateway.api = DeconzSession(loop, session, **config_entry.data) gateway.api.config = Mock() - hass.data[deconz.DOMAIN] = gateway + hass.data[deconz.DOMAIN] = {gateway.bridgeid: gateway} with patch('pydeconz.DeconzSession.async_get_state', return_value=mock_coro(data)): @@ -101,6 +101,7 @@ async def setup_gateway(hass, data, allow_clip_sensor=True): config_entry, 'sensor') # To flush out the service call to update the group await hass.async_block_till_done() + return gateway async def test_platform_manually_configured(hass): @@ -115,58 +116,56 @@ async def test_platform_manually_configured(hass): async def test_no_sensors(hass): """Test that no sensors in deconz results in no sensor entities.""" - await setup_gateway(hass, {}) - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + gateway = await setup_gateway(hass, {}) + assert not hass.data[deconz.DOMAIN][gateway.bridgeid].deconz_ids assert len(hass.states.async_all()) == 0 async def test_sensors(hass): """Test successful creation of sensor entities.""" - await setup_gateway(hass, {"sensors": SENSOR}) - assert "sensor.sensor_1_name" in hass.data[deconz.DOMAIN].deconz_ids - assert "sensor.sensor_2_name" not in hass.data[deconz.DOMAIN].deconz_ids - assert "sensor.sensor_3_name" not in hass.data[deconz.DOMAIN].deconz_ids - assert "sensor.sensor_3_name_battery_level" not in \ - hass.data[deconz.DOMAIN].deconz_ids - assert "sensor.sensor_4_name" not in hass.data[deconz.DOMAIN].deconz_ids - assert "sensor.sensor_4_name_battery_level" in \ - hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway(hass, {"sensors": SENSOR}) + assert "sensor.sensor_1_name" in gateway.deconz_ids + assert "sensor.sensor_2_name" not in gateway.deconz_ids + assert "sensor.sensor_3_name" not in gateway.deconz_ids + assert "sensor.sensor_3_name_battery_level" not in gateway.deconz_ids + assert "sensor.sensor_4_name" not in gateway.deconz_ids + assert "sensor.sensor_4_name_battery_level" in gateway.deconz_ids assert len(hass.states.async_all()) == 5 - hass.data[deconz.DOMAIN].api.sensors['1'].async_update( - {'state': {'on': False}}) - hass.data[deconz.DOMAIN].api.sensors['4'].async_update( - {'config': {'battery': 75}}) + gateway.api.sensors['1'].async_update({'state': {'on': False}}) + gateway.api.sensors['4'].async_update({'config': {'battery': 75}}) async def test_add_new_sensor(hass): """Test successful creation of sensor entities.""" - await setup_gateway(hass, {}) + gateway = await setup_gateway(hass, {}) sensor = Mock() sensor.name = 'name' sensor.type = 'ZHATemperature' sensor.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_sensor', [sensor]) + async_dispatcher_send( + hass, gateway.async_event_new_device('sensor'), [sensor]) await hass.async_block_till_done() - assert "sensor.name" in hass.data[deconz.DOMAIN].deconz_ids + assert "sensor.name" in gateway.deconz_ids async def test_do_not_allow_clipsensor(hass): """Test that clip sensors can be ignored.""" - await setup_gateway(hass, {}, allow_clip_sensor=False) + gateway = await setup_gateway(hass, {}, allow_clip_sensor=False) sensor = Mock() sensor.name = 'name' sensor.type = 'CLIPTemperature' sensor.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_sensor', [sensor]) + async_dispatcher_send( + hass, gateway.async_event_new_device('sensor'), [sensor]) await hass.async_block_till_done() - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + assert len(gateway.deconz_ids) == 0 async def test_unload_sensor(hass): """Test that it works to unload sensor entities.""" - await setup_gateway(hass, {"sensors": SENSOR}) + gateway = await setup_gateway(hass, {"sensors": SENSOR}) - await hass.data[deconz.DOMAIN].async_reset() + await gateway.async_reset() assert len(hass.states.async_all()) == 0 diff --git a/tests/components/deconz/test_switch.py b/tests/components/deconz/test_switch.py index 245be27961d..e05362953a1 100644 --- a/tests/components/deconz/test_switch.py +++ b/tests/components/deconz/test_switch.py @@ -65,7 +65,7 @@ async def setup_gateway(hass, data): gateway = deconz.DeconzGateway(hass, config_entry) gateway.api = DeconzSession(loop, session, **config_entry.data) gateway.api.config = Mock() - hass.data[deconz.DOMAIN] = gateway + hass.data[deconz.DOMAIN] = {gateway.bridgeid: gateway} with patch('pydeconz.DeconzSession.async_get_state', return_value=mock_coro(data)): @@ -74,6 +74,7 @@ async def setup_gateway(hass, data): await hass.config_entries.async_forward_entry_setup(config_entry, 'switch') # To flush out the service call to update the group await hass.async_block_till_done() + return gateway async def test_platform_manually_configured(hass): @@ -88,8 +89,8 @@ async def test_platform_manually_configured(hass): async def test_no_switches(hass): """Test that no switch entities are created.""" - await setup_gateway(hass, {}) - assert len(hass.data[deconz.DOMAIN].deconz_ids) == 0 + gateway = await setup_gateway(hass, {}) + assert not hass.data[deconz.DOMAIN][gateway.bridgeid].deconz_ids assert len(hass.states.async_all()) == 0 @@ -97,10 +98,10 @@ async def test_switches(hass): """Test that all supported switch entities are created.""" with patch('pydeconz.DeconzSession.async_put_state', return_value=mock_coro(True)): - await setup_gateway(hass, {"lights": SUPPORTED_SWITCHES}) - assert "switch.switch_1_name" in hass.data[deconz.DOMAIN].deconz_ids - assert "switch.switch_2_name" in hass.data[deconz.DOMAIN].deconz_ids - assert "switch.switch_3_name" in hass.data[deconz.DOMAIN].deconz_ids + gateway = await setup_gateway(hass, {"lights": SUPPORTED_SWITCHES}) + assert "switch.switch_1_name" in gateway.deconz_ids + assert "switch.switch_2_name" in gateway.deconz_ids + assert "switch.switch_3_name" in gateway.deconz_ids assert len(SUPPORTED_SWITCHES) == len(SWITCH_TYPES) assert len(hass.states.async_all()) == 4 @@ -111,7 +112,7 @@ async def test_switches(hass): assert switch_3 is not None assert switch_3.state == 'on' - hass.data[deconz.DOMAIN].api.lights['1'].async_update({}) + gateway.api.lights['1'].async_update({}) await hass.services.async_call('switch', 'turn_on', { 'entity_id': 'switch.switch_1_name' @@ -130,14 +131,15 @@ async def test_switches(hass): async def test_add_new_switch(hass): """Test successful creation of switch entity.""" - await setup_gateway(hass, {}) + gateway = await setup_gateway(hass, {}) switch = Mock() switch.name = 'name' switch.type = "Smart plug" switch.register_async_callback = Mock() - async_dispatcher_send(hass, 'deconz_new_light', [switch]) + async_dispatcher_send( + hass, gateway.async_event_new_device('light'), [switch]) await hass.async_block_till_done() - assert "switch.name" in hass.data[deconz.DOMAIN].deconz_ids + assert "switch.name" in gateway.deconz_ids async def test_unsupported_switch(hass): @@ -148,8 +150,8 @@ async def test_unsupported_switch(hass): async def test_unload_switch(hass): """Test that it works to unload switch entities.""" - await setup_gateway(hass, {"lights": SUPPORTED_SWITCHES}) + gateway = await setup_gateway(hass, {"lights": SUPPORTED_SWITCHES}) - await hass.data[deconz.DOMAIN].async_reset() + await gateway.async_reset() assert len(hass.states.async_all()) == 1 From 6996fec809b759e7075677c1c6e3f4e4a9394e7b Mon Sep 17 00:00:00 2001 From: Wolfgang Malgadey Date: Fri, 5 Apr 2019 02:52:06 +0200 Subject: [PATCH 096/167] Fix tado turn on off (#22291) * fix for turn on and off, with new pyTado missing blank line * removed, because can't push * uploaded the file through github again --- homeassistant/components/tado/__init__.py | 5 +++++ homeassistant/components/tado/climate.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/tado/__init__.py b/homeassistant/components/tado/__init__.py index 6808729685e..8d3f541972e 100644 --- a/homeassistant/components/tado/__init__.py +++ b/homeassistant/components/tado/__init__.py @@ -121,3 +121,8 @@ class TadoDataStore: """Wrap for setZoneOverlay(..).""" self.tado.setZoneOverlay(zone_id, mode, temperature, duration) self.update(no_throttle=True) # pylint: disable=unexpected-keyword-arg + + def set_zone_off(self, zone_id, mode): + """Set a zone to off.""" + self.tado.setZoneOverlay(zone_id, mode, None, None, 'HEATING', 'OFF') + self.update(no_throttle=True) # pylint: disable=unexpected-keyword-arg diff --git a/homeassistant/components/tado/climate.py b/homeassistant/components/tado/climate.py index 56c670184b5..90d5f076974 100644 --- a/homeassistant/components/tado/climate.py +++ b/homeassistant/components/tado/climate.py @@ -363,7 +363,7 @@ class TadoClimate(ClimateDevice): if self._current_operation == CONST_MODE_OFF: _LOGGER.info("Switching mytado.com to OFF for zone %s", self.zone_name) - self._store.set_zone_overlay(self.zone_id, CONST_OVERLAY_MANUAL) + self._store.set_zone_off(self.zone_id, CONST_OVERLAY_MANUAL) self._overlay_mode = self._current_operation return From eadc1e037af1d7098ac450f53ac936c0745d4eb5 Mon Sep 17 00:00:00 2001 From: Markus Jankowski Date: Fri, 5 Apr 2019 03:37:59 +0200 Subject: [PATCH 097/167] add device class signal strength (#22738) --- homeassistant/components/sensor/__init__.py | 5 +++-- homeassistant/const.py | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index e11ace9749c..89963118300 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -7,8 +7,8 @@ import voluptuous as vol from homeassistant.const import ( DEVICE_CLASS_BATTERY, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, - DEVICE_CLASS_POWER, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_TIMESTAMP) + DEVICE_CLASS_POWER, DEVICE_CLASS_PRESSURE, DEVICE_CLASS_SIGNAL_STRENGTH, + DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TIMESTAMP) from homeassistant.helpers.config_validation import ( # noqa PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE) from homeassistant.helpers.entity_component import EntityComponent @@ -24,6 +24,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_BATTERY, # % of battery that is left DEVICE_CLASS_HUMIDITY, # % of humidity in the air DEVICE_CLASS_ILLUMINANCE, # current light level (lx/lm) + DEVICE_CLASS_SIGNAL_STRENGTH, # signal strength (dB/dBm) DEVICE_CLASS_TEMPERATURE, # temperature (C/F) DEVICE_CLASS_TIMESTAMP, # timestamp (ISO8601) DEVICE_CLASS_PRESSURE, # pressure (hPa/mbar) diff --git a/homeassistant/const.py b/homeassistant/const.py index 295a73a0e6c..e4f1ac95af4 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -180,6 +180,7 @@ EVENT_SCRIPT_STARTED = 'script_started' DEVICE_CLASS_BATTERY = 'battery' DEVICE_CLASS_HUMIDITY = 'humidity' DEVICE_CLASS_ILLUMINANCE = 'illuminance' +DEVICE_CLASS_SIGNAL_STRENGTH = 'signal_strength' DEVICE_CLASS_TEMPERATURE = 'temperature' DEVICE_CLASS_TIMESTAMP = 'timestamp' DEVICE_CLASS_PRESSURE = 'pressure' From b130c433c94873c65701074a237d2af86a63a0fe Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Thu, 4 Apr 2019 20:50:07 -0700 Subject: [PATCH 098/167] Update pywebpush version in manifest.json Missed during #22737 --- homeassistant/components/html5/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/html5/manifest.json b/homeassistant/components/html5/manifest.json index 98b2834be7f..81e4072e629 100644 --- a/homeassistant/components/html5/manifest.json +++ b/homeassistant/components/html5/manifest.json @@ -3,7 +3,7 @@ "name": "HTML5 Notifications", "documentation": "https://www.home-assistant.io/components/html5", "requirements": [ - "pywebpush==1.6.0" + "pywebpush==1.9.2" ], "dependencies": [], "codeowners": [ From be579b783aba180a7997b4cd8751c77a4a9b3d0c Mon Sep 17 00:00:00 2001 From: Rohan Kapoor Date: Thu, 4 Apr 2019 21:24:55 -0700 Subject: [PATCH 099/167] Update PR template requirements to point to the manifest (#22751) ## Description: Update the PR template to point requirements to the new manifest requirements. **Related issue (if applicable):** relates to #22700 **Pull request in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) with documentation (if applicable):** https://github.com/home-assistant/developers.home-assistant/pull/214 ## Example entry for `configuration.yaml` (if applicable): ```yaml ``` ## Checklist: - [ ] The code change is tested and works locally. - [ ] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass** - [ ] There is no commented out code in this PR. If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) If the code communicates with devices, web services, or third-party tools: - [ ] New dependencies have been added to the `REQUIREMENTS` variable ([example][ex-requir]). - [ ] New dependencies are only imported inside functions that use them ([example][ex-import]). - [ ] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`. - [ ] New files were added to `.coveragerc`. If the code does not interact with devices: - [ ] Tests have been added to verify that the new code works. [ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14 [ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23 --- .github/PULL_REQUEST_TEMPLATE.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ecdbddf5b5d..9b3ca90db2f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -23,7 +23,8 @@ If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) If the code communicates with devices, web services, or third-party tools: - - [ ] New dependencies have been added to the `REQUIREMENTS` variable ([example][ex-requir]). + - [ ] There is a manifest with all fields filled out correctly ([example][ex-manifest]). + - [ ] New dependencies have been added to `requirements` in the manifest ([example][ex-requir]). - [ ] New dependencies are only imported inside functions that use them ([example][ex-import]). - [ ] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`. - [ ] New files were added to `.coveragerc`. @@ -31,5 +32,6 @@ If the code communicates with devices, web services, or third-party tools: If the code does not interact with devices: - [ ] Tests have been added to verify that the new code works. -[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14 +[ex-manifest]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json +[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json#L5 [ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23 From 6c5f0b74349dd84762b76b454aeb45cfd0f6e7f2 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Thu, 4 Apr 2019 21:27:18 -0700 Subject: [PATCH 100/167] It doesnt count as a fail if you catch it within 2 minutes --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9b3ca90db2f..ebebf487275 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -23,7 +23,7 @@ If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) If the code communicates with devices, web services, or third-party tools: - - [ ] There is a manifest with all fields filled out correctly ([example][ex-manifest]). + - [ ] [_The manifest file_][manifest-docs] has all fields filled out correctly ([example][ex-manifest]). - [ ] New dependencies have been added to `requirements` in the manifest ([example][ex-requir]). - [ ] New dependencies are only imported inside functions that use them ([example][ex-import]). - [ ] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`. @@ -35,3 +35,4 @@ If the code does not interact with devices: [ex-manifest]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json [ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json#L5 [ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23 +[manifest-docs]: https://developers.home-assistant.io/docs/en/development_checklist.html#_the-manifest-file_ From d15eedc0fb3f5ea023c710407b7af6ca24f799a6 Mon Sep 17 00:00:00 2001 From: Rohan Kapoor Date: Thu, 4 Apr 2019 21:29:29 -0700 Subject: [PATCH 101/167] Generate requirements_* from manifests (#22718) ## Description: Generate requirements_* from manifests (if present). If not, fallback to the current approach of reading `REQUIREMENTS` from the module attribute. I disabled exploring the children of the `homeassistant.components.*` packages since that will just add a dependency (from the manifest) due to each of the python files in the package. Just having one for the top level package should be sufficient. **Related issue (if applicable):** relates to #22700 ## Checklist: - [x] The code change is tested and works locally. - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass** - [x] There is no commented out code in this PR. [ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14 [ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23 Co-authored-by: Jason Hu --- requirements_all.txt | 834 +++++++++++++++----------------- requirements_test_all.txt | 110 ++--- script/gen_requirements_all.py | 73 +-- script/manifest/requirements.py | 22 + 4 files changed, 515 insertions(+), 524 deletions(-) create mode 100644 script/manifest/requirements.py diff --git a/requirements_all.txt b/requirements_all.txt index 1351a640008..7d154cd2ed7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -20,13 +20,13 @@ voluptuous-serialize==2.1.0 # homeassistant.components.nuimo_controller --only-binary=all nuimo==0.1.0 -# homeassistant.components.dht.sensor +# homeassistant.components.dht # Adafruit-DHT==1.4.0 -# homeassistant.components.sht31.sensor +# homeassistant.components.sht31 Adafruit-GPIO==1.0.3 -# homeassistant.components.sht31.sensor +# homeassistant.components.sht31 Adafruit-SHT31==1.0.2 # homeassistant.components.bbb_gpio @@ -35,16 +35,16 @@ Adafruit-SHT31==1.0.2 # homeassistant.components.homekit HAP-python==2.4.2 -# homeassistant.components.mastodon.notify +# homeassistant.components.mastodon Mastodon.py==1.3.1 -# homeassistant.components.github.sensor +# homeassistant.components.github PyGithub==1.43.5 # homeassistant.components.isy994 PyISY==1.1.1 -# homeassistant.components.mvglive.sensor +# homeassistant.components.mvglive PyMVGLive==1.1.4 # homeassistant.components.arduino @@ -57,13 +57,13 @@ PyNaCl==1.3.0 # homeassistant.auth.mfa_modules.totp PyQRCode==1.2.1 -# homeassistant.components.rmvtransport.sensor +# homeassistant.components.rmvtransport PyRMVtransport==0.1.3 -# homeassistant.components.switchbot.switch +# homeassistant.components.switchbot # PySwitchbot==0.5 -# homeassistant.components.transport_nsw.sensor +# homeassistant.components.transport_nsw PyTransportNSW==0.1.1 # homeassistant.components.xiaomi_aqara @@ -75,40 +75,40 @@ PyXiaomiGateway==0.12.2 # homeassistant.components.remember_the_milk RtmAPI==0.7.0 -# homeassistant.components.travisci.sensor +# homeassistant.components.travisci TravisPy==0.3.5 -# homeassistant.components.twitter.notify +# homeassistant.components.twitter TwitterAPI==2.5.9 -# homeassistant.components.tof.sensor +# homeassistant.components.tof # VL53L1X2==0.1.5 -# homeassistant.components.waze_travel_time.sensor +# homeassistant.components.waze_travel_time WazeRouteCalculator==0.9 -# homeassistant.components.yessssms.notify +# homeassistant.components.yessssms YesssSMS==0.2.3 # homeassistant.components.abode abodepy==0.15.0 -# homeassistant.components.frontier_silicon.media_player +# homeassistant.components.frontier_silicon afsapi==0.0.4 # homeassistant.components.ambient_station -aioambient==0.2.0 +aioambient==0.1.3 # homeassistant.components.asuswrt aioasuswrt==1.1.21 -# homeassistant.components.automatic.device_tracker +# homeassistant.components.automatic aioautomatic==0.6.5 # homeassistant.components.aws aiobotocore==0.10.2 -# homeassistant.components.dnsip.sensor +# homeassistant.components.dnsip aiodns==1.1.1 # homeassistant.components.esphome @@ -117,11 +117,11 @@ aioesphomeapi==1.7.0 # homeassistant.components.freebox aiofreepybox==0.0.8 -# homeassistant.components.yi.camera +# homeassistant.components.yi aioftp==0.12.0 -# homeassistant.components.harmony.remote -aioharmony==0.1.11 +# homeassistant.components.harmony +aioharmony==0.1.8 # homeassistant.components.emulated_hue # homeassistant.components.http @@ -130,85 +130,85 @@ aiohttp_cors==0.7.0 # homeassistant.components.hue aiohue==1.9.1 -# homeassistant.components.imap.sensor +# homeassistant.components.imap aioimaplib==0.7.15 # homeassistant.components.lifx aiolifx==0.6.7 -# homeassistant.components.lifx.light +# homeassistant.components.lifx aiolifx_effects==0.2.1 -# homeassistant.components.hunterdouglas_powerview.scene +# homeassistant.components.hunterdouglas_powerview aiopvapi==1.6.14 # homeassistant.components.unifi aiounifi==4 -# homeassistant.components.aladdin_connect.cover +# homeassistant.components.aladdin_connect aladdin_connect==0.3 # homeassistant.components.alarmdecoder alarmdecoder==1.13.2 -# homeassistant.components.alpha_vantage.sensor +# homeassistant.components.alpha_vantage alpha_vantage==2.1.0 # homeassistant.components.amcrest amcrest==1.3.0 -# homeassistant.components.androidtv.media_player +# homeassistant.components.androidtv androidtv==0.0.14 -# homeassistant.components.anel_pwrctrl.switch +# homeassistant.components.anel_pwrctrl anel_pwrctrl-homeassistant==0.0.1.dev2 -# homeassistant.components.anthemav.media_player +# homeassistant.components.anthemav anthemav==1.1.10 # homeassistant.components.apcupsd apcaccess==0.0.13 -# homeassistant.components.apns.notify +# homeassistant.components.apns apns2==0.3.0 # homeassistant.components.aqualogic aqualogic==1.0 -# homeassistant.components.ampio.air_quality +# homeassistant.components.ampio asmog==0.0.6 # homeassistant.components.asterisk_mbox asterisk_mbox==0.5.0 +# homeassistant.components.dlna_dmr # homeassistant.components.upnp -# homeassistant.components.dlna_dmr.media_player async-upnp-client==0.14.7 # homeassistant.components.stream av==6.1.2 -# homeassistant.components.avion.light +# homeassistant.components.avion # avion==0.10 # homeassistant.components.axis axis==19 -# homeassistant.components.baidu.tts +# homeassistant.components.baidu baidu-aip==1.6.6 -# homeassistant.components.modem_callerid.sensor +# homeassistant.components.modem_callerid basicmodem==0.7 -# homeassistant.components.linux_battery.sensor +# homeassistant.components.linux_battery batinfo==0.4.2 -# homeassistant.components.eddystone_temperature.sensor +# homeassistant.components.eddystone_temperature # beacontools[scan]==1.2.3 -# homeassistant.components.linksys_ap.device_tracker -# homeassistant.components.scrape.sensor -# homeassistant.components.sytadin.sensor +# homeassistant.components.linksys_ap +# homeassistant.components.scrape +# homeassistant.components.sytadin beautifulsoup4==4.7.1 # homeassistant.components.zha @@ -220,135 +220,127 @@ bimmer_connected==0.5.3 # homeassistant.components.blink blinkpy==0.13.1 -# homeassistant.components.blinksticklight.light +# homeassistant.components.blinksticklight blinkstick==1.1.8 -# homeassistant.components.blinkt.light +# homeassistant.components.blinkt # blinkt==0.1.0 -# homeassistant.components.bitcoin.sensor +# homeassistant.components.bitcoin blockchain==1.4.4 -# homeassistant.components.decora.light +# homeassistant.components.decora # bluepy==1.1.4 -# homeassistant.components.bme680.sensor +# homeassistant.components.bme680 # bme680==1.0.5 +# homeassistant.components.amazon_polly +# homeassistant.components.aws_lambda +# homeassistant.components.aws_sns +# homeassistant.components.aws_sqs # homeassistant.components.route53 -# homeassistant.components.amazon_polly.tts boto3==1.9.16 -# homeassistant.components.braviatv.media_player +# homeassistant.components.braviatv braviarc-homeassistant==0.3.7.dev0 -# homeassistant.components.broadlink.sensor -# homeassistant.components.broadlink.switch +# homeassistant.components.broadlink broadlink==0.9.0 -# homeassistant.components.brottsplatskartan.sensor +# homeassistant.components.brottsplatskartan brottsplatskartan==0.0.1 -# homeassistant.components.brunt.cover +# homeassistant.components.brunt brunt==0.1.3 -# homeassistant.components.bluetooth_tracker.device_tracker +# homeassistant.components.bluetooth_tracker bt_proximity==0.1.2 -# homeassistant.components.bt_home_hub_5.device_tracker +# homeassistant.components.bt_home_hub_5 bthomehub5-devicelist==0.1.1 -# homeassistant.components.bt_smarthub.device_tracker +# homeassistant.components.bt_smarthub btsmarthub_devicelist==0.1.3 -# homeassistant.components.buienradar.sensor -# homeassistant.components.buienradar.weather +# homeassistant.components.buienradar buienradar==0.91 -# homeassistant.components.caldav.calendar +# homeassistant.components.caldav caldav==0.5.0 -# homeassistant.components.cisco_mobility_express.device_tracker +# homeassistant.components.cisco_mobility_express ciscomobilityexpress==0.1.5 -# homeassistant.components.ciscospark.notify +# homeassistant.components.ciscospark ciscosparkapi==0.4.2 -# homeassistant.components.cppm_tracker.device_tracker +# homeassistant.components.cppm_tracker clearpasspy==1.0.2 -# homeassistant.components.co2signal.sensor +# homeassistant.components.co2signal co2signal==0.4.2 # homeassistant.components.coinbase coinbase==2.1.0 -# homeassistant.components.coinmarketcap.sensor +# homeassistant.components.coinmarketcap coinmarketcap==5.0.3 # homeassistant.scripts.check_config colorlog==4.0.2 -# homeassistant.components.concord232.alarm_control_panel -# homeassistant.components.concord232.binary_sensor +# homeassistant.components.concord232 concord232==0.15 -# homeassistant.components.eddystone_temperature.sensor -# homeassistant.components.eq3btsmart.climate -# homeassistant.components.xiaomi_miio.device_tracker -# homeassistant.components.xiaomi_miio.fan -# homeassistant.components.xiaomi_miio.light -# homeassistant.components.xiaomi_miio.remote -# homeassistant.components.xiaomi_miio.sensor -# homeassistant.components.xiaomi_miio.switch -# homeassistant.components.xiaomi_miio.vacuum +# homeassistant.components.eddystone_temperature +# homeassistant.components.eq3btsmart +# homeassistant.components.xiaomi_miio construct==2.9.45 # homeassistant.scripts.credstash # credstash==1.15.0 -# homeassistant.components.crimereports.sensor +# homeassistant.components.crimereports crimereports==1.0.1 # homeassistant.components.datadog datadog==0.15.0 -# homeassistant.components.metoffice.sensor -# homeassistant.components.metoffice.weather +# homeassistant.components.metoffice datapoint==0.4.3 -# homeassistant.components.decora.light +# homeassistant.components.decora # decora==0.6 -# homeassistant.components.decora_wifi.light +# homeassistant.components.decora_wifi # decora_wifi==1.3 # homeassistant.components.ihc # homeassistant.components.namecheapdns -# homeassistant.components.ohmconnect.sensor -# homeassistant.components.upc_connect.device_tracker +# homeassistant.components.ohmconnect +# homeassistant.components.upc_connect defusedxml==0.5.0 -# homeassistant.components.deluge.sensor -# homeassistant.components.deluge.switch +# homeassistant.components.deluge deluge-client==1.4.0 -# homeassistant.components.denonavr.media_player +# homeassistant.components.denonavr denonavr==0.7.8 -# homeassistant.components.directv.media_player +# homeassistant.components.directv directpy==0.5 -# homeassistant.components.discogs.sensor +# homeassistant.components.discogs discogs_client==2.2.1 -# homeassistant.components.discord.notify +# homeassistant.components.discord discord.py==0.16.12 # homeassistant.components.updater distro==1.4.0 -# homeassistant.components.digitalloggers.switch +# homeassistant.components.digitalloggers dlipower==0.7.165 # homeassistant.components.doorbird @@ -357,11 +349,10 @@ doorbirdpy==2.0.6 # homeassistant.components.dovado dovado==0.4.1 -# homeassistant.components.dsmr.sensor +# homeassistant.components.dsmr dsmr_parser==0.12 # homeassistant.components.dweet -# homeassistant.components.dweet.sensor dweepy==0.3.0 # homeassistant.components.ebusd @@ -373,10 +364,10 @@ ecoaliface==0.4.0 # homeassistant.components.edp_redy edp_redy==0.0.3 -# homeassistant.components.ee_brightbox.device_tracker +# homeassistant.components.ee_brightbox eebrightbox==0.0.4 -# homeassistant.components.eliqonline.sensor +# homeassistant.components.eliqonline eliqonline==1.2.2 # homeassistant.components.elkm1 @@ -388,19 +379,19 @@ emulated_roku==0.1.8 # homeassistant.components.enocean enocean==0.40 -# homeassistant.components.entur_public_transport.sensor +# homeassistant.components.entur_public_transport enturclient==0.2.0 -# homeassistant.components.envirophat.sensor +# homeassistant.components.envirophat # envirophat==0.0.6 -# homeassistant.components.enphase_envoy.sensor +# homeassistant.components.enphase_envoy envoy_reader==0.3 -# homeassistant.components.season.sensor +# homeassistant.components.season ephem==3.7.6.0 -# homeassistant.components.epson.media_player +# homeassistant.components.epson epson-projector==0.1.3 # homeassistant.components.netgear_lte @@ -410,17 +401,17 @@ eternalegypt==0.0.6 # evdev==0.6.1 # homeassistant.components.evohome -# homeassistant.components.honeywell.climate +# homeassistant.components.honeywell evohomeclient==0.3.2 -# homeassistant.components.dlib_face_detect.image_processing -# homeassistant.components.dlib_face_identify.image_processing +# homeassistant.components.dlib_face_detect +# homeassistant.components.dlib_face_identify # face_recognition==1.2.3 # homeassistant.components.fastdotcom fastdotcom==0.0.3 -# homeassistant.components.fedex.sensor +# homeassistant.components.fedex fedexdeliverymanager==1.0.6 # homeassistant.components.feedreader @@ -429,56 +420,56 @@ feedparser-homeassistant==5.2.2.dev1 # homeassistant.components.fibaro fiblary3==0.1.7 -# homeassistant.components.fints.sensor +# homeassistant.components.fints fints==1.0.1 -# homeassistant.components.fitbit.sensor +# homeassistant.components.fitbit fitbit==0.3.0 -# homeassistant.components.fixer.sensor +# homeassistant.components.fixer fixerio==1.0.0a0 -# homeassistant.components.flux_led.light +# homeassistant.components.flux_led flux_led==0.22 -# homeassistant.components.foobot.sensor +# homeassistant.components.foobot foobot_async==0.3.1 -# homeassistant.components.free_mobile.notify +# homeassistant.components.free_mobile freesms==0.1.2 -# homeassistant.components.fritz.device_tracker -# homeassistant.components.fritzbox_callmonitor.sensor -# homeassistant.components.fritzbox_netmonitor.sensor +# homeassistant.components.fritz +# homeassistant.components.fritzbox_callmonitor +# homeassistant.components.fritzbox_netmonitor # fritzconnection==0.6.5 -# homeassistant.components.fritzdect.switch +# homeassistant.components.fritzdect fritzhome==1.0.4 -# homeassistant.components.google.tts +# homeassistant.components.google gTTS-token==1.1.3 -# homeassistant.components.gearbest.sensor +# homeassistant.components.gearbest gearbest_parser==1.0.7 -# homeassistant.components.geizhals.sensor +# homeassistant.components.geizhals geizhals==0.0.9 -# homeassistant.components.geo_json_events.geo_location -# homeassistant.components.nsw_rural_fire_service_feed.geo_location -# homeassistant.components.usgs_earthquakes_feed.geo_location +# homeassistant.components.geo_json_events +# homeassistant.components.nsw_rural_fire_service_feed +# homeassistant.components.usgs_earthquakes_feed geojson_client==0.3 -# homeassistant.components.geo_rss_events.sensor +# homeassistant.components.geo_rss_events georss_generic_client==0.2 -# homeassistant.components.gitter.sensor +# homeassistant.components.gitter gitterpy==0.1.7 -# homeassistant.components.glances.sensor +# homeassistant.components.glances glances_api==0.2.0 -# homeassistant.components.gntp.notify +# homeassistant.components.gntp gntp==1.0.3 # homeassistant.components.google @@ -490,25 +481,25 @@ google-cloud-pubsub==0.39.1 # homeassistant.components.googlehome googledevices==1.0.2 -# homeassistant.components.google_travel_time.sensor +# homeassistant.components.google_travel_time googlemaps==2.5.1 -# homeassistant.components.gpsd.sensor +# homeassistant.components.gpsd gps3==0.33.3 # homeassistant.components.greeneye_monitor greeneye_monitor==1.0 -# homeassistant.components.greenwave.light +# homeassistant.components.greenwave greenwavereality==0.5.1 -# homeassistant.components.gstreamer.media_player +# homeassistant.components.gstreamer gstreamer-player==1.1.2 # homeassistant.components.ffmpeg ha-ffmpeg==2.0 -# homeassistant.components.philips_js.media_player +# homeassistant.components.philips_js ha-philipsjs==0.0.5 # homeassistant.components.habitica @@ -520,31 +511,31 @@ hangups==0.4.6 # homeassistant.components.cloud hass-nabucasa==0.11 -# homeassistant.components.mqtt.server +# homeassistant.components.mqtt hbmqtt==0.9.4 -# homeassistant.components.jewish_calendar.sensor +# homeassistant.components.jewish_calendar hdate==0.8.7 -# homeassistant.components.heatmiser.climate +# homeassistant.components.heatmiser heatmiserV3==0.9.1 -# homeassistant.components.hikvisioncam.switch +# homeassistant.components.hikvisioncam hikvision==0.4 -# homeassistant.components.hipchat.notify +# homeassistant.components.hipchat hipnotify==1.0.8 -# homeassistant.components.harman_kardon_avr.media_player +# homeassistant.components.harman_kardon_avr hkavr==0.0.5 # homeassistant.components.hlk_sw16 hlk-sw16==0.0.7 -# homeassistant.components.pi_hole.sensor +# homeassistant.components.pi_hole hole==0.3.0 -# homeassistant.components.workday.binary_sensor +# homeassistant.components.workday holidays==0.9.10 # homeassistant.components.frontend @@ -559,7 +550,7 @@ homekit[IP]==0.13.0 # homeassistant.components.homematicip_cloud homematicip==0.10.6 -# homeassistant.components.horizon.media_player +# homeassistant.components.horizon horimote==0.4.1 # homeassistant.components.google @@ -572,22 +563,21 @@ huawei-lte-api==1.1.5 # homeassistant.components.hydrawise hydrawiser==0.1.1 -# homeassistant.components.bh1750.sensor -# homeassistant.components.bme280.sensor -# homeassistant.components.htu21d.sensor +# homeassistant.components.bh1750 +# homeassistant.components.bme280 +# homeassistant.components.htu21d # i2csense==0.0.4 # homeassistant.components.watson_iot ibmiotf==0.3.4 -# homeassistant.components.iglo.light +# homeassistant.components.iglo iglo==1.2.7 # homeassistant.components.ihc ihcsdk==2.3.0 # homeassistant.components.influxdb -# homeassistant.components.influxdb.sensor influxdb==5.2.0 # homeassistant.components.insteon @@ -602,11 +592,10 @@ ipify==1.0.0 # homeassistant.components.verisure jsonpath==0.75 -# homeassistant.components.kodi.media_player -# homeassistant.components.kodi.notify +# homeassistant.components.kodi jsonrpc-async==0.6 -# homeassistant.components.kodi.media_player +# homeassistant.components.kodi jsonrpc-websocket==0.6 # homeassistant.scripts.keyring @@ -615,7 +604,7 @@ keyring==17.1.1 # homeassistant.scripts.keyring keyrings.alt==3.1.1 -# homeassistant.components.kiwi.lock +# homeassistant.components.kiwi kiwiki-client==0.1.1 # homeassistant.components.konnected @@ -627,44 +616,43 @@ lakeside==0.12 # homeassistant.components.dyson libpurecool==0.5.0 -# homeassistant.components.foscam.camera +# homeassistant.components.foscam libpyfoscam==1.0 -# homeassistant.components.mikrotik.device_tracker +# homeassistant.components.mikrotik librouteros==2.2.0 -# homeassistant.components.soundtouch.media_player +# homeassistant.components.soundtouch libsoundtouch==0.7.2 -# homeassistant.components.lifx_legacy.light +# homeassistant.components.lifx_legacy liffylights==0.9.4 -# homeassistant.components.osramlightify.light +# homeassistant.components.osramlightify lightify==1.0.7.2 # homeassistant.components.lightwave lightwave==0.15 -# homeassistant.components.limitlessled.light +# homeassistant.components.limitlessled limitlessled==1.1.3 # homeassistant.components.linode linode-api==4.1.9b1 -# homeassistant.components.liveboxplaytv.media_player +# homeassistant.components.liveboxplaytv liveboxplaytv==2.0.2 # homeassistant.components.lametric -# homeassistant.components.lametric.notify lmnotify==0.0.4 -# homeassistant.components.google_maps.device_tracker +# homeassistant.components.google_maps locationsharinglib==3.0.11 # homeassistant.components.logi_circle logi_circle==0.1.7 -# homeassistant.components.london_underground.sensor +# homeassistant.components.london_underground london-tube-status==0.2 # homeassistant.components.luftdaten @@ -673,13 +661,13 @@ luftdaten==0.3.4 # homeassistant.components.lupusec lupupy==0.0.17 -# homeassistant.components.lw12wifi.light +# homeassistant.components.lw12wifi lw12==0.9.2 -# homeassistant.components.lyft.sensor +# homeassistant.components.lyft lyft_rides==0.2 -# homeassistant.components.magicseaweed.sensor +# homeassistant.components.magicseaweed magicseaweed==1.0.3 # homeassistant.components.matrix @@ -691,23 +679,22 @@ maxcube-api==0.1.0 # homeassistant.components.mythicbeastsdns mbddns==0.1.2 -# homeassistant.components.message_bird.notify +# homeassistant.components.message_bird messagebird==1.2.0 # homeassistant.components.meteo_france meteofrance==0.3.4 -# homeassistant.components.mfi.sensor -# homeassistant.components.mfi.switch +# homeassistant.components.mfi mficlient==0.3.0 -# homeassistant.components.miflora.sensor +# homeassistant.components.miflora miflora==0.4.0 -# homeassistant.components.mill.climate +# homeassistant.components.mill millheater==0.3.4 -# homeassistant.components.mitemp_bt.sensor +# homeassistant.components.mitemp_bt mitemp_bt==0.0.1 # homeassistant.components.mopar @@ -728,95 +715,95 @@ myusps==1.3.2 # homeassistant.components.n26 n26==0.2.7 -# homeassistant.components.nad.media_player +# homeassistant.components.nad nad_receiver==0.0.11 -# homeassistant.components.keenetic_ndms2.device_tracker +# homeassistant.components.keenetic_ndms2 ndms2_client==0.0.6 # homeassistant.components.ness_alarm nessclient==0.9.15 -# homeassistant.components.netdata.sensor +# homeassistant.components.netdata netdata==0.1.2 # homeassistant.components.discovery netdisco==2.6.0 -# homeassistant.components.neurio_energy.sensor +# homeassistant.components.neurio_energy neurio==0.3.1 -# homeassistant.components.niko_home_control.light +# homeassistant.components.niko_home_control niko-home-control==0.1.8 -# homeassistant.components.nilu.air_quality +# homeassistant.components.nilu niluclient==0.1.2 -# homeassistant.components.nederlandse_spoorwegen.sensor +# homeassistant.components.nederlandse_spoorwegen nsapi==2.7.4 -# homeassistant.components.nsw_fuel_station.sensor +# homeassistant.components.nsw_fuel_station nsw-fuel-api-client==1.0.10 # homeassistant.components.nuheat nuheat==0.3.0 -# homeassistant.components.opencv.image_processing -# homeassistant.components.pollen.sensor -# homeassistant.components.tensorflow.image_processing -# homeassistant.components.trend.binary_sensor +# homeassistant.components.opencv +# homeassistant.components.pollen +# homeassistant.components.tensorflow +# homeassistant.components.trend numpy==1.16.2 # homeassistant.components.google oauth2client==4.0.0 -# homeassistant.components.oem.climate +# homeassistant.components.oem oemthermostat==1.1 -# homeassistant.components.onkyo.media_player +# homeassistant.components.onkyo onkyo-eiscp==1.2.4 -# homeassistant.components.onvif.camera +# homeassistant.components.onvif onvif-py3==0.1.3 -# homeassistant.components.openevse.sensor +# homeassistant.components.openevse openevsewifi==0.4 -# homeassistant.components.openhome.media_player +# homeassistant.components.openhome openhomedevice==0.4.2 -# homeassistant.components.opensensemap.air_quality +# homeassistant.components.opensensemap opensensemap-api==0.1.5 -# homeassistant.components.enigma2.media_player +# homeassistant.components.enigma2 openwebifpy==3.1.0 -# homeassistant.components.luci.device_tracker +# homeassistant.components.luci openwrt-luci-rpc==1.0.5 -# homeassistant.components.orvibo.switch +# homeassistant.components.orvibo orvibo==1.1.1 # homeassistant.components.mqtt # homeassistant.components.shiftr paho-mqtt==1.4.0 -# homeassistant.components.panasonic_bluray.media_player +# homeassistant.components.panasonic_bluray panacotta==0.1 -# homeassistant.components.panasonic_viera.media_player +# homeassistant.components.panasonic_viera panasonic_viera==0.3.2 -# homeassistant.components.dunehd.media_player +# homeassistant.components.dunehd pdunehd==1.3 -# homeassistant.components.pencom.switch +# homeassistant.components.pencom pencompy==0.0.3 -# homeassistant.components.aruba.device_tracker -# homeassistant.components.cisco_ios.device_tracker -# homeassistant.components.pandora.media_player -# homeassistant.components.unifi_direct.device_tracker +# homeassistant.components.aruba +# homeassistant.components.cisco_ios +# homeassistant.components.pandora +# homeassistant.components.unifi_direct pexpect==4.6.0 # homeassistant.components.rpi_pfio @@ -825,69 +812,67 @@ pifacecommon==4.2.2 # homeassistant.components.rpi_pfio pifacedigitalio==3.0.5 -# homeassistant.components.piglow.light +# homeassistant.components.piglow piglow==1.2.4 # homeassistant.components.pilight pilight==0.1.1 -# homeassistant.components.proxy.camera -# homeassistant.components.qrcode.image_processing -# homeassistant.components.tensorflow.image_processing +# homeassistant.components.proxy +# homeassistant.components.qrcode +# homeassistant.components.tensorflow pillow==5.4.1 # homeassistant.components.dominos pizzapi==0.0.3 -# homeassistant.components.plex.media_player -# homeassistant.components.plex.sensor +# homeassistant.components.plex plexapi==3.0.6 # homeassistant.components.plum_lightpad plumlightpad==0.0.11 -# homeassistant.components.mhz19.sensor -# homeassistant.components.serial_pm.sensor +# homeassistant.components.mhz19 +# homeassistant.components.serial_pm pmsensor==0.4 -# homeassistant.components.pocketcasts.sensor +# homeassistant.components.pocketcasts pocketcasts==0.1 -# homeassistant.components.postnl.sensor +# homeassistant.components.postnl postnl_api==1.0.2 -# homeassistant.components.reddit.sensor +# homeassistant.components.reddit praw==6.1.1 -# homeassistant.components.islamic_prayer_times.sensor +# homeassistant.components.islamic_prayer_times prayer_times_calculator==0.0.3 -# homeassistant.components.prezzibenzina.sensor +# homeassistant.components.prezzibenzina prezzibenzina-py==1.1.4 -# homeassistant.components.proliphix.climate +# homeassistant.components.proliphix proliphix==0.4.1 # homeassistant.components.prometheus prometheus_client==0.2.0 -# homeassistant.components.tensorflow.image_processing +# homeassistant.components.tensorflow protobuf==3.6.1 -# homeassistant.components.systemmonitor.sensor +# homeassistant.components.systemmonitor psutil==5.6.1 # homeassistant.components.wink pubnubsub-handler==1.0.3 -# homeassistant.components.pushbullet.notify -# homeassistant.components.pushbullet.sensor +# homeassistant.components.pushbullet pushbullet.py==0.11.0 -# homeassistant.components.pushetta.notify +# homeassistant.components.pushetta pushetta==1.0.15 -# homeassistant.components.rpi_gpio_pwm.light +# homeassistant.components.rpi_gpio_pwm pwmled==1.4.1 # homeassistant.components.august @@ -896,16 +881,16 @@ py-august==0.7.0 # homeassistant.components.canary py-canary==0.5.0 -# homeassistant.components.cpuspeed.sensor +# homeassistant.components.cpuspeed py-cpuinfo==5.0.0 # homeassistant.components.melissa py-melissa-climate==2.0.0 -# homeassistant.components.synology.camera +# homeassistant.components.synology py-synology==0.2.0 -# homeassistant.components.seventeentrack.sensor +# homeassistant.components.seventeentrack py17track==2.2.2 # homeassistant.components.hdmi_cec @@ -914,38 +899,38 @@ pyCEC==0.4.13 # homeassistant.components.tplink pyHS100==0.3.4 -# homeassistant.components.met.weather -# homeassistant.components.norway_air.air_quality +# homeassistant.components.met +# homeassistant.components.norway_air pyMetno==0.4.6 # homeassistant.components.rfxtrx pyRFXtrx==0.23 -# homeassistant.components.switchmate.switch +# homeassistant.components.switchmate # pySwitchmate==0.4.5 # homeassistant.components.tibber pyTibber==0.10.1 -# homeassistant.components.dlink.switch +# homeassistant.components.dlink pyW215==0.6.0 # homeassistant.components.w800rf32 pyW800rf32==0.1 -# homeassistant.components.noaa_tides.sensor +# homeassistant.components.noaa_tides # py_noaa==0.3.0 # homeassistant.components.ads pyads==3.0.7 -# homeassistant.components.aftership.sensor +# homeassistant.components.aftership pyaftership==0.1.2 -# homeassistant.components.airvisual.sensor +# homeassistant.components.airvisual pyairvisual==3.0.1 -# homeassistant.components.alarmdotcom.alarm_control_panel +# homeassistant.components.alarmdotcom pyalarmdotcom==0.3.2 # homeassistant.components.arlo @@ -957,14 +942,13 @@ pyatmo==1.9 # homeassistant.components.apple_tv pyatv==0.3.12 -# homeassistant.components.bbox.device_tracker -# homeassistant.components.bbox.sensor +# homeassistant.components.bbox pybbox==0.0.5-alpha -# homeassistant.components.blackbird.media_player +# homeassistant.components.blackbird pyblackbird==0.5 -# homeassistant.components.bluetooth_tracker.device_tracker +# homeassistant.components.bluetooth_tracker # pybluez==0.22 # homeassistant.components.neato @@ -976,25 +960,25 @@ pycarwings2==2.8 # homeassistant.components.cloudflare pycfdns==0.0.1 -# homeassistant.components.channels.media_player +# homeassistant.components.channels pychannels==1.0.0 # homeassistant.components.cast pychromecast==3.2.0 -# homeassistant.components.cmus.media_player +# homeassistant.components.cmus pycmus==0.1.1 # homeassistant.components.comfoconnect pycomfoconnect==0.3 -# homeassistant.components.coolmaster.climate +# homeassistant.components.coolmaster pycoolmasternet==0.0.4 -# homeassistant.components.microsoft.tts +# homeassistant.components.microsoft pycsspeechtts==1.0.2 -# homeassistant.components.cups.sensor +# homeassistant.components.cups # pycups==1.9.73 # homeassistant.components.daikin @@ -1012,46 +996,46 @@ pydispatcher==2.0.5 # homeassistant.components.android_ip_webcam pydroid-ipcam==0.8 -# homeassistant.components.duke_energy.sensor +# homeassistant.components.duke_energy pydukeenergy==0.0.6 -# homeassistant.components.ebox.sensor +# homeassistant.components.ebox pyebox==1.1.4 -# homeassistant.components.econet.water_heater +# homeassistant.components.econet pyeconet==0.0.10 -# homeassistant.components.edimax.switch +# homeassistant.components.edimax pyedimax==0.1 # homeassistant.components.eight_sleep pyeight==0.1.1 -# homeassistant.components.emby.media_player +# homeassistant.components.emby pyemby==1.6 # homeassistant.components.envisalink pyenvisalink==3.8 -# homeassistant.components.ephember.climate +# homeassistant.components.ephember pyephember==0.2.0 -# homeassistant.components.everlights.light +# homeassistant.components.everlights pyeverlights==0.1.0 -# homeassistant.components.fido.sensor +# homeassistant.components.fido pyfido==2.1.1 -# homeassistant.components.flexit.climate +# homeassistant.components.flexit pyflexit==0.3 -# homeassistant.components.flic.binary_sensor +# homeassistant.components.flic pyflic-homeassistant==0.4.dev0 -# homeassistant.components.flunearyou.sensor +# homeassistant.components.flunearyou pyflunearyou==1.0.3 -# homeassistant.components.futurenow.light +# homeassistant.components.futurenow pyfnip==0.2 # homeassistant.components.fritzbox @@ -1060,26 +1044,26 @@ pyfritzhome==0.4.0 # homeassistant.components.ifttt pyfttt==0.3 -# homeassistant.components.bluetooth_le_tracker.device_tracker -# homeassistant.components.skybeacon.sensor +# homeassistant.components.bluetooth_le_tracker +# homeassistant.components.skybeacon pygatt[GATTTOOL]==3.2.0 -# homeassistant.components.gogogate2.cover +# homeassistant.components.gogogate2 pygogogate2==0.1.1 -# homeassistant.components.gtfs.sensor +# homeassistant.components.gtfs pygtfs==0.1.5 -# homeassistant.components.gtt.sensor +# homeassistant.components.gtt pygtt==1.1.2 -# homeassistant.components.version.sensor +# homeassistant.components.version pyhaversion==2.0.3 # homeassistant.components.heos pyheos==0.3.0 -# homeassistant.components.hikvision.binary_sensor +# homeassistant.components.hikvision pyhik==0.2.2 # homeassistant.components.hive @@ -1091,56 +1075,55 @@ pyhomematic==0.1.58 # homeassistant.components.homeworks pyhomeworks==0.0.6 -# homeassistant.components.hydroquebec.sensor +# homeassistant.components.hydroquebec pyhydroquebec==2.2.2 -# homeassistant.components.ialarm.alarm_control_panel +# homeassistant.components.ialarm pyialarm==0.3 -# homeassistant.components.icloud.device_tracker +# homeassistant.components.icloud pyicloud==0.9.1 -# homeassistant.components.ipma.weather +# homeassistant.components.ipma pyipma==1.2.1 -# homeassistant.components.irish_rail_transport.sensor +# homeassistant.components.irish_rail_transport pyirishrail==0.0.2 -# homeassistant.components.iss.binary_sensor +# homeassistant.components.iss pyiss==1.0.1 -# homeassistant.components.itach.remote +# homeassistant.components.itach pyitachip2ir==0.0.7 # homeassistant.components.kira pykira==0.1.1 -# homeassistant.components.kwb.sensor +# homeassistant.components.kwb pykwb==0.0.8 -# homeassistant.components.lacrosse.sensor +# homeassistant.components.lacrosse pylacrosse==0.3.1 -# homeassistant.components.lastfm.sensor +# homeassistant.components.lastfm pylast==3.1.0 -# homeassistant.components.launch_library.sensor +# homeassistant.components.launch_library pylaunches==0.2.0 -# homeassistant.components.lg_netcast.media_player +# homeassistant.components.lg_netcast pylgnetcast-homeassistant==0.2.0.dev0 -# homeassistant.components.webostv.media_player -# homeassistant.components.webostv.notify +# homeassistant.components.webostv pylgtv==0.1.9 -# homeassistant.components.linky.sensor +# homeassistant.components.linky pylinky==0.3.3 # homeassistant.components.litejet pylitejet==0.1 -# homeassistant.components.loopenergy.sensor +# homeassistant.components.loopenergy pyloopenergy==0.1.2 # homeassistant.components.lutron_caseta @@ -1149,13 +1132,13 @@ pylutron-caseta==0.5.0 # homeassistant.components.lutron pylutron==0.2.0 -# homeassistant.components.mailgun.notify +# homeassistant.components.mailgun pymailgunner==1.4 -# homeassistant.components.mediaroom.media_player +# homeassistant.components.mediaroom pymediaroom==0.6.4 -# homeassistant.components.xiaomi_tv.media_player +# homeassistant.components.xiaomi_tv pymitv==1.4.3 # homeassistant.components.mochad @@ -1164,44 +1147,43 @@ pymochad==0.2.0 # homeassistant.components.modbus pymodbus==1.5.2 -# homeassistant.components.monoprice.media_player +# homeassistant.components.monoprice pymonoprice==0.3 -# homeassistant.components.yamaha_musiccast.media_player +# homeassistant.components.yamaha_musiccast pymusiccast==0.1.6 -# homeassistant.components.myq.cover +# homeassistant.components.myq pymyq==1.1.0 # homeassistant.components.mysensors pymysensors==0.18.0 -# homeassistant.components.nanoleaf.light +# homeassistant.components.nanoleaf pynanoleaf==0.0.5 -# homeassistant.components.nello.lock +# homeassistant.components.nello pynello==2.0.2 -# homeassistant.components.netgear.device_tracker +# homeassistant.components.netgear pynetgear==0.5.2 -# homeassistant.components.netio.switch +# homeassistant.components.netio pynetio==0.1.9.1 -# homeassistant.components.nuki.lock +# homeassistant.components.nuki pynuki==1.3.2 -# homeassistant.components.nut.sensor +# homeassistant.components.nut pynut2==2.1.2 -# homeassistant.components.nx584.alarm_control_panel -# homeassistant.components.nx584.binary_sensor +# homeassistant.components.nx584 pynx584==0.4 # homeassistant.components.openuv pyopenuv==1.0.9 -# homeassistant.components.opple.light +# homeassistant.components.opple pyoppleio==1.0.5 # homeassistant.components.iota @@ -1212,26 +1194,25 @@ pyotgw==0.4b3 # homeassistant.auth.mfa_modules.notify # homeassistant.auth.mfa_modules.totp -# homeassistant.components.otp.sensor +# homeassistant.components.otp pyotp==2.2.6 # homeassistant.components.owlet pyowlet==1.0.2 -# homeassistant.components.openweathermap.sensor -# homeassistant.components.openweathermap.weather +# homeassistant.components.openweathermap pyowm==2.10.0 # homeassistant.components.lcn pypck==0.5.9 -# homeassistant.components.pjlink.media_player +# homeassistant.components.pjlink pypjlink2==1.2.0 # homeassistant.components.point pypoint==1.1.1 -# homeassistant.components.pollen.sensor +# homeassistant.components.pollen pypollencom==2.2.3 # homeassistant.components.ps4 @@ -1240,40 +1221,40 @@ pyps4-homeassistant==0.5.2 # homeassistant.components.qwikswitch pyqwikswitch==0.93 -# homeassistant.components.nmbs.sensor +# homeassistant.components.nmbs pyrail==0.0.3 # homeassistant.components.rainbird pyrainbird==0.1.6 -# homeassistant.components.recswitch.switch +# homeassistant.components.recswitch pyrecswitch==1.0.2 -# homeassistant.components.ruter.sensor +# homeassistant.components.ruter pyruter==1.1.0 # homeassistant.components.sabnzbd pysabnzbd==1.1.0 -# homeassistant.components.sony_projector.switch +# homeassistant.components.sony_projector pysdcp==1 -# homeassistant.components.sensibo.climate +# homeassistant.components.sensibo pysensibo==1.0.3 -# homeassistant.components.serial.sensor +# homeassistant.components.serial pyserial-asyncio==0.4 -# homeassistant.components.acer_projector.switch +# homeassistant.components.acer_projector pyserial==3.1.1 -# homeassistant.components.sesame.lock +# homeassistant.components.sesame pysesame==0.1.0 # homeassistant.components.goalfeed pysher==1.0.1 -# homeassistant.components.sma.sensor +# homeassistant.components.sma pysma==0.3.1 # homeassistant.components.smartthings @@ -1282,9 +1263,7 @@ pysmartapp==0.3.2 # homeassistant.components.smartthings pysmartthings==0.6.7 -# homeassistant.components.snmp.device_tracker -# homeassistant.components.snmp.sensor -# homeassistant.components.snmp.switch +# homeassistant.components.snmp pysnmp==4.4.8 # homeassistant.components.sonos @@ -1293,29 +1272,28 @@ pysonos==0.0.8 # homeassistant.components.spc pyspcwebgw==0.4.0 -# homeassistant.components.stride.notify +# homeassistant.components.stride pystride==0.1.7 -# homeassistant.components.syncthru.sensor +# homeassistant.components.syncthru pysyncthru==0.3.1 -# homeassistant.components.tautulli.sensor +# homeassistant.components.tautulli pytautulli==0.5.0 -# homeassistant.components.liveboxplaytv.media_player +# homeassistant.components.liveboxplaytv pyteleloisirs==3.4 -# homeassistant.components.tfiac.climate +# homeassistant.components.tfiac pytfiac==0.3 -# homeassistant.components.thinkingcleaner.sensor -# homeassistant.components.thinkingcleaner.switch +# homeassistant.components.thinkingcleaner pythinkingcleaner==0.0.3 -# homeassistant.components.blockchain.sensor +# homeassistant.components.blockchain python-blockchain-api==0.0.2 -# homeassistant.components.clementine.media_player +# homeassistant.components.clementine python-clementine-remote==1.0.1 # homeassistant.components.digital_ocean @@ -1324,30 +1302,28 @@ python-digitalocean==1.13.2 # homeassistant.components.ecobee python-ecobee-api==0.0.18 -# homeassistant.components.eq3btsmart.climate +# homeassistant.components.eq3btsmart # python-eq3bt==0.1.9 -# homeassistant.components.etherscan.sensor +# homeassistant.components.etherscan python-etherscan-api==0.0.3 -# homeassistant.components.familyhub.camera +# homeassistant.components.familyhub python-family-hub-local==0.0.2 -# homeassistant.components.darksky.sensor -# homeassistant.components.darksky.weather +# homeassistant.components.darksky python-forecastio==1.4.0 # homeassistant.components.gc100 python-gc100==1.0.3a -# homeassistant.components.gitlab_ci.sensor +# homeassistant.components.gitlab_ci python-gitlab==1.6.0 -# homeassistant.components.hp_ilo.sensor +# homeassistant.components.hp_ilo python-hpilo==3.9 # homeassistant.components.joaoapps_join -# homeassistant.components.joaoapps_join.notify python-join-api==0.0.4 # homeassistant.components.juicenet @@ -1356,47 +1332,40 @@ python-juicenet==0.0.5 # homeassistant.components.lirc # python-lirc==1.2.3 -# homeassistant.components.xiaomi_miio.device_tracker -# homeassistant.components.xiaomi_miio.fan -# homeassistant.components.xiaomi_miio.light -# homeassistant.components.xiaomi_miio.remote -# homeassistant.components.xiaomi_miio.sensor -# homeassistant.components.xiaomi_miio.switch -# homeassistant.components.xiaomi_miio.vacuum +# homeassistant.components.xiaomi_miio python-miio==0.4.5 -# homeassistant.components.mpd.media_player +# homeassistant.components.mpd python-mpd2==1.0.0 -# homeassistant.components.mystrom.light -# homeassistant.components.mystrom.switch +# homeassistant.components.mystrom python-mystrom==0.5.0 # homeassistant.components.nest python-nest==4.1.0 -# homeassistant.components.nmap_tracker.device_tracker +# homeassistant.components.nmap_tracker python-nmap==0.6.1 -# homeassistant.components.pushover.notify +# homeassistant.components.pushover python-pushover==0.3 -# homeassistant.components.qbittorrent.sensor +# homeassistant.components.qbittorrent python-qbittorrent==0.3.1 -# homeassistant.components.ripple.sensor +# homeassistant.components.ripple python-ripple-api==0.0.3 # homeassistant.components.roku python-roku==3.1.5 -# homeassistant.components.sochain.sensor +# homeassistant.components.sochain python-sochain-api==0.0.2 -# homeassistant.components.songpal.media_player +# homeassistant.components.songpal python-songpal==0.0.9.1 -# homeassistant.components.synologydsm.sensor +# homeassistant.components.synologydsm python-synology==0.2.0 # homeassistant.components.tado @@ -1405,55 +1374,55 @@ python-tado==0.2.9 # homeassistant.components.telegram_bot python-telegram-bot==11.1.0 -# homeassistant.components.twitch.sensor +# homeassistant.components.twitch python-twitch-client==0.6.0 # homeassistant.components.velbus python-velbus==2.0.22 -# homeassistant.components.vlc.media_player +# homeassistant.components.vlc python-vlc==1.1.2 -# homeassistant.components.whois.sensor +# homeassistant.components.whois python-whois==0.7.1 # homeassistant.components.wink python-wink==1.10.3 -# homeassistant.components.awair.sensor +# homeassistant.components.awair python_awair==0.0.3 -# homeassistant.components.swiss_public_transport.sensor +# homeassistant.components.swiss_public_transport python_opendata_transport==0.1.4 # homeassistant.components.egardia pythonegardia==1.0.39 -# homeassistant.components.tile.device_tracker +# homeassistant.components.tile pytile==2.0.6 -# homeassistant.components.touchline.climate +# homeassistant.components.touchline pytouchline==0.7 -# homeassistant.components.traccar.device_tracker +# homeassistant.components.traccar pytraccar==0.5.0 -# homeassistant.components.trackr.device_tracker +# homeassistant.components.trackr pytrackr==0.0.5 # homeassistant.components.tradfri pytradfri[async]==6.0.1 -# homeassistant.components.trafikverket_weatherstation.sensor +# homeassistant.components.trafikverket_weatherstation pytrafikverket==0.1.5.9 -# homeassistant.components.ubee.device_tracker +# homeassistant.components.ubee pyubee==0.2 -# homeassistant.components.unifi.device_tracker +# homeassistant.components.unifi pyunifi==2.16 -# homeassistant.components.uptimerobot.binary_sensor +# homeassistant.components.uptimerobot pyuptimerobot==0.0.5 # homeassistant.components.keyboard @@ -1462,40 +1431,40 @@ pyuptimerobot==0.0.5 # homeassistant.components.vera pyvera==0.2.45 -# homeassistant.components.vesync.switch +# homeassistant.components.vesync pyvesync_v2==0.9.6 -# homeassistant.components.vizio.media_player +# homeassistant.components.vizio pyvizio==0.0.4 # homeassistant.components.velux pyvlx==0.2.10 -# homeassistant.components.html5.notify -pywebpush==1.9.2 +# homeassistant.components.html5 +pywebpush==1.6.0 # homeassistant.components.wemo pywemo==0.4.34 -# homeassistant.components.xeoma.camera +# homeassistant.components.xeoma pyxeoma==1.4.1 # homeassistant.components.zabbix pyzabbix==0.7.4 -# homeassistant.components.qrcode.image_processing +# homeassistant.components.qrcode pyzbar==0.1.7 -# homeassistant.components.qnap.sensor +# homeassistant.components.qnap qnapstats==0.2.7 -# homeassistant.components.quantum_gateway.device_tracker +# homeassistant.components.quantum_gateway quantum-gateway==0.0.5 # homeassistant.components.rachio rachiopy==0.1.3 -# homeassistant.components.radiotherm.climate +# homeassistant.components.radiotherm radiotherm==2.0.0 # homeassistant.components.raincloud @@ -1504,10 +1473,10 @@ raincloudy==0.0.5 # homeassistant.components.raspihats # raspihats==2.2.3 -# homeassistant.components.raspyrfm.switch +# homeassistant.components.raspyrfm raspyrfm-client==1.2.8 -# homeassistant.components.recollect_waste.sensor +# homeassistant.components.recollect_waste recollect-waste==1.0.1 # homeassistant.components.rainmachine @@ -1525,62 +1494,61 @@ rflink==0.0.37 # homeassistant.components.ring ring_doorbell==0.2.3 -# homeassistant.components.ritassist.device_tracker +# homeassistant.components.ritassist ritassist==0.9.2 -# homeassistant.components.rejseplanen.sensor +# homeassistant.components.rejseplanen rjpl==0.3.5 -# homeassistant.components.rocketchat.notify +# homeassistant.components.rocketchat rocketchat-API==0.6.1 -# homeassistant.components.roomba.vacuum +# homeassistant.components.roomba roombapy==1.3.1 -# homeassistant.components.rova.sensor +# homeassistant.components.rova rova==0.1.0 -# homeassistant.components.rpi_rf.switch +# homeassistant.components.rpi_rf # rpi-rf==0.9.7 -# homeassistant.components.russound_rnet.media_player +# homeassistant.components.russound_rnet russound==0.1.9 -# homeassistant.components.russound_rio.media_player +# homeassistant.components.russound_rio russound_rio==0.1.4 -# homeassistant.components.yamaha.media_player +# homeassistant.components.yamaha rxv==0.6.0 -# homeassistant.components.samsungtv.media_player +# homeassistant.components.samsungtv samsungctl[websocket]==0.7.1 # homeassistant.components.satel_integra satel_integra==0.3.2 -# homeassistant.components.deutsche_bahn.sensor +# homeassistant.components.deutsche_bahn schiene==0.23 # homeassistant.components.scsgate scsgate==0.1.0 -# homeassistant.components.sendgrid.notify +# homeassistant.components.sendgrid sendgrid==5.6.0 -# homeassistant.components.sensehat.light -# homeassistant.components.sensehat.sensor +# homeassistant.components.sensehat sense-hat==2.2.0 # homeassistant.components.sense sense_energy==0.7.0 -# homeassistant.components.aquostv.media_player +# homeassistant.components.aquostv sharp_aquos_rc==0.3.2 -# homeassistant.components.shodan.sensor +# homeassistant.components.shodan shodan==1.11.1 -# homeassistant.components.simplepush.notify +# homeassistant.components.simplepush simplepush==1.1.4 # homeassistant.components.simplisafe @@ -1592,39 +1560,39 @@ sisyphus-control==2.1 # homeassistant.components.skybell skybellpy==0.3.0 -# homeassistant.components.slack.notify +# homeassistant.components.slack slacker==0.12.0 # homeassistant.components.sleepiq sleepyq==0.6 -# homeassistant.components.xmpp.notify +# homeassistant.components.xmpp slixmpp==1.4.2 # homeassistant.components.smappee smappy==0.2.16 +# homeassistant.components.bh1750 +# homeassistant.components.bme280 +# homeassistant.components.bme680 +# homeassistant.components.envirophat +# homeassistant.components.htu21d # homeassistant.components.raspihats -# homeassistant.components.bh1750.sensor -# homeassistant.components.bme280.sensor -# homeassistant.components.bme680.sensor -# homeassistant.components.envirophat.sensor -# homeassistant.components.htu21d.sensor # smbus-cffi==0.5.1 # homeassistant.components.smhi smhi-pkg==1.0.10 -# homeassistant.components.snapcast.media_player +# homeassistant.components.snapcast snapcast==2.0.9 -# homeassistant.components.socialblade.sensor +# homeassistant.components.socialblade socialbladeclient==0.2 -# homeassistant.components.solaredge.sensor +# homeassistant.components.solaredge solaredge==0.0.2 -# homeassistant.components.honeywell.climate +# homeassistant.components.honeywell somecomfort==0.5.2 # homeassistant.components.speedtestdotnet @@ -1633,55 +1601,55 @@ speedtest-cli==2.1.1 # homeassistant.components.spider spiderpy==1.3.1 -# homeassistant.components.spotcrime.sensor +# homeassistant.components.spotcrime spotcrime==1.0.3 -# homeassistant.components.spotify.media_player +# homeassistant.components.spotify spotipy-homeassistant==2.4.4.dev1 # homeassistant.components.recorder -# homeassistant.components.sql.sensor +# homeassistant.components.sql sqlalchemy==1.3.0 -# homeassistant.components.srp_energy.sensor +# homeassistant.components.srp_energy srpenergy==1.0.6 -# homeassistant.components.starlingbank.sensor +# homeassistant.components.starlingbank starlingbank==3.1 # homeassistant.components.statsd statsd==3.2.1 -# homeassistant.components.steam_online.sensor +# homeassistant.components.steam_online steamodd==4.21 -# homeassistant.components.solaredge.sensor -# homeassistant.components.thermoworks_smoke.sensor -# homeassistant.components.traccar.device_tracker +# homeassistant.components.solaredge +# homeassistant.components.thermoworks_smoke +# homeassistant.components.traccar stringcase==1.2.0 # homeassistant.components.ecovacs sucks==0.9.3 -# homeassistant.components.onvif.camera +# homeassistant.components.onvif suds-passworddigest-homeassistant==0.1.2a0.dev0 -# homeassistant.components.onvif.camera +# homeassistant.components.onvif suds-py3==1.3.3.0 -# homeassistant.components.swiss_hydrological_data.sensor +# homeassistant.components.swiss_hydrological_data swisshydrodata==0.0.3 -# homeassistant.components.synology_srm.device_tracker +# homeassistant.components.synology_srm synology-srm==0.0.6 # homeassistant.components.tahoma tahoma-api==0.0.14 -# homeassistant.components.tank_utility.sensor +# homeassistant.components.tank_utility tank_utility==1.4.0 -# homeassistant.components.tapsaff.binary_sensor +# homeassistant.components.tapsaff tapsaff==0.2.0 # homeassistant.components.tellstick @@ -1693,37 +1661,37 @@ tellcore-py==1.1.2 # homeassistant.components.tellduslive tellduslive==0.10.10 -# homeassistant.components.lg_soundbar.media_player +# homeassistant.components.lg_soundbar temescal==0.1 -# homeassistant.components.temper.sensor +# homeassistant.components.temper temperusb==1.5.3 # homeassistant.components.tesla teslajsonpy==0.0.25 -# homeassistant.components.thermoworks_smoke.sensor +# homeassistant.components.thermoworks_smoke thermoworks_smoke==0.1.8 # homeassistant.components.thingspeak thingspeak==0.4.1 -# homeassistant.components.tikteck.light +# homeassistant.components.tikteck tikteck==0.4 -# homeassistant.components.todoist.calendar +# homeassistant.components.todoist todoist-python==7.0.17 # homeassistant.components.toon toonapilib==3.2.2 -# homeassistant.components.totalconnect.alarm_control_panel +# homeassistant.components.totalconnect total_connect_client==0.25 # homeassistant.components.tplink_lte tp-connected==0.0.4 -# homeassistant.components.tplink.device_tracker +# homeassistant.components.tplink tplink==0.2.1 # homeassistant.components.transmission @@ -1735,25 +1703,25 @@ tuyapy==0.1.3 # homeassistant.components.twilio twilio==6.19.1 -# homeassistant.components.uber.sensor +# homeassistant.components.uber uber_rides==0.6.0 # homeassistant.components.upcloud upcloud-api==0.4.3 -# homeassistant.components.ups.sensor +# homeassistant.components.ups upsmychoice==1.0.6 -# homeassistant.components.uscis.sensor +# homeassistant.components.uscis uscisstatus==0.1.1 -# homeassistant.components.uvc.camera +# homeassistant.components.uvc uvcclient==0.11.0 -# homeassistant.components.venstar.climate +# homeassistant.components.venstar venstarcolortouch==0.6 -# homeassistant.components.volkszaehler.sensor +# homeassistant.components.volkszaehler volkszaehler==0.1.2 # homeassistant.components.volvooncall @@ -1762,19 +1730,18 @@ volvooncall==0.8.7 # homeassistant.components.verisure vsure==1.5.2 -# homeassistant.components.vasttrafik.sensor +# homeassistant.components.vasttrafik vtjp==0.1.14 # homeassistant.components.vultr vultr==0.1.2 +# homeassistant.components.panasonic_viera +# homeassistant.components.samsungtv # homeassistant.components.wake_on_lan -# homeassistant.components.panasonic_viera.media_player -# homeassistant.components.samsungtv.media_player -# homeassistant.components.wake_on_lan.switch wakeonlan==1.1.6 -# homeassistant.components.waqi.sensor +# homeassistant.components.waqi waqiasync==1.0.0 # homeassistant.components.folder_watcher @@ -1783,13 +1750,13 @@ watchdog==0.8.3 # homeassistant.components.waterfurnace waterfurnace==1.1.0 -# homeassistant.components.cisco_webex_teams.notify +# homeassistant.components.cisco_webex_teams webexteamssdk==1.1.1 -# homeassistant.components.gpmdp.media_player +# homeassistant.components.gpmdp websocket-client==0.54.0 -# homeassistant.components.webostv.media_player +# homeassistant.components.webostv websockets==6.0 # homeassistant.components.wirelesstag @@ -1801,42 +1768,41 @@ wunderpy2==0.1.6 # homeassistant.components.zigbee xbee-helper==0.0.7 -# homeassistant.components.xbox_live.sensor +# homeassistant.components.xbox_live xboxapi==0.1.1 -# homeassistant.components.xfinity.device_tracker +# homeassistant.components.xfinity xfinity-gateway==0.0.4 # homeassistant.components.knx xknx==0.10.0 -# homeassistant.components.bluesound.media_player -# homeassistant.components.startca.sensor -# homeassistant.components.ted5000.sensor -# homeassistant.components.yr.sensor -# homeassistant.components.zestimate.sensor +# homeassistant.components.bluesound +# homeassistant.components.startca +# homeassistant.components.ted5000 +# homeassistant.components.yr +# homeassistant.components.zestimate xmltodict==0.11.0 # homeassistant.components.xs1 xs1-api-client==2.3.5 -# homeassistant.components.yweather.sensor -# homeassistant.components.yweather.weather +# homeassistant.components.yweather yahooweather==0.10 -# homeassistant.components.yale_smart_alarm.alarm_control_panel +# homeassistant.components.yale_smart_alarm yalesmartalarmclient==0.1.6 # homeassistant.components.yeelight yeelight==0.4.4 -# homeassistant.components.yeelightsunflower.light +# homeassistant.components.yeelightsunflower yeelightsunflower==0.0.10 # homeassistant.components.media_extractor youtube_dl==2019.03.18 -# homeassistant.components.zengge.light +# homeassistant.components.zengge zengge==0.2 # homeassistant.components.zeroconf @@ -1845,10 +1811,10 @@ zeroconf==0.21.3 # homeassistant.components.zha zha-quirks==0.0.7 -# homeassistant.components.zhong_hong.climate +# homeassistant.components.zhong_hong zhong_hong_hvac==1.0.9 -# homeassistant.components.ziggo_mediabox_xl.media_player +# homeassistant.components.ziggo_mediabox_xl ziggo-mediabox-xl==1.1.0 # homeassistant.components.zha diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 73fbae3aadb..8b26b7f4b93 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -26,19 +26,19 @@ HAP-python==2.4.2 # homeassistant.components.owntracks PyNaCl==1.3.0 -# homeassistant.components.rmvtransport.sensor +# homeassistant.components.rmvtransport PyRMVtransport==0.1.3 -# homeassistant.components.transport_nsw.sensor +# homeassistant.components.transport_nsw PyTransportNSW==0.1.1 -# homeassistant.components.yessssms.notify +# homeassistant.components.yessssms YesssSMS==0.2.3 # homeassistant.components.ambient_station -aioambient==0.2.0 +aioambient==0.1.3 -# homeassistant.components.automatic.device_tracker +# homeassistant.components.automatic aioautomatic==0.6.5 # homeassistant.components.aws @@ -54,7 +54,7 @@ aiohue==1.9.1 # homeassistant.components.unifi aiounifi==4 -# homeassistant.components.apns.notify +# homeassistant.components.apns apns2==0.3.0 # homeassistant.components.stream @@ -66,49 +66,49 @@ axis==19 # homeassistant.components.zha bellows-homeassistant==0.7.2 -# homeassistant.components.caldav.calendar +# homeassistant.components.caldav caldav==0.5.0 -# homeassistant.components.coinmarketcap.sensor +# homeassistant.components.coinmarketcap coinmarketcap==5.0.3 # homeassistant.components.ihc # homeassistant.components.namecheapdns -# homeassistant.components.ohmconnect.sensor -# homeassistant.components.upc_connect.device_tracker +# homeassistant.components.ohmconnect +# homeassistant.components.upc_connect defusedxml==0.5.0 -# homeassistant.components.dsmr.sensor +# homeassistant.components.dsmr dsmr_parser==0.12 -# homeassistant.components.ee_brightbox.device_tracker +# homeassistant.components.ee_brightbox eebrightbox==0.0.4 # homeassistant.components.emulated_roku emulated_roku==0.1.8 -# homeassistant.components.season.sensor +# homeassistant.components.season ephem==3.7.6.0 # homeassistant.components.evohome -# homeassistant.components.honeywell.climate +# homeassistant.components.honeywell evohomeclient==0.3.2 # homeassistant.components.feedreader feedparser-homeassistant==5.2.2.dev1 -# homeassistant.components.foobot.sensor +# homeassistant.components.foobot foobot_async==0.3.1 -# homeassistant.components.google.tts +# homeassistant.components.google gTTS-token==1.1.3 -# homeassistant.components.geo_json_events.geo_location -# homeassistant.components.nsw_rural_fire_service_feed.geo_location -# homeassistant.components.usgs_earthquakes_feed.geo_location +# homeassistant.components.geo_json_events +# homeassistant.components.nsw_rural_fire_service_feed +# homeassistant.components.usgs_earthquakes_feed geojson_client==0.3 -# homeassistant.components.geo_rss_events.sensor +# homeassistant.components.geo_rss_events georss_generic_client==0.2 # homeassistant.components.ffmpeg @@ -120,13 +120,13 @@ hangups==0.4.6 # homeassistant.components.cloud hass-nabucasa==0.11 -# homeassistant.components.mqtt.server +# homeassistant.components.mqtt hbmqtt==0.9.4 -# homeassistant.components.jewish_calendar.sensor +# homeassistant.components.jewish_calendar hdate==0.8.7 -# homeassistant.components.workday.binary_sensor +# homeassistant.components.workday holidays==0.9.10 # homeassistant.components.frontend @@ -139,7 +139,6 @@ homekit[IP]==0.13.0 homematicip==0.10.6 # homeassistant.components.influxdb -# homeassistant.components.influxdb.sensor influxdb==5.2.0 # homeassistant.components.verisure @@ -148,7 +147,7 @@ jsonpath==0.75 # homeassistant.components.dyson libpurecool==0.5.0 -# homeassistant.components.soundtouch.media_player +# homeassistant.components.soundtouch libsoundtouch==0.7.2 # homeassistant.components.luftdaten @@ -157,38 +156,36 @@ luftdaten==0.3.4 # homeassistant.components.mythicbeastsdns mbddns==0.1.2 -# homeassistant.components.mfi.sensor -# homeassistant.components.mfi.switch +# homeassistant.components.mfi mficlient==0.3.0 -# homeassistant.components.opencv.image_processing -# homeassistant.components.pollen.sensor -# homeassistant.components.tensorflow.image_processing -# homeassistant.components.trend.binary_sensor +# homeassistant.components.opencv +# homeassistant.components.pollen +# homeassistant.components.tensorflow +# homeassistant.components.trend numpy==1.16.2 # homeassistant.components.mqtt # homeassistant.components.shiftr paho-mqtt==1.4.0 -# homeassistant.components.aruba.device_tracker -# homeassistant.components.cisco_ios.device_tracker -# homeassistant.components.pandora.media_player -# homeassistant.components.unifi_direct.device_tracker +# homeassistant.components.aruba +# homeassistant.components.cisco_ios +# homeassistant.components.pandora +# homeassistant.components.unifi_direct pexpect==4.6.0 # homeassistant.components.pilight pilight==0.1.1 -# homeassistant.components.mhz19.sensor -# homeassistant.components.serial_pm.sensor +# homeassistant.components.mhz19 +# homeassistant.components.serial_pm pmsensor==0.4 # homeassistant.components.prometheus prometheus_client==0.2.0 -# homeassistant.components.pushbullet.notify -# homeassistant.components.pushbullet.sensor +# homeassistant.components.pushbullet pushbullet.py==0.11.0 # homeassistant.components.canary @@ -197,7 +194,7 @@ py-canary==0.5.0 # homeassistant.components.tplink pyHS100==0.3.4 -# homeassistant.components.blackbird.media_player +# homeassistant.components.blackbird pyblackbird==0.5 # homeassistant.components.deconz @@ -215,11 +212,10 @@ pyhomematic==0.1.58 # homeassistant.components.litejet pylitejet==0.1 -# homeassistant.components.monoprice.media_player +# homeassistant.components.monoprice pymonoprice==0.3 -# homeassistant.components.nx584.alarm_control_panel -# homeassistant.components.nx584.binary_sensor +# homeassistant.components.nx584 pynx584==0.4 # homeassistant.components.openuv @@ -227,7 +223,7 @@ pyopenuv==1.0.9 # homeassistant.auth.mfa_modules.notify # homeassistant.auth.mfa_modules.totp -# homeassistant.components.otp.sensor +# homeassistant.components.otp pyotp==2.2.6 # homeassistant.components.ps4 @@ -248,24 +244,23 @@ pysonos==0.0.8 # homeassistant.components.spc pyspcwebgw==0.4.0 -# homeassistant.components.darksky.sensor -# homeassistant.components.darksky.weather +# homeassistant.components.darksky python-forecastio==1.4.0 # homeassistant.components.nest python-nest==4.1.0 -# homeassistant.components.awair.sensor +# homeassistant.components.awair python_awair==0.0.3 # homeassistant.components.tradfri pytradfri[async]==6.0.1 -# homeassistant.components.unifi.device_tracker +# homeassistant.components.unifi pyunifi==2.16 -# homeassistant.components.html5.notify -pywebpush==1.9.2 +# homeassistant.components.html5 +pywebpush==1.6.0 # homeassistant.components.rainmachine regenmaschine==1.4.0 @@ -279,7 +274,7 @@ rflink==0.0.37 # homeassistant.components.ring ring_doorbell==0.2.3 -# homeassistant.components.yamaha.media_player +# homeassistant.components.yamaha rxv==0.6.0 # homeassistant.components.simplisafe @@ -291,14 +286,14 @@ sleepyq==0.6 # homeassistant.components.smhi smhi-pkg==1.0.10 -# homeassistant.components.honeywell.climate +# homeassistant.components.honeywell somecomfort==0.5.2 # homeassistant.components.recorder -# homeassistant.components.sql.sensor +# homeassistant.components.sql sqlalchemy==1.3.0 -# homeassistant.components.srp_energy.sensor +# homeassistant.components.srp_energy srpenergy==1.0.6 # homeassistant.components.statsd @@ -307,7 +302,7 @@ statsd==3.2.1 # homeassistant.components.toon toonapilib==3.2.2 -# homeassistant.components.uvc.camera +# homeassistant.components.uvc uvcclient==0.11.0 # homeassistant.components.verisure @@ -316,10 +311,9 @@ vsure==1.5.2 # homeassistant.components.vultr vultr==0.1.2 +# homeassistant.components.panasonic_viera +# homeassistant.components.samsungtv # homeassistant.components.wake_on_lan -# homeassistant.components.panasonic_viera.media_player -# homeassistant.components.samsungtv.media_player -# homeassistant.components.wake_on_lan.switch wakeonlan==1.1.6 # homeassistant.components.zha diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 33a7b4fd16f..8f6172c2323 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -7,6 +7,8 @@ import pkgutil import re import sys +from script.manifest.requirements import gather_requirements_from_manifests + COMMENT_REQUIREMENTS = ( 'Adafruit-DHT', 'Adafruit_BBIO', @@ -213,36 +215,8 @@ def gather_modules(): errors = [] - for package in sorted( - explore_module('homeassistant.components', True) + - explore_module('homeassistant.scripts', True) + - explore_module('homeassistant.auth', True)): - try: - module = importlib.import_module(package) - except ImportError as err: - for pattern in IGNORE_PACKAGES: - if fnmatch.fnmatch(package, pattern): - break - else: - print("{}: {}".format(package.replace('.', '/') + '.py', err)) - errors.append(package) - continue - - if not getattr(module, 'REQUIREMENTS', None): - continue - - for req in module.REQUIREMENTS: - if req in IGNORE_REQ: - continue - if '://' in req and 'pyharmony' not in req: - errors.append( - "{}[Only pypi dependencies are allowed: {}]".format( - package, req)) - if req.partition('==')[1] == '' and req not in IGNORE_PIN: - errors.append( - "{}[Please pin requirement {}, see {}]".format( - package, req, URL_PIN)) - reqs.setdefault(req, []).append(package) + gather_requirements_from_manifests(process_requirements, errors, reqs) + gather_requirements_from_modules(errors, reqs) for key in reqs: reqs[key] = sorted(reqs[key], @@ -257,12 +231,47 @@ def gather_modules(): return reqs +def gather_requirements_from_modules(errors, reqs): + """Collect the requirements from the modules directly.""" + for package in sorted( + explore_module('homeassistant.scripts', True) + + explore_module('homeassistant.auth', True)): + try: + module = importlib.import_module(package) + except ImportError as err: + for pattern in IGNORE_PACKAGES: + if fnmatch.fnmatch(package, pattern): + break + else: + print("{}: {}".format(package.replace('.', '/') + '.py', err)) + errors.append(package) + continue + + if getattr(module, 'REQUIREMENTS', None): + process_requirements(errors, module.REQUIREMENTS, package, reqs) + + +def process_requirements(errors, module_requirements, package, reqs): + """Process all of the requirements.""" + for req in module_requirements: + if req in IGNORE_REQ: + continue + if '://' in req: + errors.append( + "{}[Only pypi dependencies are allowed: {}]".format( + package, req)) + if req.partition('==')[1] == '' and req not in IGNORE_PIN: + errors.append( + "{}[Please pin requirement {}, see {}]".format( + package, req, URL_PIN)) + reqs.setdefault(req, []).append(package) + + def generate_requirements_list(reqs): """Generate a pip file based on requirements.""" output = [] for pkg, requirements in sorted(reqs.items(), key=lambda item: item[0]): - for req in sorted(requirements, - key=lambda name: (len(name.split('.')), name)): + for req in sorted(requirements): output.append('\n# {}'.format(req)) if comment_requirement(pkg): diff --git a/script/manifest/requirements.py b/script/manifest/requirements.py new file mode 100644 index 00000000000..5a370510484 --- /dev/null +++ b/script/manifest/requirements.py @@ -0,0 +1,22 @@ +"""Helpers to gather requirements from manifests.""" +from .manifest_helper import iter_manifests + + +def gather_requirements_from_manifests(process_requirements, errors, reqs): + """Gather all of the requirements from manifests.""" + for manifest in iter_manifests(): + assert manifest['domain'] + + if manifest.get('requirements') is None: + errors.append( + 'The manifest for component {} is invalid. Please run' + 'script/manifest/validate.py'.format(manifest['domain']) + ) + continue + + process_requirements( + errors, + manifest['requirements'], + 'homeassistant.components.{}'.format(manifest['domain']), + reqs + ) From 8b77298908cd67d9814894abb0de7939731d9cea Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Thu, 4 Apr 2019 21:57:34 -0700 Subject: [PATCH 102/167] More fallout from #22737 and b130c433c94873c65701074a237d2af86a63a0fe --- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements_all.txt b/requirements_all.txt index 7d154cd2ed7..5720f84436d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1441,7 +1441,7 @@ pyvizio==0.0.4 pyvlx==0.2.10 # homeassistant.components.html5 -pywebpush==1.6.0 +pywebpush==1.9.2 # homeassistant.components.wemo pywemo==0.4.34 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8b26b7f4b93..402f1f63ce8 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -260,7 +260,7 @@ pytradfri[async]==6.0.1 pyunifi==2.16 # homeassistant.components.html5 -pywebpush==1.6.0 +pywebpush==1.9.2 # homeassistant.components.rainmachine regenmaschine==1.4.0 From 563e4fbfca3b07b2fd77083642a7e145c05be868 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 5 Apr 2019 08:38:10 +0200 Subject: [PATCH 103/167] Add deprecation warning to embedded broker (#22753) --- homeassistant/components/mqtt/__init__.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 81d2dd8ea03..f77cd985a8a 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -179,6 +179,16 @@ MQTT_WILL_BIRTH_SCHEMA = vol.Schema({ vol.Optional(ATTR_RETAIN, default=DEFAULT_RETAIN): cv.boolean, }, required=True) + +def embedded_broker_deprecated(value): + """Warn user that embedded MQTT broker is deprecated.""" + _LOGGER.warning( + "The embedded MQTT broker has been deprecated and will stop working" + "after June 5th, 2019. Use an external broker instead. For" + "instructions, see https://www.home-assistant.io/docs/mqtt/broker") + return value + + CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Optional(CONF_CLIENT_ID): cv.string, @@ -198,7 +208,8 @@ CONFIG_SCHEMA = vol.Schema({ vol.Any('auto', '1.0', '1.1', '1.2'), vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTOCOL): vol.All(cv.string, vol.In([PROTOCOL_31, PROTOCOL_311])), - vol.Optional(CONF_EMBEDDED): HBMQTT_CONFIG_SCHEMA, + vol.Optional(CONF_EMBEDDED): + vol.All(HBMQTT_CONFIG_SCHEMA, embedded_broker_deprecated), vol.Optional(CONF_WILL_MESSAGE): MQTT_WILL_BIRTH_SCHEMA, vol.Optional(CONF_BIRTH_MESSAGE): MQTT_WILL_BIRTH_SCHEMA, vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY): cv.boolean, From a75b151dfa97388b75ab6a3347901df15f6142ea Mon Sep 17 00:00:00 2001 From: Jason Hunter Date: Fri, 5 Apr 2019 02:39:19 -0400 Subject: [PATCH 104/167] fix flaky test (#22748) --- tests/components/stream/test_recorder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/stream/test_recorder.py b/tests/components/stream/test_recorder.py index 4e227e463b4..8e4a69e28ff 100644 --- a/tests/components/stream/test_recorder.py +++ b/tests/components/stream/test_recorder.py @@ -41,7 +41,7 @@ async def test_record_stream(hass, hass_client): stream.stop() - assert segments == 3 + assert segments > 1 async def test_recorder_timeout(hass, hass_client): From 8c657d4254a1f64f2b8efebef429d0e685fe0f26 Mon Sep 17 00:00:00 2001 From: Jason Hunter Date: Fri, 5 Apr 2019 02:40:22 -0400 Subject: [PATCH 105/167] use the input stream codec as the template for the output streams (#22747) --- homeassistant/components/stream/worker.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/homeassistant/components/stream/worker.py b/homeassistant/components/stream/worker.py index 3ca8ac079e3..0292fd30596 100644 --- a/homeassistant/components/stream/worker.py +++ b/homeassistant/components/stream/worker.py @@ -29,11 +29,7 @@ def create_stream_buffer(stream_output, video_stream, audio_frame): segment = io.BytesIO() output = av.open( segment, mode='w', format=stream_output.format) - vstream = output.add_stream( - stream_output.video_codec, video_stream.rate) - # Fix format - vstream.codec_context.format = \ - video_stream.codec_context.format + vstream = output.add_stream(template=video_stream) # Check if audio is requested astream = None if stream_output.audio_codec: From 82a1c0d0e8fecaea8eadd41bbe561758303ff835 Mon Sep 17 00:00:00 2001 From: Chris Helming Date: Fri, 5 Apr 2019 02:40:47 -0400 Subject: [PATCH 106/167] Update Foscam stream for newer models (#22744) * Update Foscam to support stream source * Removing spaces and tabs * Changing to Python3-style string formatting * Adding '_media_port' to hopefully cover other models * changing logic for success and return none * Update Foscam stream for newer models * change if to or --- homeassistant/components/foscam/camera.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/foscam/camera.py b/homeassistant/components/foscam/camera.py index 9852f617d01..308e6e86ec8 100644 --- a/homeassistant/components/foscam/camera.py +++ b/homeassistant/components/foscam/camera.py @@ -53,10 +53,11 @@ class FoscamCam(Camera): self._foscam_session = FoscamCamera( ip_address, port, self._username, self._password, verbose=False) - self._media_port = None + self._rtsp_port = None result, response = self._foscam_session.get_port_info() if result == 0: - self._media_port = response['mediaPort'] + self._rtsp_port = response.get('rtspPort') or \ + response.get('mediaPort') def camera_image(self): """Return a still image response from the camera.""" @@ -71,19 +72,19 @@ class FoscamCam(Camera): @property def supported_features(self): """Return supported features.""" - if self._media_port: + if self._rtsp_port: return SUPPORT_STREAM return 0 @property def stream_source(self): """Return the stream source.""" - if self._media_port: + if self._rtsp_port: return 'rtsp://{}:{}@{}:{}/videoMain'.format( self._username, self._password, self._foscam_session.host, - self._media_port) + self._rtsp_port) return None @property From 71e120ce971373afd466c9027b11e55b2c3b6f73 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 5 Apr 2019 08:41:13 +0200 Subject: [PATCH 107/167] Fix chunk streaming (#22730) * Fix chunk streaming * Cleanup a print * Better error handling * Fix import order --- homeassistant/components/hassio/http.py | 1 - homeassistant/components/hassio/ingress.py | 22 ++++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/hassio/http.py b/homeassistant/components/hassio/http.py index 7284004d72f..a798d312c25 100644 --- a/homeassistant/components/hassio/http.py +++ b/homeassistant/components/hassio/http.py @@ -85,7 +85,6 @@ class HassIOView(HomeAssistantView): "http://{}/{}".format(self._host, path), data=data, headers=headers, timeout=read_timeout ) - print(client.headers) # Simple request if int(client.headers.get(CONTENT_LENGTH, 0)) < 4194000: diff --git a/homeassistant/components/hassio/ingress.py b/homeassistant/components/hassio/ingress.py index 49e949c5789..27a7f05ec14 100644 --- a/homeassistant/components/hassio/ingress.py +++ b/homeassistant/components/hassio/ingress.py @@ -1,21 +1,23 @@ """Hass.io Add-on ingress service.""" import asyncio -from ipaddress import ip_address +import logging import os +from ipaddress import ip_address from typing import Dict, Union import aiohttp -from aiohttp import web -from aiohttp import hdrs +from aiohttp import hdrs, web from aiohttp.web_exceptions import HTTPBadGateway from multidict import CIMultiDict -from homeassistant.core import callback from homeassistant.components.http import HomeAssistantView +from homeassistant.core import callback from homeassistant.helpers.typing import HomeAssistantType from .const import X_HASSIO, X_INGRESS_PATH +_LOGGER = logging.getLogger(__name__) + @callback def async_setup_ingress(hass: HomeAssistantType, host: str): @@ -54,8 +56,8 @@ class HassIOIngress(HomeAssistantView): # Request return await self._handle_request(request, token, path) - except aiohttp.ClientError: - pass + except aiohttp.ClientError as err: + _LOGGER.debug("Ingress error with %s / %s: %s", token, path, err) raise HTTPBadGateway() from None @@ -126,11 +128,11 @@ class HassIOIngress(HomeAssistantView): try: await response.prepare(request) - async for data in result.content: + async for data in result.content.iter_chunked(4096): await response.write(data) - except (aiohttp.ClientError, aiohttp.ClientPayloadError): - pass + except (aiohttp.ClientError, aiohttp.ClientPayloadError) as err: + _LOGGER.debug("Stream error %s / %s: %s", token, path, err) return response @@ -183,7 +185,7 @@ def _response_header(response: aiohttp.ClientResponse) -> Dict[str, str]: for name, value in response.headers.items(): if name in (hdrs.TRANSFER_ENCODING, hdrs.CONTENT_LENGTH, - hdrs.CONTENT_TYPE): + hdrs.CONTENT_TYPE, hdrs.CONTENT_ENCODING): continue headers[name] = value From 876b5fbe966ec88edd6d091b6c660102aecc5876 Mon Sep 17 00:00:00 2001 From: Fredrik Erlandsson Date: Fri, 5 Apr 2019 08:48:41 +0200 Subject: [PATCH 108/167] fixes configuration flow #22706 (#22754) --- homeassistant/components/daikin/config_flow.py | 7 +++++-- tests/components/daikin/test_config_flow.py | 7 ++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/daikin/config_flow.py b/homeassistant/components/daikin/config_flow.py index 590b5a02738..3c5daac4653 100644 --- a/homeassistant/components/daikin/config_flow.py +++ b/homeassistant/components/daikin/config_flow.py @@ -38,9 +38,12 @@ class FlowHandler(config_entries.ConfigFlow): """Create device.""" from pydaikin.appliance import Appliance try: + device = Appliance( + host, + self.hass.helpers.aiohttp_client.async_get_clientsession(), + ) with async_timeout.timeout(10): - device = await self.hass.async_add_executor_job( - Appliance, host) + await device.init() except asyncio.TimeoutError: return self.async_abort(reason='device_timeout') except Exception: # pylint: disable=broad-except diff --git a/tests/components/daikin/test_config_flow.py b/tests/components/daikin/test_config_flow.py index f6b2f0b1d41..fa288f6c2ef 100644 --- a/tests/components/daikin/test_config_flow.py +++ b/tests/components/daikin/test_config_flow.py @@ -24,9 +24,14 @@ def init_config_flow(hass): @pytest.fixture def mock_daikin(): - """Mock tellduslive.""" + """Mock pydaikin.""" + async def mock_daikin_init(): + """Mock the init function in pydaikin.""" + pass + with MockDependency('pydaikin.appliance') as mock_daikin_: mock_daikin_.Appliance().values.get.return_value = 'AABBCCDDEEFF' + mock_daikin_.Appliance().init = mock_daikin_init yield mock_daikin_ From 4b877dd96ff17aaa884d56726cd399b435dcc57c Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 5 Apr 2019 13:29:43 +0200 Subject: [PATCH 109/167] Cleanup cookie handling (#22757) --- homeassistant/components/hassio/ingress.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/hassio/ingress.py b/homeassistant/components/hassio/ingress.py index 27a7f05ec14..91224c6f54d 100644 --- a/homeassistant/components/hassio/ingress.py +++ b/homeassistant/components/hassio/ingress.py @@ -106,7 +106,7 @@ class HassIOIngress(HomeAssistantView): async with self._websession.request( request.method, url, headers=source_header, - params=request.query, data=data, cookies=request.cookies + params=request.query, data=data ) as result: headers = _response_header(result) @@ -145,7 +145,8 @@ def _init_header( # filter flags for name, value in request.headers.items(): - if name in (hdrs.CONTENT_LENGTH, hdrs.CONTENT_TYPE): + if name in (hdrs.CONTENT_LENGTH, hdrs.CONTENT_TYPE, + hdrs.CONTENT_ENCODING): continue headers[name] = value From 5e7fdb479b7ccb8381a538b5a47980819f9c8725 Mon Sep 17 00:00:00 2001 From: zewelor Date: Fri, 5 Apr 2019 13:32:46 +0200 Subject: [PATCH 110/167] Fix yeelight recorder warning (#22756) --- homeassistant/components/yeelight/__init__.py | 34 +--------------- homeassistant/components/yeelight/light.py | 39 +++++++++++++++++-- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/homeassistant/components/yeelight/__init__.py b/homeassistant/components/yeelight/__init__.py index fb218a67698..99382bb1da9 100644 --- a/homeassistant/components/yeelight/__init__.py +++ b/homeassistant/components/yeelight/__init__.py @@ -111,37 +111,6 @@ UPDATE_REQUEST_PROPERTIES = [ ] -def _transitions_config_parser(transitions): - """Parse transitions config into initialized objects.""" - import yeelight - - transition_objects = [] - for transition_config in transitions: - transition, params = list(transition_config.items())[0] - transition_objects.append(getattr(yeelight, transition)(*params)) - - return transition_objects - - -def _parse_custom_effects(effects_config): - import yeelight - - effects = {} - for config in effects_config: - params = config[CONF_FLOW_PARAMS] - action = yeelight.Flow.actions[params[ATTR_ACTION]] - transitions = _transitions_config_parser( - params[ATTR_TRANSITIONS]) - - effects[config[CONF_NAME]] = { - ATTR_COUNT: params[ATTR_COUNT], - ATTR_ACTION: action, - ATTR_TRANSITIONS: transitions - } - - return effects - - def setup(hass, config): """Set up the Yeelight bulbs.""" conf = config.get(DOMAIN, {}) @@ -192,9 +161,8 @@ def _setup_device(hass, hass_config, ipaddr, device_config): platform_config = device_config.copy() platform_config[CONF_HOST] = ipaddr - platform_config[CONF_CUSTOM_EFFECTS] = _parse_custom_effects( + platform_config[CONF_CUSTOM_EFFECTS] = \ hass_config.get(DOMAIN, {}).get(CONF_CUSTOM_EFFECTS, {}) - ) load_platform(hass, LIGHT_DOMAIN, DOMAIN, platform_config, hass_config) load_platform(hass, BINARY_SENSOR_DOMAIN, DOMAIN, platform_config, diff --git a/homeassistant/components/yeelight/light.py b/homeassistant/components/yeelight/light.py index 92b668c6987..912a4f99c92 100644 --- a/homeassistant/components/yeelight/light.py +++ b/homeassistant/components/yeelight/light.py @@ -7,7 +7,7 @@ from homeassistant.helpers.service import extract_entity_ids from homeassistant.util.color import ( color_temperature_mired_to_kelvin as mired_to_kelvin, color_temperature_kelvin_to_mired as kelvin_to_mired) -from homeassistant.const import CONF_HOST, ATTR_ENTITY_ID +from homeassistant.const import CONF_HOST, ATTR_ENTITY_ID, CONF_NAME from homeassistant.core import callback from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_HS_COLOR, ATTR_TRANSITION, ATTR_COLOR_TEMP, @@ -19,8 +19,8 @@ from homeassistant.components.yeelight import ( CONF_TRANSITION, DATA_YEELIGHT, CONF_MODE_MUSIC, CONF_SAVE_ON_CHANGE, CONF_CUSTOM_EFFECTS, DATA_UPDATED, YEELIGHT_SERVICE_SCHEMA, DOMAIN, ATTR_TRANSITIONS, - YEELIGHT_FLOW_TRANSITION_SCHEMA, _transitions_config_parser, - ACTION_RECOVER) + YEELIGHT_FLOW_TRANSITION_SCHEMA, ACTION_RECOVER, CONF_FLOW_PARAMS, + ATTR_ACTION, ATTR_COUNT) DEPENDENCIES = ['yeelight'] @@ -81,6 +81,37 @@ YEELIGHT_EFFECT_LIST = [ EFFECT_STOP] +def _transitions_config_parser(transitions): + """Parse transitions config into initialized objects.""" + import yeelight + + transition_objects = [] + for transition_config in transitions: + transition, params = list(transition_config.items())[0] + transition_objects.append(getattr(yeelight, transition)(*params)) + + return transition_objects + + +def _parse_custom_effects(effects_config): + import yeelight + + effects = {} + for config in effects_config: + params = config[CONF_FLOW_PARAMS] + action = yeelight.Flow.actions[params[ATTR_ACTION]] + transitions = _transitions_config_parser( + params[ATTR_TRANSITIONS]) + + effects[config[CONF_NAME]] = { + ATTR_COUNT: params[ATTR_COUNT], + ATTR_ACTION: action, + ATTR_TRANSITIONS: transitions + } + + return effects + + def _cmd(func): """Define a wrapper to catch exceptions from the bulb.""" def _wrap(self, *args, **kwargs): @@ -109,7 +140,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): device = hass.data[DATA_YEELIGHT][discovery_info[CONF_HOST]] _LOGGER.debug("Adding %s", device.name) - custom_effects = discovery_info[CONF_CUSTOM_EFFECTS] + custom_effects = _parse_custom_effects(discovery_info[CONF_CUSTOM_EFFECTS]) lights = [YeelightLight(device, custom_effects=custom_effects)] From 323dc5b78a03d9121393544579a82d1c481783e2 Mon Sep 17 00:00:00 2001 From: carstenschroeder Date: Fri, 5 Apr 2019 17:14:44 +0200 Subject: [PATCH 111/167] Improve exception handling in ADS integration (#22627) * add exception handling * fix hound findings * improve logging * improve logging II * fix try..except to large --- homeassistant/components/ads/__init__.py | 35 ++++++++++++++++-------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/ads/__init__.py b/homeassistant/components/ads/__init__.py index 5ab53e3acd2..92c6ecb3335 100644 --- a/homeassistant/components/ads/__init__.py +++ b/homeassistant/components/ads/__init__.py @@ -160,28 +160,41 @@ class AdsHub: def write_by_name(self, name, value, plc_datatype): """Write a value to the device.""" + import pyads with self._lock: - return self._client.write_by_name(name, value, plc_datatype) + try: + return self._client.write_by_name(name, value, plc_datatype) + except pyads.ADSError as err: + _LOGGER.error("Error writing %s: %s", name, err) def read_by_name(self, name, plc_datatype): """Read a value from the device.""" + import pyads with self._lock: - return self._client.read_by_name(name, plc_datatype) + try: + return self._client.read_by_name(name, plc_datatype) + except pyads.ADSError as err: + _LOGGER.error("Error reading %s: %s", name, err) def add_device_notification(self, name, plc_datatype, callback): """Add a notification to the ADS devices.""" - from pyads import NotificationAttrib - attr = NotificationAttrib(ctypes.sizeof(plc_datatype)) + import pyads + attr = pyads.NotificationAttrib(ctypes.sizeof(plc_datatype)) with self._lock: - hnotify, huser = self._client.add_device_notification( - name, attr, self._device_notification_callback) - hnotify = int(hnotify) - self._notification_items[hnotify] = NotificationItem( - hnotify, huser, name, plc_datatype, callback) + try: + hnotify, huser = self._client.add_device_notification( + name, attr, self._device_notification_callback) + except pyads.ADSError as err: + _LOGGER.error("Error subscribing to %s: %s", name, err) + else: + hnotify = int(hnotify) + self._notification_items[hnotify] = NotificationItem( + hnotify, huser, name, plc_datatype, callback) - _LOGGER.debug( - "Added device notification %d for variable %s", hnotify, name) + _LOGGER.debug( + "Added device notification %d for variable %s", + hnotify, name) def _device_notification_callback(self, notification, name): """Handle device notifications.""" From 879967bed216be6dc4b58cb8b0f1eafa9c89be56 Mon Sep 17 00:00:00 2001 From: Rohan Kapoor Date: Fri, 5 Apr 2019 09:15:35 -0700 Subject: [PATCH 112/167] Correctly load Mopar's config (#22771) --- homeassistant/components/mopar/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/mopar/__init__.py b/homeassistant/components/mopar/__init__.py index d845d585765..4ee9f3219b4 100644 --- a/homeassistant/components/mopar/__init__.py +++ b/homeassistant/components/mopar/__init__.py @@ -53,12 +53,13 @@ def setup(hass, config): """Set up the Mopar component.""" import motorparts + conf = config[DOMAIN] cookie = hass.config.path(COOKIE_FILE) try: session = motorparts.get_session( - config[CONF_USERNAME], - config[CONF_PASSWORD], - config[CONF_PIN], + conf[CONF_USERNAME], + conf[CONF_PASSWORD], + conf[CONF_PIN], cookie_path=cookie ) except motorparts.MoparError: @@ -69,7 +70,7 @@ def setup(hass, config): data.update(now=None) track_time_interval( - hass, data.update, config[CONF_SCAN_INTERVAL] + hass, data.update, conf[CONF_SCAN_INTERVAL] ) def handle_horn(call): From b3e60df82aec2116040a2814cd3c9d09aef320ed Mon Sep 17 00:00:00 2001 From: teliov Date: Fri, 5 Apr 2019 19:11:04 +0200 Subject: [PATCH 113/167] Add google hangouts manual authentication option (#22158) * Added option to use manual authentication for google hangout component See: https://hangups.readthedocs.io/en/latest/user_guide.html#logging-in for manual log in example Bumped up version of hangups to 0.4.9 * Updated components/hangouts/strings.json and generated translation string by running script/translations_develop Reduced verbosity of modifications to components/hangouts/config_flow.py * Added option to use manual authentication for google hangout component See: https://hangups.readthedocs.io/en/latest/user_guide.html#logging-in for manual log in example Bumped up version of hangups to 0.4.9 * Updated components/hangouts/strings.json and generated translation string by running script/translations_develop Reduced verbosity of modifications to components/hangouts/config_flow.py * fixing missing rebase --- .../components/hangouts/.translations/en.json | 1 + homeassistant/components/hangouts/__init__.py | 2 +- .../components/hangouts/config_flow.py | 29 ++++++++++++++----- homeassistant/components/hangouts/const.py | 1 + .../components/hangouts/hangups_utils.py | 17 ++++++++++- .../components/hangouts/strings.json | 3 +- tests/components/hangouts/test_config_flow.py | 14 +++++++++ 7 files changed, 57 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/hangouts/.translations/en.json b/homeassistant/components/hangouts/.translations/en.json index f526bec4f34..31e5f9894f9 100644 --- a/homeassistant/components/hangouts/.translations/en.json +++ b/homeassistant/components/hangouts/.translations/en.json @@ -18,6 +18,7 @@ }, "user": { "data": { + "authorization_code": "Authorization Code (required for manual authentication)", "email": "E-Mail Address", "password": "Password" }, diff --git a/homeassistant/components/hangouts/__init__.py b/homeassistant/components/hangouts/__init__.py index 2d36de8b769..29cdc29e5ad 100644 --- a/homeassistant/components/hangouts/__init__.py +++ b/homeassistant/components/hangouts/__init__.py @@ -19,7 +19,7 @@ from .const import ( MESSAGE_SCHEMA, SERVICE_RECONNECT, SERVICE_SEND_MESSAGE, SERVICE_UPDATE, TARGETS_SCHEMA) -REQUIREMENTS = ['hangups==0.4.6'] +REQUIREMENTS = ['hangups==0.4.9'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/hangouts/config_flow.py b/homeassistant/components/hangouts/config_flow.py index 5eecc24d45e..743c49abfdf 100644 --- a/homeassistant/components/hangouts/config_flow.py +++ b/homeassistant/components/hangouts/config_flow.py @@ -1,11 +1,14 @@ """Config flow to configure Google Hangouts.""" +import functools import voluptuous as vol + from homeassistant import config_entries from homeassistant.const import CONF_EMAIL, CONF_PASSWORD from homeassistant.core import callback -from .const import CONF_2FA, CONF_REFRESH_TOKEN, DOMAIN as HANGOUTS_DOMAIN +from .const import CONF_2FA, CONF_REFRESH_TOKEN, CONF_AUTH_CODE, \ + DOMAIN as HANGOUTS_DOMAIN @callback @@ -41,13 +44,24 @@ class HangoutsFlowHandler(config_entries.ConfigFlow): from .hangups_utils import (HangoutsCredentials, HangoutsRefreshToken, GoogleAuthError, Google2FAError) - self._credentials = HangoutsCredentials(user_input[CONF_EMAIL], - user_input[CONF_PASSWORD]) + user_email = user_input[CONF_EMAIL] + user_password = user_input[CONF_PASSWORD] + user_auth_code = user_input.get(CONF_AUTH_CODE) + manual_login = user_auth_code is not None + + user_pin = None + self._credentials = HangoutsCredentials(user_email, + user_password, + user_pin, + user_auth_code) self._refresh_token = HangoutsRefreshToken(None) try: - await self.hass.async_add_executor_job(get_auth, - self._credentials, - self._refresh_token) + await self.hass.async_add_executor_job( + functools.partial(get_auth, + self._credentials, + self._refresh_token, + manual_login=manual_login) + ) return await self.async_step_final() except GoogleAuthError as err: @@ -63,7 +77,8 @@ class HangoutsFlowHandler(config_entries.ConfigFlow): step_id='user', data_schema=vol.Schema({ vol.Required(CONF_EMAIL): str, - vol.Required(CONF_PASSWORD): str + vol.Required(CONF_PASSWORD): str, + vol.Optional(CONF_AUTH_CODE): str }), errors=errors ) diff --git a/homeassistant/components/hangouts/const.py b/homeassistant/components/hangouts/const.py index 38b238292b3..f664e769b9f 100644 --- a/homeassistant/components/hangouts/const.py +++ b/homeassistant/components/hangouts/const.py @@ -13,6 +13,7 @@ _LOGGER = logging.getLogger('.') DOMAIN = 'hangouts' CONF_2FA = '2fa' +CONF_AUTH_CODE = 'authorization_code' CONF_REFRESH_TOKEN = 'refresh_token' CONF_BOT = 'bot' diff --git a/homeassistant/components/hangouts/hangups_utils.py b/homeassistant/components/hangouts/hangups_utils.py index 9aff7730201..d2556ac15a0 100644 --- a/homeassistant/components/hangouts/hangups_utils.py +++ b/homeassistant/components/hangouts/hangups_utils.py @@ -13,7 +13,7 @@ class HangoutsCredentials(CredentialsPrompt): This implementation gets the user data as params. """ - def __init__(self, email, password, pin=None): + def __init__(self, email, password, pin=None, auth_code=None): """Google account credentials. :param email: Google account email address. @@ -23,6 +23,7 @@ class HangoutsCredentials(CredentialsPrompt): self._email = email self._password = password self._pin = pin + self._auth_code = auth_code def get_email(self): """Return email. @@ -54,6 +55,20 @@ class HangoutsCredentials(CredentialsPrompt): """ self._pin = pin + def get_authorization_code(self): + """Return the oauth authorization code. + + :return: Google oauth code. + """ + return self._auth_code + + def set_authorization_code(self, code): + """Set the google oauth authorization code. + + :param code: Oauth code returned after authentication with google. + """ + self._auth_code = code + class HangoutsRefreshToken(RefreshTokenCache): """Memory-based cache for refresh token.""" diff --git a/homeassistant/components/hangouts/strings.json b/homeassistant/components/hangouts/strings.json index c83a0ae0876..8c155784ebe 100644 --- a/homeassistant/components/hangouts/strings.json +++ b/homeassistant/components/hangouts/strings.json @@ -13,7 +13,8 @@ "user": { "data": { "email": "E-Mail Address", - "password": "Password" + "password": "Password", + "authorization_code": "Authorization Code (required for manual authentication)" }, "title": "Google Hangouts Login" }, diff --git a/tests/components/hangouts/test_config_flow.py b/tests/components/hangouts/test_config_flow.py index af9bb018919..becb981d68d 100644 --- a/tests/components/hangouts/test_config_flow.py +++ b/tests/components/hangouts/test_config_flow.py @@ -19,6 +19,20 @@ async def test_flow_works(hass, aioclient_mock): assert result['title'] == 'test@test.com' +async def test_flow_works_with_authcode(hass, aioclient_mock): + """Test config flow without 2fa.""" + flow = config_flow.HangoutsFlowHandler() + + flow.hass = hass + + with patch('hangups.get_auth'): + result = await flow.async_step_user( + {'email': 'test@test.com', 'password': '1232456', + 'authorization_code': 'c29tZXJhbmRvbXN0cmluZw=='}) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['title'] == 'test@test.com' + + async def test_flow_works_with_2fa(hass, aioclient_mock): """Test config flow with 2fa.""" from homeassistant.components.hangouts.hangups_utils import Google2FAError From 008b641c564d48c0d3a80491d8b5572a12c32b7f Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 5 Apr 2019 19:14:54 +0200 Subject: [PATCH 114/167] Axis - support stream (#22593) * Add support for new stream component --- homeassistant/components/axis/camera.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/homeassistant/components/axis/camera.py b/homeassistant/components/axis/camera.py index ec1d761d3d0..62b694a99bb 100644 --- a/homeassistant/components/axis/camera.py +++ b/homeassistant/components/axis/camera.py @@ -1,5 +1,6 @@ """Support for Axis camera streaming.""" +from homeassistant.components.camera import SUPPORT_STREAM from homeassistant.components.mjpeg.camera import ( CONF_MJPEG_URL, CONF_STILL_IMAGE_URL, MjpegCamera, filter_urllib3_logging) from homeassistant.const import ( @@ -14,6 +15,7 @@ DEPENDENCIES = [AXIS_DOMAIN] AXIS_IMAGE = 'http://{}:{}/axis-cgi/jpg/image.cgi' AXIS_VIDEO = 'http://{}:{}/axis-cgi/mjpg/video.cgi' +AXIS_STREAM = 'rtsp://{}:{}@{}/axis-media/media.amp?videocodec=h264' async def async_setup_entry(hass, config_entry, async_add_entities): @@ -56,6 +58,19 @@ class AxisCamera(MjpegCamera): self.unsub_dispatcher.append(async_dispatcher_connect( self.hass, self.device.event_reachable, self.update_callback)) + @property + def supported_features(self): + """Return supported features.""" + return SUPPORT_STREAM + + @property + def stream_source(self): + """Return the stream source.""" + return AXIS_STREAM.format( + self.device.config_entry.data[CONF_DEVICE][CONF_USERNAME], + self.device.config_entry.data[CONF_DEVICE][CONF_PASSWORD], + self.device.host) + @callback def update_callback(self, no_delay=None): """Update the cameras state.""" From 7a33dc5cec0fe864c0857c570c89cbfbb6502401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Osb=C3=A4ck?= Date: Fri, 5 Apr 2019 21:22:24 +0200 Subject: [PATCH 115/167] update core dependencies due to pywebpush update (#22767) --- homeassistant/package_constraints.txt | 4 ++-- requirements_all.txt | 4 ++-- setup.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 04704a00484..5b0673038bb 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -5,8 +5,8 @@ attrs==18.2.0 bcrypt==3.1.6 certifi>=2018.04.16 jinja2>=2.10 -PyJWT==1.6.4 -cryptography==2.5 +PyJWT==1.7.1 +cryptography==2.6.1 pip>=8.0.3 python-slugify==1.2.6 pytz>=2018.07 diff --git a/requirements_all.txt b/requirements_all.txt index 5720f84436d..64b7b4aa072 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -6,8 +6,8 @@ attrs==18.2.0 bcrypt==3.1.6 certifi>=2018.04.16 jinja2>=2.10 -PyJWT==1.6.4 -cryptography==2.5 +PyJWT==1.7.1 +cryptography==2.6.1 pip>=8.0.3 python-slugify==1.2.6 pytz>=2018.07 diff --git a/setup.py b/setup.py index 8f7e84dd8d8..0245923afb1 100755 --- a/setup.py +++ b/setup.py @@ -39,9 +39,9 @@ REQUIRES = [ 'bcrypt==3.1.6', 'certifi>=2018.04.16', 'jinja2>=2.10', - 'PyJWT==1.6.4', + 'PyJWT==1.7.1', # PyJWT has loose dependency. We want the latest one. - 'cryptography==2.5', + 'cryptography==2.6.1', 'pip>=8.0.3', 'python-slugify==1.2.6', 'pytz>=2018.07', From d1bf4708997483fc15a1f5d32a1b56ac9f5f7e1d Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 5 Apr 2019 22:21:06 +0200 Subject: [PATCH 116/167] deCONZ multiple gateways fixup (#22774) * Initial PR was merged before a proper review was performed * These fixes follow Martins review comments after merge --- homeassistant/components/deconz/__init__.py | 4 +--- tests/components/deconz/test_init.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index ff1ee2bf06e..807f82821fb 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -4,7 +4,6 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.const import ( CONF_API_KEY, CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP) -from homeassistant.core import callback from homeassistant.helpers import config_validation as cv # Loading the config flow file will register the flow @@ -51,7 +50,7 @@ async def async_setup(hass, config): """ if not hass.config_entries.async_entries(DOMAIN) and DOMAIN in config: deconz_config = config[DOMAIN] - hass.async_add_job(hass.config_entries.flow.async_init( + hass.async_create_task(hass.config_entries.flow.async_init( DOMAIN, context={'source': config_entries.SOURCE_IMPORT}, data=deconz_config )) @@ -175,7 +174,6 @@ async def async_unload_entry(hass, config_entry): return await gateway.async_reset() -@callback async def async_populate_options(hass, config_entry): """Populate default options for gateway. diff --git a/tests/components/deconz/test_init.py b/tests/components/deconz/test_init.py index da37f4a9652..b844cf4336e 100644 --- a/tests/components/deconz/test_init.py +++ b/tests/components/deconz/test_init.py @@ -41,7 +41,7 @@ async def test_config_with_host_passed_to_config_entry(hass): } }) is True # Import flow started - assert len(mock_config_flow.mock_calls) == 2 + assert len(mock_config_flow.mock_calls) == 1 async def test_config_without_host_not_passed_to_config_entry(hass): From 144632a81b9b9409afafa6f884904317f59ffc3b Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Fri, 5 Apr 2019 18:22:57 -0400 Subject: [PATCH 117/167] Fix konnected unique_id computation for switches (#22777) --- homeassistant/components/konnected/switch.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/konnected/switch.py b/homeassistant/components/konnected/switch.py index 7384d62900e..3db602215b9 100644 --- a/homeassistant/components/konnected/switch.py +++ b/homeassistant/components/konnected/switch.py @@ -41,9 +41,10 @@ class KonnectedSwitch(ToggleEntity): self._pause = self._data.get(CONF_PAUSE) self._repeat = self._data.get(CONF_REPEAT) self._state = self._boolean_state(self._data.get(ATTR_STATE)) - self._unique_id = '{}-{}'.format(device_id, hash(frozenset( - {self._pin_num, self._momentary, self._pause, self._repeat}))) self._name = self._data.get(CONF_NAME) + self._unique_id = '{}-{}-{}-{}-{}'.format( + device_id, self._pin_num, self._momentary, + self._pause, self._repeat) @property def unique_id(self) -> str: From 8dfbfae270f457d2f45dfc10d3628321e21cf636 Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Fri, 5 Apr 2019 19:06:41 -0400 Subject: [PATCH 118/167] ZHA Light debug logging. (#22776) --- homeassistant/components/zha/light.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index 573936d6ac2..feccbc09663 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -167,6 +167,7 @@ class Light(ZhaEntity, light.Light): duration = transition * 10 if transition else DEFAULT_DURATION brightness = kwargs.get(light.ATTR_BRIGHTNESS) + t_log = {} if (brightness is not None or transition) and \ self._supported_features & light.SUPPORT_BRIGHTNESS: if brightness is not None: @@ -177,7 +178,9 @@ class Light(ZhaEntity, light.Light): level, duration ) + t_log['move_to_level_with_on_off'] = success if not success: + self.debug("turned on: %s", t_log) return self._state = bool(level) if level: @@ -185,7 +188,9 @@ class Light(ZhaEntity, light.Light): if brightness is None or brightness: success = await self._on_off_channel.on() + t_log['on_off'] = success if not success: + self.debug("turned on: %s", t_log) return self._state = True @@ -194,7 +199,9 @@ class Light(ZhaEntity, light.Light): temperature = kwargs[light.ATTR_COLOR_TEMP] success = await self._color_channel.move_to_color_temp( temperature, duration) + t_log['move_to_color_temp'] = success if not success: + self.debug("turned on: %s", t_log) return self._color_temp = temperature @@ -207,10 +214,13 @@ class Light(ZhaEntity, light.Light): int(xy_color[1] * 65535), duration, ) + t_log['move_to_color'] = success if not success: + self.debug("turned on: %s", t_log) return self._hs_color = hs_color + self.debug("turned on: %s", t_log) self.async_schedule_update_ha_state() async def async_turn_off(self, **kwargs): @@ -224,7 +234,7 @@ class Light(ZhaEntity, light.Light): ) else: success = await self._on_off_channel.off() - _LOGGER.debug("%s was turned off: %s", self.entity_id, success) + self.debug("turned off: %s", success) if not success: return self._state = False @@ -243,3 +253,7 @@ class Light(ZhaEntity, light.Light): async def refresh(self, time): """Call async_update at an interval.""" await self.async_update() + + def debug(self, msg, *args): + """Log debug message.""" + _LOGGER.debug('%s: ' + msg, self.entity_id, *args) From 192ed90773c9c605ff3323224d57fb1ae74585da Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Fri, 5 Apr 2019 19:50:20 -0400 Subject: [PATCH 119/167] make the custom polling actually request state (#22778) --- homeassistant/components/zha/light.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index feccbc09663..cebc18e6a3e 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -243,16 +243,20 @@ class Light(ZhaEntity, light.Light): async def async_update(self): """Attempt to retrieve on off state from the light.""" await super().async_update() + await self.async_get_state() + + async def async_get_state(self, from_cache=True): + """Attempt to retrieve on off state from the light.""" if self._on_off_channel: self._state = await self._on_off_channel.get_attribute_value( - 'on_off') + 'on_off', from_cache=from_cache) if self._level_channel: self._brightness = await self._level_channel.get_attribute_value( - 'current_level') + 'current_level', from_cache=from_cache) async def refresh(self, time): - """Call async_update at an interval.""" - await self.async_update() + """Call async_get_state at an interval.""" + await self.async_get_state(from_cache=False) def debug(self, msg, *args): """Log debug message.""" From 2b490e44862ca7daae113fff092202ce9a646823 Mon Sep 17 00:00:00 2001 From: Chris Helming Date: Fri, 5 Apr 2019 23:02:38 -0400 Subject: [PATCH 120/167] Add optional rtsp_port for Foscam (#22786) * add optional rtsp port for config * getting rid of default=None * removing vol.Any --- homeassistant/components/foscam/camera.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/foscam/camera.py b/homeassistant/components/foscam/camera.py index 308e6e86ec8..6ce8f1865fc 100644 --- a/homeassistant/components/foscam/camera.py +++ b/homeassistant/components/foscam/camera.py @@ -14,6 +14,7 @@ _LOGGER = logging.getLogger(__name__) REQUIREMENTS = ['libpyfoscam==1.0'] CONF_IP = 'ip' +CONF_RTSP_PORT = 'rtsp_port' DEFAULT_NAME = 'Foscam Camera' DEFAULT_PORT = 88 @@ -26,6 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_USERNAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Optional(CONF_RTSP_PORT): cv.port }) @@ -53,11 +55,12 @@ class FoscamCam(Camera): self._foscam_session = FoscamCamera( ip_address, port, self._username, self._password, verbose=False) - self._rtsp_port = None - result, response = self._foscam_session.get_port_info() - if result == 0: - self._rtsp_port = response.get('rtspPort') or \ - response.get('mediaPort') + self._rtsp_port = device_info.get(CONF_RTSP_PORT) + if not self._rtsp_port: + result, response = self._foscam_session.get_port_info() + if result == 0: + self._rtsp_port = response.get('rtspPort') or \ + response.get('mediaPort') def camera_image(self): """Return a still image response from the camera.""" From 8b3cf2d493c308d397845b70bc839a91a70bbbef Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sat, 6 Apr 2019 12:09:15 +0200 Subject: [PATCH 121/167] Update homeassistant-pyozw 0.1.4 (#22794) --- homeassistant/components/zwave/__init__.py | 2 +- homeassistant/components/zwave/manifest.json | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index 4abaaa31210..aca36aabd3b 100644 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -37,7 +37,7 @@ from .discovery_schemas import DISCOVERY_SCHEMAS from .util import (check_node_schema, check_value_schema, node_name, check_has_unique_id, is_node_parsed) -REQUIREMENTS = ['pydispatcher==2.0.5', 'homeassistant-pyozw==0.1.3'] +REQUIREMENTS = ['pydispatcher==2.0.5', 'homeassistant-pyozw==0.1.4'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/zwave/manifest.json b/homeassistant/components/zwave/manifest.json index ac7e327f19a..598af58ad17 100644 --- a/homeassistant/components/zwave/manifest.json +++ b/homeassistant/components/zwave/manifest.json @@ -3,7 +3,7 @@ "name": "Z-Wave", "documentation": "https://www.home-assistant.io/components/zwave", "requirements": [ - "homeassistant-pyozw==0.1.3", + "homeassistant-pyozw==0.1.4", "pydispatcher==2.0.5" ], "dependencies": [], diff --git a/requirements_all.txt b/requirements_all.txt index 64b7b4aa072..2effe22f37b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -542,7 +542,7 @@ holidays==0.9.10 home-assistant-frontend==20190331.0 # homeassistant.components.zwave -homeassistant-pyozw==0.1.3 +homeassistant-pyozw==0.1.4 # homeassistant.components.homekit_controller homekit[IP]==0.13.0 From 6351c5c6ab953b7e87c4a9263e514bd3fd796b3c Mon Sep 17 00:00:00 2001 From: panosmz Date: Sat, 6 Apr 2019 16:20:51 +0300 Subject: [PATCH 122/167] Add OASA Telematics greek public transport sensor component (#22196) * add telematics sensor * add missing final newline * code cleanup & add manifest * fixes from review * fix flake8 warning * rerun gen_requirements_all.py script --- .coveragerc | 1 + .../components/oasa_telematics/__init__.py | 1 + .../components/oasa_telematics/manifest.json | 10 + .../components/oasa_telematics/sensor.py | 192 ++++++++++++++++++ requirements_all.txt | 3 + 5 files changed, 207 insertions(+) create mode 100644 homeassistant/components/oasa_telematics/__init__.py create mode 100644 homeassistant/components/oasa_telematics/manifest.json create mode 100644 homeassistant/components/oasa_telematics/sensor.py diff --git a/.coveragerc b/.coveragerc index 957b3402c46..5eac18b8d7e 100644 --- a/.coveragerc +++ b/.coveragerc @@ -398,6 +398,7 @@ omit = homeassistant/components/nzbget/sensor.py homeassistant/components/octoprint/* homeassistant/components/oem/climate.py + homeassistant/components/oasa_telematics/sensor.py homeassistant/components/ohmconnect/sensor.py homeassistant/components/onewire/sensor.py homeassistant/components/onkyo/media_player.py diff --git a/homeassistant/components/oasa_telematics/__init__.py b/homeassistant/components/oasa_telematics/__init__.py new file mode 100644 index 00000000000..3629f31982b --- /dev/null +++ b/homeassistant/components/oasa_telematics/__init__.py @@ -0,0 +1 @@ +"""The OASA Telematics component.""" diff --git a/homeassistant/components/oasa_telematics/manifest.json b/homeassistant/components/oasa_telematics/manifest.json new file mode 100644 index 00000000000..15bf40e63c8 --- /dev/null +++ b/homeassistant/components/oasa_telematics/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "oasa_telematics", + "name": "OASA Telematics", + "documentation": "https://www.home-assistant.io/components/oasa_telematics/", + "requirements": [ + "oasatelematics==0.3" + ], + "dependencies": [], + "codeowners": [] +} \ No newline at end of file diff --git a/homeassistant/components/oasa_telematics/sensor.py b/homeassistant/components/oasa_telematics/sensor.py new file mode 100644 index 00000000000..665f2f83f86 --- /dev/null +++ b/homeassistant/components/oasa_telematics/sensor.py @@ -0,0 +1,192 @@ +"""Support for OASA Telematics from telematics.oasa.gr.""" +import logging +from datetime import timedelta +from operator import itemgetter + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ( + CONF_NAME, ATTR_ATTRIBUTION, DEVICE_CLASS_TIMESTAMP) +from homeassistant.helpers.entity import Entity +from homeassistant.util import dt as dt_util + +REQUIREMENTS = ['oasatelematics==0.3'] +_LOGGER = logging.getLogger(__name__) + +ATTR_STOP_ID = 'stop_id' +ATTR_STOP_NAME = 'stop_name' +ATTR_ROUTE_ID = 'route_id' +ATTR_ROUTE_NAME = 'route_name' +ATTR_NEXT_ARRIVAL = 'next_arrival' +ATTR_SECOND_NEXT_ARRIVAL = 'second_next_arrival' +ATTR_NEXT_DEPARTURE = 'next_departure' + +ATTRIBUTION = "Data retrieved from telematics.oasa.gr" + +CONF_STOP_ID = 'stop_id' +CONF_ROUTE_ID = 'route_id' + +DEFAULT_NAME = 'OASA Telematics' +ICON = 'mdi:bus' + +SCAN_INTERVAL = timedelta(seconds=60) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_STOP_ID): cv.string, + vol.Required(CONF_ROUTE_ID): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string +}) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the OASA Telematics sensor.""" + name = config[CONF_NAME] + stop_id = config[CONF_STOP_ID] + route_id = config.get(CONF_ROUTE_ID) + + data = OASATelematicsData(stop_id, route_id) + + add_entities([OASATelematicsSensor( + data, stop_id, route_id, name)], True) + + +class OASATelematicsSensor(Entity): + """Implementation of the OASA Telematics sensor.""" + + def __init__(self, data, stop_id, route_id, name): + """Initialize the sensor.""" + self.data = data + self._name = name + self._stop_id = stop_id + self._route_id = route_id + self._name_data = self._times = self._state = None + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def device_class(self): + """Return the class of this sensor.""" + return DEVICE_CLASS_TIMESTAMP + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def device_state_attributes(self): + """Return the state attributes.""" + params = {} + if self._times is not None: + next_arrival_data = self._times[0] + if ATTR_NEXT_ARRIVAL in next_arrival_data: + next_arrival = next_arrival_data[ATTR_NEXT_ARRIVAL] + params.update({ + ATTR_NEXT_ARRIVAL: next_arrival.isoformat() + }) + if len(self._times) > 1: + second_next_arrival_time = self._times[1][ATTR_NEXT_ARRIVAL] + if second_next_arrival_time is not None: + second_arrival = second_next_arrival_time + params.update({ + ATTR_SECOND_NEXT_ARRIVAL: second_arrival.isoformat() + }) + params.update({ + ATTR_ROUTE_ID: self._times[0][ATTR_ROUTE_ID], + ATTR_STOP_ID: self._stop_id, + ATTR_ATTRIBUTION: ATTRIBUTION, + }) + params.update({ + ATTR_ROUTE_NAME: self._name_data[ATTR_ROUTE_NAME], + ATTR_STOP_NAME: self._name_data[ATTR_STOP_NAME] + }) + return {k: v for k, v in params.items() if v} + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return ICON + + def update(self): + """Get the latest data from OASA API and update the states.""" + self.data.update() + self._times = self.data.info + self._name_data = self.data.name_data + next_arrival_data = self._times[0] + if ATTR_NEXT_ARRIVAL in next_arrival_data: + self._state = next_arrival_data[ATTR_NEXT_ARRIVAL].isoformat() + + +class OASATelematicsData(): + """The class for handling data retrieval.""" + + def __init__(self, stop_id, route_id): + """Initialize the data object.""" + import oasatelematics + self.stop_id = stop_id + self.route_id = route_id + self.info = self.empty_result() + self.oasa_api = oasatelematics + self.name_data = {ATTR_ROUTE_NAME: self.get_route_name(), + ATTR_STOP_NAME: self.get_stop_name()} + + def empty_result(self): + """Object returned when no arrivals are found.""" + return [{ATTR_ROUTE_ID: self.route_id}] + + def get_route_name(self): + """Get the route name from the API.""" + try: + route = self.oasa_api.getRouteName(self.route_id) + if route: + return route[0].get('route_departure_eng') + except TypeError: + _LOGGER.error("Cannot get route name from OASA API") + return None + + def get_stop_name(self): + """Get the stop name from the API.""" + try: + name_data = self.oasa_api.getStopNameAndXY(self.stop_id) + if name_data: + return name_data[0].get('stop_descr_matrix_eng') + except TypeError: + _LOGGER.error("Cannot get stop name from OASA API") + return None + + def update(self): + """Get the latest arrival data from telematics.oasa.gr API.""" + self.info = [] + + results = self.oasa_api.getStopArrivals(self.stop_id) + + if not results: + self.info = self.empty_result() + return + + # Parse results + results = [r for r in results if r.get('route_code') in self.route_id] + current_time = dt_util.utcnow() + + for result in results: + btime2 = result.get('btime2') + if btime2 is not None: + arrival_min = int(btime2) + timestamp = current_time + timedelta(minutes=arrival_min) + arrival_data = {ATTR_NEXT_ARRIVAL: timestamp, + ATTR_ROUTE_ID: self.route_id} + self.info.append(arrival_data) + + if not self.info: + _LOGGER.debug("No arrivals with given parameters") + self.info = self.empty_result() + return + + # Sort the data by time + sort = sorted(self.info, itemgetter(ATTR_NEXT_ARRIVAL)) + self.info = sort diff --git a/requirements_all.txt b/requirements_all.txt index 2effe22f37b..757994485a0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -754,6 +754,9 @@ nuheat==0.3.0 # homeassistant.components.trend numpy==1.16.2 +# homeassistant.components.oasa_telematics +oasatelematics==0.3 + # homeassistant.components.google oauth2client==4.0.0 From a747eaa3ba0546ec886b4e58646f544689df5707 Mon Sep 17 00:00:00 2001 From: Jeff Irion Date: Sat, 6 Apr 2019 08:18:50 -0700 Subject: [PATCH 123/167] Remove pycryptodome requirement for Android TV (#22552) * Bump androidtv to 0.0.15 * Bump androidtv to 0.0.15 in manifest.json --- .../components/androidtv/manifest.json | 2 +- .../components/androidtv/media_player.py | 24 +++++++++---------- requirements_all.txt | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/androidtv/manifest.json b/homeassistant/components/androidtv/manifest.json index 815a97394cb..841ad299785 100644 --- a/homeassistant/components/androidtv/manifest.json +++ b/homeassistant/components/androidtv/manifest.json @@ -3,7 +3,7 @@ "name": "Androidtv", "documentation": "https://www.home-assistant.io/components/androidtv", "requirements": [ - "androidtv==0.0.14" + "androidtv==0.0.15" ], "dependencies": [], "codeowners": [] diff --git a/homeassistant/components/androidtv/media_player.py b/homeassistant/components/androidtv/media_player.py index a62a7f2a6d9..706ef6f8402 100644 --- a/homeassistant/components/androidtv/media_player.py +++ b/homeassistant/components/androidtv/media_player.py @@ -18,7 +18,7 @@ import homeassistant.helpers.config_validation as cv ANDROIDTV_DOMAIN = 'androidtv' -REQUIREMENTS = ['androidtv==0.0.14'] +REQUIREMENTS = ['androidtv==0.0.15'] _LOGGER = logging.getLogger(__name__) @@ -294,12 +294,12 @@ class ADBDevice(MediaPlayerDevice): @adb_decorator() def media_previous_track(self): """Send previous track command (results in rewind).""" - self.aftv.media_previous() + self.aftv.media_previous_track() @adb_decorator() def media_next_track(self): """Send next track command (results in fast-forward).""" - self.aftv.media_next() + self.aftv.media_next_track() @adb_decorator() def adb_command(self, cmd): @@ -324,11 +324,11 @@ class AndroidTVDevice(ADBDevice): turn_off_command) self._device = None - self._muted = None self._device_properties = self.aftv.device_properties + self._is_volume_muted = None self._unique_id = 'androidtv-{}-{}'.format( name, self._device_properties['serialno']) - self._volume = None + self._volume_level = None @adb_decorator(override_available=True) def update(self): @@ -345,16 +345,16 @@ class AndroidTVDevice(ADBDevice): if not self._available: return - # Get the `state`, `current_app`, and `running_apps`. - state, self._current_app, self._device, self._muted, self._volume = \ - self.aftv.update() + # Get the updated state and attributes. + state, self._current_app, self._device, self._is_volume_muted, \ + self._volume_level = self.aftv.update() self._state = ANDROIDTV_STATES[state] @property def is_volume_muted(self): """Boolean if volume is currently muted.""" - return self._muted + return self._is_volume_muted @property def source(self): @@ -374,7 +374,7 @@ class AndroidTVDevice(ADBDevice): @property def volume_level(self): """Return the volume level.""" - return self._volume + return self._volume_level @adb_decorator() def media_stop(self): @@ -389,12 +389,12 @@ class AndroidTVDevice(ADBDevice): @adb_decorator() def volume_down(self): """Send volume down command.""" - self.aftv.volume_down() + self._volume_level = self.aftv.volume_down(self._volume_level) @adb_decorator() def volume_up(self): """Send volume up command.""" - self.aftv.volume_up() + self._volume_level = self.aftv.volume_up(self._volume_level) class FireTVDevice(ADBDevice): diff --git a/requirements_all.txt b/requirements_all.txt index 757994485a0..4493911e106 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -158,7 +158,7 @@ alpha_vantage==2.1.0 amcrest==1.3.0 # homeassistant.components.androidtv -androidtv==0.0.14 +androidtv==0.0.15 # homeassistant.components.anel_pwrctrl anel_pwrctrl-homeassistant==0.0.1.dev2 From 87cabc933c9481530048033f99d7cfd1cd9a5bb9 Mon Sep 17 00:00:00 2001 From: Andrew Hayworth Date: Sat, 6 Apr 2019 20:55:15 -0500 Subject: [PATCH 124/167] Update version of python_awair to 0.0.4 (#22809) The awair API has changed again, this time substituting 'lat' and 'lon' for 'latitude' and 'longitude'. --- homeassistant/components/awair/manifest.json | 2 +- homeassistant/components/awair/sensor.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/awair/manifest.json b/homeassistant/components/awair/manifest.json index bc63ef06cc2..cba11e8be1c 100644 --- a/homeassistant/components/awair/manifest.json +++ b/homeassistant/components/awair/manifest.json @@ -3,7 +3,7 @@ "name": "Awair", "documentation": "https://www.home-assistant.io/components/awair", "requirements": [ - "python_awair==0.0.3" + "python_awair==0.0.4" ], "dependencies": [], "codeowners": [] diff --git a/homeassistant/components/awair/sensor.py b/homeassistant/components/awair/sensor.py index 5b199538e68..7fdcc673549 100644 --- a/homeassistant/components/awair/sensor.py +++ b/homeassistant/components/awair/sensor.py @@ -15,7 +15,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle, dt -REQUIREMENTS = ['python_awair==0.0.3'] +REQUIREMENTS = ['python_awair==0.0.4'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 4493911e106..d91af2c43cb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1393,7 +1393,7 @@ python-whois==0.7.1 python-wink==1.10.3 # homeassistant.components.awair -python_awair==0.0.3 +python_awair==0.0.4 # homeassistant.components.swiss_public_transport python_opendata_transport==0.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 402f1f63ce8..54b6230ae81 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -251,7 +251,7 @@ python-forecastio==1.4.0 python-nest==4.1.0 # homeassistant.components.awair -python_awair==0.0.3 +python_awair==0.0.4 # homeassistant.components.tradfri pytradfri[async]==6.0.1 From 55619da7228740d9b78ce988a166436271f09868 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 05:31:21 +0200 Subject: [PATCH 125/167] Remove unused group status (#22791) --- homeassistant/components/cast/media_player.py | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index c4019b4686c..4b2972b0c00 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -406,13 +406,10 @@ class CastStatusListener: """Handle the cast removed from a group.""" if self._valid: self._cast_device.multizone_new_media_status(group_uuid, None) - self._cast_device.multizone_new_cast_status(group_uuid, None) def multizone_new_cast_status(self, group_uuid, cast_status): - """Handle reception of a new MediaStatus for a group.""" - if self._valid: - self._cast_device.multizone_new_cast_status( - group_uuid, cast_status) + """Handle reception of a new CastStatus for a group.""" + pass def multizone_new_media_status(self, group_uuid, media_status): """Handle reception of a new MediaStatus for a group.""" @@ -456,8 +453,7 @@ class DynamicGroupCastStatusListener: def new_cast_status(self, cast_status): """Handle reception of a new CastStatus.""" - if self._valid: - self._cast_device.new_dynamic_group_cast_status(cast_status) + pass def new_media_status(self, media_status): """Handle reception of a new MediaStatus.""" @@ -502,10 +498,8 @@ class CastDevice(MediaPlayerDevice): self._dynamic_group_cast_info = None # type: ChromecastInfo self._dynamic_group_cast = None \ # type: Optional[pychromecast.Chromecast] - self.dynamic_group_cast_status = None self.dynamic_group_media_status = None self.dynamic_group_media_status_received = None - self.mz_cast_status = {} self.mz_media_status = {} self.mz_media_status_received = {} self.mz_mgr = None @@ -685,7 +679,6 @@ class CastDevice(MediaPlayerDevice): self._dynamic_group_status_listener = DynamicGroupCastStatusListener( self, chromecast, mz_mgr) self._dynamic_group_available = False - self.dynamic_group_cast_status = chromecast.status self.dynamic_group_media_status = chromecast.media_controller.status self._dynamic_group_cast.start() self.async_schedule_update_ha_state() @@ -734,7 +727,6 @@ class CastDevice(MediaPlayerDevice): self.cast_status = None self.media_status = None self.media_status_received = None - self.mz_cast_status = {} self.mz_media_status = {} self.mz_media_status_received = {} self.mz_mgr = None @@ -745,7 +737,6 @@ class CastDevice(MediaPlayerDevice): def _dynamic_group_invalidate(self): """Invalidate some attributes.""" self._dynamic_group_cast = None - self.dynamic_group_cast_status = None self.dynamic_group_media_status = None self.dynamic_group_media_status_received = None if self._dynamic_group_status_listener is not None: @@ -797,11 +788,6 @@ class CastDevice(MediaPlayerDevice): self._available = new_available self.schedule_update_ha_state() - def new_dynamic_group_cast_status(self, cast_status): - """Handle updates of the cast status.""" - self.dynamic_group_cast_status = cast_status - self.schedule_update_ha_state() - def new_dynamic_group_media_status(self, media_status): """Handle updates of the media status.""" self.dynamic_group_media_status = media_status @@ -848,16 +834,6 @@ class CastDevice(MediaPlayerDevice): self.mz_media_status_received[group_uuid] = dt_util.utcnow() self.schedule_update_ha_state() - def multizone_new_cast_status(self, group_uuid, cast_status): - """Handle updates of audio group status.""" - _LOGGER.debug( - "[%s %s (%s:%s)] Multizone %s cast status: %s", - self.entity_id, self._cast_info.friendly_name, - self._cast_info.host, self._cast_info.port, - group_uuid, cast_status) - self.mz_cast_status[group_uuid] = cast_status - self.schedule_update_ha_state() - # ========== Service Calls ========== def _media_controller(self): """ From 353fca3b6eca478bbaf7bbf3475f735f9896ef8a Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 05:31:39 +0200 Subject: [PATCH 126/167] Raise severity of MQTT callback deprecation warning (#22792) --- homeassistant/components/mqtt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index f77cd985a8a..9af0465c0de 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -371,7 +371,7 @@ async def async_subscribe(hass: HomeAssistantType, topic: str, wrapped_msg_callback = msg_callback # If we have 3 paramaters with no default value, wrap the callback if non_default == 3: - _LOGGER.info( + _LOGGER.warning( "Signature of MQTT msg_callback '%s.%s' is deprecated", inspect.getmodule(msg_callback).__name__, msg_callback.__name__) wrapped_msg_callback = wrap_msg_callback(msg_callback) From 8c17b2f7dd6990e26ab2264e5a836c17b7efae68 Mon Sep 17 00:00:00 2001 From: Justin Vanderhooft Date: Sat, 6 Apr 2019 23:33:28 -0400 Subject: [PATCH 127/167] Bump raincloud dependency to fix broken integration: Fixes #22422 (#22805) * Bump raincloud dependency to fix broken integration: Fixes #22422 * bump requirements_all * bump CODEOWNERS * edit codeowners in response to PR feedback --- CODEOWNERS | 1 + homeassistant/components/raincloud/__init__.py | 2 +- homeassistant/components/raincloud/manifest.json | 4 ++-- requirements_all.txt | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 5adc4d071c2..a5c06f991c9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -162,6 +162,7 @@ homeassistant/components/pvoutput/* @fabaff homeassistant/components/qnap/* @colinodell homeassistant/components/quantum_gateway/* @cisasteelersfan homeassistant/components/qwikswitch/* @kellerza +homeassistant/components/raincloud/* @vanstinator homeassistant/components/rainmachine/* @bachya homeassistant/components/random/* @fabaff homeassistant/components/rfxtrx/* @danielhiversen diff --git a/homeassistant/components/raincloud/__init__.py b/homeassistant/components/raincloud/__init__.py index 473d52bdbdd..c31729197be 100644 --- a/homeassistant/components/raincloud/__init__.py +++ b/homeassistant/components/raincloud/__init__.py @@ -13,7 +13,7 @@ from homeassistant.helpers.dispatcher import ( from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import track_time_interval -REQUIREMENTS = ['raincloudy==0.0.5'] +REQUIREMENTS = ['raincloudy==0.0.6'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/raincloud/manifest.json b/homeassistant/components/raincloud/manifest.json index 2befec24b91..dddfc6f156a 100644 --- a/homeassistant/components/raincloud/manifest.json +++ b/homeassistant/components/raincloud/manifest.json @@ -3,8 +3,8 @@ "name": "Raincloud", "documentation": "https://www.home-assistant.io/components/raincloud", "requirements": [ - "raincloudy==0.0.5" + "raincloudy==0.0.6" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@vanstinator"] } diff --git a/requirements_all.txt b/requirements_all.txt index d91af2c43cb..265ff9de860 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1471,7 +1471,7 @@ rachiopy==0.1.3 radiotherm==2.0.0 # homeassistant.components.raincloud -raincloudy==0.0.5 +raincloudy==0.0.6 # homeassistant.components.raspihats # raspihats==2.2.3 From c8eebb6b4a5fbefec0f4fc6621bf9466e34de6b6 Mon Sep 17 00:00:00 2001 From: Markus Jankowski Date: Sun, 7 Apr 2019 09:43:07 +0200 Subject: [PATCH 128/167] Add HmIP-SMO to Homematic IP (#22802) --- .../components/homematicip_cloud/binary_sensor.py | 7 ++++--- homeassistant/components/homematicip_cloud/sensor.py | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/binary_sensor.py b/homeassistant/components/homematicip_cloud/binary_sensor.py index 071b4a0a3fb..44c17282dda 100644 --- a/homeassistant/components/homematicip_cloud/binary_sensor.py +++ b/homeassistant/components/homematicip_cloud/binary_sensor.py @@ -30,9 +30,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the HomematicIP Cloud binary sensor from a config entry.""" from homematicip.aio.device import ( AsyncDevice, AsyncShutterContact, AsyncMotionDetectorIndoor, - AsyncSmokeDetector, AsyncWaterSensor, AsyncRotaryHandleSensor, - AsyncMotionDetectorPushButton, AsyncWeatherSensor, - AsyncWeatherSensorPlus, AsyncWeatherSensorPro) + AsyncMotionDetectorOutdoor, AsyncSmokeDetector, AsyncWaterSensor, + AsyncRotaryHandleSensor, AsyncMotionDetectorPushButton, + AsyncWeatherSensor, AsyncWeatherSensorPlus, AsyncWeatherSensorPro) from homematicip.aio.group import ( AsyncSecurityGroup, AsyncSecurityZoneGroup) @@ -43,6 +43,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): if isinstance(device, (AsyncShutterContact, AsyncRotaryHandleSensor)): devices.append(HomematicipShutterContact(home, device)) if isinstance(device, (AsyncMotionDetectorIndoor, + AsyncMotionDetectorOutdoor, AsyncMotionDetectorPushButton)): devices.append(HomematicipMotionDetector(home, device)) if isinstance(device, AsyncSmokeDetector): diff --git a/homeassistant/components/homematicip_cloud/sensor.py b/homeassistant/components/homematicip_cloud/sensor.py index 2038433df4f..5f345f419fa 100644 --- a/homeassistant/components/homematicip_cloud/sensor.py +++ b/homeassistant/components/homematicip_cloud/sensor.py @@ -28,7 +28,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): AsyncHeatingThermostat, AsyncHeatingThermostatCompact, AsyncTemperatureHumiditySensorWithoutDisplay, AsyncTemperatureHumiditySensorDisplay, AsyncMotionDetectorIndoor, - AsyncTemperatureHumiditySensorOutdoor, + AsyncMotionDetectorOutdoor, AsyncTemperatureHumiditySensorOutdoor, AsyncMotionDetectorPushButton, AsyncLightSensor, AsyncPlugableSwitchMeasuring, AsyncBrandSwitchMeasuring, AsyncFullFlushSwitchMeasuring, AsyncWeatherSensor, @@ -49,6 +49,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): devices.append(HomematicipTemperatureSensor(home, device)) devices.append(HomematicipHumiditySensor(home, device)) if isinstance(device, (AsyncMotionDetectorIndoor, + AsyncMotionDetectorOutdoor, AsyncMotionDetectorPushButton, AsyncWeatherSensor, AsyncWeatherSensorPlus, From 3ce6be62979f84e17454d1de98a8985ca4c4f2ca Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Sun, 7 Apr 2019 01:16:54 -0700 Subject: [PATCH 129/167] Add a new mobile_app webhook command to get config (#22813) * Add a new mobile_app webhook command to get config * Limit fields returned --- homeassistant/components/mobile_app/const.py | 6 ++-- .../components/mobile_app/webhook.py | 24 ++++++++++--- tests/components/mobile_app/test_webhook.py | 34 +++++++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/mobile_app/const.py b/homeassistant/components/mobile_app/const.py index b59c631ba99..52ca0aa3993 100644 --- a/homeassistant/components/mobile_app/const.py +++ b/homeassistant/components/mobile_app/const.py @@ -67,6 +67,7 @@ ERR_SENSOR_DUPLICATE_UNIQUE_ID = 'duplicate_unique_id' WEBHOOK_TYPE_CALL_SERVICE = 'call_service' WEBHOOK_TYPE_FIRE_EVENT = 'fire_event' +WEBHOOK_TYPE_GET_CONFIG = 'get_config' WEBHOOK_TYPE_GET_ZONES = 'get_zones' WEBHOOK_TYPE_REGISTER_SENSOR = 'register_sensor' WEBHOOK_TYPE_RENDER_TEMPLATE = 'render_template' @@ -75,8 +76,9 @@ WEBHOOK_TYPE_UPDATE_REGISTRATION = 'update_registration' WEBHOOK_TYPE_UPDATE_SENSOR_STATES = 'update_sensor_states' WEBHOOK_TYPES = [WEBHOOK_TYPE_CALL_SERVICE, WEBHOOK_TYPE_FIRE_EVENT, - WEBHOOK_TYPE_GET_ZONES, WEBHOOK_TYPE_REGISTER_SENSOR, - WEBHOOK_TYPE_RENDER_TEMPLATE, WEBHOOK_TYPE_UPDATE_LOCATION, + WEBHOOK_TYPE_GET_CONFIG, WEBHOOK_TYPE_GET_ZONES, + WEBHOOK_TYPE_REGISTER_SENSOR, WEBHOOK_TYPE_RENDER_TEMPLATE, + WEBHOOK_TYPE_UPDATE_LOCATION, WEBHOOK_TYPE_UPDATE_REGISTRATION, WEBHOOK_TYPE_UPDATE_SENSOR_STATES] diff --git a/homeassistant/components/mobile_app/webhook.py b/homeassistant/components/mobile_app/webhook.py index 71c6d0d6673..a57d3930f50 100644 --- a/homeassistant/components/mobile_app/webhook.py +++ b/homeassistant/components/mobile_app/webhook.py @@ -8,7 +8,7 @@ from homeassistant.components.device_tracker import (ATTR_ATTRIBUTES, ATTR_DEV_ID, DOMAIN as DT_DOMAIN, SERVICE_SEE as DT_SEE) - +from homeassistant.components.frontend import MANIFEST_JSON from homeassistant.components.zone.const import DOMAIN as ZONE_DOMAIN from homeassistant.const import (ATTR_DOMAIN, ATTR_SERVICE, ATTR_SERVICE_DATA, @@ -36,9 +36,9 @@ from .const import (ATTR_ALTITUDE, ATTR_BATTERY, ATTR_COURSE, ATTR_DEVICE_ID, ERR_SENSOR_DUPLICATE_UNIQUE_ID, ERR_SENSOR_NOT_REGISTERED, SIGNAL_SENSOR_UPDATE, WEBHOOK_PAYLOAD_SCHEMA, WEBHOOK_SCHEMAS, WEBHOOK_TYPES, WEBHOOK_TYPE_CALL_SERVICE, - WEBHOOK_TYPE_FIRE_EVENT, WEBHOOK_TYPE_GET_ZONES, - WEBHOOK_TYPE_REGISTER_SENSOR, WEBHOOK_TYPE_RENDER_TEMPLATE, - WEBHOOK_TYPE_UPDATE_LOCATION, + WEBHOOK_TYPE_FIRE_EVENT, WEBHOOK_TYPE_GET_CONFIG, + WEBHOOK_TYPE_GET_ZONES, WEBHOOK_TYPE_REGISTER_SENSOR, + WEBHOOK_TYPE_RENDER_TEMPLATE, WEBHOOK_TYPE_UPDATE_LOCATION, WEBHOOK_TYPE_UPDATE_REGISTRATION, WEBHOOK_TYPE_UPDATE_SENSOR_STATES) @@ -273,3 +273,19 @@ async def handle_webhook(hass: HomeAssistantType, webhook_id: str, in sorted(hass.states.async_entity_ids(ZONE_DOMAIN))) return webhook_response(list(zones), registration=registration, headers=headers) + + if webhook_type == WEBHOOK_TYPE_GET_CONFIG: + + hass_config = hass.config.as_dict() + + return webhook_response({ + 'latitude': hass_config['latitude'], + 'longitude': hass_config['longitude'], + 'elevation': hass_config['elevation'], + 'unit_system': hass_config['unit_system'], + 'location_name': hass_config['location_name'], + 'time_zone': hass_config['time_zone'], + 'components': hass_config['components'], + 'version': hass_config['version'], + 'theme_color': MANIFEST_JSON['theme_color'], + }, registration=registration, headers=headers) diff --git a/tests/components/mobile_app/test_webhook.py b/tests/components/mobile_app/test_webhook.py index ad19a70a806..43eac28ec18 100644 --- a/tests/components/mobile_app/test_webhook.py +++ b/tests/components/mobile_app/test_webhook.py @@ -126,6 +126,40 @@ async def test_webhook_handle_get_zones(hass, create_registrations, # noqa: F40 assert json[0]['entity_id'] == 'zone.home' +async def test_webhook_handle_get_config(hass, create_registrations, # noqa: F401, F811, E501 + webhook_client): # noqa: F811 + """Test that we can get config properly.""" + resp = await webhook_client.post( + '/api/webhook/{}'.format(create_registrations[1]['webhook_id']), + json={'type': 'get_config'} + ) + + assert resp.status == 200 + + json = await resp.json() + if 'components' in json: + json['components'] = set(json['components']) + if 'whitelist_external_dirs' in json: + json['whitelist_external_dirs'] = \ + set(json['whitelist_external_dirs']) + + hass_config = hass.config.as_dict() + + expected_dict = { + 'latitude': hass_config['latitude'], + 'longitude': hass_config['longitude'], + 'elevation': hass_config['elevation'], + 'unit_system': hass_config['unit_system'], + 'location_name': hass_config['location_name'], + 'time_zone': hass_config['time_zone'], + 'components': hass_config['components'], + 'version': hass_config['version'], + 'theme_color': '#03A9F4', # Default frontend theme color + } + + assert expected_dict == json + + async def test_webhook_returns_error_incorrect_json(webhook_client, # noqa: F401, F811, E501 create_registrations, # noqa: F401, F811, E501 caplog): # noqa: E501 F811 From 6492809a7eb91a278676e34edd0027a2b26e4462 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Sun, 7 Apr 2019 01:17:14 -0700 Subject: [PATCH 130/167] Fix for optional values in the update_location webhook call (#22817) * Fix for optional values in the update_location webhook call * Square brackets instead of .get --- .../components/mobile_app/webhook.py | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/mobile_app/webhook.py b/homeassistant/components/mobile_app/webhook.py index a57d3930f50..7a83ba4e978 100644 --- a/homeassistant/components/mobile_app/webhook.py +++ b/homeassistant/components/mobile_app/webhook.py @@ -145,18 +145,26 @@ async def handle_webhook(hass: HomeAssistantType, webhook_id: str, if webhook_type == WEBHOOK_TYPE_UPDATE_LOCATION: see_payload = { ATTR_DEV_ID: registration[ATTR_DEVICE_ID], - ATTR_LOCATION_NAME: data.get(ATTR_LOCATION_NAME), - ATTR_GPS: data.get(ATTR_GPS), - ATTR_GPS_ACCURACY: data.get(ATTR_GPS_ACCURACY), - ATTR_BATTERY: data.get(ATTR_BATTERY), - ATTR_ATTRIBUTES: { - ATTR_SPEED: data.get(ATTR_SPEED), - ATTR_ALTITUDE: data.get(ATTR_ALTITUDE), - ATTR_COURSE: data.get(ATTR_COURSE), - ATTR_VERTICAL_ACCURACY: data.get(ATTR_VERTICAL_ACCURACY), - } + ATTR_GPS: data[ATTR_GPS], + ATTR_GPS_ACCURACY: data[ATTR_GPS_ACCURACY], } + for key in (ATTR_LOCATION_NAME, ATTR_BATTERY): + value = data.get(key) + if value is not None: + see_payload[key] = value + + attrs = {} + + for key in (ATTR_ALTITUDE, ATTR_COURSE, + ATTR_SPEED, ATTR_VERTICAL_ACCURACY): + value = data.get(key) + if value is not None: + attrs[key] = value + + if attrs: + see_payload[ATTR_ATTRIBUTES] = attrs + try: await hass.services.async_call(DT_DOMAIN, DT_SEE, see_payload, From 83fb3637d9cac18a135756fc53680acfc9d707ec Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 15:56:38 +0200 Subject: [PATCH 131/167] Sort configuration schema. (#22835) --- homeassistant/components/mqtt/lock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/mqtt/lock.py b/homeassistant/components/mqtt/lock.py index e01a30f0fab..b9c095a054a 100644 --- a/homeassistant/components/mqtt/lock.py +++ b/homeassistant/components/mqtt/lock.py @@ -30,14 +30,14 @@ DEFAULT_PAYLOAD_UNLOCK = 'UNLOCK' DEPENDENCIES = ['mqtt'] PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, vol.Optional(CONF_PAYLOAD_LOCK, default=DEFAULT_PAYLOAD_LOCK): cv.string, vol.Optional(CONF_PAYLOAD_UNLOCK, default=DEFAULT_PAYLOAD_UNLOCK): cv.string, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) From 842534d472b887268ad6f3bae9f72bff666d70dc Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 16:00:40 +0200 Subject: [PATCH 132/167] Use dict[key] for required config keys and keys with default values. (#22831) --- homeassistant/components/mqtt/climate.py | 158 +++++++++++------------ 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/homeassistant/components/mqtt/climate.py b/homeassistant/components/mqtt/climate.py index 52d18a03419..0f4229c8688 100644 --- a/homeassistant/components/mqtt/climate.py +++ b/homeassistant/components/mqtt/climate.py @@ -66,11 +66,11 @@ 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' -CONF_MIN_TEMP = 'min_temp' -CONF_MAX_TEMP = 'max_temp' +CONF_TEMP_INITIAL = 'initial' +CONF_TEMP_MIN = 'min_temp' +CONF_TEMP_MAX = 'max_temp' CONF_TEMP_STEP = 'temp_step' TEMPLATE_KEYS = ( @@ -87,57 +87,53 @@ TEMPLATE_KEYS = ( SCHEMA_BASE = CLIMATE_PLATFORM_SCHEMA.extend(MQTT_BASE_PLATFORM_SCHEMA.schema) PLATFORM_SCHEMA = SCHEMA_BASE.extend({ - vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean, - 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_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_POWER_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_MODE_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_TEMPERATURE_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_FAN_MODE_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_SWING_MODE_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_AWAY_MODE_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_HOLD_STATE_TEMPLATE): cv.template, vol.Optional(CONF_AUX_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_AUX_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_AWAY_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_AWAY_MODE_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_AWAY_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_CURRENT_TEMPERATURE_TEMPLATE): cv.template, - vol.Optional(CONF_CURRENT_TEMPERATURE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, + vol.Optional(CONF_FAN_MODE_COMMAND_TOPIC): mqtt.valid_publish_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_FAN_MODE_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_FAN_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_HOLD_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_HOLD_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_HOLD_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic, 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_MODE_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic, 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, - - vol.Optional(CONF_MIN_TEMP, default=DEFAULT_MIN_TEMP): vol.Coerce(float), - vol.Optional(CONF_MAX_TEMP, default=DEFAULT_MAX_TEMP): vol.Coerce(float), + vol.Optional(CONF_POWER_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_POWER_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_POWER_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean, + vol.Optional(CONF_SEND_IF_OFF, default=True): cv.boolean, + vol.Optional(CONF_SWING_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_SWING_MODE_LIST, + default=[STATE_ON, STATE_OFF]): cv.ensure_list, + vol.Optional(CONF_SWING_MODE_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_SWING_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_TEMP_INITIAL, default=21): cv.positive_int, + vol.Optional(CONF_TEMP_MIN, default=DEFAULT_MIN_TEMP): vol.Coerce(float), + vol.Optional(CONF_TEMP_MAX, default=DEFAULT_MAX_TEMP): vol.Coerce(float), vol.Optional(CONF_TEMP_STEP, default=1.0): vol.Coerce(float), + vol.Optional(CONF_TEMPERATURE_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_TEMPERATURE_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_TEMPERATURE_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, + vol.Optional(CONF_VALUE_TEMPLATE): cv.template, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) @@ -255,7 +251,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._target_temperature = self._current_fan_mode = \ self._current_operation = self._current_swing_mode = None if self._topic[CONF_TEMPERATURE_STATE_TOPIC] is None: - self._target_temperature = config.get(CONF_INITIAL) + self._target_temperature = config[CONF_TEMP_INITIAL] if self._topic[CONF_FAN_MODE_STATE_TOPIC] is None: self._current_fan_mode = SPEED_LOW if self._topic[CONF_SWING_MODE_STATE_TOPIC] is None: @@ -279,7 +275,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, async def _subscribe_topics(self): """(Re)Subscribe to topics.""" topics = {} - qos = self._config.get(CONF_QOS) + qos = self._config[CONF_QOS] @callback def handle_current_temp_received(msg): @@ -310,7 +306,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, payload = self._value_templates[CONF_MODE_STATE_TEMPLATE].\ async_render_with_possible_json_value(payload) - if payload not in self._config.get(CONF_MODE_LIST): + if payload not in self._config[CONF_MODE_LIST]: _LOGGER.error("Invalid mode: %s", payload) else: self._current_operation = payload @@ -352,7 +348,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._value_templates[CONF_FAN_MODE_STATE_TEMPLATE].\ async_render_with_possible_json_value(payload) - if payload not in self._config.get(CONF_FAN_MODE_LIST): + if payload not in self._config[CONF_FAN_MODE_LIST]: _LOGGER.error("Invalid fan mode: %s", payload) else: self._current_fan_mode = payload @@ -373,7 +369,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._value_templates[CONF_SWING_MODE_STATE_TEMPLATE].\ async_render_with_possible_json_value(payload) - if payload not in self._config.get(CONF_SWING_MODE_LIST): + if payload not in self._config[CONF_SWING_MODE_LIST]: _LOGGER.error("Invalid swing mode: %s", payload) else: self._current_swing_mode = payload @@ -389,8 +385,8 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, def handle_away_mode_received(msg): """Handle receiving away mode via MQTT.""" payload = msg.payload - payload_on = self._config.get(CONF_PAYLOAD_ON) - payload_off = self._config.get(CONF_PAYLOAD_OFF) + payload_on = self._config[CONF_PAYLOAD_ON] + payload_off = self._config[CONF_PAYLOAD_OFF] if CONF_AWAY_MODE_STATE_TEMPLATE in self._value_templates: payload = \ self._value_templates[CONF_AWAY_MODE_STATE_TEMPLATE].\ @@ -419,8 +415,8 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, def handle_aux_mode_received(msg): """Handle receiving aux mode via MQTT.""" payload = msg.payload - payload_on = self._config.get(CONF_PAYLOAD_ON) - payload_off = self._config.get(CONF_PAYLOAD_OFF) + payload_on = self._config[CONF_PAYLOAD_ON] + payload_off = self._config[CONF_PAYLOAD_OFF] if CONF_AUX_STATE_TEMPLATE in self._value_templates: payload = self._value_templates[CONF_AUX_STATE_TEMPLATE].\ async_render_with_possible_json_value(payload) @@ -480,7 +476,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def name(self): """Return the name of the climate device.""" - return self._config.get(CONF_NAME) + return self._config[CONF_NAME] @property def unique_id(self): @@ -510,12 +506,12 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def operation_list(self): """Return the list of available operation modes.""" - return self._config.get(CONF_MODE_LIST) + return self._config[CONF_MODE_LIST] @property def target_temperature_step(self): """Return the supported step of target temperature.""" - return self._config.get(CONF_TEMP_STEP) + return self._config[CONF_TEMP_STEP] @property def is_away_mode_on(self): @@ -540,7 +536,7 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def fan_list(self): """Return the list of available fan modes.""" - return self._config.get(CONF_FAN_MODE_LIST) + return self._config[CONF_FAN_MODE_LIST] async def async_set_temperature(self, **kwargs): """Set new target temperatures.""" @@ -553,24 +549,24 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, # optimistic mode self._target_temperature = kwargs.get(ATTR_TEMPERATURE) - if (self._config.get(CONF_SEND_IF_OFF) or + if (self._config[CONF_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._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + kwargs.get(ATTR_TEMPERATURE), self._config[CONF_QOS], + self._config[CONF_RETAIN]) # Always optimistic? self.async_write_ha_state() async def async_set_swing_mode(self, swing_mode): """Set new swing mode.""" - if (self._config.get(CONF_SEND_IF_OFF) or + if (self._config[CONF_SEND_IF_OFF] or self._current_operation != STATE_OFF): mqtt.async_publish( self.hass, self._topic[CONF_SWING_MODE_COMMAND_TOPIC], - swing_mode, self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + swing_mode, self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._topic[CONF_SWING_MODE_STATE_TOPIC] is None: self._current_swing_mode = swing_mode @@ -578,12 +574,12 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, async def async_set_fan_mode(self, fan_mode): """Set new target temperature.""" - if (self._config.get(CONF_SEND_IF_OFF) or + if (self._config[CONF_SEND_IF_OFF] or self._current_operation != STATE_OFF): mqtt.async_publish( self.hass, self._topic[CONF_FAN_MODE_COMMAND_TOPIC], - fan_mode, self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + fan_mode, self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._topic[CONF_FAN_MODE_STATE_TOPIC] is None: self._current_fan_mode = fan_mode @@ -591,19 +587,19 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, async def async_set_operation_mode(self, operation_mode) -> None: """Set new operation mode.""" - qos = self._config.get(CONF_QOS) - retain = self._config.get(CONF_RETAIN) + qos = self._config[CONF_QOS] + retain = self._config[CONF_RETAIN] 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._config.get(CONF_PAYLOAD_ON), qos, retain) + self._config[CONF_PAYLOAD_ON], qos, retain) elif (self._current_operation != STATE_OFF and operation_mode == STATE_OFF): mqtt.async_publish( self.hass, self._topic[CONF_POWER_COMMAND_TOPIC], - self._config.get(CONF_PAYLOAD_OFF), qos, retain) + self._config[CONF_PAYLOAD_OFF], qos, retain) if self._topic[CONF_MODE_COMMAND_TOPIC] is not None: mqtt.async_publish( @@ -622,16 +618,16 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def swing_list(self): """List of available swing modes.""" - return self._config.get(CONF_SWING_MODE_LIST) + return self._config[CONF_SWING_MODE_LIST] async 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._config.get(CONF_PAYLOAD_ON), - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_PAYLOAD_ON], + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._topic[CONF_AWAY_MODE_STATE_TOPIC] is None: self._away = True @@ -642,9 +638,9 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, if self._topic[CONF_AWAY_MODE_COMMAND_TOPIC] is not None: mqtt.async_publish(self.hass, self._topic[CONF_AWAY_MODE_COMMAND_TOPIC], - self._config.get(CONF_PAYLOAD_OFF), - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_PAYLOAD_OFF], + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._topic[CONF_AWAY_MODE_STATE_TOPIC] is None: self._away = False @@ -655,8 +651,8 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, if self._topic[CONF_HOLD_COMMAND_TOPIC] is not None: mqtt.async_publish(self.hass, self._topic[CONF_HOLD_COMMAND_TOPIC], - hold_mode, self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + hold_mode, self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._topic[CONF_HOLD_STATE_TOPIC] is None: self._hold = hold_mode @@ -666,9 +662,9 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """Turn auxiliary heater on.""" if self._topic[CONF_AUX_COMMAND_TOPIC] is not None: mqtt.async_publish(self.hass, self._topic[CONF_AUX_COMMAND_TOPIC], - self._config.get(CONF_PAYLOAD_ON), - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_PAYLOAD_ON], + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._topic[CONF_AUX_STATE_TOPIC] is None: self._aux = True @@ -678,9 +674,9 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """Turn auxiliary heater off.""" if self._topic[CONF_AUX_COMMAND_TOPIC] is not None: mqtt.async_publish(self.hass, self._topic[CONF_AUX_COMMAND_TOPIC], - self._config.get(CONF_PAYLOAD_OFF), - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_PAYLOAD_OFF], + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._topic[CONF_AUX_STATE_TOPIC] is None: self._aux = False @@ -724,9 +720,9 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def min_temp(self): """Return the minimum temperature.""" - return self._config.get(CONF_MIN_TEMP) + return self._config[CONF_TEMP_MIN] @property def max_temp(self): """Return the maximum temperature.""" - return self._config.get(CONF_MAX_TEMP) + return self._config[CONF_TEMP_MAX] From bb5c18f7be2e525ca38c0ed8c3b39bcf8ec58c83 Mon Sep 17 00:00:00 2001 From: zewelor Date: Sun, 7 Apr 2019 16:07:15 +0200 Subject: [PATCH 133/167] Use relative imports in yeelight (#22839) --- homeassistant/components/yeelight/binary_sensor.py | 2 +- homeassistant/components/yeelight/light.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/yeelight/binary_sensor.py b/homeassistant/components/yeelight/binary_sensor.py index cf7bbc5244e..d39af08f768 100644 --- a/homeassistant/components/yeelight/binary_sensor.py +++ b/homeassistant/components/yeelight/binary_sensor.py @@ -4,7 +4,7 @@ import logging from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from homeassistant.components.yeelight import DATA_YEELIGHT, DATA_UPDATED +from . import DATA_YEELIGHT, DATA_UPDATED DEPENDENCIES = ['yeelight'] diff --git a/homeassistant/components/yeelight/light.py b/homeassistant/components/yeelight/light.py index 912a4f99c92..4840ad7381a 100644 --- a/homeassistant/components/yeelight/light.py +++ b/homeassistant/components/yeelight/light.py @@ -15,7 +15,7 @@ from homeassistant.components.light import ( SUPPORT_COLOR, SUPPORT_TRANSITION, SUPPORT_COLOR_TEMP, SUPPORT_FLASH, SUPPORT_EFFECT, Light) import homeassistant.util.color as color_util -from homeassistant.components.yeelight import ( +from . import ( CONF_TRANSITION, DATA_YEELIGHT, CONF_MODE_MUSIC, CONF_SAVE_ON_CHANGE, CONF_CUSTOM_EFFECTS, DATA_UPDATED, YEELIGHT_SERVICE_SCHEMA, DOMAIN, ATTR_TRANSITIONS, From a91e79ee77394ccf127cc6c65533dc66a4e3fef3 Mon Sep 17 00:00:00 2001 From: zewelor Date: Sun, 7 Apr 2019 16:07:34 +0200 Subject: [PATCH 134/167] Improve yeelight imports (#22804) --- homeassistant/components/yeelight/__init__.py | 20 +++++++------------ homeassistant/components/yeelight/light.py | 17 ++++++++-------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/yeelight/__init__.py b/homeassistant/components/yeelight/__init__.py index 99382bb1da9..7a14a4d1842 100644 --- a/homeassistant/components/yeelight/__init__.py +++ b/homeassistant/components/yeelight/__init__.py @@ -185,8 +185,8 @@ class YeelightDevice: @property def bulb(self): """Return bulb device.""" - import yeelight if self._bulb_device is None: + import yeelight try: self._bulb_device = yeelight.Bulb(self._ipaddr, model=self._model) @@ -241,33 +241,27 @@ class YeelightDevice: def turn_on(self, duration=DEFAULT_TRANSITION, light_type=None): """Turn on device.""" - import yeelight - - if not light_type: - light_type = yeelight.enums.LightType.Main + from yeelight import BulbException try: self.bulb.turn_on(duration=duration, light_type=light_type) - except yeelight.BulbException as ex: + except BulbException as ex: _LOGGER.error("Unable to turn the bulb on: %s", ex) return def turn_off(self, duration=DEFAULT_TRANSITION, light_type=None): """Turn off device.""" - import yeelight - - if not light_type: - light_type = yeelight.enums.LightType.Main + from yeelight import BulbException try: self.bulb.turn_off(duration=duration, light_type=light_type) - except yeelight.BulbException as ex: + except BulbException as ex: _LOGGER.error("Unable to turn the bulb off: %s", ex) return def update(self): """Read new properties from the device.""" - import yeelight + from yeelight import BulbException if not self.bulb: return @@ -275,7 +269,7 @@ class YeelightDevice: try: self.bulb.get_properties(UPDATE_REQUEST_PROPERTIES) self._available = True - except yeelight.BulbException as ex: + except BulbException as ex: if self._available: # just inform once _LOGGER.error("Unable to update bulb status: %s", ex) self._available = False diff --git a/homeassistant/components/yeelight/light.py b/homeassistant/components/yeelight/light.py index 4840ad7381a..74796a524b0 100644 --- a/homeassistant/components/yeelight/light.py +++ b/homeassistant/components/yeelight/light.py @@ -189,6 +189,8 @@ class YeelightLight(Light): def __init__(self, device, custom_effects=None): """Initialize the Yeelight light.""" + from yeelight.enums import LightType + self.config = device.config self._device = device @@ -202,6 +204,8 @@ class YeelightLight(Light): self._min_mireds = None self._max_mireds = None + self._light_type = LightType.Main + if custom_effects: self._custom_effects = custom_effects else: @@ -281,8 +285,7 @@ class YeelightLight(Light): @property def light_type(self): """Return light type.""" - import yeelight - return yeelight.enums.LightType.Main + return self._light_type def _get_hs_from_properties(self): rgb = self._get_property('rgb') @@ -589,21 +592,19 @@ class YeelightAmbientLight(YeelightLight): def __init__(self, *args, **kwargs): """Initialize the Yeelight Ambient light.""" + from yeelight.enums import LightType + super().__init__(*args, **kwargs) self._min_mireds = kelvin_to_mired(6500) self._max_mireds = kelvin_to_mired(1700) + self._light_type = LightType.Ambient + @property def name(self) -> str: """Return the name of the device if any.""" return "{} ambilight".format(self.device.name) - @property - def light_type(self): - """Return light type.""" - import yeelight - return yeelight.enums.LightType.Ambient - @property def _is_nightlight_enabled(self): return False From f62d1d8d09158eb65c8afb56d9fab93b52ed1351 Mon Sep 17 00:00:00 2001 From: zewelor Date: Sun, 7 Apr 2019 16:07:50 +0200 Subject: [PATCH 135/167] Optimize yeelight signal handling (#22806) --- homeassistant/components/yeelight/__init__.py | 4 ++-- homeassistant/components/yeelight/binary_sensor.py | 9 +++++---- homeassistant/components/yeelight/light.py | 9 +++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/yeelight/__init__.py b/homeassistant/components/yeelight/__init__.py index 7a14a4d1842..dc79e9357ff 100644 --- a/homeassistant/components/yeelight/__init__.py +++ b/homeassistant/components/yeelight/__init__.py @@ -22,7 +22,7 @@ _LOGGER = logging.getLogger(__name__) DOMAIN = "yeelight" DATA_YEELIGHT = DOMAIN -DATA_UPDATED = '{}_data_updated'.format(DOMAIN) +DATA_UPDATED = 'yeelight_{}_data_updated' DEFAULT_NAME = 'Yeelight' DEFAULT_TRANSITION = 350 @@ -274,4 +274,4 @@ class YeelightDevice: _LOGGER.error("Unable to update bulb status: %s", ex) self._available = False - dispatcher_send(self._hass, DATA_UPDATED, self._ipaddr) + dispatcher_send(self._hass, DATA_UPDATED.format(self._ipaddr)) diff --git a/homeassistant/components/yeelight/binary_sensor.py b/homeassistant/components/yeelight/binary_sensor.py index d39af08f768..0b44966f15c 100644 --- a/homeassistant/components/yeelight/binary_sensor.py +++ b/homeassistant/components/yeelight/binary_sensor.py @@ -31,14 +31,15 @@ class YeelightNightlightModeSensor(BinarySensorDevice): self._device = device @callback - def _schedule_immediate_update(self, ipaddr): - if ipaddr == self._device.ipaddr: - self.async_schedule_update_ha_state() + def _schedule_immediate_update(self): + self.async_schedule_update_ha_state() async def async_added_to_hass(self): """Handle entity which will be added.""" async_dispatcher_connect( - self.hass, DATA_UPDATED, self._schedule_immediate_update + self.hass, + DATA_UPDATED.format(self._device.ipaddr), + self._schedule_immediate_update ) @property diff --git a/homeassistant/components/yeelight/light.py b/homeassistant/components/yeelight/light.py index 74796a524b0..8aa5c3d7300 100644 --- a/homeassistant/components/yeelight/light.py +++ b/homeassistant/components/yeelight/light.py @@ -212,14 +212,15 @@ class YeelightLight(Light): self._custom_effects = {} @callback - def _schedule_immediate_update(self, ipaddr): - if ipaddr == self.device.ipaddr: - self.async_schedule_update_ha_state(True) + def _schedule_immediate_update(self): + self.async_schedule_update_ha_state(True) async def async_added_to_hass(self): """Handle entity which will be added.""" async_dispatcher_connect( - self.hass, DATA_UPDATED, self._schedule_immediate_update + self.hass, + DATA_UPDATED.format(self._device.ipaddr), + self._schedule_immediate_update ) @property From 439197ea3e811d38ef65afe0afb4ea8303834ce7 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 16:08:04 +0200 Subject: [PATCH 136/167] Use dict[key] for required config keys and keys with default values. (#22828) --- .../components/mqtt/alarm_control_panel.py | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/mqtt/alarm_control_panel.py b/homeassistant/components/mqtt/alarm_control_panel.py index d30c91bb9b2..03a2ac8e388 100644 --- a/homeassistant/components/mqtt/alarm_control_panel.py +++ b/homeassistant/components/mqtt/alarm_control_panel.py @@ -40,22 +40,22 @@ DEFAULT_NAME = 'MQTT Alarm' DEPENDENCIES = ['mqtt'] PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ - vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean, - vol.Required(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_CODE): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_PAYLOAD_ARM_NIGHT, default=DEFAULT_ARM_NIGHT): cv.string, - vol.Optional(CONF_PAYLOAD_ARM_AWAY, default=DEFAULT_ARM_AWAY): cv.string, - vol.Optional(CONF_PAYLOAD_ARM_HOME, default=DEFAULT_ARM_HOME): cv.string, - vol.Optional(CONF_PAYLOAD_DISARM, default=DEFAULT_DISARM): cv.string, vol.Optional(CONF_CODE_ARM_REQUIRED, default=True): cv.boolean, vol.Optional(CONF_CODE_DISARM_REQUIRED, default=True): cv.boolean, vol.Optional(CONF_COMMAND_TEMPLATE, default=DEFAULT_COMMAND_TEMPLATE): cv.template, - vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_UNIQUE_ID): cv.string, + vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_PAYLOAD_ARM_AWAY, default=DEFAULT_ARM_AWAY): cv.string, + vol.Optional(CONF_PAYLOAD_ARM_HOME, default=DEFAULT_ARM_HOME): cv.string, + vol.Optional(CONF_PAYLOAD_ARM_NIGHT, default=DEFAULT_ARM_NIGHT): cv.string, + vol.Optional(CONF_PAYLOAD_DISARM, default=DEFAULT_DISARM): cv.string, + vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean, + vol.Required(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_UNIQUE_ID): cv.string, + vol.Optional(CONF_VALUE_TEMPLATE): cv.template, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) @@ -130,9 +130,8 @@ class MqttAlarm(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, value_template = self._config.get(CONF_VALUE_TEMPLATE) if value_template is not None: value_template.hass = self.hass - command_template = self._config.get(CONF_COMMAND_TEMPLATE) - if command_template is not None: - command_template.hass = self.hass + command_template = self._config[CONF_COMMAND_TEMPLATE] + command_template.hass = self.hass @callback def message_received(msg): @@ -154,9 +153,9 @@ class MqttAlarm(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._sub_state = await subscription.async_subscribe_topics( self.hass, self._sub_state, - {'state_topic': {'topic': self._config.get(CONF_STATE_TOPIC), + {'state_topic': {'topic': self._config[CONF_STATE_TOPIC], 'msg_callback': message_received, - 'qos': self._config.get(CONF_QOS)}}) + 'qos': self._config[CONF_QOS]}}) async def async_will_remove_from_hass(self): """Unsubscribe when removed.""" @@ -173,7 +172,7 @@ class MqttAlarm(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def name(self): """Return the name of the device.""" - return self._config.get(CONF_NAME) + return self._config[CONF_NAME] @property def unique_id(self): @@ -200,10 +199,10 @@ class MqttAlarm(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, This method is a coroutine. """ - code_required = self._config.get(CONF_CODE_DISARM_REQUIRED) + code_required = self._config[CONF_CODE_DISARM_REQUIRED] if code_required and not self._validate_code(code, 'disarming'): return - payload = self._config.get(CONF_PAYLOAD_DISARM) + payload = self._config[CONF_PAYLOAD_DISARM] self._publish(code, payload) async def async_alarm_arm_home(self, code=None): @@ -211,10 +210,10 @@ class MqttAlarm(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, This method is a coroutine. """ - code_required = self._config.get(CONF_CODE_ARM_REQUIRED) + code_required = self._config[CONF_CODE_ARM_REQUIRED] if code_required and not self._validate_code(code, 'arming home'): return - action = self._config.get(CONF_PAYLOAD_ARM_HOME) + action = self._config[CONF_PAYLOAD_ARM_HOME] self._publish(code, action) async def async_alarm_arm_away(self, code=None): @@ -222,10 +221,10 @@ class MqttAlarm(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, This method is a coroutine. """ - code_required = self._config.get(CONF_CODE_ARM_REQUIRED) + code_required = self._config[CONF_CODE_ARM_REQUIRED] if code_required and not self._validate_code(code, 'arming away'): return - action = self._config.get(CONF_PAYLOAD_ARM_AWAY) + action = self._config[CONF_PAYLOAD_ARM_AWAY] self._publish(code, action) async def async_alarm_arm_night(self, code=None): @@ -233,22 +232,22 @@ class MqttAlarm(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, This method is a coroutine. """ - code_required = self._config.get(CONF_CODE_ARM_REQUIRED) + code_required = self._config[CONF_CODE_ARM_REQUIRED] if code_required and not self._validate_code(code, 'arming night'): return - action = self._config.get(CONF_PAYLOAD_ARM_NIGHT) + action = self._config[CONF_PAYLOAD_ARM_NIGHT] self._publish(code, action) def _publish(self, code, action): """Publish via mqtt.""" - command_template = self._config.get(CONF_COMMAND_TEMPLATE) + command_template = self._config[CONF_COMMAND_TEMPLATE] values = {'action': action, 'code': code} payload = command_template.async_render(**values) mqtt.async_publish( - self.hass, self._config.get(CONF_COMMAND_TOPIC), + self.hass, self._config[CONF_COMMAND_TOPIC], payload, - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_QOS], + self._config[CONF_RETAIN]) def _validate_code(self, code, state): """Validate given code.""" From a4e7708450ea8128128f2368627d03840f7369ae Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 16:08:47 +0200 Subject: [PATCH 137/167] Use dict[key] for required config keys and keys with default values. (#22833) --- homeassistant/components/mqtt/fan.py | 68 ++++++++++++++-------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/homeassistant/components/mqtt/fan.py b/homeassistant/components/mqtt/fan.py index 7dff81160e0..d86390ee31d 100644 --- a/homeassistant/components/mqtt/fan.py +++ b/homeassistant/components/mqtt/fan.py @@ -50,29 +50,29 @@ OSCILLATE_OFF_PAYLOAD = 'oscillate_off' OSCILLATION = 'oscillation' PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_SPEED_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_SPEED_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_SPEED_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_OSCILLATION_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_OSCILLATION_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_OSCILLATION_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, - vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, - vol.Optional(CONF_PAYLOAD_OSCILLATION_ON, - default=DEFAULT_PAYLOAD_ON): cv.string, - vol.Optional(CONF_PAYLOAD_OSCILLATION_OFF, - default=DEFAULT_PAYLOAD_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_HIGH_SPEED, default=SPEED_HIGH): cv.string, vol.Optional(CONF_PAYLOAD_LOW_SPEED, default=SPEED_LOW): cv.string, vol.Optional(CONF_PAYLOAD_MEDIUM_SPEED, default=SPEED_MEDIUM): cv.string, - vol.Optional(CONF_PAYLOAD_HIGH_SPEED, default=SPEED_HIGH): cv.string, + vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, + vol.Optional(CONF_PAYLOAD_OSCILLATION_OFF, + default=DEFAULT_PAYLOAD_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_OSCILLATION_ON, + default=DEFAULT_PAYLOAD_ON): cv.string, + vol.Optional(CONF_SPEED_COMMAND_TOPIC): mqtt.valid_publish_topic, vol.Optional(CONF_SPEED_LIST, default=[SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]): cv.ensure_list, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_SPEED_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_SPEED_VALUE_TEMPLATE): cv.template, + vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template, vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) @@ -174,15 +174,15 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, OSCILLATION: config.get(CONF_OSCILLATION_VALUE_TEMPLATE) } self._payload = { - STATE_ON: config.get(CONF_PAYLOAD_ON), - STATE_OFF: config.get(CONF_PAYLOAD_OFF), - OSCILLATE_ON_PAYLOAD: config.get(CONF_PAYLOAD_OSCILLATION_ON), - OSCILLATE_OFF_PAYLOAD: config.get(CONF_PAYLOAD_OSCILLATION_OFF), - SPEED_LOW: config.get(CONF_PAYLOAD_LOW_SPEED), - SPEED_MEDIUM: config.get(CONF_PAYLOAD_MEDIUM_SPEED), - SPEED_HIGH: config.get(CONF_PAYLOAD_HIGH_SPEED), + STATE_ON: config[CONF_PAYLOAD_ON], + STATE_OFF: config[CONF_PAYLOAD_OFF], + OSCILLATE_ON_PAYLOAD: config[CONF_PAYLOAD_OSCILLATION_ON], + OSCILLATE_OFF_PAYLOAD: config[CONF_PAYLOAD_OSCILLATION_OFF], + SPEED_LOW: config[CONF_PAYLOAD_LOW_SPEED], + SPEED_MEDIUM: config[CONF_PAYLOAD_MEDIUM_SPEED], + SPEED_HIGH: config[CONF_PAYLOAD_HIGH_SPEED], } - optimistic = config.get(CONF_OPTIMISTIC) + optimistic = config[CONF_OPTIMISTIC] self._optimistic = optimistic or self._topic[CONF_STATE_TOPIC] is None self._optimistic_oscillation = ( optimistic or self._topic[CONF_OSCILLATION_STATE_TOPIC] is None) @@ -220,7 +220,7 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, topics[CONF_STATE_TOPIC] = { 'topic': self._topic[CONF_STATE_TOPIC], 'msg_callback': state_received, - 'qos': self._config.get(CONF_QOS)} + 'qos': self._config[CONF_QOS]} @callback def speed_received(msg): @@ -238,7 +238,7 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, topics[CONF_SPEED_STATE_TOPIC] = { 'topic': self._topic[CONF_SPEED_STATE_TOPIC], 'msg_callback': speed_received, - 'qos': self._config.get(CONF_QOS)} + 'qos': self._config[CONF_QOS]} self._speed = SPEED_OFF @callback @@ -255,7 +255,7 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, topics[CONF_OSCILLATION_STATE_TOPIC] = { 'topic': self._topic[CONF_OSCILLATION_STATE_TOPIC], 'msg_callback': oscillation_received, - 'qos': self._config.get(CONF_QOS)} + 'qos': self._config[CONF_QOS]} self._oscillation = False self._sub_state = await subscription.async_subscribe_topics( @@ -287,12 +287,12 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def name(self) -> str: """Get entity name.""" - return self._config.get(CONF_NAME) + return self._config[CONF_NAME] @property def speed_list(self) -> list: """Get the list of available speeds.""" - return self._config.get(CONF_SPEED_LIST) + return self._config[CONF_SPEED_LIST] @property def supported_features(self) -> int: @@ -316,8 +316,8 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """ mqtt.async_publish( self.hass, self._topic[CONF_COMMAND_TOPIC], - self._payload[STATE_ON], self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._payload[STATE_ON], self._config[CONF_QOS], + self._config[CONF_RETAIN]) if speed: await self.async_set_speed(speed) @@ -328,8 +328,8 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """ mqtt.async_publish( self.hass, self._topic[CONF_COMMAND_TOPIC], - self._payload[STATE_OFF], self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._payload[STATE_OFF], self._config[CONF_QOS], + self._config[CONF_RETAIN]) async def async_set_speed(self, speed: str) -> None: """Set the speed of the fan. @@ -350,8 +350,8 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, mqtt.async_publish( self.hass, self._topic[CONF_SPEED_COMMAND_TOPIC], - mqtt_payload, self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + mqtt_payload, self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._optimistic_speed: self._speed = speed @@ -372,7 +372,7 @@ class MqttFan(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, mqtt.async_publish( self.hass, self._topic[CONF_OSCILLATION_COMMAND_TOPIC], - payload, self._config.get(CONF_QOS), self._config.get(CONF_RETAIN)) + payload, self._config[CONF_QOS], self._config[CONF_RETAIN]) if self._optimistic_oscillation: self._oscillation = oscillating From b1213b7a2dd1b353f1d168506de4d4b5f3d3ebd1 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 16:09:43 +0200 Subject: [PATCH 138/167] Use dict[key] for required config keys and keys with default values. (#22836) --- homeassistant/components/mqtt/sensor.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/mqtt/sensor.py b/homeassistant/components/mqtt/sensor.py index 1e024fdc768..b6419ea2c24 100644 --- a/homeassistant/components/mqtt/sensor.py +++ b/homeassistant/components/mqtt/sensor.py @@ -35,17 +35,15 @@ DEFAULT_FORCE_UPDATE = False DEPENDENCIES = ['mqtt'] PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, - vol.Optional(CONF_ICON): cv.icon, + vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, - vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv, vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int, vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean, - # Integrations should never expose unique_id through configuration. - # This is an exception because MQTT is a message transport, not a protocol. + vol.Optional(CONF_ICON): cv.icon, + vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, + vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) @@ -146,7 +144,7 @@ class MqttSensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._expiration_trigger = async_track_point_in_utc_time( self.hass, self.value_is_expired, expiration_at) - json_attributes = set(self._config.get(CONF_JSON_ATTRS)) + json_attributes = set(self._config[CONF_JSON_ATTRS]) if json_attributes: self._attributes = {} try: @@ -169,9 +167,9 @@ class MqttSensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._sub_state = await subscription.async_subscribe_topics( self.hass, self._sub_state, - {'state_topic': {'topic': self._config.get(CONF_STATE_TOPIC), + {'state_topic': {'topic': self._config[CONF_STATE_TOPIC], 'msg_callback': message_received, - 'qos': self._config.get(CONF_QOS)}}) + 'qos': self._config[CONF_QOS]}}) async def async_will_remove_from_hass(self): """Unsubscribe when removed.""" @@ -195,7 +193,7 @@ class MqttSensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def name(self): """Return the name of the sensor.""" - return self._config.get(CONF_NAME) + return self._config[CONF_NAME] @property def unit_of_measurement(self): @@ -205,7 +203,7 @@ class MqttSensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def force_update(self): """Force update.""" - return self._config.get(CONF_FORCE_UPDATE) + return self._config[CONF_FORCE_UPDATE] @property def state(self): From 2a629069653845c167543518b7197f3fd162935e Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 16:10:13 +0200 Subject: [PATCH 139/167] Use dict[key] for required config keys and keys with default values. (#22837) --- homeassistant/components/mqtt/switch.py | 42 ++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/mqtt/switch.py b/homeassistant/components/mqtt/switch.py index acfcf3de01c..20d28b6496c 100644 --- a/homeassistant/components/mqtt/switch.py +++ b/homeassistant/components/mqtt/switch.py @@ -32,15 +32,15 @@ CONF_STATE_ON = "state_on" CONF_STATE_OFF = "state_off" PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_ICON): cv.icon, - vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, - vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, - vol.Optional(CONF_STATE_ON): cv.string, - vol.Optional(CONF_STATE_OFF): cv.string, - vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, + vol.Optional(CONF_ICON): cv.icon, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, + vol.Optional(CONF_STATE_OFF): cv.string, + vol.Optional(CONF_STATE_ON): cv.string, + vol.Optional(CONF_UNIQUE_ID): cv.string, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) @@ -123,13 +123,13 @@ class MqttSwitch(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._config = config state_on = config.get(CONF_STATE_ON) - self._state_on = state_on if state_on else config.get(CONF_PAYLOAD_ON) + self._state_on = state_on if state_on else config[CONF_PAYLOAD_ON] state_off = config.get(CONF_STATE_OFF) self._state_off = state_off if state_off else \ - config.get(CONF_PAYLOAD_OFF) + config[CONF_PAYLOAD_OFF] - self._optimistic = config.get(CONF_OPTIMISTIC) + self._optimistic = config[CONF_OPTIMISTIC] async def _subscribe_topics(self): """(Re)Subscribe to topics.""" @@ -160,7 +160,7 @@ class MqttSwitch(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, {CONF_STATE_TOPIC: {'topic': self._config.get(CONF_STATE_TOPIC), 'msg_callback': state_message_received, - 'qos': self._config.get(CONF_QOS)}}) + 'qos': self._config[CONF_QOS]}}) if self._optimistic: last_state = await self.async_get_last_state() @@ -182,7 +182,7 @@ class MqttSwitch(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def name(self): """Return the name of the switch.""" - return self._config.get(CONF_NAME) + return self._config[CONF_NAME] @property def is_on(self): @@ -211,10 +211,10 @@ class MqttSwitch(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """ mqtt.async_publish( self.hass, - self._config.get(CONF_COMMAND_TOPIC), - self._config.get(CONF_PAYLOAD_ON), - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_COMMAND_TOPIC], + self._config[CONF_PAYLOAD_ON], + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._optimistic: # Optimistically assume that switch has changed state. self._state = True @@ -227,10 +227,10 @@ class MqttSwitch(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """ mqtt.async_publish( self.hass, - self._config.get(CONF_COMMAND_TOPIC), - self._config.get(CONF_PAYLOAD_OFF), - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_COMMAND_TOPIC], + self._config[CONF_PAYLOAD_OFF], + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._optimistic: # Optimistically assume that switch has changed state. self._state = False From dbb42e5890ff78f4bfae1c072a66987a25dc1d18 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 16:10:57 +0200 Subject: [PATCH 140/167] Use dict[key] for required config keys and keys with default values. (#22838) --- homeassistant/components/mqtt/vacuum.py | 69 ++++++++++++------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/homeassistant/components/mqtt/vacuum.py b/homeassistant/components/mqtt/vacuum.py index 63a764e8746..23a5e34b3ca 100644 --- a/homeassistant/components/mqtt/vacuum.py +++ b/homeassistant/components/mqtt/vacuum.py @@ -102,45 +102,44 @@ DEFAULT_PAYLOAD_LOCATE = 'locate' DEFAULT_PAYLOAD_START_PAUSE = 'start_pause' PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_BATTERY_LEVEL_TEMPLATE): cv.template, + vol.Optional(CONF_BATTERY_LEVEL_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_CHARGING_TEMPLATE): cv.template, + vol.Optional(CONF_CHARGING_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_CLEANING_TEMPLATE): cv.template, + vol.Optional(CONF_CLEANING_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, + vol.Optional(CONF_DOCKED_TEMPLATE): cv.template, + vol.Optional(CONF_DOCKED_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_ERROR_TEMPLATE): cv.template, + vol.Optional(CONF_ERROR_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_FAN_SPEED_LIST, default=[]): + vol.All(cv.ensure_list, [cv.string]), + vol.Optional(CONF_FAN_SPEED_TEMPLATE): cv.template, + vol.Optional(CONF_FAN_SPEED_TOPIC): mqtt.valid_publish_topic, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_SUPPORTED_FEATURES, default=DEFAULT_SERVICE_STRINGS): - vol.All(cv.ensure_list, [vol.In(STRING_TO_SERVICE.keys())]), - vol.Optional(mqtt.CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, - vol.Optional(mqtt.CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_PAYLOAD_TURN_ON, - default=DEFAULT_PAYLOAD_TURN_ON): cv.string, - vol.Optional(CONF_PAYLOAD_TURN_OFF, - default=DEFAULT_PAYLOAD_TURN_OFF): cv.string, - vol.Optional(CONF_PAYLOAD_RETURN_TO_BASE, - default=DEFAULT_PAYLOAD_RETURN_TO_BASE): cv.string, - vol.Optional(CONF_PAYLOAD_STOP, - default=DEFAULT_PAYLOAD_STOP): cv.string, vol.Optional(CONF_PAYLOAD_CLEAN_SPOT, default=DEFAULT_PAYLOAD_CLEAN_SPOT): cv.string, vol.Optional(CONF_PAYLOAD_LOCATE, default=DEFAULT_PAYLOAD_LOCATE): cv.string, + vol.Optional(CONF_PAYLOAD_RETURN_TO_BASE, + default=DEFAULT_PAYLOAD_RETURN_TO_BASE): cv.string, vol.Optional(CONF_PAYLOAD_START_PAUSE, default=DEFAULT_PAYLOAD_START_PAUSE): cv.string, - vol.Optional(CONF_BATTERY_LEVEL_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_BATTERY_LEVEL_TEMPLATE): cv.template, - vol.Optional(CONF_CHARGING_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_CHARGING_TEMPLATE): cv.template, - vol.Optional(CONF_CLEANING_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_CLEANING_TEMPLATE): cv.template, - vol.Optional(CONF_DOCKED_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_DOCKED_TEMPLATE): cv.template, - vol.Optional(CONF_ERROR_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_ERROR_TEMPLATE): cv.template, - vol.Optional(CONF_STATE_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_STATE_TEMPLATE): cv.template, - vol.Optional(CONF_FAN_SPEED_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_FAN_SPEED_TEMPLATE): cv.template, - vol.Optional(CONF_SET_FAN_SPEED_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_FAN_SPEED_LIST, default=[]): - vol.All(cv.ensure_list, [cv.string]), + vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): cv.string, + vol.Optional(CONF_PAYLOAD_TURN_OFF, + default=DEFAULT_PAYLOAD_TURN_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_TURN_ON, + default=DEFAULT_PAYLOAD_TURN_ON): cv.string, vol.Optional(CONF_SEND_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_SET_FAN_SPEED_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_STATE_TEMPLATE): cv.template, + vol.Optional(CONF_STATE_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_SUPPORTED_FEATURES, default=DEFAULT_SERVICE_STRINGS): + vol.All(cv.ensure_list, [vol.In(STRING_TO_SERVICE.keys())]), vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, + vol.Optional(mqtt.CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(mqtt.CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) @@ -206,14 +205,14 @@ class MqttVacuum(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo.__init__(self, device_config, config_entry) def _setup_from_config(self, config): - self._name = config.get(CONF_NAME) - supported_feature_strings = config.get(CONF_SUPPORTED_FEATURES) + self._name = config[CONF_NAME] + supported_feature_strings = config[CONF_SUPPORTED_FEATURES] self._supported_features = strings_to_services( supported_feature_strings ) - self._fan_speed_list = config.get(CONF_FAN_SPEED_LIST) - self._qos = config.get(mqtt.CONF_QOS) - self._retain = config.get(mqtt.CONF_RETAIN) + self._fan_speed_list = config[CONF_FAN_SPEED_LIST] + self._qos = config[mqtt.CONF_QOS] + self._retain = config[mqtt.CONF_RETAIN] self._command_topic = config.get(mqtt.CONF_COMMAND_TOPIC) self._set_fan_speed_topic = config.get(CONF_SET_FAN_SPEED_TOPIC) From 58220a94484b5531b24002ee4a68d33af87d3378 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 16:11:20 +0200 Subject: [PATCH 141/167] Use dict[key] for required config keys and keys with default values. (#22829) --- .../components/mqtt/binary_sensor.py | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/mqtt/binary_sensor.py b/homeassistant/components/mqtt/binary_sensor.py index f942091984a..95daad9b262 100644 --- a/homeassistant/components/mqtt/binary_sensor.py +++ b/homeassistant/components/mqtt/binary_sensor.py @@ -32,17 +32,15 @@ DEFAULT_FORCE_UPDATE = False DEPENDENCIES = ['mqtt'] PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, - vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, + vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_OFF_DELAY): vol.All(vol.Coerce(int), vol.Range(min=0)), - # Integrations should never expose unique_id through configuration. - # This is an exception because MQTT is a message transport, not a protocol + vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, + vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) @@ -135,15 +133,15 @@ class MqttBinarySensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, if value_template is not None: payload = value_template.async_render_with_possible_json_value( payload, variables={'entity_id': self.entity_id}) - if payload == self._config.get(CONF_PAYLOAD_ON): + if payload == self._config[CONF_PAYLOAD_ON]: self._state = True - elif payload == self._config.get(CONF_PAYLOAD_OFF): + elif payload == self._config[CONF_PAYLOAD_OFF]: self._state = False else: # Payload is not for this entity _LOGGER.warning('No matching payload found' ' for entity: %s with state_topic: %s', - self._config.get(CONF_NAME), - self._config.get(CONF_STATE_TOPIC)) + self._config[CONF_NAME], + self._config[CONF_STATE_TOPIC]) return if self._delay_listener is not None: @@ -159,9 +157,9 @@ class MqttBinarySensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._sub_state = await subscription.async_subscribe_topics( self.hass, self._sub_state, - {'state_topic': {'topic': self._config.get(CONF_STATE_TOPIC), + {'state_topic': {'topic': self._config[CONF_STATE_TOPIC], 'msg_callback': state_message_received, - 'qos': self._config.get(CONF_QOS)}}) + 'qos': self._config[CONF_QOS]}}) async def async_will_remove_from_hass(self): """Unsubscribe when removed.""" @@ -178,7 +176,7 @@ class MqttBinarySensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def name(self): """Return the name of the binary sensor.""" - return self._config.get(CONF_NAME) + return self._config[CONF_NAME] @property def is_on(self): @@ -193,7 +191,7 @@ class MqttBinarySensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def force_update(self): """Force update.""" - return self._config.get(CONF_FORCE_UPDATE) + return self._config[CONF_FORCE_UPDATE] @property def unique_id(self): From fa2e07d7c5ba5543e2c8ab7d48b91dcba4127957 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Sun, 7 Apr 2019 16:11:45 +0200 Subject: [PATCH 142/167] Use dict[key] for required config keys and keys with default values. (#22830) --- homeassistant/components/mqtt/camera.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/mqtt/camera.py b/homeassistant/components/mqtt/camera.py index 34e83a51f28..f651050b6c8 100644 --- a/homeassistant/components/mqtt/camera.py +++ b/homeassistant/components/mqtt/camera.py @@ -26,9 +26,9 @@ DEFAULT_NAME = 'MQTT Camera' DEPENDENCIES = ['mqtt'] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Required(CONF_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string }) @@ -103,7 +103,7 @@ class MqttCamera(MqttDiscoveryUpdate, Camera): self._sub_state = await subscription.async_subscribe_topics( self.hass, self._sub_state, - {'state_topic': {'topic': self._config.get(CONF_TOPIC), + {'state_topic': {'topic': self._config[CONF_TOPIC], 'msg_callback': message_received, 'qos': self._qos, 'encoding': None}}) @@ -121,7 +121,7 @@ class MqttCamera(MqttDiscoveryUpdate, Camera): @property def name(self): """Return the name of this camera.""" - return self._config.get(CONF_NAME) + return self._config[CONF_NAME] @property def unique_id(self): From 02b7fd93ed2684cca2f5cf31229a99dcca317e1d Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Sun, 7 Apr 2019 07:37:27 -0700 Subject: [PATCH 143/167] Fix for rate limits should be optional (#22823) --- homeassistant/components/mobile_app/const.py | 5 ++++ homeassistant/components/mobile_app/notify.py | 28 +++++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/mobile_app/const.py b/homeassistant/components/mobile_app/const.py index 52ca0aa3993..31364ba063d 100644 --- a/homeassistant/components/mobile_app/const.py +++ b/homeassistant/components/mobile_app/const.py @@ -42,6 +42,11 @@ ATTR_OS_NAME = 'os_name' ATTR_OS_VERSION = 'os_version' ATTR_PUSH_TOKEN = 'push_token' ATTR_PUSH_URL = 'push_url' +ATTR_PUSH_RATE_LIMITS = 'rateLimits' +ATTR_PUSH_RATE_LIMITS_ERRORS = 'errors' +ATTR_PUSH_RATE_LIMITS_MAXIMUM = 'maximum' +ATTR_PUSH_RATE_LIMITS_RESETS_AT = 'resetsAt' +ATTR_PUSH_RATE_LIMITS_SUCCESSFUL = 'successful' ATTR_SUPPORTS_ENCRYPTION = 'supports_encryption' ATTR_EVENT_DATA = 'event_data' diff --git a/homeassistant/components/mobile_app/notify.py b/homeassistant/components/mobile_app/notify.py index 0120b1a6ffb..8d2ac1b97ec 100644 --- a/homeassistant/components/mobile_app/notify.py +++ b/homeassistant/components/mobile_app/notify.py @@ -8,13 +8,18 @@ import async_timeout from homeassistant.components.notify import ( ATTR_DATA, ATTR_MESSAGE, ATTR_TARGET, ATTR_TITLE, ATTR_TITLE_DEFAULT, BaseNotificationService) -from homeassistant.components.mobile_app.const import ( - ATTR_APP_DATA, ATTR_APP_ID, ATTR_APP_VERSION, ATTR_DEVICE_NAME, - ATTR_OS_VERSION, ATTR_PUSH_TOKEN, ATTR_PUSH_URL, DATA_CONFIG_ENTRIES, - DOMAIN) + from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.util.dt as dt_util +from .const import (ATTR_APP_DATA, ATTR_APP_ID, ATTR_APP_VERSION, + ATTR_DEVICE_NAME, ATTR_OS_VERSION, ATTR_PUSH_RATE_LIMITS, + ATTR_PUSH_RATE_LIMITS_ERRORS, + ATTR_PUSH_RATE_LIMITS_MAXIMUM, + ATTR_PUSH_RATE_LIMITS_RESETS_AT, + ATTR_PUSH_RATE_LIMITS_SUCCESSFUL, ATTR_PUSH_TOKEN, + ATTR_PUSH_URL, DATA_CONFIG_ENTRIES, DOMAIN) + _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['mobile_app'] @@ -38,16 +43,21 @@ def push_registrations(hass): # pylint: disable=invalid-name def log_rate_limits(hass, device_name, resp, level=logging.INFO): """Output rate limit log line at given level.""" - rate_limits = resp['rateLimits'] - resetsAt = dt_util.parse_datetime(rate_limits['resetsAt']) - resetsAtTime = resetsAt - datetime.now(timezone.utc) + if ATTR_PUSH_RATE_LIMITS not in resp: + return + + rate_limits = resp[ATTR_PUSH_RATE_LIMITS] + resetsAt = rate_limits[ATTR_PUSH_RATE_LIMITS_RESETS_AT] + resetsAtTime = (dt_util.parse_datetime(resetsAt) - + datetime.now(timezone.utc)) rate_limit_msg = ("mobile_app push notification rate limits for %s: " "%d sent, %d allowed, %d errors, " "resets in %s") _LOGGER.log(level, rate_limit_msg, device_name, - rate_limits['successful'], - rate_limits['maximum'], rate_limits['errors'], + rate_limits[ATTR_PUSH_RATE_LIMITS_SUCCESSFUL], + rate_limits[ATTR_PUSH_RATE_LIMITS_MAXIMUM], + rate_limits[ATTR_PUSH_RATE_LIMITS_ERRORS], str(resetsAtTime).split(".")[0]) From c7a49e0820a5f1c7b4eae1e49c7a219fda4267c4 Mon Sep 17 00:00:00 2001 From: roblandry Date: Sun, 7 Apr 2019 13:07:05 -0400 Subject: [PATCH 144/167] Fix glances docker container errors (#22846) * Fix unavailable container errors * Update to dev * Use const --- homeassistant/components/glances/sensor.py | 41 ++++++++++++++-------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/glances/sensor.py b/homeassistant/components/glances/sensor.py index e59b9144b4c..db8f0397887 100644 --- a/homeassistant/components/glances/sensor.py +++ b/homeassistant/components/glances/sensor.py @@ -7,7 +7,7 @@ import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( CONF_HOST, CONF_NAME, CONF_PORT, CONF_USERNAME, CONF_PASSWORD, CONF_SSL, - CONF_VERIFY_SSL, CONF_RESOURCES, TEMP_CELSIUS) + CONF_VERIFY_SSL, CONF_RESOURCES, STATE_UNAVAILABLE, TEMP_CELSIUS) from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv @@ -183,21 +183,34 @@ class GlancesSensor(Entity): self._state = sensor['value'] elif self.type == 'docker_active': count = 0 - for container in value['docker']['containers']: - if container['Status'] == 'running' or \ - 'Up' in container['Status']: - count += 1 - self._state = count + try: + for container in value['docker']['containers']: + if container['Status'] == 'running' or \ + 'Up' in container['Status']: + count += 1 + self._state = count + except KeyError: + self._state = count elif self.type == 'docker_cpu_use': - use = 0.0 - for container in value['docker']['containers']: - use += container['cpu']['total'] - self._state = round(use, 1) + cpu_use = 0.0 + try: + for container in value['docker']['containers']: + if container['Status'] == 'running' or \ + 'Up' in container['Status']: + cpu_use += container['cpu']['total'] + self._state = round(cpu_use, 1) + except KeyError: + self._state = STATE_UNAVAILABLE elif self.type == 'docker_memory_use': - use = 0.0 - for container in value['docker']['containers']: - use += container['memory']['usage'] - self._state = round(use / 1024**2, 1) + mem_use = 0.0 + try: + for container in value['docker']['containers']: + if container['Status'] == 'running' or \ + 'Up' in container['Status']: + mem_use += container['memory']['usage'] + self._state = round(mem_use / 1024**2, 1) + except KeyError: + self._state = STATE_UNAVAILABLE class GlancesData: From 3fde1d3bab11dff8e46520c2797d978a973cac0c Mon Sep 17 00:00:00 2001 From: Jason Hunter Date: Sun, 7 Apr 2019 13:08:08 -0400 Subject: [PATCH 145/167] coerce duration and lookback to int so they can be used in template automation (#22819) --- homeassistant/components/camera/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 10739a1c7bb..2ddab537acc 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -83,8 +83,8 @@ CAMERA_SERVICE_PLAY_STREAM = CAMERA_SERVICE_SCHEMA.extend({ CAMERA_SERVICE_RECORD = CAMERA_SERVICE_SCHEMA.extend({ vol.Required(CONF_FILENAME): cv.template, - vol.Optional(CONF_DURATION, default=30): int, - vol.Optional(CONF_LOOKBACK, default=0): int, + vol.Optional(CONF_DURATION, default=30): vol.Coerce(int), + vol.Optional(CONF_LOOKBACK, default=0): vol.Coerce(int), }) WS_TYPE_CAMERA_THUMBNAIL = 'camera_thumbnail' From abe85c73ae73e309742bdec10cc3fd3845446a5e Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sun, 7 Apr 2019 12:42:16 -0700 Subject: [PATCH 146/167] Fix flaky test (#22850) --- tests/components/stream/test_hls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/stream/test_hls.py b/tests/components/stream/test_hls.py index a2c962ffb45..9d898d96d78 100644 --- a/tests/components/stream/test_hls.py +++ b/tests/components/stream/test_hls.py @@ -110,7 +110,7 @@ async def test_stream_ended(hass): while await track.recv() is not None: segments += 1 - assert segments == 3 + assert segments > 1 assert not track.get_segment() # Stop stream, if it hasn't quit already From e407226afc13122a1f846345b6ecc27fb814a36d Mon Sep 17 00:00:00 2001 From: zewelor Date: Sun, 7 Apr 2019 22:05:38 +0200 Subject: [PATCH 147/167] Fix yeelight possible array change during iteration (#22849) --- homeassistant/components/yeelight/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/yeelight/__init__.py b/homeassistant/components/yeelight/__init__.py index dc79e9357ff..9b9778fd5d2 100644 --- a/homeassistant/components/yeelight/__init__.py +++ b/homeassistant/components/yeelight/__init__.py @@ -134,7 +134,7 @@ def setup(hass, config): discovery.listen(hass, SERVICE_YEELIGHT, device_discovered) def update(event): - for device in yeelight_data.values(): + for device in list(yeelight_data.values()): device.update() track_time_interval( From a40a0c40426e96549560b122eefdb3782578a27e Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Sun, 7 Apr 2019 14:21:29 -0600 Subject: [PATCH 148/167] Bump aioambient to 0.3.0 (#22855) * Bump aioambient to 0.3.0 * Updated requirements * Removed old REQUIREMENTS reference --- homeassistant/components/ambient_station/__init__.py | 2 -- homeassistant/components/ambient_station/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/ambient_station/__init__.py b/homeassistant/components/ambient_station/__init__.py index cb0a2067d9f..a715ded1bb7 100644 --- a/homeassistant/components/ambient_station/__init__.py +++ b/homeassistant/components/ambient_station/__init__.py @@ -20,8 +20,6 @@ from .const import ( ATTR_LAST_DATA, CONF_APP_KEY, DATA_CLIENT, DOMAIN, TOPIC_UPDATE, TYPE_BINARY_SENSOR, TYPE_SENSOR) -REQUIREMENTS = ['aioambient==0.2.0'] - _LOGGER = logging.getLogger(__name__) DATA_CONFIG = 'config' diff --git a/homeassistant/components/ambient_station/manifest.json b/homeassistant/components/ambient_station/manifest.json index 13a74fec26e..11d2ad3668e 100644 --- a/homeassistant/components/ambient_station/manifest.json +++ b/homeassistant/components/ambient_station/manifest.json @@ -3,7 +3,7 @@ "name": "Ambient station", "documentation": "https://www.home-assistant.io/components/ambient_station", "requirements": [ - "aioambient==0.1.3" + "aioambient==0.3.0" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index 265ff9de860..926549160a2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -97,7 +97,7 @@ abodepy==0.15.0 afsapi==0.0.4 # homeassistant.components.ambient_station -aioambient==0.1.3 +aioambient==0.3.0 # homeassistant.components.asuswrt aioasuswrt==1.1.21 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 54b6230ae81..c9890f92626 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -36,7 +36,7 @@ PyTransportNSW==0.1.1 YesssSMS==0.2.3 # homeassistant.components.ambient_station -aioambient==0.1.3 +aioambient==0.3.0 # homeassistant.components.automatic aioautomatic==0.6.5 From 3086e1d39d32e98957485cebf9ec8d21251fd93b Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Sun, 7 Apr 2019 22:03:38 -0400 Subject: [PATCH 149/167] get temp and color for light during init and poll (#22847) --- .../components/zha/core/channels/lighting.py | 4 ++++ homeassistant/components/zha/light.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/homeassistant/components/zha/core/channels/lighting.py b/homeassistant/components/zha/core/channels/lighting.py index 696a15b483b..c7cbdc67db9 100644 --- a/homeassistant/components/zha/core/channels/lighting.py +++ b/homeassistant/components/zha/core/channels/lighting.py @@ -33,6 +33,10 @@ class ColorChannel(ZigbeeChannel): async def async_initialize(self, from_cache): """Initialize channel.""" await self.fetch_color_capabilities(True) + await self.get_attribute_value( + 'color_temperature', from_cache=from_cache) + await self.get_attribute_value('current_x', from_cache=from_cache) + await self.get_attribute_value('current_y', from_cache=from_cache) async def fetch_color_capabilities(self, from_cache): """Get the color configuration.""" diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index cebc18e6a3e..eadc9e03af0 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -253,6 +253,20 @@ class Light(ZhaEntity, light.Light): if self._level_channel: self._brightness = await self._level_channel.get_attribute_value( 'current_level', from_cache=from_cache) + if self._color_channel: + color_capabilities = self._color_channel.get_color_capabilities() + if color_capabilities is not None and\ + color_capabilities & CAPABILITIES_COLOR_TEMP: + self._color_temp = await\ + self._color_channel.get_attribute_value( + 'color_temperature', from_cache=from_cache) + if color_capabilities is not None and\ + color_capabilities & CAPABILITIES_COLOR_XY: + color_x = await self._color_channel.get_attribute_value( + 'current_x', from_cache=from_cache) + color_y = await self._color_channel.get_attribute_value( + 'current_y', from_cache=from_cache) + self._hs_color = color_util.color_xy_to_hs(color_x, color_y) async def refresh(self, time): """Call async_get_state at an interval.""" From 8bebd8583f78ce3a829b7f7517b9181f7ef35e5c Mon Sep 17 00:00:00 2001 From: cdce8p <30130371+cdce8p@users.noreply.github.com> Date: Mon, 8 Apr 2019 06:01:05 +0200 Subject: [PATCH 150/167] Fix manifest codeowners (#22871) * Added individual files section * Replaced some manifest/codeowners --- CODEOWNERS | 8 ++++++-- homeassistant/components/cover/manifest.json | 2 +- homeassistant/components/demo/manifest.json | 2 +- script/manifest/codeowners.py | 8 ++++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index a5c06f991c9..6ce7388e0d1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -45,13 +45,13 @@ homeassistant/components/configurator/* @home-assistant/core homeassistant/components/conversation/* @home-assistant/core homeassistant/components/coolmaster/* @OnFreund homeassistant/components/counter/* @fabaff -homeassistant/components/cover/* @cdce8p +homeassistant/components/cover/* @home-assistant/core homeassistant/components/cpuspeed/* @fabaff homeassistant/components/cups/* @fabaff homeassistant/components/daikin/* @fredrike @rofrantz homeassistant/components/darksky/* @fabaff homeassistant/components/deconz/* @kane610 -homeassistant/components/demo/* @fabaff +homeassistant/components/demo/* @home-assistant/core homeassistant/components/digital_ocean/* @fabaff homeassistant/components/discogs/* @thibmaek homeassistant/components/doorbird/* @oblogic7 @@ -243,3 +243,7 @@ homeassistant/components/zha/* @dmulcahey @adminiuga homeassistant/components/zone/* @home-assistant/core homeassistant/components/zoneminder/* @rohankapoorcom homeassistant/components/zwave/* @home-assistant/z-wave + +# Individual files +homeassistant/components/group/cover @cdce8p +homeassistant/components/demo/weather @fabaff diff --git a/homeassistant/components/cover/manifest.json b/homeassistant/components/cover/manifest.json index f39f7fb0650..da5a644334c 100644 --- a/homeassistant/components/cover/manifest.json +++ b/homeassistant/components/cover/manifest.json @@ -7,6 +7,6 @@ "group" ], "codeowners": [ - "@cdce8p" + "@home-assistant/core" ] } diff --git a/homeassistant/components/demo/manifest.json b/homeassistant/components/demo/manifest.json index 08cf75a3c53..859cac597dc 100644 --- a/homeassistant/components/demo/manifest.json +++ b/homeassistant/components/demo/manifest.json @@ -9,6 +9,6 @@ "zone" ], "codeowners": [ - "@fabaff" + "@home-assistant/core" ] } diff --git a/script/manifest/codeowners.py b/script/manifest/codeowners.py index 9745f3b82f2..96b2b252e3d 100755 --- a/script/manifest/codeowners.py +++ b/script/manifest/codeowners.py @@ -27,6 +27,12 @@ homeassistant/scripts/check_config.py @kellerza # Integrations """ +INDIVIDUAL_FILES = """ +# Individual files +homeassistant/components/group/cover @cdce8p +homeassistant/components/demo/weather @fabaff +""" + def generate(): """Generate CODEOWNERS.""" @@ -39,6 +45,8 @@ def generate(): parts.append("homeassistant/components/{}/* {}".format( manifest['domain'], ' '.join(manifest['codeowners']))) + parts.append('\n' + INDIVIDUAL_FILES.strip()) + return '\n'.join(parts) From 4982c0b196890ca69167d2a4ef51af3a08739d35 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Sun, 7 Apr 2019 22:02:03 -0600 Subject: [PATCH 151/167] Added REQUIREMENTS back to Ambient (#22875) --- homeassistant/components/ambient_station/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/ambient_station/__init__.py b/homeassistant/components/ambient_station/__init__.py index a715ded1bb7..6dee4637a96 100644 --- a/homeassistant/components/ambient_station/__init__.py +++ b/homeassistant/components/ambient_station/__init__.py @@ -20,6 +20,8 @@ from .const import ( ATTR_LAST_DATA, CONF_APP_KEY, DATA_CLIENT, DOMAIN, TOPIC_UPDATE, TYPE_BINARY_SENSOR, TYPE_SENSOR) +REQUIREMENTS = ['aioambient==0.3.0'] + _LOGGER = logging.getLogger(__name__) DATA_CONFIG = 'config' From 2d287d2abe2ac4c465383f1a33a2a381652473db Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 8 Apr 2019 09:22:55 +0200 Subject: [PATCH 152/167] Fix content_type handling ingress (#22864) --- homeassistant/components/hassio/ingress.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/hassio/ingress.py b/homeassistant/components/hassio/ingress.py index 91224c6f54d..4f7c99618c1 100644 --- a/homeassistant/components/hassio/ingress.py +++ b/homeassistant/components/hassio/ingress.py @@ -118,6 +118,7 @@ class HassIOIngress(HomeAssistantView): return web.Response( headers=headers, status=result.status, + content_type=result.content_type, body=body ) @@ -145,8 +146,7 @@ def _init_header( # filter flags for name, value in request.headers.items(): - if name in (hdrs.CONTENT_LENGTH, hdrs.CONTENT_TYPE, - hdrs.CONTENT_ENCODING): + if name in (hdrs.CONTENT_LENGTH, hdrs.CONTENT_ENCODING): continue headers[name] = value From 137d80452dd9262870dfcf440551b092fe1b817c Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Mon, 8 Apr 2019 01:13:26 -0700 Subject: [PATCH 153/167] Minor sensor fixes (#22884) * Minor sensor fixes * Fix tests --- homeassistant/components/mobile_app/const.py | 2 +- homeassistant/components/mobile_app/sensor.py | 2 +- homeassistant/components/mobile_app/webhook.py | 4 ++-- tests/components/mobile_app/test_entity.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/mobile_app/const.py b/homeassistant/components/mobile_app/const.py index 31364ba063d..05d240da909 100644 --- a/homeassistant/components/mobile_app/const.py +++ b/homeassistant/components/mobile_app/const.py @@ -171,7 +171,7 @@ REGISTER_SENSOR_SCHEMA = vol.Schema({ vol.Required(ATTR_SENSOR_NAME): cv.string, vol.Required(ATTR_SENSOR_TYPE): vol.In(SENSOR_TYPES), vol.Required(ATTR_SENSOR_UNIQUE_ID): cv.string, - vol.Required(ATTR_SENSOR_UOM): cv.string, + vol.Optional(ATTR_SENSOR_UOM): cv.string, vol.Required(ATTR_SENSOR_STATE): vol.Any(bool, str, int, float), vol.Optional(ATTR_SENSOR_ICON, default='mdi:cellphone'): cv.icon, }) diff --git a/homeassistant/components/mobile_app/sensor.py b/homeassistant/components/mobile_app/sensor.py index c6a53ce57ec..b2846a6002b 100644 --- a/homeassistant/components/mobile_app/sensor.py +++ b/homeassistant/components/mobile_app/sensor.py @@ -55,4 +55,4 @@ class MobileAppSensor(MobileAppEntity): @property def unit_of_measurement(self): """Return the unit of measurement this sensor expresses itself in.""" - return self._config[ATTR_SENSOR_UOM] + return self._config.get(ATTR_SENSOR_UOM) diff --git a/homeassistant/components/mobile_app/webhook.py b/homeassistant/components/mobile_app/webhook.py index 7a83ba4e978..28ef6bccd6a 100644 --- a/homeassistant/components/mobile_app/webhook.py +++ b/homeassistant/components/mobile_app/webhook.py @@ -228,7 +228,7 @@ async def handle_webhook(hass: HomeAssistantType, webhook_id: str, data[ATTR_SENSOR_TYPE]) async_dispatcher_send(hass, register_signal, data) - return webhook_response({"status": "registered"}, + return webhook_response({'success': True}, registration=registration, status=HTTP_CREATED, headers=headers) @@ -271,7 +271,7 @@ async def handle_webhook(hass: HomeAssistantType, webhook_id: str, async_dispatcher_send(hass, SIGNAL_SENSOR_UPDATE, new_state) - resp[unique_id] = {"status": "okay"} + resp[unique_id] = {'success': True} return webhook_response(resp, registration=registration, headers=headers) diff --git a/tests/components/mobile_app/test_entity.py b/tests/components/mobile_app/test_entity.py index 5dc285cfe9e..3d8e575f686 100644 --- a/tests/components/mobile_app/test_entity.py +++ b/tests/components/mobile_app/test_entity.py @@ -35,7 +35,7 @@ async def test_sensor(hass, create_registrations, webhook_client): # noqa: F401 assert reg_resp.status == 201 json = await reg_resp.json() - assert json == {'status': 'registered'} + assert json == {'success': True} entity = hass.states.get('sensor.battery_state') assert entity is not None @@ -122,7 +122,7 @@ async def test_sensor_id_no_dupes(hass, create_registrations, # noqa: F401, F81 assert reg_resp.status == 201 reg_json = await reg_resp.json() - assert reg_json == {'status': 'registered'} + assert reg_json == {'success': True} dupe_resp = await webhook_client.post(webhook_url, json=payload) From a4ffc9e37aacace178c470278e938e504f852212 Mon Sep 17 00:00:00 2001 From: Finbarr Brady Date: Mon, 8 Apr 2019 13:48:19 +0100 Subject: [PATCH 154/167] add myself as codeowner (#22885) --- CODEOWNERS | 7 +++++++ homeassistant/components/cisco_ios/manifest.json | 2 +- .../components/cisco_mobility_express/manifest.json | 2 +- homeassistant/components/cisco_webex_teams/manifest.json | 2 +- homeassistant/components/ciscospark/manifest.json | 2 +- homeassistant/components/enigma2/manifest.json | 2 +- homeassistant/components/hikvisioncam/manifest.json | 2 +- homeassistant/components/luci/manifest.json | 2 +- 8 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 6ce7388e0d1..30a91a7c76d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -38,6 +38,10 @@ homeassistant/components/braviatv/* @robbiet480 homeassistant/components/broadlink/* @danielhiversen homeassistant/components/brunt/* @eavanvalkenburg homeassistant/components/bt_smarthub/* @jxwolstenholme +homeassistant/components/cisco_ios/* @fbradyirl +homeassistant/components/cisco_mobility_express/* @fbradyirl +homeassistant/components/cisco_webex_teams/* @fbradyirl +homeassistant/components/ciscospark/* @fbradyirl homeassistant/components/cloud/* @home-assistant/core homeassistant/components/cloudflare/* @ludeeus homeassistant/components/config/* @home-assistant/core @@ -61,6 +65,7 @@ homeassistant/components/edp_redy/* @abmantis homeassistant/components/egardia/* @jeroenterheerdt homeassistant/components/eight_sleep/* @mezz64 homeassistant/components/emby/* @mezz64 +homeassistant/components/enigma2/* @fbradyirl homeassistant/components/ephember/* @ttroy50 homeassistant/components/eq3btsmart/* @rytilahti homeassistant/components/esphome/* @OttoWinter @@ -86,6 +91,7 @@ homeassistant/components/harmony/* @ehendrix23 homeassistant/components/hassio/* @home-assistant/hass-io homeassistant/components/heos/* @andrewsayre homeassistant/components/hikvision/* @mezz64 +homeassistant/components/hikvisioncam/* @fbradyirl homeassistant/components/history/* @home-assistant/core homeassistant/components/history_graph/* @andrey-git homeassistant/components/hive/* @Rendili @KJonline @@ -120,6 +126,7 @@ homeassistant/components/linux_battery/* @fabaff homeassistant/components/liveboxplaytv/* @pschmitt homeassistant/components/logger/* @home-assistant/core homeassistant/components/lovelace/* @home-assistant/core +homeassistant/components/luci/* @fbradyirl homeassistant/components/luftdaten/* @fabaff homeassistant/components/mastodon/* @fabaff homeassistant/components/matrix/* @tinloaf diff --git a/homeassistant/components/cisco_ios/manifest.json b/homeassistant/components/cisco_ios/manifest.json index d1a9e9933b9..9a12ba252e3 100644 --- a/homeassistant/components/cisco_ios/manifest.json +++ b/homeassistant/components/cisco_ios/manifest.json @@ -6,5 +6,5 @@ "pexpect==4.6.0" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@fbradyirl"] } diff --git a/homeassistant/components/cisco_mobility_express/manifest.json b/homeassistant/components/cisco_mobility_express/manifest.json index 6bd56ccd15e..d1b4687c2cd 100644 --- a/homeassistant/components/cisco_mobility_express/manifest.json +++ b/homeassistant/components/cisco_mobility_express/manifest.json @@ -6,5 +6,5 @@ "ciscomobilityexpress==0.1.5" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@fbradyirl"] } diff --git a/homeassistant/components/cisco_webex_teams/manifest.json b/homeassistant/components/cisco_webex_teams/manifest.json index d13b893ce69..21c4efe071c 100644 --- a/homeassistant/components/cisco_webex_teams/manifest.json +++ b/homeassistant/components/cisco_webex_teams/manifest.json @@ -6,5 +6,5 @@ "webexteamssdk==1.1.1" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@fbradyirl"] } diff --git a/homeassistant/components/ciscospark/manifest.json b/homeassistant/components/ciscospark/manifest.json index c6b0c42e89c..926925a7bf1 100644 --- a/homeassistant/components/ciscospark/manifest.json +++ b/homeassistant/components/ciscospark/manifest.json @@ -6,5 +6,5 @@ "ciscosparkapi==0.4.2" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@fbradyirl"] } diff --git a/homeassistant/components/enigma2/manifest.json b/homeassistant/components/enigma2/manifest.json index 78eb9f9deff..6619e6c1f0d 100644 --- a/homeassistant/components/enigma2/manifest.json +++ b/homeassistant/components/enigma2/manifest.json @@ -6,5 +6,5 @@ "openwebifpy==3.1.0" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@fbradyirl"] } diff --git a/homeassistant/components/hikvisioncam/manifest.json b/homeassistant/components/hikvisioncam/manifest.json index ec63425572d..f2bb0822d17 100644 --- a/homeassistant/components/hikvisioncam/manifest.json +++ b/homeassistant/components/hikvisioncam/manifest.json @@ -6,5 +6,5 @@ "hikvision==0.4" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@fbradyirl"] } diff --git a/homeassistant/components/luci/manifest.json b/homeassistant/components/luci/manifest.json index 46e1702c36e..13b8b172a5d 100644 --- a/homeassistant/components/luci/manifest.json +++ b/homeassistant/components/luci/manifest.json @@ -6,5 +6,5 @@ "openwrt-luci-rpc==1.0.5" ], "dependencies": [], - "codeowners": [] + "codeowners": ["@fbradyirl"] } From a0d6e08421c0e1a903f3a5e7befd882f3de6f402 Mon Sep 17 00:00:00 2001 From: Finbarr Brady Date: Mon, 8 Apr 2019 13:49:52 +0100 Subject: [PATCH 155/167] Bump pypi module version for enigma2 (#22886) * Bug fix for #22727 * Update requirements_all.txt * Update manifest.json --- homeassistant/components/enigma2/manifest.json | 2 +- homeassistant/components/enigma2/media_player.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/enigma2/manifest.json b/homeassistant/components/enigma2/manifest.json index 6619e6c1f0d..d523bd72b72 100644 --- a/homeassistant/components/enigma2/manifest.json +++ b/homeassistant/components/enigma2/manifest.json @@ -3,7 +3,7 @@ "name": "Enigma2", "documentation": "https://www.home-assistant.io/components/enigma2", "requirements": [ - "openwebifpy==3.1.0" + "openwebifpy==3.1.1" ], "dependencies": [], "codeowners": ["@fbradyirl"] diff --git a/homeassistant/components/enigma2/media_player.py b/homeassistant/components/enigma2/media_player.py index 0b6f995be97..11c3e0fe3ce 100644 --- a/homeassistant/components/enigma2/media_player.py +++ b/homeassistant/components/enigma2/media_player.py @@ -14,7 +14,7 @@ from homeassistant.const import ( STATE_OFF, STATE_ON, STATE_PLAYING, CONF_PORT) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['openwebifpy==3.1.0'] +REQUIREMENTS = ['openwebifpy==3.1.1'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 926549160a2..ddab662c1d5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -779,7 +779,7 @@ openhomedevice==0.4.2 opensensemap-api==0.1.5 # homeassistant.components.enigma2 -openwebifpy==3.1.0 +openwebifpy==3.1.1 # homeassistant.components.luci openwrt-luci-rpc==1.0.5 From 45a43592bd7ac664fd3509afa15f4c2ede2ad785 Mon Sep 17 00:00:00 2001 From: John Raahauge <43510812+AZDane@users.noreply.github.com> Date: Mon, 8 Apr 2019 05:53:00 -0700 Subject: [PATCH 156/167] Fix position of add_entities of binary sensor (#22866) * Bugfix - binary_sensor.py * Added features to Concord232 Alarm Panel * Added New Line End Of File * Deleted Whitespace * Back to original Removed added feature and sticking to bugfix --- homeassistant/components/concord232/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/concord232/binary_sensor.py b/homeassistant/components/concord232/binary_sensor.py index 5aff0f09983..c1a31eb9ead 100644 --- a/homeassistant/components/concord232/binary_sensor.py +++ b/homeassistant/components/concord232/binary_sensor.py @@ -74,7 +74,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): ) ) - add_entities(sensors, True) + add_entities(sensors, True) def get_opening_type(zone): From 8cc5cc7f43cdc76328869ab072535268701875dd Mon Sep 17 00:00:00 2001 From: cgtobi Date: Mon, 8 Apr 2019 15:18:52 +0200 Subject: [PATCH 157/167] Add zwave network key validator (#22785) * Add zwave network key validator * Move validator to zwave component * Move validator to zwave component * Move stuff * Move stuff * Remove helper and replace with voluptuous method * Add test * Fix long line * Improve tests * Add more negative tests * Remove unnecessary assertion * Make the linter happy * Remove print --- homeassistant/components/zwave/__init__.py | 3 ++- tests/components/zwave/test_init.py | 30 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index aca36aabd3b..6028e5547c6 100644 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -159,7 +159,8 @@ CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Optional(CONF_AUTOHEAL, default=DEFAULT_CONF_AUTOHEAL): cv.boolean, vol.Optional(CONF_CONFIG_PATH): cv.string, - vol.Optional(CONF_NETWORK_KEY): cv.string, + vol.Optional(CONF_NETWORK_KEY): + vol.All(cv.string, vol.Match(r'(0x\w\w,\s?){15}0x\w\w')), vol.Optional(CONF_DEVICE_CONFIG, default={}): vol.Schema({cv.entity_id: DEVICE_CONFIG_SCHEMA_ENTRY}), vol.Optional(CONF_DEVICE_CONFIG_GLOB, default={}): diff --git a/tests/components/zwave/test_init.py b/tests/components/zwave/test_init.py index 66011f3e6ee..3f0c082591c 100644 --- a/tests/components/zwave/test_init.py +++ b/tests/components/zwave/test_init.py @@ -3,6 +3,7 @@ import asyncio from collections import OrderedDict from datetime import datetime from pytz import utc +import voluptuous as vol import unittest from unittest.mock import patch, MagicMock @@ -83,6 +84,35 @@ async def test_network_options(hass, mock_openzwave): assert network.options.config_path == 'mock_config_path' +async def test_network_key_validation(hass, mock_openzwave): + """Test network key validation.""" + test_values = [ + ('0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, ' + '0x0C, 0x0D, 0x0E, 0x0F, 0x10'), + ('0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,' + '0x0E,0x0F,0x10'), + ] + for value in test_values: + result = zwave.CONFIG_SCHEMA({'zwave': {'network_key': value}}) + assert result['zwave']['network_key'] == value + + +async def test_erronous_network_key_fails_validation(hass, mock_openzwave): + """Test failing erronous network key validation.""" + test_values = [ + ('0x 01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, ' + '0x0C, 0x0D, 0x0E, 0x0F, 0x10'), + ('0X01,0X02,0X03,0X04,0X05,0X06,0X07,0X08,0X09,0X0A,0X0B,0X0C,0X0D,' + '0X0E,0X0F,0X10'), + 'invalid', + '1234567', + 1234567 + ] + for value in test_values: + with pytest.raises(vol.Invalid): + zwave.CONFIG_SCHEMA({'zwave': {'network_key': value}}) + + async def test_auto_heal_midnight(hass, mock_openzwave): """Test network auto-heal at midnight.""" await async_setup_component(hass, 'zwave', { From d8c716037775c1e2c68a9fcd86640153b07f1c57 Mon Sep 17 00:00:00 2001 From: akasma74 Date: Mon, 8 Apr 2019 16:21:13 +0300 Subject: [PATCH 158/167] force_update=False (not None) (#22867) because force_update: boolean --- homeassistant/components/rflink/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/rflink/binary_sensor.py b/homeassistant/components/rflink/binary_sensor.py index e98fb756659..4e487eb6e81 100644 --- a/homeassistant/components/rflink/binary_sensor.py +++ b/homeassistant/components/rflink/binary_sensor.py @@ -53,7 +53,7 @@ class RflinkBinarySensor(RflinkDevice, BinarySensorDevice): """Representation of an Rflink binary sensor.""" def __init__(self, device_id, device_class=None, - force_update=None, off_delay=None, + force_update=False, off_delay=None, **kwargs): """Handle sensor specific args and super init.""" self._state = None From 36c135c785f7daa9f739103befbff68d38f86a1a Mon Sep 17 00:00:00 2001 From: Matt Snyder Date: Mon, 8 Apr 2019 08:22:31 -0500 Subject: [PATCH 159/167] Stream support for Doorbird component (#22876) * Support stream source for doorbird live camera * Support stream source for doorbird live camera * Support stream component on Doorbird camera entities * Bump library version * Update manifest * Lint * Correct parameter order --- homeassistant/components/doorbird/__init__.py | 2 +- homeassistant/components/doorbird/camera.py | 19 ++++++++++++++++--- .../components/doorbird/manifest.json | 2 +- requirements_all.txt | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/doorbird/__init__.py b/homeassistant/components/doorbird/__init__.py index d477836425d..25a2c5caff9 100644 --- a/homeassistant/components/doorbird/__init__.py +++ b/homeassistant/components/doorbird/__init__.py @@ -11,7 +11,7 @@ from homeassistant.const import ( import homeassistant.helpers.config_validation as cv from homeassistant.util import dt as dt_util, slugify -REQUIREMENTS = ['doorbirdpy==2.0.6'] +REQUIREMENTS = ['doorbirdpy==2.0.8'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/doorbird/camera.py b/homeassistant/components/doorbird/camera.py index 272a3cb932a..a93b0fbf194 100644 --- a/homeassistant/components/doorbird/camera.py +++ b/homeassistant/components/doorbird/camera.py @@ -6,7 +6,7 @@ import logging import aiohttp import async_timeout -from homeassistant.components.camera import Camera +from homeassistant.components.camera import Camera, SUPPORT_STREAM from homeassistant.helpers.aiohttp_client import async_get_clientsession from . import DOMAIN as DOORBIRD_DOMAIN @@ -32,7 +32,8 @@ async def async_setup_platform(hass, config, async_add_entities, DoorBirdCamera( device.live_image_url, _CAMERA_LIVE.format(doorstation.name), - _LIVE_INTERVAL), + _LIVE_INTERVAL, + device.rtsp_live_video_url), DoorBirdCamera( device.history_image_url(1, 'doorbell'), _CAMERA_LAST_VISITOR.format(doorstation.name), @@ -47,15 +48,27 @@ async def async_setup_platform(hass, config, async_add_entities, class DoorBirdCamera(Camera): """The camera on a DoorBird device.""" - def __init__(self, url, name, interval=None): + def __init__(self, url, name, interval=None, stream_url=None): """Initialize the camera on a DoorBird device.""" self._url = url + self._stream_url = stream_url self._name = name self._last_image = None + self._supported_features = SUPPORT_STREAM if self._stream_url else 0 self._interval = interval or datetime.timedelta self._last_update = datetime.datetime.min super().__init__() + @property + def stream_source(self): + """Return the stream source.""" + return self._stream_url + + @property + def supported_features(self): + """Return supported features.""" + return self._supported_features + @property def name(self): """Get the name of the camera.""" diff --git a/homeassistant/components/doorbird/manifest.json b/homeassistant/components/doorbird/manifest.json index f65af20f93c..3fb9fdc753b 100644 --- a/homeassistant/components/doorbird/manifest.json +++ b/homeassistant/components/doorbird/manifest.json @@ -3,7 +3,7 @@ "name": "Doorbird", "documentation": "https://www.home-assistant.io/components/doorbird", "requirements": [ - "doorbirdpy==2.0.6" + "doorbirdpy==2.0.8" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index ddab662c1d5..de505dec18f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -344,7 +344,7 @@ distro==1.4.0 dlipower==0.7.165 # homeassistant.components.doorbird -doorbirdpy==2.0.6 +doorbirdpy==2.0.8 # homeassistant.components.dovado dovado==0.4.1 From c9ec166f4b79cd59f501b358eacf344d1f590943 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 8 Apr 2019 15:28:42 +0200 Subject: [PATCH 160/167] Add MQTT climate two-point target temperature support (#22860) * Add MQTT climate two-point target temperature support * Sort * Fix test --- homeassistant/components/mqtt/climate.py | 104 ++++++++++++++++++++++- tests/components/mqtt/test_climate.py | 69 ++++++++++++++- 2 files changed, 170 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/mqtt/climate.py b/homeassistant/components/mqtt/climate.py index 0f4229c8688..17d32984bb5 100644 --- a/homeassistant/components/mqtt/climate.py +++ b/homeassistant/components/mqtt/climate.py @@ -10,7 +10,10 @@ from homeassistant.components.climate.const import ( ATTR_OPERATION_MODE, DEFAULT_MAX_TEMP, DEFAULT_MIN_TEMP, STATE_AUTO, STATE_COOL, STATE_DRY, STATE_FAN_ONLY, STATE_HEAT, SUPPORT_AUX_HEAT, SUPPORT_AWAY_MODE, SUPPORT_FAN_MODE, SUPPORT_HOLD_MODE, - SUPPORT_OPERATION_MODE, SUPPORT_SWING_MODE, SUPPORT_TARGET_TEMPERATURE) + SUPPORT_OPERATION_MODE, SUPPORT_SWING_MODE, SUPPORT_TARGET_TEMPERATURE, + ATTR_TARGET_TEMP_LOW, + ATTR_TARGET_TEMP_HIGH, SUPPORT_TARGET_TEMPERATURE_LOW, + SUPPORT_TARGET_TEMPERATURE_HIGH) from homeassistant.components.fan import SPEED_HIGH, SPEED_LOW, SPEED_MEDIUM from homeassistant.const import ( ATTR_TEMPERATURE, CONF_DEVICE, CONF_NAME, CONF_VALUE_TEMPLATE, STATE_OFF, @@ -41,6 +44,10 @@ CONF_MODE_STATE_TEMPLATE = 'mode_state_template' CONF_TEMPERATURE_COMMAND_TOPIC = 'temperature_command_topic' CONF_TEMPERATURE_STATE_TOPIC = 'temperature_state_topic' CONF_TEMPERATURE_STATE_TEMPLATE = 'temperature_state_template' +CONF_TEMPERATURE_LOW_COMMAND_TOPIC = 'temperature_low_command_topic' +CONF_TEMPERATURE_LOW_STATE_TOPIC = 'temperature_low_state_topic' +CONF_TEMPERATURE_HIGH_COMMAND_TOPIC = 'temperature_high_command_topic' +CONF_TEMPERATURE_HIGH_STATE_TOPIC = 'temperature_high_state_topic' CONF_FAN_MODE_COMMAND_TOPIC = 'fan_mode_command_topic' CONF_FAN_MODE_STATE_TOPIC = 'fan_mode_state_topic' CONF_FAN_MODE_STATE_TEMPLATE = 'fan_mode_state_template' @@ -130,6 +137,12 @@ PLATFORM_SCHEMA = SCHEMA_BASE.extend({ vol.Optional(CONF_TEMP_MAX, default=DEFAULT_MAX_TEMP): vol.Coerce(float), vol.Optional(CONF_TEMP_STEP, default=1.0): vol.Coerce(float), vol.Optional(CONF_TEMPERATURE_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_TEMPERATURE_HIGH_COMMAND_TOPIC): + mqtt.valid_publish_topic, + vol.Optional(CONF_TEMPERATURE_HIGH_STATE_TOPIC): + mqtt.valid_subscribe_topic, + vol.Optional(CONF_TEMPERATURE_LOW_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_TEMPERATURE_LOW_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_TEMPERATURE_STATE_TEMPLATE): cv.template, vol.Optional(CONF_TEMPERATURE_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_UNIQUE_ID): cv.string, @@ -186,6 +199,8 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, self._topic = None self._value_templates = None self._target_temperature = None + self._target_temperature_low = None + self._target_temperature_high = None self._current_fan_mode = None self._current_operation = None self._current_swing_mode = None @@ -230,6 +245,8 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, CONF_POWER_COMMAND_TOPIC, CONF_MODE_COMMAND_TOPIC, CONF_TEMPERATURE_COMMAND_TOPIC, + CONF_TEMPERATURE_LOW_COMMAND_TOPIC, + CONF_TEMPERATURE_HIGH_COMMAND_TOPIC, CONF_FAN_MODE_COMMAND_TOPIC, CONF_SWING_MODE_COMMAND_TOPIC, CONF_AWAY_MODE_COMMAND_TOPIC, @@ -238,6 +255,8 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, CONF_POWER_STATE_TOPIC, CONF_MODE_STATE_TOPIC, CONF_TEMPERATURE_STATE_TOPIC, + CONF_TEMPERATURE_LOW_STATE_TOPIC, + CONF_TEMPERATURE_HIGH_STATE_TOPIC, CONF_FAN_MODE_STATE_TOPIC, CONF_SWING_MODE_STATE_TOPIC, CONF_AWAY_MODE_STATE_TOPIC, @@ -250,8 +269,16 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, # set to None in non-optimistic mode self._target_temperature = self._current_fan_mode = \ self._current_operation = self._current_swing_mode = None + self._target_temperature_low = None + self._target_temperature_high = None + if self._topic[CONF_TEMPERATURE_STATE_TOPIC] is None: self._target_temperature = config[CONF_TEMP_INITIAL] + if self._topic[CONF_TEMPERATURE_LOW_STATE_TOPIC] is None: + self._target_temperature_low = config[CONF_TEMP_INITIAL] + if self._topic[CONF_TEMPERATURE_HIGH_STATE_TOPIC] is None: + self._target_temperature_high = config[CONF_TEMP_INITIAL] + if self._topic[CONF_FAN_MODE_STATE_TOPIC] is None: self._current_fan_mode = SPEED_LOW if self._topic[CONF_SWING_MODE_STATE_TOPIC] is None: @@ -339,6 +366,38 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, 'msg_callback': handle_temperature_received, 'qos': qos} + @callback + def handle_temperature_low_received(msg): + """Handle target temperature low coming via MQTT.""" + try: + self._target_temperature_low = float(msg.payload) + self.async_write_ha_state() + except ValueError: + _LOGGER.error("Could not parse low temperature from %s", + msg.payload) + + if self._topic[CONF_TEMPERATURE_LOW_STATE_TOPIC] is not None: + topics[CONF_TEMPERATURE_LOW_STATE_TOPIC] = { + 'topic': self._topic[CONF_TEMPERATURE_LOW_STATE_TOPIC], + 'msg_callback': handle_temperature_low_received, + 'qos': qos} + + @callback + def handle_temperature_high_received(msg): + """Handle target temperature high coming via MQTT.""" + try: + self._target_temperature_high = float(msg.payload) + self.async_write_ha_state() + except ValueError: + _LOGGER.error("Could not parse high temperature from %s", + msg.payload) + + if self._topic[CONF_TEMPERATURE_HIGH_STATE_TOPIC] is not None: + topics[CONF_TEMPERATURE_HIGH_STATE_TOPIC] = { + 'topic': self._topic[CONF_TEMPERATURE_HIGH_STATE_TOPIC], + 'msg_callback': handle_temperature_high_received, + 'qos': qos} + @callback def handle_fan_mode_received(msg): """Handle receiving fan mode via MQTT.""" @@ -498,6 +557,16 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """Return the temperature we try to reach.""" return self._target_temperature + @property + def target_temperature_low(self): + """Return the low target temperature we try to reach.""" + return self._target_temperature_low + + @property + def target_temperature_high(self): + """Return the high target temperature we try to reach.""" + return self._target_temperature_high + @property def current_operation(self): """Return current operation ie. heat, cool, idle.""" @@ -556,6 +625,31 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, kwargs.get(ATTR_TEMPERATURE), self._config[CONF_QOS], self._config[CONF_RETAIN]) + if kwargs.get(ATTR_TARGET_TEMP_LOW) is not None: + if self._topic[CONF_TEMPERATURE_LOW_STATE_TOPIC] is None: + # optimistic mode + self._target_temperature_low = kwargs[ATTR_TARGET_TEMP_LOW] + + if (self._config[CONF_SEND_IF_OFF] or + self._current_operation != STATE_OFF): + mqtt.async_publish( + self.hass, self._topic[CONF_TEMPERATURE_LOW_COMMAND_TOPIC], + kwargs.get(ATTR_TARGET_TEMP_LOW), self._config[CONF_QOS], + self._config[CONF_RETAIN]) + + if kwargs.get(ATTR_TARGET_TEMP_HIGH) is not None: + if self._topic[CONF_TEMPERATURE_HIGH_STATE_TOPIC] is None: + # optimistic mode + self._target_temperature_high = kwargs[ATTR_TARGET_TEMP_HIGH] + + if (self._config[CONF_SEND_IF_OFF] or + self._current_operation != STATE_OFF): + mqtt.async_publish( + self.hass, + self._topic[CONF_TEMPERATURE_HIGH_COMMAND_TOPIC], + kwargs.get(ATTR_TARGET_TEMP_HIGH), self._config[CONF_QOS], + self._config[CONF_RETAIN]) + # Always optimistic? self.async_write_ha_state() @@ -691,6 +785,14 @@ class MqttClimate(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, (self._topic[CONF_TEMPERATURE_COMMAND_TOPIC] is not None): support |= SUPPORT_TARGET_TEMPERATURE + if (self._topic[CONF_TEMPERATURE_LOW_STATE_TOPIC] is not None) or \ + (self._topic[CONF_TEMPERATURE_LOW_COMMAND_TOPIC] is not None): + support |= SUPPORT_TARGET_TEMPERATURE_LOW + + if (self._topic[CONF_TEMPERATURE_HIGH_STATE_TOPIC] is not None) or \ + (self._topic[CONF_TEMPERATURE_HIGH_COMMAND_TOPIC] is not None): + support |= SUPPORT_TARGET_TEMPERATURE_HIGH + if (self._topic[CONF_MODE_COMMAND_TOPIC] is not None) or \ (self._topic[CONF_MODE_STATE_TOPIC] is not None): support |= SUPPORT_OPERATION_MODE diff --git a/tests/components/mqtt/test_climate.py b/tests/components/mqtt/test_climate.py index 7bdfe8f452f..a8e1ae6111e 100644 --- a/tests/components/mqtt/test_climate.py +++ b/tests/components/mqtt/test_climate.py @@ -15,7 +15,8 @@ from homeassistant.components.climate.const import ( SUPPORT_AUX_HEAT, SUPPORT_AWAY_MODE, SUPPORT_FAN_MODE, SUPPORT_HOLD_MODE, SUPPORT_OPERATION_MODE, SUPPORT_SWING_MODE, SUPPORT_TARGET_TEMPERATURE, STATE_AUTO, - STATE_COOL, STATE_HEAT, STATE_DRY, STATE_FAN_ONLY) + STATE_COOL, STATE_HEAT, STATE_DRY, STATE_FAN_ONLY, + SUPPORT_TARGET_TEMPERATURE_LOW, SUPPORT_TARGET_TEMPERATURE_HIGH) from homeassistant.components.mqtt.discovery import async_start from homeassistant.const import STATE_OFF, STATE_UNAVAILABLE from homeassistant.setup import setup_component @@ -35,6 +36,8 @@ DEFAULT_CONFIG = { 'name': 'test', 'mode_command_topic': 'mode-topic', 'temperature_command_topic': 'temperature-topic', + 'temperature_low_command_topic': 'temperature-low-topic', + 'temperature_high_command_topic': 'temperature-high-topic', 'fan_mode_command_topic': 'fan-mode-topic', 'swing_mode_command_topic': 'swing-mode-topic', 'away_mode_command_topic': 'away-mode-topic', @@ -75,7 +78,9 @@ class TestMQTTClimate(unittest.TestCase): state = self.hass.states.get(ENTITY_CLIMATE) support = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE | SUPPORT_SWING_MODE | SUPPORT_FAN_MODE | SUPPORT_AWAY_MODE | - SUPPORT_HOLD_MODE | SUPPORT_AUX_HEAT) + SUPPORT_HOLD_MODE | SUPPORT_AUX_HEAT | + SUPPORT_TARGET_TEMPERATURE_LOW | + SUPPORT_TARGET_TEMPERATURE_HIGH) assert state.attributes.get("supported_features") == support @@ -341,6 +346,66 @@ class TestMQTTClimate(unittest.TestCase): state = self.hass.states.get(ENTITY_CLIMATE) assert 1701 == state.attributes.get('temperature') + def test_set_target_temperature_low_high(self): + """Test setting the low/high target temperature.""" + assert setup_component(self.hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) + + common.set_temperature(self.hass, target_temp_low=20, + target_temp_high=23, + entity_id=ENTITY_CLIMATE) + self.hass.block_till_done() + state = self.hass.states.get(ENTITY_CLIMATE) + print(state.attributes) + assert 20 == state.attributes.get('target_temp_low') + assert 23 == state.attributes.get('target_temp_high') + self.mock_publish.async_publish.assert_any_call( + 'temperature-low-topic', 20, 0, False) + self.mock_publish.async_publish.assert_any_call( + 'temperature-high-topic', 23, 0, False) + + def test_set_target_temperature_low_highpessimistic(self): + """Test setting the low/high target temperature.""" + config = copy.deepcopy(DEFAULT_CONFIG) + config['climate']['temperature_low_state_topic'] = \ + 'temperature-low-state' + config['climate']['temperature_high_state_topic'] = \ + 'temperature-high-state' + assert setup_component(self.hass, CLIMATE_DOMAIN, config) + + state = self.hass.states.get(ENTITY_CLIMATE) + assert state.attributes.get('target_temp_low') is None + assert state.attributes.get('target_temp_high') is None + self.hass.block_till_done() + common.set_temperature(self.hass, target_temp_low=20, + target_temp_high=23, + entity_id=ENTITY_CLIMATE) + self.hass.block_till_done() + state = self.hass.states.get(ENTITY_CLIMATE) + assert state.attributes.get('target_temp_low') is None + assert state.attributes.get('target_temp_high') is None + + fire_mqtt_message(self.hass, 'temperature-low-state', '1701') + self.hass.block_till_done() + state = self.hass.states.get(ENTITY_CLIMATE) + assert 1701 == state.attributes.get('target_temp_low') + assert state.attributes.get('target_temp_high') is None + + fire_mqtt_message(self.hass, 'temperature-high-state', '1703') + self.hass.block_till_done() + state = self.hass.states.get(ENTITY_CLIMATE) + assert 1701 == state.attributes.get('target_temp_low') + assert 1703 == state.attributes.get('target_temp_high') + + fire_mqtt_message(self.hass, 'temperature-low-state', 'not a number') + self.hass.block_till_done() + state = self.hass.states.get(ENTITY_CLIMATE) + assert 1701 == state.attributes.get('target_temp_low') + + fire_mqtt_message(self.hass, 'temperature-high-state', 'not a number') + self.hass.block_till_done() + state = self.hass.states.get(ENTITY_CLIMATE) + assert 1703 == state.attributes.get('target_temp_high') + def test_receive_mqtt_temperature(self): """Test getting the current temperature via MQTT.""" config = copy.deepcopy(DEFAULT_CONFIG) From 6c53528ae8ae03f47e41ee56164183b2df0d8ab0 Mon Sep 17 00:00:00 2001 From: Rohan Kapoor Date: Mon, 8 Apr 2019 06:43:38 -0700 Subject: [PATCH 161/167] Update harmony manifest to match REQUIREMENTS in module (#22826) --- homeassistant/components/harmony/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/harmony/manifest.json b/homeassistant/components/harmony/manifest.json index c82e9b7bf10..b2f9e69e014 100644 --- a/homeassistant/components/harmony/manifest.json +++ b/homeassistant/components/harmony/manifest.json @@ -3,7 +3,7 @@ "name": "Harmony", "documentation": "https://www.home-assistant.io/components/harmony", "requirements": [ - "aioharmony==0.1.8" + "aioharmony==0.1.11" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index de505dec18f..76ec55ee3ce 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -121,7 +121,7 @@ aiofreepybox==0.0.8 aioftp==0.12.0 # homeassistant.components.harmony -aioharmony==0.1.8 +aioharmony==0.1.11 # homeassistant.components.emulated_hue # homeassistant.components.http From 5727beed8e15597e3708e84bf8f583d598b42d64 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 8 Apr 2019 15:44:24 +0200 Subject: [PATCH 162/167] Add ESPHome Cover position/tilt support (#22858) ## Description: Add ESPHome cover position and tilt support. The aioesphomeapi also received a small refactor for these changes and those are part of this PR (constants were refactored into enums and optimistic was renamed to assumed_state). If possible, I'd like to include those in this PR because: 1. It's mostly just very simple changes 2. Because of the new position change the dev branch would be in a non-working state for a while until the split PR is merged (unless I write some temporary glue logic, but I'd prefer to avoid that) ## Checklist: - [x] The code change is tested and works locally. - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass** - [x] There is no commented out code in this PR. If the code communicates with devices, web services, or third-party tools: - [x] [_The manifest file_][manifest-docs] has all fields filled out correctly ([example][ex-manifest]). - [x] New dependencies have been added to `requirements` in the manifest ([example][ex-requir]). - [x] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`. [ex-manifest]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json [ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json#L5 [ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23 [manifest-docs]: https://developers.home-assistant.io/docs/en/development_checklist.html#_the-manifest-file_ --- homeassistant/components/esphome/__init__.py | 13 ++- homeassistant/components/esphome/cover.py | 89 +++++++++++++++---- homeassistant/components/esphome/fan.py | 33 ++++--- .../components/esphome/manifest.json | 4 +- homeassistant/components/esphome/switch.py | 2 +- requirements_all.txt | 2 +- 6 files changed, 105 insertions(+), 38 deletions(-) diff --git a/homeassistant/components/esphome/__init__.py b/homeassistant/components/esphome/__init__.py index 39422c530b3..19cd851002a 100644 --- a/homeassistant/components/esphome/__init__.py +++ b/homeassistant/components/esphome/__init__.py @@ -32,7 +32,7 @@ if TYPE_CHECKING: ServiceCall, UserService DOMAIN = 'esphome' -REQUIREMENTS = ['aioesphomeapi==1.7.0'] +REQUIREMENTS = ['aioesphomeapi==2.0.0'] _LOGGER = logging.getLogger(__name__) @@ -381,16 +381,15 @@ async def _async_setup_device_registry(hass: HomeAssistantType, async def _register_service(hass: HomeAssistantType, entry_data: RuntimeEntryData, service: 'UserService'): - from aioesphomeapi import USER_SERVICE_ARG_BOOL, USER_SERVICE_ARG_INT, \ - USER_SERVICE_ARG_FLOAT, USER_SERVICE_ARG_STRING + from aioesphomeapi import UserServiceArgType service_name = '{}_{}'.format(entry_data.device_info.name, service.name) schema = {} for arg in service.args: schema[vol.Required(arg.name)] = { - USER_SERVICE_ARG_BOOL: cv.boolean, - USER_SERVICE_ARG_INT: vol.Coerce(int), - USER_SERVICE_ARG_FLOAT: vol.Coerce(float), - USER_SERVICE_ARG_STRING: cv.string, + UserServiceArgType.BOOL: cv.boolean, + UserServiceArgType.INT: vol.Coerce(int), + UserServiceArgType.FLOAT: vol.Coerce(float), + UserServiceArgType.STRING: cv.string, }[arg.type_] async def execute_service(call): diff --git a/homeassistant/components/esphome/cover.py b/homeassistant/components/esphome/cover.py index d86c40e627e..68eb4221a93 100644 --- a/homeassistant/components/esphome/cover.py +++ b/homeassistant/components/esphome/cover.py @@ -3,7 +3,9 @@ import logging from typing import TYPE_CHECKING, Optional from homeassistant.components.cover import ( - SUPPORT_CLOSE, SUPPORT_OPEN, SUPPORT_STOP, CoverDevice) + ATTR_POSITION, ATTR_TILT_POSITION, SUPPORT_CLOSE, SUPPORT_CLOSE_TILT, + SUPPORT_OPEN, SUPPORT_OPEN_TILT, SUPPORT_SET_POSITION, + SUPPORT_SET_TILT_POSITION, SUPPORT_STOP, CoverDevice) from homeassistant.config_entries import ConfigEntry from homeassistant.helpers.typing import HomeAssistantType @@ -38,44 +40,97 @@ class EsphomeCover(EsphomeEntity, CoverDevice): def _static_info(self) -> 'CoverInfo': return super()._static_info - @property - def _state(self) -> Optional['CoverState']: - return super()._state - @property def supported_features(self) -> int: """Flag supported features.""" - return SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP + flags = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP + if self._static_info.supports_position: + flags |= SUPPORT_SET_POSITION + if self._static_info.supports_tilt: + flags |= (SUPPORT_OPEN_TILT | SUPPORT_CLOSE_TILT | + SUPPORT_SET_TILT_POSITION) + return flags + + @property + def device_class(self): + """Return the class of this device, from component DEVICE_CLASSES.""" + return self._static_info.device_class @property def assumed_state(self) -> bool: """Return true if we do optimistic updates.""" - return self._static_info.is_optimistic + return self._static_info.assumed_state + + @property + def _state(self) -> Optional['CoverState']: + return super()._state @property def is_closed(self) -> Optional[bool]: """Return if the cover is closed or not.""" if self._state is None: return None - return bool(self._state.state) + # Check closed state with api version due to a protocol change + return self._state.is_closed(self._client.api_version) + + @property + def is_opening(self): + """Return if the cover is opening or not.""" + from aioesphomeapi import CoverOperation + if self._state is None: + return None + return self._state.current_operation == CoverOperation.IS_OPENING + + @property + def is_closing(self): + """Return if the cover is closing or not.""" + from aioesphomeapi import CoverOperation + if self._state is None: + return None + return self._state.current_operation == CoverOperation.IS_CLOSING + + @property + def current_cover_position(self) -> Optional[float]: + """Return current position of cover. 0 is closed, 100 is open.""" + if self._state is None or not self._static_info.supports_position: + return None + return self._state.position * 100.0 + + @property + def current_cover_tilt_position(self) -> Optional[float]: + """Return current position of cover tilt. 0 is closed, 100 is open.""" + if self._state is None or not self._static_info.supports_tilt: + return None + return self._state.tilt * 100.0 async def async_open_cover(self, **kwargs) -> None: """Open the cover.""" - from aioesphomeapi.client import COVER_COMMAND_OPEN - await self._client.cover_command(key=self._static_info.key, - command=COVER_COMMAND_OPEN) + position=1.0) async def async_close_cover(self, **kwargs) -> None: """Close cover.""" - from aioesphomeapi.client import COVER_COMMAND_CLOSE - await self._client.cover_command(key=self._static_info.key, - command=COVER_COMMAND_CLOSE) + position=0.0) - async def async_stop_cover(self, **kwargs): + async def async_stop_cover(self, **kwargs) -> None: """Stop the cover.""" - from aioesphomeapi.client import COVER_COMMAND_STOP + await self._client.cover_command(key=self._static_info.key, stop=True) + async def async_set_cover_position(self, **kwargs) -> None: + """Move the cover to a specific position.""" await self._client.cover_command(key=self._static_info.key, - command=COVER_COMMAND_STOP) + position=kwargs[ATTR_POSITION] / 100) + + async def async_open_cover_tilt(self, **kwargs) -> None: + """Open the cover tilt.""" + await self._client.cover_command(key=self._static_info.key, tilt=1.0) + + async def async_close_cover_tilt(self, **kwargs) -> None: + """Close the cover tilt.""" + await self._client.cover_command(key=self._static_info.key, tilt=0.0) + + async def async_set_cover_tilt_position(self, **kwargs) -> None: + """Move the cover tilt to a specific position.""" + await self._client.cover_command(key=self._static_info.key, + tilt=kwargs[ATTR_TILT_POSITION] / 100) diff --git a/homeassistant/components/esphome/fan.py b/homeassistant/components/esphome/fan.py index 05f18cb014a..973fa85774c 100644 --- a/homeassistant/components/esphome/fan.py +++ b/homeassistant/components/esphome/fan.py @@ -12,7 +12,7 @@ from . import EsphomeEntity, platform_async_setup_entry if TYPE_CHECKING: # pylint: disable=unused-import - from aioesphomeapi import FanInfo, FanState # noqa + from aioesphomeapi import FanInfo, FanState, FanSpeed # noqa DEPENDENCIES = ['esphome'] _LOGGER = logging.getLogger(__name__) @@ -32,12 +32,24 @@ async def async_setup_entry(hass: HomeAssistantType, ) -FAN_SPEED_STR_TO_INT = { - SPEED_LOW: 0, - SPEED_MEDIUM: 1, - SPEED_HIGH: 2 -} -FAN_SPEED_INT_TO_STR = {v: k for k, v in FAN_SPEED_STR_TO_INT.items()} +def _ha_fan_speed_to_esphome(speed: str) -> 'FanSpeed': + # pylint: disable=redefined-outer-name + from aioesphomeapi import FanSpeed # noqa + return { + SPEED_LOW: FanSpeed.LOW, + SPEED_MEDIUM: FanSpeed.MEDIUM, + SPEED_HIGH: FanSpeed.HIGH, + }[speed] + + +def _esphome_fan_speed_to_ha(speed: 'FanSpeed') -> str: + # pylint: disable=redefined-outer-name + from aioesphomeapi import FanSpeed # noqa + return { + FanSpeed.LOW: SPEED_LOW, + FanSpeed.MEDIUM: SPEED_MEDIUM, + FanSpeed.HIGH: SPEED_HIGH, + }[speed] class EsphomeFan(EsphomeEntity, FanEntity): @@ -56,8 +68,9 @@ class EsphomeFan(EsphomeEntity, FanEntity): if speed == SPEED_OFF: await self.async_turn_off() return + await self._client.fan_command( - self._static_info.key, speed=FAN_SPEED_STR_TO_INT[speed]) + self._static_info.key, speed=_ha_fan_speed_to_esphome(speed)) async def async_turn_on(self, speed: Optional[str] = None, **kwargs) -> None: @@ -67,7 +80,7 @@ class EsphomeFan(EsphomeEntity, FanEntity): return data = {'key': self._static_info.key, 'state': True} if speed is not None: - data['speed'] = FAN_SPEED_STR_TO_INT[speed] + data['speed'] = _ha_fan_speed_to_esphome(speed) await self._client.fan_command(**data) # pylint: disable=arguments-differ @@ -94,7 +107,7 @@ class EsphomeFan(EsphomeEntity, FanEntity): return None if not self._static_info.supports_speed: return None - return FAN_SPEED_INT_TO_STR[self._state.speed] + return _esphome_fan_speed_to_ha(self._state.speed) @property def oscillating(self) -> None: diff --git a/homeassistant/components/esphome/manifest.json b/homeassistant/components/esphome/manifest.json index b00cdf9607d..734544b49c7 100644 --- a/homeassistant/components/esphome/manifest.json +++ b/homeassistant/components/esphome/manifest.json @@ -1,9 +1,9 @@ { "domain": "esphome", - "name": "Esphome", + "name": "ESPHome", "documentation": "https://www.home-assistant.io/components/esphome", "requirements": [ - "aioesphomeapi==1.7.0" + "aioesphomeapi==2.0.0" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/components/esphome/switch.py b/homeassistant/components/esphome/switch.py index e5a9d0cf446..e736c1df209 100644 --- a/homeassistant/components/esphome/switch.py +++ b/homeassistant/components/esphome/switch.py @@ -49,7 +49,7 @@ class EsphomeSwitch(EsphomeEntity, SwitchDevice): @property def assumed_state(self) -> bool: """Return true if we do optimistic updates.""" - return self._static_info.optimistic + return self._static_info.assumed_state @property def is_on(self): diff --git a/requirements_all.txt b/requirements_all.txt index 76ec55ee3ce..9709d7c87ef 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -112,7 +112,7 @@ aiobotocore==0.10.2 aiodns==1.1.1 # homeassistant.components.esphome -aioesphomeapi==1.7.0 +aioesphomeapi==2.0.0 # homeassistant.components.freebox aiofreepybox==0.0.8 From 49a2f5a40b6476c4ce97735f943d46c783e0ef1d Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 8 Apr 2019 17:47:40 +0200 Subject: [PATCH 163/167] Use dict[key] for required config keys and keys with default values. (#22832) --- homeassistant/components/mqtt/cover.py | 144 ++++++++++++------------- 1 file changed, 71 insertions(+), 73 deletions(-) diff --git a/homeassistant/components/mqtt/cover.py b/homeassistant/components/mqtt/cover.py index 08b6c2b74ba..5cb7300f0ef 100644 --- a/homeassistant/components/mqtt/cover.py +++ b/homeassistant/components/mqtt/cover.py @@ -84,38 +84,36 @@ def validate_options(value): PLATFORM_SCHEMA = vol.All(mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ vol.Optional(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_SET_POSITION_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_SET_POSITION_TEMPLATE): cv.template, - vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, - vol.Optional(CONF_GET_POSITION_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_PAYLOAD_OPEN, default=DEFAULT_PAYLOAD_OPEN): cv.string, - vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): cv.string, - vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): cv.string, - vol.Optional(CONF_STATE_OPEN, default=STATE_OPEN): cv.string, - vol.Optional(CONF_STATE_CLOSED, default=STATE_CLOSED): cv.string, - vol.Optional(CONF_POSITION_OPEN, - default=DEFAULT_POSITION_OPEN): int, - vol.Optional(CONF_POSITION_CLOSED, - default=DEFAULT_POSITION_CLOSED): int, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, - vol.Optional(CONF_TILT_COMMAND_TOPIC): mqtt.valid_publish_topic, - vol.Optional(CONF_TILT_STATUS_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_TILT_CLOSED_POSITION, - default=DEFAULT_TILT_CLOSED_POSITION): int, - vol.Optional(CONF_TILT_OPEN_POSITION, - default=DEFAULT_TILT_OPEN_POSITION): int, - vol.Optional(CONF_TILT_MIN, default=DEFAULT_TILT_MIN): int, - vol.Optional(CONF_TILT_MAX, default=DEFAULT_TILT_MAX): int, - vol.Optional(CONF_TILT_STATE_OPTIMISTIC, - default=DEFAULT_TILT_OPTIMISTIC): cv.boolean, - vol.Optional(CONF_TILT_INVERT_STATE, - default=DEFAULT_TILT_INVERT_STATE): cv.boolean, - vol.Optional(CONF_UNIQUE_ID): cv.string, vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_GET_POSITION_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): cv.string, + vol.Optional(CONF_PAYLOAD_OPEN, default=DEFAULT_PAYLOAD_OPEN): cv.string, + vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): cv.string, + vol.Optional(CONF_POSITION_CLOSED, default=DEFAULT_POSITION_CLOSED): int, + vol.Optional(CONF_POSITION_OPEN, default=DEFAULT_POSITION_OPEN): int, + vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, + vol.Optional(CONF_SET_POSITION_TEMPLATE): cv.template, + vol.Optional(CONF_SET_POSITION_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_STATE_CLOSED, default=STATE_CLOSED): cv.string, + vol.Optional(CONF_STATE_OPEN, default=STATE_OPEN): cv.string, + vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_TILT_CLOSED_POSITION, + default=DEFAULT_TILT_CLOSED_POSITION): int, + vol.Optional(CONF_TILT_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Optional(CONF_TILT_INVERT_STATE, + default=DEFAULT_TILT_INVERT_STATE): cv.boolean, + vol.Optional(CONF_TILT_MAX, default=DEFAULT_TILT_MAX): int, + vol.Optional(CONF_TILT_MIN, default=DEFAULT_TILT_MIN): int, + vol.Optional(CONF_TILT_OPEN_POSITION, + default=DEFAULT_TILT_OPEN_POSITION): int, + vol.Optional(CONF_TILT_STATE_OPTIMISTIC, + default=DEFAULT_TILT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_TILT_STATUS_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_UNIQUE_ID): cv.string, + vol.Optional(CONF_VALUE_TEMPLATE): cv.template, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema).extend( mqtt.MQTT_JSON_ATTRS_SCHEMA.schema), validate_options) @@ -194,10 +192,10 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, def _setup_from_config(self, config): self._config = config - self._optimistic = (config.get(CONF_OPTIMISTIC) or + self._optimistic = (config[CONF_OPTIMISTIC] or (config.get(CONF_STATE_TOPIC) is None and config.get(CONF_GET_POSITION_TOPIC) is None)) - self._tilt_optimistic = config.get(CONF_TILT_STATE_OPTIMISTIC) + self._tilt_optimistic = config[CONF_TILT_STATE_OPTIMISTIC] async def _subscribe_topics(self): """(Re)Subscribe to topics.""" @@ -214,8 +212,8 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, def tilt_updated(msg): """Handle tilt updates.""" if (msg.payload.isnumeric() and - (self._config.get(CONF_TILT_MIN) <= int(msg.payload) <= - self._config.get(CONF_TILT_MAX))): + (self._config[CONF_TILT_MIN] <= int(msg.payload) <= + self._config[CONF_TILT_MAX])): level = self.find_percentage_in_range(float(msg.payload)) self._tilt_value = level @@ -229,9 +227,9 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, payload = template.async_render_with_possible_json_value( payload) - if payload == self._config.get(CONF_STATE_OPEN): + if payload == self._config[CONF_STATE_OPEN]: self._state = False - elif payload == self._config.get(CONF_STATE_CLOSED): + elif payload == self._config[CONF_STATE_CLOSED]: self._state = True else: _LOGGER.warning("Payload is not True or False: %s", payload) @@ -262,12 +260,12 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, topics['get_position_topic'] = { 'topic': self._config.get(CONF_GET_POSITION_TOPIC), 'msg_callback': position_message_received, - 'qos': self._config.get(CONF_QOS)} + 'qos': self._config[CONF_QOS]} elif self._config.get(CONF_STATE_TOPIC): topics['state_topic'] = { 'topic': self._config.get(CONF_STATE_TOPIC), 'msg_callback': state_message_received, - 'qos': self._config.get(CONF_QOS)} + 'qos': self._config[CONF_QOS]} else: # Force into optimistic mode. self._optimistic = True @@ -280,7 +278,7 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, topics['tilt_status_topic'] = { 'topic': self._config.get(CONF_TILT_STATUS_TOPIC), 'msg_callback': tilt_updated, - 'qos': self._config.get(CONF_QOS)} + 'qos': self._config[CONF_QOS]} self._sub_state = await subscription.async_subscribe_topics( self.hass, self._sub_state, @@ -306,7 +304,7 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, @property def name(self): """Return the name of the cover.""" - return self._config.get(CONF_NAME) + return self._config[CONF_NAME] @property def is_closed(self): @@ -353,14 +351,14 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """ mqtt.async_publish( self.hass, self._config.get(CONF_COMMAND_TOPIC), - self._config.get(CONF_PAYLOAD_OPEN), self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_PAYLOAD_OPEN], self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._optimistic: # Optimistically assume that cover has changed state. self._state = False if self._config.get(CONF_GET_POSITION_TOPIC): self._position = self.find_percentage_in_range( - self._config.get(CONF_POSITION_OPEN), COVER_PAYLOAD) + self._config[CONF_POSITION_OPEN], COVER_PAYLOAD) self.async_write_ha_state() async def async_close_cover(self, **kwargs): @@ -370,14 +368,14 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """ mqtt.async_publish( self.hass, self._config.get(CONF_COMMAND_TOPIC), - self._config.get(CONF_PAYLOAD_CLOSE), self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_PAYLOAD_CLOSE], self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._optimistic: # Optimistically assume that cover has changed state. self._state = True if self._config.get(CONF_GET_POSITION_TOPIC): self._position = self.find_percentage_in_range( - self._config.get(CONF_POSITION_CLOSED), COVER_PAYLOAD) + self._config[CONF_POSITION_CLOSED], COVER_PAYLOAD) self.async_write_ha_state() async def async_stop_cover(self, **kwargs): @@ -387,29 +385,29 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """ mqtt.async_publish( self.hass, self._config.get(CONF_COMMAND_TOPIC), - self._config.get(CONF_PAYLOAD_STOP), self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_PAYLOAD_STOP], self._config[CONF_QOS], + self._config[CONF_RETAIN]) async def async_open_cover_tilt(self, **kwargs): """Tilt the cover open.""" mqtt.async_publish(self.hass, self._config.get(CONF_TILT_COMMAND_TOPIC), - self._config.get(CONF_TILT_OPEN_POSITION), - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_TILT_OPEN_POSITION], + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._tilt_optimistic: - self._tilt_value = self._config.get(CONF_TILT_OPEN_POSITION) + self._tilt_value = self._config[CONF_TILT_OPEN_POSITION] self.async_write_ha_state() async def async_close_cover_tilt(self, **kwargs): """Tilt the cover closed.""" mqtt.async_publish(self.hass, self._config.get(CONF_TILT_COMMAND_TOPIC), - self._config.get(CONF_TILT_CLOSED_POSITION), - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_TILT_CLOSED_POSITION], + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._tilt_optimistic: - self._tilt_value = self._config.get(CONF_TILT_CLOSED_POSITION) + self._tilt_value = self._config[CONF_TILT_CLOSED_POSITION] self.async_write_ha_state() async def async_set_cover_tilt_position(self, **kwargs): @@ -425,8 +423,8 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, mqtt.async_publish(self.hass, self._config.get(CONF_TILT_COMMAND_TOPIC), level, - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_QOS], + self._config[CONF_RETAIN]) async def async_set_cover_position(self, **kwargs): """Move the cover to a specific position.""" @@ -441,19 +439,19 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, except TemplateError as ex: _LOGGER.error(ex) self._state = None - elif (self._config.get(CONF_POSITION_OPEN) != 100 and - self._config.get(CONF_POSITION_CLOSED) != 0): + elif (self._config[CONF_POSITION_OPEN] != 100 and + self._config[CONF_POSITION_CLOSED] != 0): position = self.find_in_range_from_percent( position, COVER_PAYLOAD) mqtt.async_publish(self.hass, self._config.get(CONF_SET_POSITION_TOPIC), position, - self._config.get(CONF_QOS), - self._config.get(CONF_RETAIN)) + self._config[CONF_QOS], + self._config[CONF_RETAIN]) if self._optimistic: self._state = percentage_position == \ - self._config.get(CONF_POSITION_CLOSED) + self._config[CONF_POSITION_CLOSED] self._position = percentage_position self.async_write_ha_state() @@ -461,11 +459,11 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, """Find the 0-100% value within the specified range.""" # the range of motion as defined by the min max values if range_type == COVER_PAYLOAD: - max_range = self._config.get(CONF_POSITION_OPEN) - min_range = self._config.get(CONF_POSITION_CLOSED) + max_range = self._config[CONF_POSITION_OPEN] + min_range = self._config[CONF_POSITION_CLOSED] else: - max_range = self._config.get(CONF_TILT_MAX) - min_range = self._config.get(CONF_TILT_MIN) + max_range = self._config[CONF_TILT_MAX] + min_range = self._config[CONF_TILT_MIN] current_range = max_range - min_range # offset to be zero based offset_position = position - min_range @@ -477,7 +475,7 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, position_percentage = min(max(position_percentage, min_percent), max_percent) if range_type == TILT_PAYLOAD and \ - self._config.get(CONF_TILT_INVERT_STATE): + self._config[CONF_TILT_INVERT_STATE]: return 100 - position_percentage return position_percentage @@ -491,18 +489,18 @@ class MqttCover(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, returning the offset """ if range_type == COVER_PAYLOAD: - max_range = self._config.get(CONF_POSITION_OPEN) - min_range = self._config.get(CONF_POSITION_CLOSED) + max_range = self._config[CONF_POSITION_OPEN] + min_range = self._config[CONF_POSITION_CLOSED] else: - max_range = self._config.get(CONF_TILT_MAX) - min_range = self._config.get(CONF_TILT_MIN) + max_range = self._config[CONF_TILT_MAX] + min_range = self._config[CONF_TILT_MIN] offset = min_range current_range = max_range - min_range position = round(current_range * (percentage / 100.0)) position += offset if range_type == TILT_PAYLOAD and \ - self._config.get(CONF_TILT_INVERT_STATE): + self._config[CONF_TILT_INVERT_STATE]: position = max_range - position + offset return position From 55c8417ec0530a9c014266215e9798188231e237 Mon Sep 17 00:00:00 2001 From: Fredrik Erlandsson Date: Mon, 8 Apr 2019 19:08:03 +0200 Subject: [PATCH 164/167] fix aiohttp ServerDisconnectedError in Daikin (#22880) --- homeassistant/components/daikin/__init__.py | 17 ++++++++++------- homeassistant/components/daikin/config_flow.py | 8 ++++++-- homeassistant/components/daikin/manifest.json | 2 +- requirements_all.txt | 2 +- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/daikin/__init__.py b/homeassistant/components/daikin/__init__.py index 5ad21f5954f..2df831eb6db 100644 --- a/homeassistant/components/daikin/__init__.py +++ b/homeassistant/components/daikin/__init__.py @@ -2,13 +2,13 @@ import asyncio from datetime import timedelta import logging -from socket import timeout -import async_timeout +from aiohttp import ClientConnectionError +from async_timeout import timeout import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry -from homeassistant.const import CONF_HOSTS, CONF_HOST +from homeassistant.const import CONF_HOST, CONF_HOSTS import homeassistant.helpers.config_validation as cv from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.typing import HomeAssistantType @@ -16,7 +16,7 @@ from homeassistant.util import Throttle from . import config_flow # noqa pylint_disable=unused-import -REQUIREMENTS = ['pydaikin==1.3.1'] +REQUIREMENTS = ['pydaikin==1.4.0'] _LOGGER = logging.getLogger(__name__) @@ -88,11 +88,14 @@ async def daikin_api_setup(hass, host): from pydaikin.appliance import Appliance session = hass.helpers.aiohttp_client.async_get_clientsession() try: - with async_timeout.timeout(10): + with timeout(10, loop=hass.loop): device = Appliance(host, session) await device.init() except asyncio.TimeoutError: - _LOGGER.error("Connection to Daikin could not be established") + _LOGGER.error("Connection to Daikin timeout") + return None + except ClientConnectionError: + _LOGGER.error("ServerDisconected") return None except Exception: # pylint: disable=broad-except _LOGGER.error("Unexpected error creating device") @@ -119,7 +122,7 @@ class DaikinApi: try: await self.device.update_status() self._available = True - except timeout: + except ClientConnectionError: _LOGGER.warning( "Connection failed for %s", self.ip_address ) diff --git a/homeassistant/components/daikin/config_flow.py b/homeassistant/components/daikin/config_flow.py index 3c5daac4653..7c214e77050 100644 --- a/homeassistant/components/daikin/config_flow.py +++ b/homeassistant/components/daikin/config_flow.py @@ -2,7 +2,8 @@ import asyncio import logging -import async_timeout +from aiohttp import ClientError +from async_timeout import timeout import voluptuous as vol from homeassistant import config_entries @@ -42,10 +43,13 @@ class FlowHandler(config_entries.ConfigFlow): host, self.hass.helpers.aiohttp_client.async_get_clientsession(), ) - with async_timeout.timeout(10): + with timeout(10): await device.init() except asyncio.TimeoutError: return self.async_abort(reason='device_timeout') + except ClientError: + _LOGGER.exception("ClientError") + return self.async_abort(reason='device_fail') except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected error creating device") return self.async_abort(reason='device_fail') diff --git a/homeassistant/components/daikin/manifest.json b/homeassistant/components/daikin/manifest.json index 28314bdf084..ab842950e24 100644 --- a/homeassistant/components/daikin/manifest.json +++ b/homeassistant/components/daikin/manifest.json @@ -3,7 +3,7 @@ "name": "Daikin", "documentation": "https://www.home-assistant.io/components/daikin", "requirements": [ - "pydaikin==1.3.1" + "pydaikin==1.4.0" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index 9709d7c87ef..e46f9dd4019 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -985,7 +985,7 @@ pycsspeechtts==1.0.2 # pycups==1.9.73 # homeassistant.components.daikin -pydaikin==1.3.1 +pydaikin==1.4.0 # homeassistant.components.danfoss_air pydanfossair==0.0.7 From d577955d1e4ae0b7ad7b308a034851b9e114e7ef Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Tue, 9 Apr 2019 02:32:56 +0200 Subject: [PATCH 165/167] Fix Sonos handling of unsupported favorites (#22906) --- homeassistant/components/sonos/__init__.py | 2 +- homeassistant/components/sonos/manifest.json | 2 +- homeassistant/components/sonos/media_player.py | 13 +------------ requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/sonos/__init__.py b/homeassistant/components/sonos/__init__.py index e9f297e4f07..9c9914b787b 100644 --- a/homeassistant/components/sonos/__init__.py +++ b/homeassistant/components/sonos/__init__.py @@ -4,7 +4,7 @@ from homeassistant.helpers import config_entry_flow DOMAIN = 'sonos' -REQUIREMENTS = ['pysonos==0.0.8'] +REQUIREMENTS = ['pysonos==0.0.9'] async def async_setup(hass, config): diff --git a/homeassistant/components/sonos/manifest.json b/homeassistant/components/sonos/manifest.json index 3fa5ac0354a..79cc7653937 100644 --- a/homeassistant/components/sonos/manifest.json +++ b/homeassistant/components/sonos/manifest.json @@ -3,7 +3,7 @@ "name": "Sonos", "documentation": "https://www.home-assistant.io/components/sonos", "requirements": [ - "pysonos==0.0.8" + "pysonos==0.0.9" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/components/sonos/media_player.py b/homeassistant/components/sonos/media_player.py index ba7854e4f0d..7c2e5fec843 100644 --- a/homeassistant/components/sonos/media_player.py +++ b/homeassistant/components/sonos/media_player.py @@ -454,18 +454,7 @@ class SonosEntity(MediaPlayerDevice): def _set_favorites(self): """Set available favorites.""" - # SoCo 0.16 raises a generic Exception on invalid xml in favorites. - # Filter those out now so our list is safe to use. - try: - self._favorites = [] - for fav in self.soco.music_library.get_sonos_favorites(): - try: - if fav.reference.get_uri(): - self._favorites.append(fav) - except Exception: # pylint: disable=broad-except - _LOGGER.debug("Ignoring invalid favorite '%s'", fav.title) - except Exception: # pylint: disable=broad-except - _LOGGER.debug("Ignoring invalid favorite list") + self._favorites = self.soco.music_library.get_sonos_favorites() def _radio_artwork(self, url): """Return the private URL with artwork for a radio stream.""" diff --git a/requirements_all.txt b/requirements_all.txt index e46f9dd4019..e61530ce77d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1270,7 +1270,7 @@ pysmartthings==0.6.7 pysnmp==4.4.8 # homeassistant.components.sonos -pysonos==0.0.8 +pysonos==0.0.9 # homeassistant.components.spc pyspcwebgw==0.4.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index c9890f92626..e2935369d92 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -239,7 +239,7 @@ pysmartapp==0.3.2 pysmartthings==0.6.7 # homeassistant.components.sonos -pysonos==0.0.8 +pysonos==0.0.9 # homeassistant.components.spc pyspcwebgw==0.4.0 From 38f063a1586f1587886b11b763bd51e5538e06ca Mon Sep 17 00:00:00 2001 From: Andrew Sayre <6730289+andrewsayre@users.noreply.github.com> Date: Mon, 8 Apr 2019 21:24:40 -0500 Subject: [PATCH 166/167] Fix HEOS discovery could result in multiple config entries (#22903) * Prevent duplicate entries from discovery * Update reqs files * Prevent duplicate entries from discovery --- homeassistant/components/heos/__init__.py | 2 +- homeassistant/components/heos/config_flow.py | 9 ++- homeassistant/components/heos/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/heos/conftest.py | 18 ++++++ tests/components/heos/test_config_flow.py | 62 ++++++++++++-------- 7 files changed, 68 insertions(+), 29 deletions(-) diff --git a/homeassistant/components/heos/__init__.py b/homeassistant/components/heos/__init__.py index dadd9f10464..ffbd8ebffd4 100644 --- a/homeassistant/components/heos/__init__.py +++ b/homeassistant/components/heos/__init__.py @@ -19,7 +19,7 @@ from .const import ( COMMAND_RETRY_ATTEMPTS, COMMAND_RETRY_DELAY, DATA_CONTROLLER, DATA_SOURCE_MANAGER, DOMAIN, SIGNAL_HEOS_SOURCES_UPDATED) -REQUIREMENTS = ['pyheos==0.3.0'] +REQUIREMENTS = ['pyheos==0.3.1'] CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ diff --git a/homeassistant/components/heos/config_flow.py b/homeassistant/components/heos/config_flow.py index 7ccb43c60e9..66650531cad 100644 --- a/homeassistant/components/heos/config_flow.py +++ b/homeassistant/components/heos/config_flow.py @@ -23,8 +23,13 @@ class HeosFlowHandler(config_entries.ConfigFlow): async def async_step_discovery(self, discovery_info): """Handle a discovered Heos device.""" - return await self.async_step_user( - {CONF_HOST: discovery_info[CONF_HOST]}) + # Only continue if this is the only active flow + flows = self.hass.config_entries.flow.async_progress() + heos_flows = [flow for flow in flows if flow['handler'] == DOMAIN] + if len(heos_flows) == 1: + return await self.async_step_user( + {CONF_HOST: discovery_info[CONF_HOST]}) + return self.async_abort(reason='already_setup') async def async_step_import(self, user_input=None): """Occurs when an entry is setup through config.""" diff --git a/homeassistant/components/heos/manifest.json b/homeassistant/components/heos/manifest.json index 91cefed75f7..2977345f97d 100644 --- a/homeassistant/components/heos/manifest.json +++ b/homeassistant/components/heos/manifest.json @@ -3,7 +3,7 @@ "name": "Heos", "documentation": "https://www.home-assistant.io/components/heos", "requirements": [ - "pyheos==0.3.0" + "pyheos==0.3.1" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index e61530ce77d..b64079b4460 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1064,7 +1064,7 @@ pygtt==1.1.2 pyhaversion==2.0.3 # homeassistant.components.heos -pyheos==0.3.0 +pyheos==0.3.1 # homeassistant.components.hikvision pyhik==0.2.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e2935369d92..6e70c636314 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -204,7 +204,7 @@ pydeconz==54 pydispatcher==2.0.5 # homeassistant.components.heos -pyheos==0.3.0 +pyheos==0.3.1 # homeassistant.components.homematic pyhomematic==0.1.58 diff --git a/tests/components/heos/conftest.py b/tests/components/heos/conftest.py index 1b76db21187..db675a24ee0 100644 --- a/tests/components/heos/conftest.py +++ b/tests/components/heos/conftest.py @@ -103,3 +103,21 @@ def input_sources_fixture() -> Sequence[InputSource]: def dispatcher_fixture() -> Dispatcher: """Create a dispatcher for testing.""" return Dispatcher() + + +@pytest.fixture(name="discovery_data") +def discovery_data_fixture() -> dict: + """Return mock discovery data for testing.""" + return { + 'host': '127.0.0.1', + 'manufacturer': 'Denon', + 'model_name': 'HEOS Drive', + 'model_number': 'DWSA-10 4.0', + 'name': 'Office', + 'port': 60006, + 'serial': None, + 'ssdp_description': + 'http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml', + 'udn': 'uuid:e61de70c-2250-1c22-0080-0005cdf512be', + 'upnp_device_type': 'urn:schemas-denon-com:device:AiosDevice:1' + } diff --git a/tests/components/heos/test_config_flow.py b/tests/components/heos/test_config_flow.py index ddb2bd39384..9c33cbee7aa 100644 --- a/tests/components/heos/test_config_flow.py +++ b/tests/components/heos/test_config_flow.py @@ -3,6 +3,7 @@ import asyncio from homeassistant import data_entry_flow from homeassistant.components.heos.config_flow import HeosFlowHandler +from homeassistant.components.heos.const import DOMAIN from homeassistant.const import CONF_HOST @@ -57,26 +58,41 @@ async def test_create_entry_when_host_valid(hass, controller): assert controller.disconnect.call_count == 1 -async def test_create_entry_with_discovery(hass, controller): - """Test result type is create entry when valid through discovery.""" - flow = HeosFlowHandler() - flow.hass = hass - data = { - 'host': '127.0.0.1', - 'manufacturer': 'Denon', - 'model_name': 'HEOS Drive', - 'model_number': 'DWSA-10 4.0', - 'name': 'Office', - 'port': 60006, - 'serial': None, - 'ssdp_description': - 'http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml', - 'udn': 'uuid:e61de70c-2250-1c22-0080-0005cdf512be', - 'upnp_device_type': 'urn:schemas-denon-com:device:AiosDevice:1' - } - result = await flow.async_step_discovery(data) - assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result['title'] == 'Controller (127.0.0.1)' - assert result['data'] == {'host': '127.0.0.1'} - assert controller.connect.call_count == 1 - assert controller.disconnect.call_count == 1 +async def test_create_entry_with_discovery(hass, controller, discovery_data): + """Test discovery creates entry.""" + await hass.config_entries.flow.async_init( + DOMAIN, context={'source': 'discovery'}, + data=discovery_data) + await hass.async_block_till_done() + entries = hass.config_entries.async_entries(DOMAIN) + assert len(entries) == 1 + assert entries[0].data == {CONF_HOST: discovery_data[CONF_HOST]} + assert entries[0].title == 'Controller (127.0.0.1)' + + +async def test_entry_already_exists_discovery( + hass, controller, discovery_data, config_entry): + """Test discovery does not create multiple entries when already setup.""" + config_entry.add_to_hass(hass) + await hass.config_entries.flow.async_init( + DOMAIN, context={'source': 'discovery'}, + data=discovery_data) + await hass.async_block_till_done() + entries = hass.config_entries.async_entries(DOMAIN) + assert len(entries) == 1 + + +async def test_multiple_discovery_creates_single_entry( + hass, controller, discovery_data): + """Test discovery of multiple devices creates a single entry.""" + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={'source': 'discovery'}, + data={CONF_HOST: discovery_data})) + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={'source': 'discovery'}, + data={CONF_HOST: discovery_data})) + await hass.async_block_till_done() + entries = hass.config_entries.async_entries(DOMAIN) + assert len(entries) == 1 From 1a05f7b04d33bf09af6a32ea760e99b7d9038da0 Mon Sep 17 00:00:00 2001 From: pbalogh77 Date: Tue, 9 Apr 2019 06:24:57 +0200 Subject: [PATCH 167/167] Initial Fibaro HC Climate support (#20256) * Initial version of climate * initial commit of climate device support * Fixed opmode and fanmode * Cleanup * meh * added back all other components Oops * wider support for thermostats Added one more identifier for thermostats to broaden compatibility * Added even more climate types * Reworked detection mechanism Better support for combined devices * Added additional modes * force visibility on climate * Changed logging of device data * Improved operatingmode support Improved operatingmode support * Updated logic for opmode/fanmode list creation Implemented a universal mapping logic for opmode and fanmode, to make it more widely compatible Improved mapping of Fibaro FGT devices * Lint fixes * bump * Fixes based on code review * Fixes * Moved to fibaro folder * lint inspired cosmetic changes * Mapped all operating modes to existing HA ones Mapped all operating modes to existing HA ones * Improved compatibility with Heatit thermostats Thanks to astrandb for testing, debugging and fixing my code * Changes based on code review Changes based on code review * more fixes based on more code review more fixes based on more code review --- homeassistant/components/fibaro/__init__.py | 51 ++-- homeassistant/components/fibaro/climate.py | 291 ++++++++++++++++++++ 2 files changed, 325 insertions(+), 17 deletions(-) create mode 100644 homeassistant/components/fibaro/climate.py diff --git a/homeassistant/components/fibaro/__init__.py b/homeassistant/components/fibaro/__init__.py index 9a6ccccb5e3..6b37b178a59 100644 --- a/homeassistant/components/fibaro/__init__.py +++ b/homeassistant/components/fibaro/__init__.py @@ -26,20 +26,11 @@ CONF_DIMMING = 'dimming' CONF_GATEWAYS = 'gateways' CONF_PLUGINS = 'plugins' CONF_RESET_COLOR = 'reset_color' - DOMAIN = 'fibaro' - FIBARO_CONTROLLERS = 'fibaro_controllers' FIBARO_DEVICES = 'fibaro_devices' - -FIBARO_COMPONENTS = [ - 'binary_sensor', - 'cover', - 'light', - 'scene', - 'sensor', - 'switch', -] +FIBARO_COMPONENTS = ['binary_sensor', 'climate', 'cover', 'light', + 'scene', 'sensor', 'switch'] FIBARO_TYPEMAP = { 'com.fibaro.multilevelSensor': "sensor", @@ -56,7 +47,11 @@ FIBARO_TYPEMAP = { 'com.fibaro.remoteSwitch': 'switch', 'com.fibaro.sensor': 'sensor', 'com.fibaro.colorController': 'light', - 'com.fibaro.securitySensor': 'binary_sensor' + 'com.fibaro.securitySensor': 'binary_sensor', + 'com.fibaro.hvac': 'climate', + 'com.fibaro.setpoint': 'climate', + 'com.fibaro.FGT001': 'climate', + 'com.fibaro.thermostatDanfoss': 'climate' } DEVICE_CONFIG_SCHEMA_ENTRY = vol.Schema({ @@ -174,6 +169,16 @@ class FibaroController(): """Register device with a callback for updates.""" self._callbacks[device_id] = callback + def get_children(self, device_id): + """Get a list of child devices.""" + return [ + device for device in self._device_map.values() + if device.parentId == device_id] + + def get_siblings(self, device_id): + """Get the siblings of a device.""" + return self.get_children(self._device_map[device_id].parentId) + @staticmethod def _map_device_to_type(device): """Map device to HA device type.""" @@ -229,6 +234,7 @@ class FibaroController(): devices = self._client.devices.list() self._device_map = {} self.fibaro_devices = defaultdict(list) + last_climate_parent = None for device in devices: try: device.fibaro_controller = self @@ -249,15 +255,26 @@ class FibaroController(): self._device_config.get(device.ha_id, {}) else: device.mapped_type = None - if device.mapped_type: + dtype = device.mapped_type + if dtype: device.unique_id_str = "{}.{}".format( self.hub_serial, device.id) self._device_map[device.id] = device - self.fibaro_devices[device.mapped_type].append(device) - _LOGGER.debug("%s (%s, %s) -> %s. Prop: %s Actions: %s", + if dtype != 'climate': + self.fibaro_devices[dtype].append(device) + else: + # if a sibling of this has been added, skip this one + # otherwise add the first visible device in the group + # which is a hack, but solves a problem with FGT having + # hidden compatibility devices before the real device + if last_climate_parent != device.parentId and \ + device.visible: + self.fibaro_devices[dtype].append(device) + last_climate_parent = device.parentId + _LOGGER.debug("%s (%s, %s) -> %s %s", device.ha_id, device.type, - device.baseType, device.mapped_type, - str(device.properties), str(device.actions)) + device.baseType, dtype, + str(device)) except (KeyError, ValueError): pass diff --git a/homeassistant/components/fibaro/climate.py b/homeassistant/components/fibaro/climate.py new file mode 100644 index 00000000000..0d1ecc3a77f --- /dev/null +++ b/homeassistant/components/fibaro/climate.py @@ -0,0 +1,291 @@ +"""Support for Fibaro thermostats.""" +import logging + +from homeassistant.components.climate.const import ( + STATE_AUTO, STATE_COOL, STATE_DRY, + STATE_ECO, STATE_FAN_ONLY, STATE_HEAT, + STATE_MANUAL, SUPPORT_TARGET_TEMPERATURE, + SUPPORT_OPERATION_MODE, SUPPORT_FAN_MODE) + +from homeassistant.components.climate import ( + ClimateDevice) + +from homeassistant.const import ( + ATTR_TEMPERATURE, + STATE_OFF, + TEMP_CELSIUS, + TEMP_FAHRENHEIT) + +from . import ( + FIBARO_DEVICES, FibaroDevice) + +SPEED_LOW = 'low' +SPEED_MEDIUM = 'medium' +SPEED_HIGH = 'high' + +# State definitions missing from HA, but defined by Z-Wave standard. +# We map them to states known supported by HA here: +STATE_AUXILIARY = STATE_HEAT +STATE_RESUME = STATE_HEAT +STATE_MOIST = STATE_DRY +STATE_AUTO_CHANGEOVER = STATE_AUTO +STATE_ENERGY_HEAT = STATE_ECO +STATE_ENERGY_COOL = STATE_COOL +STATE_FULL_POWER = STATE_AUTO +STATE_FORCE_OPEN = STATE_MANUAL +STATE_AWAY = STATE_AUTO +STATE_FURNACE = STATE_HEAT + +FAN_AUTO_HIGH = 'auto_high' +FAN_AUTO_MEDIUM = 'auto_medium' +FAN_CIRCULATION = 'circulation' +FAN_HUMIDITY_CIRCULATION = 'humidity_circulation' +FAN_LEFT_RIGHT = 'left_right' +FAN_UP_DOWN = 'up_down' +FAN_QUIET = 'quiet' + +DEPENDENCIES = ['fibaro'] + +_LOGGER = logging.getLogger(__name__) + +# SDS13781-10 Z-Wave Application Command Class Specification 2019-01-04 +# Table 128, Thermostat Fan Mode Set version 4::Fan Mode encoding +FANMODES = { + 0: STATE_OFF, + 1: SPEED_LOW, + 2: FAN_AUTO_HIGH, + 3: SPEED_HIGH, + 4: FAN_AUTO_MEDIUM, + 5: SPEED_MEDIUM, + 6: FAN_CIRCULATION, + 7: FAN_HUMIDITY_CIRCULATION, + 8: FAN_LEFT_RIGHT, + 9: FAN_UP_DOWN, + 10: FAN_QUIET, + 128: STATE_AUTO +} + +# SDS13781-10 Z-Wave Application Command Class Specification 2019-01-04 +# Table 130, Thermostat Mode Set version 3::Mode encoding. +OPMODES = { + 0: STATE_OFF, + 1: STATE_HEAT, + 2: STATE_COOL, + 3: STATE_AUTO, + 4: STATE_AUXILIARY, + 5: STATE_RESUME, + 6: STATE_FAN_ONLY, + 7: STATE_FURNACE, + 8: STATE_DRY, + 9: STATE_MOIST, + 10: STATE_AUTO_CHANGEOVER, + 11: STATE_ENERGY_HEAT, + 12: STATE_ENERGY_COOL, + 13: STATE_AWAY, + 15: STATE_FULL_POWER, + 31: STATE_FORCE_OPEN +} + +SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Perform the setup for Fibaro controller devices.""" + if discovery_info is None: + return + + add_entities( + [FibaroThermostat(device) + for device in hass.data[FIBARO_DEVICES]['climate']], True) + + +class FibaroThermostat(FibaroDevice, ClimateDevice): + """Representation of a Fibaro Thermostat.""" + + def __init__(self, fibaro_device): + """Initialize the Fibaro device.""" + super().__init__(fibaro_device) + self._temp_sensor_device = None + self._target_temp_device = None + self._op_mode_device = None + self._fan_mode_device = None + self._support_flags = 0 + self.entity_id = 'climate.{}'.format(self.ha_id) + self._fan_mode_to_state = {} + self._fan_state_to_mode = {} + self._op_mode_to_state = {} + self._op_state_to_mode = {} + + siblings = fibaro_device.fibaro_controller.get_siblings( + fibaro_device.id) + tempunit = 'C' + for device in siblings: + if device.type == 'com.fibaro.temperatureSensor': + self._temp_sensor_device = FibaroDevice(device) + tempunit = device.properties.unit + if 'setTargetLevel' in device.actions or \ + 'setThermostatSetpoint' in device.actions: + self._target_temp_device = FibaroDevice(device) + self._support_flags |= SUPPORT_TARGET_TEMPERATURE + tempunit = device.properties.unit + if 'setMode' in device.actions or \ + 'setOperatingMode' in device.actions: + self._op_mode_device = FibaroDevice(device) + self._support_flags |= SUPPORT_OPERATION_MODE + if 'setFanMode' in device.actions: + self._fan_mode_device = FibaroDevice(device) + self._support_flags |= SUPPORT_FAN_MODE + + if tempunit == 'F': + self._unit_of_temp = TEMP_FAHRENHEIT + else: + self._unit_of_temp = TEMP_CELSIUS + + if self._fan_mode_device: + fan_modes = self._fan_mode_device.fibaro_device.\ + properties.supportedModes.split(",") + for mode in fan_modes: + try: + self._fan_mode_to_state[int(mode)] = FANMODES[int(mode)] + self._fan_state_to_mode[FANMODES[int(mode)]] = int(mode) + except KeyError: + self._fan_mode_to_state[int(mode)] = 'unknown' + + if self._op_mode_device: + prop = self._op_mode_device.fibaro_device.properties + if "supportedOperatingModes" in prop: + op_modes = prop.supportedOperatingModes.split(",") + elif "supportedModes" in prop: + op_modes = prop.supportedModes.split(",") + for mode in op_modes: + try: + self._op_mode_to_state[int(mode)] = OPMODES[int(mode)] + self._op_state_to_mode[OPMODES[int(mode)]] = int(mode) + except KeyError: + self._op_mode_to_state[int(mode)] = 'unknown' + + async def async_added_to_hass(self): + """Call when entity is added to hass.""" + _LOGGER.debug("Climate %s\n" + "- _temp_sensor_device %s\n" + "- _target_temp_device %s\n" + "- _op_mode_device %s\n" + "- _fan_mode_device %s", + self.ha_id, + self._temp_sensor_device.ha_id + if self._temp_sensor_device else "None", + self._target_temp_device.ha_id + if self._target_temp_device else "None", + self._op_mode_device.ha_id + if self._op_mode_device else "None", + self._fan_mode_device.ha_id + if self._fan_mode_device else "None") + await super().async_added_to_hass() + + # Register update callback for child devices + siblings = self.fibaro_device.fibaro_controller.get_siblings( + self.fibaro_device.id) + for device in siblings: + if device != self.fibaro_device: + self.controller.register(device.id, + self._update_callback) + + @property + def supported_features(self): + """Return the list of supported features.""" + return self._support_flags + + @property + def fan_list(self): + """Return the list of available fan modes.""" + if self._fan_mode_device is None: + return None + return list(self._fan_state_to_mode) + + @property + def current_fan_mode(self): + """Return the fan setting.""" + if self._fan_mode_device is None: + return None + + mode = int(self._fan_mode_device.fibaro_device.properties.mode) + return self._fan_mode_to_state[mode] + + def set_fan_mode(self, fan_mode): + """Set new target fan mode.""" + if self._fan_mode_device is None: + return + self._fan_mode_device.action( + "setFanMode", self._fan_state_to_mode[fan_mode]) + + @property + def current_operation(self): + """Return current operation ie. heat, cool, idle.""" + if self._op_mode_device is None: + return None + + if "operatingMode" in self._op_mode_device.fibaro_device.properties: + mode = int(self._op_mode_device.fibaro_device. + properties.operatingMode) + else: + mode = int(self._op_mode_device.fibaro_device.properties.mode) + return self._op_mode_to_state.get(mode) + + @property + def operation_list(self): + """Return the list of available operation modes.""" + if self._op_mode_device is None: + return None + return list(self._op_state_to_mode) + + def set_operation_mode(self, operation_mode): + """Set new target operation mode.""" + if self._op_mode_device is None: + return + if "setOperatingMode" in self._op_mode_device.fibaro_device.actions: + self._op_mode_device.action( + "setOperatingMode", self._op_state_to_mode[operation_mode]) + elif "setMode" in self._op_mode_device.fibaro_device.actions: + self._op_mode_device.action( + "setMode", self._op_state_to_mode[operation_mode]) + + @property + def temperature_unit(self): + """Return the unit of measurement.""" + return self._unit_of_temp + + @property + def current_temperature(self): + """Return the current temperature.""" + if self._temp_sensor_device: + device = self._temp_sensor_device.fibaro_device + return float(device.properties.value) + return None + + @property + def target_temperature(self): + """Return the temperature we try to reach.""" + if self._target_temp_device: + device = self._target_temp_device.fibaro_device + return float(device.properties.targetLevel) + return None + + def set_temperature(self, **kwargs): + """Set new target temperatures.""" + temperature = kwargs.get(ATTR_TEMPERATURE) + target = self._target_temp_device + if temperature is not None: + if "setThermostatSetpoint" in target.fibaro_device.actions: + target.action("setThermostatSetpoint", + self._op_state_to_mode[self.current_operation], + temperature) + else: + target.action("setTargetLevel", + temperature) + + @property + def is_on(self): + """Return true if on.""" + if self.current_operation == STATE_OFF: + return False + return True