From 1a458589041e2df1ba1b8a8ed9e128627b4ea036 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 13 May 2024 07:56:55 +1000 Subject: [PATCH 1/7] Add pylint to git pre-commit hooks (#6726) --- .pre-commit-config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6f4bb52104..ce226846e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,3 +40,10 @@ repos: hooks: - id: clang-format types_or: [c, c++] + - repo: local + hooks: + - id: pylint + name: pylint + entry: pylint + language: system + types: [python] From 61b65e2726485ea4d12fc5f47de1e614236fa182 Mon Sep 17 00:00:00 2001 From: Marcin Krasowski Date: Mon, 13 May 2024 01:25:41 +0200 Subject: [PATCH 2/7] fix(ltr390): stuck ALS values when configured for ALS+UV readings (#6723) --- esphome/components/ltr390/ltr390.cpp | 31 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/esphome/components/ltr390/ltr390.cpp b/esphome/components/ltr390/ltr390.cpp index 65c08ab614..4eb1ff2c46 100644 --- a/esphome/components/ltr390/ltr390.cpp +++ b/esphome/components/ltr390/ltr390.cpp @@ -8,6 +8,9 @@ namespace ltr390 { static const char *const TAG = "ltr390"; +static const uint8_t LTR390_WAKEUP_TIME = 10; +static const uint8_t LTR390_SETTLE_TIME = 5; + static const uint8_t LTR390_MAIN_CTRL = 0x00; static const uint8_t LTR390_MEAS_RATE = 0x04; static const uint8_t LTR390_GAIN = 0x05; @@ -101,21 +104,27 @@ void LTR390Component::read_mode_(int mode_index) { std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); ctrl[LTR390_CTRL_MODE] = mode; + ctrl[LTR390_CTRL_EN] = true; this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); // After the sensor integration time do the following - this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100, [this, mode_index]() { - // Read from the sensor - std::get<1>(this->mode_funcs_[mode_index])(); + this->set_timeout(((uint32_t) RESOLUTIONVALUE[this->res_]) * 100 + LTR390_WAKEUP_TIME + LTR390_SETTLE_TIME, + [this, mode_index]() { + // Read from the sensor + std::get<1>(this->mode_funcs_[mode_index])(); - // If there are more modes to read then begin the next - // otherwise stop - if (mode_index + 1 < (int) this->mode_funcs_.size()) { - this->read_mode_(mode_index + 1); - } else { - this->reading_ = false; - } - }); + // If there are more modes to read then begin the next + // otherwise stop + if (mode_index + 1 < (int) this->mode_funcs_.size()) { + this->read_mode_(mode_index + 1); + } else { + // put sensor in standby + std::bitset<8> ctrl = this->reg(LTR390_MAIN_CTRL).get(); + ctrl[LTR390_CTRL_EN] = false; + this->reg(LTR390_MAIN_CTRL) = ctrl.to_ulong(); + this->reading_ = false; + } + }); } void LTR390Component::setup() { From 67ca60e2afa118818a97c12246a1b751b16a2cf4 Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 13 May 2024 01:54:43 +0200 Subject: [PATCH 3/7] separate debug component for each platform in different file (#6715) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/debug/debug_component.cpp | 374 +------------------ esphome/components/debug/debug_component.h | 5 + esphome/components/debug/debug_esp32.cpp | 287 ++++++++++++++ esphome/components/debug/debug_esp8266.cpp | 94 +++++ esphome/components/debug/debug_host.cpp | 18 + esphome/components/debug/debug_libretiny.cpp | 44 +++ esphome/components/debug/debug_rp2040.cpp | 23 ++ 7 files changed, 479 insertions(+), 366 deletions(-) create mode 100644 esphome/components/debug/debug_esp32.cpp create mode 100644 esphome/components/debug/debug_esp8266.cpp create mode 100644 esphome/components/debug/debug_host.cpp create mode 100644 esphome/components/debug/debug_libretiny.cpp create mode 100644 esphome/components/debug/debug_rp2040.cpp diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index f22a8a2e5d..cbd4249d92 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -8,62 +8,16 @@ #include #include -#ifdef USE_ESP32 - -#include -#include - -#include -#if defined(USE_ESP32_VARIANT_ESP32) -#include -#elif defined(USE_ESP32_VARIANT_ESP32C3) -#include -#elif defined(USE_ESP32_VARIANT_ESP32C6) -#include -#elif defined(USE_ESP32_VARIANT_ESP32S2) -#include -#elif defined(USE_ESP32_VARIANT_ESP32S3) -#include -#endif - -#endif // USE_ESP32 - -#ifdef USE_ARDUINO -#ifdef USE_RP2040 -#include -#elif defined(USE_ESP32) || defined(USE_ESP8266) -#include -#endif -#endif - namespace esphome { namespace debug { static const char *const TAG = "debug"; -static uint32_t get_free_heap() { -#if defined(USE_ESP8266) - return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance) -#elif defined(USE_ESP32) - return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); -#elif defined(USE_RP2040) - return rp2040.getFreeHeap(); -#elif defined(USE_LIBRETINY) - return lt_heap_get_free(); -#elif defined(USE_HOST) - return INT_MAX; -#endif -} - void DebugComponent::dump_config() { #ifndef ESPHOME_LOG_HAS_DEBUG return; // Can't log below if debug logging is disabled #endif - std::string device_info; - std::string reset_reason; - device_info.reserve(256); - ESP_LOGCONFIG(TAG, "Debug component:"); #ifdef USE_TEXT_SENSOR LOG_TEXT_SENSOR(" ", "Device info", this->device_info_); @@ -76,305 +30,15 @@ void DebugComponent::dump_config() { #endif // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) #endif // USE_SENSOR + std::string device_info; + device_info.reserve(256); ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION); device_info += ESPHOME_VERSION; - this->free_heap_ = get_free_heap(); + this->free_heap_ = get_free_heap_(); ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); -#if defined(USE_ARDUINO) && (defined(USE_ESP32) || defined(USE_ESP8266)) - const char *flash_mode; - switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance) - case FM_QIO: - flash_mode = "QIO"; - break; - case FM_QOUT: - flash_mode = "QOUT"; - break; - case FM_DIO: - flash_mode = "DIO"; - break; - case FM_DOUT: - flash_mode = "DOUT"; - break; -#ifdef USE_ESP32 - case FM_FAST_READ: - flash_mode = "FAST_READ"; - break; - case FM_SLOW_READ: - flash_mode = "SLOW_READ"; - break; -#endif - default: - flash_mode = "UNKNOWN"; - } - ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s", - ESP.getFlashChipSize() / 1024, // NOLINT - ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT - device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT - "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT - device_info += flash_mode; -#endif // USE_ARDUINO && (USE_ESP32 || USE_ESP8266) - -#ifdef USE_ESP32 - esp_chip_info_t info; - esp_chip_info(&info); - const char *model; -#if defined(USE_ESP32_VARIANT_ESP32) - model = "ESP32"; -#elif defined(USE_ESP32_VARIANT_ESP32C3) - model = "ESP32-C3"; -#elif defined(USE_ESP32_VARIANT_ESP32C6) - model = "ESP32-C6"; -#elif defined(USE_ESP32_VARIANT_ESP32S2) - model = "ESP32-S2"; -#elif defined(USE_ESP32_VARIANT_ESP32S3) - model = "ESP32-S3"; -#elif defined(USE_ESP32_VARIANT_ESP32H2) - model = "ESP32-H2"; -#else - model = "UNKNOWN"; -#endif - std::string features; - if (info.features & CHIP_FEATURE_EMB_FLASH) { - features += "EMB_FLASH,"; - info.features &= ~CHIP_FEATURE_EMB_FLASH; - } - if (info.features & CHIP_FEATURE_WIFI_BGN) { - features += "WIFI_BGN,"; - info.features &= ~CHIP_FEATURE_WIFI_BGN; - } - if (info.features & CHIP_FEATURE_BLE) { - features += "BLE,"; - info.features &= ~CHIP_FEATURE_BLE; - } - if (info.features & CHIP_FEATURE_BT) { - features += "BT,"; - info.features &= ~CHIP_FEATURE_BT; - } - if (info.features & CHIP_FEATURE_EMB_PSRAM) { - features += "EMB_PSRAM,"; - info.features &= ~CHIP_FEATURE_EMB_PSRAM; - } - if (info.features) - features += "Other:" + format_hex(info.features); - ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores, - info.revision); - device_info += "|Chip: "; - device_info += model; - device_info += " Features:"; - device_info += features; - device_info += " Cores:" + to_string(info.cores); - device_info += " Revision:" + to_string(info.revision); - - ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version()); - device_info += "|ESP-IDF: "; - device_info += esp_get_idf_version(); - - std::string mac = get_mac_address_pretty(); - ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str()); - device_info += "|EFuse MAC: "; - device_info += mac; - - switch (rtc_get_reset_reason(0)) { - case POWERON_RESET: - reset_reason = "Power On Reset"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case SW_RESET: -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case RTC_SW_SYS_RESET: -#endif - reset_reason = "Software Reset Digital Core"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case OWDT_RESET: - reset_reason = "Watch Dog Reset Digital Core"; - break; -#endif - case DEEPSLEEP_RESET: - reset_reason = "Deep Sleep Reset Digital Core"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case SDIO_RESET: - reset_reason = "SLC Module Reset Digital Core"; - break; -#endif - case TG0WDT_SYS_RESET: - reset_reason = "Timer Group 0 Watch Dog Reset Digital Core"; - break; - case TG1WDT_SYS_RESET: - reset_reason = "Timer Group 1 Watch Dog Reset Digital Core"; - break; - case RTCWDT_SYS_RESET: - reset_reason = "RTC Watch Dog Reset Digital Core"; - break; -#if !defined(USE_ESP32_VARIANT_ESP32C6) - case INTRUSION_RESET: - reset_reason = "Intrusion Reset CPU"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32) - case TGWDT_CPU_RESET: - reset_reason = "Timer Group Reset CPU"; - break; -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case TG0WDT_CPU_RESET: - reset_reason = "Timer Group 0 Reset CPU"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32) - case SW_CPU_RESET: -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case RTC_SW_CPU_RESET: -#endif - reset_reason = "Software Reset CPU"; - break; - case RTCWDT_CPU_RESET: - reset_reason = "RTC Watch Dog Reset CPU"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case EXT_CPU_RESET: - reset_reason = "External CPU Reset"; - break; -#endif - case RTCWDT_BROWN_OUT_RESET: - reset_reason = "Voltage Unstable Reset"; - break; - case RTCWDT_RTC_RESET: - reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module"; - break; -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case TG1WDT_CPU_RESET: - reset_reason = "Timer Group 1 Reset CPU"; - break; - case SUPER_WDT_RESET: - reset_reason = "Super Watchdog Reset Digital Core And RTC Module"; - break; - case GLITCH_RTC_RESET: - reset_reason = "Glitch Reset Digital Core And RTC Module"; - break; - case EFUSE_RESET: - reset_reason = "eFuse Reset Digital Core"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) - case USB_UART_CHIP_RESET: - reset_reason = "USB UART Reset Digital Core"; - break; - case USB_JTAG_CHIP_RESET: - reset_reason = "USB JTAG Reset Digital Core"; - break; - case POWER_GLITCH_RESET: - reset_reason = "Power Glitch Reset Digital Core And RTC Module"; - break; -#endif - default: - reset_reason = "Unknown Reset Reason"; - } - ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str()); - device_info += "|Reset: "; - device_info += reset_reason; - - const char *wakeup_reason; - switch (rtc_get_wakeup_cause()) { - case NO_SLEEP: - wakeup_reason = "No Sleep"; - break; - case EXT_EVENT0_TRIG: - wakeup_reason = "External Event 0"; - break; - case EXT_EVENT1_TRIG: - wakeup_reason = "External Event 1"; - break; - case GPIO_TRIG: - wakeup_reason = "GPIO"; - break; - case TIMER_EXPIRE: - wakeup_reason = "Wakeup Timer"; - break; - case SDIO_TRIG: - wakeup_reason = "SDIO"; - break; - case MAC_TRIG: - wakeup_reason = "MAC"; - break; - case UART0_TRIG: - wakeup_reason = "UART0"; - break; - case UART1_TRIG: - wakeup_reason = "UART1"; - break; - case TOUCH_TRIG: - wakeup_reason = "Touch"; - break; - case SAR_TRIG: - wakeup_reason = "SAR"; - break; - case BT_TRIG: - wakeup_reason = "BT"; - break; - default: - wakeup_reason = "Unknown"; - } - ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason); - device_info += "|Wakeup: "; - device_info += wakeup_reason; -#endif - -#if defined(USE_ESP8266) && !defined(CLANG_TIDY) - 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", ESP.getResetReason().c_str()); - ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str()); - - device_info += "|Chip: 0x" + format_hex(ESP.getChipId()); - device_info += "|SDK: "; - device_info += ESP.getSdkVersion(); - device_info += "|Core: "; - device_info += ESP.getCoreVersion().c_str(); - device_info += "|Boot: "; - device_info += to_string(ESP.getBootVersion()); - device_info += "|Mode: " + to_string(ESP.getBootMode()); - device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz()); - device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId()); - device_info += "|Reset: "; - device_info += ESP.getResetReason().c_str(); - device_info += "|"; - device_info += ESP.getResetInfo().c_str(); - - reset_reason = ESP.getResetReason().c_str(); -#endif - -#ifdef USE_RP2040 - ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu()); - device_info += "CPU Frequency: " + to_string(rp2040.f_cpu()); -#endif // USE_RP2040 - -#ifdef USE_LIBRETINY - 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", lt_get_reboot_reason_name(lt_get_reboot_reason())); - - device_info += "|Version: "; - device_info += LT_BANNER_STR + 10; - device_info += "|Reset Reason: "; - device_info += lt_get_reboot_reason_name(lt_get_reboot_reason()); - device_info += "|Chip Name: "; - device_info += lt_cpu_get_model_name(); - device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id()); - device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB"; - device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB"; - - reset_reason = lt_get_reboot_reason_name(lt_get_reboot_reason()); -#endif // USE_LIBRETINY + get_device_info_(device_info); #ifdef USE_TEXT_SENSOR if (this->device_info_ != nullptr) { @@ -383,14 +47,14 @@ void DebugComponent::dump_config() { this->device_info_->publish_state(device_info); } if (this->reset_reason_ != nullptr) { - this->reset_reason_->publish_state(reset_reason); + this->reset_reason_->publish_state(get_reset_reason_()); } #endif // USE_TEXT_SENSOR } void DebugComponent::loop() { // log when free heap space has halved - uint32_t new_free_heap = get_free_heap(); + uint32_t new_free_heap = get_free_heap_(); if (new_free_heap < this->free_heap_ / 2) { this->free_heap_ = new_free_heap; ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_); @@ -411,38 +75,16 @@ void DebugComponent::loop() { void DebugComponent::update() { #ifdef USE_SENSOR if (this->free_sensor_ != nullptr) { - this->free_sensor_->publish_state(get_free_heap()); + this->free_sensor_->publish_state(get_free_heap_()); } - if (this->block_sensor_ != nullptr) { -#if defined(USE_ESP8266) - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize()); -#elif defined(USE_ESP32) - this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); -#elif defined(USE_LIBRETINY) - this->block_sensor_->publish_state(lt_heap_get_max_alloc()); -#endif - } - -#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) - if (this->fragmentation_sensor_ != nullptr) { - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation()); - } -#endif - if (this->loop_time_sensor_ != nullptr) { this->loop_time_sensor_->publish_state(this->max_loop_time_); this->max_loop_time_ = 0; } -#ifdef USE_ESP32 - if (this->psram_sensor_ != nullptr) { - this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); - } -#endif // USE_ESP32 #endif // USE_SENSOR + update_platform_(); } float DebugComponent::get_setup_priority() const { return setup_priority::LATE; } diff --git a/esphome/components/debug/debug_component.h b/esphome/components/debug/debug_component.h index 93e3ba4857..2b54406603 100644 --- a/esphome/components/debug/debug_component.h +++ b/esphome/components/debug/debug_component.h @@ -59,6 +59,11 @@ class DebugComponent : public PollingComponent { text_sensor::TextSensor *device_info_{nullptr}; text_sensor::TextSensor *reset_reason_{nullptr}; #endif // USE_TEXT_SENSOR + + std::string get_reset_reason_(); + uint32_t get_free_heap_(); + void get_device_info_(std::string &device_info); + void update_platform_(); }; } // namespace debug diff --git a/esphome/components/debug/debug_esp32.cpp b/esphome/components/debug/debug_esp32.cpp new file mode 100644 index 0000000000..cfdfdd2a61 --- /dev/null +++ b/esphome/components/debug/debug_esp32.cpp @@ -0,0 +1,287 @@ +#include "debug_component.h" +#ifdef USE_ESP32 +#include "esphome/core/log.h" + +#include +#include +#include + +#if defined(USE_ESP32_VARIANT_ESP32) +#include +#elif defined(USE_ESP32_VARIANT_ESP32C3) +#include +#elif defined(USE_ESP32_VARIANT_ESP32C6) +#include +#elif defined(USE_ESP32_VARIANT_ESP32S2) +#include +#elif defined(USE_ESP32_VARIANT_ESP32S3) +#include +#endif +#ifdef USE_ARDUINO +#include +#endif + +namespace esphome { +namespace debug { + +static const char *const TAG = "debug"; + +std::string DebugComponent::get_reset_reason_() { + std::string reset_reason; + switch (rtc_get_reset_reason(0)) { + case POWERON_RESET: + reset_reason = "Power On Reset"; + break; +#if defined(USE_ESP32_VARIANT_ESP32) + case SW_RESET: +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case RTC_SW_SYS_RESET: +#endif + reset_reason = "Software Reset Digital Core"; + break; +#if defined(USE_ESP32_VARIANT_ESP32) + case OWDT_RESET: + reset_reason = "Watch Dog Reset Digital Core"; + break; +#endif + case DEEPSLEEP_RESET: + reset_reason = "Deep Sleep Reset Digital Core"; + break; +#if defined(USE_ESP32_VARIANT_ESP32) + case SDIO_RESET: + reset_reason = "SLC Module Reset Digital Core"; + break; +#endif + case TG0WDT_SYS_RESET: + reset_reason = "Timer Group 0 Watch Dog Reset Digital Core"; + break; + case TG1WDT_SYS_RESET: + reset_reason = "Timer Group 1 Watch Dog Reset Digital Core"; + break; + case RTCWDT_SYS_RESET: + reset_reason = "RTC Watch Dog Reset Digital Core"; + break; +#if !defined(USE_ESP32_VARIANT_ESP32C6) + case INTRUSION_RESET: + reset_reason = "Intrusion Reset CPU"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32) + case TGWDT_CPU_RESET: + reset_reason = "Timer Group Reset CPU"; + break; +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case TG0WDT_CPU_RESET: + reset_reason = "Timer Group 0 Reset CPU"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32) + case SW_CPU_RESET: +#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case RTC_SW_CPU_RESET: +#endif + reset_reason = "Software Reset CPU"; + break; + case RTCWDT_CPU_RESET: + reset_reason = "RTC Watch Dog Reset CPU"; + break; +#if defined(USE_ESP32_VARIANT_ESP32) + case EXT_CPU_RESET: + reset_reason = "External CPU Reset"; + break; +#endif + case RTCWDT_BROWN_OUT_RESET: + reset_reason = "Voltage Unstable Reset"; + break; + case RTCWDT_RTC_RESET: + reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module"; + break; +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + case TG1WDT_CPU_RESET: + reset_reason = "Timer Group 1 Reset CPU"; + break; + case SUPER_WDT_RESET: + reset_reason = "Super Watchdog Reset Digital Core And RTC Module"; + break; + case GLITCH_RTC_RESET: + reset_reason = "Glitch Reset Digital Core And RTC Module"; + break; + case EFUSE_RESET: + reset_reason = "eFuse Reset Digital Core"; + break; +#endif +#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) + case USB_UART_CHIP_RESET: + reset_reason = "USB UART Reset Digital Core"; + break; + case USB_JTAG_CHIP_RESET: + reset_reason = "USB JTAG Reset Digital Core"; + break; + case POWER_GLITCH_RESET: + reset_reason = "Power Glitch Reset Digital Core And RTC Module"; + break; +#endif + default: + reset_reason = "Unknown Reset Reason"; + } + ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str()); + return reset_reason; +} + +uint32_t DebugComponent::get_free_heap_() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); } + +void DebugComponent::get_device_info_(std::string &device_info) { +#if defined(USE_ARDUINO) + const char *flash_mode; + switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance) + case FM_QIO: + flash_mode = "QIO"; + break; + case FM_QOUT: + flash_mode = "QOUT"; + break; + case FM_DIO: + flash_mode = "DIO"; + break; + case FM_DOUT: + flash_mode = "DOUT"; + break; + case FM_FAST_READ: + flash_mode = "FAST_READ"; + break; + case FM_SLOW_READ: + flash_mode = "SLOW_READ"; + break; + default: + flash_mode = "UNKNOWN"; + } + ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s", + ESP.getFlashChipSize() / 1024, // NOLINT + ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT + device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT + "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT + device_info += flash_mode; +#endif + + esp_chip_info_t info; + esp_chip_info(&info); + const char *model; +#if defined(USE_ESP32_VARIANT_ESP32) + model = "ESP32"; +#elif defined(USE_ESP32_VARIANT_ESP32C3) + model = "ESP32-C3"; +#elif defined(USE_ESP32_VARIANT_ESP32C6) + model = "ESP32-C6"; +#elif defined(USE_ESP32_VARIANT_ESP32S2) + model = "ESP32-S2"; +#elif defined(USE_ESP32_VARIANT_ESP32S3) + model = "ESP32-S3"; +#elif defined(USE_ESP32_VARIANT_ESP32H2) + model = "ESP32-H2"; +#else + model = "UNKNOWN"; +#endif + std::string features; + if (info.features & CHIP_FEATURE_EMB_FLASH) { + features += "EMB_FLASH,"; + info.features &= ~CHIP_FEATURE_EMB_FLASH; + } + if (info.features & CHIP_FEATURE_WIFI_BGN) { + features += "WIFI_BGN,"; + info.features &= ~CHIP_FEATURE_WIFI_BGN; + } + if (info.features & CHIP_FEATURE_BLE) { + features += "BLE,"; + info.features &= ~CHIP_FEATURE_BLE; + } + if (info.features & CHIP_FEATURE_BT) { + features += "BT,"; + info.features &= ~CHIP_FEATURE_BT; + } + if (info.features & CHIP_FEATURE_EMB_PSRAM) { + features += "EMB_PSRAM,"; + info.features &= ~CHIP_FEATURE_EMB_PSRAM; + } + if (info.features) + features += "Other:" + format_hex(info.features); + ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores, + info.revision); + device_info += "|Chip: "; + device_info += model; + device_info += " Features:"; + device_info += features; + device_info += " Cores:" + to_string(info.cores); + device_info += " Revision:" + to_string(info.revision); + + ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version()); + device_info += "|ESP-IDF: "; + device_info += esp_get_idf_version(); + + std::string mac = get_mac_address_pretty(); + ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str()); + device_info += "|EFuse MAC: "; + device_info += mac; + + device_info += "|Reset: "; + device_info += get_reset_reason_(); + + const char *wakeup_reason; + switch (rtc_get_wakeup_cause()) { + case NO_SLEEP: + wakeup_reason = "No Sleep"; + break; + case EXT_EVENT0_TRIG: + wakeup_reason = "External Event 0"; + break; + case EXT_EVENT1_TRIG: + wakeup_reason = "External Event 1"; + break; + case GPIO_TRIG: + wakeup_reason = "GPIO"; + break; + case TIMER_EXPIRE: + wakeup_reason = "Wakeup Timer"; + break; + case SDIO_TRIG: + wakeup_reason = "SDIO"; + break; + case MAC_TRIG: + wakeup_reason = "MAC"; + break; + case UART0_TRIG: + wakeup_reason = "UART0"; + break; + case UART1_TRIG: + wakeup_reason = "UART1"; + break; + case TOUCH_TRIG: + wakeup_reason = "Touch"; + break; + case SAR_TRIG: + wakeup_reason = "SAR"; + break; + case BT_TRIG: + wakeup_reason = "BT"; + break; + default: + wakeup_reason = "Unknown"; + } + ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason); + device_info += "|Wakeup: "; + device_info += wakeup_reason; +} + +void DebugComponent::update_platform_() { +#ifdef USE_SENSOR + if (this->block_sensor_ != nullptr) { + this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); + } + if (this->psram_sensor_ != nullptr) { + this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + } +#endif +} + +} // namespace debug +} // namespace esphome +#endif diff --git a/esphome/components/debug/debug_esp8266.cpp b/esphome/components/debug/debug_esp8266.cpp new file mode 100644 index 0000000000..3395d9db12 --- /dev/null +++ b/esphome/components/debug/debug_esp8266.cpp @@ -0,0 +1,94 @@ +#include "debug_component.h" +#ifdef USE_ESP8266 +#include "esphome/core/log.h" +#include + +namespace esphome { +namespace debug { + +static const char *const TAG = "debug"; + +std::string DebugComponent::get_reset_reason_() { +#if !defined(CLANG_TIDY) + return ESP.getResetReason().c_str(); +#else + return ""; +#endif +} + +uint32_t DebugComponent::get_free_heap_() { + return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance) +} + +void DebugComponent::get_device_info_(std::string &device_info) { + const char *flash_mode; + switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance) + case FM_QIO: + flash_mode = "QIO"; + break; + case FM_QOUT: + flash_mode = "QOUT"; + break; + case FM_DIO: + flash_mode = "DIO"; + break; + case FM_DOUT: + flash_mode = "DOUT"; + break; + default: + flash_mode = "UNKNOWN"; + } + ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s", + ESP.getFlashChipSize() / 1024, // NOLINT + ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT + device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT + "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT + device_info += flash_mode; + +#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()); + + device_info += "|Chip: 0x" + format_hex(ESP.getChipId()); + device_info += "|SDK: "; + device_info += ESP.getSdkVersion(); + device_info += "|Core: "; + device_info += ESP.getCoreVersion().c_str(); + device_info += "|Boot: "; + device_info += to_string(ESP.getBootVersion()); + device_info += "|Mode: " + to_string(ESP.getBootMode()); + device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz()); + device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId()); + device_info += "|Reset: "; + device_info += reset_reason; + device_info += "|"; + device_info += ESP.getResetInfo().c_str(); +#endif +} + +void DebugComponent::update_platform_() { +#ifdef USE_SENSOR + if (this->block_sensor_ != nullptr) { + // NOLINTNEXTLINE(readability-static-accessed-through-instance) + this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize()); + } +#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) + if (this->fragmentation_sensor_ != nullptr) { + // NOLINTNEXTLINE(readability-static-accessed-through-instance) + this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation()); + } +#endif + +#endif +} + +} // namespace debug +} // namespace esphome +#endif diff --git a/esphome/components/debug/debug_host.cpp b/esphome/components/debug/debug_host.cpp new file mode 100644 index 0000000000..09ad34ef88 --- /dev/null +++ b/esphome/components/debug/debug_host.cpp @@ -0,0 +1,18 @@ +#include "debug_component.h" +#ifdef USE_HOST +#include + +namespace esphome { +namespace debug { + +std::string DebugComponent::get_reset_reason_() { return ""; } + +uint32_t DebugComponent::get_free_heap_() { return INT_MAX; } + +void DebugComponent::get_device_info_(std::string &device_info) {} + +void DebugComponent::update_platform_() {} + +} // namespace debug +} // namespace esphome +#endif diff --git a/esphome/components/debug/debug_libretiny.cpp b/esphome/components/debug/debug_libretiny.cpp new file mode 100644 index 0000000000..725cd870ca --- /dev/null +++ b/esphome/components/debug/debug_libretiny.cpp @@ -0,0 +1,44 @@ +#include "debug_component.h" +#ifdef USE_LIBRETINY +#include "esphome/core/log.h" + +namespace esphome { +namespace debug { + +static const char *const TAG = "debug"; + +std::string DebugComponent::get_reset_reason_() { return lt_get_reboot_reason_name(lt_get_reboot_reason()); } + +uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); } + +void DebugComponent::get_device_info_(std::string &device_info) { + 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()); + + device_info += "|Version: "; + device_info += LT_BANNER_STR + 10; + device_info += "|Reset Reason: "; + device_info += reset_reason; + device_info += "|Chip Name: "; + device_info += lt_cpu_get_model_name(); + device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id()); + device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB"; + device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB"; +} + +void DebugComponent::update_platform_() { +#ifdef USE_SENSOR + if (this->block_sensor_ != nullptr) { + this->block_sensor_->publish_state(lt_heap_get_max_alloc()); + } +#endif +} + +} // namespace debug +} // namespace esphome +#endif diff --git a/esphome/components/debug/debug_rp2040.cpp b/esphome/components/debug/debug_rp2040.cpp new file mode 100644 index 0000000000..497547e30d --- /dev/null +++ b/esphome/components/debug/debug_rp2040.cpp @@ -0,0 +1,23 @@ +#include "debug_component.h" +#ifdef USE_RP2040 +#include "esphome/core/log.h" +#include +namespace esphome { +namespace debug { + +static const char *const TAG = "debug"; + +std::string DebugComponent::get_reset_reason_() { return ""; } + +uint32_t DebugComponent::get_free_heap_() { return rp2040.getFreeHeap(); } + +void DebugComponent::get_device_info_(std::string &device_info) { + ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu()); + device_info += "CPU Frequency: " + to_string(rp2040.f_cpu()); +} + +void DebugComponent::update_platform_() {} + +} // namespace debug +} // namespace esphome +#endif From 13e3920c13ce8af481b0e89d61703e61051a0b0d Mon Sep 17 00:00:00 2001 From: Szewcson Date: Mon, 13 May 2024 03:36:10 +0200 Subject: [PATCH 4/7] GDK101 support (#4703) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/gdk101/__init__.py | 32 ++++ esphome/components/gdk101/binary_sensor.py | 29 +++ esphome/components/gdk101/gdk101.cpp | 189 ++++++++++++++++++++ esphome/components/gdk101/gdk101.h | 52 ++++++ esphome/components/gdk101/sensor.py | 83 +++++++++ esphome/const.py | 3 + tests/components/gdk101/common.yaml | 28 +++ tests/components/gdk101/test.esp32-idf.yaml | 5 + tests/components/gdk101/test.esp32.yaml | 5 + tests/components/gdk101/test.esp8266.yaml | 5 + tests/components/gdk101/test.rp2040.yaml | 5 + 12 files changed, 437 insertions(+) create mode 100644 esphome/components/gdk101/__init__.py create mode 100644 esphome/components/gdk101/binary_sensor.py create mode 100644 esphome/components/gdk101/gdk101.cpp create mode 100644 esphome/components/gdk101/gdk101.h create mode 100644 esphome/components/gdk101/sensor.py create mode 100644 tests/components/gdk101/common.yaml create mode 100644 tests/components/gdk101/test.esp32-idf.yaml create mode 100644 tests/components/gdk101/test.esp32.yaml create mode 100644 tests/components/gdk101/test.esp8266.yaml create mode 100644 tests/components/gdk101/test.rp2040.yaml diff --git a/CODEOWNERS b/CODEOWNERS index c630db7948..88f875f368 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -135,6 +135,7 @@ esphome/components/fs3000/* @kahrendt esphome/components/ft5x06/* @clydebarrow esphome/components/ft63x6/* @gpambrozio esphome/components/gcja5/* @gcormier +esphome/components/gdk101/* @Szewcson esphome/components/globals/* @esphome/core esphome/components/gp8403/* @jesserockz esphome/components/gpio/* @esphome/core diff --git a/esphome/components/gdk101/__init__.py b/esphome/components/gdk101/__init__.py new file mode 100644 index 0000000000..0d90257964 --- /dev/null +++ b/esphome/components/gdk101/__init__.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c +from esphome.const import CONF_ID + +CODEOWNERS = ["@Szewcson"] + +DEPENDENCIES = ["i2c"] +MULTI_CONF = True + +CONF_GDK101_ID = "gdk101_id" + +gdk101_ns = cg.esphome_ns.namespace("gdk101") +GDK101Component = gdk101_ns.class_( + "GDK101Component", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(GDK101Component), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x18)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/gdk101/binary_sensor.py b/esphome/components/gdk101/binary_sensor.py new file mode 100644 index 0000000000..2a3d6f07eb --- /dev/null +++ b/esphome/components/gdk101/binary_sensor.py @@ -0,0 +1,29 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor +from esphome.const import ( + CONF_VIBRATIONS, + DEVICE_CLASS_VIBRATION, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_VIBRATE, +) +from . import CONF_GDK101_ID, GDK101Component + +DEPENDENCIES = ["gdk101"] + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_GDK101_ID): cv.use_id(GDK101Component), + cv.Required(CONF_VIBRATIONS): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_VIBRATION, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + icon=ICON_VIBRATE, + ), + } +) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_GDK101_ID]) + var = await binary_sensor.new_binary_sensor(config[CONF_VIBRATIONS]) + cg.add(hub.set_vibration_binary_sensor(var)) diff --git a/esphome/components/gdk101/gdk101.cpp b/esphome/components/gdk101/gdk101.cpp new file mode 100644 index 0000000000..93f3c20fa8 --- /dev/null +++ b/esphome/components/gdk101/gdk101.cpp @@ -0,0 +1,189 @@ +#include "gdk101.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace gdk101 { + +static const char *const TAG = "gdk101"; +static const uint8_t NUMBER_OF_READ_RETRIES = 5; + +void GDK101Component::update() { + uint8_t data[2]; + if (!this->read_dose_1m_(data)) { + this->status_set_warning("Failed to read dose 1m"); + return; + } + + if (!this->read_dose_10m_(data)) { + this->status_set_warning("Failed to read dose 10m"); + return; + } + + if (!this->read_status_(data)) { + this->status_set_warning("Failed to read status"); + return; + } + + if (!this->read_measurement_duration_(data)) { + this->status_set_warning("Failed to read measurement duration"); + return; + } + this->status_clear_warning(); +} + +void GDK101Component::setup() { + uint8_t data[2]; + ESP_LOGCONFIG(TAG, "Setting up GDK101..."); + // first, reset the sensor + if (!this->reset_sensor_(data)) { + this->status_set_error("Reset failed!"); + this->mark_failed(); + return; + } + // sensor should acknowledge success of the reset procedure + if (data[0] != 1) { + this->status_set_error("Reset not acknowledged!"); + this->mark_failed(); + return; + } + delay(10); + // read firmware version + if (!this->read_fw_version_(data)) { + this->status_set_error("Failed to read firmware version"); + this->mark_failed(); + return; + } +} + +void GDK101Component::dump_config() { + ESP_LOGCONFIG(TAG, "GDK101:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, "Communication with GDK101 failed!"); + } +#ifdef USE_SENSOR + LOG_SENSOR(" ", "Firmware Version", this->fw_version_sensor_); + LOG_SENSOR(" ", "Average Radaition Dose per 1 minute", this->rad_1m_sensor_); + LOG_SENSOR(" ", "Average Radaition Dose per 10 minutes", this->rad_10m_sensor_); + LOG_SENSOR(" ", "Status", this->status_sensor_); + LOG_SENSOR(" ", "Measurement Duration", this->measurement_duration_sensor_); +#endif // USE_SENSOR + +#ifdef USE_BINARY_SENSOR + LOG_BINARY_SENSOR(" ", "Vibration Status", this->vibration_binary_sensor_); +#endif // USE_BINARY_SENSOR +} + +float GDK101Component::get_setup_priority() const { return setup_priority::DATA; } + +bool GDK101Component::read_bytes_with_retry_(uint8_t a_register, uint8_t *data, uint8_t len) { + uint8_t retry = NUMBER_OF_READ_RETRIES; + bool status = false; + while (!status && retry) { + status = this->read_bytes(a_register, data, len); + retry--; + } + return status; +} + +bool GDK101Component::reset_sensor_(uint8_t *data) { + // It looks like reset is not so well designed in that sensor + // After sending reset command it looks that sensor start performing reset and is unresponsible during read + // after a while we can send another reset command and read "0x01" as confirmation + // Documentation not going in to such details unfortunately + if (!this->read_bytes_with_retry_(GDK101_REG_RESET, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + return true; +} + +bool GDK101Component::read_dose_1m_(uint8_t *data) { +#ifdef USE_SENSOR + if (this->rad_1m_sensor_ != nullptr) { + if (!this->read_bytes(GDK101_REG_READ_1MIN_AVG, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + const float dose = data[0] + (data[1] / 100.0f); + + this->rad_1m_sensor_->publish_state(dose); + } +#endif // USE_SENSOR + return true; +} + +bool GDK101Component::read_dose_10m_(uint8_t *data) { +#ifdef USE_SENSOR + if (this->rad_10m_sensor_ != nullptr) { + if (!this->read_bytes(GDK101_REG_READ_10MIN_AVG, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + const float dose = data[0] + (data[1] / 100.0f); + + this->rad_10m_sensor_->publish_state(dose); + } +#endif // USE_SENSOR + return true; +} + +bool GDK101Component::read_status_(uint8_t *data) { + if (!this->read_bytes(GDK101_REG_READ_STATUS, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + +#ifdef USE_SENSOR + if (this->status_sensor_ != nullptr) { + this->status_sensor_->publish_state(data[0]); + } +#endif // USE_SENSOR + +#ifdef USE_BINARY_SENSOR + if (this->vibration_binary_sensor_ != nullptr) { + this->vibration_binary_sensor_->publish_state(data[1]); + } +#endif // USE_BINARY_SENSOR + + return true; +} + +bool GDK101Component::read_fw_version_(uint8_t *data) { +#ifdef USE_SENSOR + if (this->fw_version_sensor_ != nullptr) { + if (!this->read_bytes(GDK101_REG_READ_FIRMWARE, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + const float fw_version = data[0] + (data[1] / 10.0f); + + this->fw_version_sensor_->publish_state(fw_version); + } +#endif // USE_SENSOR + return true; +} + +bool GDK101Component::read_measurement_duration_(uint8_t *data) { +#ifdef USE_SENSOR + if (this->measurement_duration_sensor_ != nullptr) { + if (!this->read_bytes(GDK101_REG_READ_MEASURING_TIME, data, 2)) { + ESP_LOGE(TAG, "Updating GDK101 failed!"); + return false; + } + + const float meas_time = (data[0] * 60) + data[1]; + + this->measurement_duration_sensor_->publish_state(meas_time); + } +#endif // USE_SENSOR + return true; +} + +} // namespace gdk101 +} // namespace esphome diff --git a/esphome/components/gdk101/gdk101.h b/esphome/components/gdk101/gdk101.h new file mode 100644 index 0000000000..460e72ac89 --- /dev/null +++ b/esphome/components/gdk101/gdk101.h @@ -0,0 +1,52 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/defines.h" +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif // USE_SENSOR +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif // USE_BINARY_SENSOR +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace gdk101 { + +static const uint8_t GDK101_REG_READ_FIRMWARE = 0xB4; // Firmware version +static const uint8_t GDK101_REG_RESET = 0xA0; // Reset register - reading its value triggers reset +static const uint8_t GDK101_REG_READ_STATUS = 0xB0; // Status register +static const uint8_t GDK101_REG_READ_MEASURING_TIME = 0xB1; // Mesuring time +static const uint8_t GDK101_REG_READ_10MIN_AVG = 0xB2; // Average radiation dose per 10 min +static const uint8_t GDK101_REG_READ_1MIN_AVG = 0xB3; // Average radiation dose per 1 min + +class GDK101Component : public PollingComponent, public i2c::I2CDevice { +#ifdef USE_SENSOR + SUB_SENSOR(rad_1m) + SUB_SENSOR(rad_10m) + SUB_SENSOR(status) + SUB_SENSOR(fw_version) + SUB_SENSOR(measurement_duration) +#endif // USE_SENSOR +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(vibration) +#endif // USE_BINARY_SENSOR + + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + void update() override; + + protected: + bool read_bytes_with_retry_(uint8_t a_register, uint8_t *data, uint8_t len); + bool reset_sensor_(uint8_t *data); + bool read_dose_1m_(uint8_t *data); + bool read_dose_10m_(uint8_t *data); + bool read_status_(uint8_t *data); + bool read_fw_version_(uint8_t *data); + bool read_measurement_duration_(uint8_t *data); +}; + +} // namespace gdk101 +} // namespace esphome diff --git a/esphome/components/gdk101/sensor.py b/esphome/components/gdk101/sensor.py new file mode 100644 index 0000000000..f782264615 --- /dev/null +++ b/esphome/components/gdk101/sensor.py @@ -0,0 +1,83 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + DEVICE_CLASS_DURATION, + DEVICE_CLASS_EMPTY, + ENTITY_CATEGORY_DIAGNOSTIC, + CONF_MEASUREMENT_DURATION, + CONF_STATUS, + CONF_VERSION, + ICON_RADIOACTIVE, + ICON_TIMER, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, + UNIT_MICROSILVERTS_PER_HOUR, + UNIT_SECOND, +) +from . import CONF_GDK101_ID, GDK101Component + +CONF_RADIATION_DOSE_PER_1M = "radiation_dose_per_1m" +CONF_RADIATION_DOSE_PER_10M = "radiation_dose_per_10m" + +DEPENDENCIES = ["gdk101"] + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_GDK101_ID): cv.use_id(GDK101Component), + cv.Optional(CONF_RADIATION_DOSE_PER_1M): sensor.sensor_schema( + icon=ICON_RADIOACTIVE, + unit_of_measurement=UNIT_MICROSILVERTS_PER_HOUR, + accuracy_decimals=2, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_RADIATION_DOSE_PER_10M): sensor.sensor_schema( + icon=ICON_RADIOACTIVE, + unit_of_measurement=UNIT_MICROSILVERTS_PER_HOUR, + accuracy_decimals=2, + device_class=DEVICE_CLASS_EMPTY, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_VERSION): sensor.sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + accuracy_decimals=1, + ), + cv.Optional(CONF_STATUS): sensor.sensor_schema( + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + accuracy_decimals=0, + ), + cv.Optional(CONF_MEASUREMENT_DURATION): sensor.sensor_schema( + unit_of_measurement=UNIT_SECOND, + icon=ICON_TIMER, + accuracy_decimals=0, + state_class=STATE_CLASS_TOTAL_INCREASING, + device_class=DEVICE_CLASS_DURATION, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } +) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_GDK101_ID]) + + if radiation_dose_per_1m := config.get(CONF_RADIATION_DOSE_PER_1M): + sens = await sensor.new_sensor(radiation_dose_per_1m) + cg.add(hub.set_rad_1m_sensor(sens)) + + if radiation_dose_per_10m := config.get(CONF_RADIATION_DOSE_PER_10M): + sens = await sensor.new_sensor(radiation_dose_per_10m) + cg.add(hub.set_rad_10m_sensor(sens)) + + if version_config := config.get(CONF_VERSION): + sens = await sensor.new_sensor(version_config) + cg.add(hub.set_fw_version_sensor(sens)) + + if status_config := config.get(CONF_STATUS): + sens = await sensor.new_sensor(status_config) + cg.add(hub.set_status_sensor(sens)) + + if measurement_duration_config := config.get(CONF_MEASUREMENT_DURATION): + sens = await sensor.new_sensor(measurement_duration_config) + cg.add(hub.set_measurement_duration_sensor(sens)) diff --git a/esphome/const.py b/esphome/const.py index dba974610a..542183d3b2 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -884,6 +884,7 @@ CONF_VALUE_FONT = "value_font" CONF_VARIABLES = "variables" CONF_VARIANT = "variant" CONF_VERSION = "version" +CONF_VIBRATIONS = "vibrations" CONF_VISIBLE = "visible" CONF_VISUAL = "visual" CONF_VOLTAGE = "voltage" @@ -983,6 +984,7 @@ ICON_SIGNAL_DISTANCE_VARIANT = "mdi:signal" ICON_THERMOMETER = "mdi:thermometer" ICON_TIMELAPSE = "mdi:timelapse" ICON_TIMER = "mdi:timer-outline" +ICON_VIBRATE = "mdi:vibrate" ICON_WATER = "mdi:water" ICON_WATER_PERCENT = "mdi:water-percent" ICON_WEATHER_SUNSET = "mdi:weather-sunset" @@ -1024,6 +1026,7 @@ UNIT_METER_PER_SECOND_SQUARED = "m/s²" UNIT_MICROGRAMS_PER_CUBIC_METER = "µg/m³" UNIT_MICROMETER = "µm" UNIT_MICROSIEMENS_PER_CENTIMETER = "µS/cm" +UNIT_MICROSILVERTS_PER_HOUR = "µSv/h" UNIT_MICROTESLA = "µT" UNIT_MILLIGRAMS_PER_CUBIC_METER = "mg/m³" UNIT_MILLISECOND = "ms" diff --git a/tests/components/gdk101/common.yaml b/tests/components/gdk101/common.yaml new file mode 100644 index 0000000000..f886fc415b --- /dev/null +++ b/tests/components/gdk101/common.yaml @@ -0,0 +1,28 @@ +i2c: + id: i2c_bus + sda: ${i2c_sda} + scl: ${i2c_scl} + +gdk101: + id: my_gdk101 + i2c_id: i2c_bus + +sensor: + - platform: gdk101 + gdk101_id: my_gdk101 + radiation_dose_per_1m: + name: Radiation Dose @ 1 min + radiation_dose_per_10m: + name: Radiation Dose @ 10 min + status: + name: Status + version: + name: FW Version + measurement_duration: + name: Measuring Time + +binary_sensor: + - platform: gdk101 + gdk101_id: my_gdk101 + vibrations: + name: Vibrations diff --git a/tests/components/gdk101/test.esp32-idf.yaml b/tests/components/gdk101/test.esp32-idf.yaml new file mode 100644 index 0000000000..1037d5d35b --- /dev/null +++ b/tests/components/gdk101/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + i2c_scl: GPIO16 + i2c_sda: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/gdk101/test.esp32.yaml b/tests/components/gdk101/test.esp32.yaml new file mode 100644 index 0000000000..1037d5d35b --- /dev/null +++ b/tests/components/gdk101/test.esp32.yaml @@ -0,0 +1,5 @@ +substitutions: + i2c_scl: GPIO16 + i2c_sda: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/gdk101/test.esp8266.yaml b/tests/components/gdk101/test.esp8266.yaml new file mode 100644 index 0000000000..d7ae0d5161 --- /dev/null +++ b/tests/components/gdk101/test.esp8266.yaml @@ -0,0 +1,5 @@ +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/gdk101/test.rp2040.yaml b/tests/components/gdk101/test.rp2040.yaml new file mode 100644 index 0000000000..d7ae0d5161 --- /dev/null +++ b/tests/components/gdk101/test.rp2040.yaml @@ -0,0 +1,5 @@ +substitutions: + i2c_scl: GPIO5 + i2c_sda: GPIO4 + +<<: !include common.yaml From dd81c836862be87cdad41902f3847c097d8b0fa5 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 13 May 2024 13:21:02 +1000 Subject: [PATCH 5/7] Typing hint and doc fixes (#6729) --- esphome/cpp_generator.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 04616d97c2..9a4cb2269a 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -2,7 +2,7 @@ import abc import inspect import math import re -from collections.abc import Generator, Sequence +from collections.abc import Sequence from typing import Any, Callable, Optional, Union from esphome.core import ( @@ -477,6 +477,7 @@ def variable( :param rhs: The expression to place on the right hand side of the assignment. :param type_: Manually define a type for the variable, only use this when it's not possible to do so during config validation phase (for example because of template arguments). + :param register: If true register the variable with the core :return: The new variable as a MockObj. """ @@ -492,9 +493,7 @@ def variable( return obj -def with_local_variable( - id_: ID, rhs: SafeExpType, callback: Callable[["MockObj"], None], *args -) -> None: +def with_local_variable(id_: ID, rhs: SafeExpType, callback: Callable, *args) -> None: """Declare a new variable, not pointer type, in the code generation, within a scoped block The variable is only usable within the callback The callback cannot be async. @@ -599,6 +598,7 @@ def add_library(name: str, version: Optional[str], repository: Optional[str] = N :param name: The name of the library (for example 'AsyncTCP') :param version: The version of the library, may be None. + :param repository: The repository for the library """ CORE.add_library(Library(name, version, repository)) @@ -654,7 +654,7 @@ async def process_lambda( parameters: list[tuple[SafeExpType, str]], capture: str = "=", return_type: SafeExpType = None, -) -> Generator[LambdaExpression, None, None]: +) -> Union[LambdaExpression, None]: """Process the given lambda value into a LambdaExpression. This is a coroutine because lambdas can depend on other IDs, @@ -673,7 +673,7 @@ async def process_lambda( ) if value is None: - return + return None parts = value.parts[:] for i, id in enumerate(value.requires_ids): full_id, var = await get_variable_with_full_id(id) @@ -712,7 +712,7 @@ async def templatable( value: Any, args: list[tuple[SafeExpType, str]], output_type: Optional[SafeExpType], - to_exp: Any = None, + to_exp: Union[Callable, dict] = None, ): """Generate code for a templatable config option. From a23d1631e199ac274a1f11d5fbe16ee12fe5b65c Mon Sep 17 00:00:00 2001 From: Jorge-Crespo-Celdran <86021690+Jorge-Crespo-Celdran@users.noreply.github.com> Date: Mon, 13 May 2024 06:04:06 +0200 Subject: [PATCH 6/7] time_based_cover.cpp with manual control fix (#6719) --- esphome/components/time_based/time_based_cover.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/time_based/time_based_cover.cpp b/esphome/components/time_based/time_based_cover.cpp index 50376224a9..e1936d5ee1 100644 --- a/esphome/components/time_based/time_based_cover.cpp +++ b/esphome/components/time_based/time_based_cover.cpp @@ -96,6 +96,9 @@ void TimeBasedCover::control(const CoverCall &call) { } } else { auto op = pos < this->position ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING; + if (this->manual_control_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) { + this->position = pos == COVER_CLOSED ? COVER_OPEN : COVER_CLOSED; + } this->target_position_ = pos; this->start_direction_(op); } From 5ee4bf380215d705c19ac4a07fb27a84cbc660db Mon Sep 17 00:00:00 2001 From: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com> Date: Mon, 13 May 2024 06:05:13 +0200 Subject: [PATCH 7/7] Set FEATURE_API_AUDIO flag also if the speaker component is not used (#6712) --- esphome/components/voice_assistant/voice_assistant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/voice_assistant/voice_assistant.h b/esphome/components/voice_assistant/voice_assistant.h index d6b1502381..1c0ea12f4f 100644 --- a/esphome/components/voice_assistant/voice_assistant.h +++ b/esphome/components/voice_assistant/voice_assistant.h @@ -94,10 +94,10 @@ class VoiceAssistant : public Component { uint32_t get_feature_flags() const { uint32_t flags = 0; flags |= VoiceAssistantFeature::FEATURE_VOICE_ASSISTANT; + flags |= VoiceAssistantFeature::FEATURE_API_AUDIO; #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { flags |= VoiceAssistantFeature::FEATURE_SPEAKER; - flags |= VoiceAssistantFeature::FEATURE_API_AUDIO; } #endif return flags;