mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Updates
This commit is contained in:
		| @@ -7,11 +7,11 @@ import random | ||||
| import sys | ||||
| from datetime import datetime | ||||
|  | ||||
| from esphomeyaml import const, core, mqtt, wizard, writer, yaml_util | ||||
| from esphomeyaml.config import core_to_code, get_component, iter_components, read_config | ||||
| from esphomeyaml import const, core, core_config, mqtt, wizard, writer, yaml_util | ||||
| from esphomeyaml.config import get_component, iter_components, read_config | ||||
| from esphomeyaml.const import CONF_BAUD_RATE, CONF_BUILD_PATH, CONF_DOMAIN, CONF_ESPHOMEYAML, \ | ||||
|     CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI, \ | ||||
|     ESP_PLATFORM_ESP8266 | ||||
|     CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_USE_CUSTOM_CODE, \ | ||||
|     CONF_WIFI, ESP_PLATFORM_ESP8266 | ||||
| from esphomeyaml.core import ESPHomeYAMLError | ||||
| from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \ | ||||
|     add_job, color, flush_tasks, indent, quote, statement | ||||
| @@ -123,7 +123,7 @@ def run_miniterm(config, port, escape=False): | ||||
| def write_cpp(config): | ||||
|     _LOGGER.info("Generating C++ source...") | ||||
|  | ||||
|     add_job(core_to_code, config[CONF_ESPHOMEYAML], domain='esphomeyaml') | ||||
|     add_job(core_config.to_code, config[CONF_ESPHOMEYAML], domain='esphomeyaml') | ||||
|     for domain in PRE_INITIALIZE: | ||||
|         if domain == CONF_ESPHOMEYAML or domain not in config: | ||||
|             continue | ||||
| @@ -139,7 +139,7 @@ def write_cpp(config): | ||||
|     add(RawStatement('')) | ||||
|     all_code = [] | ||||
|     for exp in _EXPRESSIONS: | ||||
|         if core.SIMPLIFY: | ||||
|         if not config[CONF_ESPHOMEYAML][CONF_USE_CUSTOM_CODE]: | ||||
|             if isinstance(exp, Expression) and not exp.required: | ||||
|                 continue | ||||
|             if isinstance(exp, AssignmentExpression) and not exp.obj.required: | ||||
| @@ -302,7 +302,7 @@ def command_compile(args, config): | ||||
|         return exit_code | ||||
|     if args.only_generate: | ||||
|         _LOGGER.info(u"Successfully generated source code.") | ||||
|         return 0; | ||||
|         return 0 | ||||
|     exit_code = compile_program(args, config) | ||||
|     if exit_code != 0: | ||||
|         return exit_code | ||||
| @@ -388,10 +388,11 @@ def parse_args(argv): | ||||
|     subparsers.required = True | ||||
|     subparsers.add_parser('config', help='Validate the configuration and spit it out.') | ||||
|  | ||||
|     parser_compile = subparsers.add_parser('compile', help='Read the configuration and compile a program.') | ||||
|     parser_compile = subparsers.add_parser('compile', | ||||
|                                            help='Read the configuration and compile a program.') | ||||
|     parser_compile.add_argument('--only-generate', | ||||
|                                help="Only generate source code, do not compile.", | ||||
|                                action='store_true') | ||||
|                                 help="Only generate source code, do not compile.", | ||||
|                                 action='store_true') | ||||
|  | ||||
|     parser_upload = subparsers.add_parser('upload', help='Validate the configuration ' | ||||
|                                                          'and upload the latest binary.') | ||||
|   | ||||
| @@ -5,7 +5,7 @@ from esphomeyaml import automation | ||||
| from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_ID, CONF_INTERNAL, CONF_INVERTED, \ | ||||
|     CONF_MAX_LENGTH, CONF_MIN_LENGTH, CONF_MQTT_ID, CONF_ON_CLICK, CONF_ON_DOUBLE_CLICK, \ | ||||
|     CONF_ON_PRESS, CONF_ON_RELEASE, CONF_TRIGGER_ID, CONF_FILTERS, CONF_INVERT, CONF_DELAYED_ON, \ | ||||
|     CONF_DELAYED_OFF, CONF_LAMBDA | ||||
|     CONF_DELAYED_OFF, CONF_LAMBDA, CONF_HEARTBEAT | ||||
| from esphomeyaml.helpers import App, NoArg, Pvariable, add, add_job, esphomelib_ns, \ | ||||
|     setup_mqtt_component, bool_, process_lambda, ArrayInitializer | ||||
|  | ||||
| @@ -30,6 +30,7 @@ InvertFilter = binary_sensor_ns.InvertFilter | ||||
| LambdaFilter = binary_sensor_ns.LambdaFilter | ||||
| DelayedOnFilter = binary_sensor_ns.DelayedOnFilter | ||||
| DelayedOffFilter = binary_sensor_ns.DelayedOffFilter | ||||
| HeartbeatFilter = binary_sensor_ns.HeartbeatFilter | ||||
| MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent | ||||
|  | ||||
| FILTER_KEYS = [CONF_INVERT, CONF_DELAYED_ON, CONF_DELAYED_OFF, CONF_LAMBDA] | ||||
| @@ -38,6 +39,7 @@ FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({ | ||||
|     vol.Optional(CONF_INVERT): None, | ||||
|     vol.Optional(CONF_DELAYED_ON): cv.positive_time_period_milliseconds, | ||||
|     vol.Optional(CONF_DELAYED_OFF): cv.positive_time_period_milliseconds, | ||||
|     vol.Optional(CONF_HEARTBEAT): cv.positive_time_period_milliseconds, | ||||
|     vol.Optional(CONF_LAMBDA): cv.lambda_, | ||||
| }, cv.has_exactly_one_key(*FILTER_KEYS))]) | ||||
|  | ||||
| @@ -82,6 +84,8 @@ def setup_filter(config): | ||||
|         yield App.register_component(DelayedOffFilter.new(config[CONF_DELAYED_OFF])) | ||||
|     elif CONF_DELAYED_ON in config: | ||||
|         yield App.register_component(DelayedOnFilter.new(config[CONF_DELAYED_ON])) | ||||
|     elif CONF_HEARTBEAT in config: | ||||
|         yield App.register_component(HeartbeatFilter.new(config[CONF_HEARTBEAT])) | ||||
|     elif CONF_LAMBDA in config: | ||||
|         lambda_ = None | ||||
|         for lambda_ in process_lambda(config[CONF_LAMBDA], [(bool_, 'x')]): | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| # coding=utf-8 | ||||
| import os.path | ||||
|  | ||||
| import voluptuous as vol | ||||
|  | ||||
| import esphomeyaml.config_validation as cv | ||||
| @@ -8,7 +6,8 @@ from esphomeyaml import core | ||||
| from esphomeyaml.components import display | ||||
| from esphomeyaml.const import CONF_FILE, CONF_GLYPHS, CONF_ID, CONF_SIZE | ||||
| from esphomeyaml.core import HexInt | ||||
| from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add | ||||
| from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add, \ | ||||
|     relative_path | ||||
|  | ||||
| DEPENDENCIES = ['display'] | ||||
|  | ||||
| @@ -57,17 +56,13 @@ def validate_pillow_installed(value): | ||||
|  | ||||
|  | ||||
| def validate_truetype_file(value): | ||||
|     value = cv.string(value) | ||||
|     path = os.path.join(os.path.dirname(core.CONFIG_PATH), value) | ||||
|     if not os.path.isfile(path): | ||||
|         raise vol.Invalid(u"Could not find file '{}'. Please make sure it exists.".format(path)) | ||||
|     if value.endswith('.zip'):  # for Google Fonts downloads | ||||
|         raise vol.Invalid(u"Please unzip the font archive '{}' first and then use the .ttf files " | ||||
|                           u"inside.".format(value)) | ||||
|     if not value.endswith('.ttf'): | ||||
|         raise vol.Invalid(u"Only truetype (.ttf) files are supported. Please make sure you're " | ||||
|                           u"using the correct format or rename the extension to .ttf") | ||||
|     return value | ||||
|     return cv.file_(value) | ||||
|  | ||||
|  | ||||
| DEFAULT_GLYPHS = u' !"%()+,-.:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°' | ||||
| @@ -88,7 +83,7 @@ def to_code(config): | ||||
|     from PIL import ImageFont | ||||
|  | ||||
|     for conf in config: | ||||
|         path = os.path.join(os.path.dirname(core.CONFIG_PATH), conf[CONF_FILE]) | ||||
|         path = relative_path(conf[CONF_FILE]) | ||||
|         try: | ||||
|             font = ImageFont.truetype(path, conf[CONF_SIZE]) | ||||
|         except Exception as e: | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| # coding=utf-8 | ||||
| import logging | ||||
| import os.path | ||||
|  | ||||
| import voluptuous as vol | ||||
|  | ||||
| @@ -9,7 +8,8 @@ from esphomeyaml import core | ||||
| from esphomeyaml.components import display, font | ||||
| from esphomeyaml.const import CONF_FILE, CONF_ID, CONF_RESIZE | ||||
| from esphomeyaml.core import HexInt | ||||
| from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add | ||||
| from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add, \ | ||||
|     relative_path | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -17,20 +17,11 @@ DEPENDENCIES = ['display'] | ||||
|  | ||||
| Image_ = display.display_ns.Image | ||||
|  | ||||
|  | ||||
| def validate_image_file(value): | ||||
|     value = cv.string(value) | ||||
|     path = os.path.join(os.path.dirname(core.CONFIG_PATH), value) | ||||
|     if not os.path.isfile(path): | ||||
|         raise vol.Invalid(u"Could not find file '{}'. Please make sure it exists.".format(path)) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| CONF_RAW_DATA_ID = 'raw_data_id' | ||||
|  | ||||
| IMAGE_SCHEMA = vol.Schema({ | ||||
|     vol.Required(CONF_ID): cv.declare_variable_id(Image_), | ||||
|     vol.Required(CONF_FILE): validate_image_file, | ||||
|     vol.Required(CONF_FILE): cv.file_, | ||||
|     vol.Optional(CONF_RESIZE): cv.dimensions, | ||||
|     cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(None), | ||||
| }) | ||||
| @@ -42,7 +33,7 @@ def to_code(config): | ||||
|     from PIL import Image | ||||
|  | ||||
|     for conf in config: | ||||
|         path = os.path.join(os.path.dirname(core.CONFIG_PATH), conf[CONF_FILE]) | ||||
|         path = relative_path(conf[CONF_FILE]) | ||||
|         try: | ||||
|             image = Image.open(path) | ||||
|         except Exception as e: | ||||
|   | ||||
| @@ -5,9 +5,10 @@ import math | ||||
| import voluptuous as vol | ||||
|  | ||||
| import esphomeyaml.config_validation as cv | ||||
| from esphomeyaml.const import CONF_TIMEZONE | ||||
| from esphomeyaml.helpers import add, add_job, esphomelib_ns | ||||
|  | ||||
| from esphomeyaml import automation | ||||
| from esphomeyaml.const import CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, CONF_HOURS, \ | ||||
|     CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_SECONDS, CONF_TIMEZONE, CONF_TRIGGER_ID | ||||
| from esphomeyaml.helpers import App, NoArg, Pvariable, add, add_job, esphomelib_ns | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -16,6 +17,7 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ | ||||
| }) | ||||
|  | ||||
| time_ns = esphomelib_ns.namespace('time') | ||||
| CronTrigger = time_ns.CronTrigger | ||||
|  | ||||
|  | ||||
| def _tz_timedelta(td): | ||||
| @@ -117,14 +119,155 @@ def detect_tz(): | ||||
|     return tzbase + tzext | ||||
|  | ||||
|  | ||||
| def _parse_cron_int(value, special_mapping, message): | ||||
|     special_mapping = special_mapping or {} | ||||
|     if isinstance(value, (str, unicode)) and value in special_mapping: | ||||
|         return special_mapping[value] | ||||
|     try: | ||||
|         return int(value) | ||||
|     except ValueError: | ||||
|         raise vol.Invalid(message.format(value)) | ||||
|  | ||||
|  | ||||
| def _parse_cron_part(part, min_value, max_value, special_mapping): | ||||
|     if part == '*' or part == '?': | ||||
|         return set(x for x in range(min_value, max_value + 1)) | ||||
|     if '/' in part: | ||||
|         data = part.split('/') | ||||
|         if len(data) > 2: | ||||
|             raise vol.Invalid(u"Can't have more than two '/' in one time expression, got {}" | ||||
|                               .format(part)) | ||||
|         offset, repeat = data | ||||
|         offset_n = 0 | ||||
|         if offset: | ||||
|             offset_n = _parse_cron_int(offset, special_mapping, | ||||
|                                        u"Offset for '/' time expression must be an integer, got {}") | ||||
|  | ||||
|         try: | ||||
|             repeat_n = int(repeat) | ||||
|         except ValueError: | ||||
|             raise vol.Invalid(u"Repeat for '/' time expression must be an integer, got {}" | ||||
|                               .format(repeat)) | ||||
|         return set(x for x in range(offset_n, max_value + 1, repeat_n)) | ||||
|     if '-' in part: | ||||
|         data = part.split('-') | ||||
|         if len(data) > 2: | ||||
|             raise vol.Invalid(u"Can't have more than two '-' in range time expression '{}'" | ||||
|                               .format(part)) | ||||
|         begin, end = data | ||||
|         begin_n = _parse_cron_int(begin, special_mapping, u"Number for time range must be integer, " | ||||
|                                                           u"got {}") | ||||
|         end_n = _parse_cron_int(end, special_mapping, u"Number for time range must be integer, " | ||||
|                                                       u"got {}") | ||||
|         if end_n < begin_n: | ||||
|             return set(x for x in range(end_n, max_value + 1)) | \ | ||||
|                    set(x for x in range(min_value, begin_n + 1)) | ||||
|         return set(x for x in range(begin_n, end_n + 1)) | ||||
|  | ||||
|     return {_parse_cron_int(part, special_mapping, u"Number for time expression must be an " | ||||
|                                                    u"integer, got {}")} | ||||
|  | ||||
|  | ||||
| def cron_expression_validator(name, min_value, max_value, special_mapping=None): | ||||
|     def validator(value): | ||||
|         if isinstance(value, list): | ||||
|             for v in value: | ||||
|                 if not isinstance(v, int): | ||||
|                     raise vol.Invalid( | ||||
|                         "Expected integer for {} '{}', got {}".format(v, name, type(v))) | ||||
|                 if v < min_value or v > max_value: | ||||
|                     raise vol.Invalid( | ||||
|                         "{} {} is out of range (min={} max={}).".format(name, v, min_value, | ||||
|                                                                         max_value)) | ||||
|             return list(sorted(value)) | ||||
|         value = cv.string(value) | ||||
|         values = set() | ||||
|         for part in value.split(','): | ||||
|             values |= _parse_cron_part(part, min_value, max_value, special_mapping) | ||||
|         return validator(list(values)) | ||||
|  | ||||
|     return validator | ||||
|  | ||||
|  | ||||
| validate_cron_seconds = cron_expression_validator('seconds', 0, 60) | ||||
| validate_cron_minutes = cron_expression_validator('minutes', 0, 59) | ||||
| validate_cron_hours = cron_expression_validator('hours', 0, 23) | ||||
| validate_cron_days_of_month = cron_expression_validator('days of month', 1, 31) | ||||
| validate_cron_months = cron_expression_validator('months', 1, 12, { | ||||
|     'JAN': 1, 'FEB': 2, 'MAR': 3, 'APR': 4, 'MAY': 5, 'JUN': 6, 'JUL': 7, 'AUG': 8, | ||||
|     'SEP': 9, 'OCT': 10, 'NOV': 11, 'DEC': 12 | ||||
| }) | ||||
| validate_cron_days_of_week = cron_expression_validator('days of week', 1, 7, { | ||||
|     'SUN': 1, 'MON': 2, 'TUE': 3, 'WED': 4, 'THU': 5, 'FRI': 6, 'SAT': 7 | ||||
| }) | ||||
| CRON_KEYS = [CONF_SECONDS, CONF_MINUTES, CONF_HOURS, CONF_DAYS_OF_MONTH, CONF_MONTHS, | ||||
|              CONF_DAYS_OF_WEEK] | ||||
|  | ||||
|  | ||||
| def validate_cron_raw(value): | ||||
|     value = cv.string(value) | ||||
|     value = value.split(' ') | ||||
|     if len(value) != 6: | ||||
|         raise vol.Invalid("Cron expression must consist of exactly 6 space-separated parts, " | ||||
|                           "not {}".format(len(value))) | ||||
|     seconds, minutes, hours, days_of_month, months, days_of_week = value | ||||
|     return { | ||||
|         CONF_SECONDS: validate_cron_seconds(seconds), | ||||
|         CONF_MINUTES: validate_cron_minutes(minutes), | ||||
|         CONF_HOURS: validate_cron_hours(hours), | ||||
|         CONF_DAYS_OF_MONTH: validate_cron_days_of_month(days_of_month), | ||||
|         CONF_MONTHS: validate_cron_months(months), | ||||
|         CONF_DAYS_OF_WEEK: validate_cron_days_of_week(days_of_week), | ||||
|     } | ||||
|  | ||||
|  | ||||
| def validate_cron_keys(value): | ||||
|     if CONF_CRON in value: | ||||
|         for key in value.keys(): | ||||
|             if key in CRON_KEYS: | ||||
|                 raise vol.Invalid("Cannot use option {} when cron: is specified.".format(key)) | ||||
|         cron_ = value[CONF_CRON] | ||||
|         value = {x: value[x] for x in value if x != CONF_CRON} | ||||
|         value.update(cron_) | ||||
|         return value | ||||
|     return cv.has_at_least_one_key(*CRON_KEYS)(value) | ||||
|  | ||||
|  | ||||
| TIME_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||||
|     vol.Optional(CONF_TIMEZONE, default=detect_tz): cv.string, | ||||
|     vol.Optional(CONF_ON_TIME): vol.All(cv.ensure_list, [vol.All(automation.validate_automation({ | ||||
|         cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(CronTrigger), | ||||
|         vol.Optional(CONF_SECONDS): validate_cron_seconds, | ||||
|         vol.Optional(CONF_MINUTES): validate_cron_minutes, | ||||
|         vol.Optional(CONF_HOURS): validate_cron_hours, | ||||
|         vol.Optional(CONF_DAYS_OF_MONTH): validate_cron_days_of_month, | ||||
|         vol.Optional(CONF_MONTHS): validate_cron_months, | ||||
|         vol.Optional(CONF_DAYS_OF_WEEK): validate_cron_days_of_week, | ||||
|         vol.Optional(CONF_CRON): validate_cron_raw, | ||||
|     }), validate_cron_keys)]), | ||||
| }) | ||||
|  | ||||
|  | ||||
| def setup_time_core_(time_var, config): | ||||
|     add(time_var.set_timezone(config[CONF_TIMEZONE])) | ||||
|  | ||||
|     for conf in config.get(CONF_ON_TIME, []): | ||||
|         rhs = App.register_component(time_var.Pmake_cron_trigger()) | ||||
|         trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs) | ||||
|         for second in conf.get(CONF_SECONDS, [x for x in range(0, 61)]): | ||||
|             add(trigger.add_second(second)) | ||||
|         for minute in conf.get(CONF_MINUTES, [x for x in range(0, 60)]): | ||||
|             add(trigger.add_minute(minute)) | ||||
|         for hour in conf.get(CONF_HOURS, [x for x in range(0, 24)]): | ||||
|             add(trigger.add_hour(hour)) | ||||
|         for day_of_month in conf.get(CONF_DAYS_OF_MONTH, [x for x in range(1, 32)]): | ||||
|             add(trigger.add_day_of_month(day_of_month)) | ||||
|         for month in conf.get(CONF_MONTHS, [x for x in range(1, 13)]): | ||||
|             add(trigger.add_month(month)) | ||||
|         for day_of_week in conf.get(CONF_DAYS_OF_WEEK, [x for x in range(1, 8)]): | ||||
|             add(trigger.add_day_of_week(day_of_week)) | ||||
|         automation.build_automation(trigger, NoArg, conf) | ||||
|  | ||||
|  | ||||
| def setup_time(time_var, config): | ||||
|     add_job(setup_time_core_, time_var, config) | ||||
|   | ||||
| @@ -8,7 +8,7 @@ from esphomeyaml.helpers import App, Pvariable | ||||
| SNTPComponent = time_.time_ns.SNTPComponent | ||||
|  | ||||
| PLATFORM_SCHEMA = time_.TIME_PLATFORM_SCHEMA.extend({ | ||||
|     vol.Required(CONF_ID): cv.declare_variable_id(SNTPComponent), | ||||
|     cv.GenerateID(): cv.declare_variable_id(SNTPComponent), | ||||
|     vol.Optional(CONF_SERVERS): vol.All(cv.ensure_list, [cv.string], vol.Length(max=3)), | ||||
|     vol.Optional(CONF_LAMBDA): cv.lambda_, | ||||
| }) | ||||
|   | ||||
| @@ -7,62 +7,20 @@ from collections import OrderedDict | ||||
| import voluptuous as vol | ||||
| from voluptuous.humanize import humanize_error | ||||
|  | ||||
| import esphomeyaml.config_validation as cv | ||||
| from esphomeyaml import core, yaml_util, automation | ||||
| from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \ | ||||
|     CONF_LIBRARY_URI, CONF_NAME, CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, \ | ||||
|     ESP_PLATFORMS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266, CONF_ON_BOOT, CONF_TRIGGER_ID, \ | ||||
|     CONF_PRIORITY, CONF_ON_SHUTDOWN, CONF_BUILD_PATH | ||||
| from esphomeyaml import core, yaml_util, core_config | ||||
| from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_PLATFORM, CONF_WIFI, ESP_PLATFORMS | ||||
| from esphomeyaml.core import ESPHomeYAMLError | ||||
| from esphomeyaml.helpers import App, add, color, esphomelib_ns, Pvariable, NoArg, const_char_p | ||||
| from esphomeyaml.helpers import color | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.7.0' | ||||
|  | ||||
| BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout'] | ||||
| StartupTrigger = esphomelib_ns.StartupTrigger | ||||
| ShutdownTrigger = esphomelib_ns.ShutdownTrigger | ||||
|  | ||||
| CORE_SCHEMA = vol.Schema({ | ||||
|     vol.Required(CONF_NAME): cv.valid_name, | ||||
|     vol.Required(CONF_PLATFORM): cv.string, | ||||
|     vol.Required(CONF_BOARD): cv.string, | ||||
|     vol.Optional(CONF_LIBRARY_URI, default=DEFAULT_LIBRARY_URI): cv.string, | ||||
|     vol.Optional(CONF_SIMPLIFY, default=True): cv.boolean, | ||||
|     vol.Optional(CONF_USE_BUILD_FLAGS, default=True): cv.boolean, | ||||
|     vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)), | ||||
|     vol.Optional(CONF_ON_BOOT): vol.All(cv.ensure_list, [automation.validate_automation({ | ||||
|         cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(StartupTrigger), | ||||
|         vol.Optional(CONF_PRIORITY): vol.Coerce(float), | ||||
|     })]), | ||||
|     vol.Optional(CONF_ON_SHUTDOWN): vol.All(cv.ensure_list, [automation.validate_automation({ | ||||
|         cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ShutdownTrigger), | ||||
|     })]), | ||||
|     vol.Optional(CONF_BUILD_PATH): cv.string, | ||||
| }) | ||||
|  | ||||
| REQUIRED_COMPONENTS = [ | ||||
|     CONF_ESPHOMEYAML, CONF_WIFI | ||||
| ] | ||||
|  | ||||
| _COMPONENT_CACHE = {} | ||||
| _ALL_COMPONENTS = [] | ||||
|  | ||||
|  | ||||
| def core_to_code(config): | ||||
|     add(App.set_name(config[CONF_NAME])) | ||||
|  | ||||
|     for conf in config.get(CONF_ON_BOOT, []): | ||||
|         rhs = App.register_component(StartupTrigger.new(conf.get(CONF_PRIORITY))) | ||||
|         trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs) | ||||
|         automation.build_automation(trigger, NoArg, conf) | ||||
|  | ||||
|     for conf in config.get(CONF_ON_SHUTDOWN, []): | ||||
|         trigger = Pvariable(conf[CONF_TRIGGER_ID], ShutdownTrigger.new()) | ||||
|         automation.build_automation(trigger, const_char_p, conf) | ||||
|  | ||||
|  | ||||
| def get_component(domain): | ||||
|     if domain in _COMPONENT_CACHE: | ||||
|         return _COMPONENT_CACHE[domain] | ||||
| @@ -171,9 +129,9 @@ def validate_config(config): | ||||
|         result.add_error(_format_config_error(ex, domain, config), domain, config) | ||||
|  | ||||
|     try: | ||||
|         result[CONF_ESPHOMEYAML] = CORE_SCHEMA(config[CONF_ESPHOMEYAML]) | ||||
|         result[CONF_ESPHOMEYAML] = core_config.CONFIG_SCHEMA(config[CONF_ESPHOMEYAML]) | ||||
|     except vol.Invalid as ex: | ||||
|         _comp_error(ex, CONF_ESPHOMEYAML, config) | ||||
|         _comp_error(ex, CONF_ESPHOMEYAML, config[CONF_ESPHOMEYAML]) | ||||
|  | ||||
|     for domain, conf in config.iteritems(): | ||||
|         domain = str(domain) | ||||
| @@ -288,23 +246,7 @@ def load_config(path): | ||||
|     except OSError: | ||||
|         raise ESPHomeYAMLError(u"Could not read configuration file at {}".format(path)) | ||||
|     core.RAW_CONFIG = config | ||||
|  | ||||
|     if CONF_ESPHOMEYAML not in config: | ||||
|         raise ESPHomeYAMLError(u"No esphomeyaml section in config") | ||||
|     core_conf = config[CONF_ESPHOMEYAML] | ||||
|     if CONF_PLATFORM not in core_conf: | ||||
|         raise ESPHomeYAMLError("esphomeyaml.platform not specified.") | ||||
|     esp_platform = unicode(core_conf[CONF_PLATFORM]) | ||||
|     esp_platform = esp_platform.upper() | ||||
|     if '8266' in esp_platform: | ||||
|         esp_platform = ESP_PLATFORM_ESP8266 | ||||
|     if '32' in esp_platform: | ||||
|         esp_platform = ESP_PLATFORM_ESP32 | ||||
|     core.ESP_PLATFORM = esp_platform | ||||
|     if CONF_BOARD not in core_conf: | ||||
|         raise ESPHomeYAMLError("esphomeyaml.board not specified.") | ||||
|     core.BOARD = unicode(core_conf[CONF_BOARD]) | ||||
|     core.SIMPLIFY = cv.boolean(core_conf.get(CONF_SIMPLIFY, True)) | ||||
|     core_config.preload_core_config(config) | ||||
|  | ||||
|     try: | ||||
|         result = validate_config(config) | ||||
|   | ||||
| @@ -3,12 +3,13 @@ | ||||
| from __future__ import print_function | ||||
|  | ||||
| import logging | ||||
| import os | ||||
| import re | ||||
| import uuid as uuid_ | ||||
|  | ||||
| import voluptuous as vol | ||||
|  | ||||
| from esphomeyaml import core | ||||
| from esphomeyaml import core, helpers | ||||
| from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \ | ||||
|     CONF_NAME, CONF_PAYLOAD_AVAILABLE, \ | ||||
|     CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \ | ||||
| @@ -240,6 +241,19 @@ def has_exactly_one_key(*keys): | ||||
|     return validate | ||||
|  | ||||
|  | ||||
| def has_at_most_one_key(*keys): | ||||
|     def validate(obj): | ||||
|         if not isinstance(obj, dict): | ||||
|             raise vol.Invalid('expected dictionary') | ||||
|  | ||||
|         number = sum(k in keys for k in obj) | ||||
|         if number > 1: | ||||
|             raise vol.Invalid("Cannot specify more than one of {}.".format(', '.join(keys))) | ||||
|         return obj | ||||
|  | ||||
|     return validate | ||||
|  | ||||
|  | ||||
| TIME_PERIOD_ERROR = "Time period {} should be format number + unit, for example 5ms, 5s, 5min, 5h" | ||||
|  | ||||
| time_period_dict = vol.All( | ||||
| @@ -598,6 +612,28 @@ def dimensions(value): | ||||
|     return dimensions([match.group(1), match.group(2)]) | ||||
|  | ||||
|  | ||||
| def directory(value): | ||||
|     value = string(value) | ||||
|     path = helpers.relative_path(value) | ||||
|     if not os.path.exists(path): | ||||
|         raise vol.Invalid(u"Could not find directory '{}'. Please make sure it exists.".format( | ||||
|             path)) | ||||
|     if not os.path.isdir(path): | ||||
|         raise vol.Invalid(u"Path '{}' is not a directory.".format(path)) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| def file_(value): | ||||
|     value = string(value) | ||||
|     path = helpers.relative_path(value) | ||||
|     if not os.path.exists(path): | ||||
|         raise vol.Invalid(u"Could not find file '{}'. Please make sure it exists.".format( | ||||
|             path)) | ||||
|     if not os.path.isfile(path): | ||||
|         raise vol.Invalid(u"Path '{}' is not a file.".format(path)) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| REGISTERED_IDS = set() | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,7 @@ MINOR_VERSION = 7 | ||||
| PATCH_VERSION = '0' | ||||
| __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) | ||||
| __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) | ||||
| ESPHOMELIB_VERSION = '1.7.0' | ||||
|  | ||||
| ESP_PLATFORM_ESP32 = 'ESP32' | ||||
| ESP_PLATFORM_ESP8266 = 'ESP8266' | ||||
| @@ -16,9 +17,14 @@ CONF_ESPHOMEYAML = 'esphomeyaml' | ||||
| CONF_NAME = 'name' | ||||
| CONF_PLATFORM = 'platform' | ||||
| CONF_BOARD = 'board' | ||||
| CONF_SIMPLIFY = 'simplify' | ||||
| CONF_USE_BUILD_FLAGS = 'use_build_flags' | ||||
| CONF_LIBRARY_URI = 'library_uri' | ||||
| CONF_ESPHOMELIB_VERSION = 'esphomelib_version' | ||||
| CONF_USE_CUSTOM_CODE = 'use_custom_code' | ||||
| CONF_ARDUINO_VERSION = 'arduino_version' | ||||
| CONF_LOCAL = 'local' | ||||
| CONF_REPOSITORY = 'repository' | ||||
| CONF_COMMIT = 'commit' | ||||
| CONF_TAG = 'tag' | ||||
| CONF_BRANCH = 'branch' | ||||
| CONF_LOGGER = 'logger' | ||||
| CONF_WIFI = 'wifi' | ||||
| CONF_SSID = 'ssid' | ||||
| @@ -323,27 +329,17 @@ CONF_COLD_WHITE = 'cold_white' | ||||
| CONF_WARM_WHITE = 'warm_white' | ||||
| CONF_COLD_WHITE_COLOR_TEMPERATURE = 'cold_white_color_temperature' | ||||
| CONF_WARM_WHITE_COLOR_TEMPERATURE = 'warm_white_color_temperature' | ||||
|  | ||||
| ESP32_BOARDS = [ | ||||
|     'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1', | ||||
|     'pocket_32', 'espectro32', 'esp32vn-iot-uno', 'esp320', 'esp-wrover-kit', | ||||
|     'esp32dev', 'heltec_wifi_kit32', 'heltec_wifi_lora_32', 'hornbill32dev', | ||||
|     'hornbill32minima', 'intorobot', 'm5stack-core-esp32', 'mhetesp32devkit', | ||||
|     'mhetesp32minikit', 'nano32', 'microduino-core-esp32', 'nodemcu-32s', | ||||
|     'quantum', 'esp32-evb', 'esp32-gateway', 'onehorse32dev', 'esp32thing', | ||||
|     'espino32', 'lolin32', 'wemosbat', 'widora-air', 'nina_w10', | ||||
| ] | ||||
|  | ||||
| ESP8266_BOARDS = [ | ||||
|     'gen4iod', 'huzzah', 'oak', 'espduino', 'espectro', 'espresso_lite_v1', | ||||
|     'espresso_lite_v2', 'espino', 'esp01', 'esp01_1m', 'esp07', 'esp12e', 'esp8285', | ||||
|     'esp_wroom_02', 'phoenix_v1', 'phoenix_v2', 'wifinfo', 'heltex_wifi_kit_8', | ||||
|     'nodemcu', 'nodemcuv2', 'modwifi', 'wio_node', 'sparkfunBlynk', 'thing', | ||||
|     'thingdev', 'esp210', 'espinotee', 'd1', 'd1_mini', 'd1_mini_lite', 'd1_mini_pro', | ||||
| ] | ||||
| ESP_BOARDS_FOR_PLATFORM = { | ||||
|     ESP_PLATFORM_ESP32: ESP32_BOARDS, | ||||
|     ESP_PLATFORM_ESP8266: ESP8266_BOARDS | ||||
| } | ||||
| CONF_ON_LOOP = 'on_loop' | ||||
| CONF_ON_TIME = 'on_time' | ||||
| CONF_SECONDS = 'seconds' | ||||
| CONF_MINUTES = 'minutes' | ||||
| CONF_HOURS = 'hours' | ||||
| CONF_DAYS_OF_MONTH = 'days_of_month' | ||||
| CONF_MONTHS = 'months' | ||||
| CONF_DAYS_OF_WEEK = 'days_of_week' | ||||
| CONF_CRON = 'cron' | ||||
|  | ||||
| ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_' | ||||
| ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage' | ||||
| ARDUINO_VERSION_ESP8266_DEV = 'https://github.com/platformio/platform-espressif8266.git#feature' \ | ||||
|                               '/stage' | ||||
|   | ||||
| @@ -239,7 +239,6 @@ class ID(object): | ||||
|  | ||||
|  | ||||
| CONFIG_PATH = None | ||||
| SIMPLIFY = True | ||||
| ESP_PLATFORM = '' | ||||
| BOARD = '' | ||||
| RAW_CONFIG = None | ||||
|   | ||||
							
								
								
									
										199
									
								
								esphomeyaml/core_config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								esphomeyaml/core_config.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| import os | ||||
| import re | ||||
|  | ||||
| import voluptuous as vol | ||||
|  | ||||
| import esphomeyaml.config_validation as cv | ||||
| from esphomeyaml import automation, core, pins | ||||
| from esphomeyaml.const import CONF_ARDUINO_VERSION, CONF_BOARD, CONF_BOARD_FLASH_MODE, \ | ||||
|     CONF_BRANCH, CONF_BUILD_PATH, CONF_COMMIT, CONF_ESPHOMELIB_VERSION, CONF_ESPHOMEYAML, \ | ||||
|     CONF_LOCAL, CONF_NAME, CONF_ON_BOOT, CONF_ON_LOOP, CONF_ON_SHUTDOWN, CONF_PLATFORM, \ | ||||
|     CONF_PRIORITY, CONF_REPOSITORY, CONF_TAG, CONF_TRIGGER_ID, CONF_USE_CUSTOM_CODE, \ | ||||
|     ESPHOMELIB_VERSION, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266, ARDUINO_VERSION_ESP8266_DEV, \ | ||||
|     ARDUINO_VERSION_ESP32_DEV | ||||
| from esphomeyaml.core import ESPHomeYAMLError | ||||
| from esphomeyaml.helpers import App, NoArg, Pvariable, add, const_char_p, esphomelib_ns, \ | ||||
|     relative_path | ||||
|  | ||||
| LIBRARY_URI_REPO = u'https://github.com/OttoWinter/esphomelib.git' | ||||
|  | ||||
| BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout'] | ||||
| StartupTrigger = esphomelib_ns.StartupTrigger | ||||
| ShutdownTrigger = esphomelib_ns.ShutdownTrigger | ||||
| LoopTrigger = esphomelib_ns.LoopTrigger | ||||
|  | ||||
| VERSION_REGEX = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+(?:-beta)?(?:-alpha)?$') | ||||
|  | ||||
|  | ||||
| def validate_board(value): | ||||
|     if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266: | ||||
|         board_pins = pins.ESP8266_BOARD_PINS | ||||
|     elif core.ESP_PLATFORM == ESP_PLATFORM_ESP32: | ||||
|         board_pins = pins.ESP32_BOARD_PINS | ||||
|     else: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     if value not in board_pins: | ||||
|         raise vol.Invalid(u"Could not find board '{}'. Valid boards are {}".format( | ||||
|             value, u', '.join(pins.ESP8266_BOARD_PINS.keys()))) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| def validate_simple_esphomelib_version(value): | ||||
|     value = cv.string_strict(value) | ||||
|     if value.upper() == 'LATEST': | ||||
|         return LIBRARY_URI_REPO + '#v{}'.format(ESPHOMELIB_VERSION) | ||||
|     elif value.upper() == 'DEV': | ||||
|         return LIBRARY_URI_REPO | ||||
|     elif VERSION_REGEX.match(value) is not None: | ||||
|         return LIBRARY_URI_REPO + '#v{}'.format(value) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| def validate_local_esphomelib_version(value): | ||||
|     value = cv.directory(value) | ||||
|     path = relative_path(value) | ||||
|     library_json = os.path.join(path, 'library.json') | ||||
|     if not os.path.exists(library_json): | ||||
|         raise vol.Invalid(u"Could not find '{}' file. '{}' does not seem to point to an " | ||||
|                           u"esphomelib copy.".format(library_json, value)) | ||||
|     return value | ||||
|  | ||||
|  | ||||
| def convert_esphomelib_version_schema(value): | ||||
|     if CONF_COMMIT in value: | ||||
|         return value[CONF_REPOSITORY] + '#' + value[CONF_COMMIT] | ||||
|     if CONF_BRANCH in value: | ||||
|         return value[CONF_REPOSITORY] + '#' + value[CONF_BRANCH] | ||||
|     return value[CONF_REPOSITORY] + '#' + value[CONF_TAG] | ||||
|  | ||||
|  | ||||
| ESPHOMELIB_VERSION_SCHEMA = vol.Any( | ||||
|     validate_simple_esphomelib_version, | ||||
|     vol.Schema({ | ||||
|         vol.Required(CONF_LOCAL): validate_local_esphomelib_version, | ||||
|     }), | ||||
|     vol.All( | ||||
|         vol.Schema({ | ||||
|             vol.Optional(CONF_REPOSITORY, default=LIBRARY_URI_REPO): cv.string, | ||||
|             vol.Optional(CONF_COMMIT, 'tag'): cv.string, | ||||
|             vol.Optional(CONF_BRANCH, 'tag'): cv.string, | ||||
|             vol.Optional(CONF_TAG, 'tag'): cv.string, | ||||
|         }), | ||||
|         cv.has_at_most_one_key(CONF_COMMIT, CONF_BRANCH, CONF_TAG), | ||||
|         convert_esphomelib_version_schema | ||||
|     ), | ||||
| ) | ||||
|  | ||||
|  | ||||
| def validate_platform(value): | ||||
|     value = cv.string(value) | ||||
|     if value.upper() in ('ESP8266', 'ESPRESSIF8266'): | ||||
|         return ESP_PLATFORM_ESP8266 | ||||
|     if value.upper() in ('ESP32', 'ESPRESSIF32'): | ||||
|         return ESP_PLATFORM_ESP32 | ||||
|     raise vol.Invalid(u"Invalid platform '{}'. Only options are ESP8266 and ESP32. Please note " | ||||
|                       u"the old way to use the latest arduino framework version has been split up " | ||||
|                       u"into the arduino_version configuration option.".format(value)) | ||||
|  | ||||
|  | ||||
| PLATFORMIO_ESP8266_LUT = { | ||||
|     '2.4.2': 'espressif8266@1.8.0', | ||||
|     '2.4.1': 'espressif8266@1.7.3', | ||||
|     '2.4.0': 'espressif8266@1.6.0', | ||||
|     '2.3.0': 'espressif8266@1.5.0', | ||||
|     'RECOMMENDED': 'espressif8266@>=1.8.0', | ||||
|     'LATEST': 'espressif8266', | ||||
|     'DEV': ARDUINO_VERSION_ESP8266_DEV, | ||||
| } | ||||
|  | ||||
| PLATFORMIO_ESP32_LUT = { | ||||
|     '1.0.0': 'espressif32@1.3.0', | ||||
|     'RECOMMENDED': 'espressif32@>=1.3.0', | ||||
|     'LATEST': 'espressif32', | ||||
|     'DEV': ARDUINO_VERSION_ESP32_DEV, | ||||
| } | ||||
|  | ||||
|  | ||||
| def validate_arduino_version(value): | ||||
|     value = cv.string_strict(value) | ||||
|     value_ = value.upper() | ||||
|     if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266: | ||||
|         if VERSION_REGEX.match(value) is not None and value_ not in PLATFORMIO_ESP8266_LUT: | ||||
|             raise vol.Invalid("Unfortunately the arduino framework version '{}' is unsupported " | ||||
|                               "at this time. You can override this by manually using " | ||||
|                               "espressif8266@<platformio version>") | ||||
|         if value_ in PLATFORMIO_ESP8266_LUT: | ||||
|             return PLATFORMIO_ESP8266_LUT[value_] | ||||
|         return value | ||||
|     elif core.ESP_PLATFORM == ESP_PLATFORM_ESP32: | ||||
|         if VERSION_REGEX.match(value) is not None and value_ not in PLATFORMIO_ESP32_LUT: | ||||
|             raise vol.Invalid("Unfortunately the arduino framework version '{}' is unsupported " | ||||
|                               "at this time. You can override this by manually using " | ||||
|                               "espressif32@<platformio version>") | ||||
|         if value_ in PLATFORMIO_ESP32_LUT: | ||||
|             return PLATFORMIO_ESP32_LUT[value_] | ||||
|         return value | ||||
|     else: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = vol.Schema({ | ||||
|     vol.Required(CONF_NAME): cv.valid_name, | ||||
|     vol.Required(CONF_PLATFORM): vol.All(vol.Upper, cv.one_of('ESP8266', 'ESPRESSIF8266', | ||||
|                                                               'ESP32', 'ESPRESSIF32')), | ||||
|     vol.Required(CONF_BOARD): validate_board, | ||||
|     vol.Optional(CONF_ESPHOMELIB_VERSION, default='latest'): ESPHOMELIB_VERSION_SCHEMA, | ||||
|     vol.Optional(CONF_ARDUINO_VERSION, default='recommended'): validate_arduino_version, | ||||
|     vol.Optional(CONF_USE_CUSTOM_CODE, default=False): cv.boolean, | ||||
|     vol.Optional(CONF_BUILD_PATH): cv.string, | ||||
|  | ||||
|     vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)), | ||||
|     vol.Optional(CONF_ON_BOOT): vol.All(cv.ensure_list, [automation.validate_automation({ | ||||
|         cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(StartupTrigger), | ||||
|         vol.Optional(CONF_PRIORITY): vol.Coerce(float), | ||||
|     })]), | ||||
|     vol.Optional(CONF_ON_SHUTDOWN): vol.All(cv.ensure_list, [automation.validate_automation({ | ||||
|         cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ShutdownTrigger), | ||||
|     })]), | ||||
|     vol.Optional(CONF_ON_LOOP): vol.All(cv.ensure_list, [automation.validate_automation({ | ||||
|         cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(LoopTrigger), | ||||
|     })]), | ||||
|  | ||||
|     vol.Optional('library_uri'): cv.invalid("The library_uri option has been removed in 1.8.0 and " | ||||
|                                             "was moved into the esphomelib_version option.") | ||||
| }) | ||||
|  | ||||
|  | ||||
| def preload_core_config(config): | ||||
|     if CONF_ESPHOMEYAML not in config: | ||||
|         raise ESPHomeYAMLError(u"No esphomeyaml section in config") | ||||
|     core_conf = config[CONF_ESPHOMEYAML] | ||||
|     if CONF_PLATFORM not in core_conf: | ||||
|         raise ESPHomeYAMLError("esphomeyaml.platform not specified.") | ||||
|     if CONF_BOARD not in core_conf: | ||||
|         raise ESPHomeYAMLError("esphomeyaml.board not specified.") | ||||
|  | ||||
|     try: | ||||
|         core.ESP_PLATFORM = validate_platform(core_conf[CONF_PLATFORM]) | ||||
|         core.BOARD = validate_board(core_conf[CONF_BOARD]) | ||||
|     except vol.Invalid as e: | ||||
|         raise ESPHomeYAMLError(unicode(e)) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
|     add(App.set_name(config[CONF_NAME])) | ||||
|  | ||||
|     for conf in config.get(CONF_ON_BOOT, []): | ||||
|         rhs = App.register_component(StartupTrigger.new(conf.get(CONF_PRIORITY))) | ||||
|         trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs) | ||||
|         automation.build_automation(trigger, NoArg, conf) | ||||
|  | ||||
|     for conf in config.get(CONF_ON_SHUTDOWN, []): | ||||
|         trigger = Pvariable(conf[CONF_TRIGGER_ID], ShutdownTrigger.new()) | ||||
|         automation.build_automation(trigger, const_char_p, conf) | ||||
|  | ||||
|     for conf in config.get(CONF_ON_LOOP, []): | ||||
|         rhs = App.register_component(LoopTrigger.new()) | ||||
|         trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs) | ||||
|         automation.build_automation(trigger, NoArg, conf) | ||||
| @@ -2,6 +2,7 @@ from __future__ import print_function | ||||
|  | ||||
| import inspect | ||||
| import logging | ||||
| import os | ||||
| import re | ||||
| from collections import OrderedDict, deque | ||||
|  | ||||
| @@ -85,8 +86,6 @@ class AssignmentExpression(Expression): | ||||
|  | ||||
|     def __str__(self): | ||||
|         type_ = self.type | ||||
|         if core.SIMPLIFY: | ||||
|             type_ = u'auto' | ||||
|         return u"{} {}{} = {}".format(type_, self.modifier, self.name, self.rhs) | ||||
|  | ||||
|     def has_side_effects(self): | ||||
| @@ -662,3 +661,7 @@ def color(the_color, message='', reset=None): | ||||
|     if not message: | ||||
|         return parse_colors(the_color) | ||||
|     return parse_colors(the_color) + message + escape_codes[reset or 'reset'] | ||||
|  | ||||
|  | ||||
| def relative_path(path): | ||||
|     return os.path.join(os.path.dirname(core.CONFIG_PATH), os.path.expanduser(path)) | ||||
|   | ||||
| @@ -10,59 +10,162 @@ from esphomeyaml.const import CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_PCF857 | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| ESP8266_PINS = { | ||||
|     'A0': 17, 'SS': 15, 'MOSI': 13, 'MISO': 12, 'SCK': 14, | ||||
| } | ||||
| ESP8266_NODEMCU_PINS = dict(ESP8266_PINS, **{ | ||||
|     'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, 'D7': 13, 'D8': 15, 'D9': 3, | ||||
|     'D10': 1, 'LED': 16, 'SDA': 4, 'SCL': 5, | ||||
| }) | ||||
| ESP8266_D1_PINS = dict(ESP8266_PINS, **{ | ||||
|     'D0': 3, 'D1': 1, 'D2': 16, 'D3': 5, 'D4': 4, 'D5': 14, 'D6': 12, 'D7': 13, 'D8': 0, 'D9': 2, | ||||
|     'D10': 15, 'D11': 13, 'D12': 14, 'D13': 14, 'D14': 4, 'D15': 5, 'LED': 2, 'SDA': 4, 'SCL': 5, | ||||
| }) | ||||
| ESP8266_D1_MINI_PINS = dict(ESP8266_PINS, **{ | ||||
|     'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, 'D7': 13, 'D8': 15, 'RX': 3, | ||||
|     'TX': 1, 'LED': 2, 'SDA': 4, 'SCL': 5, | ||||
| }) | ||||
| ESP8266_THING_PINS = dict(ESP8266_PINS, **{ | ||||
|     'LED': 5, 'SDA': 2, 'SCL': 14, | ||||
| }) | ||||
| ESP8266_ADAFRUIT_PINS = dict(ESP8266_PINS, **{ | ||||
|     'LED': 0, 'SDA': 4, 'SCL': 5, | ||||
| }) | ||||
| ESP8266_ESPDUINO_PINS = dict(ESP8266_PINS, **{ | ||||
|     'LED': 16, 'SDA': 4, 'SCL': 5, | ||||
| }) | ||||
| ESP8266_BOARD_TO_PINS = { | ||||
|     'huzzah': ESP8266_ADAFRUIT_PINS, | ||||
|     'espduino': ESP8266_ESPDUINO_PINS, | ||||
|     'nodemcu': ESP8266_NODEMCU_PINS, 'nodemcuv2': ESP8266_NODEMCU_PINS, | ||||
|     'thing': ESP8266_THING_PINS, 'thingdev': ESP8266_THING_PINS, | ||||
|     'd1': ESP8266_D1_PINS, | ||||
|     'd1_mini': ESP8266_D1_MINI_PINS, 'd1_mini_lite': ESP8266_D1_MINI_PINS, | ||||
|     'd1_mini_pro': ESP8266_D1_MINI_PINS | ||||
| ESP8266_BASE_PINS = { | ||||
|     'A0': 17, 'SS': 15, 'MOSI': 13, 'MISO': 12, 'SCK': 14, 'SDA': 4, 'SCL': 5, 'RX': 3, 'TX': 1 | ||||
| } | ||||
|  | ||||
| ESP32_PINS = { | ||||
| ESP8266_BOARD_PINS = { | ||||
|     'd1': {'D0': 3, 'D1': 1, 'D2': 16, 'D3': 5, 'D4': 4, 'D5': 14, 'D6': 12, 'D7': 13, 'D8': 0, | ||||
|            'D9': 2, 'D10': 15, 'D11': 13, 'D12': 14, 'D13': 14, 'D14': 4, 'D15': 5, 'LED': 2}, | ||||
|     'd1_mini': {'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, 'D7': 13, | ||||
|                 'D8': 15, 'LED': 2}, | ||||
|     'd1_mini_lite': 'd1_mini', | ||||
|     'd1_mini_pro': 'd1_mini', | ||||
|     'esp01': {}, | ||||
|     'esp01_1m': {}, | ||||
|     'esp07': {}, | ||||
|     'esp12e': {}, | ||||
|     'esp210': {}, | ||||
|     'esp8285': {}, | ||||
|     'esp_wroom_02': {}, | ||||
|     'espduino': {'LED': 16}, | ||||
|     'espectro': {'LED': 15, 'BUTTON': 2}, | ||||
|     'espino': {'LED': 2, 'LED_RED': 2, 'LED_GREEN': 4, 'LED_BLUE': 5, 'BUTTON': 0}, | ||||
|     'espinotee': {'LED': 16}, | ||||
|     'espresso_lite_v1': {'LED': 16}, | ||||
|     'espresso_lite_v2': {'LED': 2}, | ||||
|     'gen4iod': {}, | ||||
|     'heltec_wifi_kit_8': 'd1_mini', | ||||
|     'huzzah': {'LED': 0}, | ||||
|     'modwifi': {}, | ||||
|     'nodemcu': {'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, 'D7': 13, | ||||
|                 'D8': 15, 'D9': 3, 'D10': 1, 'LED': 16}, | ||||
|     'nodemcuv2': 'nodemcu', | ||||
|     'oak': {'P0': 2, 'P1': 5, 'P2': 0, 'P3': 3, 'P4': 1, 'P5': 4, 'P6': 15, 'P7': 13, 'P8': 12, | ||||
|             'P9': 14, 'P10': 16, 'P11': 17, 'LED': 5}, | ||||
|     'phoenix_v1': {'LED': 16}, | ||||
|     'phoenix_v2': {'LED': 2}, | ||||
|     'sparkfunBlynk': 'thing', | ||||
|     'thing': {'LED': 5, 'SDA': 2, 'SCL': 14}, | ||||
|     'thingdev': 'thing', | ||||
|     'wifi_slot': {'LED': 2}, | ||||
|     'wifiduino': {'D0': 3, 'D1': 1, 'D2': 2, 'D3': 0, 'D4': 4, 'D5': 5, 'D6': 16, 'D7': 14, | ||||
|                   'D8': 12, 'D9': 13, 'D10': 15, 'D11': 13, 'D12': 12, 'D13': 14}, | ||||
|     'wifinfo': {'LED': 12, 'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, | ||||
|                 'D7': 13, 'D8': 15, 'D9': 3, 'D10': 1}, | ||||
|     'wio_link': {'LED': 2, 'GROVE': 15}, | ||||
|     'wio_node': 'nodemcu', | ||||
|     'xinabox_cw01': {'SDA': 2, 'SCL': 14, 'LED': 5, 'LED_RED': 12, 'LED_GREEN': 13} | ||||
| } | ||||
|  | ||||
| ESP32_BASE_PINS = { | ||||
|     'TX': 1, 'RX': 3, 'SDA': 21, 'SCL': 22, 'SS': 5, 'MOSI': 23, 'MISO': 19, 'SCK': 18, 'A0': 36, | ||||
|     'A3': 39, 'A4': 32, 'A5': 33, 'A6': 34, 'A7': 35, 'A10': 4, 'A11': 0, 'A12': 2, 'A13': 15, | ||||
|     'A14': 13, 'A15': 12, 'A16': 14, 'A17': 27, 'A18': 25, 'A19': 26, 'T0': 4, 'T1': 0, 'T2': 2, | ||||
|     'T3': 15, 'T4': 12, 'T5': 12, 'T6': 14, 'T7': 27, 'T8': 33, 'T9': 32, 'DAC1': 25, 'DAC2': 26, | ||||
|     'T3': 15, 'T4': 13, 'T5': 12, 'T6': 14, 'T7': 27, 'T8': 33, 'T9': 32, 'DAC1': 25, 'DAC2': 26, | ||||
|     'SVP': 36, 'SVN': 39, | ||||
| } | ||||
| ESP32_NODEMCU_32S_PINS = dict(ESP32_PINS, **{ | ||||
|     'LED': 2, | ||||
| }) | ||||
| ESP32_LOLIN32_PINS = dict(ESP32_PINS, **{ | ||||
|     'LED': 5 | ||||
| }) | ||||
| ESP32_BOARD_TO_PINS = { | ||||
|     'nodemcu-32s': ESP32_NODEMCU_32S_PINS, | ||||
|     'lolin32': ESP32_LOLIN32_PINS, | ||||
|  | ||||
| ESP32_BOARD_PINS = { | ||||
|     'alksesp32': {'D0': 40, 'D1': 41, 'D2': 15, 'D3': 2, 'D4': 0, 'D5': 4, 'D6': 16, 'D7': 17, | ||||
|                   'D8': 5, 'D9': 18, 'D10': 19, 'D11': 21, 'D12': 22, 'D13': 23, 'A0': 32, 'A1': 33, | ||||
|                   'A2': 25, 'A3': 26, 'A4': 27, 'A5': 14, 'A6': 12, 'A7': 15, 'L_R': 22, 'L_G': 17, | ||||
|                   'L_Y': 23, 'L_B': 5, 'L_RGB_R': 4, 'L_RGB_G': 21, 'L_RGB_B': 16, 'SW1': 15, | ||||
|                   'SW2': 2, 'SW3': 0, 'POT1': 32, 'POT2': 33, 'PIEZO1': 19, 'PIEZO2': 18, | ||||
|                   'PHOTO': 25, 'DHT_PIN': 26, 'S1': 4, 'S2': 16, 'S3': 18, 'S4': 19, 'S5': 21, | ||||
|                   'SDA': 27, 'SCL': 14, 'SS': 19, 'MOSI': 21, 'MISO': 22, 'SCK': 23}, | ||||
|     'esp-wrover-kit': {}, | ||||
|     'esp32-evb': {'BUTTON': 34, 'SDA': 13, 'SCL': 16, 'SS': 17, 'MOSI': 2, 'MISO': 15, 'SCK': 14}, | ||||
|     'esp32-gateway': {'LED': 33, 'BUTTON': 34, 'SCL': 16, 'SDA': 17}, | ||||
|     'esp320': {'LED': 5, 'SDA': 2, 'SCL': 14, 'SS': 15, 'MOSI': 13, 'MISO': 12, 'SCK': 14}, | ||||
|     'esp32dev': {}, | ||||
|     'esp32doit-devkit-v1': {'LED': 2}, | ||||
|     'esp32thing': {'LED': 5, 'BUTTON': 0, 'SS': 2}, | ||||
|     'esp32vn-iot-uno': {}, | ||||
|     'espea32': {'LED': 5, 'BUTTON': 0}, | ||||
|     'espectro32': {'LED': 15, 'SD_SS': 33}, | ||||
|     'espino32': {'LED': 16, 'BUTTON': 0}, | ||||
|     'featheresp32': {'LED': 13, 'TX': 17, 'RX': 16, 'SDA': 23, 'SS': 2, 'MOSI': 18, 'SCK': 5, | ||||
|                      'A0': 26, 'A1': 25, 'A2': 34, 'A4': 36, 'A5': 4, 'A6': 14, 'A7': 32, 'A8': 15, | ||||
|                      'A9': 33, 'A10': 27, 'A11': 12, 'A12': 13, 'A13': 35}, | ||||
|     'firebeetle32': {'LED': 2}, | ||||
|     'heltec_wifi_kit_32': {'LED': 25, 'BUTTON': 0, 'A1': 37, 'A2': 38}, | ||||
|     'heltec_wifi_lora_32': {'LED': 25, 'BUTTON': 0, 'SDA': 4, 'SCL': 15, 'SS': 18, 'MOSI': 27, | ||||
|                             'SCK': 5, 'A1': 37, 'A2': 38, 'T8': 32, 'T9': 33, 'DAC1': 26, | ||||
|                             'DAC2': 25, 'OLED_SCL': 15, 'OLED_SDA': 4, 'OLED_RST': 16, | ||||
|                             'LORA_SCK': 5, 'LORA_MOSI': 27, 'LORA_MISO': 19, 'LORA_CS': 18, | ||||
|                             'LORA_RST': 14, 'LORA_IRQ': 26}, | ||||
|     'hornbill32dev': {'LED': 13, 'BUTTON': 0}, | ||||
|     'hornbill32minima': {'SS': 2}, | ||||
|     'intorobot': {'LED': 4, 'LED_RED': 27, 'LED_GREEN': 21, 'LED_BLUE': 22, | ||||
|                   'BUTTON': 0, 'SDA': 23, 'SCL': 19, 'MOSI': 16, 'MISO': 17, 'A1': 39, 'A2': 35, | ||||
|                   'A3': 25, 'A4': 26, 'A5': 14, 'A6': 12, 'A7': 15, 'A8': 13, 'A9': 2, 'D0': 19, | ||||
|                   'D1': 23, 'D2': 18, 'D3': 17, 'D4': 16, 'D5': 5, 'D6': 4, 'T0': 19, 'T1': 23, | ||||
|                   'T2': 18, 'T3': 17, 'T4': 16, 'T5': 5, 'T6': 4}, | ||||
|     'lolin32': {'LED': 5}, | ||||
|     'lolin_d32': {'LED': 5, 'VBAT': 35}, | ||||
|     'lolin_d32_pro': {'LED': 5, 'VBAT': 35, 'TF_CS': 4, 'TS_CS': 12, 'TFT_CS': 14, 'TFT_LED': 32, | ||||
|                       'TFT_RST': 33, 'TFT_DC': 27}, | ||||
|     'm5stack-core-esp32': {'TXD2': 17, 'RXD2': 16, 'G23': 23, 'G19': 19, 'G18': 18, 'G3': 3, | ||||
|                            'G16': 16, 'G21': 21, 'G2': 2, 'G12': 12, 'G15': 15, 'G35': 35, | ||||
|                            'G36': 36, 'G25': 25, 'G26': 26, 'G1': 1, 'G17': 17, 'G22': 22, 'G5': 5, | ||||
|                            'G13': 13, 'G0': 0, 'G34': 34, 'ADC1': 35, 'ADC2': 36}, | ||||
|     'm5stack-fire': {'G23': 23, 'G19': 19, 'G18': 18, 'G3': 3, 'G16': 16, 'G21': 21, 'G2': 2, | ||||
|                      'G12': 12, 'G15': 15, 'G35': 35, 'G36': 36, 'G25': 25, 'G26': 26, 'G1': 1, | ||||
|                      'G17': 17, 'G22': 22, 'G5': 5, 'G13': 13, 'G0': 0, 'G34': 34, 'ADC1': 35, | ||||
|                      'ADC2': 36}, | ||||
|     'mhetesp32devkit': {'LED': 2}, | ||||
|     'mhetesp32minikit': {'LED': 2}, | ||||
|     'microduino-core-esp32': {'SDA': 22, 'SCL': 21, 'SDA1': 12, 'SCL1': 13, 'A0': 12, 'A1': 13, | ||||
|                               'A2': 15, 'A3': 4, 'A6': 38, 'A7': 37, 'A8': 32, 'A9': 33, 'A10': 25, | ||||
|                               'A11': 26, 'A12': 27, 'A13': 14, 'D0': 3, 'D1': 1, 'D2': 16, 'D3': 17, | ||||
|                               'D4': 32, 'D5': 33, 'D6': 25, 'D7': 26, 'D8': 27, 'D9': 14, 'D10': 5, | ||||
|                               'D11': 23, 'D12': 19, 'D13': 18, 'D14': 12, 'D15': 13, 'D16': 15, | ||||
|                               'D17': 4, 'D18': 22, 'D19': 21, 'D20': 38, 'D21': 37}, | ||||
|     'nano32': {'LED': 16, 'BUTTON': 0}, | ||||
|     'nina_w10': {'LED_GREEN': 33, 'LED_RED': 23, 'LED_BLUE': 21, 'SW1': 33, 'SW2': 27, 'SDA': 12, | ||||
|                  'SCL': 13, 'D0': 3, 'D1': 1, 'D2': 26, 'D3': 25, 'D4': 35, 'D5': 27, 'D6': 22, | ||||
|                  'D7': 0, 'D8': 15, 'D9': 14, 'D10': 5, 'D11': 19, 'D12': 23, 'D13': 18, 'D14': 13, | ||||
|                  'D15': 12, 'D16': 32, 'D17': 33, 'D18': 21, 'D19': 34, 'D20': 36, 'D21': 39}, | ||||
|     'node32s': {}, | ||||
|     'nodemcu-32s': {'LED': 2, 'BUTTON': 0}, | ||||
|     'odroid_esp32': {'LED': 2, 'SDA': 15, 'SCL': 4, 'SS': 22, 'ADC1': 35, 'ADC2': 36}, | ||||
|     'onehorse32dev': {'LED': 5, 'BUTTON': 0, 'A1': 37, 'A2': 38}, | ||||
|     'pico32': {}, | ||||
|     'pocket_32': {'LED': 16}, | ||||
|     'quantum': {}, | ||||
|     'ttgo-lora32-v1': {'LED': 2, 'BUTTON': 0, 'SS': 18, 'MOSI': 27, 'SCK': 5, 'A1': 37, 'A2': 38, | ||||
|                        'T8': 32, 'T9': 33, 'DAC1': 26, 'DAC2': 25, 'OLED_SDA': 4, 'OLED_SCL': 15, | ||||
|                        'OLED_RST': 16, 'LORA_SCK': 5, 'LORA_MISO': 19, 'LORA_MOSI': 27, | ||||
|                        'LORA_CS': 18, 'LORA_RST': 14, 'LORA_IRQ': 26}, | ||||
|     'wemosbat': 'pocket_32', | ||||
|     'widora-air': {'LED': 25, 'BUTTON': 0, 'SDA': 23, 'SCL': 19, 'MOSI': 16, 'MISO': 17, 'A1': 39, | ||||
|                    'A2': 35, 'A3': 25, 'A4': 26, 'A5': 14, 'A6': 12, 'A7': 15, 'A8': 13, 'A9': 2, | ||||
|                    'D0': 19, 'D1': 23, 'D2': 18, 'D3': 17, 'D4': 16, 'D5': 5, 'D6': 4, 'T0': 19, | ||||
|                    'T1': 23, 'T2': 18, 'T3': 17, 'T4': 16, 'T5': 5, 'T6': 4}, | ||||
|     'xinabox_cw02': {'LED': 27}, | ||||
| } | ||||
|  | ||||
|  | ||||
| def _lookup_pin(platform, board, value): | ||||
|     if platform == ESP_PLATFORM_ESP8266: | ||||
|         board_pins = ESP8266_BOARD_PINS.get(board, {}) | ||||
|         base_pins = ESP8266_BASE_PINS | ||||
|     elif platform == ESP_PLATFORM_ESP32: | ||||
|         board_pins = ESP32_BOARD_PINS.get(board, {}) | ||||
|         base_pins = ESP32_BASE_PINS | ||||
|     else: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     if isinstance(board_pins, str): | ||||
|         return _lookup_pin(platform, board_pins, value) | ||||
|     if value in board_pins: | ||||
|         return board_pins[value] | ||||
|     if value in base_pins: | ||||
|         return base_pins[value] | ||||
|     raise vol.Invalid(u"Can't find internal pin number for {}.".format(value)) | ||||
|  | ||||
|  | ||||
| def _translate_pin(value): | ||||
|     if isinstance(value, dict) or value is None: | ||||
|         raise vol.Invalid(u"This variable only supports pin numbers, not full pin schemas " | ||||
| @@ -75,27 +178,7 @@ def _translate_pin(value): | ||||
|         pass | ||||
|     if value.startswith('GPIO'): | ||||
|         return vol.Coerce(int)(value[len('GPIO'):].strip()) | ||||
|     if core.ESP_PLATFORM == ESP_PLATFORM_ESP32: | ||||
|         if value in ESP32_PINS: | ||||
|             return ESP32_PINS[value] | ||||
|         if core.BOARD not in ESP32_BOARD_TO_PINS: | ||||
|             raise vol.Invalid(u"ESP32: Unknown board {} with unknown " | ||||
|                               u"pin {}.".format(core.BOARD, value)) | ||||
|         if value not in ESP32_BOARD_TO_PINS[core.BOARD]: | ||||
|             raise vol.Invalid(u"ESP32: Board {} doesn't have " | ||||
|                               u"pin {}".format(core.BOARD, value)) | ||||
|         return ESP32_BOARD_TO_PINS[core.BOARD][value] | ||||
|     elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266: | ||||
|         if value in ESP8266_PINS: | ||||
|             return ESP8266_PINS[value] | ||||
|         if core.BOARD not in ESP8266_BOARD_TO_PINS: | ||||
|             raise vol.Invalid(u"ESP8266: Unknown board {} with unknown " | ||||
|                               u"pin {}.".format(core.BOARD, value)) | ||||
|         if value not in ESP8266_BOARD_TO_PINS[core.BOARD]: | ||||
|             raise vol.Invalid(u"ESP8266: Board {} doesn't have " | ||||
|                               u"pin {}".format(core.BOARD, value)) | ||||
|         return ESP8266_BOARD_TO_PINS[core.BOARD][value] | ||||
|     raise vol.Invalid(u"Invalid ESP platform.") | ||||
|     return _lookup_pin(core.ESP_PLATFORM, core.BOARD, value) | ||||
|  | ||||
|  | ||||
| def validate_gpio_pin(value): | ||||
|   | ||||
| @@ -8,12 +8,13 @@ import voluptuous as vol | ||||
|  | ||||
| import esphomeyaml.config_validation as cv | ||||
| from esphomeyaml.components import mqtt | ||||
| from esphomeyaml.const import ESP_BOARDS_FOR_PLATFORM, ESP_PLATFORMS, ESP_PLATFORM_ESP32, \ | ||||
|     ESP_PLATFORM_ESP8266 | ||||
| from esphomeyaml.const import ESP_PLATFORMS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 | ||||
| from esphomeyaml.helpers import color | ||||
|  | ||||
|  | ||||
| # pylint: disable=anomalous-backslash-in-string | ||||
| from esphomeyaml.pins import ESP32_BOARD_PINS, ESP8266_BOARD_PINS | ||||
|  | ||||
| CORE_BIG = """    _____ ____  _____  ______ | ||||
|    / ____/ __ \|  __ \|  ____| | ||||
|   | |   | |  | | |__) | |__ | ||||
| @@ -187,11 +188,12 @@ def wizard(path): | ||||
|     # Don't sleep because user needs to copy link | ||||
|     if platform == ESP_PLATFORM_ESP32: | ||||
|         print("For example \"{}\".".format(color("bold_white", 'nodemcu-32s'))) | ||||
|         boards = list(ESP32_BOARD_PINS.keys()) | ||||
|     else: | ||||
|         print("For example \"{}\".".format(color("bold_white", 'nodemcuv2'))) | ||||
|         boards = list(ESP8266_BOARD_PINS.keys()) | ||||
|     while True: | ||||
|         board = raw_input(color("bold_white", "(board): ")) | ||||
|         boards = ESP_BOARDS_FOR_PLATFORM[platform] | ||||
|         try: | ||||
|             board = vol.All(vol.Lower, vol.Any(*boards))(board) | ||||
|             break | ||||
|   | ||||
| @@ -2,14 +2,17 @@ from __future__ import print_function | ||||
|  | ||||
| import codecs | ||||
| import errno | ||||
| import json | ||||
| import os | ||||
|  | ||||
| from esphomeyaml import core | ||||
| from esphomeyaml.config import iter_components | ||||
| 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 | ||||
| from esphomeyaml.const import CONF_ARDUINO_VERSION, CONF_BOARD, CONF_BOARD_FLASH_MODE, \ | ||||
|     CONF_ESPHOMELIB_VERSION, CONF_ESPHOMEYAML, CONF_LOCAL, CONF_NAME, CONF_USE_CUSTOM_CODE, \ | ||||
|     ESP_PLATFORM_ESP32, ARDUINO_VERSION_ESP32_DEV | ||||
| from esphomeyaml.core import ESPHomeYAMLError | ||||
| from esphomeyaml.core_config import VERSION_REGEX | ||||
| from esphomeyaml.helpers import relative_path | ||||
|  | ||||
| CPP_AUTO_GENERATE_BEGIN = u'// ========== AUTO GENERATED CODE BEGIN ===========' | ||||
| CPP_AUTO_GENERATE_END = u'// =========== AUTO GENERATED CODE END ============' | ||||
| @@ -59,11 +62,6 @@ build_flags = | ||||
|     ${{common.build_flags}} | ||||
| """ | ||||
|  | ||||
| PLATFORM_TO_PLATFORMIO = { | ||||
|     ESP_PLATFORM_ESP32: 'espressif32', | ||||
|     ESP_PLATFORM_ESP8266: 'espressif8266' | ||||
| } | ||||
|  | ||||
|  | ||||
| def get_build_flags(config, key): | ||||
|     build_flags = set() | ||||
| @@ -81,19 +79,16 @@ def get_build_flags(config, key): | ||||
|     return build_flags | ||||
|  | ||||
|  | ||||
| def get_ini_content(config): | ||||
| def get_ini_content(config, path): | ||||
|     version_specific_settings = determine_platformio_version_settings() | ||||
|     platform = config[CONF_ESPHOMEYAML][CONF_PLATFORM] | ||||
|     if platform in PLATFORM_TO_PLATFORMIO: | ||||
|         platform = PLATFORM_TO_PLATFORMIO[platform] | ||||
|     options = { | ||||
|         u'env': config[CONF_ESPHOMEYAML][CONF_NAME], | ||||
|         u'platform': platform, | ||||
|         u'platform': config[CONF_ESPHOMEYAML][CONF_ARDUINO_VERSION], | ||||
|         u'board': config[CONF_ESPHOMEYAML][CONF_BOARD], | ||||
|         u'build_flags': u'', | ||||
|     } | ||||
|     build_flags = set() | ||||
|     if config[CONF_ESPHOMEYAML][CONF_USE_BUILD_FLAGS]: | ||||
|     if not config[CONF_ESPHOMEYAML][CONF_USE_CUSTOM_CODE]: | ||||
|         build_flags |= get_build_flags(config, 'build_flags') | ||||
|         build_flags |= get_build_flags(config, 'BUILD_FLAGS') | ||||
|         build_flags.add(u"-DESPHOMEYAML_USE") | ||||
| @@ -106,13 +101,48 @@ def get_ini_content(config): | ||||
|         options[u'build_flags'] = u'\n    '.join(build_flags) | ||||
|  | ||||
|     lib_deps = set() | ||||
|     lib_deps.add(config[CONF_ESPHOMEYAML][CONF_LIBRARY_URI]) | ||||
|  | ||||
|     lib_version = config[CONF_ESPHOMEYAML][CONF_ESPHOMELIB_VERSION] | ||||
|     lib_path = os.path.join(path, 'lib') | ||||
|     dst_path = os.path.join(lib_path, 'esphomelib') | ||||
|     if isinstance(lib_version, (str, unicode)): | ||||
|         lib_deps.add(lib_version) | ||||
|         if os.path.islink(dst_path): | ||||
|             os.unlink(dst_path) | ||||
|     else: | ||||
|         src_path = relative_path(lib_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) | ||||
|             os.symlink(src_path, dst_path) | ||||
|  | ||||
|         # Manually add lib_deps because platformio seems to ignore them inside libs/ | ||||
|         library_json_path = os.path.join(src_path, 'library.json') | ||||
|         with codecs.open(library_json_path, 'r', encoding='utf-8') as f_handle: | ||||
|             library_json_text = f_handle.read() | ||||
|  | ||||
|         library_json = json.loads(library_json_text) | ||||
|         for dep in library_json.get('dependencies', []): | ||||
|             if 'version' in dep and VERSION_REGEX.match(dep['version']) is not None: | ||||
|                 lib_deps.add(dep['name'] + '@' + dep['version']) | ||||
|             else: | ||||
|                 lib_deps.add(dep['version']) | ||||
|  | ||||
|     lib_deps |= get_build_flags(config, 'LIB_DEPS') | ||||
|     lib_deps |= get_build_flags(config, 'lib_deps') | ||||
|     if core.ESP_PLATFORM == ESP_PLATFORM_ESP32: | ||||
|         lib_deps |= { | ||||
|             'Preferences',  # Preferences helper | ||||
|         } | ||||
|         # Manual fix for AsyncTCP | ||||
|         if config[CONF_ESPHOMEYAML].get(CONF_ARDUINO_VERSION) == ARDUINO_VERSION_ESP32_DEV: | ||||
|             lib_deps.add('https://github.com/me-no-dev/AsyncTCP.git#idf-update') | ||||
|     # avoid changing build flags order | ||||
|     lib_deps = sorted(x for x in lib_deps if x) | ||||
|     if lib_deps: | ||||
| @@ -178,7 +208,7 @@ def write_platformio_ini(content, path): | ||||
|  | ||||
| def write_platformio_project(config, path): | ||||
|     platformio_ini = os.path.join(path, 'platformio.ini') | ||||
|     content = get_ini_content(config) | ||||
|     content = get_ini_content(config, path) | ||||
|     if 'esp32_ble_beacon' in config or 'esp32_ble_tracker' in config: | ||||
|         content += 'board_build.partitions = partitions.csv\n' | ||||
|         partitions_csv = os.path.join(path, 'partitions.csv') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user