diff --git a/.coveragerc b/.coveragerc index 5eac18b8d7e..a87b4d7f8f4 100644 --- a/.coveragerc +++ b/.coveragerc @@ -539,6 +539,7 @@ omit = homeassistant/components/sochain/sensor.py homeassistant/components/socialblade/sensor.py homeassistant/components/solaredge/sensor.py + homeassistant/components/somfy_mylink/* homeassistant/components/sonarr/sensor.py homeassistant/components/songpal/media_player.py homeassistant/components/sonos/* diff --git a/homeassistant/components/somfy_mylink/__init__.py b/homeassistant/components/somfy_mylink/__init__.py new file mode 100755 index 00000000000..c8a6314acaa --- /dev/null +++ b/homeassistant/components/somfy_mylink/__init__.py @@ -0,0 +1,63 @@ +"""Component for the Somfy MyLink device supporting the Synergy API.""" +import logging + +import voluptuous as vol + +from homeassistant.const import CONF_HOST, CONF_PORT +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.discovery import async_load_platform + +_LOGGER = logging.getLogger(__name__) +REQUIREMENTS = ['somfy-mylink-synergy==1.0.4'] +CONF_ENTITY_CONFIG = 'entity_config' +CONF_SYSTEM_ID = 'system_id' +CONF_REVERSE = 'reverse' +CONF_DEFAULT_REVERSE = 'default_reverse' +DATA_SOMFY_MYLINK = 'somfy_mylink_data' +DOMAIN = 'somfy_mylink' +SOMFY_MYLINK_COMPONENTS = [ + 'cover' +] + + +def validate_entity_config(values): + """Validate config entry for CONF_ENTITY.""" + entity_config_schema = vol.Schema({ + vol.Optional(CONF_REVERSE): cv.boolean + }) + if not isinstance(values, dict): + raise vol.Invalid('expected a dictionary') + entities = {} + for entity_id, config in values.items(): + entity = cv.entity_id(entity_id) + config = entity_config_schema(config) + entities[entity] = config + return entities + + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_SYSTEM_ID): cv.string, + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_PORT, default=44100): cv.port, + vol.Optional(CONF_DEFAULT_REVERSE, default=False): cv.boolean, + vol.Optional(CONF_ENTITY_CONFIG, default={}): validate_entity_config + }) +}, extra=vol.ALLOW_EXTRA) + + +async def async_setup(hass, config): + """Set up the MyLink platform.""" + from somfy_mylink_synergy import SomfyMyLinkSynergy + host = config[DOMAIN][CONF_HOST] + port = config[DOMAIN][CONF_PORT] + system_id = config[DOMAIN][CONF_SYSTEM_ID] + entity_config = config[DOMAIN][CONF_ENTITY_CONFIG] + entity_config[CONF_DEFAULT_REVERSE] = config[DOMAIN][CONF_DEFAULT_REVERSE] + somfy_mylink = SomfyMyLinkSynergy(system_id, host, port) + hass.data[DATA_SOMFY_MYLINK] = somfy_mylink + for component in SOMFY_MYLINK_COMPONENTS: + hass.async_create_task(async_load_platform( + hass, component, DOMAIN, entity_config, + config)) + return True diff --git a/homeassistant/components/somfy_mylink/cover.py b/homeassistant/components/somfy_mylink/cover.py new file mode 100755 index 00000000000..c5ea70a600d --- /dev/null +++ b/homeassistant/components/somfy_mylink/cover.py @@ -0,0 +1,85 @@ +"""Cover Platform for the Somfy MyLink component.""" +import logging + +from homeassistant.components.cover import ENTITY_ID_FORMAT, CoverDevice +from homeassistant.util import slugify + +from . import CONF_DEFAULT_REVERSE, DATA_SOMFY_MYLINK + +_LOGGER = logging.getLogger(__name__) +DEPENDENCIES = ['somfy_mylink'] + + +async def async_setup_platform(hass, + config, + async_add_entities, + discovery_info=None): + """Discover and configure Somfy covers.""" + if discovery_info is None: + return + somfy_mylink = hass.data[DATA_SOMFY_MYLINK] + cover_list = [] + try: + mylink_status = await somfy_mylink.status_info() + except TimeoutError: + _LOGGER.error("Unable to connect to the Somfy MyLink device, " + "please check your settings") + return + for cover in mylink_status['result']: + entity_id = ENTITY_ID_FORMAT.format(slugify(cover['name'])) + entity_config = discovery_info.get(entity_id, {}) + default_reverse = discovery_info[CONF_DEFAULT_REVERSE] + cover_config = {} + cover_config['target_id'] = cover['targetID'] + cover_config['name'] = cover['name'] + cover_config['reverse'] = entity_config.get('reverse', default_reverse) + cover_list.append(SomfyShade(somfy_mylink, **cover_config)) + _LOGGER.info('Adding Somfy Cover: %s with targetID %s', + cover_config['name'], cover_config['target_id']) + async_add_entities(cover_list) + + +class SomfyShade(CoverDevice): + """Object for controlling a Somfy cover.""" + + def __init__(self, somfy_mylink, target_id='AABBCC', name='SomfyShade', + reverse=False, device_class='window'): + """Initialize the cover.""" + self.somfy_mylink = somfy_mylink + self._target_id = target_id + self._name = name + self._reverse = reverse + self._device_class = device_class + + @property + def name(self): + """Return the name of the cover.""" + return self._name + + @property + def is_closed(self): + """Return if the cover is closed.""" + pass + + @property + def device_class(self): + """Return the class of this device, from component DEVICE_CLASSES.""" + return self._device_class + + async def async_open_cover(self, **kwargs): + """Wrap Homeassistant calls to open the cover.""" + if not self._reverse: + await self.somfy_mylink.move_up(self._target_id) + else: + await self.somfy_mylink.move_down(self._target_id) + + async def async_close_cover(self, **kwargs): + """Wrap Homeassistant calls to close the cover.""" + if not self._reverse: + await self.somfy_mylink.move_down(self._target_id) + else: + await self.somfy_mylink.move_up(self._target_id) + + async def async_stop_cover(self, **kwargs): + """Stop the cover.""" + await self.somfy_mylink.move_stop(self._target_id) diff --git a/homeassistant/components/somfy_mylink/manifest.json b/homeassistant/components/somfy_mylink/manifest.json new file mode 100644 index 00000000000..5a3cec0def8 --- /dev/null +++ b/homeassistant/components/somfy_mylink/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "somfy_mylink", + "name": "Somfy MyLink", + "documentation": "https://www.home-assistant.io/components/somfy_mylink", + "requirements": [ + "somfy-mylink-synergy==1.0.4" + ], + "dependencies": [], + "codeowners": [] + } \ No newline at end of file diff --git a/requirements_all.txt b/requirements_all.txt index b64079b4460..26668571462 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1598,6 +1598,9 @@ solaredge==0.0.2 # homeassistant.components.honeywell somecomfort==0.5.2 +# homeassistant.components.somfy_mylink +somfy-mylink-synergy==1.0.4 + # homeassistant.components.speedtestdotnet speedtest-cli==2.1.1