mirror of
https://github.com/esphome/esphome.git
synced 2026-09-18 18:48:39 +00:00
Merge remote-tracking branch 'upstream/get_peername_stack_save_ram' into get_peername_stack_save_ram
This commit is contained in:
@@ -90,13 +90,16 @@ void AbsoluteHumidityComponent::loop() {
|
||||
this->status_set_error(LOG_STR("Invalid saturation vapor pressure equation selection!"));
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Saturation vapor pressure %f kPa", es);
|
||||
|
||||
// Calculate absolute humidity
|
||||
const float absolute_humidity = vapor_density(es, hr, temperature_k);
|
||||
|
||||
ESP_LOGD(TAG,
|
||||
"Saturation vapor pressure %f kPa\n"
|
||||
"Publishing absolute humidity %f g/m³",
|
||||
es, absolute_humidity);
|
||||
|
||||
// Publish absolute humidity
|
||||
ESP_LOGD(TAG, "Publishing absolute humidity %f g/m³", absolute_humidity);
|
||||
this->status_clear_warning();
|
||||
this->publish_state(absolute_humidity);
|
||||
}
|
||||
|
||||
@@ -211,13 +211,13 @@ void AcDimmer::write_state(float state) {
|
||||
this->store_.value = new_value;
|
||||
}
|
||||
void AcDimmer::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "AcDimmer:");
|
||||
LOG_PIN(" Output Pin: ", this->gate_pin_);
|
||||
LOG_PIN(" Zero-Cross Pin: ", this->zero_cross_pin_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"AcDimmer:\n"
|
||||
" Min Power: %.1f%%\n"
|
||||
" Init with half cycle: %s",
|
||||
this->store_.min_power / 10.0f, YESNO(this->init_with_half_cycle_));
|
||||
LOG_PIN(" Output Pin: ", this->gate_pin_);
|
||||
LOG_PIN(" Zero-Cross Pin: ", this->zero_cross_pin_);
|
||||
if (method_ == DIM_METHOD_LEADING_PULSE) {
|
||||
ESP_LOGCONFIG(TAG, " Method: leading pulse");
|
||||
} else if (method_ == DIM_METHOD_LEADING) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import esphome.codegen as cg
|
||||
from esphome.components import output
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_METHOD, CONF_MIN_POWER
|
||||
from esphome.core import CORE
|
||||
|
||||
CODEOWNERS = ["@glmnet"]
|
||||
|
||||
@@ -36,6 +37,12 @@ CONFIG_SCHEMA = cv.All(
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
if CORE.is_esp8266:
|
||||
# ac_dimmer uses setTimer1Callback which requires the waveform generator
|
||||
from esphome.components.esp8266.const import require_waveform
|
||||
|
||||
require_waveform()
|
||||
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
|
||||
|
||||
@@ -121,23 +121,21 @@ void ADCSensor::setup() {
|
||||
void ADCSensor::dump_config() {
|
||||
LOG_SENSOR("", "ADC Sensor", this);
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Channel: %d\n"
|
||||
" Unit: %s\n"
|
||||
" Attenuation: %s\n"
|
||||
" Samples: %i\n"
|
||||
" Sampling mode: %s",
|
||||
this->channel_, LOG_STR_ARG(adc_unit_to_str(this->adc_unit_)),
|
||||
this->autorange_ ? "Auto" : LOG_STR_ARG(attenuation_to_str(this->attenuation_)), this->sample_count_,
|
||||
LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
|
||||
|
||||
ESP_LOGCONFIG(
|
||||
TAG,
|
||||
" Channel: %d\n"
|
||||
" Unit: %s\n"
|
||||
" Attenuation: %s\n"
|
||||
" Samples: %i\n"
|
||||
" Sampling mode: %s\n"
|
||||
" Setup Status:\n"
|
||||
" Handle Init: %s\n"
|
||||
" Config: %s\n"
|
||||
" Calibration: %s\n"
|
||||
" Overall Init: %s",
|
||||
this->channel_, LOG_STR_ARG(adc_unit_to_str(this->adc_unit_)),
|
||||
this->autorange_ ? "Auto" : LOG_STR_ARG(attenuation_to_str(this->attenuation_)), this->sample_count_,
|
||||
LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)),
|
||||
this->setup_flags_.handle_init_complete ? "OK" : "FAILED", this->setup_flags_.config_complete ? "OK" : "FAILED",
|
||||
this->setup_flags_.calibration_complete ? "OK" : "FAILED", this->setup_flags_.init_complete ? "OK" : "FAILED");
|
||||
|
||||
|
||||
@@ -162,11 +162,13 @@ void ADE7880::update() {
|
||||
}
|
||||
|
||||
void ADE7880::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ADE7880:");
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"ADE7880:\n"
|
||||
" Frequency: %.0f Hz",
|
||||
this->frequency_);
|
||||
LOG_PIN(" IRQ0 Pin: ", this->irq0_pin_);
|
||||
LOG_PIN(" IRQ1 Pin: ", this->irq1_pin_);
|
||||
LOG_PIN(" RESET Pin: ", this->reset_pin_);
|
||||
ESP_LOGCONFIG(TAG, " Frequency: %.0f Hz", this->frequency_);
|
||||
|
||||
if (this->channel_a_ != nullptr) {
|
||||
ESP_LOGCONFIG(TAG, " Phase A:");
|
||||
|
||||
@@ -21,10 +21,12 @@ void ADS1115Sensor::update() {
|
||||
|
||||
void ADS1115Sensor::dump_config() {
|
||||
LOG_SENSOR(" ", "ADS1115 Sensor", this);
|
||||
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_);
|
||||
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_);
|
||||
ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_);
|
||||
ESP_LOGCONFIG(TAG, " Sample rate: %u", this->samplerate_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Multiplexer: %u\n"
|
||||
" Gain: %u\n"
|
||||
" Resolution: %u\n"
|
||||
" Sample rate: %u",
|
||||
this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
|
||||
}
|
||||
|
||||
} // namespace ads1115
|
||||
|
||||
@@ -9,8 +9,10 @@ static const char *const TAG = "ads1118.sensor";
|
||||
|
||||
void ADS1118Sensor::dump_config() {
|
||||
LOG_SENSOR(" ", "ADS1118 Sensor", this);
|
||||
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_);
|
||||
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Multiplexer: %u\n"
|
||||
" Gain: %u",
|
||||
this->multiplexer_, this->gain_);
|
||||
}
|
||||
|
||||
float ADS1118Sensor::sample() {
|
||||
|
||||
@@ -67,8 +67,10 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||
auto *chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
|
||||
if (chr == nullptr) {
|
||||
ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str());
|
||||
ESP_LOGW(TAG,
|
||||
"[%s] No control service found at device, not an Anova..?\n"
|
||||
"[%s] Note, this component does not currently support Anova Nano.",
|
||||
this->get_name().c_str(), this->get_name().c_str());
|
||||
break;
|
||||
}
|
||||
this->char_handle_ = chr->handle;
|
||||
|
||||
@@ -16,7 +16,7 @@ with warnings.catch_warnings():
|
||||
|
||||
import contextlib
|
||||
|
||||
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
|
||||
from esphome.const import CONF_KEY, CONF_PORT, __version__
|
||||
from esphome.core import CORE
|
||||
|
||||
from . import CONF_ENCRYPTION
|
||||
@@ -35,7 +35,6 @@ async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
conf = config["api"]
|
||||
name = config["esphome"]["name"]
|
||||
port: int = int(conf[CONF_PORT])
|
||||
password: str = conf[CONF_PASSWORD]
|
||||
noise_psk: str | None = None
|
||||
if (encryption := conf.get(CONF_ENCRYPTION)) and (key := encryption.get(CONF_KEY)):
|
||||
noise_psk = key
|
||||
@@ -50,7 +49,7 @@ async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
|
||||
cli = APIClient(
|
||||
addresses[0], # Primary address for compatibility
|
||||
port,
|
||||
password,
|
||||
"", # Password auth removed in 2026.1.0
|
||||
client_info=f"ESPHome Logs {__version__}",
|
||||
noise_psk=noise_psk,
|
||||
addresses=addresses, # Pass all addresses for automatic retry
|
||||
|
||||
@@ -305,12 +305,14 @@ bool AS3935Component::calibrate_oscillator() {
|
||||
}
|
||||
|
||||
void AS3935Component::tune_antenna() {
|
||||
ESP_LOGI(TAG, "Starting antenna tuning");
|
||||
uint8_t div_ratio = this->read_div_ratio();
|
||||
uint8_t tune_val = this->read_capacitance();
|
||||
ESP_LOGI(TAG, "Division Ratio is set to: %d", div_ratio);
|
||||
ESP_LOGI(TAG, "Internal Capacitor is set to: %d", tune_val);
|
||||
ESP_LOGI(TAG, "Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio");
|
||||
ESP_LOGI(TAG,
|
||||
"Starting antenna tuning\n"
|
||||
"Division Ratio is set to: %d\n"
|
||||
"Internal Capacitor is set to: %d\n"
|
||||
"Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio",
|
||||
div_ratio, tune_val);
|
||||
this->display_oscillator(true, ANTFREQ);
|
||||
}
|
||||
|
||||
|
||||
@@ -216,11 +216,14 @@ bool BedJetHub::discover_characteristics_() {
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "[%s] Discovered service characteristics: ", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, " - Command char: 0x%x", this->char_handle_cmd_);
|
||||
ESP_LOGI(TAG, " - Status char: 0x%x", this->char_handle_status_);
|
||||
ESP_LOGI(TAG, " - config descriptor: 0x%x", this->config_descr_status_);
|
||||
ESP_LOGI(TAG, " - Name char: 0x%x", this->char_handle_name_);
|
||||
ESP_LOGI(TAG,
|
||||
"[%s] Discovered service characteristics:\n"
|
||||
" - Command char: 0x%x\n"
|
||||
" - Status char: 0x%x\n"
|
||||
" - config descriptor: 0x%x\n"
|
||||
" - Name char: 0x%x",
|
||||
this->get_name().c_str(), this->char_handle_cmd_, this->char_handle_status_, this->config_descr_status_,
|
||||
this->char_handle_name_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ void MultiClickTrigger::on_state_(bool state) {
|
||||
// Start matching
|
||||
MultiClickTriggerEvent evt = this->timing_[0];
|
||||
if (evt.state == state) {
|
||||
ESP_LOGV(TAG, "START min=%" PRIu32 " max=%" PRIu32, evt.min_length, evt.max_length);
|
||||
ESP_LOGV(TAG, "Multi Click: Starting multi click action!");
|
||||
ESP_LOGV(TAG,
|
||||
"START min=%" PRIu32 " max=%" PRIu32 "\n"
|
||||
"Multi Click: Starting multi click action!",
|
||||
evt.min_length, evt.max_length);
|
||||
this->at_index_ = 1;
|
||||
if (this->timing_.size() == 1 && evt.max_length == 4294967294UL) {
|
||||
this->set_timeout("trigger", evt.min_length, [this]() { this->trigger_(); });
|
||||
|
||||
@@ -103,8 +103,10 @@ void BLENUS::on_log(uint8_t level, const char *tag, const char *message, size_t
|
||||
#endif
|
||||
|
||||
void BLENUS::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ble nus:");
|
||||
ESP_LOGCONFIG(TAG, " log: %s", YESNO(this->expose_log_));
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"ble nus:\n"
|
||||
" log: %s",
|
||||
YESNO(this->expose_log_));
|
||||
uint32_t mtu = 0;
|
||||
bt_conn *conn = this->conn_.load();
|
||||
if (conn) {
|
||||
|
||||
@@ -22,13 +22,13 @@ void BP1658CJ::setup() {
|
||||
this->pwm_amounts_.resize(5, 0);
|
||||
}
|
||||
void BP1658CJ::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "BP1658CJ:");
|
||||
LOG_PIN(" Data Pin: ", this->data_pin_);
|
||||
LOG_PIN(" Clock Pin: ", this->clock_pin_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"BP1658CJ:\n"
|
||||
" Color Channels Max Power: %u\n"
|
||||
" White Channels Max Power: %u",
|
||||
this->max_power_color_channels_, this->max_power_white_channels_);
|
||||
LOG_PIN(" Data Pin: ", this->data_pin_);
|
||||
LOG_PIN(" Clock Pin: ", this->clock_pin_);
|
||||
}
|
||||
|
||||
void BP1658CJ::loop() {
|
||||
|
||||
@@ -63,14 +63,14 @@ void CAP1188Component::finish_setup_() {
|
||||
}
|
||||
|
||||
void CAP1188Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "CAP1188:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"CAP1188:\n"
|
||||
" Product ID: 0x%x\n"
|
||||
" Manufacture ID: 0x%x\n"
|
||||
" Revision ID: 0x%x",
|
||||
this->cap1188_product_id_, this->cap1188_manufacture_id_, this->cap1188_revision_);
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
|
||||
switch (this->error_code_) {
|
||||
case COMMUNICATION_FAILED:
|
||||
|
||||
@@ -49,9 +49,11 @@ void CaptivePortal::handle_config(AsyncWebServerRequest *request) {
|
||||
void CaptivePortal::handle_wifisave(AsyncWebServerRequest *request) {
|
||||
std::string ssid = request->arg("ssid").c_str(); // NOLINT(readability-redundant-string-cstr)
|
||||
std::string psk = request->arg("psk").c_str(); // NOLINT(readability-redundant-string-cstr)
|
||||
ESP_LOGI(TAG, "Requested WiFi Settings Change:");
|
||||
ESP_LOGI(TAG, " SSID='%s'", ssid.c_str());
|
||||
ESP_LOGI(TAG, " Password=" LOG_SECRET("'%s'"), psk.c_str());
|
||||
ESP_LOGI(TAG,
|
||||
"Requested WiFi Settings Change:\n"
|
||||
" SSID='%s'\n"
|
||||
" Password=" LOG_SECRET("'%s'"),
|
||||
ssid.c_str(), psk.c_str());
|
||||
// Defer save to main loop thread to avoid NVS operations from HTTP thread
|
||||
this->defer([ssid, psk]() { wifi::global_wifi_component->save_wifi_sta(ssid, psk); });
|
||||
request->redirect(ESPHOME_F("/?save"));
|
||||
|
||||
@@ -32,14 +32,14 @@ void CHSC6XTouchscreen::update_touches() {
|
||||
}
|
||||
|
||||
void CHSC6XTouchscreen::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "CHSC6X Touchscreen:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"CHSC6X Touchscreen:\n"
|
||||
" Touch timeout: %d\n"
|
||||
" x_raw_max_: %d\n"
|
||||
" y_raw_max_: %d",
|
||||
this->touch_timeout_, this->x_raw_max_, this->y_raw_max_);
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
|
||||
}
|
||||
|
||||
} // namespace chsc6x
|
||||
|
||||
@@ -83,14 +83,14 @@ void CST816Touchscreen::update_touches() {
|
||||
}
|
||||
|
||||
void CST816Touchscreen::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "CST816 Touchscreen:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"CST816 Touchscreen:\n"
|
||||
" X Raw Min: %d, X Raw Max: %d\n"
|
||||
" Y Raw Min: %d, Y Raw Max: %d",
|
||||
this->x_raw_min_, this->x_raw_max_, this->y_raw_min_, this->y_raw_max_);
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
const char *name;
|
||||
switch (this->chip_id_) {
|
||||
case CST716_CHIP_ID:
|
||||
|
||||
@@ -47,14 +47,17 @@ void DebugComponent::get_device_info_(std::string &device_info) {
|
||||
|
||||
#if !defined(CLANG_TIDY)
|
||||
auto reset_reason = get_reset_reason_();
|
||||
ESP_LOGD(TAG, "Chip ID: 0x%08X", ESP.getChipId());
|
||||
ESP_LOGD(TAG, "SDK Version: %s", ESP.getSdkVersion());
|
||||
ESP_LOGD(TAG, "Core Version: %s", ESP.getCoreVersion().c_str());
|
||||
ESP_LOGD(TAG, "Boot Version=%u Mode=%u", ESP.getBootVersion(), ESP.getBootMode());
|
||||
ESP_LOGD(TAG, "CPU Frequency: %u", ESP.getCpuFreqMHz());
|
||||
ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId());
|
||||
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
|
||||
ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str());
|
||||
ESP_LOGD(TAG,
|
||||
"Chip ID: 0x%08X\n"
|
||||
"SDK Version: %s\n"
|
||||
"Core Version: %s\n"
|
||||
"Boot Version=%u Mode=%u\n"
|
||||
"CPU Frequency: %u\n"
|
||||
"Flash Chip ID=0x%08X\n"
|
||||
"Reset Reason: %s\n"
|
||||
"Reset Info: %s",
|
||||
ESP.getChipId(), ESP.getSdkVersion(), ESP.getCoreVersion().c_str(), ESP.getBootVersion(), ESP.getBootMode(),
|
||||
ESP.getCpuFreqMHz(), ESP.getFlashChipId(), reset_reason.c_str(), ESP.getResetInfo().c_str());
|
||||
|
||||
device_info += "|Chip: 0x" + format_hex(ESP.getChipId());
|
||||
device_info += "|SDK: ";
|
||||
|
||||
@@ -13,12 +13,15 @@ uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); }
|
||||
|
||||
void DebugComponent::get_device_info_(std::string &device_info) {
|
||||
std::string reset_reason = get_reset_reason_();
|
||||
ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version());
|
||||
ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz());
|
||||
ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id());
|
||||
ESP_LOGD(TAG, "Board: %s", lt_get_board_code());
|
||||
ESP_LOGD(TAG, "Flash: %u KiB / RAM: %u KiB", lt_flash_get_size() / 1024, lt_ram_get_size() / 1024);
|
||||
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
|
||||
ESP_LOGD(TAG,
|
||||
"LibreTiny Version: %s\n"
|
||||
"Chip: %s (%04x) @ %u MHz\n"
|
||||
"Chip ID: 0x%06X\n"
|
||||
"Board: %s\n"
|
||||
"Flash: %u KiB / RAM: %u KiB\n"
|
||||
"Reset Reason: %s",
|
||||
lt_get_version(), lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz(), lt_cpu_get_mac_id(),
|
||||
lt_get_board_code(), lt_flash_get_size() / 1024, lt_ram_get_size() / 1024, reset_reason.c_str());
|
||||
|
||||
device_info += "|Version: ";
|
||||
device_info += LT_BANNER_STR + 10;
|
||||
|
||||
@@ -106,13 +106,13 @@ static void fa_cb(const struct flash_area *fa, void *user_data) {
|
||||
void DebugComponent::log_partition_info_() {
|
||||
#if CONFIG_FLASH_MAP_LABELS
|
||||
ESP_LOGCONFIG(TAG, "ID | Device | Device Name "
|
||||
"| Label | Offset | Size");
|
||||
ESP_LOGCONFIG(TAG, "--------------------------------------------"
|
||||
"| Label | Offset | Size\n"
|
||||
"--------------------------------------------"
|
||||
"-----------------------------------------------");
|
||||
#else
|
||||
ESP_LOGCONFIG(TAG, "ID | Device | Device Name "
|
||||
"| Offset | Size");
|
||||
ESP_LOGCONFIG(TAG, "-----------------------------------------"
|
||||
"| Offset | Size\n"
|
||||
"-----------------------------------------"
|
||||
"------------------------------");
|
||||
#endif
|
||||
flash_area_foreach(fa_cb, nullptr);
|
||||
@@ -300,18 +300,18 @@ void DebugComponent::get_device_info_(std::string &device_info) {
|
||||
return "Unspecified";
|
||||
};
|
||||
|
||||
ESP_LOGD(TAG, "Code page size: %u, code size: %u, device id: 0x%08x%08x", NRF_FICR->CODEPAGESIZE, NRF_FICR->CODESIZE,
|
||||
NRF_FICR->DEVICEID[1], NRF_FICR->DEVICEID[0]);
|
||||
ESP_LOGD(TAG, "Encryption root: 0x%08x%08x%08x%08x, Identity Root: 0x%08x%08x%08x%08x", NRF_FICR->ER[0],
|
||||
ESP_LOGD(TAG,
|
||||
"Code page size: %u, code size: %u, device id: 0x%08x%08x\n"
|
||||
"Encryption root: 0x%08x%08x%08x%08x, Identity Root: 0x%08x%08x%08x%08x\n"
|
||||
"Device address type: %s, address: %s\n"
|
||||
"Part code: nRF%x, version: %c%c%c%c, package: %s\n"
|
||||
"RAM: %ukB, Flash: %ukB, production test: %sdone",
|
||||
NRF_FICR->CODEPAGESIZE, NRF_FICR->CODESIZE, NRF_FICR->DEVICEID[1], NRF_FICR->DEVICEID[0], NRF_FICR->ER[0],
|
||||
NRF_FICR->ER[1], NRF_FICR->ER[2], NRF_FICR->ER[3], NRF_FICR->IR[0], NRF_FICR->IR[1], NRF_FICR->IR[2],
|
||||
NRF_FICR->IR[3]);
|
||||
ESP_LOGD(TAG, "Device address type: %s, address: %s", (NRF_FICR->DEVICEADDRTYPE & 0x1 ? "Random" : "Public"),
|
||||
get_mac_address_pretty().c_str());
|
||||
ESP_LOGD(TAG, "Part code: nRF%x, version: %c%c%c%c, package: %s", NRF_FICR->INFO.PART,
|
||||
NRF_FICR->INFO.VARIANT >> 24 & 0xFF, NRF_FICR->INFO.VARIANT >> 16 & 0xFF, NRF_FICR->INFO.VARIANT >> 8 & 0xFF,
|
||||
NRF_FICR->INFO.VARIANT & 0xFF, package(NRF_FICR->INFO.PACKAGE));
|
||||
ESP_LOGD(TAG, "RAM: %ukB, Flash: %ukB, production test: %sdone", NRF_FICR->INFO.RAM, NRF_FICR->INFO.FLASH,
|
||||
(NRF_FICR->PRODTEST[0] == 0xBB42319F ? "" : "not "));
|
||||
NRF_FICR->IR[3], (NRF_FICR->DEVICEADDRTYPE & 0x1 ? "Random" : "Public"), get_mac_address_pretty().c_str(),
|
||||
NRF_FICR->INFO.PART, NRF_FICR->INFO.VARIANT >> 24 & 0xFF, NRF_FICR->INFO.VARIANT >> 16 & 0xFF,
|
||||
NRF_FICR->INFO.VARIANT >> 8 & 0xFF, NRF_FICR->INFO.VARIANT & 0xFF, package(NRF_FICR->INFO.PACKAGE),
|
||||
NRF_FICR->INFO.RAM, NRF_FICR->INFO.FLASH, (NRF_FICR->PRODTEST[0] == 0xBB42319F ? "" : "not "));
|
||||
bool n_reset_enabled = NRF_UICR->PSELRESET[0] == NRF_UICR->PSELRESET[1] &&
|
||||
(NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) == UICR_PSELRESET_CONNECT_Connected
|
||||
<< UICR_PSELRESET_CONNECT_Pos;
|
||||
@@ -329,9 +329,10 @@ void DebugComponent::get_device_info_(std::string &device_info) {
|
||||
#else
|
||||
ESP_LOGD(TAG, "bootloader: Adafruit, version %u.%u.%u", (BOOTLOADER_VERSION_REGISTER >> 16) & 0xFF,
|
||||
(BOOTLOADER_VERSION_REGISTER >> 8) & 0xFF, BOOTLOADER_VERSION_REGISTER & 0xFF);
|
||||
ESP_LOGD(TAG, "MBR bootloader addr 0x%08x, UICR bootloader addr 0x%08x", read_mem_u32(MBR_BOOTLOADER_ADDR),
|
||||
NRF_UICR->NRFFW[0]);
|
||||
ESP_LOGD(TAG, "MBR param page addr 0x%08x, UICR param page addr 0x%08x", read_mem_u32(MBR_PARAM_PAGE_ADDR),
|
||||
ESP_LOGD(TAG,
|
||||
"MBR bootloader addr 0x%08x, UICR bootloader addr 0x%08x\n"
|
||||
"MBR param page addr 0x%08x, UICR param page addr 0x%08x",
|
||||
read_mem_u32(MBR_BOOTLOADER_ADDR), NRF_UICR->NRFFW[0], read_mem_u32(MBR_PARAM_PAGE_ADDR),
|
||||
NRF_UICR->NRFFW[1]);
|
||||
if (is_sd_present()) {
|
||||
uint32_t const sd_id = sd_id_get();
|
||||
@@ -368,8 +369,10 @@ void DebugComponent::get_device_info_(std::string &device_info) {
|
||||
}
|
||||
return res;
|
||||
};
|
||||
ESP_LOGD(TAG, "NRFFW %s", uicr(NRF_UICR->NRFFW, 13).c_str());
|
||||
ESP_LOGD(TAG, "NRFHW %s", uicr(NRF_UICR->NRFHW, 12).c_str());
|
||||
ESP_LOGD(TAG,
|
||||
"NRFFW %s\n"
|
||||
"NRFHW %s",
|
||||
uicr(NRF_UICR->NRFFW, 13).c_str(), uicr(NRF_UICR->NRFHW, 12).c_str());
|
||||
}
|
||||
|
||||
void DebugComponent::update_platform_() {}
|
||||
|
||||
@@ -17,11 +17,14 @@ void DHT::setup() {
|
||||
}
|
||||
|
||||
void DHT::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "DHT:");
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"DHT:\n"
|
||||
" %sModel: %s\n"
|
||||
" Internal pull-up: %s",
|
||||
this->is_auto_detect_ ? "Auto-detected " : "",
|
||||
this->model_ == DHT_MODEL_DHT11 ? "DHT11" : "DHT22 or equivalent",
|
||||
ONOFF(this->t_pin_->get_flags() & gpio::FLAG_PULLUP));
|
||||
LOG_PIN(" Pin: ", this->t_pin_);
|
||||
ESP_LOGCONFIG(TAG, " %sModel: %s", this->is_auto_detect_ ? "Auto-detected " : "",
|
||||
this->model_ == DHT_MODEL_DHT11 ? "DHT11" : "DHT22 or equivalent");
|
||||
ESP_LOGCONFIG(TAG, " Internal pull-up: %s", ONOFF(this->t_pin_->get_flags() & gpio::FLAG_PULLUP));
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
|
||||
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
|
||||
|
||||
@@ -104,10 +104,12 @@ void EndstopCover::loop() {
|
||||
}
|
||||
void EndstopCover::dump_config() {
|
||||
LOG_COVER("", "Endstop Cover", this);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Open Duration: %.1fs\n"
|
||||
" Close Duration: %.1fs",
|
||||
this->open_duration_ / 1e3f, this->close_duration_ / 1e3f);
|
||||
LOG_BINARY_SENSOR(" ", "Open Endstop", this->open_endstop_);
|
||||
ESP_LOGCONFIG(TAG, " Open Duration: %.1fs", this->open_duration_ / 1e3f);
|
||||
LOG_BINARY_SENSOR(" ", "Close Endstop", this->close_endstop_);
|
||||
ESP_LOGCONFIG(TAG, " Close Duration: %.1fs", this->close_duration_ / 1e3f);
|
||||
}
|
||||
float EndstopCover::get_setup_priority() const { return setup_priority::DATA; }
|
||||
void EndstopCover::stop_prev_trigger_() {
|
||||
|
||||
@@ -331,20 +331,21 @@ void HOT EPaperBase::draw_pixel_at(int x, int y, Color color) {
|
||||
|
||||
void EPaperBase::dump_config() {
|
||||
LOG_DISPLAY("", "E-Paper SPI", this);
|
||||
ESP_LOGCONFIG(TAG, " Model: %s", this->name_);
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Model: %s\n"
|
||||
" SPI Data Rate: %uMHz\n"
|
||||
" Full update every: %d\n"
|
||||
" Swap X/Y: %s\n"
|
||||
" Mirror X: %s\n"
|
||||
" Mirror Y: %s",
|
||||
(unsigned) (this->data_rate_ / 1000000), this->full_update_every_, YESNO(this->transform_ & SWAP_XY),
|
||||
YESNO(this->transform_ & MIRROR_X), YESNO(this->transform_ & MIRROR_Y));
|
||||
this->name_, (unsigned) (this->data_rate_ / 1000000), this->full_update_every_,
|
||||
YESNO(this->transform_ & SWAP_XY), YESNO(this->transform_ & MIRROR_X),
|
||||
YESNO(this->transform_ & MIRROR_Y));
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
} // namespace esphome::epaper_spi
|
||||
|
||||
@@ -644,6 +644,7 @@ CONF_DISABLE_VFS_SUPPORT_SELECT = "disable_vfs_support_select"
|
||||
CONF_DISABLE_VFS_SUPPORT_DIR = "disable_vfs_support_dir"
|
||||
CONF_FREERTOS_IN_IRAM = "freertos_in_iram"
|
||||
CONF_RINGBUF_IN_IRAM = "ringbuf_in_iram"
|
||||
CONF_HEAP_IN_IRAM = "heap_in_iram"
|
||||
CONF_LOOP_TASK_STACK_SIZE = "loop_task_stack_size"
|
||||
|
||||
# VFS requirement tracking
|
||||
@@ -745,6 +746,7 @@ FRAMEWORK_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_DISABLE_VFS_SUPPORT_DIR, default=True): cv.boolean,
|
||||
cv.Optional(CONF_FREERTOS_IN_IRAM, default=False): cv.boolean,
|
||||
cv.Optional(CONF_RINGBUF_IN_IRAM, default=False): cv.boolean,
|
||||
cv.Optional(CONF_HEAP_IN_IRAM, default=False): cv.boolean,
|
||||
cv.Optional(CONF_EXECUTE_FROM_PSRAM, default=False): cv.boolean,
|
||||
cv.Optional(CONF_LOOP_TASK_STACK_SIZE, default=8192): cv.int_range(
|
||||
min=8192, max=32768
|
||||
@@ -1090,6 +1092,12 @@ async def to_code(config):
|
||||
# Place in flash to save IRAM (default)
|
||||
add_idf_sdkconfig_option("CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH", True)
|
||||
|
||||
# Place heap functions into flash to save IRAM (~4-6KB savings)
|
||||
# Safe as long as heap functions are not called from ISRs (which they shouldn't be)
|
||||
# Users can set heap_in_iram: true as an escape hatch if needed
|
||||
if not conf[CONF_ADVANCED][CONF_HEAP_IN_IRAM]:
|
||||
add_idf_sdkconfig_option("CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH", True)
|
||||
|
||||
# Setup watchdog
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_PANIC", True)
|
||||
|
||||
@@ -70,9 +70,9 @@ float BLEClientBase::get_setup_priority() const { return setup_priority::AFTER_B
|
||||
void BLEClientBase::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Address: %s\n"
|
||||
" Auto-Connect: %s",
|
||||
this->address_str(), TRUEFALSE(this->auto_connect_));
|
||||
ESP_LOGCONFIG(TAG, " State: %s", espbt::client_state_to_string(this->state()));
|
||||
" Auto-Connect: %s\n"
|
||||
" State: %s",
|
||||
this->address_str(), TRUEFALSE(this->auto_connect_), espbt::client_state_to_string(this->state()));
|
||||
if (this->status_ == ESP_GATT_NO_RESOURCES) {
|
||||
ESP_LOGE(TAG, " Failed due to no resources. Try to reduce number of BLE clients in config.");
|
||||
} else if (this->status_ != ESP_GATT_OK) {
|
||||
@@ -415,8 +415,10 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
for (auto &svc : this->services_) {
|
||||
char uuid_buf[espbt::UUID_STR_LEN];
|
||||
svc->uuid.to_str(uuid_buf);
|
||||
ESP_LOGV(TAG, "[%d] [%s] Service UUID: %s", this->connection_index_, this->address_str_, uuid_buf);
|
||||
ESP_LOGV(TAG, "[%d] [%s] start_handle: 0x%x end_handle: 0x%x", this->connection_index_, this->address_str_,
|
||||
ESP_LOGV(TAG,
|
||||
"[%d] [%s] Service UUID: %s\n"
|
||||
"[%d] [%s] start_handle: 0x%x end_handle: 0x%x",
|
||||
this->connection_index_, this->address_str_, uuid_buf, this->connection_index_, this->address_str_,
|
||||
svc->start_handle, svc->end_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -657,8 +657,10 @@ void ESP32BLETracker::dump_config() {
|
||||
" Continuous Scanning: %s",
|
||||
this->scan_duration_, this->scan_interval_ * 0.625f, this->scan_window_ * 0.625f,
|
||||
this->scan_active_ ? "ACTIVE" : "PASSIVE", YESNO(this->scan_continuous_));
|
||||
ESP_LOGCONFIG(TAG, " Scanner State: %s", this->scanner_state_to_string_(this->scanner_state_));
|
||||
ESP_LOGCONFIG(TAG, " Connecting: %d, discovered: %d, disconnecting: %d", this->client_state_counts_.connecting,
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Scanner State: %s\n"
|
||||
" Connecting: %d, discovered: %d, disconnecting: %d",
|
||||
this->scanner_state_to_string_(this->scanner_state_), this->client_state_counts_.connecting,
|
||||
this->client_state_counts_.discovered, this->client_state_counts_.disconnecting);
|
||||
if (this->scan_start_fail_count_) {
|
||||
ESP_LOGCONFIG(TAG, " Scan Start Fail Count: %d", this->scan_start_fail_count_);
|
||||
|
||||
@@ -98,7 +98,7 @@ void ESP32RMTLEDStripLightOutput::setup() {
|
||||
channel.trans_queue_depth = 1;
|
||||
channel.flags.io_loop_back = 0;
|
||||
channel.flags.io_od_mode = 0;
|
||||
channel.flags.invert_out = 0;
|
||||
channel.flags.invert_out = this->invert_out_;
|
||||
channel.flags.with_dma = this->use_dma_;
|
||||
channel.intr_priority = 0;
|
||||
if (rmt_new_tx_channel(&channel, &this->channel_) != ESP_OK) {
|
||||
|
||||
@@ -49,6 +49,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
|
||||
}
|
||||
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
void set_inverted(bool inverted) { this->invert_out_ = inverted; }
|
||||
void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; }
|
||||
void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; }
|
||||
void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; }
|
||||
@@ -93,6 +94,7 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
|
||||
bool is_wrgb_{false};
|
||||
bool use_dma_{false};
|
||||
bool use_psram_{false};
|
||||
bool invert_out_{false};
|
||||
|
||||
RGBOrder rgb_order_{ORDER_RGB};
|
||||
|
||||
|
||||
@@ -8,9 +8,11 @@ from esphome.components.const import CONF_USE_PSRAM
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_CHIPSET,
|
||||
CONF_INVERTED,
|
||||
CONF_IS_RGBW,
|
||||
CONF_MAX_REFRESH_RATE,
|
||||
CONF_NUM_LEDS,
|
||||
CONF_NUMBER,
|
||||
CONF_OUTPUT_ID,
|
||||
CONF_PIN,
|
||||
CONF_RGB_ORDER,
|
||||
@@ -71,7 +73,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
light.ADDRESSABLE_LIGHT_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(ESP32RMTLEDStripLightOutput),
|
||||
cv.Required(CONF_PIN): pins.internal_gpio_output_pin_number,
|
||||
cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema,
|
||||
cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
|
||||
cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True),
|
||||
cv.SplitDefault(
|
||||
@@ -132,7 +134,9 @@ async def to_code(config):
|
||||
await cg.register_component(var, config)
|
||||
|
||||
cg.add(var.set_num_leds(config[CONF_NUM_LEDS]))
|
||||
cg.add(var.set_pin(config[CONF_PIN]))
|
||||
cg.add(var.set_pin(config[CONF_PIN][CONF_NUMBER]))
|
||||
if config[CONF_PIN][CONF_INVERTED]:
|
||||
cg.add(var.set_inverted(True))
|
||||
|
||||
if CONF_MAX_REFRESH_RATE in config:
|
||||
cg.add(var.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE]))
|
||||
|
||||
@@ -18,9 +18,11 @@ void ESP8266PWM::setup() {
|
||||
this->turn_off();
|
||||
}
|
||||
void ESP8266PWM::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ESP8266 PWM:");
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"ESP8266 PWM:\n"
|
||||
" Frequency: %.1f Hz",
|
||||
this->frequency_);
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
ESP_LOGCONFIG(TAG, " Frequency: %.1f Hz", this->frequency_);
|
||||
LOG_FLOAT_OUTPUT(this);
|
||||
}
|
||||
void HOT ESP8266PWM::write_state(float state) {
|
||||
|
||||
@@ -21,9 +21,11 @@ void EspLdo::setup() {
|
||||
}
|
||||
}
|
||||
void EspLdo::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ESP LDO Channel %d:", this->channel_);
|
||||
ESP_LOGCONFIG(TAG, " Voltage: %fV", this->voltage_);
|
||||
ESP_LOGCONFIG(TAG, " Adjustable: %s", YESNO(this->adjustable_));
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"ESP LDO Channel %d:\n"
|
||||
" Voltage: %fV\n"
|
||||
" Adjustable: %s",
|
||||
this->channel_, this->voltage_, YESNO(this->adjustable_));
|
||||
}
|
||||
|
||||
void EspLdo::adjust_voltage(float voltage) {
|
||||
|
||||
@@ -64,18 +64,6 @@ static const LogString *espnow_error_to_str(esp_err_t error) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string peer_str(uint8_t *peer) {
|
||||
if (peer == nullptr || peer[0] == 0) {
|
||||
return "[Not Set]";
|
||||
} else if (memcmp(peer, ESPNOW_BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0) {
|
||||
return "[Broadcast]";
|
||||
} else if (memcmp(peer, ESPNOW_MULTICAST_ADDR, ESP_NOW_ETH_ALEN) == 0) {
|
||||
return "[Multicast]";
|
||||
} else {
|
||||
return format_mac_address_pretty(peer);
|
||||
}
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
|
||||
void on_send_report(const esp_now_send_info_t *info, esp_now_send_status_t status)
|
||||
#else
|
||||
@@ -140,11 +128,13 @@ void ESPNowComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Disabled");
|
||||
return;
|
||||
}
|
||||
char own_addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(this->own_address_, own_addr_buf);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Own address: %s\n"
|
||||
" Version: v%" PRIu32 "\n"
|
||||
" Wi-Fi channel: %d",
|
||||
format_mac_address_pretty(this->own_address_).c_str(), version, this->wifi_channel_);
|
||||
own_addr_buf, version, this->wifi_channel_);
|
||||
#ifdef USE_WIFI
|
||||
ESP_LOGCONFIG(TAG, " Wi-Fi enabled: %s", YESNO(this->is_wifi_enabled()));
|
||||
#endif
|
||||
@@ -300,9 +290,12 @@ void ESPNowComponent::loop() {
|
||||
// Intentionally left as if instead of else in case the peer is added above
|
||||
if (esp_now_is_peer_exist(info.src_addr)) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char src_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
char dst_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
char hex_buf[format_hex_pretty_size(ESP_NOW_MAX_DATA_LEN)];
|
||||
ESP_LOGV(TAG, "<<< [%s -> %s] %s", format_mac_address_pretty(info.src_addr).c_str(),
|
||||
format_mac_address_pretty(info.des_addr).c_str(),
|
||||
format_mac_addr_upper(info.src_addr, src_buf);
|
||||
format_mac_addr_upper(info.des_addr, dst_buf);
|
||||
ESP_LOGV(TAG, "<<< [%s -> %s] %s", src_buf, dst_buf,
|
||||
format_hex_pretty_to(hex_buf, packet->packet_.receive.data, packet->packet_.receive.size));
|
||||
#endif
|
||||
if (memcmp(info.des_addr, ESPNOW_BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0) {
|
||||
@@ -321,8 +314,9 @@ void ESPNowComponent::loop() {
|
||||
}
|
||||
case ESPNowPacket::SENT: {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
ESP_LOGV(TAG, ">>> [%s] %s", format_mac_address_pretty(packet->packet_.sent.address).c_str(),
|
||||
LOG_STR_ARG(espnow_error_to_str(packet->packet_.sent.status)));
|
||||
char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(packet->packet_.sent.address, addr_buf);
|
||||
ESP_LOGV(TAG, ">>> [%s] %s", addr_buf, LOG_STR_ARG(espnow_error_to_str(packet->packet_.sent.status)));
|
||||
#endif
|
||||
if (this->current_send_packet_ != nullptr) {
|
||||
this->current_send_packet_->callback_(packet->packet_.sent.status);
|
||||
@@ -409,8 +403,9 @@ void ESPNowComponent::send_() {
|
||||
this->current_send_packet_ = packet;
|
||||
esp_err_t err = esp_now_send(packet->address_, packet->data_, packet->size_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send packet to %s - %s", format_mac_address_pretty(packet->address_).c_str(),
|
||||
LOG_STR_ARG(espnow_error_to_str(err)));
|
||||
char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(packet->address_, addr_buf);
|
||||
ESP_LOGE(TAG, "Failed to send packet to %s - %s", addr_buf, LOG_STR_ARG(espnow_error_to_str(err)));
|
||||
if (packet->callback_ != nullptr) {
|
||||
packet->callback_(err);
|
||||
}
|
||||
@@ -439,8 +434,9 @@ esp_err_t ESPNowComponent::add_peer(const uint8_t *peer) {
|
||||
esp_err_t err = esp_now_add_peer(&peer_info);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to add peer %s - %s", format_mac_address_pretty(peer).c_str(),
|
||||
LOG_STR_ARG(espnow_error_to_str(err)));
|
||||
char peer_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(peer, peer_buf);
|
||||
ESP_LOGE(TAG, "Failed to add peer %s - %s", peer_buf, LOG_STR_ARG(espnow_error_to_str(err)));
|
||||
this->status_momentary_warning("peer-add-failed");
|
||||
return err;
|
||||
}
|
||||
@@ -468,8 +464,9 @@ esp_err_t ESPNowComponent::del_peer(const uint8_t *peer) {
|
||||
if (esp_now_is_peer_exist(peer)) {
|
||||
esp_err_t err = esp_now_del_peer(peer);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to delete peer %s - %s", format_mac_address_pretty(peer).c_str(),
|
||||
LOG_STR_ARG(espnow_error_to_str(err)));
|
||||
char peer_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(peer, peer_buf);
|
||||
ESP_LOGE(TAG, "Failed to delete peer %s - %s", peer_buf, LOG_STR_ARG(espnow_error_to_str(err)));
|
||||
this->status_momentary_warning("peer-del-failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,11 @@ void ESPNowTransport::setup() {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Registering ESP-NOW handlers");
|
||||
ESP_LOGI(TAG, "Peer address: %02X:%02X:%02X:%02X:%02X:%02X", this->peer_address_[0], this->peer_address_[1],
|
||||
this->peer_address_[2], this->peer_address_[3], this->peer_address_[4], this->peer_address_[5]);
|
||||
ESP_LOGI(TAG,
|
||||
"Registering ESP-NOW handlers\n"
|
||||
"Peer address: %02X:%02X:%02X:%02X:%02X:%02X",
|
||||
this->peer_address_[0], this->peer_address_[1], this->peer_address_[2], this->peer_address_[3],
|
||||
this->peer_address_[4], this->peer_address_[5]);
|
||||
|
||||
// Register received handler
|
||||
this->parent_->register_received_handler(this);
|
||||
|
||||
@@ -813,8 +813,10 @@ void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister regi
|
||||
ESPHL_ERROR_CHECK(err, "Select PHY Register page failed");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Writing to PHY Register Address: 0x%02" PRIX32, register_data.address);
|
||||
ESP_LOGD(TAG, "Writing to PHY Register Value: 0x%04" PRIX32, register_data.value);
|
||||
ESP_LOGD(TAG,
|
||||
"Writing to PHY Register Address: 0x%02" PRIX32 "\n"
|
||||
"Writing to PHY Register Value: 0x%04" PRIX32,
|
||||
register_data.address, register_data.value);
|
||||
err = mac->write_phy_reg(mac, this->phy_addr_, register_data.address, register_data.value);
|
||||
ESPHL_ERROR_CHECK(err, "Writing PHY Register failed");
|
||||
|
||||
|
||||
@@ -148,10 +148,13 @@ void EzoPMP::read_command_result_() {
|
||||
char current_char = response_buffer[i];
|
||||
|
||||
if (current_char == '\0') {
|
||||
ESP_LOGV(TAG, "Read Response from device: %s", (char *) response_buffer);
|
||||
ESP_LOGV(TAG, "First Component: %s", (char *) first_parameter_buffer);
|
||||
ESP_LOGV(TAG, "Second Component: %s", (char *) second_parameter_buffer);
|
||||
ESP_LOGV(TAG, "Third Component: %s", (char *) third_parameter_buffer);
|
||||
ESP_LOGV(TAG,
|
||||
"Read Response from device: %s\n"
|
||||
"First Component: %s\n"
|
||||
"Second Component: %s\n"
|
||||
"Third Component: %s",
|
||||
(char *) response_buffer, (char *) first_parameter_buffer, (char *) second_parameter_buffer,
|
||||
(char *) third_parameter_buffer);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -179,8 +179,10 @@ void Fan::add_on_state_callback(std::function<void()> &&callback) { this->state_
|
||||
void Fan::publish_state() {
|
||||
auto traits = this->get_traits();
|
||||
|
||||
ESP_LOGD(TAG, "'%s' - Sending state:", this->name_.c_str());
|
||||
ESP_LOGD(TAG, " State: %s", ONOFF(this->state));
|
||||
ESP_LOGD(TAG,
|
||||
"'%s' - Sending state:\n"
|
||||
" State: %s",
|
||||
this->name_.c_str(), ONOFF(this->state));
|
||||
if (traits.supports_speed()) {
|
||||
ESP_LOGD(TAG, " Speed: %d", this->speed);
|
||||
}
|
||||
|
||||
@@ -105,9 +105,8 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
|
||||
|
||||
// we will compute MD5 on the fly for verification -- Arduino OTA seems to ignore it
|
||||
md5_receive.init();
|
||||
ESP_LOGV(TAG, "MD5Digest initialized");
|
||||
|
||||
ESP_LOGV(TAG, "OTA backend begin");
|
||||
ESP_LOGV(TAG, "MD5Digest initialized\n"
|
||||
"OTA backend begin");
|
||||
auto backend = ota::make_ota_backend();
|
||||
auto error_code = backend->begin(container->content_length);
|
||||
if (error_code != ota::OTA_RESPONSE_OK) {
|
||||
|
||||
@@ -250,7 +250,7 @@ async def register_i2c_device(var, config):
|
||||
|
||||
Sets the i2c bus to use and the i2c address.
|
||||
|
||||
This is a coroutine, you need to await it with a 'yield' expression!
|
||||
This is a coroutine, you need to await it with an 'await' expression!
|
||||
"""
|
||||
parent = await cg.get_variable(config[CONF_I2C_ID])
|
||||
cg.add(var.set_i2c_bus(parent))
|
||||
|
||||
@@ -386,7 +386,7 @@ async def to_code(config):
|
||||
except cv.Invalid:
|
||||
pass
|
||||
|
||||
if CORE.using_zephyr:
|
||||
if CORE.is_nrf52:
|
||||
if config[CONF_HARDWARE_UART] == UART0:
|
||||
zephyr_add_overlay("""&uart0 { status = "okay";};""")
|
||||
if config[CONF_HARDWARE_UART] == UART1:
|
||||
|
||||
@@ -66,6 +66,8 @@ void Logger::pre_setup() {
|
||||
void HOT Logger::write_msg_(const char *msg, size_t len) {
|
||||
// Single write with newline already in buffer (added by caller)
|
||||
#ifdef CONFIG_PRINTK
|
||||
// Requires the debug component and an active SWD connection.
|
||||
// It is used for pyocd rtt -t nrf52840
|
||||
k_str_out(const_cast<char *>(msg), len);
|
||||
#endif
|
||||
if (this->uart_dev_ == nullptr) {
|
||||
|
||||
@@ -13,6 +13,9 @@ static const uint8_t MHZ19_COMMAND_GET_PPM[] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x
|
||||
static const uint8_t MHZ19_COMMAND_ABC_ENABLE[] = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00};
|
||||
static const uint8_t MHZ19_COMMAND_ABC_DISABLE[] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
static const uint8_t MHZ19_COMMAND_CALIBRATE_ZERO[] = {0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
static const uint8_t MHZ19_COMMAND_DETECTION_RANGE_0_2000PPM[] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x07, 0xD0};
|
||||
static const uint8_t MHZ19_COMMAND_DETECTION_RANGE_0_5000PPM[] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x13, 0x88};
|
||||
static const uint8_t MHZ19_COMMAND_DETECTION_RANGE_0_10000PPM[] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x27, 0x10};
|
||||
|
||||
uint8_t mhz19_checksum(const uint8_t *command) {
|
||||
uint8_t sum = 0;
|
||||
@@ -28,6 +31,8 @@ void MHZ19Component::setup() {
|
||||
} else if (this->abc_boot_logic_ == MHZ19_ABC_DISABLED) {
|
||||
this->abc_disable();
|
||||
}
|
||||
|
||||
this->range_set(this->detection_range_);
|
||||
}
|
||||
|
||||
void MHZ19Component::update() {
|
||||
@@ -86,6 +91,26 @@ void MHZ19Component::abc_disable() {
|
||||
this->mhz19_write_command_(MHZ19_COMMAND_ABC_DISABLE, nullptr);
|
||||
}
|
||||
|
||||
void MHZ19Component::range_set(MHZ19DetectionRange detection_ppm) {
|
||||
switch (detection_ppm) {
|
||||
case MHZ19_DETECTION_RANGE_DEFAULT:
|
||||
ESP_LOGV(TAG, "Using previously set detection range (no change)");
|
||||
break;
|
||||
case MHZ19_DETECTION_RANGE_0_2000PPM:
|
||||
ESP_LOGD(TAG, "Setting detection range to 0 to 2000ppm");
|
||||
this->mhz19_write_command_(MHZ19_COMMAND_DETECTION_RANGE_0_2000PPM, nullptr);
|
||||
break;
|
||||
case MHZ19_DETECTION_RANGE_0_5000PPM:
|
||||
ESP_LOGD(TAG, "Setting detection range to 0 to 5000ppm");
|
||||
this->mhz19_write_command_(MHZ19_COMMAND_DETECTION_RANGE_0_5000PPM, nullptr);
|
||||
break;
|
||||
case MHZ19_DETECTION_RANGE_0_10000PPM:
|
||||
ESP_LOGD(TAG, "Setting detection range to 0 to 10000ppm");
|
||||
this->mhz19_write_command_(MHZ19_COMMAND_DETECTION_RANGE_0_10000PPM, nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MHZ19Component::mhz19_write_command_(const uint8_t *command, uint8_t *response) {
|
||||
// Empty RX Buffer
|
||||
while (this->available())
|
||||
@@ -99,7 +124,9 @@ bool MHZ19Component::mhz19_write_command_(const uint8_t *command, uint8_t *respo
|
||||
|
||||
return this->read_array(response, MHZ19_RESPONSE_LENGTH);
|
||||
}
|
||||
|
||||
float MHZ19Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
void MHZ19Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MH-Z19:");
|
||||
LOG_SENSOR(" ", "CO2", this->co2_sensor_);
|
||||
@@ -113,6 +140,23 @@ void MHZ19Component::dump_config() {
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(TAG, " Warmup time: %" PRIu32 " s", this->warmup_seconds_);
|
||||
|
||||
const char *range_str;
|
||||
switch (this->detection_range_) {
|
||||
case MHZ19_DETECTION_RANGE_DEFAULT:
|
||||
range_str = "default";
|
||||
break;
|
||||
case MHZ19_DETECTION_RANGE_0_2000PPM:
|
||||
range_str = "0 to 2000ppm";
|
||||
break;
|
||||
case MHZ19_DETECTION_RANGE_0_5000PPM:
|
||||
range_str = "0 to 5000ppm";
|
||||
break;
|
||||
case MHZ19_DETECTION_RANGE_0_10000PPM:
|
||||
range_str = "0 to 10000ppm";
|
||||
break;
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Detection range: %s", range_str);
|
||||
}
|
||||
|
||||
} // namespace mhz19
|
||||
|
||||
@@ -8,7 +8,18 @@
|
||||
namespace esphome {
|
||||
namespace mhz19 {
|
||||
|
||||
enum MHZ19ABCLogic { MHZ19_ABC_NONE = 0, MHZ19_ABC_ENABLED, MHZ19_ABC_DISABLED };
|
||||
enum MHZ19ABCLogic {
|
||||
MHZ19_ABC_NONE = 0,
|
||||
MHZ19_ABC_ENABLED,
|
||||
MHZ19_ABC_DISABLED,
|
||||
};
|
||||
|
||||
enum MHZ19DetectionRange {
|
||||
MHZ19_DETECTION_RANGE_DEFAULT = 0,
|
||||
MHZ19_DETECTION_RANGE_0_2000PPM,
|
||||
MHZ19_DETECTION_RANGE_0_5000PPM,
|
||||
MHZ19_DETECTION_RANGE_0_10000PPM,
|
||||
};
|
||||
|
||||
class MHZ19Component : public PollingComponent, public uart::UARTDevice {
|
||||
public:
|
||||
@@ -21,11 +32,13 @@ class MHZ19Component : public PollingComponent, public uart::UARTDevice {
|
||||
void calibrate_zero();
|
||||
void abc_enable();
|
||||
void abc_disable();
|
||||
void range_set(MHZ19DetectionRange detection_ppm);
|
||||
|
||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
|
||||
void set_co2_sensor(sensor::Sensor *co2_sensor) { co2_sensor_ = co2_sensor; }
|
||||
void set_abc_enabled(bool abc_enabled) { abc_boot_logic_ = abc_enabled ? MHZ19_ABC_ENABLED : MHZ19_ABC_DISABLED; }
|
||||
void set_warmup_seconds(uint32_t seconds) { warmup_seconds_ = seconds; }
|
||||
void set_detection_range(MHZ19DetectionRange detection_range) { detection_range_ = detection_range; }
|
||||
|
||||
protected:
|
||||
bool mhz19_write_command_(const uint8_t *command, uint8_t *response);
|
||||
@@ -33,37 +46,32 @@ class MHZ19Component : public PollingComponent, public uart::UARTDevice {
|
||||
sensor::Sensor *temperature_sensor_{nullptr};
|
||||
sensor::Sensor *co2_sensor_{nullptr};
|
||||
MHZ19ABCLogic abc_boot_logic_{MHZ19_ABC_NONE};
|
||||
|
||||
uint32_t warmup_seconds_;
|
||||
|
||||
MHZ19DetectionRange detection_range_{MHZ19_DETECTION_RANGE_DEFAULT};
|
||||
};
|
||||
|
||||
template<typename... Ts> class MHZ19CalibrateZeroAction : public Action<Ts...> {
|
||||
template<typename... Ts> class MHZ19CalibrateZeroAction : public Action<Ts...>, public Parented<MHZ19Component> {
|
||||
public:
|
||||
MHZ19CalibrateZeroAction(MHZ19Component *mhz19) : mhz19_(mhz19) {}
|
||||
|
||||
void play(const Ts &...x) override { this->mhz19_->calibrate_zero(); }
|
||||
|
||||
protected:
|
||||
MHZ19Component *mhz19_;
|
||||
void play(const Ts &...x) override { this->parent_->calibrate_zero(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class MHZ19ABCEnableAction : public Action<Ts...> {
|
||||
template<typename... Ts> class MHZ19ABCEnableAction : public Action<Ts...>, public Parented<MHZ19Component> {
|
||||
public:
|
||||
MHZ19ABCEnableAction(MHZ19Component *mhz19) : mhz19_(mhz19) {}
|
||||
|
||||
void play(const Ts &...x) override { this->mhz19_->abc_enable(); }
|
||||
|
||||
protected:
|
||||
MHZ19Component *mhz19_;
|
||||
void play(const Ts &...x) override { this->parent_->abc_enable(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class MHZ19ABCDisableAction : public Action<Ts...> {
|
||||
template<typename... Ts> class MHZ19ABCDisableAction : public Action<Ts...>, public Parented<MHZ19Component> {
|
||||
public:
|
||||
MHZ19ABCDisableAction(MHZ19Component *mhz19) : mhz19_(mhz19) {}
|
||||
void play(const Ts &...x) override { this->parent_->abc_disable(); }
|
||||
};
|
||||
|
||||
void play(const Ts &...x) override { this->mhz19_->abc_disable(); }
|
||||
template<typename... Ts> class MHZ19DetectionRangeSetAction : public Action<Ts...>, public Parented<MHZ19Component> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(MHZ19DetectionRange, detection_range)
|
||||
|
||||
protected:
|
||||
MHZ19Component *mhz19_;
|
||||
void play(const Ts &...x) override { this->parent_->range_set(this->detection_range_.value(x...)); }
|
||||
};
|
||||
|
||||
} // namespace mhz19
|
||||
|
||||
@@ -19,14 +19,33 @@ DEPENDENCIES = ["uart"]
|
||||
|
||||
CONF_AUTOMATIC_BASELINE_CALIBRATION = "automatic_baseline_calibration"
|
||||
CONF_WARMUP_TIME = "warmup_time"
|
||||
CONF_DETECTION_RANGE = "detection_range"
|
||||
|
||||
mhz19_ns = cg.esphome_ns.namespace("mhz19")
|
||||
MHZ19Component = mhz19_ns.class_("MHZ19Component", cg.PollingComponent, uart.UARTDevice)
|
||||
MHZ19CalibrateZeroAction = mhz19_ns.class_(
|
||||
"MHZ19CalibrateZeroAction", automation.Action
|
||||
"MHZ19CalibrateZeroAction", automation.Action, cg.Parented.template(MHZ19Component)
|
||||
)
|
||||
MHZ19ABCEnableAction = mhz19_ns.class_("MHZ19ABCEnableAction", automation.Action)
|
||||
MHZ19ABCDisableAction = mhz19_ns.class_("MHZ19ABCDisableAction", automation.Action)
|
||||
MHZ19ABCEnableAction = mhz19_ns.class_(
|
||||
"MHZ19ABCEnableAction", automation.Action, cg.Parented.template(MHZ19Component)
|
||||
)
|
||||
MHZ19ABCDisableAction = mhz19_ns.class_(
|
||||
"MHZ19ABCDisableAction", automation.Action, cg.Parented.template(MHZ19Component)
|
||||
)
|
||||
MHZ19DetectionRangeSetAction = mhz19_ns.class_(
|
||||
"MHZ19DetectionRangeSetAction",
|
||||
automation.Action,
|
||||
cg.Parented.template(MHZ19Component),
|
||||
)
|
||||
|
||||
mhz19_detection_range = mhz19_ns.enum("MHZ19DetectionRange")
|
||||
MHZ19_DETECTION_RANGE_ENUM = {
|
||||
2000: mhz19_detection_range.MHZ19_DETECTION_RANGE_0_2000PPM,
|
||||
5000: mhz19_detection_range.MHZ19_DETECTION_RANGE_0_5000PPM,
|
||||
10000: mhz19_detection_range.MHZ19_DETECTION_RANGE_0_10000PPM,
|
||||
}
|
||||
|
||||
_validate_ppm = cv.float_with_unit("parts per million", "ppm")
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
@@ -49,6 +68,9 @@ CONFIG_SCHEMA = (
|
||||
cv.Optional(
|
||||
CONF_WARMUP_TIME, default="75s"
|
||||
): cv.positive_time_period_seconds,
|
||||
cv.Optional(CONF_DETECTION_RANGE): cv.All(
|
||||
_validate_ppm, cv.enum(MHZ19_DETECTION_RANGE_ENUM)
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
@@ -78,8 +100,11 @@ async def to_code(config):
|
||||
|
||||
cg.add(var.set_warmup_seconds(config[CONF_WARMUP_TIME]))
|
||||
|
||||
if CONF_DETECTION_RANGE in config:
|
||||
cg.add(var.set_detection_range(config[CONF_DETECTION_RANGE]))
|
||||
|
||||
CALIBRATION_ACTION_SCHEMA = maybe_simple_id(
|
||||
|
||||
NO_ARGS_ACTION_SCHEMA = maybe_simple_id(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(MHZ19Component),
|
||||
}
|
||||
@@ -87,14 +112,37 @@ CALIBRATION_ACTION_SCHEMA = maybe_simple_id(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"mhz19.calibrate_zero", MHZ19CalibrateZeroAction, CALIBRATION_ACTION_SCHEMA
|
||||
"mhz19.calibrate_zero", MHZ19CalibrateZeroAction, NO_ARGS_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"mhz19.abc_enable", MHZ19ABCEnableAction, CALIBRATION_ACTION_SCHEMA
|
||||
"mhz19.abc_enable", MHZ19ABCEnableAction, NO_ARGS_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"mhz19.abc_disable", MHZ19ABCDisableAction, CALIBRATION_ACTION_SCHEMA
|
||||
"mhz19.abc_disable", MHZ19ABCDisableAction, NO_ARGS_ACTION_SCHEMA
|
||||
)
|
||||
async def mhz19_calibration_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
async def mhz19_no_args_action_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
return var
|
||||
|
||||
|
||||
RANGE_ACTION_SCHEMA = maybe_simple_id(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(MHZ19Component),
|
||||
cv.Required(CONF_DETECTION_RANGE): cv.All(
|
||||
_validate_ppm, cv.enum(MHZ19_DETECTION_RANGE_ENUM)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"mhz19.detection_range_set", MHZ19DetectionRangeSetAction, RANGE_ACTION_SCHEMA
|
||||
)
|
||||
async def mhz19_detection_range_set_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
detection_range = config.get(CONF_DETECTION_RANGE)
|
||||
template_ = await cg.templatable(detection_range, args, mhz19_detection_range)
|
||||
cg.add(var.set_detection_range(template_))
|
||||
return var
|
||||
|
||||
@@ -12,6 +12,7 @@ from esphome.components.zephyr import (
|
||||
zephyr_add_prj_conf,
|
||||
zephyr_data,
|
||||
zephyr_set_core_data,
|
||||
zephyr_setup_preferences,
|
||||
zephyr_to_code,
|
||||
)
|
||||
from esphome.components.zephyr.const import (
|
||||
@@ -49,7 +50,7 @@ from .const import (
|
||||
from .gpio import nrf52_pin_to_code # noqa
|
||||
|
||||
CODEOWNERS = ["@tomaszduda23"]
|
||||
AUTO_LOAD = ["zephyr"]
|
||||
AUTO_LOAD = ["zephyr", "preferences"]
|
||||
IS_TARGET_PLATFORM = True
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -194,6 +195,7 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add_platformio_option("board_upload.require_upload_port", "true")
|
||||
cg.add_platformio_option("board_upload.wait_for_upload_port", "true")
|
||||
|
||||
zephyr_setup_preferences()
|
||||
zephyr_to_code(config)
|
||||
|
||||
if dfu_config := config.get(CONF_DFU):
|
||||
@@ -206,6 +208,18 @@ async def to_code(config: ConfigType) -> None:
|
||||
if reg0_config[CONF_UICR_ERASE]:
|
||||
cg.add_define("USE_NRF52_UICR_ERASE")
|
||||
|
||||
# c++ support
|
||||
zephyr_add_prj_conf("CPLUSPLUS", True)
|
||||
zephyr_add_prj_conf("LIB_CPLUSPLUS", True)
|
||||
# watchdog
|
||||
zephyr_add_prj_conf("WATCHDOG", True)
|
||||
zephyr_add_prj_conf("WDT_DISABLE_AT_BOOT", False)
|
||||
# disable console
|
||||
zephyr_add_prj_conf("UART_CONSOLE", False)
|
||||
zephyr_add_prj_conf("CONSOLE", False)
|
||||
# use NFC pins as GPIO
|
||||
zephyr_add_prj_conf("NFCT_PINS_AS_GPIOS", True)
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.DIAGNOSTICS)
|
||||
async def _dfu_to_code(dfu_config):
|
||||
|
||||
@@ -71,8 +71,15 @@ NRF52_PIN_SCHEMA = cv.All(
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(PLATFORM_NRF52, NRF52_PIN_SCHEMA)
|
||||
async def nrf52_pin_to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
num = config[CONF_NUMBER]
|
||||
port = num // 32
|
||||
pin_name_prefix = f"P{port}."
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
cg.RawExpression(f"DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpio{port}))"),
|
||||
32,
|
||||
pin_name_prefix,
|
||||
)
|
||||
cg.add(var.set_pin(num))
|
||||
# Only set if true to avoid bloating setup() function
|
||||
# (inverted bit in pin_flags_ bitfield is zero-initialized to false)
|
||||
|
||||
@@ -32,7 +32,7 @@ async def register_one_wire_device(var, config):
|
||||
|
||||
Sets the 1-wire bus to use and the 1-wire address.
|
||||
|
||||
This is a coroutine, you need to await it with a 'yield' expression!
|
||||
This is a coroutine, you need to await it with an 'await' expression!
|
||||
"""
|
||||
parent = await cg.get_variable(config[CONF_ONE_WIRE_ID])
|
||||
cg.add(var.set_one_wire_bus(parent))
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import water_heater
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_MODE,
|
||||
CONF_OPTIMISTIC,
|
||||
CONF_RESTORE_MODE,
|
||||
CONF_SET_ACTION,
|
||||
CONF_SUPPORTED_MODES,
|
||||
CONF_TARGET_TEMPERATURE,
|
||||
)
|
||||
from esphome.core import ID
|
||||
from esphome.cpp_generator import MockObj, TemplateArgsType
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import template_ns
|
||||
|
||||
CONF_CURRENT_TEMPERATURE = "current_temperature"
|
||||
|
||||
TemplateWaterHeater = template_ns.class_(
|
||||
"TemplateWaterHeater", water_heater.WaterHeater
|
||||
)
|
||||
|
||||
TemplateWaterHeaterPublishAction = template_ns.class_(
|
||||
"TemplateWaterHeaterPublishAction",
|
||||
automation.Action,
|
||||
cg.Parented.template(TemplateWaterHeater),
|
||||
)
|
||||
|
||||
TemplateWaterHeaterRestoreMode = template_ns.enum("TemplateWaterHeaterRestoreMode")
|
||||
RESTORE_MODES = {
|
||||
"NO_RESTORE": TemplateWaterHeaterRestoreMode.WATER_HEATER_NO_RESTORE,
|
||||
"RESTORE": TemplateWaterHeaterRestoreMode.WATER_HEATER_RESTORE,
|
||||
"RESTORE_AND_CALL": TemplateWaterHeaterRestoreMode.WATER_HEATER_RESTORE_AND_CALL,
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = water_heater.water_heater_schema(TemplateWaterHeater).extend(
|
||||
{
|
||||
cv.Optional(CONF_OPTIMISTIC, default=True): cv.boolean,
|
||||
cv.Optional(CONF_SET_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_RESTORE_MODE, default="NO_RESTORE"): cv.enum(
|
||||
RESTORE_MODES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_CURRENT_TEMPERATURE): cv.returning_lambda,
|
||||
cv.Optional(CONF_MODE): cv.returning_lambda,
|
||||
cv.Optional(CONF_SUPPORTED_MODES): cv.ensure_list(
|
||||
water_heater.validate_water_heater_mode
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await water_heater.register_water_heater(var, config)
|
||||
|
||||
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
|
||||
|
||||
if CONF_SET_ACTION in config:
|
||||
await automation.build_automation(
|
||||
var.get_set_trigger(), [], config[CONF_SET_ACTION]
|
||||
)
|
||||
|
||||
cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
|
||||
|
||||
if CONF_CURRENT_TEMPERATURE in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_CURRENT_TEMPERATURE],
|
||||
[],
|
||||
return_type=cg.optional.template(cg.float_),
|
||||
)
|
||||
cg.add(var.set_current_temperature_lambda(template_))
|
||||
|
||||
if CONF_MODE in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_MODE],
|
||||
[],
|
||||
return_type=cg.optional.template(water_heater.WaterHeaterMode),
|
||||
)
|
||||
cg.add(var.set_mode_lambda(template_))
|
||||
|
||||
if CONF_SUPPORTED_MODES in config:
|
||||
cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES]))
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"water_heater.template.publish",
|
||||
TemplateWaterHeaterPublishAction,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(TemplateWaterHeater),
|
||||
cv.Optional(CONF_CURRENT_TEMPERATURE): cv.templatable(cv.temperature),
|
||||
cv.Optional(CONF_TARGET_TEMPERATURE): cv.templatable(cv.temperature),
|
||||
cv.Optional(CONF_MODE): cv.templatable(
|
||||
water_heater.validate_water_heater_mode
|
||||
),
|
||||
}
|
||||
),
|
||||
)
|
||||
async def water_heater_template_publish_to_code(
|
||||
config: ConfigType,
|
||||
action_id: ID,
|
||||
template_arg: cg.TemplateArguments,
|
||||
args: TemplateArgsType,
|
||||
) -> MockObj:
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
|
||||
if current_temp := config.get(CONF_CURRENT_TEMPERATURE):
|
||||
template_ = await cg.templatable(current_temp, args, float)
|
||||
cg.add(var.set_current_temperature(template_))
|
||||
|
||||
if target_temp := config.get(CONF_TARGET_TEMPERATURE):
|
||||
template_ = await cg.templatable(target_temp, args, float)
|
||||
cg.add(var.set_target_temperature(template_))
|
||||
|
||||
if mode := config.get(CONF_MODE):
|
||||
template_ = await cg.templatable(mode, args, water_heater.WaterHeaterMode)
|
||||
cg.add(var.set_mode(template_))
|
||||
|
||||
return var
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "template_water_heater.h"
|
||||
#include "esphome/core/automation.h"
|
||||
|
||||
namespace esphome::template_ {
|
||||
|
||||
template<typename... Ts>
|
||||
class TemplateWaterHeaterPublishAction : public Action<Ts...>, public Parented<TemplateWaterHeater> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(float, current_temperature)
|
||||
TEMPLATABLE_VALUE(float, target_temperature)
|
||||
TEMPLATABLE_VALUE(water_heater::WaterHeaterMode, mode)
|
||||
|
||||
void play(const Ts &...x) override {
|
||||
if (this->current_temperature_.has_value()) {
|
||||
this->parent_->set_current_temperature(this->current_temperature_.value(x...));
|
||||
}
|
||||
bool needs_call = this->target_temperature_.has_value() || this->mode_.has_value();
|
||||
if (needs_call) {
|
||||
auto call = this->parent_->make_call();
|
||||
if (this->target_temperature_.has_value()) {
|
||||
call.set_target_temperature(this->target_temperature_.value(x...));
|
||||
}
|
||||
if (this->mode_.has_value()) {
|
||||
call.set_mode(this->mode_.value(x...));
|
||||
}
|
||||
call.perform();
|
||||
} else {
|
||||
this->parent_->publish_state();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace esphome::template_
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "template_water_heater.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::template_ {
|
||||
|
||||
static const char *const TAG = "template.water_heater";
|
||||
|
||||
TemplateWaterHeater::TemplateWaterHeater() : set_trigger_(new Trigger<>()) {}
|
||||
|
||||
void TemplateWaterHeater::setup() {
|
||||
if (this->restore_mode_ == TemplateWaterHeaterRestoreMode::WATER_HEATER_RESTORE ||
|
||||
this->restore_mode_ == TemplateWaterHeaterRestoreMode::WATER_HEATER_RESTORE_AND_CALL) {
|
||||
auto restore = this->restore_state();
|
||||
|
||||
if (restore.has_value()) {
|
||||
restore->perform();
|
||||
}
|
||||
}
|
||||
if (!this->current_temperature_f_.has_value() && !this->mode_f_.has_value())
|
||||
this->disable_loop();
|
||||
}
|
||||
|
||||
water_heater::WaterHeaterTraits TemplateWaterHeater::traits() {
|
||||
water_heater::WaterHeaterTraits traits;
|
||||
|
||||
if (!this->supported_modes_.empty()) {
|
||||
traits.set_supported_modes(this->supported_modes_);
|
||||
}
|
||||
|
||||
traits.set_supports_current_temperature(true);
|
||||
return traits;
|
||||
}
|
||||
|
||||
void TemplateWaterHeater::loop() {
|
||||
bool changed = false;
|
||||
|
||||
auto curr_temp = this->current_temperature_f_.call();
|
||||
if (curr_temp.has_value()) {
|
||||
if (*curr_temp != this->current_temperature_) {
|
||||
this->current_temperature_ = *curr_temp;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto new_mode = this->mode_f_.call();
|
||||
if (new_mode.has_value()) {
|
||||
if (*new_mode != this->mode_) {
|
||||
this->mode_ = *new_mode;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this->publish_state();
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateWaterHeater::dump_config() {
|
||||
LOG_WATER_HEATER("", "Template Water Heater", this);
|
||||
ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_));
|
||||
}
|
||||
|
||||
float TemplateWaterHeater::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
water_heater::WaterHeaterCallInternal TemplateWaterHeater::make_call() {
|
||||
return water_heater::WaterHeaterCallInternal(this);
|
||||
}
|
||||
|
||||
void TemplateWaterHeater::control(const water_heater::WaterHeaterCall &call) {
|
||||
if (call.get_mode().has_value()) {
|
||||
if (this->optimistic_) {
|
||||
this->mode_ = *call.get_mode();
|
||||
}
|
||||
}
|
||||
if (!std::isnan(call.get_target_temperature())) {
|
||||
if (this->optimistic_) {
|
||||
this->target_temperature_ = call.get_target_temperature();
|
||||
}
|
||||
}
|
||||
|
||||
this->set_trigger_->trigger();
|
||||
|
||||
if (this->optimistic_) {
|
||||
this->publish_state();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::template_
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
#include "esphome/components/water_heater/water_heater.h"
|
||||
|
||||
namespace esphome::template_ {
|
||||
|
||||
enum TemplateWaterHeaterRestoreMode {
|
||||
WATER_HEATER_NO_RESTORE,
|
||||
WATER_HEATER_RESTORE,
|
||||
WATER_HEATER_RESTORE_AND_CALL,
|
||||
};
|
||||
|
||||
class TemplateWaterHeater : public water_heater::WaterHeater {
|
||||
public:
|
||||
TemplateWaterHeater();
|
||||
|
||||
template<typename F> void set_current_temperature_lambda(F &&f) {
|
||||
this->current_temperature_f_.set(std::forward<F>(f));
|
||||
}
|
||||
template<typename F> void set_mode_lambda(F &&f) { this->mode_f_.set(std::forward<F>(f)); }
|
||||
|
||||
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
void set_restore_mode(TemplateWaterHeaterRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
|
||||
void set_supported_modes(const std::initializer_list<water_heater::WaterHeaterMode> &modes) {
|
||||
this->supported_modes_ = modes;
|
||||
}
|
||||
|
||||
Trigger<> *get_set_trigger() const { return this->set_trigger_; }
|
||||
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
|
||||
water_heater::WaterHeaterCallInternal make_call() override;
|
||||
|
||||
protected:
|
||||
void control(const water_heater::WaterHeaterCall &call) override;
|
||||
water_heater::WaterHeaterTraits traits() override;
|
||||
|
||||
// Ordered to minimize padding on 32-bit: 4-byte members first, then smaller
|
||||
Trigger<> *set_trigger_;
|
||||
TemplateLambda<float> current_temperature_f_;
|
||||
TemplateLambda<water_heater::WaterHeaterMode> mode_f_;
|
||||
TemplateWaterHeaterRestoreMode restore_mode_{WATER_HEATER_NO_RESTORE};
|
||||
water_heater::WaterHeaterModeMask supported_modes_;
|
||||
bool optimistic_{true};
|
||||
};
|
||||
|
||||
} // namespace esphome::template_
|
||||
@@ -482,7 +482,7 @@ def final_validate_device_schema(
|
||||
async def register_uart_device(var, config):
|
||||
"""Register a UART device, setting up all the internal values.
|
||||
|
||||
This is a coroutine, you need to await it with a 'yield' expression!
|
||||
This is a coroutine, you need to await it with an 'await' expression!
|
||||
"""
|
||||
parent = await cg.get_variable(config[CONF_UART_ID])
|
||||
cg.add(var.set_uart_parent(parent))
|
||||
|
||||
@@ -120,8 +120,10 @@ void LibreTinyUARTComponent::setup() {
|
||||
|
||||
void LibreTinyUARTComponent::dump_config() {
|
||||
bool is_software = this->hardware_idx_ == -1;
|
||||
ESP_LOGCONFIG(TAG, "UART Bus:");
|
||||
ESP_LOGCONFIG(TAG, " Type: %s", UART_TYPE[is_software]);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"UART Bus:\n"
|
||||
" Type: %s",
|
||||
UART_TYPE[is_software]);
|
||||
if (!is_software) {
|
||||
ESP_LOGCONFIG(TAG, " Port number: %d", this->hardware_idx_);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ namespace update {
|
||||
static const char *const TAG = "update";
|
||||
|
||||
void UpdateEntity::publish_state() {
|
||||
ESP_LOGD(TAG, "'%s' - Publishing:", this->name_.c_str());
|
||||
ESP_LOGD(TAG, " Current Version: %s", this->update_info_.current_version.c_str());
|
||||
ESP_LOGD(TAG,
|
||||
"'%s' - Publishing:\n"
|
||||
" Current Version: %s",
|
||||
this->name_.c_str(), this->update_info_.current_version.c_str());
|
||||
|
||||
if (!this->update_info_.md5.empty()) {
|
||||
ESP_LOGD(TAG, " Latest Version: %s", this->update_info_.latest_version.c_str());
|
||||
|
||||
@@ -152,8 +152,10 @@ void WaterHeater::setup() {
|
||||
|
||||
void WaterHeater::publish_state() {
|
||||
auto traits = this->get_traits();
|
||||
ESP_LOGD(TAG, "'%s' - Sending state:", this->name_.c_str());
|
||||
ESP_LOGD(TAG, " Mode: %s", LOG_STR_ARG(water_heater_mode_to_string(this->mode_)));
|
||||
ESP_LOGD(TAG,
|
||||
"'%s' - Sending state:\n"
|
||||
" Mode: %s",
|
||||
this->name_.c_str(), LOG_STR_ARG(water_heater_mode_to_string(this->mode_)));
|
||||
if (!std::isnan(this->current_temperature_)) {
|
||||
ESP_LOGD(TAG, " Current Temperature: %.2f°C", this->current_temperature_);
|
||||
}
|
||||
|
||||
@@ -781,8 +781,10 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
|
||||
get_max_retries_for_phase(this->retry_phase_), LOG_STR_ARG(retry_phase_to_log_string(this->retry_phase_)));
|
||||
|
||||
#ifdef ESPHOME_LOG_HAS_VERBOSE
|
||||
ESP_LOGV(TAG, "Connection Params:");
|
||||
ESP_LOGV(TAG, " SSID: '%s'", ap.get_ssid().c_str());
|
||||
ESP_LOGV(TAG,
|
||||
"Connection Params:\n"
|
||||
" SSID: '%s'",
|
||||
ap.get_ssid().c_str());
|
||||
if (ap.has_bssid()) {
|
||||
ESP_LOGV(TAG, " BSSID: %s", bssid_s);
|
||||
} else {
|
||||
@@ -791,20 +793,28 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
|
||||
|
||||
#ifdef USE_WIFI_WPA2_EAP
|
||||
if (ap.get_eap().has_value()) {
|
||||
ESP_LOGV(TAG, " WPA2 Enterprise authentication configured:");
|
||||
EAPAuth eap_config = ap.get_eap().value();
|
||||
ESP_LOGV(TAG, " Identity: " LOG_SECRET("'%s'"), eap_config.identity.c_str());
|
||||
ESP_LOGV(TAG, " Username: " LOG_SECRET("'%s'"), eap_config.username.c_str());
|
||||
ESP_LOGV(TAG, " Password: " LOG_SECRET("'%s'"), eap_config.password.c_str());
|
||||
// clang-format off
|
||||
ESP_LOGV(
|
||||
TAG,
|
||||
" WPA2 Enterprise authentication configured:\n"
|
||||
" Identity: " LOG_SECRET("'%s'") "\n"
|
||||
" Username: " LOG_SECRET("'%s'") "\n"
|
||||
" Password: " LOG_SECRET("'%s'"),
|
||||
eap_config.identity.c_str(), eap_config.username.c_str(), eap_config.password.c_str());
|
||||
// clang-format on
|
||||
#if defined(USE_ESP32) && defined(USE_WIFI_WPA2_EAP) && ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
ESP_LOGV(TAG, " TTLS Phase 2: " LOG_SECRET("'%s'"), eap_phase2_to_str(eap_config.ttls_phase_2));
|
||||
#endif
|
||||
bool ca_cert_present = eap_config.ca_cert != nullptr && strlen(eap_config.ca_cert);
|
||||
bool client_cert_present = eap_config.client_cert != nullptr && strlen(eap_config.client_cert);
|
||||
bool client_key_present = eap_config.client_key != nullptr && strlen(eap_config.client_key);
|
||||
ESP_LOGV(TAG, " CA Cert: %s", ca_cert_present ? "present" : "not present");
|
||||
ESP_LOGV(TAG, " Client Cert: %s", client_cert_present ? "present" : "not present");
|
||||
ESP_LOGV(TAG, " Client Key: %s", client_key_present ? "present" : "not present");
|
||||
ESP_LOGV(TAG,
|
||||
" CA Cert: %s\n"
|
||||
" Client Cert: %s\n"
|
||||
" Client Key: %s",
|
||||
ca_cert_present ? "present" : "not present", client_cert_present ? "present" : "not present",
|
||||
client_key_present ? "present" : "not present");
|
||||
} else {
|
||||
#endif
|
||||
ESP_LOGV(TAG, " Password: " LOG_SECRET("'%s'"), ap.get_password().c_str());
|
||||
@@ -1049,15 +1059,27 @@ template<typename VectorType> static void insertion_sort_scan_results(VectorType
|
||||
}
|
||||
|
||||
// Helper function to log matching scan results - marked noinline to prevent re-inlining into loop
|
||||
//
|
||||
// IMPORTANT: This function deliberately uses a SINGLE log call to minimize blocking.
|
||||
// In environments with many matching networks (e.g., 18+ mesh APs), multiple log calls
|
||||
// per network would block the main loop for an unacceptable duration. Each log call
|
||||
// has overhead from UART transmission, so combining INFO+DEBUG into one line halves
|
||||
// the blocking time. Do NOT split this into separate ESP_LOGI/ESP_LOGD calls.
|
||||
__attribute__((noinline)) static void log_scan_result(const WiFiScanResult &res) {
|
||||
char bssid_s[18];
|
||||
auto bssid = res.get_bssid();
|
||||
format_mac_addr_upper(bssid.data(), bssid_s);
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
||||
// Single combined log line with all details when DEBUG enabled
|
||||
ESP_LOGI(TAG, "- '%s' %s" LOG_SECRET("(%s) ") "%s Ch:%2u %3ddB P:%d", res.get_ssid().c_str(),
|
||||
res.get_is_hidden() ? LOG_STR_LITERAL("(HIDDEN) ") : LOG_STR_LITERAL(""), bssid_s,
|
||||
LOG_STR_ARG(get_signal_bars(res.get_rssi())), res.get_channel(), res.get_rssi(), res.get_priority());
|
||||
#else
|
||||
ESP_LOGI(TAG, "- '%s' %s" LOG_SECRET("(%s) ") "%s", res.get_ssid().c_str(),
|
||||
res.get_is_hidden() ? LOG_STR_LITERAL("(HIDDEN) ") : LOG_STR_LITERAL(""), bssid_s,
|
||||
LOG_STR_ARG(get_signal_bars(res.get_rssi())));
|
||||
ESP_LOGD(TAG, " Channel: %2u, RSSI: %3d dB, Priority: %4d", res.get_channel(), res.get_rssi(), res.get_priority());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
|
||||
@@ -518,8 +518,12 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
switch (event->event) {
|
||||
case EVENT_STAMODE_CONNECTED: {
|
||||
auto it = event->event_info.connected;
|
||||
ESP_LOGV(TAG, "Connected ssid='%.*s' bssid=%s channel=%u", it.ssid_len, (const char *) it.ssid,
|
||||
format_mac_address_pretty(it.bssid).c_str(), it.channel);
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char bssid_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.bssid, bssid_buf);
|
||||
ESP_LOGV(TAG, "Connected ssid='%.*s' bssid=%s channel=%u", it.ssid_len, (const char *) it.ssid, bssid_buf,
|
||||
it.channel);
|
||||
#endif
|
||||
s_sta_connected = true;
|
||||
#ifdef USE_WIFI_LISTENERS
|
||||
for (auto *listener : global_wifi_component->connect_state_listeners_) {
|
||||
@@ -594,18 +598,30 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
break;
|
||||
}
|
||||
case EVENT_SOFTAPMODE_STACONNECTED: {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
auto it = event->event_info.sta_connected;
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s aid=%u", format_mac_address_pretty(it.mac).c_str(), it.aid);
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.mac, mac_buf);
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s aid=%u", mac_buf, it.aid);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case EVENT_SOFTAPMODE_STADISCONNECTED: {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
auto it = event->event_info.sta_disconnected;
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s aid=%u", format_mac_address_pretty(it.mac).c_str(), it.aid);
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.mac, mac_buf);
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s aid=%u", mac_buf, it.aid);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case EVENT_SOFTAPMODE_PROBEREQRECVED: {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
auto it = event->event_info.ap_probereqrecved;
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_address_pretty(it.mac).c_str(), it.rssi);
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.mac, mac_buf);
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", mac_buf, it.rssi);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 4, 0)
|
||||
@@ -616,9 +632,12 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
break;
|
||||
}
|
||||
case EVENT_SOFTAPMODE_DISTRIBUTE_STA_IP: {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
auto it = event->event_info.distribute_sta_ip;
|
||||
ESP_LOGV(TAG, "AP Distribute Station IP MAC=%s IP=%s aid=%u", format_mac_address_pretty(it.mac).c_str(),
|
||||
format_ip_addr(it.ip).c_str(), it.aid);
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.mac, mac_buf);
|
||||
ESP_LOGV(TAG, "AP Distribute Station IP MAC=%s IP=%s aid=%u", mac_buf, format_ip_addr(it.ip).c_str(), it.aid);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -734,9 +734,12 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_CONNECTED) {
|
||||
const auto &it = data->data.sta_connected;
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char bssid_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.bssid, bssid_buf);
|
||||
ESP_LOGV(TAG, "Connected ssid='%.*s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", it.ssid_len,
|
||||
(const char *) it.ssid, format_mac_address_pretty(it.bssid).c_str(), it.channel,
|
||||
get_auth_mode_str(it.authmode));
|
||||
(const char *) it.ssid, bssid_buf, it.channel, get_auth_mode_str(it.authmode));
|
||||
#endif
|
||||
s_sta_connected = true;
|
||||
#ifdef USE_WIFI_LISTENERS
|
||||
for (auto *listener : this->connect_state_listeners_) {
|
||||
@@ -855,16 +858,28 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
||||
this->ap_started_ = false;
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_PROBEREQRECVED) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
const auto &it = data->data.ap_probe_req_rx;
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_address_pretty(it.mac).c_str(), it.rssi);
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.mac, mac_buf);
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", mac_buf, it.rssi);
|
||||
#endif
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_STACONNECTED) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
const auto &it = data->data.ap_staconnected;
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s", format_mac_address_pretty(it.mac).c_str());
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.mac, mac_buf);
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s", mac_buf);
|
||||
#endif
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_STADISCONNECTED) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
const auto &it = data->data.ap_stadisconnected;
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s", format_mac_address_pretty(it.mac).c_str());
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(it.mac, mac_buf);
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s", mac_buf);
|
||||
#endif
|
||||
|
||||
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_AP_STAIPASSIGNED) {
|
||||
const auto &it = data->data.ip_ap_staipassigned;
|
||||
|
||||
@@ -71,17 +71,20 @@ void WTS01Sensor::process_packet_() {
|
||||
}
|
||||
|
||||
// Extract temperature value
|
||||
int8_t temp = this->buffer_[6];
|
||||
int32_t sign = 1;
|
||||
const uint8_t raw = this->buffer_[6];
|
||||
|
||||
// Handle negative temperatures
|
||||
if (temp < 0) {
|
||||
sign = -1;
|
||||
// WTS01 encodes sign in bit 7, magnitude in bits 0-6
|
||||
const bool negative = (raw & 0x80) != 0;
|
||||
const uint8_t magnitude = raw & 0x7F;
|
||||
|
||||
const float decimal = static_cast<float>(this->buffer_[7]) / 100.0f;
|
||||
|
||||
float temperature = static_cast<float>(magnitude) + decimal;
|
||||
|
||||
if (negative) {
|
||||
temperature = -temperature;
|
||||
}
|
||||
|
||||
// Calculate temperature (temp + decimal/100)
|
||||
float temperature = static_cast<float>(temp) + (sign * static_cast<float>(this->buffer_[7]) / 100.0f);
|
||||
|
||||
ESP_LOGV(TAG, "Received new temperature: %.2f°C", temperature);
|
||||
|
||||
this->publish_state(temperature);
|
||||
|
||||
@@ -21,7 +21,6 @@ from .const import (
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@tomaszduda23"]
|
||||
AUTO_LOAD = ["preferences"]
|
||||
|
||||
PrjConfValueType = bool | str | int
|
||||
|
||||
@@ -111,32 +110,15 @@ def add_extra_script(stage: str, filename: str, path: Path) -> None:
|
||||
|
||||
|
||||
def zephyr_to_code(config):
|
||||
cg.add(zephyr_ns.setup_preferences())
|
||||
cg.add_build_flag("-DUSE_ZEPHYR")
|
||||
cg.set_cpp_standard("gnu++20")
|
||||
# build is done by west so bypass board checking in platformio
|
||||
cg.add_platformio_option("boards_dir", CORE.relative_build_path("boards"))
|
||||
|
||||
# c++ support
|
||||
zephyr_add_prj_conf("NEWLIB_LIBC", True)
|
||||
zephyr_add_prj_conf("CONFIG_FPU", True)
|
||||
zephyr_add_prj_conf("FPU", True)
|
||||
zephyr_add_prj_conf("NEWLIB_LIBC_FLOAT_PRINTF", True)
|
||||
zephyr_add_prj_conf("CPLUSPLUS", True)
|
||||
zephyr_add_prj_conf("CONFIG_STD_CPP20", True)
|
||||
zephyr_add_prj_conf("LIB_CPLUSPLUS", True)
|
||||
# preferences
|
||||
zephyr_add_prj_conf("SETTINGS", True)
|
||||
zephyr_add_prj_conf("NVS", True)
|
||||
zephyr_add_prj_conf("FLASH_MAP", True)
|
||||
zephyr_add_prj_conf("CONFIG_FLASH", True)
|
||||
# watchdog
|
||||
zephyr_add_prj_conf("WATCHDOG", True)
|
||||
zephyr_add_prj_conf("WDT_DISABLE_AT_BOOT", False)
|
||||
# disable console
|
||||
zephyr_add_prj_conf("UART_CONSOLE", False)
|
||||
zephyr_add_prj_conf("CONSOLE", False, False)
|
||||
# use NFC pins as GPIO
|
||||
zephyr_add_prj_conf("NFCT_PINS_AS_GPIOS", True)
|
||||
zephyr_add_prj_conf("STD_CPP20", True)
|
||||
|
||||
# <err> os: ***** USAGE FAULT *****
|
||||
# <err> os: Illegal load of EXC_RETURN into PC
|
||||
@@ -149,6 +131,14 @@ def zephyr_to_code(config):
|
||||
)
|
||||
|
||||
|
||||
def zephyr_setup_preferences():
|
||||
cg.add(zephyr_ns.setup_preferences())
|
||||
zephyr_add_prj_conf("SETTINGS", True)
|
||||
zephyr_add_prj_conf("NVS", True)
|
||||
zephyr_add_prj_conf("FLASH_MAP", True)
|
||||
zephyr_add_prj_conf("FLASH", True)
|
||||
|
||||
|
||||
def _format_prj_conf_val(value: PrjConfValueType) -> str:
|
||||
if isinstance(value, bool):
|
||||
return "y" if value else "n"
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
static int wdt_channel_id = -1; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
static const device *const WDT = DEVICE_DT_GET(DT_ALIAS(watchdog0));
|
||||
#endif
|
||||
|
||||
void yield() { ::k_yield(); }
|
||||
uint32_t millis() { return k_ticks_to_ms_floor32(k_uptime_ticks()); }
|
||||
@@ -20,6 +22,7 @@ void delayMicroseconds(uint32_t us) { ::k_usleep(us); }
|
||||
void delay(uint32_t ms) { ::k_msleep(ms); }
|
||||
|
||||
void arch_init() {
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
if (device_is_ready(WDT)) {
|
||||
static wdt_timeout_cfg wdt_config{};
|
||||
wdt_config.flags = WDT_FLAG_RESET_SOC;
|
||||
@@ -36,12 +39,15 @@ void arch_init() {
|
||||
wdt_setup(WDT, options);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void arch_feed_wdt() {
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
if (wdt_channel_id >= 0) {
|
||||
wdt_feed(WDT, wdt_channel_id);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void arch_restart() { sys_reboot(SYS_REBOOT_COLD); }
|
||||
@@ -72,6 +78,7 @@ bool random_bytes(uint8_t *data, size_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_NRF52
|
||||
void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter)
|
||||
mac[0] = ((NRF_FICR->DEVICEADDR[1] & 0xFFFF) >> 8) | 0xC0;
|
||||
mac[1] = NRF_FICR->DEVICEADDR[1] & 0xFFFF;
|
||||
@@ -80,7 +87,7 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame
|
||||
mac[4] = NRF_FICR->DEVICEADDR[0] >> 8;
|
||||
mac[5] = NRF_FICR->DEVICEADDR[0];
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace esphome
|
||||
|
||||
void setup();
|
||||
|
||||
@@ -50,25 +50,7 @@ void ZephyrGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::Inte
|
||||
}
|
||||
|
||||
void ZephyrGPIOPin::setup() {
|
||||
const struct device *gpio = nullptr;
|
||||
if (this->pin_ < 32) {
|
||||
#define GPIO0 DT_NODELABEL(gpio0)
|
||||
#if DT_NODE_HAS_STATUS(GPIO0, okay)
|
||||
gpio = DEVICE_DT_GET(GPIO0);
|
||||
#else
|
||||
#error "gpio0 is disabled"
|
||||
#endif
|
||||
} else {
|
||||
#define GPIO1 DT_NODELABEL(gpio1)
|
||||
#if DT_NODE_HAS_STATUS(GPIO1, okay)
|
||||
gpio = DEVICE_DT_GET(GPIO1);
|
||||
#else
|
||||
#error "gpio1 is disabled"
|
||||
#endif
|
||||
}
|
||||
if (device_is_ready(gpio)) {
|
||||
this->gpio_ = gpio;
|
||||
} else {
|
||||
if (!device_is_ready(this->gpio_)) {
|
||||
ESP_LOGE(TAG, "gpio %u is not ready.", this->pin_);
|
||||
return;
|
||||
}
|
||||
@@ -79,21 +61,22 @@ void ZephyrGPIOPin::pin_mode(gpio::Flags flags) {
|
||||
if (nullptr == this->gpio_) {
|
||||
return;
|
||||
}
|
||||
auto ret = gpio_pin_configure(this->gpio_, this->pin_ % 32, flags_to_mode(flags, this->inverted_, this->value_));
|
||||
auto ret = gpio_pin_configure(this->gpio_, this->pin_ % this->gpio_size_,
|
||||
flags_to_mode(flags, this->inverted_, this->value_));
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "gpio %u cannot be configured %d.", this->pin_, ret);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZephyrGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "GPIO%u, P%u.%u", this->pin_, this->pin_ / 32, this->pin_ % 32);
|
||||
return snprintf(buffer, len, "GPIO%u, %s%u", this->pin_, this->pin_name_prefix_, this->pin_ % this->gpio_size_);
|
||||
}
|
||||
|
||||
bool ZephyrGPIOPin::digital_read() {
|
||||
if (nullptr == this->gpio_) {
|
||||
return false;
|
||||
}
|
||||
return bool(gpio_pin_get(this->gpio_, this->pin_ % 32) != this->inverted_);
|
||||
return bool(gpio_pin_get(this->gpio_, this->pin_ % this->gpio_size_) != this->inverted_);
|
||||
}
|
||||
|
||||
void ZephyrGPIOPin::digital_write(bool value) {
|
||||
@@ -103,7 +86,7 @@ void ZephyrGPIOPin::digital_write(bool value) {
|
||||
if (nullptr == this->gpio_) {
|
||||
return;
|
||||
}
|
||||
gpio_pin_set(this->gpio_, this->pin_ % 32, value != this->inverted_ ? 1 : 0);
|
||||
gpio_pin_set(this->gpio_, this->pin_ % this->gpio_size_, value != this->inverted_ ? 1 : 0);
|
||||
}
|
||||
void ZephyrGPIOPin::detach_interrupt() const {
|
||||
// TODO
|
||||
|
||||
@@ -8,6 +8,11 @@ namespace zephyr {
|
||||
|
||||
class ZephyrGPIOPin : public InternalGPIOPin {
|
||||
public:
|
||||
ZephyrGPIOPin(const device *gpio, int gpio_size, const char *pin_name_prefix) {
|
||||
this->gpio_ = gpio;
|
||||
this->gpio_size_ = gpio_size;
|
||||
this->pin_name_prefix_ = pin_name_prefix;
|
||||
}
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
void set_inverted(bool inverted) { this->inverted_ = inverted; }
|
||||
void set_flags(gpio::Flags flags) { this->flags_ = flags; }
|
||||
@@ -25,10 +30,12 @@ class ZephyrGPIOPin : public InternalGPIOPin {
|
||||
|
||||
protected:
|
||||
void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override;
|
||||
uint8_t pin_;
|
||||
bool inverted_{};
|
||||
gpio::Flags flags_{};
|
||||
const device *gpio_{nullptr};
|
||||
const char *pin_name_prefix_{nullptr};
|
||||
gpio::Flags flags_{};
|
||||
uint8_t pin_;
|
||||
uint8_t gpio_size_{};
|
||||
bool inverted_{};
|
||||
bool value_{false};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#ifdef USE_ZEPHYR
|
||||
#ifdef CONFIG_SETTINGS
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include "esphome/core/preferences.h"
|
||||
@@ -154,3 +155,4 @@ ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const
|
||||
} // namespace esphome
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -205,7 +205,13 @@ void Component::call() {
|
||||
this->call_setup();
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
||||
uint32_t setup_time = millis() - start_time;
|
||||
ESP_LOGCONFIG(TAG, "Setup %s took %ums", LOG_STR_ARG(this->get_component_log_str()), (unsigned) setup_time);
|
||||
// Only log at CONFIG level if setup took longer than the blocking threshold
|
||||
// to avoid spamming the log and blocking the event loop
|
||||
if (setup_time >= WARN_IF_BLOCKING_OVER_MS) {
|
||||
ESP_LOGCONFIG(TAG, "Setup %s took %ums", LOG_STR_ARG(this->get_component_log_str()), (unsigned) setup_time);
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Setup %s took %ums", LOG_STR_ARG(this->get_component_log_str()), (unsigned) setup_time);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -643,7 +643,7 @@ async def get_variable(id_: ID) -> "MockObj":
|
||||
Wait for the given ID to be defined in the code generation and
|
||||
return it as a MockObj.
|
||||
|
||||
This is a coroutine, you need to await it with a 'await' expression!
|
||||
This is a coroutine, you need to await it with an 'await' expression!
|
||||
|
||||
:param id_: The ID to retrieve
|
||||
:return: The variable as a MockObj.
|
||||
@@ -656,7 +656,7 @@ async def get_variable_with_full_id(id_: ID) -> tuple[ID, "MockObj"]:
|
||||
Wait for the given ID to be defined in the code generation and
|
||||
return it as a MockObj.
|
||||
|
||||
This is a coroutine, you need to await it with a 'await' expression!
|
||||
This is a coroutine, you need to await it with an 'await' expression!
|
||||
|
||||
:param id_: The ID to retrieve
|
||||
:return: The variable as a MockObj.
|
||||
|
||||
+8
-2
@@ -12,14 +12,20 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile
|
||||
esptool==5.1.0
|
||||
click==8.1.7
|
||||
esphome-dashboard==20251013.0
|
||||
aioesphomeapi==43.10.0
|
||||
aioesphomeapi==43.10.1
|
||||
zeroconf==0.148.0
|
||||
puremagic==1.30
|
||||
ruamel.yaml==0.19.1 # dashboard_import
|
||||
ruamel.yaml.clib==0.2.15 # dashboard_import
|
||||
esphome-glyphsets==0.2.0
|
||||
pillow==11.3.0
|
||||
cairosvg==2.8.2
|
||||
|
||||
# pycairo fork for Windows
|
||||
cairosvg @ git+https://github.com/clydebarrow/cairosvg.git@release ; sys_platform == 'win32'
|
||||
|
||||
# Original for everything else
|
||||
cairosvg==2.8.2 ; sys_platform != 'win32'
|
||||
|
||||
freetype-py==2.5.1
|
||||
jinja2==3.1.6
|
||||
bleak==2.1.1
|
||||
|
||||
@@ -6,3 +6,4 @@ sensor:
|
||||
name: MH-Z19 Temperature
|
||||
automatic_baseline_calibration: false
|
||||
update_interval: 15s
|
||||
detection_range: 5000ppm
|
||||
|
||||
@@ -9,6 +9,18 @@ esphome:
|
||||
id: template_sens
|
||||
state: !lambda "return 42.0;"
|
||||
|
||||
- water_heater.template.publish:
|
||||
id: template_water_heater
|
||||
target_temperature: 50.0
|
||||
mode: ECO
|
||||
|
||||
# Templated
|
||||
- water_heater.template.publish:
|
||||
id: template_water_heater
|
||||
current_temperature: !lambda "return 45.0;"
|
||||
target_temperature: !lambda "return 55.0;"
|
||||
mode: !lambda "return water_heater::WATER_HEATER_MODE_GAS;"
|
||||
|
||||
# Test C++ API: set_template() with stateless lambda (no captures)
|
||||
# NOTE: set_template() is not intended to be a public API, but we test it to ensure it doesn't break.
|
||||
- lambda: |-
|
||||
@@ -299,6 +311,24 @@ alarm_control_panel:
|
||||
codes:
|
||||
- "1234"
|
||||
|
||||
water_heater:
|
||||
- platform: template
|
||||
id: template_water_heater
|
||||
name: "Template Water Heater"
|
||||
optimistic: true
|
||||
current_temperature: !lambda "return 42.0f;"
|
||||
mode: !lambda "return water_heater::WATER_HEATER_MODE_ECO;"
|
||||
supported_modes:
|
||||
- "OFF"
|
||||
- ECO
|
||||
- GAS
|
||||
- ELECTRIC
|
||||
- HEAT_PUMP
|
||||
- HIGH_DEMAND
|
||||
- PERFORMANCE
|
||||
set_action:
|
||||
- logger.log: "set_action"
|
||||
|
||||
datetime:
|
||||
- platform: template
|
||||
name: Date
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
water_heater:
|
||||
- platform: template
|
||||
id: my_boiler
|
||||
name: "Test Boiler"
|
||||
min_temperature: 10
|
||||
max_temperature: 85
|
||||
target_temperature_step: 0.5
|
||||
current_temperature_step: 0.1
|
||||
optimistic: true
|
||||
current_temperature: 45.0
|
||||
mode: !lambda "return water_heater::WATER_HEATER_MODE_ECO;"
|
||||
visual:
|
||||
min_temperature: 10
|
||||
max_temperature: 85
|
||||
target_temperature_step: 0.5
|
||||
current_temperature_step: 0.1
|
||||
@@ -36,3 +36,4 @@ datetime:
|
||||
optimistic: yes
|
||||
event:
|
||||
update:
|
||||
water_heater:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
esphome:
|
||||
name: water-heater-template-test
|
||||
host:
|
||||
api:
|
||||
logger:
|
||||
|
||||
water_heater:
|
||||
- platform: template
|
||||
id: test_boiler
|
||||
name: Test Boiler
|
||||
optimistic: true
|
||||
current_temperature: !lambda "return 45.0f;"
|
||||
# Note: No mode lambda - we want optimistic mode changes to stick
|
||||
# A mode lambda would override mode changes in loop()
|
||||
supported_modes:
|
||||
- "off"
|
||||
- eco
|
||||
- gas
|
||||
- performance
|
||||
visual:
|
||||
min_temperature: 30.0
|
||||
max_temperature: 85.0
|
||||
target_temperature_step: 0.5
|
||||
@@ -0,0 +1,109 @@
|
||||
"""Integration test for template water heater component."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
import aioesphomeapi
|
||||
from aioesphomeapi import WaterHeaterInfo, WaterHeaterMode, WaterHeaterState
|
||||
import pytest
|
||||
|
||||
from .state_utils import InitialStateHelper
|
||||
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_water_heater_template(
|
||||
yaml_config: str,
|
||||
run_compiled: RunCompiledFunction,
|
||||
api_client_connected: APIClientConnectedFactory,
|
||||
) -> None:
|
||||
"""Test template water heater basic state and mode changes."""
|
||||
loop = asyncio.get_running_loop()
|
||||
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||
states: dict[int, aioesphomeapi.EntityState] = {}
|
||||
gas_mode_future: asyncio.Future[WaterHeaterState] = loop.create_future()
|
||||
eco_mode_future: asyncio.Future[WaterHeaterState] = loop.create_future()
|
||||
|
||||
def on_state(state: aioesphomeapi.EntityState) -> None:
|
||||
states[state.key] = state
|
||||
if isinstance(state, WaterHeaterState):
|
||||
# Wait for GAS mode
|
||||
if state.mode == WaterHeaterMode.GAS and not gas_mode_future.done():
|
||||
gas_mode_future.set_result(state)
|
||||
# Wait for ECO mode (we start at OFF, so test transitioning to ECO)
|
||||
elif state.mode == WaterHeaterMode.ECO and not eco_mode_future.done():
|
||||
eco_mode_future.set_result(state)
|
||||
|
||||
# Get entities and set up state synchronization
|
||||
entities, services = await client.list_entities_services()
|
||||
initial_state_helper = InitialStateHelper(entities)
|
||||
water_heater_infos = [e for e in entities if isinstance(e, WaterHeaterInfo)]
|
||||
assert len(water_heater_infos) == 1, (
|
||||
f"Expected exactly 1 water heater entity, got {len(water_heater_infos)}. Entity types: {[type(e).__name__ for e in entities]}"
|
||||
)
|
||||
|
||||
test_water_heater = water_heater_infos[0]
|
||||
|
||||
# Verify water heater entity info
|
||||
assert test_water_heater.object_id == "test_boiler"
|
||||
assert test_water_heater.name == "Test Boiler"
|
||||
assert test_water_heater.min_temperature == 30.0
|
||||
assert test_water_heater.max_temperature == 85.0
|
||||
assert test_water_heater.target_temperature_step == 0.5
|
||||
|
||||
# Verify supported modes
|
||||
supported_modes = test_water_heater.supported_modes
|
||||
assert WaterHeaterMode.OFF in supported_modes, "Expected OFF in supported modes"
|
||||
assert WaterHeaterMode.ECO in supported_modes, "Expected ECO in supported modes"
|
||||
assert WaterHeaterMode.GAS in supported_modes, "Expected GAS in supported modes"
|
||||
assert WaterHeaterMode.PERFORMANCE in supported_modes, (
|
||||
"Expected PERFORMANCE in supported modes"
|
||||
)
|
||||
assert len(supported_modes) == 4, (
|
||||
f"Expected 4 supported modes, got {len(supported_modes)}: {supported_modes}"
|
||||
)
|
||||
|
||||
# Subscribe with the wrapper that filters initial states
|
||||
client.subscribe_states(initial_state_helper.on_state_wrapper(on_state))
|
||||
|
||||
# Wait for all initial states to be broadcast
|
||||
try:
|
||||
await initial_state_helper.wait_for_initial_states()
|
||||
except TimeoutError:
|
||||
pytest.fail("Timeout waiting for initial states")
|
||||
|
||||
# Get initial state and verify
|
||||
initial_state = initial_state_helper.initial_states.get(test_water_heater.key)
|
||||
assert initial_state is not None, "Water heater initial state not found"
|
||||
assert isinstance(initial_state, WaterHeaterState)
|
||||
# Initial mode is OFF (default) since we don't have a mode lambda
|
||||
# A mode lambda would override optimistic mode changes
|
||||
assert initial_state.mode == WaterHeaterMode.OFF, (
|
||||
f"Expected initial mode OFF, got {initial_state.mode}"
|
||||
)
|
||||
assert initial_state.current_temperature == 45.0, (
|
||||
f"Expected current temp 45.0, got {initial_state.current_temperature}"
|
||||
)
|
||||
|
||||
# Test changing to GAS mode
|
||||
client.water_heater_command(test_water_heater.key, mode=WaterHeaterMode.GAS)
|
||||
|
||||
try:
|
||||
gas_state = await asyncio.wait_for(gas_mode_future, timeout=5.0)
|
||||
except TimeoutError:
|
||||
pytest.fail("GAS mode change not received within 5 seconds")
|
||||
|
||||
assert isinstance(gas_state, WaterHeaterState)
|
||||
assert gas_state.mode == WaterHeaterMode.GAS
|
||||
|
||||
# Test changing to ECO mode (from GAS)
|
||||
client.water_heater_command(test_water_heater.key, mode=WaterHeaterMode.ECO)
|
||||
|
||||
try:
|
||||
eco_state = await asyncio.wait_for(eco_mode_future, timeout=5.0)
|
||||
except TimeoutError:
|
||||
pytest.fail("ECO mode change not received within 5 seconds")
|
||||
|
||||
assert isinstance(eco_state, WaterHeaterState)
|
||||
assert eco_state.mode == WaterHeaterMode.ECO
|
||||
Reference in New Issue
Block a user