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"), )
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, )
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)
def write_cpp(code_s): path = CORE.relative_build_path('src', 'main.cpp') if os.path.isfile(path): try: with codecs.open(path, 'r', encoding='utf-8') as f_handle: text = f_handle.read() except OSError: raise EsphomeError(u"Could not read C++ file at {}".format(path)) prev_file = text 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: prev_file = None mkdir_p(os.path.dirname(path)) code_format = CPP_BASE_FORMAT include_s = get_include_text() full_file = code_format[ 0] + CPP_INCLUDE_BEGIN + u'\n' + include_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] if prev_file == full_file: return with codecs.open(path, 'w+', encoding='utf-8') as f_handle: f_handle.write(full_file)
def write_platformio_project(): mkdir_p(CORE.build_path) platformio_ini = CORE.relative_build_path('platformio.ini') content = get_ini_content() write_gitignore() write_platformio_ini(content, platformio_ini)
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') if not os.path.isfile(partitions_csv): with open(partitions_csv, "w") as f: f.write("nvs, data, nvs, 0x009000, 0x005000,\n") f.write("otadata, data, ota, 0x00e000, 0x002000,\n") f.write("app0, app, ota_0, 0x010000, 0x190000,\n") f.write("app1, app, ota_1, 0x200000, 0x190000,\n") f.write("eeprom, data, 0x99, 0x390000, 0x001000,\n") f.write("spiffs, data, spiffs, 0x391000, 0x00F000\n") 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 if not CORE.config[CONF_ESPHOME][CONF_USE_CUSTOM_CODE]: # Ignore libraries that are not explicitly used, but may # be added by LDF data['lib_ldf_mode'] = 'chain' REMOVABLE_LIBRARIES = [ 'ArduinoOTA', 'Update', 'Wire', 'FastLED', 'NeoPixelBus', 'ESP Async WebServer', 'AsyncMqttClient', 'AsyncTCP', 'ESPAsyncTCP', ] ignore = [] for x in REMOVABLE_LIBRARIES: for o in lib_deps: if o.startswith(x): break else: ignore.append(x) if ignore: data['lib_ignore'] = ignore data.update(CORE.config[CONF_ESPHOME].get(CONF_PLATFORMIO_OPTIONS, {})) content = u'[env:{}]\n'.format(CORE.name) content += format_ini(data) return content
def update_esphome_core_repo(): if CONF_REPOSITORY not in CORE.esphome_core_version: return if CONF_BRANCH not in CORE.esphome_core_version: # Git commit hash or tag cannot be updated return esphome_core_path = CORE.relative_build_path('.piolibdeps', 'esphome-core') rc, _, _ = run_system_command('git', '-C', esphome_core_path, '--help') if rc != 0: # git not installed or repo not downloaded yet return rc, _, _ = run_system_command('git', '-C', esphome_core_path, 'diff-index', '--quiet', 'HEAD', '--') if rc != 0: # local changes, cannot update _LOGGER.warning( "Local changes in esphome-core copy from git. Will not auto-update." ) return _LOGGER.info("Updating esphome-core copy from git (%s)", esphome_core_path) rc, stdout, _ = run_system_command('git', '-c', 'color.ui=always', '-C', esphome_core_path, 'pull', '--stat') if rc != 0: _LOGGER.warning("Couldn't auto-update local git copy of esphome-core.") return if IS_PY3: stdout = stdout.decode('utf-8', 'backslashreplace') safe_print(stdout.strip())
def clean_build(): for directory in ('.piolibdeps', '.pioenvs'): dir_path = CORE.relative_build_path(directory) if not os.path.isdir(dir_path): continue _LOGGER.info("Deleting %s", dir_path) shutil.rmtree(dir_path)
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)
def includes(config): ret = [] for include in config.get(CONF_INCLUDES, []): path = CORE.relative_path(include) res = os.path.relpath(path, CORE.relative_build_path('src')) ret.append(u'#include "{}"'.format(res)) return ret
def copy_files(): 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"), )
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
def symlink_esphome_core_version(esphome_core_version): lib_path = CORE.relative_build_path('lib') dst_path = CORE.relative_build_path('lib', 'esphome-core') if CORE.is_local_esphome_core_copy: src_path = CORE.relative_path(esphome_core_version[CONF_LOCAL]) do_write = True if os.path.islink(dst_path): old_path = os.path.join(os.readlink(dst_path), lib_path) if old_path != lib_path: os.unlink(dst_path) else: do_write = False if do_write: mkdir_p(lib_path) symlink(src_path, dst_path) else: # Remove symlink when changing back from local version if os.path.islink(dst_path): os.unlink(dst_path)
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"), )
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
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)
def _load_idedata(config): platformio_ini = Path(CORE.relative_build_path("platformio.ini")) temp_idedata = Path(CORE.relative_internal_path("idedata", f"{CORE.name}.json")) changed = False if not platformio_ini.is_file() or not temp_idedata.is_file(): changed = True elif platformio_ini.stat().st_mtime >= temp_idedata.stat().st_mtime: changed = True if not changed: try: return json.loads(temp_idedata.read_text(encoding="utf-8")) except ValueError: pass temp_idedata.parent.mkdir(exist_ok=True, parents=True) data = _run_idedata(config) temp_idedata.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8") return data
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') if not os.path.isfile(partitions_csv): with open(partitions_csv, "w") as f: f.write("nvs, data, nvs, 0x009000, 0x005000,\n") f.write("otadata, data, ota, 0x00e000, 0x002000,\n") f.write("app0, app, ota_0, 0x010000, 0x190000,\n") f.write("app1, app, ota_1, 0x200000, 0x190000,\n") f.write("eeprom, data, 0x99, 0x390000, 0x001000,\n") f.write("spiffs, data, spiffs, 0x391000, 0x00F000\n") 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 # 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 = u'[env:{}]\n'.format(CORE.name) content += format_ini(data) return content
def copy_src_tree(): source_files: List[loader.FileResource] = [] for _, component, _ in iter_components(CORE.config): source_files += component.resources source_files_map = { Path(x.package.replace(".", "/") + "/" + x.resource): x for x in source_files } # Convert to list and sort source_files_l = list(source_files_map.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_map.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_build_path("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"), generate_version_h()) if CORE.is_esp32: from esphome.components.esp32 import copy_files copy_files() elif CORE.is_esp8266: from esphome.components.esp8266 import copy_files copy_files()