Merge branch 'esphome:dev' into ads1220

This commit is contained in:
Miika Syvänen 2024-03-26 13:56:32 +02:00 committed by GitHub
commit b1b09113f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 343 additions and 164 deletions

View File

@ -40,19 +40,18 @@ void AHT10Component::setup() {
} }
delay(AHT10_SOFTRESET_DELAY); delay(AHT10_SOFTRESET_DELAY);
const uint8_t *init_cmd; i2c::ErrorCode error_code = i2c::ERROR_INVALID_ARGUMENT;
switch (this->variant_) { switch (this->variant_) {
case AHT10Variant::AHT20: case AHT10Variant::AHT20:
init_cmd = AHT20_INITIALIZE_CMD;
ESP_LOGCONFIG(TAG, "Setting up AHT20"); ESP_LOGCONFIG(TAG, "Setting up AHT20");
error_code = this->write(AHT20_INITIALIZE_CMD, sizeof(AHT20_INITIALIZE_CMD));
break; break;
case AHT10Variant::AHT10: case AHT10Variant::AHT10:
default:
init_cmd = AHT10_INITIALIZE_CMD;
ESP_LOGCONFIG(TAG, "Setting up AHT10"); ESP_LOGCONFIG(TAG, "Setting up AHT10");
error_code = this->write(AHT10_INITIALIZE_CMD, sizeof(AHT10_INITIALIZE_CMD));
break;
} }
if (error_code != i2c::ERROR_OK) {
if (this->write(init_cmd, sizeof(init_cmd)) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with AHT10 failed!"); ESP_LOGE(TAG, "Communication with AHT10 failed!");
this->mark_failed(); this->mark_failed();
return; return;

View File

@ -1,36 +1,87 @@
#ifdef USE_HOST #ifdef USE_HOST
#include <filesystem>
#include <fstream>
#include "preferences.h" #include "preferences.h"
#include <cstring> #include "esphome/core/application.h"
#include "esphome/core/preferences.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "esphome/core/defines.h"
namespace esphome { namespace esphome {
namespace host { namespace host {
namespace fs = std::filesystem;
static const char *const TAG = "host.preferences"; static const char *const TAG = "host.preferences";
class HostPreferences : public ESPPreferences { void HostPreferences::setup_() {
public: if (this->setup_complete_)
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override { return {}; } return;
this->filename_.append(getenv("HOME"));
this->filename_.append("/.esphome");
this->filename_.append("/prefs");
fs::create_directories(this->filename_);
this->filename_.append("/");
this->filename_.append(App.get_name());
this->filename_.append(".prefs");
FILE *fp = fopen(this->filename_.c_str(), "rb");
if (fp != nullptr) {
while (!feof((fp))) {
uint32_t key;
uint8_t len;
if (fread(&key, sizeof(key), 1, fp) != 1)
break;
if (fread(&len, sizeof(len), 1, fp) != 1)
break;
uint8_t data[len];
if (fread(data, sizeof(uint8_t), len, fp) != len)
break;
std::vector vec(data, data + len);
this->data[key] = vec;
}
fclose(fp);
}
this->setup_complete_ = true;
}
ESPPreferenceObject make_preference(size_t length, uint32_t type) override { return {}; } bool HostPreferences::sync() {
this->setup_();
FILE *fp = fopen(this->filename_.c_str(), "wb");
std::map<uint32_t, std::vector<uint8_t>>::iterator it;
bool sync() override { return true; } for (it = this->data.begin(); it != this->data.end(); ++it) {
bool reset() override { return true; } fwrite(&it->first, sizeof(uint32_t), 1, fp);
uint8_t len = it->second.size();
fwrite(&len, sizeof(len), 1, fp);
fwrite(it->second.data(), sizeof(uint8_t), it->second.size(), fp);
}
fclose(fp);
return true;
}
bool HostPreferences::reset() {
host_preferences->data.clear();
return true;
}
ESPPreferenceObject HostPreferences::make_preference(size_t length, uint32_t type, bool in_flash) {
auto backend = new HostPreferenceBackend(type);
return ESPPreferenceObject(backend);
}; };
void setup_preferences() { void setup_preferences() {
auto *pref = new HostPreferences(); // NOLINT(cppcoreguidelines-owning-memory) auto *pref = new HostPreferences(); // NOLINT(cppcoreguidelines-owning-memory)
host_preferences = pref;
global_preferences = pref; global_preferences = pref;
} }
bool HostPreferenceBackend::save(const uint8_t *data, size_t len) {
return host_preferences->save(this->key_, data, len);
}
bool HostPreferenceBackend::load(uint8_t *data, size_t len) { return host_preferences->load(this->key_, data, len); }
HostPreferences *host_preferences;
} // namespace host } // namespace host
ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace esphome } // namespace esphome
#endif // USE_HOST #endif // USE_HOST

View File

@ -2,10 +2,63 @@
#ifdef USE_HOST #ifdef USE_HOST
#include "esphome/core/preferences.h"
#include <map>
namespace esphome { namespace esphome {
namespace host { namespace host {
class HostPreferenceBackend : public ESPPreferenceBackend {
public:
explicit HostPreferenceBackend(uint32_t key) { this->key_ = key; }
bool save(const uint8_t *data, size_t len) override;
bool load(uint8_t *data, size_t len) override;
protected:
uint32_t key_{};
};
class HostPreferences : public ESPPreferences {
public:
bool sync() override;
bool reset() override;
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override;
ESPPreferenceObject make_preference(size_t length, uint32_t type) override {
return make_preference(length, type, false);
}
bool save(uint32_t key, const uint8_t *data, size_t len) {
if (len > 255)
return false;
this->setup_();
std::vector vec(data, data + len);
this->data[key] = vec;
return true;
}
bool load(uint32_t key, uint8_t *data, size_t len) {
if (len > 255)
return false;
this->setup_();
if (this->data.count(key) == 0)
return false;
auto vec = this->data[key];
if (vec.size() != len)
return false;
memcpy(data, vec.data(), len);
return true;
}
protected:
void setup_();
bool setup_complete_{};
std::string filename_{};
std::map<uint32_t, std::vector<uint8_t>> data{};
};
void setup_preferences(); void setup_preferences();
extern HostPreferences *host_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace host } // namespace host
} // namespace esphome } // namespace esphome

View File

@ -287,7 +287,7 @@ def _load_model_data(manifest_path: Path):
except cv.Invalid as e: except cv.Invalid as e:
raise EsphomeError(f"Invalid manifest file: {e}") from e raise EsphomeError(f"Invalid manifest file: {e}") from e
model_path = urljoin(str(manifest_path), manifest[CONF_MODEL]) model_path = manifest_path.parent / manifest[CONF_MODEL]
with open(model_path, "rb") as f: with open(model_path, "rb") as f:
model = f.read() model = f.read()

View File

@ -22,7 +22,7 @@ CONF_PEER_ALLOWED_IPS = "peer_allowed_ips"
CONF_PEER_PERSISTENT_KEEPALIVE = "peer_persistent_keepalive" CONF_PEER_PERSISTENT_KEEPALIVE = "peer_persistent_keepalive"
CONF_REQUIRE_CONNECTION_TO_PROCEED = "require_connection_to_proceed" CONF_REQUIRE_CONNECTION_TO_PROCEED = "require_connection_to_proceed"
DEPENDENCIES = ["time", "esp32"] DEPENDENCIES = ["time"]
CODEOWNERS = ["@lhoracek", "@droscy", "@thomas0bernard"] CODEOWNERS = ["@lhoracek", "@droscy", "@thomas0bernard"]
# The key validation regex has been described by Jason Donenfeld himself # The key validation regex has been described by Jason Donenfeld himself
@ -120,7 +120,7 @@ async def to_code(config):
# the '+1' modifier is relative to the device's own address that will # the '+1' modifier is relative to the device's own address that will
# be automatically added to the provided list. # be automatically added to the provided list.
cg.add_build_flag(f"-DCONFIG_WIREGUARD_MAX_SRC_IPS={len(allowed_ips) + 1}") cg.add_build_flag(f"-DCONFIG_WIREGUARD_MAX_SRC_IPS={len(allowed_ips) + 1}")
cg.add_library("droscy/esp_wireguard", "0.3.2") cg.add_library("droscy/esp_wireguard", "0.4.0")
await cg.register_component(var, config) await cg.register_component(var, config)

View File

@ -1,7 +1,5 @@
#include "wireguard.h" #include "wireguard.h"
#ifdef USE_ESP32
#include <cinttypes> #include <cinttypes>
#include <ctime> #include <ctime>
#include <functional> #include <functional>
@ -11,26 +9,20 @@
#include "esphome/core/time.h" #include "esphome/core/time.h"
#include "esphome/components/network/util.h" #include "esphome/components/network/util.h"
#include <esp_err.h>
#include <esp_wireguard.h> #include <esp_wireguard.h>
#include <esp_wireguard_err.h>
// includes for resume/suspend wdt
#if defined(USE_ESP_IDF)
#include <esp_task_wdt.h>
#if ESP_IDF_VERSION_MAJOR >= 5
#include <spi_flash_mmap.h>
#endif
#elif defined(USE_ARDUINO)
#include <esp32-hal.h>
#endif
namespace esphome { namespace esphome {
namespace wireguard { namespace wireguard {
static const char *const TAG = "wireguard"; static const char *const TAG = "wireguard";
static const char *const LOGMSG_PEER_STATUS = "WireGuard remote peer is %s (latest handshake %s)"; /*
* Cannot use `static const char*` for LOGMSG_PEER_STATUS on esp8266 platform
* because log messages in `Wireguard::update()` method fail.
*/
#define LOGMSG_PEER_STATUS "WireGuard remote peer is %s (latest handshake %s)"
static const char *const LOGMSG_ONLINE = "online"; static const char *const LOGMSG_ONLINE = "online";
static const char *const LOGMSG_OFFLINE = "offline"; static const char *const LOGMSG_OFFLINE = "offline";
@ -257,20 +249,13 @@ void Wireguard::start_connection_() {
} }
ESP_LOGD(TAG, "starting WireGuard connection..."); ESP_LOGD(TAG, "starting WireGuard connection...");
/*
* The function esp_wireguard_connect() contains a DNS resolution
* that could trigger the watchdog, so before it we suspend (or
* increase the time, it depends on the platform) the wdt and
* then we resume the normal timeout.
*/
suspend_wdt();
ESP_LOGV(TAG, "executing esp_wireguard_connect");
this->wg_connected_ = esp_wireguard_connect(&(this->wg_ctx_)); this->wg_connected_ = esp_wireguard_connect(&(this->wg_ctx_));
resume_wdt();
if (this->wg_connected_ == ESP_OK) { if (this->wg_connected_ == ESP_OK) {
ESP_LOGI(TAG, "WireGuard connection started"); ESP_LOGI(TAG, "WireGuard connection started");
} else if (this->wg_connected_ == ESP_ERR_RETRY) {
ESP_LOGD(TAG, "WireGuard is waiting for endpoint IP address to be available");
return;
} else { } else {
ESP_LOGW(TAG, "cannot start WireGuard connection, error code %d", this->wg_connected_); ESP_LOGW(TAG, "cannot start WireGuard connection, error code %d", this->wg_connected_);
return; return;
@ -300,44 +285,7 @@ void Wireguard::stop_connection_() {
} }
} }
void suspend_wdt() {
#if defined(USE_ESP_IDF)
#if ESP_IDF_VERSION_MAJOR >= 5
ESP_LOGV(TAG, "temporarily increasing wdt timeout to 15000 ms");
esp_task_wdt_config_t wdtc;
wdtc.timeout_ms = 15000;
wdtc.idle_core_mask = 0;
wdtc.trigger_panic = false;
esp_task_wdt_reconfigure(&wdtc);
#else
ESP_LOGV(TAG, "temporarily increasing wdt timeout to 15 seconds");
esp_task_wdt_init(15, false);
#endif
#elif defined(USE_ARDUINO)
ESP_LOGV(TAG, "temporarily disabling the wdt");
disableLoopWDT();
#endif
}
void resume_wdt() {
#if defined(USE_ESP_IDF)
#if ESP_IDF_VERSION_MAJOR >= 5
wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000;
esp_task_wdt_reconfigure(&wdtc);
ESP_LOGV(TAG, "wdt resumed with %" PRIu32 " ms timeout", wdtc.timeout_ms);
#else
esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false);
ESP_LOGV(TAG, "wdt resumed with %d seconds timeout", CONFIG_ESP_TASK_WDT_TIMEOUT_S);
#endif
#elif defined(USE_ARDUINO)
enableLoopWDT();
ESP_LOGV(TAG, "wdt resumed");
#endif
}
std::string mask_key(const std::string &key) { return (key.substr(0, 5) + "[...]="); } std::string mask_key(const std::string &key) { return (key.substr(0, 5) + "[...]="); }
} // namespace wireguard } // namespace wireguard
} // namespace esphome } // namespace esphome
#endif // USE_ESP32

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
#ifdef USE_ESP32
#include <ctime> #include <ctime>
#include <vector> #include <vector>
#include <tuple> #include <tuple>
@ -172,5 +170,3 @@ template<typename... Ts> class WireguardDisableAction : public Action<Ts...>, pu
} // namespace wireguard } // namespace wireguard
} // namespace esphome } // namespace esphome
#endif // USE_ESP32

View File

@ -1,10 +1,11 @@
from __future__ import annotations
import abc import abc
import functools import functools
import heapq import heapq
import logging import logging
import re import re
from typing import Optional, Union from typing import Union, Any
from contextlib import contextmanager from contextlib import contextmanager
import contextvars import contextvars
@ -76,7 +77,7 @@ def _path_begins_with(path: ConfigPath, other: ConfigPath) -> bool:
@functools.total_ordering @functools.total_ordering
class _ValidationStepTask: class _ValidationStepTask:
def __init__(self, priority: float, id_number: int, step: "ConfigValidationStep"): def __init__(self, priority: float, id_number: int, step: ConfigValidationStep):
self.priority = priority self.priority = priority
self.id_number = id_number self.id_number = id_number
self.step = step self.step = step
@ -130,7 +131,7 @@ class Config(OrderedDict, fv.FinalValidateConfig):
) )
self.errors.append(error) self.errors.append(error)
def add_validation_step(self, step: "ConfigValidationStep"): def add_validation_step(self, step: ConfigValidationStep):
id_num = self._validation_tasks_id id_num = self._validation_tasks_id
self._validation_tasks_id += 1 self._validation_tasks_id += 1
heapq.heappush( heapq.heappush(
@ -172,7 +173,7 @@ class Config(OrderedDict, fv.FinalValidateConfig):
conf = conf[key] conf = conf[key]
conf[path[-1]] = value conf[path[-1]] = value
def get_error_for_path(self, path: ConfigPath) -> Optional[vol.Invalid]: def get_error_for_path(self, path: ConfigPath) -> vol.Invalid | None:
for err in self.errors: for err in self.errors:
if self.get_deepest_path(err.path) == path: if self.get_deepest_path(err.path) == path:
self.errors.remove(err) self.errors.remove(err)
@ -181,7 +182,7 @@ class Config(OrderedDict, fv.FinalValidateConfig):
def get_deepest_document_range_for_path( def get_deepest_document_range_for_path(
self, path: ConfigPath, get_key: bool = False self, path: ConfigPath, get_key: bool = False
) -> Optional[ESPHomeDataBase]: ) -> ESPHomeDataBase | None:
data = self data = self
doc_range = None doc_range = None
for index, path_item in enumerate(path): for index, path_item in enumerate(path):
@ -733,7 +734,9 @@ class PinUseValidationCheck(ConfigValidationStep):
pins.PIN_SCHEMA_REGISTRY.final_validate(result) pins.PIN_SCHEMA_REGISTRY.final_validate(result)
def validate_config(config, command_line_substitutions) -> Config: def validate_config(
config: dict[str, Any], command_line_substitutions: dict[str, Any]
) -> Config:
result = Config() result = Config()
loader.clear_component_meta_finders() loader.clear_component_meta_finders()
@ -897,24 +900,23 @@ class InvalidYAMLError(EsphomeError):
self.base_exc = base_exc self.base_exc = base_exc
def _load_config(command_line_substitutions): def _load_config(command_line_substitutions: dict[str, Any]) -> Config:
"""Load the configuration file."""
try: try:
config = yaml_util.load_yaml(CORE.config_path) config = yaml_util.load_yaml(CORE.config_path)
except EsphomeError as e: except EsphomeError as e:
raise InvalidYAMLError(e) from e raise InvalidYAMLError(e) from e
try: try:
result = validate_config(config, command_line_substitutions) return validate_config(config, command_line_substitutions)
except EsphomeError: except EsphomeError:
raise raise
except Exception: except Exception:
_LOGGER.error("Unexpected exception while reading configuration:") _LOGGER.error("Unexpected exception while reading configuration:")
raise raise
return result
def load_config(command_line_substitutions: dict[str, Any]) -> Config:
def load_config(command_line_substitutions):
try: try:
return _load_config(command_line_substitutions) return _load_config(command_line_substitutions)
except vol.Invalid as err: except vol.Invalid as err:

View File

@ -1,9 +1,4 @@
import json
import os
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.core import CORE
from esphome.helpers import read_file
class Extend: class Extend:
@ -38,25 +33,6 @@ class Remove:
return isinstance(b, Remove) and self.value == b.value return isinstance(b, Remove) and self.value == b.value
def read_config_file(path: str) -> str:
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(input())
assert data["type"] == "file_response"
return data["content"]
return read_file(path)
def merge_config(full_old, full_new): def merge_config(full_old, full_new):
def merge(old, new): def merge(old, new):
if isinstance(new, dict): if isinstance(new, dict):

View File

@ -1,4 +1,6 @@
#ifdef USE_DATETIME
#include <regex> #include <regex>
#endif
#include "helpers.h" #include "helpers.h"
#include "time.h" // NOLINT #include "time.h" // NOLINT
@ -64,6 +66,8 @@ std::string ESPTime::strftime(const std::string &format) {
return timestr; return timestr;
} }
#ifdef USE_DATETIME
bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) { bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) {
// clang-format off // clang-format off
std::regex dt_regex(R"(^ std::regex dt_regex(R"(^
@ -102,6 +106,8 @@ bool ESPTime::strptime(const std::string &time_to_parse, ESPTime &esp_time) {
return true; return true;
} }
#endif
void ESPTime::increment_second() { void ESPTime::increment_second() {
this->timestamp++; this->timestamp++;
if (!increment_time_value(this->second, 0, 60)) if (!increment_time_value(this->second, 0, 60))

View File

@ -67,6 +67,8 @@ struct ESPTime {
this->day_of_year < 367 && this->month > 0 && this->month < 13; this->day_of_year < 367 && this->month > 0 && this->month < 13;
} }
#ifdef USE_DATETIME
/** Convert a string to ESPTime struct as specified by the format argument. /** Convert a string to ESPTime struct as specified by the format argument.
* @param time_to_parse null-terminated c string formatet like this: 2020-08-25 05:30:00. * @param time_to_parse null-terminated c string formatet like this: 2020-08-25 05:30:00.
* @param esp_time an instance of a ESPTime struct * @param esp_time an instance of a ESPTime struct
@ -74,6 +76,8 @@ struct ESPTime {
*/ */
static bool strptime(const std::string &time_to_parse, ESPTime &esp_time); static bool strptime(const std::string &time_to_parse, ESPTime &esp_time);
#endif
/// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance. /// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance.
static ESPTime from_c_tm(struct tm *c_tm, time_t c_time); static ESPTime from_c_tm(struct tm *c_tm, time_t c_time);

View File

@ -311,10 +311,18 @@ def gpio_base_schema(
map(lambda m: (cv.Optional(m, default=mode_default), cv.boolean), modes) map(lambda m: (cv.Optional(m, default=mode_default), cv.boolean), modes)
) )
def _number_validator(value):
if isinstance(value, str) and value.upper().startswith("GPIOX"):
raise cv.Invalid(
f"Found placeholder '{value}' when expecting a GPIO pin number.\n"
"You must replace this with an actual pin number."
)
return number_validator(value)
schema = cv.Schema( schema = cv.Schema(
{ {
cv.GenerateID(): cv.declare_id(pin_type), cv.GenerateID(): cv.declare_id(pin_type),
cv.Required(CONF_NUMBER): number_validator, cv.Required(CONF_NUMBER): _number_validator,
cv.Optional(CONF_ALLOW_OTHER_USES): cv.boolean, cv.Optional(CONF_ALLOW_OTHER_USES): cv.boolean,
cv.Optional(CONF_MODE, default={}): cv.All(mode_dict, mode_validator), cv.Optional(CONF_MODE, default={}): cv.All(mode_dict, mode_validator),
} }

View File

@ -1,20 +1,22 @@
from __future__ import annotations
import json import json
import os import os
from io import StringIO
from typing import Any
from typing import Optional from esphome.yaml_util import parse_yaml
from esphome.config import validate_config, _format_vol_invalid, Config
from esphome.config import load_config, _format_vol_invalid, Config
from esphome.core import CORE, DocumentRange from esphome.core import CORE, DocumentRange
import esphome.config_validation as cv import esphome.config_validation as cv
def _get_invalid_range(res: Config, invalid: cv.Invalid) -> Optional[DocumentRange]: def _get_invalid_range(res: Config, invalid: cv.Invalid) -> DocumentRange | None:
return res.get_deepest_document_range_for_path( return res.get_deepest_document_range_for_path(
invalid.path, invalid.error_message == "extra keys not allowed" invalid.path, invalid.error_message == "extra keys not allowed"
) )
def _dump_range(range: Optional[DocumentRange]) -> Optional[dict]: def _dump_range(range: DocumentRange | None) -> dict | None:
if range is None: if range is None:
return None return None
return { return {
@ -56,6 +58,25 @@ class VSCodeResult:
) )
def _read_file_content_from_json_on_stdin() -> str:
"""Read the content of a json encoded file from stdin."""
data = json.loads(input())
assert data["type"] == "file_response"
return data["content"]
def _print_file_read_event(path: str) -> None:
"""Print a file read event."""
print(
json.dumps(
{
"type": "read_file",
"path": path,
}
)
)
def read_config(args): def read_config(args):
while True: while True:
CORE.reset() CORE.reset()
@ -68,9 +89,17 @@ def read_config(args):
CORE.config_path = os.path.join(args.configuration, f) CORE.config_path = os.path.join(args.configuration, f)
else: else:
CORE.config_path = data["file"] CORE.config_path = data["file"]
file_name = CORE.config_path
_print_file_read_event(file_name)
raw_yaml = _read_file_content_from_json_on_stdin()
command_line_substitutions: dict[str, Any] = (
dict(args.substitution) if args.substitution else {}
)
vs = VSCodeResult() vs = VSCodeResult()
try: try:
res = load_config(dict(args.substitution) if args.substitution else {}) config = parse_yaml(file_name, StringIO(raw_yaml))
res = validate_config(config, command_line_substitutions)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
vs.add_yaml_error(str(err)) vs.add_yaml_error(str(err))
else: else:

View File

@ -417,20 +417,25 @@ def load_yaml(fname: str, clear_secrets: bool = True) -> Any:
return _load_yaml_internal(fname) return _load_yaml_internal(fname)
def parse_yaml(file_name: str, file_handle: TextIOWrapper) -> Any:
"""Parse a YAML file."""
try:
return _load_yaml_internal_with_type(ESPHomeLoader, file_name, file_handle)
except EsphomeError:
# Loading failed, so we now load with the Python loader which has more
# readable exceptions
# Rewind the stream so we can try again
file_handle.seek(0, 0)
return _load_yaml_internal_with_type(
ESPHomePurePythonLoader, file_name, file_handle
)
def _load_yaml_internal(fname: str) -> Any: def _load_yaml_internal(fname: str) -> Any:
"""Load a YAML file.""" """Load a YAML file."""
try: try:
with open(fname, encoding="utf-8") as f_handle: with open(fname, encoding="utf-8") as f_handle:
try: return parse_yaml(fname, f_handle)
return _load_yaml_internal_with_type(ESPHomeLoader, fname, f_handle)
except EsphomeError:
# Loading failed, so we now load with the Python loader which has more
# readable exceptions
# Rewind the stream so we can try again
f_handle.seek(0, 0)
return _load_yaml_internal_with_type(
ESPHomePurePythonLoader, fname, f_handle
)
except (UnicodeDecodeError, OSError) as err: except (UnicodeDecodeError, OSError) as err:
raise EsphomeError(f"Error reading file {fname}: {err}") from err raise EsphomeError(f"Error reading file {fname}: {err}") from err

View File

@ -94,6 +94,7 @@ lib_deps =
ESP8266mDNS ; mdns (Arduino built-in) ESP8266mDNS ; mdns (Arduino built-in)
DNSServer ; captive_portal (Arduino built-in) DNSServer ; captive_portal (Arduino built-in)
crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir
droscy/esp_wireguard@0.4.0 ; wireguard
build_flags = build_flags =
${common:arduino.build_flags} ${common:arduino.build_flags}
-Wno-nonnull-compare -Wno-nonnull-compare
@ -123,7 +124,7 @@ lib_deps =
DNSServer ; captive_portal (Arduino built-in) DNSServer ; captive_portal (Arduino built-in)
esphome/ESP32-audioI2S@2.0.7 ; i2s_audio esphome/ESP32-audioI2S@2.0.7 ; i2s_audio
crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir crankyoldgit/IRremoteESP8266@~2.8.4 ; heatpumpir
droscy/esp_wireguard@0.3.2 ; wireguard droscy/esp_wireguard@0.4.0 ; wireguard
build_flags = build_flags =
${common:arduino.build_flags} ${common:arduino.build_flags}
-DUSE_ESP32 -DUSE_ESP32
@ -142,7 +143,7 @@ framework = espidf
lib_deps = lib_deps =
${common:idf.lib_deps} ${common:idf.lib_deps}
espressif/esp32-camera@1.0.0 ; esp32_camera espressif/esp32-camera@1.0.0 ; esp32_camera
droscy/esp_wireguard@0.3.2 ; wireguard droscy/esp_wireguard@0.4.0 ; wireguard
build_flags = build_flags =
${common:idf.build_flags} ${common:idf.build_flags}
-Wno-nonnull-compare -Wno-nonnull-compare

View File

@ -13,7 +13,6 @@ classifier =
Programming Language :: C++ Programming Language :: C++
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Topic :: Home Automation Topic :: Home Automation
Topic :: Home Automation
[flake8] [flake8]
max-line-length = 120 max-line-length = 120

View File

@ -1,36 +1,14 @@
---
esphome:
name: test10
build_path: build/test10
esp32:
board: esp32doit-devkit-v1
framework:
type: arduino
wifi: wifi:
ssid: "MySSID1" ssid: "MySSID1"
password: "password1" password: "password1"
reboot_timeout: 3min
power_save_mode: high
network: network:
enable_ipv6: true enable_ipv6: true
logger:
level: VERBOSE
api:
reboot_timeout: 10min
web_server:
version: 3
time: time:
- platform: sntp - platform: sntp
wireguard: wireguard:
id: vpn
address: 172.16.34.100 address: 172.16.34.100
netmask: 255.255.255.0 netmask: 255.255.255.0
# NEVER use the following keys for your vpn, they are now public! # NEVER use the following keys for your vpn, they are now public!

View File

@ -0,0 +1,62 @@
wifi:
ssid: "MySSID1"
password: "password1"
network:
enable_ipv6: true
time:
- platform: sntp
wireguard:
address: 172.16.34.100
netmask: 255.255.255.0
# NEVER use the following keys for your vpn, they are now public!
private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8=
peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc=
peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60=
peer_endpoint: wg.server.example
peer_persistent_keepalive: 25s
peer_allowed_ips:
- 172.16.34.0/24
- 192.168.4.0/24
binary_sensor:
- platform: wireguard
status:
name: 'WireGuard Status'
enabled:
name: 'WireGuard Enabled'
sensor:
- platform: wireguard
latest_handshake:
name: 'WireGuard Latest Handshake'
text_sensor:
- platform: wireguard
address:
name: 'WireGuard Address'
button:
- platform: template
name: 'Toggle WireGuard'
entity_category: config
on_press:
- if:
condition: wireguard.enabled
then:
- wireguard.disable:
else:
- wireguard.enable:
- platform: template
name: 'Log WireGuard status'
entity_category: config
on_press:
- if:
condition: wireguard.peer_online
then:
- logger.log: 'wireguard remote peer is online'
else:
- logger.log: 'wireguard remote peer is offline'

View File

@ -0,0 +1,62 @@
wifi:
ssid: "MySSID1"
password: "password1"
network:
enable_ipv6: true
time:
- platform: sntp
wireguard:
address: 172.16.34.100
netmask: 255.255.255.0
# NEVER use the following keys for your vpn, they are now public!
private_key: wPBMxtNYH3mChicrbpsRpZIasIdPq3yZuthn23FbGG8=
peer_public_key: Hs2JfikvYU03/Kv3YoAs1hrUIPPTEkpsZKSPUljE9yc=
peer_preshared_key: 20fjM5GRnSolGPC5SRj9ljgIUyQfruv0B0bvLl3Yt60=
peer_endpoint: wg.server.example
peer_persistent_keepalive: 25s
peer_allowed_ips:
- 172.16.34.0/24
- 192.168.4.0/24
binary_sensor:
- platform: wireguard
status:
name: 'WireGuard Status'
enabled:
name: 'WireGuard Enabled'
sensor:
- platform: wireguard
latest_handshake:
name: 'WireGuard Latest Handshake'
text_sensor:
- platform: wireguard
address:
name: 'WireGuard Address'
button:
- platform: template
name: 'Toggle WireGuard'
entity_category: config
on_press:
- if:
condition: wireguard.enabled
then:
- wireguard.disable:
else:
- wireguard.enable:
- platform: template
name: 'Log WireGuard status'
entity_category: config
on_press:
- if:
condition: wireguard.peer_online
then:
- logger.log: 'wireguard remote peer is online'
else:
- logger.log: 'wireguard remote peer is offline'