2018-04-07 01:23:03 +02:00
|
|
|
from __future__ import print_function
|
|
|
|
|
|
|
|
import codecs
|
|
|
|
import errno
|
|
|
|
import os
|
|
|
|
|
2018-05-06 15:56:12 +02:00
|
|
|
from esphomeyaml import core
|
2018-04-18 18:43:13 +02:00
|
|
|
from esphomeyaml.config import iter_components
|
2018-05-16 19:45:33 +02:00
|
|
|
from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \
|
|
|
|
CONF_LIBRARY_URI, \
|
|
|
|
CONF_NAME, CONF_PLATFORM, CONF_USE_BUILD_FLAGS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
|
2018-04-07 01:23:03 +02:00
|
|
|
from esphomeyaml.core import ESPHomeYAMLError
|
|
|
|
|
|
|
|
CPP_AUTO_GENERATE_BEGIN = u'// ========== AUTO GENERATED CODE BEGIN ==========='
|
|
|
|
CPP_AUTO_GENERATE_END = u'// =========== AUTO GENERATED CODE END ============'
|
|
|
|
INI_AUTO_GENERATE_BEGIN = u'; ========== AUTO GENERATED CODE BEGIN ==========='
|
|
|
|
INI_AUTO_GENERATE_END = u'; =========== AUTO GENERATED CODE END ============'
|
|
|
|
|
|
|
|
CPP_BASE_FORMAT = (u"""// Auto generated code by esphomeyaml
|
|
|
|
#include "esphomelib/application.h"
|
|
|
|
|
|
|
|
using namespace esphomelib;
|
|
|
|
|
|
|
|
void setup() {
|
|
|
|
// ===== DO NOT EDIT ANYTHING BELOW THIS LINE =====
|
|
|
|
""", u"""
|
|
|
|
// ========= YOU CAN EDIT AFTER THIS LINE =========
|
|
|
|
App.setup();
|
|
|
|
}
|
|
|
|
|
|
|
|
void loop() {
|
|
|
|
App.loop();
|
2018-05-17 17:20:43 +02:00
|
|
|
delay(16);
|
2018-04-07 01:23:03 +02:00
|
|
|
}
|
|
|
|
""")
|
|
|
|
|
|
|
|
INI_BASE_FORMAT = (u"""; Auto generated code by esphomeyaml
|
|
|
|
|
|
|
|
[common]
|
2018-04-10 17:17:46 +02:00
|
|
|
lib_deps =
|
|
|
|
build_flags =
|
|
|
|
upload_flags =
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
; ===== DO NOT EDIT ANYTHING BELOW THIS LINE =====
|
|
|
|
""", u"""
|
|
|
|
; ========= YOU CAN EDIT AFTER THIS LINE =========
|
|
|
|
|
|
|
|
""")
|
|
|
|
|
|
|
|
INI_CONTENT_FORMAT = u"""[env:{env}]
|
|
|
|
platform = {platform}
|
|
|
|
board = {board}
|
|
|
|
framework = arduino
|
|
|
|
lib_deps =
|
2018-05-06 15:56:12 +02:00
|
|
|
{lib_deps}
|
2018-04-07 01:23:03 +02:00
|
|
|
${{common.lib_deps}}
|
2018-04-18 18:43:13 +02:00
|
|
|
build_flags =
|
|
|
|
{build_flags}
|
2018-04-07 01:23:03 +02:00
|
|
|
${{common.build_flags}}
|
|
|
|
"""
|
|
|
|
|
|
|
|
PLATFORM_TO_PLATFORMIO = {
|
|
|
|
ESP_PLATFORM_ESP32: 'espressif32',
|
|
|
|
ESP_PLATFORM_ESP8266: 'espressif8266'
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-18 18:43:13 +02:00
|
|
|
def get_build_flags(config, key):
|
|
|
|
build_flags = set()
|
|
|
|
for _, component, conf in iter_components(config):
|
|
|
|
if not hasattr(component, key):
|
|
|
|
continue
|
2018-05-06 15:56:12 +02:00
|
|
|
flags = getattr(component, key)
|
|
|
|
if callable(flags):
|
|
|
|
flags = flags(conf)
|
2018-04-18 18:43:13 +02:00
|
|
|
if flags is None:
|
|
|
|
continue
|
|
|
|
if isinstance(flags, (str, unicode)):
|
|
|
|
flags = [flags]
|
|
|
|
build_flags |= set(flags)
|
|
|
|
return build_flags
|
|
|
|
|
|
|
|
|
2018-04-07 01:23:03 +02:00
|
|
|
def get_ini_content(config):
|
2018-06-08 11:34:06 +02:00
|
|
|
version_specific_settings = determine_platformio_version_settings()
|
2018-04-18 18:43:13 +02:00
|
|
|
platform = config[CONF_ESPHOMEYAML][CONF_PLATFORM]
|
|
|
|
if platform in PLATFORM_TO_PLATFORMIO:
|
|
|
|
platform = PLATFORM_TO_PLATFORMIO[platform]
|
2018-04-10 17:17:46 +02:00
|
|
|
options = {
|
2018-04-07 01:23:03 +02:00
|
|
|
u'env': config[CONF_ESPHOMEYAML][CONF_NAME],
|
2018-04-18 18:43:13 +02:00
|
|
|
u'platform': platform,
|
2018-04-07 01:23:03 +02:00
|
|
|
u'board': config[CONF_ESPHOMEYAML][CONF_BOARD],
|
|
|
|
u'build_flags': u'',
|
|
|
|
}
|
2018-04-18 18:43:13 +02:00
|
|
|
build_flags = set()
|
|
|
|
if config[CONF_ESPHOMEYAML][CONF_USE_BUILD_FLAGS]:
|
|
|
|
build_flags |= get_build_flags(config, 'build_flags')
|
2018-05-06 15:56:12 +02:00
|
|
|
build_flags |= get_build_flags(config, 'BUILD_FLAGS')
|
2018-04-18 18:43:13 +02:00
|
|
|
build_flags.add(u"-DESPHOMEYAML_USE")
|
|
|
|
build_flags |= get_build_flags(config, 'required_build_flags')
|
2018-05-14 11:50:56 +02:00
|
|
|
build_flags |= get_build_flags(config, 'REQUIRED_BUILD_FLAGS')
|
2018-04-18 18:43:13 +02:00
|
|
|
|
|
|
|
# avoid changing build flags order
|
|
|
|
build_flags = sorted(list(build_flags))
|
|
|
|
if build_flags:
|
|
|
|
options[u'build_flags'] = u'\n '.join(build_flags)
|
2018-05-06 15:56:12 +02:00
|
|
|
|
|
|
|
lib_deps = set()
|
|
|
|
lib_deps.add(config[CONF_ESPHOMEYAML][CONF_LIBRARY_URI])
|
2018-05-14 11:50:56 +02:00
|
|
|
lib_deps |= get_build_flags(config, 'LIB_DEPS')
|
|
|
|
lib_deps |= get_build_flags(config, 'lib_deps')
|
2018-05-06 15:56:12 +02:00
|
|
|
if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
|
|
|
|
lib_deps |= {
|
2018-05-14 11:50:56 +02:00
|
|
|
'Preferences', # Preferences helper
|
2018-05-06 15:56:12 +02:00
|
|
|
}
|
2018-05-14 11:50:56 +02:00
|
|
|
# avoid changing build flags order
|
|
|
|
lib_deps = sorted(x for x in lib_deps if x)
|
|
|
|
if lib_deps:
|
|
|
|
options[u'lib_deps'] = u'\n '.join(lib_deps)
|
2018-05-06 15:56:12 +02:00
|
|
|
|
2018-05-16 19:45:33 +02:00
|
|
|
content = INI_CONTENT_FORMAT.format(**options)
|
|
|
|
if CONF_BOARD_FLASH_MODE in config[CONF_ESPHOMEYAML]:
|
2018-06-08 11:34:06 +02:00
|
|
|
flash_mode_key = version_specific_settings['flash_mode_key']
|
2018-05-16 19:45:33 +02:00
|
|
|
flash_mode = config[CONF_ESPHOMEYAML][CONF_BOARD_FLASH_MODE]
|
2018-06-08 11:34:06 +02:00
|
|
|
content += "{} = {}\n".format(flash_mode_key, flash_mode)
|
2018-05-16 19:45:33 +02:00
|
|
|
return content
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
def mkdir_p(path):
|
|
|
|
try:
|
|
|
|
os.makedirs(path)
|
|
|
|
except OSError as exc: # Python >2.5
|
|
|
|
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
def find_begin_end(text, begin_s, end_s):
|
|
|
|
begin_index = text.find(begin_s)
|
|
|
|
if begin_index == -1:
|
|
|
|
raise ESPHomeYAMLError(u"Could not find auto generated code begin in file, either"
|
|
|
|
u"delete the main sketch file or insert the comment again.")
|
|
|
|
if text.find(begin_s, begin_index + 1) != -1:
|
|
|
|
raise ESPHomeYAMLError(u"Found multiple auto generate code begins, don't know"
|
|
|
|
u"which to chose, please remove one of them.")
|
|
|
|
end_index = text.find(end_s)
|
|
|
|
if end_index == -1:
|
|
|
|
raise ESPHomeYAMLError(u"Could not find auto generated code end in file, either"
|
|
|
|
u"delete the main sketch file or insert the comment again.")
|
|
|
|
if text.find(end_s, end_index + 1) != -1:
|
|
|
|
raise ESPHomeYAMLError(u"Found multiple auto generate code endings, don't know"
|
|
|
|
u"which to chose, please remove one of them.")
|
|
|
|
|
|
|
|
return text[:begin_index], text[(end_index + len(end_s)):]
|
|
|
|
|
|
|
|
|
|
|
|
def write_platformio_ini(content, path):
|
|
|
|
if os.path.isfile(path):
|
|
|
|
try:
|
2018-04-10 17:17:46 +02:00
|
|
|
with codecs.open(path, 'r', encoding='utf-8') as f_handle:
|
|
|
|
text = f_handle.read()
|
2018-04-07 01:23:03 +02:00
|
|
|
except OSError:
|
|
|
|
raise ESPHomeYAMLError(u"Could not read ini file at {}".format(path))
|
|
|
|
prev_file = text
|
|
|
|
content_format = find_begin_end(text, INI_AUTO_GENERATE_BEGIN, INI_AUTO_GENERATE_END)
|
|
|
|
else:
|
|
|
|
prev_file = None
|
|
|
|
mkdir_p(os.path.dirname(path))
|
|
|
|
content_format = INI_BASE_FORMAT
|
|
|
|
full_file = content_format[0] + INI_AUTO_GENERATE_BEGIN + '\n' + \
|
2018-05-21 15:07:17 +02:00
|
|
|
content + INI_AUTO_GENERATE_END + content_format[1]
|
2018-04-07 01:23:03 +02:00
|
|
|
if prev_file == full_file:
|
|
|
|
return
|
2018-04-10 17:17:46 +02:00
|
|
|
with codecs.open(path, mode='w+', encoding='utf-8') as f_handle:
|
|
|
|
f_handle.write(full_file)
|
2018-04-07 01:23:03 +02:00
|
|
|
|
|
|
|
|
2018-06-12 21:18:04 +02:00
|
|
|
def write_platformio_project(config, path):
|
|
|
|
platformio_ini = os.path.join(path, 'platformio.ini')
|
|
|
|
content = get_ini_content(config)
|
2018-08-13 19:11:33 +02:00
|
|
|
if 'esp32_ble_beacon' in config or 'esp32_ble_tracker' in config:
|
2018-06-12 21:18:04 +02:00
|
|
|
content += 'board_build.partitions = partitions.csv\n'
|
|
|
|
partitions_csv = os.path.join(path, 'partitions.csv')
|
|
|
|
if not os.path.isfile(partitions_csv):
|
2018-08-13 19:11:33 +02:00
|
|
|
mkdir_p(path)
|
2018-06-12 21:18:04 +02:00
|
|
|
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")
|
|
|
|
write_platformio_ini(content, platformio_ini)
|
|
|
|
|
|
|
|
|
2018-04-07 01:23:03 +02:00
|
|
|
def write_cpp(code_s, path):
|
|
|
|
if os.path.isfile(path):
|
|
|
|
try:
|
2018-04-10 17:17:46 +02:00
|
|
|
with codecs.open(path, 'r', encoding='utf-8') as f_handle:
|
|
|
|
text = f_handle.read()
|
2018-04-07 01:23:03 +02:00
|
|
|
except OSError:
|
|
|
|
raise ESPHomeYAMLError(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)
|
|
|
|
else:
|
|
|
|
prev_file = None
|
|
|
|
mkdir_p(os.path.dirname(path))
|
|
|
|
code_format = CPP_BASE_FORMAT
|
|
|
|
|
|
|
|
full_file = code_format[0] + CPP_AUTO_GENERATE_BEGIN + '\n' + \
|
2018-05-21 15:07:17 +02:00
|
|
|
code_s + CPP_AUTO_GENERATE_END + code_format[1]
|
2018-04-07 01:23:03 +02:00
|
|
|
if prev_file == full_file:
|
|
|
|
return
|
2018-04-10 17:17:46 +02:00
|
|
|
with codecs.open(path, 'w+', encoding='utf-8') as f_handle:
|
|
|
|
f_handle.write(full_file)
|
2018-06-08 11:34:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
def determine_platformio_version_settings():
|
|
|
|
import platformio
|
|
|
|
|
|
|
|
settings = {}
|
|
|
|
|
|
|
|
if platformio.VERSION < (3, 5, 3):
|
|
|
|
settings['flash_mode_key'] = 'board_flash_mode'
|
|
|
|
else:
|
|
|
|
settings['flash_mode_key'] = 'board_build.flash_mode'
|
|
|
|
|
|
|
|
return settings
|