Esempio n. 1
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 EsphomeError("Cannot connect to MQTT broker: {}".format(err))

    try:
        client.loop_forever()
    except KeyboardInterrupt:
        pass
    return 0
Esempio n. 2
0
def choose_prompt(options):
    if not options:
        raise EsphomeError(
            "Found no valid options for upload/logging, please make sure relevant "
            "sections (ota, api, mqtt, ...) are in your configuration and/or the "
            "device is plugged in.")

    if len(options) == 1:
        return options[0][1]

    safe_print("Found multiple options, please choose one:")
    for i, (desc, _) in enumerate(options):
        safe_print(f"  [{i+1}] {desc}")

    while True:
        opt = input("(number): ")
        if opt in options:
            opt = options.index(opt)
            break
        try:
            opt = int(opt)
            if opt < 1 or opt > len(options):
                raise ValueError
            break
        except ValueError:
            safe_print(color(Fore.RED, f"Invalid option: '{opt}'"))
    return options[opt - 1][1]
Esempio n. 3
0
def write_file(path: Union[Path, str], text: str):
    try:
        _write_file(path, text)
    except OSError as err:
        from esphome.core import EsphomeError

        raise EsphomeError(f"Could not write file at {path}") from err
Esempio n. 4
0
def show_logs(config, args, port):
    if 'logger' not in config:
        raise EsphomeError("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:
        from esphome.api.client import run_logs

        return run_logs(config, port)
    if get_port_type(port) == 'MQTT' and 'mqtt' in config:
        from esphome import mqtt

        return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id)

    raise EsphomeError("No remote or local logging method configured (api/mqtt/logger)")
Esempio n. 5
0
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 EsphomeError(
                f"The local log level {level} for {tag} must be less severe than the global log level {global_level}."
            )
    return value
Esempio n. 6
0
def find_begin_end(text, begin_s, end_s):
    begin_index = text.find(begin_s)
    if begin_index == -1:
        raise EsphomeError(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 EsphomeError(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 EsphomeError(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 EsphomeError(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)):]
Esempio n. 7
0
def write_file(path, text):
    try:
        mkdir_p(os.path.dirname(path))
        with codecs.open(path, 'w+', encoding='utf-8') as f_handle:
            f_handle.write(text)
    except OSError:
        from esphome.core import EsphomeError
        raise EsphomeError(u"Could not write file at {}".format(path))
Esempio n. 8
0
def show_logs(config, args, port):
    if "logger" not in config:
        raise EsphomeError("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:
        from esphome.api.client import run_logs

        return run_logs(config, port)
    if get_port_type(port) == "MQTT" and "mqtt" in config:
        from esphome import mqtt

        return mqtt.show_logs(config, args.topic, args.username, args.password,
                              args.client_id)

    raise EsphomeError(
        "No remote or local logging method configured (api/mqtt/logger)")
Esempio n. 9
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_internal(secret_path)
    if node.value not in secrets:
        raise EsphomeError(u"Secret {} not defined".format(node.value))
    val = secrets[node.value]
    _SECRET_VALUES[text_type(val)] = node.value
    return val
Esempio n. 10
0
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 EsphomeError(
                u"The local log level {} for {} must be less severe than the "
                u"global log level {}.".format(level, tag, global_level))
    return value
Esempio n. 11
0
def copy_file_if_changed(src, dst):
    import shutil
    if file_compare(src, dst):
        return
    mkdir_p(os.path.dirname(dst))
    try:
        shutil.copy(src, dst)
    except OSError as err:
        from esphome.core import EsphomeError
        raise EsphomeError(f"Error copying file {src} to {dst}: {err}")
Esempio n. 12
0
def _resolve_with_zeroconf(host):
    from esphome.core import EsphomeError
    try:
        zc = Zeroconf()
    except Exception:
        raise EsphomeError(
            "Cannot start mDNS sockets, is this a docker container without "
            "host network mode?")
    try:
        info = zc.resolve_host(host + '.')
    except Exception as err:
        raise EsphomeError("Error resolving mDNS hostname: {}".format(err))
    finally:
        zc.close()
    if info is None:
        raise EsphomeError(
            "Error resolving address with mDNS: Did not respond. "
            "Maybe the device is offline.")
    return info
Esempio n. 13
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 EsphomeError(u"Environment variable {} not defined.".format(node.value))
Esempio n. 14
0
def read_config_file(path):
    # type: (basestring) -> unicode
    if CORE.vscode and (not CORE.ace or os.path.abspath(path)
                        == os.path.abspath(CORE.config_path)):
        print(json.dumps({
            'type': 'read_file',
            'path': path,
        }))
        data = json.loads(safe_input())
        assert data['type'] == 'file_response'
        return data['content']

    try:
        with codecs.open(path, encoding='utf-8') as handle:
            return handle.read()
    except IOError as exc:
        raise EsphomeError(u"Error accessing file {}: {}".format(path, exc))
    except UnicodeDecodeError as exc:
        raise EsphomeError(u"Unable to read file {}: {}".format(path, exc))
Esempio n. 15
0
def _load_yaml_internal(fname):
    content = read_config_file(fname)
    loader = ESPHomeLoader(content)
    loader.name = fname
    try:
        return loader.get_single_data() or OrderedDict()
    except yaml.YAMLError as exc:
        raise EsphomeError(exc) from exc
    finally:
        loader.dispose()
Esempio n. 16
0
def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as err:
        import errno
        if err.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            from esphome.core import EsphomeError
            raise EsphomeError(u"Error creating directories {}: {}".format(
                path, err))
Esempio n. 17
0
def resolve_ip_address(host):
    from esphome.core import EsphomeError

    try:
        ip = socket.gethostbyname(host)
    except socket.error as err:
        if host.endswith('.local'):
            ip = _resolve_with_zeroconf(host)
        else:
            raise EsphomeError("Error resolving IP address: {}".format(err))

    return ip
Esempio n. 18
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 esphome.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 EsphomeError(u"Unknown default mode {}".format(default_mode))
    if CONF_MCP23017 in conf:
        from esphome.components import mcp23017

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

        if default_mode == u'INPUT':
            mode = mcp23017.MCP23017_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 EsphomeError(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)
    def symlink(src, dst):
        csl = ctypes.windll.kernel32.CreateSymbolicLinkW
        csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32)
        csl.restype = ctypes.c_ubyte
        flags = 1 if os.path.isdir(src) else 0
        if csl(dst, src, flags) == 0:
            error = ctypes.WinError()
            # pylint: disable=no-member
            if error.winerror == 1314 and error.errno == 22:
                from esphome.core import EsphomeError
                raise EsphomeError("Cannot create symlink from '%s' to '%s'. Try running tool \
with elevated privileges" % (src, dst))
            raise error
Esempio n. 20
0
def show_logs(config, args, port):
    if 'logger' not in config:
        raise EsphomeError("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
Esempio n. 21
0
def mkdir_p(path):
    if not path:
        # Empty path - means create current dir
        return
    try:
        os.makedirs(path)
    except OSError as err:
        import errno
        if err.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            from esphome.core import EsphomeError
            raise EsphomeError(f"Error creating directories {path}: {err}")
Esempio n. 22
0
def upload_program(config, args, host):
    # if upload is to a serial port use platformio, otherwise assume ota
    if get_port_type(host) == "SERIAL":
        return upload_using_esptool(config, host)

    from esphome import espota2

    if CONF_OTA not in config:
        raise EsphomeError(
            "Cannot upload Over the Air as the config does not include the ota: "
            "component")

    ota_conf = config[CONF_OTA]
    remote_port = ota_conf[CONF_PORT]
    password = ota_conf.get(CONF_PASSWORD, "")
    return espota2.run_ota(host, remote_port, password, CORE.firmware_bin)
Esempio n. 23
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 EsphomeError(
                    "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
Esempio n. 24
0
def resolve_ip_address(host):
    from esphome.core import EsphomeError
    import socket

    errs = []

    if host.endswith(".local"):
        try:
            return _resolve_with_zeroconf(host)
        except EsphomeError as err:
            errs.append(str(err))

    try:
        return socket.gethostbyname(host)
    except OSError as err:
        errs.append(str(err))
        raise EsphomeError(f"Error resolving IP address: {', '.join(errs)}") from err
Esempio n. 25
0
def load_config():
    try:
        config = yaml_util.load_yaml(CORE.config_path)
    except OSError:
        raise EsphomeError(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 EsphomeError:
        raise
    except Exception:
        _LOGGER.error(u"Unexpected exception while reading configuration:")
        raise

    return result
Esempio n. 26
0
def write_platformio_ini(content, path):
    symlink_esphome_core_version(CORE.esphome_core_version)
    update_esphome_core_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 EsphomeError(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)
Esempio n. 27
0
def load_config():
    try:
        return _load_config()
    except vol.Invalid as err:
        raise EsphomeError("Error while parsing config: {}".format(err))
Esempio n. 28
0
def load_config(command_line_substitutions):
    try:
        return _load_config(command_line_substitutions)
    except vol.Invalid as err:
        raise EsphomeError(f"Error while parsing config: {err}") from err
Esempio n. 29
0
def write_file(path, text):
    try:
        _write_file(path, text)
    except OSError:
        from esphome.core import EsphomeError
        raise EsphomeError(f"Could not write file at {path}")
Esempio n. 30
0
def write_file(path, text):
    try:
        _write_file(path, text)
    except OSError:
        from esphome.core import EsphomeError
        raise EsphomeError(u"Could not write file at {}".format(path))