예제 #1
0
def do_substitution_pass(config):
    if CONF_SUBSTITUTIONS not in config:
        return config

    substitutions = config[CONF_SUBSTITUTIONS]
    if not isinstance(substitutions, dict):
        raise EsphomeyamlError(
            u"Substitutions must be a key to value mapping, got {}"
            u"".format(type(substitutions)))

    key = ''
    try:
        replace_keys = []
        for key, value in substitutions.items():
            sub = validate_substitution_key(key)
            if sub != key:
                replace_keys.append((key, sub))
            substitutions[key] = cv.string_strict(value)
        for old, new in replace_keys:
            substitutions[new] = substitutions[old]
            del substitutions[old]
    except vol.Invalid as err:
        err.path.append(key)

        raise EsphomeyamlError(
            u"Error while parsing substitutions: {}".format(err))

    config[CONF_SUBSTITUTIONS] = substitutions
    _substitute_item(substitutions, config, [])

    return config
예제 #2
0
def load_yaml(fname):
    """Load a YAML file."""
    try:
        with codecs.open(fname, encoding='utf-8') as conf_file:
            return yaml.load(conf_file, Loader=SafeLineLoader) or OrderedDict()
    except yaml.YAMLError as exc:
        raise EsphomeyamlError(exc)
    except IOError as exc:
        raise EsphomeyamlError(u"Error accessing file {}: {}".format(
            fname, exc))
    except UnicodeDecodeError as exc:
        _LOGGER.error(u"Unable to read file %s: %s", fname, exc)
        raise EsphomeyamlError(exc)
예제 #3
0
파일: logger.py 프로젝트: psbaltar/esphome
def validate_local_no_higher_than_global(value):
    global_level = value.get(CONF_LEVEL, 'DEBUG')
    for tag, level in value.get(CONF_LOGS, {}).items():
        if LOG_LEVEL_SEVERITY.index(level) > LOG_LEVEL_SEVERITY.index(global_level):
            raise EsphomeyamlError(u"The local log level {} for {} must be less severe than the "
                                   u"global log level {}.".format(level, tag, global_level))
    return value
예제 #4
0
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 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)
        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)
예제 #5
0
 def __init__(self, config):
     if 'mqtt' not in config:
         raise EsphomeyamlError(
             "Cannot generate Home Assistant MQTT config if MQTT is not "
             "used!")
     mqtt = config[CONF_MQTT]
     self.topic_prefix = mqtt.get(CONF_TOPIC_PREFIX,
                                  config[CONF_ESPHOMEYAML][CONF_NAME])
     birth_message = mqtt.get(CONF_BIRTH_MESSAGE)
     if CONF_BIRTH_MESSAGE not in mqtt:
         birth_message = {
             CONF_TOPIC: self.topic_prefix + '/status',
             CONF_PAYLOAD: 'online',
         }
     will_message = mqtt.get(CONF_WILL_MESSAGE)
     if CONF_WILL_MESSAGE not in mqtt:
         will_message = {
             CONF_TOPIC: self.topic_prefix + '/status',
             CONF_PAYLOAD: 'offline'
         }
     if not birth_message or not will_message:
         self.availability = None
     elif birth_message[CONF_TOPIC] != will_message[CONF_TOPIC]:
         self.availability = None
     else:
         self.availability = {
             CONF_TOPIC: birth_message[CONF_TOPIC],
             CONF_PAYLOAD_AVAILABLE: birth_message[CONF_PAYLOAD],
             CONF_PAYLOAD_NOT_AVAILABLE: will_message[CONF_PAYLOAD],
         }
예제 #6
0
def generic_gpio_pin_expression_(conf, mock_obj, default_mode):
    if conf is None:
        return
    number = conf[CONF_NUMBER]
    inverted = conf.get(CONF_INVERTED)
    if CONF_PCF8574 in conf:
        from esphomeyaml.components import pcf8574

        for hub in CORE.get_variable(conf[CONF_PCF8574]):
            yield None

        if default_mode == u'INPUT':
            mode = pcf8574.PCF8675_GPIO_MODES[conf.get(CONF_MODE, u'INPUT')]
            yield hub.make_input_pin(number, mode, inverted)
            return
        if default_mode == u'OUTPUT':
            yield hub.make_output_pin(number, inverted)
            return

        raise EsphomeyamlError(u"Unknown default mode {}".format(default_mode))
    if len(conf) == 1:
        yield IntLiteral(number)
        return
    mode = RawExpression(conf.get(CONF_MODE, default_mode))
    yield mock_obj(number, mode, inverted)
예제 #7
0
def _secret_yaml(loader, node):
    """Load secrets and embed it into the configuration YAML."""
    secret_path = os.path.join(os.path.dirname(loader.name), SECRET_YAML)
    secrets = load_yaml(secret_path)
    if node.value not in secrets:
        raise EsphomeyamlError(u"Secret {} not defined".format(node.value))
    return secrets[node.value]
예제 #8
0
def _ordered_dict(loader, node):
    """Load YAML mappings into an ordered dictionary to preserve key order."""
    custom_flatten_mapping(loader, node)
    nodes = custom_construct_pairs(loader, node)

    seen = {}
    for (key, _), nv in zip(nodes, node.value):
        if isinstance(nv, yaml.ScalarNode):
            line = nv.start_mark.line
        else:
            line = nv[0].start_mark.line

        try:
            hash(key)
        except TypeError:
            fname = getattr(loader.stream, 'name', '')
            raise yaml.MarkedYAMLError(
                context="invalid key: \"{}\"".format(key),
                context_mark=yaml.Mark(fname, 0, line, -1, None, None))

        if key in seen:
            fname = getattr(loader.stream, 'name', '')
            raise EsphomeyamlError(
                u'YAML file {} contains duplicate key "{}". '
                u'Check lines {} and {}.'.format(fname, key, seen[key], line))
        seen[key] = line

    return _add_reference(OrderedDict(nodes), loader, node)
예제 #9
0
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)):]
예제 #10
0
파일: helpers.py 프로젝트: psbaltar/esphome
def resolve_ip_address(host):
    try:
        ip = socket.gethostbyname(host)
    except socket.error as err:
        from esphomeyaml.core import EsphomeyamlError

        raise EsphomeyamlError("Error resolving IP address: {}".format(err))

    return ip
예제 #11
0
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.")
    if CONF_NAME not in core_conf:
        raise EsphomeyamlError("esphomeyaml.name not specified.")

    try:
        CORE.esp_platform = validate_platform(core_conf[CONF_PLATFORM])
        CORE.board = validate_board(core_conf[CONF_BOARD])
        CORE.name = cv.valid_name(core_conf[CONF_NAME])
        CORE.build_path = CORE.relative_path(
            cv.string(core_conf.get(CONF_BUILD_PATH, default_build_path())))
    except vol.Invalid as e:
        raise EsphomeyamlError(text_type(e))
예제 #12
0
def _env_var_yaml(_, node):
    """Load environment variables and embed it into the configuration YAML."""
    args = node.value.split()

    # Check for a default value
    if len(args) > 1:
        return os.getenv(args[0], u' '.join(args[1:]))
    if args[0] in os.environ:
        return os.environ[args[0]]
    raise EsphomeyamlError(u"Environment variable {} not defined.".format(
        node.value))
예제 #13
0
def initialize(config, subscriptions, on_message, username, password, client_id):
    def on_connect(client, userdata, flags, return_code):
        for topic in subscriptions:
            client.subscribe(topic)

    def on_disconnect(client, userdata, result_code):
        if result_code == 0:
            return

        tries = 0
        while True:
            try:
                if client.reconnect() == 0:
                    _LOGGER.info("Successfully reconnected to the MQTT server")
                    break
            except socket.error:
                pass

            wait_time = min(2**tries, 300)
            _LOGGER.warning(
                "Disconnected from MQTT (%s). Trying to reconnect in %s s",
                result_code, wait_time)
            time.sleep(wait_time)
            tries += 1

    client = mqtt.Client(client_id or u'')
    client.on_connect = on_connect
    client.on_message = on_message
    client.on_disconnect = on_disconnect
    if username is None:
        if config[CONF_MQTT].get(CONF_USERNAME):
            client.username_pw_set(config[CONF_MQTT][CONF_USERNAME],
                                   config[CONF_MQTT][CONF_PASSWORD])
    elif username:
        client.username_pw_set(username, password)

    if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS):
        if sys.version_info >= (2, 7, 13):
            tls_version = ssl.PROTOCOL_TLS  # pylint: disable=no-member
        else:
            tls_version = ssl.PROTOCOL_SSLv23
        client.tls_set(ca_certs=None, certfile=None, keyfile=None, cert_reqs=ssl.CERT_REQUIRED,
                       tls_version=tls_version, ciphers=None)

    try:
        client.connect(config[CONF_MQTT][CONF_BROKER], config[CONF_MQTT][CONF_PORT])
    except socket.error as err:
        raise EsphomeyamlError("Cannot connect to MQTT broker: {}".format(err))

    try:
        client.loop_forever()
    except KeyboardInterrupt:
        pass
    return 0
예제 #14
0
def show_logs(config, args, port):
    if 'logger' not in config:
        raise EsphomeyamlError("Logger is not configured!")
    if get_port_type(port) == 'SERIAL':
        run_miniterm(config, port)
        return 0
    if get_port_type(port) == 'NETWORK' and 'api' in config:
        return run_logs(config, port)
    if get_port_type(port) == 'MQTT' and 'mqtt' in config:
        return mqtt.show_logs(config, args.topic, args.username, args.password,
                              args.client_id)

    raise ValueError
예제 #15
0
def custom_construct_pairs(loader, node):
    pairs = []
    for kv in node.value:
        if isinstance(kv, yaml.ScalarNode):
            obj = loader.construct_object(kv)
            if not isinstance(obj, dict):
                raise EsphomeyamlError(
                    "Expected mapping for anchored include tag, got {}".format(
                        type(obj)))
            for key, value in obj.items():
                pairs.append((key, value))
        else:
            key_node, value_node = kv
            key = loader.construct_object(key_node)
            value = loader.construct_object(value_node)
            pairs.append((key, value))

    return pairs
예제 #16
0
파일: config.py 프로젝트: psbaltar/esphome
def load_config():
    try:
        config = yaml_util.load_yaml(CORE.config_path)
    except OSError:
        raise EsphomeyamlError(u"Invalid YAML at {}".format(CORE.config_path))
    CORE.raw_config = config
    config = substitutions.do_substitution_pass(config)
    core_config.preload_core_config(config)

    try:
        result = validate_config(config)
    except EsphomeyamlError:
        raise
    except Exception:
        _LOGGER.error(u"Unexpected exception while reading configuration:")
        raise

    return result
예제 #17
0
def write_platformio_ini(content, path):
    symlink_esphomelib_version(CORE.esphomelib_version)
    update_esphomelib_repo()
    update_storage_json()

    if os.path.isfile(path):
        try:
            with codecs.open(path, 'r', encoding='utf-8') as f_handle:
                text = f_handle.read()
        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
        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]
    if prev_file == full_file:
        return
    with codecs.open(path, mode='w+', encoding='utf-8') as f_handle:
        f_handle.write(full_file)