Skip to content

Commit

Permalink
Fix demo (#23087)
Browse files Browse the repository at this point in the history
* Fix demo

* Fix types

* Fix all the things

* Fix type

* Fix test

* Lint
  • Loading branch information
balloob authored Apr 14, 2019
1 parent 1d2e9b6 commit 6b0180f
Show file tree
Hide file tree
Showing 20 changed files with 137 additions and 200 deletions.
16 changes: 7 additions & 9 deletions homeassistant/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
import voluptuous as vol

from homeassistant import core, config as conf_util, config_entries, loader
from homeassistant.components import (
persistent_notification, homeassistant as core_component
)
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
from homeassistant.setup import async_setup_component
from homeassistant.util.logging import AsyncHandler
Expand Down Expand Up @@ -139,17 +136,18 @@ async def async_from_config_dict(config: Dict[str, Any],
if isinstance(dep_domains, set):
domains.update(dep_domains)

# setup components
res = await core_component.async_setup(hass, config)
if not res:
# Set up core.
if not all(await asyncio.gather(
async_setup_component(hass, 'homeassistant', config),
async_setup_component(hass, 'persistent_notification', config),
)):
_LOGGER.error("Home Assistant core failed to initialize. "
"Further initialization aborted")
return hass

await persistent_notification.async_setup(hass, config)

_LOGGER.info("Home Assistant core initialized")
_LOGGER.debug("Home Assistant core initialized")

# setup components
# stage 0, load logging components
for domain in domains:
if domain in LOGGING_COMPONENT:
Expand Down
157 changes: 61 additions & 96 deletions homeassistant/components/demo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""Set up the demo environment that mimics interaction with devices."""
import asyncio
import logging
import time
import sys

from homeassistant import bootstrap
import homeassistant.core as ha
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM
from homeassistant.const import ATTR_ENTITY_ID, EVENT_HOMEASSISTANT_START

DOMAIN = 'demo'

_LOGGER = logging.getLogger(__name__)
COMPONENTS_WITH_DEMO_PLATFORM = [
'air_quality',
'alarm_control_panel',
Expand All @@ -31,36 +31,31 @@
]


async def _async_setup(hass, config):
async def async_setup(hass, config):
"""Set up the demo environment."""
group = hass.components.group
configurator = hass.components.configurator
persistent_notification = hass.components.persistent_notification
if DOMAIN not in config:
return True

config.setdefault(ha.DOMAIN, {})
config.setdefault(DOMAIN, {})

if config[DOMAIN].get('hide_demo_state') != 1:
hass.states.async_set('a.Demo_Mode', 'Enabled')
# Set up demo platforms
for component in COMPONENTS_WITH_DEMO_PLATFORM:
hass.async_create_task(hass.helpers.discovery.async_load_platform(
component, DOMAIN, {}, config,
))

# Setup sun
# Set up sun
if not hass.config.latitude:
hass.config.latitude = 32.87336

if not hass.config.longitude:
hass.config.longitude = 117.22743

tasks = [
bootstrap.async_setup_component(hass, 'sun')
bootstrap.async_setup_component(hass, 'sun', config)
]

# Set up demo platforms
demo_config = config.copy()
for component in COMPONENTS_WITH_DEMO_PLATFORM:
demo_config[component] = {CONF_PLATFORM: 'demo'}
tasks.append(
bootstrap.async_setup_component(hass, component, demo_config))

# Set up input select
tasks.append(bootstrap.async_setup_component(
hass, 'input_select',
Expand All @@ -72,6 +67,7 @@ async def _async_setup(hass, config):
'initial': 'Anne Therese',
'name': 'Cook today',
'options': ['Paulus', 'Anne Therese']}}}))

# Set up input boolean
tasks.append(bootstrap.async_setup_component(
hass, 'input_boolean',
Expand All @@ -96,36 +92,71 @@ async def _async_setup(hass, config):
{'weblink': {'entities': [{'name': 'Router',
'url': 'http://192.168.1.1'}]}}))

results = await asyncio.gather(*tasks, loop=hass.loop)
results = await asyncio.gather(*tasks)

if any(not result for result in results):
return False

# Set up example persistent notification
persistent_notification.async_create(
hass.components.persistent_notification.async_create(
'This is an example of a persistent notification.',
title='Example Notification')

# Set up room groups
# Set up configurator
configurator_ids = []
configurator = hass.components.configurator

def hue_configuration_callback(data):
"""Fake callback, mark config as done."""
time.sleep(2)

# First time it is called, pretend it failed.
if len(configurator_ids) == 1:
configurator.notify_errors(
configurator_ids[0],
"Failed to register, please try again.")

configurator_ids.append(0)
else:
configurator.request_done(configurator_ids[0])

request_id = configurator.async_request_config(
"Philips Hue", hue_configuration_callback,
description=("Press the button on the bridge to register Philips "
"Hue with Home Assistant."),
description_image="/static/images/config_philips_hue.jpg",
fields=[{'id': 'username', 'name': 'Username'}],
submit_caption="I have pressed the button"
)
configurator_ids.append(request_id)

async def demo_start_listener(_event):
"""Finish set up."""
await finish_setup(hass, config)

hass.bus.async_listen(EVENT_HOMEASSISTANT_START, demo_start_listener)

return True


async def finish_setup(hass, config):
"""Finish set up once demo platforms are set up."""
lights = sorted(hass.states.async_entity_ids('light'))
switches = sorted(hass.states.async_entity_ids('switch'))
media_players = sorted(hass.states.async_entity_ids('media_player'))

tasks2 = []

# Set up history graph
tasks2.append(bootstrap.async_setup_component(
await bootstrap.async_setup_component(
hass, 'history_graph',
{'history_graph': {'switches': {
'name': 'Recent Switches',
'entities': switches,
'hours_to_show': 1,
'refresh': 60
}}}
))
)

# Set up scripts
tasks2.append(bootstrap.async_setup_component(
await bootstrap.async_setup_component(
hass, 'script',
{'script': {
'demo': {
Expand All @@ -144,10 +175,10 @@ async def _async_setup(hass, config):
'service': 'light.turn_off',
'data': {ATTR_ENTITY_ID: lights[0]}
}]
}}}))
}}})

# Set up scenes
tasks2.append(bootstrap.async_setup_component(
await bootstrap.async_setup_component(
hass, 'scene',
{'scene': [
{'name': 'Romantic lights',
Expand All @@ -161,70 +192,4 @@ async def _async_setup(hass, config):
switches[0]: True,
switches[1]: False,
}},
]}))

tasks2.append(group.Group.async_create_group(hass, 'Living Room', [
lights[1], switches[0], 'input_select.living_room_preset',
'cover.living_room_window', media_players[1],
'scene.romantic_lights']))
tasks2.append(group.Group.async_create_group(hass, 'Bedroom', [
lights[0], switches[1], media_players[0],
'input_number.noise_allowance']))
tasks2.append(group.Group.async_create_group(hass, 'Kitchen', [
lights[2], 'cover.kitchen_window', 'lock.kitchen_door']))
tasks2.append(group.Group.async_create_group(hass, 'Doors', [
'lock.front_door', 'lock.kitchen_door',
'garage_door.right_garage_door', 'garage_door.left_garage_door']))
tasks2.append(group.Group.async_create_group(hass, 'Automations', [
'input_select.who_cooks', 'input_boolean.notify', ]))
tasks2.append(group.Group.async_create_group(hass, 'People', [
'device_tracker.demo_anne_therese', 'device_tracker.demo_home_boy',
'device_tracker.demo_paulus']))
tasks2.append(group.Group.async_create_group(hass, 'Downstairs', [
'group.living_room', 'group.kitchen',
'scene.romantic_lights', 'cover.kitchen_window',
'cover.living_room_window', 'group.doors',
'climate.ecobee',
], view=True))

results = await asyncio.gather(*tasks2, loop=hass.loop)

if any(not result for result in results):
return False

# Set up configurator
configurator_ids = []

def hue_configuration_callback(data):
"""Fake callback, mark config as done."""
time.sleep(2)

# First time it is called, pretend it failed.
if len(configurator_ids) == 1:
configurator.notify_errors(
configurator_ids[0],
"Failed to register, please try again.")

configurator_ids.append(0)
else:
configurator.request_done(configurator_ids[0])

def setup_configurator():
"""Set up a configurator."""
request_id = configurator.request_config(
"Philips Hue", hue_configuration_callback,
description=("Press the button on the bridge to register Philips "
"Hue with Home Assistant."),
description_image="/static/images/config_philips_hue.jpg",
fields=[{'id': 'username', 'name': 'Username'}],
submit_caption="I have pressed the button"
)
configurator_ids.append(request_id)

hass.async_add_job(setup_configurator)

return True


if 'pytest' not in sys.modules:
async_setup = _async_setup # pylint: disable=invalid-name
]})
2 changes: 1 addition & 1 deletion homeassistant/components/wemo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def discover_wemo_devices(now):
'ssdp_description': url,
}

discovery.discover(hass, SERVICE_WEMO, discovery_info)
discovery_dispatch(SERVICE_WEMO, discovery_info)

_LOGGER.debug("WeMo device discovery has finished")

Expand Down
6 changes: 3 additions & 3 deletions homeassistant/helpers/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ def discovery_event_listener(event):


@bind_hass
def discover(hass, service, discovered=None, component=None, hass_config=None):
def discover(hass, service, discovered, component, hass_config):
"""Fire discovery event. Can ensure a component is loaded."""
hass.add_job(
async_discover(hass, service, discovered, component, hass_config))


@bind_hass
async def async_discover(hass, service, discovered=None, component=None,
hass_config=None):
async def async_discover(hass, service, discovered, component,
hass_config):
"""Fire discovery event. Can ensure a component is loaded."""
if component in DEPENDENCY_BLACKLIST:
raise HomeAssistantError(
Expand Down
6 changes: 5 additions & 1 deletion homeassistant/helpers/entity_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ async def async_setup_entry(self, config_entry):
"""Set up a config entry."""
platform_type = config_entry.domain
platform = await async_prepare_setup_platform(
self.hass, self.config, self.domain, platform_type)
self.hass,
# In future PR we should make hass_config part of the constructor
# params.
self.config or {},
self.domain, platform_type)

if platform is None:
return False
Expand Down
4 changes: 4 additions & 0 deletions homeassistant/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ def get_platform(self, platform_name: str) -> ModuleType:
)
return cache[full_name] # type: ignore

def __repr__(self) -> str:
"""Text representation of class."""
return "<Integration {}: {}>".format(self.domain, self.pkg_path)


async def async_get_integration(hass: 'HomeAssistant', domain: str)\
-> Integration:
Expand Down
14 changes: 4 additions & 10 deletions homeassistant/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,26 @@


def setup_component(hass: core.HomeAssistant, domain: str,
config: Optional[Dict] = None) -> bool:
config: Dict) -> bool:
"""Set up a component and all its dependencies."""
return run_coroutine_threadsafe( # type: ignore
async_setup_component(hass, domain, config), loop=hass.loop).result()


async def async_setup_component(hass: core.HomeAssistant, domain: str,
config: Optional[Dict] = None) -> bool:
config: Dict) -> bool:
"""Set up a component and all its dependencies.
This method is a coroutine.
"""
if domain in hass.config.components:
return True

setup_tasks = hass.data.get(DATA_SETUP)
setup_tasks = hass.data.setdefault(DATA_SETUP, {})

if setup_tasks is not None and domain in setup_tasks:
if domain in setup_tasks:
return await setup_tasks[domain] # type: ignore

if config is None:
config = {}

if setup_tasks is None:
setup_tasks = hass.data[DATA_SETUP] = {}

task = setup_tasks[domain] = hass.async_create_task(
_async_setup_component(hass, domain, config))

Expand Down
Loading

0 comments on commit 6b0180f

Please sign in to comment.