Add custom component mechanism

This commit is contained in:
Otto Winter 2019-05-13 12:03:52 +02:00
parent b7afb8c887
commit db0dd6af09
No known key found for this signature in database
GPG key ID: DB66C0BE6013F97E

View file

@ -7,6 +7,7 @@ import re
import os.path import os.path
# pylint: disable=unused-import, wrong-import-order # pylint: disable=unused-import, wrong-import-order
import sys
from contextlib import contextmanager from contextlib import contextmanager
import voluptuous as vol import voluptuous as vol
@ -17,7 +18,7 @@ from esphome.components.substitutions import CONF_SUBSTITUTIONS
from esphome.const import CONF_ESPHOME, CONF_PLATFORM, ESP_PLATFORMS from esphome.const import CONF_ESPHOME, CONF_PLATFORM, ESP_PLATFORMS
from esphome.core import CORE, EsphomeError # noqa from esphome.core import CORE, EsphomeError # noqa
from esphome.helpers import color, indent from esphome.helpers import color, indent
from esphome.py_compat import text_type from esphome.py_compat import text_type, IS_PY2
from esphome.util import safe_print, OrderedDict from esphome.util import safe_print, OrderedDict
from typing import List, Optional, Tuple, Union # noqa from typing import List, Optional, Tuple, Union # noqa
@ -106,15 +107,53 @@ class ComponentManifest(object):
CORE_COMPONENTS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'components')) CORE_COMPONENTS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'components'))
_UNDEF = object()
CUSTOM_COMPONENTS_PATH = _UNDEF
def _mount_config_dir():
global CUSTOM_COMPONENTS_PATH
if CUSTOM_COMPONENTS_PATH is not _UNDEF:
return
custom_path = os.path.abspath(os.path.join(CORE.config_dir, 'custom_components'))
if not os.path.isdir(custom_path):
CUSTOM_COMPONENTS_PATH = None
return
init_path = os.path.join(custom_path, '__init__.py')
if IS_PY2 and not os.path.isfile(init_path):
_LOGGER.warning("Found 'custom_components' folder, but file __init__.py was not found. "
"ESPHome will automatically create it now....")
with open(init_path, 'w') as f:
f.write('\n')
if CORE.config_dir not in sys.path:
sys.path.insert(0, CORE.config_dir)
CUSTOM_COMPONENTS_PATH = custom_path
def _lookup_module(domain, is_platform): def _lookup_module(domain, is_platform):
if domain in _COMPONENT_CACHE: if domain in _COMPONENT_CACHE:
return _COMPONENT_CACHE[domain] return _COMPONENT_CACHE[domain]
path = 'esphome.components.{}'.format(domain) _mount_config_dir()
# First look for custom_components
try: try:
module = importlib.import_module(path) module = importlib.import_module('custom_components.{}'.format(domain))
except ImportError as e:
# ImportError when no such module
if 'No module named' not in str(e):
_LOGGER.warn("Unable to import custom component %s:", domain, exc_info=True)
except Exception: # pylint: disable=broad-except
# Other error means component has an issue
_LOGGER.error("Unable to load custom component %s:", domain, exc_info=True)
return None
else:
# Found in custom components
manif = ComponentManifest(module, CUSTOM_COMPONENTS_PATH, is_platform=is_platform)
_COMPONENT_CACHE[domain] = manif
return manif
try:
module = importlib.import_module('esphome.components.{}'.format(domain))
except ImportError as e: except ImportError as e:
if 'No module named' in str(e): if 'No module named' in str(e):
_LOGGER.error("Unable to import component %s:", domain) _LOGGER.error("Unable to import component %s:", domain)