2020-02-14 02:52:51 +00:00
|
|
|
"""
|
|
|
|
Custom element manager for community created elements.
|
|
|
|
|
|
|
|
For more details about this integration, please refer to the documentation at
|
|
|
|
https://hacs.xyz/
|
|
|
|
"""
|
2020-04-10 01:29:27 +00:00
|
|
|
|
2020-02-14 02:52:51 +00:00
|
|
|
import voluptuous as vol
|
2020-05-21 22:48:00 +00:00
|
|
|
from aiogithubapi import GitHub, AIOGitHubAPIException
|
2020-02-14 02:52:51 +00:00
|
|
|
from homeassistant import config_entries
|
|
|
|
from homeassistant.const import EVENT_HOMEASSISTANT_START
|
|
|
|
from homeassistant.const import __version__ as HAVERSION
|
|
|
|
from homeassistant.components.lovelace import system_health_info
|
|
|
|
from homeassistant.exceptions import ConfigEntryNotReady, ServiceNotFound
|
|
|
|
from homeassistant.helpers.aiohttp_client import async_create_clientsession
|
|
|
|
from homeassistant.helpers.event import async_call_later
|
|
|
|
|
2020-05-21 22:48:00 +00:00
|
|
|
from custom_components.hacs.configuration_schema import hacs_config_combined
|
2020-04-10 01:29:27 +00:00
|
|
|
from custom_components.hacs.const import DOMAIN, ELEMENT_TYPES, STARTUP, VERSION
|
2020-05-21 22:48:00 +00:00
|
|
|
from custom_components.hacs.constrains import check_constrains
|
2020-05-03 20:23:17 +00:00
|
|
|
from custom_components.hacs.helpers.remaining_github_calls import get_fetch_updates_for
|
2020-04-10 01:29:27 +00:00
|
|
|
from custom_components.hacs.hacsbase.configuration import Configuration
|
|
|
|
from custom_components.hacs.hacsbase.data import HacsData
|
|
|
|
from custom_components.hacs.setup import (
|
|
|
|
add_sensor,
|
|
|
|
load_hacs_repository,
|
|
|
|
setup_frontend,
|
|
|
|
)
|
|
|
|
|
|
|
|
from custom_components.hacs.globals import get_hacs
|
|
|
|
|
|
|
|
from custom_components.hacs.helpers.network import internet_connectivity_check
|
2020-02-14 02:52:51 +00:00
|
|
|
|
2020-05-21 22:48:00 +00:00
|
|
|
CONFIG_SCHEMA = vol.Schema({DOMAIN: hacs_config_combined()}, extra=vol.ALLOW_EXTRA)
|
2020-02-14 02:52:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def async_setup(hass, config):
|
|
|
|
"""Set up this integration using yaml."""
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs = get_hacs()
|
2020-02-14 02:52:51 +00:00
|
|
|
if DOMAIN not in config:
|
|
|
|
return True
|
2020-05-03 20:23:17 +00:00
|
|
|
if hacs.configuration and hacs.configuration.config_type == "flow":
|
|
|
|
return True
|
2020-02-14 02:52:51 +00:00
|
|
|
hass.data[DOMAIN] = config
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.hass = hass
|
|
|
|
hacs.session = async_create_clientsession(hass)
|
2020-05-21 22:48:00 +00:00
|
|
|
hacs.configuration = Configuration.from_dict(config[DOMAIN])
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.configuration.config = config
|
|
|
|
hacs.configuration.config_type = "yaml"
|
|
|
|
await startup_wrapper_for_yaml()
|
2020-02-14 02:52:51 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
async def async_setup_entry(hass, config_entry):
|
|
|
|
"""Set up this integration using UI."""
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs = get_hacs()
|
2020-02-14 02:52:51 +00:00
|
|
|
conf = hass.data.get(DOMAIN)
|
2020-05-21 22:48:00 +00:00
|
|
|
if conf is not None:
|
|
|
|
return False
|
2020-02-14 02:52:51 +00:00
|
|
|
if config_entry.source == config_entries.SOURCE_IMPORT:
|
2020-05-21 22:48:00 +00:00
|
|
|
hass.async_create_task(hass.config_entries.async_remove(config_entry.entry_id))
|
2020-02-14 02:52:51 +00:00
|
|
|
return False
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.hass = hass
|
|
|
|
hacs.session = async_create_clientsession(hass)
|
|
|
|
hacs.configuration = Configuration.from_dict(
|
2020-02-14 02:52:51 +00:00
|
|
|
config_entry.data, config_entry.options
|
|
|
|
)
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.configuration.config_type = "flow"
|
|
|
|
hacs.configuration.config_entry = config_entry
|
2020-02-14 02:52:51 +00:00
|
|
|
config_entry.add_update_listener(reload_hacs)
|
2020-05-03 20:23:17 +00:00
|
|
|
try:
|
|
|
|
startup_result = await hacs_startup()
|
2020-05-21 22:48:00 +00:00
|
|
|
except AIOGitHubAPIException:
|
2020-05-03 20:23:17 +00:00
|
|
|
startup_result = False
|
2020-02-14 02:52:51 +00:00
|
|
|
if not startup_result:
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.system.disabled = True
|
2020-02-14 02:52:51 +00:00
|
|
|
raise ConfigEntryNotReady
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.system.disabled = False
|
2020-02-14 02:52:51 +00:00
|
|
|
return startup_result
|
|
|
|
|
|
|
|
|
2020-04-10 01:29:27 +00:00
|
|
|
async def startup_wrapper_for_yaml():
|
2020-02-14 02:52:51 +00:00
|
|
|
"""Startup wrapper for yaml config."""
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs = get_hacs()
|
2020-05-03 20:23:17 +00:00
|
|
|
try:
|
|
|
|
startup_result = await hacs_startup()
|
2020-05-21 22:48:00 +00:00
|
|
|
except AIOGitHubAPIException:
|
2020-05-03 20:23:17 +00:00
|
|
|
startup_result = False
|
2020-02-14 02:52:51 +00:00
|
|
|
if not startup_result:
|
|
|
|
hacs.system.disabled = True
|
|
|
|
hacs.hass.components.frontend.async_remove_panel(
|
|
|
|
hacs.configuration.sidepanel_title.lower()
|
|
|
|
.replace(" ", "_")
|
|
|
|
.replace("-", "_")
|
|
|
|
)
|
|
|
|
hacs.logger.info("Could not setup HACS, trying again in 15 min")
|
2020-04-10 01:29:27 +00:00
|
|
|
async_call_later(hacs.hass, 900, startup_wrapper_for_yaml())
|
2020-02-14 02:52:51 +00:00
|
|
|
return
|
|
|
|
hacs.system.disabled = False
|
|
|
|
|
|
|
|
|
2020-04-10 01:29:27 +00:00
|
|
|
async def hacs_startup():
|
2020-02-14 02:52:51 +00:00
|
|
|
"""HACS startup tasks."""
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs = get_hacs()
|
2020-02-14 02:52:51 +00:00
|
|
|
if hacs.configuration.debug:
|
|
|
|
try:
|
|
|
|
await hacs.hass.services.async_call(
|
|
|
|
"logger", "set_level", {"hacs": "debug"}
|
|
|
|
)
|
2020-05-03 20:23:17 +00:00
|
|
|
await hacs.hass.services.async_call(
|
|
|
|
"logger", "set_level", {"queueman": "debug"}
|
|
|
|
)
|
|
|
|
await hacs.hass.services.async_call(
|
|
|
|
"logger", "set_level", {"AioGitHub": "debug"}
|
|
|
|
)
|
2020-02-14 02:52:51 +00:00
|
|
|
except ServiceNotFound:
|
|
|
|
hacs.logger.error(
|
|
|
|
"Could not set logging level to debug, logger is not enabled"
|
|
|
|
)
|
|
|
|
|
|
|
|
lovelace_info = await system_health_info(hacs.hass)
|
|
|
|
hacs.logger.debug(f"Configuration type: {hacs.configuration.config_type}")
|
|
|
|
hacs.version = VERSION
|
|
|
|
hacs.logger.info(STARTUP)
|
|
|
|
hacs.system.config_path = hacs.hass.config.path()
|
|
|
|
hacs.system.ha_version = HAVERSION
|
|
|
|
|
|
|
|
hacs.system.lovelace_mode = lovelace_info.get("mode", "yaml")
|
|
|
|
hacs.system.disabled = False
|
2020-05-21 22:48:00 +00:00
|
|
|
hacs.github = GitHub(
|
2020-02-14 02:52:51 +00:00
|
|
|
hacs.configuration.token, async_create_clientsession(hacs.hass)
|
|
|
|
)
|
|
|
|
hacs.data = HacsData()
|
|
|
|
|
2020-05-03 20:23:17 +00:00
|
|
|
can_update = await get_fetch_updates_for(hacs.github)
|
|
|
|
if can_update == 0:
|
|
|
|
hacs.logger.info("HACS is ratelimited, repository updates will resume in 1h.")
|
|
|
|
else:
|
|
|
|
hacs.logger.debug(f"Can update {can_update} repositories")
|
|
|
|
|
2020-02-14 02:52:51 +00:00
|
|
|
# Check HACS Constrains
|
2020-05-21 22:48:00 +00:00
|
|
|
if not await hacs.hass.async_add_executor_job(check_constrains):
|
2020-02-14 02:52:51 +00:00
|
|
|
if hacs.configuration.config_type == "flow":
|
|
|
|
if hacs.configuration.config_entry is not None:
|
|
|
|
await async_remove_entry(hacs.hass, hacs.configuration.config_entry)
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Set up frontend
|
2020-04-10 01:29:27 +00:00
|
|
|
await setup_frontend()
|
2020-02-14 02:52:51 +00:00
|
|
|
|
2020-04-10 01:29:27 +00:00
|
|
|
if not await hacs.hass.async_add_executor_job(internet_connectivity_check):
|
|
|
|
hacs.logger.critical("No network connectivity")
|
|
|
|
return False
|
2020-02-14 02:52:51 +00:00
|
|
|
|
|
|
|
# Load HACS
|
2020-04-10 01:29:27 +00:00
|
|
|
if not await load_hacs_repository():
|
2020-02-14 02:52:51 +00:00
|
|
|
if hacs.configuration.config_type == "flow":
|
|
|
|
if hacs.configuration.config_entry is not None:
|
|
|
|
await async_remove_entry(hacs.hass, hacs.configuration.config_entry)
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Restore from storefiles
|
|
|
|
if not await hacs.data.restore():
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs_repo = hacs.get_by_name("hacs/integration")
|
2020-02-14 02:52:51 +00:00
|
|
|
hacs_repo.pending_restart = True
|
|
|
|
if hacs.configuration.config_type == "flow":
|
|
|
|
if hacs.configuration.config_entry is not None:
|
|
|
|
await async_remove_entry(hacs.hass, hacs.configuration.config_entry)
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Add aditional categories
|
|
|
|
hacs.common.categories = ELEMENT_TYPES
|
|
|
|
if hacs.configuration.appdaemon:
|
|
|
|
hacs.common.categories.append("appdaemon")
|
2020-04-10 01:29:27 +00:00
|
|
|
if hacs.configuration.netdaemon:
|
|
|
|
hacs.common.categories.append("netdaemon")
|
2020-02-14 02:52:51 +00:00
|
|
|
|
|
|
|
# Setup startup tasks
|
|
|
|
if hacs.configuration.config_type == "yaml":
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, hacs.startup_tasks())
|
2020-02-14 02:52:51 +00:00
|
|
|
else:
|
2020-04-10 01:29:27 +00:00
|
|
|
async_call_later(hacs.hass, 5, hacs.startup_tasks())
|
2020-02-14 02:52:51 +00:00
|
|
|
|
|
|
|
# Show the configuration
|
|
|
|
hacs.configuration.print()
|
|
|
|
|
2020-04-10 01:29:27 +00:00
|
|
|
# Set up sensor
|
|
|
|
await hacs.hass.async_add_executor_job(add_sensor)
|
|
|
|
|
2020-02-14 02:52:51 +00:00
|
|
|
# Mischief managed!
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
async def async_remove_entry(hass, config_entry):
|
|
|
|
"""Handle removal of an entry."""
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs = get_hacs()
|
|
|
|
hacs.logger.info("Disabling HACS")
|
|
|
|
hacs.logger.info("Removing recuring tasks")
|
|
|
|
for task in hacs.recuring_tasks:
|
2020-02-14 02:52:51 +00:00
|
|
|
task()
|
2020-05-29 20:45:24 +00:00
|
|
|
if config_entry.state == "loaded":
|
|
|
|
hacs.logger.info("Removing sensor")
|
|
|
|
try:
|
|
|
|
await hass.config_entries.async_forward_entry_unload(config_entry, "sensor")
|
|
|
|
except ValueError:
|
|
|
|
pass
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.logger.info("Removing sidepanel")
|
2020-02-14 02:52:51 +00:00
|
|
|
try:
|
|
|
|
hass.components.frontend.async_remove_panel("hacs")
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
2020-04-10 01:29:27 +00:00
|
|
|
hacs.system.disabled = True
|
|
|
|
hacs.logger.info("HACS is now disabled")
|
2020-02-14 02:52:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def reload_hacs(hass, config_entry):
|
|
|
|
"""Reload HACS."""
|
|
|
|
await async_remove_entry(hass, config_entry)
|
|
|
|
await async_setup_entry(hass, config_entry)
|