Пример #1
0
async def to_code(config):
    paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID])

    var = cg.new_Pvariable(config[CONF_ID], paren)
    await cg.register_component(var, config)

    cg.add_define("USE_WEBSERVER")

    cg.add(paren.set_port(config[CONF_PORT]))
    cg.add_define("USE_WEBSERVER")
    cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT])
    cg.add_define("USE_WEBSERVER_VERSION", config[CONF_VERSION])
    cg.add(var.set_css_url(config[CONF_CSS_URL]))
    cg.add(var.set_js_url(config[CONF_JS_URL]))
    cg.add(var.set_allow_ota(config[CONF_OTA]))
    if CONF_AUTH in config:
        cg.add(paren.set_auth_username(config[CONF_AUTH][CONF_USERNAME]))
        cg.add(paren.set_auth_password(config[CONF_AUTH][CONF_PASSWORD]))
    if CONF_CSS_INCLUDE in config:
        cg.add_define("USE_WEBSERVER_CSS_INCLUDE")
        path = CORE.relative_config_path(config[CONF_CSS_INCLUDE])
        with open(file=path, encoding="utf-8") as myfile:
            cg.add(var.set_css_include(myfile.read()))
    if CONF_JS_INCLUDE in config:
        cg.add_define("USE_WEBSERVER_JS_INCLUDE")
        path = CORE.relative_config_path(config[CONF_JS_INCLUDE])
        with open(file=path, encoding="utf-8") as myfile:
            cg.add(var.set_js_include(myfile.read()))
    cg.add(var.set_include_internal(config[CONF_INCLUDE_INTERNAL]))
    if CONF_LOCAL in config and config[CONF_LOCAL]:
        cg.add_define("USE_WEBSERVER_LOCAL")
Пример #2
0
def file_(value):
    import json

    value = string(value)
    path = CORE.relative_config_path(value)

    if CORE.vscode and (not CORE.ace or os.path.abspath(path)
                        == os.path.abspath(CORE.config_path)):
        print(json.dumps({
            "type": "check_file_exists",
            "path": path,
        }))
        data = json.loads(input())
        assert data["type"] == "file_exists_response"
        if data["content"]:
            return value
        raise Invalid(
            "Could not find file '{}'. Please make sure it exists (full path: {})."
            "".format(path, os.path.abspath(path)))

    if not os.path.exists(path):
        raise Invalid(
            "Could not find file '{}'. Please make sure it exists (full path: {})."
            "".format(path, os.path.abspath(path)))
    if not os.path.isfile(path):
        raise Invalid("Path '{}' is not a file (full path: {})."
                      "".format(path, os.path.abspath(path)))
    return value
Пример #3
0
def _process_single_config(config: dict):
    conf = config[CONF_SOURCE]
    if conf[CONF_TYPE] == TYPE_GIT:
        with cv.prepend_path([CONF_SOURCE]):
            components_dir = _process_git_config(config[CONF_SOURCE],
                                                 config[CONF_REFRESH])
    elif conf[CONF_TYPE] == TYPE_LOCAL:
        components_dir = Path(CORE.relative_config_path(conf[CONF_PATH]))
    else:
        raise NotImplementedError()

    if config[CONF_COMPONENTS] == "all":
        num_components = len(list(components_dir.glob("*/__init__.py")))
        if num_components > 100:
            # Prevent accidentally including all components from an esphome fork/branch
            # In this case force the user to manually specify which components they want to include
            raise cv.Invalid(
                "This source is an ESPHome fork or branch. Please manually specify the components you want to import using the 'components' key",
                [CONF_COMPONENTS],
            )
        allowed_components = None
    else:
        for i, name in enumerate(config[CONF_COMPONENTS]):
            expected = components_dir / name / "__init__.py"
            if not expected.is_file():
                raise cv.Invalid(
                    f"Could not find __init__.py file for component {name}. Please check the component is defined by this source (search path: {expected})",
                    [CONF_COMPONENTS, i],
                )
        allowed_components = config[CONF_COMPONENTS]

    loader.install_meta_finder(components_dir,
                               allowed_components=allowed_components)
Пример #4
0
def directory(value):
    import json
    value = string(value)
    path = CORE.relative_config_path(value)

    if CORE.vscode and (not CORE.ace or
                        os.path.abspath(path) == os.path.abspath(CORE.config_path)):
        print(json.dumps({
            'type': 'check_directory_exists',
            'path': path,
        }))
        data = json.loads(input())
        assert data['type'] == 'directory_exists_response'
        if data['content']:
            return value
        raise Invalid("Could not find directory '{}'. Please make sure it exists (full path: {})."
                      "".format(path, os.path.abspath(path)))

    if not os.path.exists(path):
        raise Invalid("Could not find directory '{}'. Please make sure it exists (full path: {})."
                      "".format(path, os.path.abspath(path)))
    if not os.path.isdir(path):
        raise Invalid("Path '{}' is not a directory (full path: {})."
                      "".format(path, os.path.abspath(path)))
    return value
Пример #5
0
def to_code(config):
    from PIL import Image

    path = CORE.relative_config_path(config[CONF_FILE])
    try:
        image = Image.open(path)
    except Exception as e:
        raise core.EsphomeError(u"Could not load image file {}: {}".format(
            path, e))

    if CONF_RESIZE in config:
        image.thumbnail(config[CONF_RESIZE])

    image = image.convert('1', dither=Image.NONE)
    width, height = image.size
    if width > 500 or height > 500:
        _LOGGER.warning(
            "The image you requested is very big. Please consider using the resize "
            "parameter")
    width8 = ((width + 7) // 8) * 8
    data = [0 for _ in range(height * width8 // 8)]
    for y in range(height):
        for x in range(width):
            if image.getpixel((x, y)):
                continue
            pos = x + y * width8
            data[pos // 8] |= 0x80 >> (pos % 8)

    rhs = [HexInt(x) for x in data]
    prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
    cg.new_Pvariable(config[CONF_ID], prog_arr, width, height)
Пример #6
0
def file_(value):
    import json
    from esphome.py_compat import safe_input
    value = string(value)
    path = CORE.relative_config_path(value)

    if CORE.vscode and (not CORE.ace or os.path.abspath(path)
                        == os.path.abspath(CORE.config_path)):
        print(json.dumps({
            'type': 'check_file_exists',
            'path': path,
        }))
        data = json.loads(safe_input())
        assert data['type'] == 'file_exists_response'
        if data['content']:
            return value
        raise Invalid(
            u"Could not find file '{}'. Please make sure it exists (full path: {})."
            u"".format(path, os.path.abspath(path)))

    if not os.path.exists(path):
        raise Invalid(
            u"Could not find file '{}'. Please make sure it exists (full path: {})."
            u"".format(path, os.path.abspath(path)))
    if not os.path.isfile(path):
        raise Invalid(u"Path '{}' is not a file (full path: {})."
                      u"".format(path, os.path.abspath(path)))
    return value
Пример #7
0
async def to_code(config):
    from PIL import Image

    path = CORE.relative_config_path(config[CONF_FILE])
    try:
        image = Image.open(path)
    except Exception as e:
        raise core.EsphomeError(f"Could not load image file {path}: {e}")

    width, height = image.size

    if CONF_RESIZE in config:
        image.thumbnail(config[CONF_RESIZE])
        width, height = image.size
    else:
        if width > 500 or height > 500:
            _LOGGER.warning(
                "The image you requested is very big. Please consider using"
                " the resize parameter.")

    dither = Image.NONE if config[
        CONF_DITHER] == "NONE" else Image.FLOYDSTEINBERG
    if config[CONF_TYPE] == "GRAYSCALE":
        image = image.convert("L", dither=dither)
        pixels = list(image.getdata())
        data = [0 for _ in range(height * width)]
        pos = 0
        for pix in pixels:
            data[pos] = pix
            pos += 1

    elif config[CONF_TYPE] == "RGB24":
        image = image.convert("RGB")
        pixels = list(image.getdata())
        data = [0 for _ in range(height * width * 3)]
        pos = 0
        for pix in pixels:
            data[pos] = pix[0]
            pos += 1
            data[pos] = pix[1]
            pos += 1
            data[pos] = pix[2]
            pos += 1

    elif config[CONF_TYPE] == "BINARY":
        image = image.convert("1", dither=dither)
        width8 = ((width + 7) // 8) * 8
        data = [0 for _ in range(height * width8 // 8)]
        for y in range(height):
            for x in range(width):
                if image.getpixel((x, y)):
                    continue
                pos = x + y * width8
                data[pos // 8] |= 0x80 >> (pos % 8)

    rhs = [HexInt(x) for x in data]
    prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
    cg.new_Pvariable(config[CONF_ID], prog_arr, width, height,
                     IMAGE_TYPE[config[CONF_TYPE]])
Пример #8
0
async def to_code(config):
    from PIL import ImageFont

    conf = config[CONF_FILE]
    if conf[CONF_TYPE] == TYPE_LOCAL:
        path = CORE.relative_config_path(conf[CONF_PATH])
    elif conf[CONF_TYPE] == TYPE_GFONTS:
        path = _compute_gfonts_local_path(conf)
    try:
        font = ImageFont.truetype(str(path), config[CONF_SIZE])
    except Exception as e:
        raise core.EsphomeError(f"Could not load truetype file {path}: {e}")

    ascent, descent = font.getmetrics()

    glyph_args = {}
    data = []
    for glyph in config[CONF_GLYPHS]:
        mask = font.getmask(glyph, mode="1")
        _, (offset_x, offset_y) = font.font.getsize(glyph)
        width, height = mask.size
        width8 = ((width + 7) // 8) * 8
        glyph_data = [0] * (height * width8 // 8)
        for y in range(height):
            for x in range(width):
                if not mask.getpixel((x, y)):
                    continue
                pos = x + y * width8
                glyph_data[pos // 8] |= 0x80 >> (pos % 8)
        glyph_args[glyph] = (len(data), offset_x, offset_y, width, height)
        data += glyph_data

    rhs = [HexInt(x) for x in data]
    prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)

    glyph_initializer = []
    for glyph in config[CONF_GLYPHS]:
        glyph_initializer.append(
            cg.StructInitializer(
                GlyphData,
                ("a_char", glyph),
                (
                    "data",
                    cg.RawExpression(
                        f"{str(prog_arr)} + {str(glyph_args[glyph][0])}"),
                ),
                ("offset_x", glyph_args[glyph][1]),
                ("offset_y", glyph_args[glyph][2]),
                ("width", glyph_args[glyph][3]),
                ("height", glyph_args[glyph][4]),
            ))

    glyphs = cg.static_const_array(config[CONF_RAW_GLYPH_ID],
                                   glyph_initializer)

    cg.new_Pvariable(config[CONF_ID], glyphs, len(glyph_initializer), ascent,
                     ascent + descent)
Пример #9
0
def file_(value):
    value = string(value)
    path = CORE.relative_config_path(value)
    if not os.path.exists(path):
        raise Invalid(u"Could not find file '{}'. Please make sure it exists (full path: {})."
                      u"".format(path, os.path.abspath(path)))
    if not os.path.isfile(path):
        raise Invalid(u"Path '{}' is not a file (full path: {})."
                      u"".format(path, os.path.abspath(path)))
    return value
Пример #10
0
def add_includes(includes):
    # Add includes at the very end, so that the included files can access global variables
    for include in includes:
        path = CORE.relative_config_path(include)
        if os.path.isdir(path):
            # Directory, copy tree
            for p in walk_files(path):
                basename = os.path.relpath(p, os.path.dirname(path))
                include_file(p, basename)
        else:
            # Copy file
            basename = os.path.basename(path)
            include_file(path, basename)
Пример #11
0
def to_code(config):
    from PIL import Image

    path = CORE.relative_config_path(config[CONF_FILE])
    try:
        image = Image.open(path)
    except Exception as e:
        raise core.EsphomeError(f"Could not load image file {path}: {e}")

    if CONF_RESIZE in config:
        image.thumbnail(config[CONF_RESIZE])

    if config[CONF_TYPE].startswith('RGB565'):
        width, height = image.size
        image = image.convert('RGB')
        pixels = list(image.getdata())
        data = [0 for _ in range(height * width * 2)]

        pos = 0
        for pix in pixels:
            r = (pix[0] >> 3) & 0x1F
            g = (pix[1] >> 2) & 0x3F
            b = (pix[2] >> 3) & 0x1F
            p = (r << 11) + (g << 5) + b
            data[pos] = (p >> 8) & 0xFF
            pos += 1
            data[pos] = p & 0xFF
            pos += 1
        rhs = [HexInt(x) for x in data]
        prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
        cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, 1)
    else:
        image = image.convert('1', dither=Image.NONE)
        width, height = image.size
        if width > 500 or height > 500:
            _LOGGER.warning(
                "The image you requested is very big. Please consider using the resize "
                "parameter")
        width8 = ((width + 7) // 8) * 8
        data = [0 for _ in range(height * width8 // 8)]
        for y in range(height):
            for x in range(width):
                if image.getpixel((x, y)):
                    continue
                pos = x + y * width8
                data[pos // 8] |= 0x80 >> (pos % 8)

        rhs = [HexInt(x) for x in data]
        prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
        cg.new_Pvariable(config[CONF_ID], prog_arr, width, height)
def preload_core_config(config):
    core_key = 'esphome'
    if 'esphomeyaml' in config:
        _LOGGER.warning("The esphomeyaml section has been renamed to esphome in 1.11.0. "
                        "Please replace 'esphomeyaml:' in your configuration with 'esphome:'.")
        config[CONF_ESPHOME] = config.pop('esphomeyaml')
        core_key = 'esphomeyaml'
    if CONF_ESPHOME not in config:
        raise cv.RequiredFieldInvalid("required key not provided", CONF_ESPHOME)
    with cv.prepend_path(core_key):
        out = PRELOAD_CONFIG_SCHEMA(config[CONF_ESPHOME])
    CORE.name = out[CONF_NAME]
    CORE.esp_platform = out[CONF_PLATFORM]
    with cv.prepend_path(core_key):
        out2 = PRELOAD_CONFIG_SCHEMA2(config[CONF_ESPHOME])
    CORE.board = out2[CONF_BOARD]
    CORE.build_path = CORE.relative_config_path(out2[CONF_BUILD_PATH])
Пример #13
0
def to_code(config):
    from PIL import ImageFont

    path = CORE.relative_config_path(config[CONF_FILE])
    try:
        font = ImageFont.truetype(path, config[CONF_SIZE])
    except Exception as e:
        raise core.EsphomeError(f"Could not load truetype file {path}: {e}")

    ascent, descent = font.getmetrics()

    glyph_args = {}
    data = []
    for glyph in config[CONF_GLYPHS]:
        mask = font.getmask(glyph, mode='1')
        _, (offset_x, offset_y) = font.font.getsize(glyph)
        width, height = mask.size
        width8 = ((width + 7) // 8) * 8
        glyph_data = [0 for _ in range(height * width8 // 8)]  # noqa: F812
        for y in range(height):
            for x in range(width):
                if not mask.getpixel((x, y)):
                    continue
                pos = x + y * width8
                glyph_data[pos // 8] |= 0x80 >> (pos % 8)
        glyph_args[glyph] = (len(data), offset_x, offset_y, width, height)
        data += glyph_data

    rhs = [HexInt(x) for x in data]
    prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)

    glyphs = []
    for glyph in config[CONF_GLYPHS]:
        glyphs.append(Glyph(glyph, prog_arr, *glyph_args[glyph]))

    cg.new_Pvariable(config[CONF_ID], glyphs, ascent, ascent + descent)
Пример #14
0
def storage_path():  # type: () -> str
    return CORE.relative_config_path(".esphome", f"{CORE.config_filename}.json")
Пример #15
0
def to_code(config):
    from PIL import Image

    path = CORE.relative_config_path(config[CONF_FILE])
    try:
        image = Image.open(path)
    except Exception as e:
        raise core.EsphomeError(f"Could not load image file {path}: {e}")

    width, height = image.size
    frames = image.n_frames
    if CONF_RESIZE in config:
        image.thumbnail(config[CONF_RESIZE])
        width, height = image.size
    else:
        if width > 500 or height > 500:
            _LOGGER.warning(
                "The image you requested is very big. Please consider using"
                " the resize parameter.")

    if config[CONF_TYPE] == 'GRAYSCALE':
        data = [0 for _ in range(height * width * frames)]
        pos = 0
        for frameIndex in range(frames):
            image.seek(frameIndex)
            frame = image.convert('L', dither=Image.NONE)
            pixels = list(frame.getdata())
            for pix in pixels:
                data[pos] = pix
                pos += 1

    elif config[CONF_TYPE] == 'RGB24':
        data = [0 for _ in range(height * width * 3 * frames)]
        pos = 0
        for frameIndex in range(frames):
            image.seek(frameIndex)
            frame = image.convert('RGB')
            pixels = list(frame.getdata())
            for pix in pixels:
                data[pos] = pix[0]
                pos += 1
                data[pos] = pix[1]
                pos += 1
                data[pos] = pix[2]
                pos += 1

    elif config[CONF_TYPE] == 'BINARY':
        width8 = ((width + 7) // 8) * 8
        data = [0 for _ in range((height * width8 // 8) * frames)]
        for frameIndex in range(frames):
            image.seek(frameIndex)
            frame = image.convert('1', dither=Image.NONE)
            for y in range(height):
                for x in range(width):
                    if frame.getpixel((x, y)):
                        continue
                    pos = x + y * width8 + (height * width8 * frameIndex)
                    data[pos // 8] |= 0x80 >> (pos % 8)

    rhs = [HexInt(x) for x in data]
    prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
    cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, frames,
                     espImage.IMAGE_TYPE[config[CONF_TYPE]])
Пример #16
0
def storage_path():  # type: () -> str
    return CORE.relative_config_path('.esphome', '{}.json'.format(CORE.config_filename))
Пример #17
0
async def to_code(config):
    from PIL import Image

    path = CORE.relative_config_path(config[CONF_FILE])
    try:
        image = Image.open(path)
    except Exception as e:
        raise core.EsphomeError(f"Could not load image file {path}: {e}")

    width, height = image.size
    frames = image.n_frames
    if CONF_RESIZE in config:
        new_width_max, new_height_max = config[CONF_RESIZE]
        ratio = min(new_width_max / width, new_height_max / height)
        width, height = int(width * ratio), int(height * ratio)
    else:
        if width > 500 or height > 500:
            _LOGGER.warning(
                "The image you requested is very big. Please consider using"
                " the resize parameter.")

    if config[CONF_TYPE] == "GRAYSCALE":
        data = [0 for _ in range(height * width * frames)]
        pos = 0
        for frameIndex in range(frames):
            image.seek(frameIndex)
            frame = image.convert("L", dither=Image.NONE)
            if CONF_RESIZE in config:
                frame = frame.resize([width, height])
            pixels = list(frame.getdata())
            if len(pixels) != height * width:
                raise core.EsphomeError(
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
                )
            for pix in pixels:
                data[pos] = pix
                pos += 1

    elif config[CONF_TYPE] == "RGB24":
        data = [0 for _ in range(height * width * 3 * frames)]
        pos = 0
        for frameIndex in range(frames):
            image.seek(frameIndex)
            frame = image.convert("RGB")
            if CONF_RESIZE in config:
                frame = frame.resize([width, height])
            pixels = list(frame.getdata())
            if len(pixels) != height * width:
                raise core.EsphomeError(
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
                )
            for pix in pixels:
                data[pos] = pix[0]
                pos += 1
                data[pos] = pix[1]
                pos += 1
                data[pos] = pix[2]
                pos += 1

    elif config[CONF_TYPE] == "RGB565":
        data = [0 for _ in range(height * width * 2 * frames)]
        pos = 0
        for frameIndex in range(frames):
            image.seek(frameIndex)
            frame = image.convert("RGB")
            if CONF_RESIZE in config:
                frame = frame.resize([width, height])
            pixels = list(frame.getdata())
            if len(pixels) != height * width:
                raise core.EsphomeError(
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
                )
            for pix in pixels:
                R = pix[0] >> 3
                G = pix[1] >> 2
                B = pix[2] >> 3
                rgb = (R << 11) | (G << 5) | B
                data[pos] = rgb >> 8
                pos += 1
                data[pos] = rgb & 255
                pos += 1

    elif config[CONF_TYPE] == "BINARY":
        width8 = ((width + 7) // 8) * 8
        data = [0 for _ in range((height * width8 // 8) * frames)]
        for frameIndex in range(frames):
            image.seek(frameIndex)
            frame = image.convert("1", dither=Image.NONE)
            if CONF_RESIZE in config:
                frame = frame.resize([width, height])
            for y in range(height):
                for x in range(width):
                    if frame.getpixel((x, y)):
                        continue
                    pos = x + y * width8 + (height * width8 * frameIndex)
                    data[pos // 8] |= 0x80 >> (pos % 8)

    rhs = [HexInt(x) for x in data]
    prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
    cg.new_Pvariable(
        config[CONF_ID],
        prog_arr,
        width,
        height,
        frames,
        espImage.IMAGE_TYPE[config[CONF_TYPE]],
    )
Пример #18
0
def write_gitignore():
    path = CORE.relative_config_path(".gitignore")
    if not os.path.isfile(path):
        with open(path, "w") as f:
            f.write(GITIGNORE_CONTENT)
Пример #19
0
def read_relative_config_path(value):
    # pylint: disable=unspecified-encoding
    return Path(CORE.relative_config_path(value)).read_text()
Пример #20
0
def write_gitignore():
    path = CORE.relative_config_path(".gitignore")
    if not os.path.isfile(path):
        with open(file=path, mode="w", encoding="utf-8") as f:
            f.write(GITIGNORE_CONTENT)
Пример #21
0
def preload_core_config(config, result):
    with cv.prepend_path(CONF_ESPHOME):
        conf = PRELOAD_CONFIG_SCHEMA(config[CONF_ESPHOME])

    CORE.name = conf[CONF_NAME]
    CORE.data[KEY_CORE] = {}

    if CONF_BUILD_PATH not in conf:
        conf[CONF_BUILD_PATH] = f".esphome/build/{CORE.name}"
    CORE.build_path = CORE.relative_config_path(conf[CONF_BUILD_PATH])

    has_oldstyle = CONF_PLATFORM in conf
    newstyle_found = [key for key in TARGET_PLATFORMS if key in config]
    oldstyle_opts = [
        CONF_ESP8266_RESTORE_FROM_FLASH,
        CONF_BOARD_FLASH_MODE,
        CONF_ARDUINO_VERSION,
        CONF_BOARD,
    ]

    if not has_oldstyle and not newstyle_found:
        raise cv.Invalid("Platform missing for core options!", [CONF_ESPHOME])
    if has_oldstyle and newstyle_found:
        raise cv.Invalid(
            f"Please remove the `platform` key from the [esphome] block. You're already using the new style with the [{conf[CONF_PLATFORM]}] block",
            [CONF_ESPHOME, CONF_PLATFORM],
        )
    if len(newstyle_found) > 1:
        raise cv.Invalid(
            f"Found multiple target platform blocks: {', '.join(newstyle_found)}. Only one is allowed.",
            [newstyle_found[0]],
        )
    if newstyle_found:
        # Convert to newstyle
        for key in oldstyle_opts:
            if key in conf:
                raise cv.Invalid(
                    f"Please move {key} to the [{newstyle_found[0]}] block.",
                    [CONF_ESPHOME, key],
                )

    if has_oldstyle:
        plat = conf.pop(CONF_PLATFORM)
        plat_conf = {}
        if CONF_ESP8266_RESTORE_FROM_FLASH in conf:
            plat_conf["restore_from_flash"] = conf.pop(
                CONF_ESP8266_RESTORE_FROM_FLASH)
        if CONF_BOARD_FLASH_MODE in conf:
            plat_conf[CONF_BOARD_FLASH_MODE] = conf.pop(CONF_BOARD_FLASH_MODE)
        if CONF_ARDUINO_VERSION in conf:
            plat_conf[CONF_FRAMEWORK] = {}
            if plat != PLATFORM_ESP8266:
                plat_conf[CONF_FRAMEWORK][CONF_TYPE] = "arduino"

            try:
                if conf[CONF_ARDUINO_VERSION] not in ("recommended", "latest",
                                                      "dev"):
                    cv.Version.parse(conf[CONF_ARDUINO_VERSION])
                plat_conf[CONF_FRAMEWORK][CONF_VERSION] = conf.pop(
                    CONF_ARDUINO_VERSION)
            except ValueError:
                plat_conf[CONF_FRAMEWORK][CONF_SOURCE] = conf.pop(
                    CONF_ARDUINO_VERSION)
        if CONF_BOARD in conf:
            plat_conf[CONF_BOARD] = conf.pop(CONF_BOARD)
        # Insert generated target platform config to main config
        config[plat] = plat_conf
    config[CONF_ESPHOME] = conf
Пример #22
0
def read_relative_config_path(value):
    return Path(CORE.relative_config_path(value)).read_text()
Пример #23
0
def _process_single_config(config: dict):
    conf = config[CONF_SOURCE]
    if conf[CONF_TYPE] == TYPE_GIT:
        key = f"{conf[CONF_URL]}@{conf.get(CONF_REF)}"
        repo_dir = _compute_destination_path(key)
        if not repo_dir.is_dir():
            cmd = ["git", "clone", "--depth=1"]
            if CONF_REF in conf:
                cmd += ["--branch", conf[CONF_REF]]
            cmd += [conf[CONF_URL], str(repo_dir)]
            ret = subprocess.run(cmd, capture_output=True, check=False)
            _handle_git_response(ret)

        else:
            # Check refresh needed
            file_timestamp = Path(repo_dir / ".git" / "FETCH_HEAD")
            # On first clone, FETCH_HEAD does not exists
            if not file_timestamp.exists():
                file_timestamp = Path(repo_dir / ".git" / "HEAD")
            age = datetime.datetime.now() - datetime.datetime.fromtimestamp(
                file_timestamp.stat().st_mtime
            )
            if age.seconds > config[CONF_REFRESH].total_seconds:
                _LOGGER.info("Executing git pull %s", key)
                cmd = ["git", "pull"]
                ret = subprocess.run(
                    cmd, cwd=repo_dir, capture_output=True, check=False
                )
                _handle_git_response(ret)

        if (repo_dir / "esphome" / "components").is_dir():
            components_dir = repo_dir / "esphome" / "components"
        elif (repo_dir / "components").is_dir():
            components_dir = repo_dir / "components"
        else:
            raise cv.Invalid(
                "Could not find components folder for source. Please check the source contains a 'components' or 'esphome/components' folder",
                [CONF_SOURCE],
            )

    elif conf[CONF_TYPE] == TYPE_LOCAL:
        components_dir = Path(CORE.relative_config_path(conf[CONF_PATH]))
    else:
        raise NotImplementedError()

    if config[CONF_COMPONENTS] == "all":
        num_components = len(list(components_dir.glob("*/__init__.py")))
        if num_components > 100:
            # Prevent accidentally including all components from an esphome fork/branch
            # In this case force the user to manually specify which components they want to include
            raise cv.Invalid(
                "This source is an ESPHome fork or branch. Please manually specify the components you want to import using the 'components' key",
                [CONF_COMPONENTS],
            )
        allowed_components = None
    else:
        for i, name in enumerate(config[CONF_COMPONENTS]):
            expected = components_dir / name / "__init__.py"
            if not expected.is_file():
                raise cv.Invalid(
                    f"Could not find __init__.py file for component {name}. Please check the component is defined by this source (search path: {expected})",
                    [CONF_COMPONENTS, i],
                )
        allowed_components = config[CONF_COMPONENTS]

    loader.install_meta_finder(components_dir, allowed_components=allowed_components)