Пример #1
0
    def test_dst_does_not_exist(self, tmp_path):
        text = "A files are unique.\n"
        dst = tmp_path / "file-a.txt"

        helpers.write_file_if_changed(dst, text)

        assert dst.read_text() == text
Пример #2
0
def migrate_src_version_0_to_1():
    main_cpp = CORE.relative_build_path('src', 'main.cpp')
    if not os.path.isfile(main_cpp):
        return

    content = read_file(main_cpp)

    if CPP_INCLUDE_BEGIN in content:
        return

    content, count = replace_file_content(content, r'\s*delay\((?:16|20)\);',
                                          '')
    if count != 0:
        _LOGGER.info("Migration: Removed %s occurrence of 'delay(16);' in %s",
                     count, main_cpp)

    content, count = replace_file_content(content,
                                          r'using namespace esphomelib;', '')
    if count != 0:
        _LOGGER.info(
            "Migration: Removed %s occurrence of 'using namespace esphomelib;' "
            "in %s", count, main_cpp)

    if CPP_INCLUDE_BEGIN not in content:
        content, count = replace_file_content(
            content, r'#include "esphomelib/application.h"',
            CPP_INCLUDE_BEGIN + u'\n' + CPP_INCLUDE_END)
        if count == 0:
            _LOGGER.error(
                "Migration failed. ESPHome 1.10.0 needs to have a new auto-generated "
                "include section in the %s file. Please remove %s and let it be "
                "auto-generated again.", main_cpp, main_cpp)
        _LOGGER.info("Migration: Added include section to %s", main_cpp)

    write_file_if_changed(content, main_cpp)
Пример #3
0
def write_file(name, obj):
    full_path = os.path.join(args.output_path, name + ".json")
    if JSON_DUMP_PRETTY:
        json_str = json.dumps(obj, indent=2)
    else:
        json_str = json.dumps(obj, separators=(",", ":"))
    write_file_if_changed(full_path, json_str)
    print(f"Wrote {full_path}")
Пример #4
0
    def test_src_and_dst_do_not_match(self, tmp_path):
        text = "A files are unique.\n"
        initial = "B files are unique.\n"
        dst = tmp_path / "file-a.txt"
        dst.write_text(initial)

        helpers.write_file_if_changed(dst, text)

        assert dst.read_text() == text
Пример #5
0
def get_ini_content():
    overrides = CORE.config[CONF_ESPHOME].get(CONF_PLATFORMIO_OPTIONS, {})

    lib_deps = gather_lib_deps()
    build_flags = gather_build_flags(overrides.pop("build_flags", []))

    data = {
        "platform": CORE.arduino_version,
        "board": CORE.board,
        "framework": "arduino",
        "lib_deps": lib_deps + ["${common.lib_deps}"],
        "build_flags": build_flags + ["${common.build_flags}"],
        "upload_speed": UPLOAD_SPEED_OVERRIDE.get(CORE.board, 115200),
    }

    if CORE.is_esp32:
        data["board_build.partitions"] = "partitions.csv"
        partitions_csv = CORE.relative_build_path("partitions.csv")
        write_file_if_changed(partitions_csv, ESP32_LARGE_PARTITIONS_CSV)

    # pylint: disable=unsubscriptable-object
    if CONF_BOARD_FLASH_MODE in CORE.config[CONF_ESPHOME]:
        flash_mode = CORE.config[CONF_ESPHOME][CONF_BOARD_FLASH_MODE]
        data["board_build.flash_mode"] = flash_mode

    # Build flags
    if CORE.is_esp8266 and CORE.board in ESP8266_FLASH_SIZES:
        flash_size = ESP8266_FLASH_SIZES[CORE.board]
        ld_scripts = ESP8266_LD_SCRIPTS[flash_size]

        versions_with_old_ldscripts = [
            ARDUINO_VERSION_ESP8266["2.4.0"],
            ARDUINO_VERSION_ESP8266["2.4.1"],
            ARDUINO_VERSION_ESP8266["2.4.2"],
        ]
        if CORE.arduino_version == ARDUINO_VERSION_ESP8266["2.3.0"]:
            # No ld script support
            ld_script = None
        if CORE.arduino_version in versions_with_old_ldscripts:
            # Old ld script path
            ld_script = ld_scripts[0]
        else:
            ld_script = ld_scripts[1]

        if ld_script is not None:
            data["board_build.ldscript"] = ld_script

    # Ignore libraries that are not explicitly used, but may
    # be added by LDF
    # data['lib_ldf_mode'] = 'chain'
    data.update(overrides)

    content = f"[env:{CORE.name}]\n"
    content += format_ini(data)

    return content
Пример #6
0
def get_ini_content():
    lib_deps = gather_lib_deps()
    build_flags = gather_build_flags()

    data = {
        'platform': CORE.arduino_version,
        'board': CORE.board,
        'framework': 'arduino',
        'lib_deps': lib_deps + ['${common.lib_deps}'],
        'build_flags': build_flags + ['${common.build_flags}'],
        'upload_speed': UPLOAD_SPEED_OVERRIDE.get(CORE.board, 115200),
    }

    if CORE.is_esp32:
        data['board_build.partitions'] = "partitions.csv"
        partitions_csv = CORE.relative_build_path('partitions.csv')
        write_file_if_changed(partitions_csv, ESP32_LARGE_PARTITIONS_CSV)

    # pylint: disable=unsubscriptable-object
    if CONF_BOARD_FLASH_MODE in CORE.config[CONF_ESPHOME]:
        flash_mode = CORE.config[CONF_ESPHOME][CONF_BOARD_FLASH_MODE]
        data['board_build.flash_mode'] = flash_mode

    # Build flags
    if CORE.is_esp8266 and CORE.board in ESP8266_FLASH_SIZES:
        flash_size = ESP8266_FLASH_SIZES[CORE.board]
        ld_scripts = ESP8266_LD_SCRIPTS[flash_size]

        versions_with_old_ldscripts = [
            ARDUINO_VERSION_ESP8266['2.4.0'],
            ARDUINO_VERSION_ESP8266['2.4.1'],
            ARDUINO_VERSION_ESP8266['2.4.2'],
        ]
        if CORE.arduino_version == ARDUINO_VERSION_ESP8266['2.3.0']:
            # No ld script support
            ld_script = None
        if CORE.arduino_version in versions_with_old_ldscripts:
            # Old ld script path
            ld_script = ld_scripts[0]
        else:
            ld_script = ld_scripts[1]

        if ld_script is not None:
            data['board_build.ldscript'] = ld_script

    # Ignore libraries that are not explicitly used, but may
    # be added by LDF
    # data['lib_ldf_mode'] = 'chain'
    data.update(CORE.config[CONF_ESPHOME].get(CONF_PLATFORMIO_OPTIONS, {}))

    content = f'[env:{CORE.name}]\n'
    content += format_ini(data)

    return content
Пример #7
0
def write_platformio_ini(content):
    update_storage_json()
    path = CORE.relative_build_path('platformio.ini')

    if os.path.isfile(path):
        text = read_file(path)
        content_format = find_begin_end(text, INI_AUTO_GENERATE_BEGIN, INI_AUTO_GENERATE_END)
    else:
        content_format = INI_BASE_FORMAT
    full_file = content_format[0] + INI_AUTO_GENERATE_BEGIN + '\n' + content
    full_file += INI_AUTO_GENERATE_END + content_format[1]
    write_file_if_changed(full_file, path)
Пример #8
0
def copy_files():
    if CORE.using_arduino:
        write_file_if_changed(
            CORE.relative_build_path("partitions.csv"),
            ARDUINO_PARTITIONS_CSV,
        )
    if CORE.using_esp_idf:
        _write_sdkconfig()
        write_file_if_changed(
            CORE.relative_build_path("partitions.csv"),
            IDF_PARTITIONS_CSV,
        )
Пример #9
0
def copy_src_tree():
    import filecmp
    import shutil

    source_files = {}
    for _, component, _ in iter_components(CORE.config):
        source_files.update(component.source_files)

    # Convert to list and sort
    source_files_l = [it for it in source_files.items()]
    source_files_l.sort()

    # Build #include list for esphome.h
    include_l = []
    for target, path in source_files_l:
        if os.path.splitext(path)[1] in HEADER_FILE_EXTENSIONS:
            include_l.append(u'#include "{}"'.format(target))
    include_l.append(u'')
    include_s = u'\n'.join(include_l)

    source_files_copy = source_files.copy()
    source_files_copy.pop(DEFINES_H_TARGET)

    for path in walk_files(CORE.relative_src_path('esphome')):
        if os.path.splitext(path)[1] not in SOURCE_FILE_EXTENSIONS:
            # Not a source file, ignore
            continue
        # Transform path to target path name
        target = os.path.relpath(path, CORE.relative_src_path()).replace(
            os.path.sep, '/')
        if target == DEFINES_H_TARGET:
            # Ignore defines.h, will be dealt with later
            continue
        if target not in source_files_copy:
            # Source file removed, delete target
            os.remove(path)
        else:
            src_path = source_files_copy.pop(target)
            if not filecmp.cmp(path, src_path):
                # Files are not same, copy
                shutil.copy(src_path, path)

    # Now copy new files
    for target, src_path in source_files_copy.items():
        dst_path = CORE.relative_src_path(*target.split('/'))
        mkdir_p(os.path.dirname(dst_path))
        shutil.copy(src_path, dst_path)

    # Finally copy defines
    write_file_if_changed(
        generate_defines_h(),
        CORE.relative_src_path('esphome', 'core', 'defines.h'))
    write_file_if_changed(ESPHOME_README_TXT,
                          CORE.relative_src_path('esphome', 'README.txt'))
    write_file_if_changed(ESPHOME_H_FORMAT.format(include_s),
                          CORE.relative_src_path('esphome.h'))
    write_file_if_changed(
        VERSION_H_FORMAT.format(__version__),
        CORE.relative_src_path('esphome'
                               'core', 'version.h'))
Пример #10
0
def _write_sdkconfig():
    # sdkconfig.{name} stores the real sdkconfig (modified by esp-idf with default)
    # sdkconfig.{name}.esphomeinternal stores what esphome last wrote
    # we use the internal one to detect if there were any changes, and if so write them to the
    # real sdkconfig
    sdk_path = Path(CORE.relative_build_path(f"sdkconfig.{CORE.name}"))
    internal_path = Path(
        CORE.relative_build_path(f"sdkconfig.{CORE.name}.esphomeinternal"))

    want_opts = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
    contents = ("\n".join(f"{name}={_format_sdkconfig_val(value)}"
                          for name, value in sorted(want_opts.items())) + "\n")
    if write_file_if_changed(internal_path, contents):
        # internal changed, update real one
        write_file_if_changed(sdk_path, contents)
Пример #11
0
def copy_src_tree():
    source_files: Dict[Path, loader.SourceFile] = CORE.extra_source_files
    for _, component, _ in iter_components(CORE.config):
        source_files.update(component.source_files)

    # Convert to list and sort
    source_files_l = list(source_files.items())
    source_files_l.sort()

    # Build #include list for esphome.h
    include_l = []
    for target, _ in source_files_l:
        if target.suffix in HEADER_FILE_EXTENSIONS:
            include_l.append(f'#include "{target}"')
    include_l.append("")
    include_s = "\n".join(include_l)

    source_files_copy = source_files.copy()
    ignore_targets = [Path(x) for x in (DEFINES_H_TARGET, VERSION_H_TARGET)]
    for t in ignore_targets:
        source_files_copy.pop(t)

    for fname in walk_files(CORE.relative_src_path("esphome")):
        p = Path(fname)
        if p.suffix not in SOURCE_FILE_EXTENSIONS:
            # Not a source file, ignore
            continue
        # Transform path to target path name
        target = p.relative_to(CORE.relative_src_path())
        if target in ignore_targets:
            # Ignore defines.h, will be dealt with later
            continue
        if target not in source_files_copy:
            # Source file removed, delete target
            p.unlink()
        else:
            src_file = source_files_copy.pop(target)
            with src_file.path() as src_path:
                copy_file_if_changed(src_path, p)

    # Now copy new files
    for target, src_file in source_files_copy.items():
        dst_path = CORE.relative_src_path(*target.parts)
        with src_file.path() as src_path:
            copy_file_if_changed(src_path, dst_path)

    # Finally copy defines
    write_file_if_changed(
        CORE.relative_src_path("esphome", "core", "defines.h"),
        generate_defines_h())
    write_file_if_changed(CORE.relative_src_path("esphome", "README.txt"),
                          ESPHOME_README_TXT)
    write_file_if_changed(CORE.relative_src_path("esphome.h"),
                          ESPHOME_H_FORMAT.format(include_s))
    write_file_if_changed(
        CORE.relative_src_path("esphome", "core", "version.h"),
        VERSION_H_FORMAT.format(__version__),
    )
Пример #12
0
def copy_src_tree():
    source_files = {}
    for _, component, _ in iter_components(CORE.config):
        source_files.update(component.source_files)

    # Convert to list and sort
    source_files_l = list(source_files.items())
    source_files_l.sort()

    # Build #include list for esphome.h
    include_l = []
    for target, path in source_files_l:
        if os.path.splitext(path)[1] in HEADER_FILE_EXTENSIONS:
            include_l.append(f'#include "{target}"')
    include_l.append("")
    include_s = "\n".join(include_l)

    source_files_copy = source_files.copy()
    source_files_copy.pop(DEFINES_H_TARGET)

    for path in walk_files(CORE.relative_src_path("esphome")):
        if os.path.splitext(path)[1] not in SOURCE_FILE_EXTENSIONS:
            # Not a source file, ignore
            continue
        # Transform path to target path name
        target = os.path.relpath(path, CORE.relative_src_path()).replace(
            os.path.sep, "/"
        )
        if target in (DEFINES_H_TARGET, VERSION_H_TARGET):
            # Ignore defines.h, will be dealt with later
            continue
        if target not in source_files_copy:
            # Source file removed, delete target
            os.remove(path)
        else:
            src_path = source_files_copy.pop(target)
            copy_file_if_changed(src_path, path)

    # Now copy new files
    for target, src_path in source_files_copy.items():
        dst_path = CORE.relative_src_path(*target.split("/"))
        copy_file_if_changed(src_path, dst_path)

    # Finally copy defines
    write_file_if_changed(
        CORE.relative_src_path("esphome", "core", "defines.h"), generate_defines_h()
    )
    write_file_if_changed(
        CORE.relative_src_path("esphome", "README.txt"), ESPHOME_README_TXT
    )
    write_file_if_changed(
        CORE.relative_src_path("esphome.h"), ESPHOME_H_FORMAT.format(include_s)
    )
    write_file_if_changed(
        CORE.relative_src_path("esphome", "core", "version.h"),
        VERSION_H_FORMAT.format(__version__),
    )
Пример #13
0
def write_cpp(code_s):
    path = CORE.relative_src_path('main.cpp')
    if os.path.isfile(path):
        text = read_file(path)
        code_format = find_begin_end(text, CPP_AUTO_GENERATE_BEGIN, CPP_AUTO_GENERATE_END)
        code_format_ = find_begin_end(code_format[0], CPP_INCLUDE_BEGIN, CPP_INCLUDE_END)
        code_format = (code_format_[0], code_format_[1], code_format[1])
    else:
        code_format = CPP_BASE_FORMAT

    copy_src_tree()
    global_s = u'#include "esphome.h"\n'
    global_s += CORE.cpp_global_section

    full_file = code_format[0] + CPP_INCLUDE_BEGIN + u'\n' + global_s + CPP_INCLUDE_END
    full_file += code_format[1] + CPP_AUTO_GENERATE_BEGIN + u'\n' + code_s + CPP_AUTO_GENERATE_END
    full_file += code_format[2]
    write_file_if_changed(full_file, path)
Пример #14
0
def copy_files():
    if CORE.using_arduino:
        write_file_if_changed(
            CORE.relative_build_path("partitions.csv"),
            ARDUINO_PARTITIONS_CSV,
        )
    if CORE.using_esp_idf:
        _write_sdkconfig()
        write_file_if_changed(
            CORE.relative_build_path("partitions.csv"),
            IDF_PARTITIONS_CSV,
        )

    dir = os.path.dirname(__file__)
    post_build_file = os.path.join(dir, "post_build.py.script")
    copy_file_if_changed(
        post_build_file,
        CORE.relative_build_path("post_build.py"),
    )
Пример #15
0
def copy_files():
    if CORE.using_arduino:
        write_file_if_changed(
            CORE.relative_build_path("partitions.csv"),
            ARDUINO_PARTITIONS_CSV,
        )
    if CORE.using_esp_idf:
        _write_sdkconfig()
        write_file_if_changed(
            CORE.relative_build_path("partitions.csv"),
            IDF_PARTITIONS_CSV,
        )
        # IDF build scripts look for version string to put in the build.
        # However, if the build path does not have an initialized git repo,
        # and no version.txt file exists, the CMake script fails for some setups.
        # Fix by manually pasting a version.txt file, containing the ESPHome version
        write_file_if_changed(
            CORE.relative_build_path("version.txt"),
            __version__,
        )

    dir = os.path.dirname(__file__)
    post_build_file = os.path.join(dir, "post_build.py.script")
    copy_file_if_changed(
        post_build_file,
        CORE.relative_build_path("post_build.py"),
    )
Пример #16
0
def dump_schema():
    import esphome.config_validation as cv

    from esphome import automation
    from esphome.automation import validate_potentially_and_condition
    from esphome import pins
    from esphome.core import CORE
    from esphome.helpers import write_file_if_changed
    from esphome.components import remote_base

    # The root directory of the repo
    root = Path(__file__).parent.parent

    # Fake some directory so that get_component works
    CORE.config_path = str(root)

    file_path = args.output

    schema_registry[cv.boolean] = {"type": "boolean"}

    for v in [
        cv.int_,
        cv.int_range,
        cv.positive_int,
        cv.float_,
        cv.positive_float,
        cv.positive_float,
        cv.positive_not_null_int,
        cv.negative_one_to_one_float,
        cv.port,
    ]:
        schema_registry[v] = {"type": "number"}

    for v in [
        cv.string,
        cv.string_strict,
        cv.valid_name,
        cv.hex_int,
        cv.hex_int_range,
        pins.output_pin,
        pins.input_pin,
        pins.input_pullup_pin,
        cv.float_with_unit,
        cv.subscribe_topic,
        cv.publish_topic,
        cv.mqtt_payload,
        cv.ssid,
        cv.percentage_int,
        cv.percentage,
        cv.possibly_negative_percentage,
        cv.positive_time_period,
        cv.positive_time_period_microseconds,
        cv.positive_time_period_milliseconds,
        cv.positive_time_period_minutes,
        cv.positive_time_period_seconds,
    ]:
        schema_registry[v] = {"type": "string"}

    schema_registry[validate_potentially_and_condition] = get_ref("condition_list")

    for v in [pins.gpio_input_pin_schema, pins.gpio_input_pullup_pin_schema]:
        schema_registry[v] = get_ref("PIN.GPIO_FULL_INPUT_PIN_SCHEMA")
    for v in [pins.internal_gpio_input_pin_schema, pins.input_pin]:
        schema_registry[v] = get_ref("PIN.INPUT_INTERNAL")

    for v in [pins.gpio_output_pin_schema, pins.internal_gpio_output_pin_schema]:
        schema_registry[v] = get_ref("PIN.GPIO_FULL_OUTPUT_PIN_SCHEMA")
    for v in [pins.internal_gpio_output_pin_schema, pins.output_pin]:
        schema_registry[v] = get_ref("PIN.OUTPUT_INTERNAL")

    add_module_schemas("CONFIG", cv)
    get_jschema("POLLING_COMPONENT", cv.polling_component_schema("60s"))

    add_pin_schema()

    add_module_schemas("REMOTE_BASE", remote_base)
    add_module_schemas("AUTOMATION", automation)

    load_components()
    add_registries()

    definitions["condition_list"] = {
        JSC_ONEOF: [
            {"type": "array", "items": get_ref(JSC_CONDITION)},
            get_ref(JSC_CONDITION),
        ]
    }

    output = {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "type": "object",
        "definitions": definitions,
        JSC_PROPERTIES: base_props,
    }

    add_core()
    add_buses()
    add_components()

    add_registries()  # need second pass, e.g. climate.pid.autotune
    add_pin_registry()
    solve_pending_refs()

    write_file_if_changed(file_path, json.dumps(output))
    print(f"Wrote {file_path}")
Пример #17
0
        if not platform_path.is_file() or platform_path.name == '__init__.py':
            continue
        codeowners[f'esphome/components/{name}/*'].extend(platform.codeowners)

for path, owners in sorted(codeowners.items()):
    owners = sorted(set(owners))
    if not owners:
        continue
    for owner in owners:
        if not owner.startswith('@'):
            print(
                f"Codeowner {owner} for integration {path} must start with an '@' symbol!"
            )
            sys.exit(1)
    parts.append(f"{path} {' '.join(owners)}")

# End newline
parts.append('')
content = '\n'.join(parts)
codeowners_file = root / 'CODEOWNERS'

if args.check:
    if codeowners_file.read_text() != content:
        print("CODEOWNERS file is not up to date.")
        print("Please run `script/build_codeowners.py`")
        sys.exit(1)
    print("CODEOWNERS file is up to date")
else:
    write_file_if_changed(codeowners_file, content)
    print("Wrote CODEOWNERS")
Пример #18
0
 def save(self, path):
     write_file_if_changed(path, self.to_json())
Пример #19
0
 def save(self, path):  # type: (str) -> None
     write_file_if_changed(path, self.to_json())