From 2d8321c9a9740eadf9868f76f4beaeaf0f0c2f60 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Wed, 21 Nov 2018 20:48:19 +0100 Subject: [PATCH] Ethernet --- esphomeyaml/__main__.py | 2 +- esphomeyaml/components/ethernet.py | 70 ++++++++++++++++ esphomeyaml/config.py | 126 ++++++++++++++++------------- esphomeyaml/pins.py | 3 + 4 files changed, 145 insertions(+), 56 deletions(-) create mode 100644 esphomeyaml/components/ethernet.py diff --git a/esphomeyaml/__main__.py b/esphomeyaml/__main__.py index 185d930b45..2d986aa5a4 100644 --- a/esphomeyaml/__main__.py +++ b/esphomeyaml/__main__.py @@ -20,7 +20,7 @@ from esphomeyaml.util import run_external_command, safe_print _LOGGER = logging.getLogger(__name__) -PRE_INITIALIZE = ['esphomeyaml', 'logger', 'wifi', 'ota', 'mqtt', 'web_server', 'i2c'] +PRE_INITIALIZE = ['esphomeyaml', 'logger', 'wifi', 'ethernet', 'ota', 'mqtt', 'web_server', 'i2c'] def get_serial_ports(): diff --git a/esphomeyaml/components/ethernet.py b/esphomeyaml/components/ethernet.py new file mode 100644 index 0000000000..52481fd174 --- /dev/null +++ b/esphomeyaml/components/ethernet.py @@ -0,0 +1,70 @@ +import voluptuous as vol + +from esphomeyaml import pins +from esphomeyaml.components import wifi +import esphomeyaml.config_validation as cv +from esphomeyaml.const import CONF_DOMAIN, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_TYPE, \ + ESP_PLATFORM_ESP32 +from esphomeyaml.cpp_generator import Pvariable, add +from esphomeyaml.cpp_helpers import gpio_output_pin_expression +from esphomeyaml.cpp_types import App, Component, esphomelib_ns, global_ns + +CONFLICTS_WITH = ['wifi'] +ESP_PLATFORMS = [ESP_PLATFORM_ESP32] + +CONF_PHY_ADDR = 'phy_addr' +CONF_MDC_PIN = 'mdc_pin' +CONF_MDIO_PIN = 'mdio_pin' +CONF_CLK_MODE = 'clk_mode' +CONF_POWER_PIN = 'power_pin' + +EthernetType = esphomelib_ns.enum('EthernetType') +ETHERNET_TYPES = { + 'LAN8720': EthernetType.ETHERNET_TYPE_LAN8720, + 'TLK110': EthernetType.ETHERNET_TYPE_TLK110, +} + +eth_clock_mode_t = global_ns.enum('eth_clock_mode_t') +CLK_MODES = { + 'GPIO0_IN': eth_clock_mode_t.ETH_CLOCK_GPIO0_IN, + 'GPIO0_OUT': eth_clock_mode_t.ETH_CLOCK_GPIO0_OUT, + 'GPIO16_OUT': eth_clock_mode_t.ETH_CLOCK_GPIO16_OUT, + 'GPIO17_OUT': eth_clock_mode_t.ETH_CLOCK_GPIO17_OUT, +} + +EthernetComponent = esphomelib_ns.class_('EthernetComponent', Component) + +CONFIG_SCHEMA = vol.Schema({ + cv.GenerateID(): cv.declare_variable_id(EthernetComponent), + vol.Required(CONF_TYPE): cv.one_of(*ETHERNET_TYPES, upper=True), + vol.Required(CONF_MDC_PIN): pins.output_pin, + vol.Required(CONF_MDIO_PIN): pins.input_output_pin, + vol.Optional(CONF_CLK_MODE, default='GPIO0_IN'): cv.one_of(*CLK_MODES, upper=True), + vol.Optional(CONF_PHY_ADDR, default=0): vol.All(cv.int_, vol.Range(min=0, max=31)), + vol.Optional(CONF_POWER_PIN): pins.gpio_output_pin_schema, + vol.Optional(CONF_MANUAL_IP): wifi.STA_MANUAL_IP_SCHEMA, + vol.Optional(CONF_HOSTNAME): cv.hostname, + vol.Optional(CONF_DOMAIN, default='.local'): cv.domain_name, +}) + + +def to_code(config): + rhs = App.init_ethernet() + eth = Pvariable(config[CONF_ID], rhs) + + add(eth.set_phy_addr(config[CONF_PHY_ADDR])) + add(eth.set_mdc_pin(config[CONF_MDC_PIN])) + add(eth.set_mdio_pin(config[CONF_MDIO_PIN])) + add(eth.set_type(ETHERNET_TYPES[config[CONF_TYPE]])) + add(eth.set_clk_mode(CLK_MODES[config[CONF_CLK_MODE]])) + + if CONF_POWER_PIN in config: + for pin in gpio_output_pin_expression(config[CONF_POWER_PIN]): + yield + add(eth.set_power_pin(pin)) + + if CONF_HOSTNAME in config: + add(eth.set_hostname(config[CONF_HOSTNAME])) + + if CONF_MANUAL_IP in config: + add(eth.set_manual_ip(wifi.manual_ip(config[CONF_MANUAL_IP]))) diff --git a/esphomeyaml/config.py b/esphomeyaml/config.py index 9c47603c52..b1817b2053 100644 --- a/esphomeyaml/config.py +++ b/esphomeyaml/config.py @@ -15,11 +15,7 @@ from esphomeyaml.util import safe_print _LOGGER = logging.getLogger(__name__) -REQUIRED_COMPONENTS = [ - CONF_ESPHOMEYAML, CONF_WIFI -] _COMPONENT_CACHE = {} -_ALL_COMPONENTS = [] def get_component(domain): @@ -137,29 +133,55 @@ def do_id_pass(result): def validate_config(config): - global _ALL_COMPONENTS - - for req in REQUIRED_COMPONENTS: - if req not in config: - raise EsphomeyamlError("Component {} is required for esphomeyaml.".format(req)) - - _ALL_COMPONENTS = list(config.keys()) - result = Config() def _comp_error(ex, domain, config): result.add_error(_format_config_error(ex, domain, config), domain, config) + skip_domains = set() + # Step 1: Load everything for domain, conf in config.iteritems(): domain = str(domain) if domain == CONF_ESPHOMEYAML or domain.startswith('.'): + skip_domains.add(domain) continue if conf is None: conf = {} component = get_component(domain) if component is None: result.add_error(u"Component not found: {}".format(domain), domain, conf) + skip_domains.add(domain) + continue + + success = True + dependencies = getattr(component, 'DEPENDENCIES', []) + for dependency in dependencies: + if dependency not in config: + result.add_error(u"Component {} requires component {}".format(domain, dependency), + domain, conf) + success = False + if not success: + skip_domains.add(domain) + continue + + success = True + conflicts_with = getattr(component, 'CONFLICTS_WITH', []) + for conflict in conflicts_with: + if conflict not in config: + result.add_error(u"Component {} cannot be used together with component {}" + u"".format(domain, conflict), + domain, conf) + success = False + if not success: + skip_domains.add(domain) + continue + + esp_platforms = getattr(component, 'ESP_PLATFORMS', ESP_PLATFORMS) + if CORE.esp_platform not in esp_platforms: + result.add_error(u"Component {} doesn't support {}.".format(domain, CORE.esp_platform), + domain, conf) + skip_domains.add(domain) continue if not hasattr(component, 'PLATFORM_SCHEMA'): @@ -177,6 +199,39 @@ def validate_config(config): platform = get_platform(domain, p_name) if platform is None: result.add_error(u"Platform not found: '{}'".format(p_domain), p_domain, p_config) + skip_domains.add(p_domain) + continue + + success = True + dependencies = getattr(platform, 'DEPENDENCIES', []) + for dependency in dependencies: + if dependency not in config: + result.add_error( + u"Platform {} requires component {}".format(p_domain, dependency), + p_domain, p_config) + success = False + if not success: + skip_domains.add(p_domain) + continue + + success = True + conflicts_with = getattr(platform, 'CONFLICTS_WITH', []) + for conflict in conflicts_with: + if conflict not in config: + result.add_error(u"Platform {} cannot be used together with component {}" + u"".format(p_domain, conflict), + domain, conf) + success = False + if not success: + skip_domains.add(p_domain) + continue + + esp_platforms = getattr(platform, 'ESP_PLATFORMS', ESP_PLATFORMS) + if CORE.esp_platform not in esp_platforms: + result.add_error( + u"Platform {} doesn't support {}.".format(p_domain, CORE.esp_platform), + p_domain, p_config) + skip_domains.add(p_domain) continue # Step 2: Validate configuration @@ -186,30 +241,12 @@ def validate_config(config): _comp_error(ex, CONF_ESPHOMEYAML, config[CONF_ESPHOMEYAML]) for domain, conf in config.iteritems(): - if domain == CONF_ESPHOMEYAML or domain.startswith('.'): - continue if conf is None: conf = {} domain = str(domain) + if domain in skip_domains: + continue component = get_component(domain) - if component is None: - continue - - esp_platforms = getattr(component, 'ESP_PLATFORMS', ESP_PLATFORMS) - if CORE.esp_platform not in esp_platforms: - result.add_error(u"Component {} doesn't support {}.".format(domain, CORE.esp_platform), - domain, conf) - continue - - success = True - dependencies = getattr(component, 'DEPENDENCIES', []) - for dependency in dependencies: - if dependency not in _ALL_COMPONENTS: - result.add_error(u"Component {} requires component {}".format(domain, dependency), - domain, conf) - success = False - if not success: - continue if hasattr(component, 'CONFIG_SCHEMA'): try: @@ -230,27 +267,9 @@ def validate_config(config): if p_name is None: continue p_domain = u'{}.{}'.format(domain, p_name) + if p_domain in skip_domains: + continue platform = get_platform(domain, p_name) - if platform is None: - continue - - success = True - dependencies = getattr(platform, 'DEPENDENCIES', []) - for dependency in dependencies: - if dependency not in _ALL_COMPONENTS: - result.add_error( - u"Platform {} requires component {}".format(p_domain, dependency), - p_domain, p_config) - success = False - if not success: - continue - - esp_platforms = getattr(platform, 'ESP_PLATFORMS', ESP_PLATFORMS) - if CORE.esp_platform not in esp_platforms: - result.add_error( - u"Platform {} doesn't support {}.".format(p_domain, CORE.esp_platform), - p_domain, p_config) - continue if hasattr(platform, u'PLATFORM_SCHEMA'): try: @@ -265,9 +284,6 @@ def validate_config(config): return result -REQUIRED = ['esphomeyaml', 'wifi'] - - def _format_config_error(ex, domain, config): message = u"Invalid config for [{}]: ".format(domain) if u'extra keys not allowed' in ex.error_message: diff --git a/esphomeyaml/pins.py b/esphomeyaml/pins.py index 0565b29a94..f699836d1d 100644 --- a/esphomeyaml/pins.py +++ b/esphomeyaml/pins.py @@ -243,6 +243,9 @@ def analog_pin(value): raise NotImplementedError +input_output_pin = vol.All(input_pin, output_pin) + + PIN_MODES_ESP8266 = [ 'INPUT', 'OUTPUT', 'INPUT_PULLUP', 'OUTPUT_OPEN_DRAIN', 'SPECIAL', 'FUNCTION_1', 'FUNCTION_2', 'FUNCTION_3', 'FUNCTION_4',