mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 00:51:49 +00:00 
			
		
		
		
	Compare commits
	
		
			41 Commits
		
	
	
		
			jesserockz
			...
			2024.12.0b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					561d92d402 | ||
| 
						 | 
					1a69236473 | ||
| 
						 | 
					c86ea99145 | ||
| 
						 | 
					7661609049 | ||
| 
						 | 
					c38826824f | ||
| 
						 | 
					e890486043 | ||
| 
						 | 
					6dcbd1a8ae | ||
| 
						 | 
					63b0930ae8 | ||
| 
						 | 
					5382bd2a97 | ||
| 
						 | 
					de1fbd390b | ||
| 
						 | 
					af23357dca | ||
| 
						 | 
					0fbe6c0d8b | ||
| 
						 | 
					4e1ff31342 | ||
| 
						 | 
					1656ced351 | ||
| 
						 | 
					5dcaf1241f | ||
| 
						 | 
					7aa54b6879 | ||
| 
						 | 
					444e162c92 | ||
| 
						 | 
					bb27eaaf1e | ||
| 
						 | 
					517f659da8 | ||
| 
						 | 
					5a92e24662 | ||
| 
						 | 
					437b236a4d | ||
| 
						 | 
					14eac3dbce | ||
| 
						 | 
					132a096ae7 | ||
| 
						 | 
					440080a753 | ||
| 
						 | 
					f15e3cfb9b | ||
| 
						 | 
					9d000e9abf | ||
| 
						 | 
					97fd7493b5 | ||
| 
						 | 
					4c87658503 | ||
| 
						 | 
					c80e035bd5 | ||
| 
						 | 
					c8ec0bb7ea | ||
| 
						 | 
					86ae1c5931 | ||
| 
						 | 
					d0958f7cf2 | ||
| 
						 | 
					982ce1db72 | ||
| 
						 | 
					f042c6e643 | ||
| 
						 | 
					5fcd26bfe9 | ||
| 
						 | 
					5717d557f5 | ||
| 
						 | 
					3bac45e737 | ||
| 
						 | 
					e623989878 | ||
| 
						 | 
					39cbc6b183 | ||
| 
						 | 
					749a5e3348 | ||
| 
						 | 
					b0e3ac01e8 | 
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -65,7 +65,7 @@ jobs:
 | 
			
		||||
          pip3 install build
 | 
			
		||||
          python3 -m build
 | 
			
		||||
      - name: Publish
 | 
			
		||||
        uses: pypa/gh-action-pypi-publish@v1.12.2
 | 
			
		||||
        uses: pypa/gh-action-pypi-publish@v1.12.3
 | 
			
		||||
 | 
			
		||||
  deploy-docker:
 | 
			
		||||
    name: Build ESPHome ${{ matrix.platform }}
 | 
			
		||||
 
 | 
			
		||||
@@ -355,6 +355,7 @@ esphome/components/sdl/* @clydebarrow
 | 
			
		||||
esphome/components/sdm_meter/* @jesserockz @polyfaces
 | 
			
		||||
esphome/components/sdp3x/* @Azimath
 | 
			
		||||
esphome/components/seeed_mr24hpc1/* @limengdu
 | 
			
		||||
esphome/components/seeed_mr60bha2/* @limengdu
 | 
			
		||||
esphome/components/seeed_mr60fda2/* @limengdu
 | 
			
		||||
esphome/components/selec_meter/* @sourabhjaiswal
 | 
			
		||||
esphome/components/select/* @esphome/core
 | 
			
		||||
 
 | 
			
		||||
@@ -169,7 +169,7 @@ ARG BUILD_VERSION=dev
 | 
			
		||||
LABEL \
 | 
			
		||||
    org.opencontainers.image.authors="The ESPHome Authors" \
 | 
			
		||||
    org.opencontainers.image.title="ESPHome" \
 | 
			
		||||
    org.opencontainers.image.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \
 | 
			
		||||
    org.opencontainers.image.description="ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems" \
 | 
			
		||||
    org.opencontainers.image.url="https://esphome.io/" \
 | 
			
		||||
    org.opencontainers.image.documentation="https://esphome.io/" \
 | 
			
		||||
    org.opencontainers.image.source="https://github.com/esphome/esphome" \
 | 
			
		||||
@@ -206,7 +206,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
			
		||||
# Labels
 | 
			
		||||
LABEL \
 | 
			
		||||
    io.hass.name="ESPHome" \
 | 
			
		||||
    io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \
 | 
			
		||||
    io.hass.description="ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems" \
 | 
			
		||||
    io.hass.type="addon" \
 | 
			
		||||
    io.hass.version="${BUILD_VERSION}"
 | 
			
		||||
    # io.hass.arch is inherited from addon-debian-base
 | 
			
		||||
 
 | 
			
		||||
@@ -3,13 +3,12 @@
 | 
			
		||||
#include "esphome/components/sensor/sensor.h"
 | 
			
		||||
#include "esphome/components/voltage_sampler/voltage_sampler.h"
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/defines.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
#include <esp_adc_cal.h>
 | 
			
		||||
#include "driver/adc.h"
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // USE_ESP32
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace adc {
 | 
			
		||||
@@ -43,7 +42,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
			
		||||
    this->channel1_ = ADC1_CHANNEL_MAX;
 | 
			
		||||
  }
 | 
			
		||||
  void set_autorange(bool autorange) { this->autorange_ = autorange; }
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // USE_ESP32
 | 
			
		||||
 | 
			
		||||
  /// Update ADC values
 | 
			
		||||
  void update() override;
 | 
			
		||||
@@ -59,11 +58,11 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
  std::string unique_id() override;
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // USE_ESP8266
 | 
			
		||||
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
  void set_is_temperature() { this->is_temperature_ = true; }
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // USE_RP2040
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  InternalGPIOPin *pin_;
 | 
			
		||||
@@ -72,7 +71,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
			
		||||
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
  bool is_temperature_{false};
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // USE_RP2040
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
  adc_atten_t attenuation_{ADC_ATTEN_DB_0};
 | 
			
		||||
@@ -83,8 +82,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
			
		||||
  esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {};
 | 
			
		||||
#else
 | 
			
		||||
  esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {};
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // ESP_IDF_VERSION_MAJOR
 | 
			
		||||
#endif  // USE_ESP32
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace adc
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								esphome/components/adc/adc_sensor_common.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								esphome/components/adc/adc_sensor_common.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
#include "adc_sensor.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace adc {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "adc.common";
 | 
			
		||||
 | 
			
		||||
void ADCSensor::update() {
 | 
			
		||||
  float value_v = this->sample();
 | 
			
		||||
  ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
 | 
			
		||||
  this->publish_state(value_v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ADCSensor::set_sample_count(uint8_t sample_count) {
 | 
			
		||||
  if (sample_count != 0) {
 | 
			
		||||
    this->sample_count_ = sample_count;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
 | 
			
		||||
 | 
			
		||||
}  // namespace adc
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
@@ -1,30 +1,13 @@
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
 | 
			
		||||
#include "adc_sensor.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
#include <Esp.h>
 | 
			
		||||
ADC_MODE(ADC_VCC)
 | 
			
		||||
#else
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
#ifdef CYW43_USES_VSYS_PIN
 | 
			
		||||
#include "pico/cyw43_arch.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include <hardware/adc.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace adc {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "adc";
 | 
			
		||||
static const char *const TAG = "adc.esp32";
 | 
			
		||||
 | 
			
		||||
// 13-bit for S2, 12-bit for all other ESP32 variants
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
 | 
			
		||||
 | 
			
		||||
#ifndef SOC_ADC_RTC_MAX_BITWIDTH
 | 
			
		||||
@@ -32,24 +15,15 @@ static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_widt
 | 
			
		||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 13;
 | 
			
		||||
#else
 | 
			
		||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12;
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // USE_ESP32_VARIANT_ESP32S2
 | 
			
		||||
#endif  // SOC_ADC_RTC_MAX_BITWIDTH
 | 
			
		||||
 | 
			
		||||
static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1;    // 4095 (12 bit) or 8191 (13 bit)
 | 
			
		||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1;  // 2048 (12 bit) or 4096 (13 bit)
 | 
			
		||||
#endif
 | 
			
		||||
static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1;
 | 
			
		||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1;
 | 
			
		||||
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
extern "C"
 | 
			
		||||
#endif
 | 
			
		||||
    void
 | 
			
		||||
    ADCSensor::setup() {
 | 
			
		||||
void ADCSensor::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
 | 
			
		||||
#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
 | 
			
		||||
  this->pin_->setup();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
  if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
			
		||||
    adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
 | 
			
		||||
    if (!this->autorange_) {
 | 
			
		||||
@@ -61,7 +35,6 @@ extern "C"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // load characteristics for each attenuation
 | 
			
		||||
  for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) {
 | 
			
		||||
    auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
 | 
			
		||||
    auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
 | 
			
		||||
@@ -79,31 +52,10 @@ extern "C"
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#endif  // USE_ESP32
 | 
			
		||||
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
  static bool initialized = false;
 | 
			
		||||
  if (!initialized) {
 | 
			
		||||
    adc_init();
 | 
			
		||||
    initialized = true;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "ADC '%s' setup finished!", this->get_name().c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ADCSensor::dump_config() {
 | 
			
		||||
  LOG_SENSOR("", "ADC Sensor", this);
 | 
			
		||||
#if defined(USE_ESP8266) || defined(USE_LIBRETINY)
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
			
		||||
#else
 | 
			
		||||
  LOG_PIN("  Pin: ", this->pin_);
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // USE_ESP8266 || USE_LIBRETINY
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
  LOG_PIN("  Pin: ", this->pin_);
 | 
			
		||||
  if (this->autorange_) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Attenuation: auto");
 | 
			
		||||
@@ -125,55 +77,10 @@ void ADCSensor::dump_config() {
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
#endif  // USE_ESP32
 | 
			
		||||
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
  if (this->is_temperature_) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Pin: Temperature");
 | 
			
		||||
  } else {
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
			
		||||
#else
 | 
			
		||||
    LOG_PIN("  Pin: ", this->pin_);
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
  }
 | 
			
		||||
#endif  // USE_RP2040
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Samples: %i", this->sample_count_);
 | 
			
		||||
  LOG_UPDATE_INTERVAL(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
 | 
			
		||||
void ADCSensor::update() {
 | 
			
		||||
  float value_v = this->sample();
 | 
			
		||||
  ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
 | 
			
		||||
  this->publish_state(value_v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ADCSensor::set_sample_count(uint8_t sample_count) {
 | 
			
		||||
  if (sample_count != 0) {
 | 
			
		||||
    this->sample_count_ = sample_count;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
  uint32_t raw = 0;
 | 
			
		||||
  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
    raw += ESP.getVcc();  // NOLINT(readability-static-accessed-through-instance)
 | 
			
		||||
#else
 | 
			
		||||
    raw += analogRead(this->pin_->get_pin());  // NOLINT
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
  if (this->output_raw_) {
 | 
			
		||||
    return raw;
 | 
			
		||||
  }
 | 
			
		||||
  return raw / 1024.0f;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
  if (!this->autorange_) {
 | 
			
		||||
    uint32_t sum = 0;
 | 
			
		||||
@@ -240,93 +147,17 @@ float ADCSensor::sample() {
 | 
			
		||||
  uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
 | 
			
		||||
  uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
 | 
			
		||||
 | 
			
		||||
  // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
 | 
			
		||||
  uint32_t c12 = std::min(raw12, ADC_HALF);
 | 
			
		||||
  uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
 | 
			
		||||
  uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
 | 
			
		||||
  uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
 | 
			
		||||
  // max theoretical csum value is 4096*4 = 16384
 | 
			
		||||
  uint32_t csum = c12 + c6 + c2 + c0;
 | 
			
		||||
 | 
			
		||||
  // each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32
 | 
			
		||||
  uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
 | 
			
		||||
  return mv_scaled / (float) (csum * 1000U);
 | 
			
		||||
}
 | 
			
		||||
#endif  // USE_ESP32
 | 
			
		||||
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
  if (this->is_temperature_) {
 | 
			
		||||
    adc_set_temp_sensor_enabled(true);
 | 
			
		||||
    delay(1);
 | 
			
		||||
    adc_select_input(4);
 | 
			
		||||
    uint32_t raw = 0;
 | 
			
		||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
      raw += adc_read();
 | 
			
		||||
    }
 | 
			
		||||
    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
    adc_set_temp_sensor_enabled(false);
 | 
			
		||||
    if (this->output_raw_) {
 | 
			
		||||
      return raw;
 | 
			
		||||
    }
 | 
			
		||||
    return raw * 3.3f / 4096.0f;
 | 
			
		||||
  } else {
 | 
			
		||||
    uint8_t pin = this->pin_->get_pin();
 | 
			
		||||
#ifdef CYW43_USES_VSYS_PIN
 | 
			
		||||
    if (pin == PICO_VSYS_PIN) {
 | 
			
		||||
      // Measuring VSYS on Raspberry Pico W needs to be wrapped with
 | 
			
		||||
      // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
 | 
			
		||||
      // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
 | 
			
		||||
      // VSYS ADC both share GPIO29
 | 
			
		||||
      cyw43_thread_enter();
 | 
			
		||||
    }
 | 
			
		||||
#endif  // CYW43_USES_VSYS_PIN
 | 
			
		||||
 | 
			
		||||
    adc_gpio_init(pin);
 | 
			
		||||
    adc_select_input(pin - 26);
 | 
			
		||||
 | 
			
		||||
    uint32_t raw = 0;
 | 
			
		||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
      raw += adc_read();
 | 
			
		||||
    }
 | 
			
		||||
    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
 | 
			
		||||
#ifdef CYW43_USES_VSYS_PIN
 | 
			
		||||
    if (pin == PICO_VSYS_PIN) {
 | 
			
		||||
      cyw43_thread_exit();
 | 
			
		||||
    }
 | 
			
		||||
#endif  // CYW43_USES_VSYS_PIN
 | 
			
		||||
 | 
			
		||||
    if (this->output_raw_) {
 | 
			
		||||
      return raw;
 | 
			
		||||
    }
 | 
			
		||||
    float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0;
 | 
			
		||||
    return raw * 3.3f / 4096.0f * coeff;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_LIBRETINY
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
  uint32_t raw = 0;
 | 
			
		||||
  if (this->output_raw_) {
 | 
			
		||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
      raw += analogRead(this->pin_->get_pin());  // NOLINT
 | 
			
		||||
    }
 | 
			
		||||
    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
    return raw;
 | 
			
		||||
  }
 | 
			
		||||
  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
    raw += analogReadVoltage(this->pin_->get_pin());  // NOLINT
 | 
			
		||||
  }
 | 
			
		||||
  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
  return raw / 1000.0f;
 | 
			
		||||
}
 | 
			
		||||
#endif  // USE_LIBRETINY
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}  // namespace adc
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#endif  // USE_ESP32
 | 
			
		||||
							
								
								
									
										58
									
								
								esphome/components/adc/adc_sensor_esp8266.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								esphome/components/adc/adc_sensor_esp8266.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
 | 
			
		||||
#include "adc_sensor.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
#include <Esp.h>
 | 
			
		||||
ADC_MODE(ADC_VCC)
 | 
			
		||||
#else
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace adc {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "adc.esp8266";
 | 
			
		||||
 | 
			
		||||
void ADCSensor::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
 | 
			
		||||
#ifndef USE_ADC_SENSOR_VCC
 | 
			
		||||
  this->pin_->setup();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ADCSensor::dump_config() {
 | 
			
		||||
  LOG_SENSOR("", "ADC Sensor", this);
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
			
		||||
#else
 | 
			
		||||
  LOG_PIN("  Pin: ", this->pin_);
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Samples: %i", this->sample_count_);
 | 
			
		||||
  LOG_UPDATE_INTERVAL(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
  uint32_t raw = 0;
 | 
			
		||||
  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
    raw += ESP.getVcc();  // NOLINT(readability-static-accessed-through-instance)
 | 
			
		||||
#else
 | 
			
		||||
    raw += analogRead(this->pin_->get_pin());  // NOLINT
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
  }
 | 
			
		||||
  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
  if (this->output_raw_) {
 | 
			
		||||
    return raw;
 | 
			
		||||
  }
 | 
			
		||||
  return raw / 1024.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
 | 
			
		||||
 | 
			
		||||
}  // namespace adc
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#endif  // USE_ESP8266
 | 
			
		||||
							
								
								
									
										48
									
								
								esphome/components/adc/adc_sensor_libretiny.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								esphome/components/adc/adc_sensor_libretiny.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
#ifdef USE_LIBRETINY
 | 
			
		||||
 | 
			
		||||
#include "adc_sensor.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace adc {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "adc.libretiny";
 | 
			
		||||
 | 
			
		||||
void ADCSensor::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
 | 
			
		||||
#ifndef USE_ADC_SENSOR_VCC
 | 
			
		||||
  this->pin_->setup();
 | 
			
		||||
#endif  // !USE_ADC_SENSOR_VCC
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ADCSensor::dump_config() {
 | 
			
		||||
  LOG_SENSOR("", "ADC Sensor", this);
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
			
		||||
#else   // USE_ADC_SENSOR_VCC
 | 
			
		||||
  LOG_PIN("  Pin: ", this->pin_);
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Samples: %i", this->sample_count_);
 | 
			
		||||
  LOG_UPDATE_INTERVAL(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
  uint32_t raw = 0;
 | 
			
		||||
  if (this->output_raw_) {
 | 
			
		||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
      raw += analogRead(this->pin_->get_pin());  // NOLINT
 | 
			
		||||
    }
 | 
			
		||||
    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
    return raw;
 | 
			
		||||
  }
 | 
			
		||||
  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
    raw += analogReadVoltage(this->pin_->get_pin());  // NOLINT
 | 
			
		||||
  }
 | 
			
		||||
  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
  return raw / 1000.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace adc
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#endif  // USE_LIBRETINY
 | 
			
		||||
							
								
								
									
										93
									
								
								esphome/components/adc/adc_sensor_rp2040.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								esphome/components/adc/adc_sensor_rp2040.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
 | 
			
		||||
#include "adc_sensor.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CYW43_USES_VSYS_PIN
 | 
			
		||||
#include "pico/cyw43_arch.h"
 | 
			
		||||
#endif  // CYW43_USES_VSYS_PIN
 | 
			
		||||
#include <hardware/adc.h>
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace adc {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "adc.rp2040";
 | 
			
		||||
 | 
			
		||||
void ADCSensor::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
 | 
			
		||||
  static bool initialized = false;
 | 
			
		||||
  if (!initialized) {
 | 
			
		||||
    adc_init();
 | 
			
		||||
    initialized = true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ADCSensor::dump_config() {
 | 
			
		||||
  LOG_SENSOR("", "ADC Sensor", this);
 | 
			
		||||
  if (this->is_temperature_) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Pin: Temperature");
 | 
			
		||||
  } else {
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
			
		||||
#else
 | 
			
		||||
    LOG_PIN("  Pin: ", this->pin_);
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
  }
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Samples: %i", this->sample_count_);
 | 
			
		||||
  LOG_UPDATE_INTERVAL(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
  if (this->is_temperature_) {
 | 
			
		||||
    adc_set_temp_sensor_enabled(true);
 | 
			
		||||
    delay(1);
 | 
			
		||||
    adc_select_input(4);
 | 
			
		||||
    uint32_t raw = 0;
 | 
			
		||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
      raw += adc_read();
 | 
			
		||||
    }
 | 
			
		||||
    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
    adc_set_temp_sensor_enabled(false);
 | 
			
		||||
    if (this->output_raw_) {
 | 
			
		||||
      return raw;
 | 
			
		||||
    }
 | 
			
		||||
    return raw * 3.3f / 4096.0f;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t pin = this->pin_->get_pin();
 | 
			
		||||
#ifdef CYW43_USES_VSYS_PIN
 | 
			
		||||
  if (pin == PICO_VSYS_PIN) {
 | 
			
		||||
    // Measuring VSYS on Raspberry Pico W needs to be wrapped with
 | 
			
		||||
    // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
 | 
			
		||||
    // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
 | 
			
		||||
    // VSYS ADC both share GPIO29
 | 
			
		||||
    cyw43_thread_enter();
 | 
			
		||||
  }
 | 
			
		||||
#endif  // CYW43_USES_VSYS_PIN
 | 
			
		||||
 | 
			
		||||
  adc_gpio_init(pin);
 | 
			
		||||
  adc_select_input(pin - 26);
 | 
			
		||||
 | 
			
		||||
  uint32_t raw = 0;
 | 
			
		||||
  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
			
		||||
    raw += adc_read();
 | 
			
		||||
  }
 | 
			
		||||
  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
			
		||||
 | 
			
		||||
#ifdef CYW43_USES_VSYS_PIN
 | 
			
		||||
  if (pin == PICO_VSYS_PIN) {
 | 
			
		||||
    cyw43_thread_exit();
 | 
			
		||||
  }
 | 
			
		||||
#endif  // CYW43_USES_VSYS_PIN
 | 
			
		||||
 | 
			
		||||
  if (this->output_raw_) {
 | 
			
		||||
    return raw;
 | 
			
		||||
  }
 | 
			
		||||
  float coeff = pin == PICO_VSYS_PIN ? 3.0f : 1.0f;
 | 
			
		||||
  return raw * 3.3f / 4096.0f * coeff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace adc
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#endif  // USE_RP2040
 | 
			
		||||
@@ -213,7 +213,6 @@ message DeviceInfoResponse {
 | 
			
		||||
  // The esphome project details if set
 | 
			
		||||
  string project_name = 8;
 | 
			
		||||
  string project_version = 9;
 | 
			
		||||
  string project_manufacturer = 18;
 | 
			
		||||
 | 
			
		||||
  uint32 webserver_port = 10;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1429,7 +1429,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
 | 
			
		||||
 | 
			
		||||
  HelloResponse resp;
 | 
			
		||||
  resp.api_version_major = 1;
 | 
			
		||||
  resp.api_version_minor = 11;
 | 
			
		||||
  resp.api_version_minor = 10;
 | 
			
		||||
  resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
 | 
			
		||||
  resp.name = App.get_name();
 | 
			
		||||
 | 
			
		||||
@@ -1479,13 +1479,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
 | 
			
		||||
  resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef ESPHOME_PROJECT_NAME
 | 
			
		||||
  if (this->client_api_version_major_ > 1 ||
 | 
			
		||||
      (this->client_api_version_major_ == 1 && this->client_api_version_minor_ >= 11)) {
 | 
			
		||||
    resp.project_name = ESPHOME_PROJECT_NAME;
 | 
			
		||||
    resp.project_manufacturer = ESPHOME_PROJECT_MANUFACTURER;
 | 
			
		||||
  } else {
 | 
			
		||||
    resp.project_name = ESPHOME_PROJECT_MANUFACTURER "." ESPHOME_PROJECT_NAME;
 | 
			
		||||
  }
 | 
			
		||||
  resp.project_name = ESPHOME_PROJECT_NAME;
 | 
			
		||||
  resp.project_version = ESPHOME_PROJECT_VERSION;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_WEBSERVER
 | 
			
		||||
 
 | 
			
		||||
@@ -826,10 +826,6 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
 | 
			
		||||
      this->project_version = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    case 18: {
 | 
			
		||||
      this->project_manufacturer = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    case 12: {
 | 
			
		||||
      this->manufacturer = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
@@ -856,7 +852,6 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
 | 
			
		||||
  buffer.encode_bool(7, this->has_deep_sleep);
 | 
			
		||||
  buffer.encode_string(8, this->project_name);
 | 
			
		||||
  buffer.encode_string(9, this->project_version);
 | 
			
		||||
  buffer.encode_string(18, this->project_manufacturer);
 | 
			
		||||
  buffer.encode_uint32(10, this->webserver_port);
 | 
			
		||||
  buffer.encode_uint32(11, this->legacy_bluetooth_proxy_version);
 | 
			
		||||
  buffer.encode_uint32(15, this->bluetooth_proxy_feature_flags);
 | 
			
		||||
@@ -906,10 +901,6 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
 | 
			
		||||
  out.append("'").append(this->project_version).append("'");
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
 | 
			
		||||
  out.append("  project_manufacturer: ");
 | 
			
		||||
  out.append("'").append(this->project_manufacturer).append("'");
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
 | 
			
		||||
  out.append("  webserver_port: ");
 | 
			
		||||
  sprintf(buffer, "%" PRIu32, this->webserver_port);
 | 
			
		||||
  out.append(buffer);
 | 
			
		||||
 
 | 
			
		||||
@@ -346,7 +346,6 @@ class DeviceInfoResponse : public ProtoMessage {
 | 
			
		||||
  bool has_deep_sleep{false};
 | 
			
		||||
  std::string project_name{};
 | 
			
		||||
  std::string project_version{};
 | 
			
		||||
  std::string project_manufacturer{};
 | 
			
		||||
  uint32_t webserver_port{0};
 | 
			
		||||
  uint32_t legacy_bluetooth_proxy_version{0};
 | 
			
		||||
  uint32_t bluetooth_proxy_feature_flags{0};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "display_color_utils.h"
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "display_color_utils.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
@@ -670,7 +670,7 @@ void Display::strftime(int x, int y, BaseFont *font, Color color, Color backgrou
 | 
			
		||||
    this->print(x, y, font, color, align, buffer, background);
 | 
			
		||||
}
 | 
			
		||||
void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) {
 | 
			
		||||
  this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
 | 
			
		||||
  this->strftime(x, y, font, color, COLOR_OFF, align, format, time);
 | 
			
		||||
}
 | 
			
		||||
void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) {
 | 
			
		||||
  this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,12 @@
 | 
			
		||||
from .const import VARIANT_ESP32, VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3
 | 
			
		||||
from .const import (
 | 
			
		||||
    VARIANT_ESP32,
 | 
			
		||||
    VARIANT_ESP32C2,
 | 
			
		||||
    VARIANT_ESP32C3,
 | 
			
		||||
    VARIANT_ESP32C6,
 | 
			
		||||
    VARIANT_ESP32H2,
 | 
			
		||||
    VARIANT_ESP32S2,
 | 
			
		||||
    VARIANT_ESP32S3,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
ESP32_BASE_PINS = {
 | 
			
		||||
    "TX": 1,
 | 
			
		||||
@@ -1344,6 +1352,26 @@ done | sort
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
BOARDS = {
 | 
			
		||||
    "4d_systems_esp32s3_gen4_r8n16": {
 | 
			
		||||
        "name": "4D Systems GEN4-ESP32 16MB (ESP32S3-R8N16)",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_camera_esp32s3": {
 | 
			
		||||
        "name": "Adafruit pyCamera S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_feather_esp32c6": {
 | 
			
		||||
        "name": "Adafruit Feather ESP32-C6",
 | 
			
		||||
        "variant": VARIANT_ESP32C6,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_feather_esp32s2": {
 | 
			
		||||
        "name": "Adafruit Feather ESP32-S2",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_feather_esp32s2_reversetft": {
 | 
			
		||||
        "name": "Adafruit Feather ESP32-S2 Reverse TFT",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_feather_esp32s2_tft": {
 | 
			
		||||
        "name": "Adafruit Feather ESP32-S2 TFT",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
@@ -1356,6 +1384,10 @@ BOARDS = {
 | 
			
		||||
        "name": "Adafruit Feather ESP32-S3 No PSRAM",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_feather_esp32s3_reversetft": {
 | 
			
		||||
        "name": "Adafruit Feather ESP32-S3 Reverse TFT",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_feather_esp32s3_tft": {
 | 
			
		||||
        "name": "Adafruit Feather ESP32-S3 TFT",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
@@ -1376,10 +1408,18 @@ BOARDS = {
 | 
			
		||||
        "name": "Adafruit MagTag 2.9",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_matrixportal_esp32s3": {
 | 
			
		||||
        "name": "Adafruit MatrixPortal ESP32-S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_metro_esp32s2": {
 | 
			
		||||
        "name": "Adafruit Metro ESP32-S2",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_metro_esp32s3": {
 | 
			
		||||
        "name": "Adafruit Metro ESP32-S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_qtpy_esp32c3": {
 | 
			
		||||
        "name": "Adafruit QT Py ESP32-C3",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
@@ -1392,10 +1432,18 @@ BOARDS = {
 | 
			
		||||
        "name": "Adafruit QT Py ESP32-S2",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_qtpy_esp32s3_n4r2": {
 | 
			
		||||
        "name": "Adafruit QT Py ESP32-S3 (4M Flash 2M PSRAM)",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_qtpy_esp32s3_nopsram": {
 | 
			
		||||
        "name": "Adafruit QT Py ESP32-S3 No PSRAM",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "adafruit_qualia_s3_rgb666": {
 | 
			
		||||
        "name": "Adafruit Qualia ESP32-S3 RGB666",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "airm2m_core_esp32c3": {
 | 
			
		||||
        "name": "AirM2M CORE ESP32C3",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
@@ -1404,14 +1452,30 @@ BOARDS = {
 | 
			
		||||
        "name": "ALKS ESP32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "arduino_nano_esp32": {
 | 
			
		||||
        "name": "Arduino Nano ESP32",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "atd147_s3": {
 | 
			
		||||
        "name": "ArtronShop ATD1.47-S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "atmegazero_esp32s2": {
 | 
			
		||||
        "name": "EspinalLab ATMegaZero ESP32-S2",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "aventen_s3_sync": {
 | 
			
		||||
        "name": "Aventen S3 Sync",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "az-delivery-devkit-v4": {
 | 
			
		||||
        "name": "AZ-Delivery ESP-32 Dev Kit C V4",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "bee_data_logger": {
 | 
			
		||||
        "name": "Smart Bee Data Logger",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "bee_motion_mini": {
 | 
			
		||||
        "name": "Smart Bee Motion Mini",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
@@ -1436,14 +1500,6 @@ BOARDS = {
 | 
			
		||||
        "name": "BPI-Leaf-S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "briki_abc_esp32": {
 | 
			
		||||
        "name": "Briki ABC (MBC-WB) - ESP32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "briki_mbc-wb_esp32": {
 | 
			
		||||
        "name": "Briki MBC-WB - ESP32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "cnrs_aw2eth": {
 | 
			
		||||
        "name": "CNRS AW2ETH",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1496,18 +1552,38 @@ BOARDS = {
 | 
			
		||||
        "name": "DFRobot Beetle ESP32-C3",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
    },
 | 
			
		||||
    "dfrobot_firebeetle2_esp32e": {
 | 
			
		||||
        "name": "DFRobot Firebeetle 2 ESP32-E",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "dfrobot_firebeetle2_esp32s3": {
 | 
			
		||||
        "name": "DFRobot Firebeetle 2 ESP32-S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "dfrobot_romeo_esp32s3": {
 | 
			
		||||
        "name": "DFRobot Romeo ESP32-S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "dpu_esp32": {
 | 
			
		||||
        "name": "TAMC DPU ESP32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "edgebox-esp-100": {
 | 
			
		||||
        "name": "Seeed Studio Edgebox-ESP-100",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "esp320": {
 | 
			
		||||
        "name": "Electronic SweetPeas ESP320",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-c2-devkitm-1": {
 | 
			
		||||
        "name": "Espressif ESP32-C2-DevKitM-1",
 | 
			
		||||
        "variant": VARIANT_ESP32C2,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-c3-devkitc-02": {
 | 
			
		||||
        "name": "Espressif ESP32-C3-DevKitC-02",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-c3-devkitm-1": {
 | 
			
		||||
        "name": "Espressif ESP32-C3-DevKitM-1",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
@@ -1516,6 +1592,14 @@ BOARDS = {
 | 
			
		||||
        "name": "Ai-Thinker ESP-C3-M1-I-Kit",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-c6-devkitc-1": {
 | 
			
		||||
        "name": "Espressif ESP32-C6-DevKitC-1",
 | 
			
		||||
        "variant": VARIANT_ESP32C6,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-c6-devkitm-1": {
 | 
			
		||||
        "name": "Espressif ESP32-C6-DevKitM-1",
 | 
			
		||||
        "variant": VARIANT_ESP32C6,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32cam": {
 | 
			
		||||
        "name": "AI Thinker ESP32-CAM",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1544,6 +1628,14 @@ BOARDS = {
 | 
			
		||||
        "name": "OLIMEX ESP32-GATEWAY",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-h2-devkitm-1": {
 | 
			
		||||
        "name": "Espressif ESP32-H2-DevKit",
 | 
			
		||||
        "variant": VARIANT_ESP32H2,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-pico-devkitm-2": {
 | 
			
		||||
        "name": "Espressif ESP32-PICO-DevKitM-2",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-poe-iso": {
 | 
			
		||||
        "name": "OLIMEX ESP32-PoE-ISO",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1580,10 +1672,22 @@ BOARDS = {
 | 
			
		||||
        "name": "Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-s3-korvo-2": {
 | 
			
		||||
        "name": "Espressif ESP32-S3-Korvo-2",
 | 
			
		||||
    "esp32-s3-devkitm-1": {
 | 
			
		||||
        "name": "Espressif ESP32-S3-DevKitM-1",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32s3_powerfeather": {
 | 
			
		||||
        "name": "ESP32-S3 PowerFeather",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32s3usbotg": {
 | 
			
		||||
        "name": "Espressif ESP32-S3-USB-OTG",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32-solo1": {
 | 
			
		||||
        "name": "Espressif Generic ESP32-solo1 4M Flash",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "esp32thing": {
 | 
			
		||||
        "name": "SparkFun ESP32 Thing",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1652,9 +1756,9 @@ BOARDS = {
 | 
			
		||||
        "name": "Heltec WiFi Kit 32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "heltec_wifi_kit_32_v2": {
 | 
			
		||||
        "name": "Heltec WiFi Kit 32 (V2)",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    "heltec_wifi_kit_32_V3": {
 | 
			
		||||
        "name": "Heltec WiFi Kit 32 (V3)",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "heltec_wifi_lora_32": {
 | 
			
		||||
        "name": "Heltec WiFi LoRa 32",
 | 
			
		||||
@@ -1664,6 +1768,10 @@ BOARDS = {
 | 
			
		||||
        "name": "Heltec WiFi LoRa 32 (V2)",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "heltec_wifi_lora_32_V3": {
 | 
			
		||||
        "name": "Heltec WiFi LoRa 32 (V3)",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "heltec_wireless_stick_lite": {
 | 
			
		||||
        "name": "Heltec Wireless Stick Lite",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1708,6 +1816,14 @@ BOARDS = {
 | 
			
		||||
        "name": "oddWires IoT-Bus Proteus",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "ioxesp32": {
 | 
			
		||||
        "name": "ArtronShop IOXESP32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "ioxesp32ps": {
 | 
			
		||||
        "name": "ArtronShop IOXESP32PS",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "kb32-ft": {
 | 
			
		||||
        "name": "MakerAsia KB32-FT",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1720,10 +1836,26 @@ BOARDS = {
 | 
			
		||||
        "name": "Labplus mPython",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "lilka_v2": {
 | 
			
		||||
        "name": "Lilka v2",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "lilygo-t-display": {
 | 
			
		||||
        "name": "LilyGo T-Display",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "lilygo-t-display-s3": {
 | 
			
		||||
        "name": "LilyGo T-Display-S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "lionbit": {
 | 
			
		||||
        "name": "Lion:Bit Dev Board",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "lionbits3": {
 | 
			
		||||
        "name": "Lion:Bit S3 STEM Dev Board",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "lolin32_lite": {
 | 
			
		||||
        "name": "WEMOS LOLIN32 Lite",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1752,10 +1884,18 @@ BOARDS = {
 | 
			
		||||
        "name": "WEMOS LOLIN S2 PICO",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "lolin_s3_mini": {
 | 
			
		||||
        "name": "WEMOS LOLIN S3 Mini",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "lolin_s3": {
 | 
			
		||||
        "name": "WEMOS LOLIN S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "lolin_s3_pro": {
 | 
			
		||||
        "name": "WEMOS LOLIN S3 PRO",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "lopy4": {
 | 
			
		||||
        "name": "Pycom LoPy4",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1768,10 +1908,18 @@ BOARDS = {
 | 
			
		||||
        "name": "M5Stack-ATOM",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack-atoms3": {
 | 
			
		||||
        "name": "M5Stack AtomS3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack-core2": {
 | 
			
		||||
        "name": "M5Stack Core2",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack-core-esp32-16M": {
 | 
			
		||||
        "name": "M5Stack Core ESP32 16M",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack-core-esp32": {
 | 
			
		||||
        "name": "M5Stack Core ESP32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1780,6 +1928,10 @@ BOARDS = {
 | 
			
		||||
        "name": "M5Stack-Core Ink",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack-cores3": {
 | 
			
		||||
        "name": "M5Stack CoreS3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack-fire": {
 | 
			
		||||
        "name": "M5Stack FIRE",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1788,6 +1940,14 @@ BOARDS = {
 | 
			
		||||
        "name": "M5Stack GREY ESP32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack_paper": {
 | 
			
		||||
        "name": "M5Stack Paper",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack-stamps3": {
 | 
			
		||||
        "name": "M5Stack StampS3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stack-station": {
 | 
			
		||||
        "name": "M5Stack Station",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1796,6 +1956,10 @@ BOARDS = {
 | 
			
		||||
        "name": "M5Stack Timer CAM",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stamp-pico": {
 | 
			
		||||
        "name": "M5Stamp-Pico",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "m5stick-c": {
 | 
			
		||||
        "name": "M5Stick-C",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1832,10 +1996,26 @@ BOARDS = {
 | 
			
		||||
        "name": "Deparment of Alchemy MiniMain ESP32-S2",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "motorgo_mini_1": {
 | 
			
		||||
        "name": "MotorGo Mini 1 (ESP32-S3)",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "namino_arancio": {
 | 
			
		||||
        "name": "Namino Arancio",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "namino_rosso": {
 | 
			
		||||
        "name": "Namino Rosso",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "nano32": {
 | 
			
		||||
        "name": "MakerAsia Nano32",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "nebulas3": {
 | 
			
		||||
        "name": "Kinetic Dynamics Nebula S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "nina_w10": {
 | 
			
		||||
        "name": "u-blox NINA-W10 series",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1896,10 +2076,22 @@ BOARDS = {
 | 
			
		||||
        "name": "Munich Labs RedPill ESP32-S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "roboheart_hercules": {
 | 
			
		||||
        "name": "RoboHeart Hercules",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "seeed_xiao_esp32c3": {
 | 
			
		||||
        "name": "Seeed Studio XIAO ESP32C3",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
    },
 | 
			
		||||
    "seeed_xiao_esp32s3": {
 | 
			
		||||
        "name": "Seeed Studio XIAO ESP32S3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "sensebox_mcu_esp32s2": {
 | 
			
		||||
        "name": "senseBox MCU-S2 ESP32-S2",
 | 
			
		||||
        "variant": VARIANT_ESP32S2,
 | 
			
		||||
    },
 | 
			
		||||
    "sensesiot_weizen": {
 | 
			
		||||
        "name": "LOGISENSES Senses Weizen",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -1912,6 +2104,10 @@ BOARDS = {
 | 
			
		||||
        "name": "S.ODI Ultra v1",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "sparkfun_esp32c6_thing_plus": {
 | 
			
		||||
        "name": "Sparkfun ESP32-C6 Thing Plus",
 | 
			
		||||
        "variant": VARIANT_ESP32C6,
 | 
			
		||||
    },
 | 
			
		||||
    "sparkfun_esp32_iot_redboard": {
 | 
			
		||||
        "name": "SparkFun ESP32 IoT RedBoard",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
@@ -2004,6 +2200,10 @@ BOARDS = {
 | 
			
		||||
        "name": "Unexpected Maker FeatherS3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "um_nanos3": {
 | 
			
		||||
        "name": "Unexpected Maker NanoS3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
    },
 | 
			
		||||
    "um_pros3": {
 | 
			
		||||
        "name": "Unexpected Maker PROS3",
 | 
			
		||||
        "variant": VARIANT_ESP32S3,
 | 
			
		||||
@@ -2040,6 +2240,14 @@ BOARDS = {
 | 
			
		||||
        "name": "uPesy ESP32 Wrover DevKit",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
    },
 | 
			
		||||
    "valtrack_v4_mfw_esp32_c3": {
 | 
			
		||||
        "name": "Valetron Systems VALTRACK-V4MVF",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
    },
 | 
			
		||||
    "valtrack_v4_vts_esp32_c3": {
 | 
			
		||||
        "name": "Valetron Systems VALTRACK-V4VTS",
 | 
			
		||||
        "variant": VARIANT_ESP32C3,
 | 
			
		||||
    },
 | 
			
		||||
    "vintlabs-devkit-v1": {
 | 
			
		||||
        "name": "VintLabs ESP32 Devkit",
 | 
			
		||||
        "variant": VARIANT_ESP32,
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,9 @@ namespace esp32_ble {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "esp32_ble";
 | 
			
		||||
 | 
			
		||||
static RAMAllocator<BLEEvent> EVENT_ALLOCATOR(  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
			
		||||
    RAMAllocator<BLEEvent>::ALLOW_FAILURE | RAMAllocator<BLEEvent>::ALLOC_INTERNAL);
 | 
			
		||||
 | 
			
		||||
void ESP32BLE::setup() {
 | 
			
		||||
  global_ble = this;
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up BLE...");
 | 
			
		||||
@@ -322,7 +325,8 @@ void ESP32BLE::loop() {
 | 
			
		||||
      default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    delete ble_event;  // NOLINT(cppcoreguidelines-owning-memory)
 | 
			
		||||
    ble_event->~BLEEvent();
 | 
			
		||||
    EVENT_ALLOCATOR.deallocate(ble_event, 1);
 | 
			
		||||
    ble_event = this->ble_events_.pop();
 | 
			
		||||
  }
 | 
			
		||||
  if (this->advertising_ != nullptr) {
 | 
			
		||||
@@ -331,9 +335,14 @@ void ESP32BLE::loop() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
 | 
			
		||||
  BLEEvent *new_event = new BLEEvent(event, param);  // NOLINT(cppcoreguidelines-owning-memory)
 | 
			
		||||
  BLEEvent *new_event = EVENT_ALLOCATOR.allocate(1);
 | 
			
		||||
  if (new_event == nullptr) {
 | 
			
		||||
    // Memory too fragmented to allocate new event. Can only drop it until memory comes back
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  new (new_event) BLEEvent(event, param);
 | 
			
		||||
  global_ble->ble_events_.push(new_event);
 | 
			
		||||
}  // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
 | 
			
		||||
}  // NOLINT(clang-analyzer-unix.Malloc)
 | 
			
		||||
 | 
			
		||||
void ESP32BLE::real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
 | 
			
		||||
  ESP_LOGV(TAG, "(BLE) gap_event_handler - %d", event);
 | 
			
		||||
@@ -344,9 +353,14 @@ void ESP32BLE::real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap
 | 
			
		||||
 | 
			
		||||
void ESP32BLE::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
 | 
			
		||||
                                   esp_ble_gatts_cb_param_t *param) {
 | 
			
		||||
  BLEEvent *new_event = new BLEEvent(event, gatts_if, param);  // NOLINT(cppcoreguidelines-owning-memory)
 | 
			
		||||
  BLEEvent *new_event = EVENT_ALLOCATOR.allocate(1);
 | 
			
		||||
  if (new_event == nullptr) {
 | 
			
		||||
    // Memory too fragmented to allocate new event. Can only drop it until memory comes back
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  new (new_event) BLEEvent(event, gatts_if, param);
 | 
			
		||||
  global_ble->ble_events_.push(new_event);
 | 
			
		||||
}  // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
 | 
			
		||||
}  // NOLINT(clang-analyzer-unix.Malloc)
 | 
			
		||||
 | 
			
		||||
void ESP32BLE::real_gatts_event_handler_(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
 | 
			
		||||
                                         esp_ble_gatts_cb_param_t *param) {
 | 
			
		||||
@@ -358,9 +372,14 @@ void ESP32BLE::real_gatts_event_handler_(esp_gatts_cb_event_t event, esp_gatt_if
 | 
			
		||||
 | 
			
		||||
void ESP32BLE::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
 | 
			
		||||
                                   esp_ble_gattc_cb_param_t *param) {
 | 
			
		||||
  BLEEvent *new_event = new BLEEvent(event, gattc_if, param);  // NOLINT(cppcoreguidelines-owning-memory)
 | 
			
		||||
  BLEEvent *new_event = EVENT_ALLOCATOR.allocate(1);
 | 
			
		||||
  if (new_event == nullptr) {
 | 
			
		||||
    // Memory too fragmented to allocate new event. Can only drop it until memory comes back
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  new (new_event) BLEEvent(event, gattc_if, param);
 | 
			
		||||
  global_ble->ble_events_.push(new_event);
 | 
			
		||||
}  // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
 | 
			
		||||
}  // NOLINT(clang-analyzer-unix.Malloc)
 | 
			
		||||
 | 
			
		||||
void ESP32BLE::real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
 | 
			
		||||
                                         esp_ble_gattc_cb_param_t *param) {
 | 
			
		||||
 
 | 
			
		||||
@@ -51,8 +51,11 @@ CONF_IGNORE_MISSING_GLYPHS = "ignore_missing_glyphs"
 | 
			
		||||
# Cache loaded freetype fonts
 | 
			
		||||
class FontCache(dict):
 | 
			
		||||
    def __missing__(self, key):
 | 
			
		||||
        res = self[key] = freetype.Face(key)
 | 
			
		||||
        return res
 | 
			
		||||
        try:
 | 
			
		||||
            res = self[key] = freetype.Face(key)
 | 
			
		||||
            return res
 | 
			
		||||
        except freetype.FT_Exception as e:
 | 
			
		||||
            raise cv.Invalid(f"Could not load Font file {key}: {e}") from e
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
FONT_CACHE = FontCache()
 | 
			
		||||
 
 | 
			
		||||
@@ -133,9 +133,11 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo
 | 
			
		||||
    auto diff_r = (float) color.r - (float) background.r;
 | 
			
		||||
    auto diff_g = (float) color.g - (float) background.g;
 | 
			
		||||
    auto diff_b = (float) color.b - (float) background.b;
 | 
			
		||||
    auto diff_w = (float) color.w - (float) background.w;
 | 
			
		||||
    auto b_r = (float) background.r;
 | 
			
		||||
    auto b_g = (float) background.g;
 | 
			
		||||
    auto b_b = (float) background.g;
 | 
			
		||||
    auto b_b = (float) background.b;
 | 
			
		||||
    auto b_w = (float) background.w;
 | 
			
		||||
    for (int glyph_y = y_start + scan_y1; glyph_y != max_y; glyph_y++) {
 | 
			
		||||
      for (int glyph_x = x_at + scan_x1; glyph_x != max_x; glyph_x++) {
 | 
			
		||||
        uint8_t pixel = 0;
 | 
			
		||||
@@ -153,8 +155,8 @@ void Font::print(int x_start, int y_start, display::Display *display, Color colo
 | 
			
		||||
          display->draw_pixel_at(glyph_x, glyph_y, color);
 | 
			
		||||
        } else if (pixel != 0) {
 | 
			
		||||
          auto on = (float) pixel / (float) bpp_max;
 | 
			
		||||
          auto blended =
 | 
			
		||||
              Color((uint8_t) (diff_r * on + b_r), (uint8_t) (diff_g * on + b_g), (uint8_t) (diff_b * on + b_b));
 | 
			
		||||
          auto blended = Color((uint8_t) (diff_r * on + b_r), (uint8_t) (diff_g * on + b_g),
 | 
			
		||||
                               (uint8_t) (diff_b * on + b_b), (uint8_t) (diff_w * on + b_w));
 | 
			
		||||
          display->draw_pixel_at(glyph_x, glyph_y, blended);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,14 +17,14 @@ void IDFI2CBus::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up I2C bus...");
 | 
			
		||||
  static i2c_port_t next_port = I2C_NUM_0;
 | 
			
		||||
  port_ = next_port;
 | 
			
		||||
#if I2C_NUM_MAX > 1
 | 
			
		||||
#if SOC_I2C_NUM > 1
 | 
			
		||||
  next_port = (next_port == I2C_NUM_0) ? I2C_NUM_1 : I2C_NUM_MAX;
 | 
			
		||||
#else
 | 
			
		||||
  next_port = I2C_NUM_MAX;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (port_ == I2C_NUM_MAX) {
 | 
			
		||||
    ESP_LOGE(TAG, "Too many I2C buses configured");
 | 
			
		||||
    ESP_LOGE(TAG, "Too many I2C buses configured. Max %u supported.", SOC_I2C_NUM);
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -247,7 +247,7 @@ void I2SAudioSpeaker::speaker_task(void *params) {
 | 
			
		||||
 | 
			
		||||
  // Ensure ring buffer is at least as large as the total size of the DMA buffers
 | 
			
		||||
  const size_t ring_buffer_size =
 | 
			
		||||
      std::min((uint32_t) dma_buffers_size, this_speaker->buffer_duration_ms_ * bytes_per_ms);
 | 
			
		||||
      std::max((uint32_t) dma_buffers_size, this_speaker->buffer_duration_ms_ * bytes_per_ms);
 | 
			
		||||
 | 
			
		||||
  if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(dma_buffers_size, ring_buffer_size))) {
 | 
			
		||||
    // Failed to allocate buffers
 | 
			
		||||
 
 | 
			
		||||
@@ -168,6 +168,7 @@ LV_EVENT_MAP = {
 | 
			
		||||
    "READY": "READY",
 | 
			
		||||
    "CANCEL": "CANCEL",
 | 
			
		||||
    "ALL_EVENTS": "ALL",
 | 
			
		||||
    "CHANGE": "VALUE_CHANGED",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT_MAP)
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ class ImgType(WidgetType):
 | 
			
		||||
        if CONF_ANTIALIAS in config:
 | 
			
		||||
            lv.img_set_antialias(w.obj, config[CONF_ANTIALIAS])
 | 
			
		||||
        if mode := config.get(CONF_MODE):
 | 
			
		||||
            lv.img_set_mode(w.obj, mode)
 | 
			
		||||
            await w.set_property("size_mode", mode)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
img_spec = ImgType()
 | 
			
		||||
 
 | 
			
		||||
@@ -152,9 +152,9 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const {
 | 
			
		||||
  auto reg_it = find_if(begin(this->register_ranges_), end(this->register_ranges_), [=](RegisterRange const &r) {
 | 
			
		||||
    return (r.start_address == start_address && r.register_type == register_type);
 | 
			
		||||
  });
 | 
			
		||||
  auto reg_it = std::find_if(
 | 
			
		||||
      std::begin(this->register_ranges_), std::end(this->register_ranges_),
 | 
			
		||||
      [=](RegisterRange const &r) { return (r.start_address == start_address && r.register_type == register_type); });
 | 
			
		||||
 | 
			
		||||
  if (reg_it == this->register_ranges_.end()) {
 | 
			
		||||
    ESP_LOGE(TAG, "No matching range for sensor found - start_address : 0x%X", start_address);
 | 
			
		||||
@@ -375,12 +375,12 @@ void ModbusController::loop() {
 | 
			
		||||
  if (!this->incoming_queue_.empty()) {
 | 
			
		||||
    auto &message = this->incoming_queue_.front();
 | 
			
		||||
    if (message != nullptr)
 | 
			
		||||
      process_modbus_data_(message.get());
 | 
			
		||||
      this->process_modbus_data_(message.get());
 | 
			
		||||
    this->incoming_queue_.pop();
 | 
			
		||||
 | 
			
		||||
  } else {
 | 
			
		||||
    // all messages processed send pending commands
 | 
			
		||||
    send_next_command_();
 | 
			
		||||
    this->send_next_command_();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -97,7 +97,7 @@ void ModbusSwitch::write_state(bool state) {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  this->parent_->queue_command(cmd);
 | 
			
		||||
  publish_state(state);
 | 
			
		||||
  this->publish_state(state);
 | 
			
		||||
}
 | 
			
		||||
// ModbusSwitch end
 | 
			
		||||
}  // namespace modbus_controller
 | 
			
		||||
 
 | 
			
		||||
@@ -81,16 +81,39 @@ void QMC5883LComponent::dump_config() {
 | 
			
		||||
}
 | 
			
		||||
float QMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; }
 | 
			
		||||
void QMC5883LComponent::update() {
 | 
			
		||||
  i2c::ErrorCode err;
 | 
			
		||||
  uint8_t status = false;
 | 
			
		||||
  this->read_byte(QMC5883L_REGISTER_STATUS, &status);
 | 
			
		||||
  // Status byte gets cleared when data is read, so we have to read this first.
 | 
			
		||||
  // If status and two axes are desired, it's possible to save one byte of traffic by enabling
 | 
			
		||||
  // ROL_PNT in setup and reading 7 bytes starting at the status register.
 | 
			
		||||
  // If status and all three axes are desired, using ROL_PNT saves you 3 bytes.
 | 
			
		||||
  // But simply not reading status saves you 4 bytes always and is much simpler.
 | 
			
		||||
  if (ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG) {
 | 
			
		||||
    err = this->read_register(QMC5883L_REGISTER_STATUS, &status, 1);
 | 
			
		||||
    if (err != i2c::ERROR_OK) {
 | 
			
		||||
      this->status_set_warning(str_sprintf("status read failed (%d)", err).c_str());
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Always request X,Y,Z regardless if there are sensors for them
 | 
			
		||||
  // to avoid https://github.com/esphome/issues/issues/5731
 | 
			
		||||
  uint16_t raw_x, raw_y, raw_z;
 | 
			
		||||
  if (!this->read_byte_16_(QMC5883L_REGISTER_DATA_X_LSB, &raw_x) ||
 | 
			
		||||
      !this->read_byte_16_(QMC5883L_REGISTER_DATA_Y_LSB, &raw_y) ||
 | 
			
		||||
      !this->read_byte_16_(QMC5883L_REGISTER_DATA_Z_LSB, &raw_z)) {
 | 
			
		||||
    this->status_set_warning();
 | 
			
		||||
  uint16_t raw[3] = {0};
 | 
			
		||||
  // Z must always be requested, otherwise the data registers will remain locked against updates.
 | 
			
		||||
  // Skipping the Y axis if X and Z are needed actually requires an additional byte of comms.
 | 
			
		||||
  // Starting partway through the axes does save you traffic.
 | 
			
		||||
  uint8_t start, dest;
 | 
			
		||||
  if (this->heading_sensor_ != nullptr || this->x_sensor_ != nullptr) {
 | 
			
		||||
    start = QMC5883L_REGISTER_DATA_X_LSB;
 | 
			
		||||
    dest = 0;
 | 
			
		||||
  } else if (this->y_sensor_ != nullptr) {
 | 
			
		||||
    start = QMC5883L_REGISTER_DATA_Y_LSB;
 | 
			
		||||
    dest = 1;
 | 
			
		||||
  } else {
 | 
			
		||||
    start = QMC5883L_REGISTER_DATA_Z_LSB;
 | 
			
		||||
    dest = 2;
 | 
			
		||||
  }
 | 
			
		||||
  err = this->read_bytes_16_le_(start, &raw[dest], 3 - dest);
 | 
			
		||||
  if (err != i2c::ERROR_OK) {
 | 
			
		||||
    this->status_set_warning(str_sprintf("mag read failed (%d)", err).c_str());
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -107,17 +130,18 @@ void QMC5883LComponent::update() {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // in µT
 | 
			
		||||
  const float x = int16_t(raw_x) * mg_per_bit * 0.1f;
 | 
			
		||||
  const float y = int16_t(raw_y) * mg_per_bit * 0.1f;
 | 
			
		||||
  const float z = int16_t(raw_z) * mg_per_bit * 0.1f;
 | 
			
		||||
  const float x = int16_t(raw[0]) * mg_per_bit * 0.1f;
 | 
			
		||||
  const float y = int16_t(raw[1]) * mg_per_bit * 0.1f;
 | 
			
		||||
  const float z = int16_t(raw[2]) * mg_per_bit * 0.1f;
 | 
			
		||||
 | 
			
		||||
  float heading = atan2f(0.0f - x, y) * 180.0f / M_PI;
 | 
			
		||||
 | 
			
		||||
  float temp = NAN;
 | 
			
		||||
  if (this->temperature_sensor_ != nullptr) {
 | 
			
		||||
    uint16_t raw_temp;
 | 
			
		||||
    if (!this->read_byte_16_(QMC5883L_REGISTER_TEMPERATURE_LSB, &raw_temp)) {
 | 
			
		||||
      this->status_set_warning();
 | 
			
		||||
    err = this->read_bytes_16_le_(QMC5883L_REGISTER_TEMPERATURE_LSB, &raw_temp);
 | 
			
		||||
    if (err != i2c::ERROR_OK) {
 | 
			
		||||
      this->status_set_warning(str_sprintf("temp read failed (%d)", err).c_str());
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    temp = int16_t(raw_temp) * 0.01f;
 | 
			
		||||
@@ -138,11 +162,13 @@ void QMC5883LComponent::update() {
 | 
			
		||||
    this->temperature_sensor_->publish_state(temp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool QMC5883LComponent::read_byte_16_(uint8_t a_register, uint16_t *data) {
 | 
			
		||||
  if (!this->read_byte_16(a_register, data))
 | 
			
		||||
    return false;
 | 
			
		||||
  *data = (*data & 0x00FF) << 8 | (*data & 0xFF00) >> 8;  // Flip Byte order, LSB first;
 | 
			
		||||
  return true;
 | 
			
		||||
i2c::ErrorCode QMC5883LComponent::read_bytes_16_le_(uint8_t a_register, uint16_t *data, uint8_t len) {
 | 
			
		||||
  i2c::ErrorCode err = this->read_register(a_register, reinterpret_cast<uint8_t *>(data), len * 2);
 | 
			
		||||
  if (err != i2c::ERROR_OK)
 | 
			
		||||
    return err;
 | 
			
		||||
  for (size_t i = 0; i < len; i++)
 | 
			
		||||
    data[i] = convert_little_endian(data[i]);
 | 
			
		||||
  return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace qmc5883l
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
 | 
			
		||||
    NONE = 0,
 | 
			
		||||
    COMMUNICATION_FAILED,
 | 
			
		||||
  } error_code_;
 | 
			
		||||
  bool read_byte_16_(uint8_t a_register, uint16_t *data);
 | 
			
		||||
  i2c::ErrorCode read_bytes_16_le_(uint8_t a_register, uint16_t *data, uint8_t len = 1);
 | 
			
		||||
  HighFrequencyLoopRequester high_freq_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,23 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome import pins
 | 
			
		||||
from esphome.components import remote_base, esp32_rmt
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
from esphome.components import esp32_rmt, remote_base
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_BUFFER_SIZE,
 | 
			
		||||
    CONF_CLOCK_DIVIDER,
 | 
			
		||||
    CONF_DUMP,
 | 
			
		||||
    CONF_FILTER,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_IDLE,
 | 
			
		||||
    CONF_MEMORY_BLOCKS,
 | 
			
		||||
    CONF_PIN,
 | 
			
		||||
    CONF_RMT_CHANNEL,
 | 
			
		||||
    CONF_TOLERANCE,
 | 
			
		||||
    CONF_TYPE,
 | 
			
		||||
    CONF_MEMORY_BLOCKS,
 | 
			
		||||
    CONF_RMT_CHANNEL,
 | 
			
		||||
    CONF_VALUE,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, TimePeriod
 | 
			
		||||
 | 
			
		||||
CONF_CLOCK_DIVIDER = "clock_divider"
 | 
			
		||||
 | 
			
		||||
AUTO_LOAD = ["remote_base"]
 | 
			
		||||
remote_receiver_ns = cg.esphome_ns.namespace("remote_receiver")
 | 
			
		||||
remote_base_ns = cg.esphome_ns.namespace("remote_base")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								esphome/components/seeed_mr60bha2/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								esphome/components/seeed_mr60bha2/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
from esphome.components import uart
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.const import CONF_ID
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@limengdu"]
 | 
			
		||||
DEPENDENCIES = ["uart"]
 | 
			
		||||
MULTI_CONF = True
 | 
			
		||||
 | 
			
		||||
mr60bha2_ns = cg.esphome_ns.namespace("seeed_mr60bha2")
 | 
			
		||||
 | 
			
		||||
MR60BHA2Component = mr60bha2_ns.class_(
 | 
			
		||||
    "MR60BHA2Component", cg.Component, uart.UARTDevice
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
CONF_MR60BHA2_ID = "mr60bha2_id"
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = (
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            cv.GenerateID(): cv.declare_id(MR60BHA2Component),
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
    .extend(uart.UART_DEVICE_SCHEMA)
 | 
			
		||||
    .extend(cv.COMPONENT_SCHEMA)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
 | 
			
		||||
    "seeed_mr60bha2",
 | 
			
		||||
    require_tx=True,
 | 
			
		||||
    require_rx=True,
 | 
			
		||||
    baud_rate=115200,
 | 
			
		||||
    parity="NONE",
 | 
			
		||||
    stop_bits=1,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
			
		||||
    await cg.register_component(var, config)
 | 
			
		||||
    await uart.register_uart_device(var, config)
 | 
			
		||||
							
								
								
									
										173
									
								
								esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,173 @@
 | 
			
		||||
#include "seeed_mr60bha2.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace seeed_mr60bha2 {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "seeed_mr60bha2";
 | 
			
		||||
 | 
			
		||||
// Prints the component's configuration data. dump_config() prints all of the component's configuration
 | 
			
		||||
// items in an easy-to-read format, including the configuration key-value pairs.
 | 
			
		||||
void MR60BHA2Component::dump_config() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "MR60BHA2:");
 | 
			
		||||
#ifdef USE_SENSOR
 | 
			
		||||
  LOG_SENSOR(" ", "Breath Rate Sensor", this->breath_rate_sensor_);
 | 
			
		||||
  LOG_SENSOR(" ", "Heart Rate Sensor", this->heart_rate_sensor_);
 | 
			
		||||
  LOG_SENSOR(" ", "Distance Sensor", this->distance_sensor_);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// main loop
 | 
			
		||||
void MR60BHA2Component::loop() {
 | 
			
		||||
  uint8_t byte;
 | 
			
		||||
 | 
			
		||||
  // Is there data on the serial port
 | 
			
		||||
  while (this->available()) {
 | 
			
		||||
    this->read_byte(&byte);
 | 
			
		||||
    this->rx_message_.push_back(byte);
 | 
			
		||||
    if (!this->validate_message_()) {
 | 
			
		||||
      this->rx_message_.clear();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Calculate the checksum for a byte array.
 | 
			
		||||
 *
 | 
			
		||||
 * This function calculates the checksum for the provided byte array using an
 | 
			
		||||
 * XOR-based checksum algorithm.
 | 
			
		||||
 *
 | 
			
		||||
 * @param data The byte array to calculate the checksum for.
 | 
			
		||||
 * @param len The length of the byte array.
 | 
			
		||||
 * @return The calculated checksum.
 | 
			
		||||
 */
 | 
			
		||||
static uint8_t calculate_checksum(const uint8_t *data, size_t len) {
 | 
			
		||||
  uint8_t checksum = 0;
 | 
			
		||||
  for (size_t i = 0; i < len; i++) {
 | 
			
		||||
    checksum ^= data[i];
 | 
			
		||||
  }
 | 
			
		||||
  checksum = ~checksum;
 | 
			
		||||
  return checksum;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Validate the checksum of a byte array.
 | 
			
		||||
 *
 | 
			
		||||
 * This function validates the checksum of the provided byte array by comparing
 | 
			
		||||
 * it to the expected checksum.
 | 
			
		||||
 *
 | 
			
		||||
 * @param data The byte array to validate.
 | 
			
		||||
 * @param len The length of the byte array.
 | 
			
		||||
 * @param expected_checksum The expected checksum.
 | 
			
		||||
 * @return True if the checksum is valid, false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
static bool validate_checksum(const uint8_t *data, size_t len, uint8_t expected_checksum) {
 | 
			
		||||
  return calculate_checksum(data, len) == expected_checksum;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MR60BHA2Component::validate_message_() {
 | 
			
		||||
  size_t at = this->rx_message_.size() - 1;
 | 
			
		||||
  auto *data = &this->rx_message_[0];
 | 
			
		||||
  uint8_t new_byte = data[at];
 | 
			
		||||
 | 
			
		||||
  if (at == 0) {
 | 
			
		||||
    return new_byte == FRAME_HEADER_BUFFER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (at <= 2) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  uint16_t frame_id = encode_uint16(data[1], data[2]);
 | 
			
		||||
 | 
			
		||||
  if (at <= 4) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint16_t length = encode_uint16(data[3], data[4]);
 | 
			
		||||
 | 
			
		||||
  if (at <= 6) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint16_t frame_type = encode_uint16(data[5], data[6]);
 | 
			
		||||
 | 
			
		||||
  if (frame_type != BREATH_RATE_TYPE_BUFFER && frame_type != HEART_RATE_TYPE_BUFFER &&
 | 
			
		||||
      frame_type != DISTANCE_TYPE_BUFFER) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t header_checksum = new_byte;
 | 
			
		||||
 | 
			
		||||
  if (at == 7) {
 | 
			
		||||
    if (!validate_checksum(data, 7, header_checksum)) {
 | 
			
		||||
      ESP_LOGE(TAG, "HEAD_CKSUM_FRAME ERROR: 0x%02x", header_checksum);
 | 
			
		||||
      ESP_LOGV(TAG, "GET FRAME: %s", format_hex_pretty(data, 8).c_str());
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Wait until all data is read
 | 
			
		||||
  if (at - 8 < length) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t data_checksum = new_byte;
 | 
			
		||||
  if (at == 8 + length) {
 | 
			
		||||
    if (!validate_checksum(data + 8, length, data_checksum)) {
 | 
			
		||||
      ESP_LOGE(TAG, "DATA_CKSUM_FRAME ERROR: 0x%02x", data_checksum);
 | 
			
		||||
      ESP_LOGV(TAG, "GET FRAME: %s", format_hex_pretty(data, 8 + length).c_str());
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const uint8_t *frame_data = data + 8;
 | 
			
		||||
  ESP_LOGV(TAG, "Received Frame: ID: 0x%04x, Type: 0x%04x, Data: [%s] Raw Data: [%s]", frame_id, frame_type,
 | 
			
		||||
           format_hex_pretty(frame_data, length).c_str(), format_hex_pretty(this->rx_message_).c_str());
 | 
			
		||||
  this->process_frame_(frame_id, frame_type, data + 8, length);
 | 
			
		||||
 | 
			
		||||
  // Return false to reset rx buffer
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MR60BHA2Component::process_frame_(uint16_t frame_id, uint16_t frame_type, const uint8_t *data, size_t length) {
 | 
			
		||||
  switch (frame_type) {
 | 
			
		||||
    case BREATH_RATE_TYPE_BUFFER:
 | 
			
		||||
      if (this->breath_rate_sensor_ != nullptr && length >= 4) {
 | 
			
		||||
        uint32_t current_breath_rate_int = encode_uint32(data[3], data[2], data[1], data[0]);
 | 
			
		||||
        if (current_breath_rate_int != 0) {
 | 
			
		||||
          float breath_rate_float;
 | 
			
		||||
          memcpy(&breath_rate_float, ¤t_breath_rate_int, sizeof(float));
 | 
			
		||||
          this->breath_rate_sensor_->publish_state(breath_rate_float);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case HEART_RATE_TYPE_BUFFER:
 | 
			
		||||
      if (this->heart_rate_sensor_ != nullptr && length >= 4) {
 | 
			
		||||
        uint32_t current_heart_rate_int = encode_uint32(data[3], data[2], data[1], data[0]);
 | 
			
		||||
        if (current_heart_rate_int != 0) {
 | 
			
		||||
          float heart_rate_float;
 | 
			
		||||
          memcpy(&heart_rate_float, ¤t_heart_rate_int, sizeof(float));
 | 
			
		||||
          this->heart_rate_sensor_->publish_state(heart_rate_float);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case DISTANCE_TYPE_BUFFER:
 | 
			
		||||
      if (!data[0]) {
 | 
			
		||||
        if (this->distance_sensor_ != nullptr && length >= 8) {
 | 
			
		||||
          uint32_t current_distance_int = encode_uint32(data[7], data[6], data[5], data[4]);
 | 
			
		||||
          float distance_float;
 | 
			
		||||
          memcpy(&distance_float, ¤t_distance_int, sizeof(float));
 | 
			
		||||
          this->distance_sensor_->publish_state(distance_float);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace seeed_mr60bha2
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
							
								
								
									
										61
									
								
								esphome/components/seeed_mr60bha2/seeed_mr60bha2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								esphome/components/seeed_mr60bha2/seeed_mr60bha2.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/defines.h"
 | 
			
		||||
#ifdef USE_SENSOR
 | 
			
		||||
#include "esphome/components/sensor/sensor.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "esphome/components/uart/uart.h"
 | 
			
		||||
#include "esphome/core/automation.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace seeed_mr60bha2 {
 | 
			
		||||
 | 
			
		||||
static const uint8_t DATA_BUF_MAX_SIZE = 12;
 | 
			
		||||
static const uint8_t FRAME_BUF_MAX_SIZE = 21;
 | 
			
		||||
static const uint8_t LEN_TO_HEAD_CKSUM = 8;
 | 
			
		||||
static const uint8_t LEN_TO_DATA_FRAME = 9;
 | 
			
		||||
 | 
			
		||||
static const uint8_t FRAME_HEADER_BUFFER = 0x01;
 | 
			
		||||
static const uint16_t BREATH_RATE_TYPE_BUFFER = 0x0A14;
 | 
			
		||||
static const uint16_t HEART_RATE_TYPE_BUFFER = 0x0A15;
 | 
			
		||||
static const uint16_t DISTANCE_TYPE_BUFFER = 0x0A16;
 | 
			
		||||
 | 
			
		||||
enum FrameLocation {
 | 
			
		||||
  LOCATE_FRAME_HEADER,
 | 
			
		||||
  LOCATE_ID_FRAME1,
 | 
			
		||||
  LOCATE_ID_FRAME2,
 | 
			
		||||
  LOCATE_LENGTH_FRAME_H,
 | 
			
		||||
  LOCATE_LENGTH_FRAME_L,
 | 
			
		||||
  LOCATE_TYPE_FRAME1,
 | 
			
		||||
  LOCATE_TYPE_FRAME2,
 | 
			
		||||
  LOCATE_HEAD_CKSUM_FRAME,  // Header checksum: [from the first byte to the previous byte of the HEAD_CKSUM bit]
 | 
			
		||||
  LOCATE_DATA_FRAME,
 | 
			
		||||
  LOCATE_DATA_CKSUM_FRAME,  // Data checksum: [from the first to the previous byte of the DATA_CKSUM bit]
 | 
			
		||||
  LOCATE_PROCESS_FRAME,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MR60BHA2Component : public Component,
 | 
			
		||||
                          public uart::UARTDevice {  // The class name must be the name defined by text_sensor.py
 | 
			
		||||
#ifdef USE_SENSOR
 | 
			
		||||
  SUB_SENSOR(breath_rate);
 | 
			
		||||
  SUB_SENSOR(heart_rate);
 | 
			
		||||
  SUB_SENSOR(distance);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  float get_setup_priority() const override { return esphome::setup_priority::LATE; }
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  void loop() override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  bool validate_message_();
 | 
			
		||||
  void process_frame_(uint16_t frame_id, uint16_t frame_type, const uint8_t *data, size_t length);
 | 
			
		||||
 | 
			
		||||
  std::vector<uint8_t> rx_message_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace seeed_mr60bha2
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
							
								
								
									
										57
									
								
								esphome/components/seeed_mr60bha2/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								esphome/components/seeed_mr60bha2/sensor.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
from esphome.components import sensor
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_DISTANCE,
 | 
			
		||||
    DEVICE_CLASS_DISTANCE,
 | 
			
		||||
    ICON_HEART_PULSE,
 | 
			
		||||
    ICON_PULSE,
 | 
			
		||||
    ICON_SIGNAL,
 | 
			
		||||
    STATE_CLASS_MEASUREMENT,
 | 
			
		||||
    UNIT_BEATS_PER_MINUTE,
 | 
			
		||||
    UNIT_CENTIMETER,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from . import CONF_MR60BHA2_ID, MR60BHA2Component
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["seeed_mr60bha2"]
 | 
			
		||||
 | 
			
		||||
CONF_BREATH_RATE = "breath_rate"
 | 
			
		||||
CONF_HEART_RATE = "heart_rate"
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.Schema(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(CONF_MR60BHA2_ID): cv.use_id(MR60BHA2Component),
 | 
			
		||||
        cv.Optional(CONF_BREATH_RATE): sensor.sensor_schema(
 | 
			
		||||
            accuracy_decimals=2,
 | 
			
		||||
            state_class=STATE_CLASS_MEASUREMENT,
 | 
			
		||||
            icon=ICON_PULSE,
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_HEART_RATE): sensor.sensor_schema(
 | 
			
		||||
            accuracy_decimals=0,
 | 
			
		||||
            icon=ICON_HEART_PULSE,
 | 
			
		||||
            state_class=STATE_CLASS_MEASUREMENT,
 | 
			
		||||
            unit_of_measurement=UNIT_BEATS_PER_MINUTE,
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_DISTANCE): sensor.sensor_schema(
 | 
			
		||||
            device_class=DEVICE_CLASS_DISTANCE,
 | 
			
		||||
            state_class=STATE_CLASS_MEASUREMENT,
 | 
			
		||||
            unit_of_measurement=UNIT_CENTIMETER,
 | 
			
		||||
            accuracy_decimals=2,
 | 
			
		||||
            icon=ICON_SIGNAL,
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    mr60bha2_component = await cg.get_variable(config[CONF_MR60BHA2_ID])
 | 
			
		||||
    if breath_rate_config := config.get(CONF_BREATH_RATE):
 | 
			
		||||
        sens = await sensor.new_sensor(breath_rate_config)
 | 
			
		||||
        cg.add(mr60bha2_component.set_breath_rate_sensor(sens))
 | 
			
		||||
    if heart_rate_config := config.get(CONF_HEART_RATE):
 | 
			
		||||
        sens = await sensor.new_sensor(heart_rate_config)
 | 
			
		||||
        cg.add(mr60bha2_component.set_heart_rate_sensor(sens))
 | 
			
		||||
    if distance_config := config.get(CONF_DISTANCE):
 | 
			
		||||
        sens = await sensor.new_sensor(distance_config)
 | 
			
		||||
        cg.add(mr60bha2_component.set_distance_sensor(sens))
 | 
			
		||||
@@ -1,19 +1,19 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.components import i2c, sensor, sensirion_common
 | 
			
		||||
from esphome import automation
 | 
			
		||||
from esphome.automation import maybe_simple_id
 | 
			
		||||
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
from esphome.components import i2c, sensirion_common, sensor
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_HUMIDITY,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_OFFSET,
 | 
			
		||||
    CONF_PM_1_0,
 | 
			
		||||
    CONF_PM_10_0,
 | 
			
		||||
    CONF_PM_2_5,
 | 
			
		||||
    CONF_PM_4_0,
 | 
			
		||||
    CONF_PM_10_0,
 | 
			
		||||
    CONF_STORE_BASELINE,
 | 
			
		||||
    CONF_TEMPERATURE,
 | 
			
		||||
    CONF_TEMPERATURE_COMPENSATION,
 | 
			
		||||
    DEVICE_CLASS_AQI,
 | 
			
		||||
    DEVICE_CLASS_HUMIDITY,
 | 
			
		||||
    DEVICE_CLASS_PM1,
 | 
			
		||||
@@ -51,7 +51,6 @@ CONF_LEARNING_TIME_OFFSET_HOURS = "learning_time_offset_hours"
 | 
			
		||||
CONF_NORMALIZED_OFFSET_SLOPE = "normalized_offset_slope"
 | 
			
		||||
CONF_NOX = "nox"
 | 
			
		||||
CONF_STD_INITIAL = "std_initial"
 | 
			
		||||
CONF_TEMPERATURE_COMPENSATION = "temperature_compensation"
 | 
			
		||||
CONF_TIME_CONSTANT = "time_constant"
 | 
			
		||||
CONF_VOC = "voc"
 | 
			
		||||
CONF_VOC_BASELINE = "voc_baseline"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,22 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
from esphome.components import i2c, sensirion_common, sensor
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.components import i2c, sensor, sensirion_common
 | 
			
		||||
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_COMPENSATION,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_BASELINE,
 | 
			
		||||
    CONF_COMPENSATION,
 | 
			
		||||
    CONF_ECO2,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_STORE_BASELINE,
 | 
			
		||||
    CONF_TEMPERATURE_SOURCE,
 | 
			
		||||
    CONF_TVOC,
 | 
			
		||||
    ICON_RADIATOR,
 | 
			
		||||
    DEVICE_CLASS_CARBON_DIOXIDE,
 | 
			
		||||
    DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
			
		||||
    STATE_CLASS_MEASUREMENT,
 | 
			
		||||
    UNIT_PARTS_PER_MILLION,
 | 
			
		||||
    UNIT_PARTS_PER_BILLION,
 | 
			
		||||
    ICON_MOLECULE_CO2,
 | 
			
		||||
    ENTITY_CATEGORY_DIAGNOSTIC,
 | 
			
		||||
    ICON_MOLECULE_CO2,
 | 
			
		||||
    ICON_RADIATOR,
 | 
			
		||||
    STATE_CLASS_MEASUREMENT,
 | 
			
		||||
    UNIT_PARTS_PER_BILLION,
 | 
			
		||||
    UNIT_PARTS_PER_MILLION,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["i2c"]
 | 
			
		||||
@@ -77,7 +76,7 @@ CONFIG_SCHEMA = (
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
    .extend(cv.polling_component_schema("1s"))
 | 
			
		||||
    .extend(cv.polling_component_schema("60s"))
 | 
			
		||||
    .extend(i2c.i2c_device_schema(0x58))
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
#include "sgp30.h"
 | 
			
		||||
#include <cinttypes>
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include <cinttypes>
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace sgp30 {
 | 
			
		||||
@@ -295,10 +295,6 @@ void SGP30Component::update() {
 | 
			
		||||
    if (this->tvoc_sensor_ != nullptr)
 | 
			
		||||
      this->tvoc_sensor_->publish_state(tvoc);
 | 
			
		||||
 | 
			
		||||
    if (this->get_update_interval() != 1000) {
 | 
			
		||||
      ESP_LOGW(TAG, "Update interval for SGP30 sensor must be set to 1s for optimized readout");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->status_clear_warning();
 | 
			
		||||
    this->send_env_data_();
 | 
			
		||||
    this->read_iaq_baseline_();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,12 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
from esphome import automation
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
from esphome.components import i2c, sensor
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_EC,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_TEMPERATURE,
 | 
			
		||||
    CONF_TEMPERATURE_COMPENSATION,
 | 
			
		||||
    DEVICE_CLASS_EMPTY,
 | 
			
		||||
    DEVICE_CLASS_TEMPERATURE,
 | 
			
		||||
    ICON_EMPTY,
 | 
			
		||||
@@ -18,7 +19,6 @@ DEPENDENCIES = ["i2c"]
 | 
			
		||||
 | 
			
		||||
CONF_SOLUTION = "solution"
 | 
			
		||||
CONF_TEMPERATURE_SENSOR = "temperature_sensor"
 | 
			
		||||
CONF_TEMPERATURE_COMPENSATION = "temperature_compensation"
 | 
			
		||||
CONF_TEMPERATURE_COEFFICIENT = "temperature_coefficient"
 | 
			
		||||
 | 
			
		||||
ufire_ec_ns = cg.esphome_ns.namespace("ufire_ec")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"""Constants used by esphome."""
 | 
			
		||||
 | 
			
		||||
__version__ = "2024.12.0-dev"
 | 
			
		||||
__version__ = "2024.12.0b3"
 | 
			
		||||
 | 
			
		||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
 | 
			
		||||
VALID_SUBSTITUTIONS_CHARACTERS = (
 | 
			
		||||
@@ -131,7 +131,9 @@ CONF_CLIENT_CERTIFICATE = "client_certificate"
 | 
			
		||||
CONF_CLIENT_CERTIFICATE_KEY = "client_certificate_key"
 | 
			
		||||
CONF_CLIENT_ID = "client_id"
 | 
			
		||||
CONF_CLK_PIN = "clk_pin"
 | 
			
		||||
CONF_CLOCK_DIVIDER = "clock_divider"
 | 
			
		||||
CONF_CLOCK_PIN = "clock_pin"
 | 
			
		||||
CONF_CLOCK_RESOLUTION = "clock_resolution"
 | 
			
		||||
CONF_CLOSE_ACTION = "close_action"
 | 
			
		||||
CONF_CLOSE_DURATION = "close_duration"
 | 
			
		||||
CONF_CLOSE_ENDSTOP = "close_endstop"
 | 
			
		||||
@@ -463,7 +465,6 @@ CONF_MAGNITUDE = "magnitude"
 | 
			
		||||
CONF_MAINS_FILTER = "mains_filter"
 | 
			
		||||
CONF_MAKE_ID = "make_id"
 | 
			
		||||
CONF_MANUAL_IP = "manual_ip"
 | 
			
		||||
CONF_MANUFACTURER = "manufacturer"
 | 
			
		||||
CONF_MANUFACTURER_ID = "manufacturer_id"
 | 
			
		||||
CONF_MASK_DISTURBER = "mask_disturber"
 | 
			
		||||
CONF_MAX_BRIGHTNESS = "max_brightness"
 | 
			
		||||
@@ -740,6 +741,7 @@ CONF_RGB_ORDER = "rgb_order"
 | 
			
		||||
CONF_RGBW = "rgbw"
 | 
			
		||||
CONF_RISING_EDGE = "rising_edge"
 | 
			
		||||
CONF_RMT_CHANNEL = "rmt_channel"
 | 
			
		||||
CONF_RMT_SYMBOLS = "rmt_symbols"
 | 
			
		||||
CONF_ROTATION = "rotation"
 | 
			
		||||
CONF_ROW = "row"
 | 
			
		||||
CONF_RS_PIN = "rs_pin"
 | 
			
		||||
@@ -865,6 +867,7 @@ CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC = "target_temperature_low_command_topi
 | 
			
		||||
CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC = "target_temperature_low_state_topic"
 | 
			
		||||
CONF_TARGET_TEMPERATURE_STATE_TOPIC = "target_temperature_state_topic"
 | 
			
		||||
CONF_TEMPERATURE = "temperature"
 | 
			
		||||
CONF_TEMPERATURE_COMPENSATION = "temperature_compensation"
 | 
			
		||||
CONF_TEMPERATURE_OFFSET = "temperature_offset"
 | 
			
		||||
CONF_TEMPERATURE_SOURCE = "temperature_source"
 | 
			
		||||
CONF_TEMPERATURE_STEP = "temperature_step"
 | 
			
		||||
@@ -918,6 +921,7 @@ CONF_UPDATE_ON_BOOT = "update_on_boot"
 | 
			
		||||
CONF_URL = "url"
 | 
			
		||||
CONF_USE_ABBREVIATIONS = "use_abbreviations"
 | 
			
		||||
CONF_USE_ADDRESS = "use_address"
 | 
			
		||||
CONF_USE_DMA = "use_dma"
 | 
			
		||||
CONF_USE_FAHRENHEIT = "use_fahrenheit"
 | 
			
		||||
CONF_USERNAME = "username"
 | 
			
		||||
CONF_UUID = "uuid"
 | 
			
		||||
@@ -1002,6 +1006,7 @@ ICON_GRAIN = "mdi:grain"
 | 
			
		||||
ICON_GYROSCOPE_X = "mdi:axis-x-rotate-clockwise"
 | 
			
		||||
ICON_GYROSCOPE_Y = "mdi:axis-y-rotate-clockwise"
 | 
			
		||||
ICON_GYROSCOPE_Z = "mdi:axis-z-rotate-clockwise"
 | 
			
		||||
ICON_HEART_PULSE = "mdi:heart-pulse"
 | 
			
		||||
ICON_HEATING_COIL = "mdi:heating-coil"
 | 
			
		||||
ICON_KEY_PLUS = "mdi:key-plus"
 | 
			
		||||
ICON_LIGHTBULB = "mdi:lightbulb"
 | 
			
		||||
@@ -1041,6 +1046,7 @@ ICON_WEATHER_WINDY = "mdi:weather-windy"
 | 
			
		||||
ICON_WIFI = "mdi:wifi"
 | 
			
		||||
 | 
			
		||||
UNIT_AMPERE = "A"
 | 
			
		||||
UNIT_BEATS_PER_MINUTE = "bpm"
 | 
			
		||||
UNIT_BECQUEREL_PER_CUBIC_METER = "Bq/m³"
 | 
			
		||||
UNIT_BYTES = "B"
 | 
			
		||||
UNIT_CELSIUS = "°C"
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@ from esphome.const import (
 | 
			
		||||
    CONF_FRIENDLY_NAME,
 | 
			
		||||
    CONF_INCLUDES,
 | 
			
		||||
    CONF_LIBRARIES,
 | 
			
		||||
    CONF_MANUFACTURER,
 | 
			
		||||
    CONF_MIN_VERSION,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_NAME_ADD_MAC_SUFFIX,
 | 
			
		||||
@@ -97,33 +96,10 @@ def valid_include(value):
 | 
			
		||||
    return value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _validate_project_info(config):
 | 
			
		||||
    name = config[CONF_NAME]
 | 
			
		||||
    dot_count = name.count(".")
 | 
			
		||||
    if CONF_MANUFACTURER not in config:
 | 
			
		||||
        if dot_count != 1:
 | 
			
		||||
            raise cv.Invalid(
 | 
			
		||||
                f"'{CONF_MANUFACTURER}' is a required option for [{CONF_PROJECT}]"
 | 
			
		||||
            )
 | 
			
		||||
        author, name = name.split(".", 1)
 | 
			
		||||
        config[CONF_MANUFACTURER] = author
 | 
			
		||||
        config[CONF_NAME] = name
 | 
			
		||||
        _LOGGER.warning(
 | 
			
		||||
            "Prefixing %s %s with %s namespace is deprecated and will be disallowed in a future release. "
 | 
			
		||||
            "Please see current documentation for the correct way to define the %s information.",
 | 
			
		||||
            CONF_PROJECT,
 | 
			
		||||
            CONF_NAME,
 | 
			
		||||
            CONF_MANUFACTURER,
 | 
			
		||||
            CONF_PROJECT,
 | 
			
		||||
        )
 | 
			
		||||
    elif dot_count != 0:
 | 
			
		||||
        author, name = name.split(".", 1)
 | 
			
		||||
        raise cv.Invalid(
 | 
			
		||||
            f"Remove {CONF_MANUFACTURER} namespace '{author}.' from the {CONF_PROJECT} {CONF_NAME}",
 | 
			
		||||
            path=[CONF_NAME],
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    return config
 | 
			
		||||
def valid_project_name(value: str):
 | 
			
		||||
    if value.count(".") != 1:
 | 
			
		||||
        raise cv.Invalid("project name needs to have a namespace")
 | 
			
		||||
    return value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if "ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT" in os.environ:
 | 
			
		||||
@@ -134,6 +110,7 @@ if "ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT" in os.environ:
 | 
			
		||||
else:
 | 
			
		||||
    _compile_process_limit_default = cv.UNDEFINED
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONF_ESP8266_RESTORE_FROM_FLASH = "esp8266_restore_from_flash"
 | 
			
		||||
CONFIG_SCHEMA = cv.All(
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
@@ -168,22 +145,20 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
            cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(valid_include),
 | 
			
		||||
            cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict),
 | 
			
		||||
            cv.Optional(CONF_NAME_ADD_MAC_SUFFIX, default=False): cv.boolean,
 | 
			
		||||
            cv.Optional(CONF_PROJECT): cv.All(
 | 
			
		||||
                cv.Schema(
 | 
			
		||||
                    {
 | 
			
		||||
                        cv.Optional(CONF_MANUFACTURER): cv.string_strict,
 | 
			
		||||
                        cv.Required(CONF_NAME): cv.string_strict,
 | 
			
		||||
                        cv.Required(CONF_VERSION): cv.string_strict,
 | 
			
		||||
                        cv.Optional(CONF_ON_UPDATE): automation.validate_automation(
 | 
			
		||||
                            {
 | 
			
		||||
                                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
 | 
			
		||||
                                    ProjectUpdateTrigger
 | 
			
		||||
                                ),
 | 
			
		||||
                            }
 | 
			
		||||
                        ),
 | 
			
		||||
                    }
 | 
			
		||||
                ),
 | 
			
		||||
                _validate_project_info,
 | 
			
		||||
            cv.Optional(CONF_PROJECT): cv.Schema(
 | 
			
		||||
                {
 | 
			
		||||
                    cv.Required(CONF_NAME): cv.All(
 | 
			
		||||
                        cv.string_strict, valid_project_name
 | 
			
		||||
                    ),
 | 
			
		||||
                    cv.Required(CONF_VERSION): cv.string_strict,
 | 
			
		||||
                    cv.Optional(CONF_ON_UPDATE): automation.validate_automation(
 | 
			
		||||
                        {
 | 
			
		||||
                            cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
 | 
			
		||||
                                ProjectUpdateTrigger
 | 
			
		||||
                            ),
 | 
			
		||||
                        }
 | 
			
		||||
                    ),
 | 
			
		||||
                }
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_MIN_VERSION, default=ESPHOME_VERSION): cv.All(
 | 
			
		||||
                cv.version_number, cv.validate_esphome_version
 | 
			
		||||
@@ -419,7 +394,6 @@ async def to_code(config):
 | 
			
		||||
 | 
			
		||||
    if project_conf := config.get(CONF_PROJECT):
 | 
			
		||||
        cg.add_define("ESPHOME_PROJECT_NAME", project_conf[CONF_NAME])
 | 
			
		||||
        cg.add_define("ESPHOME_PROJECT_AUTHOR", project_conf[CONF_MANUFACTURER])
 | 
			
		||||
        cg.add_define("ESPHOME_PROJECT_VERSION", project_conf[CONF_VERSION])
 | 
			
		||||
        cg.add_define("ESPHOME_PROJECT_VERSION_30", project_conf[CONF_VERSION][:29])
 | 
			
		||||
        for conf in project_conf.get(CONF_ON_UPDATE, []):
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@
 | 
			
		||||
// Informative flags
 | 
			
		||||
#define ESPHOME_BOARD "dummy_board"
 | 
			
		||||
#define ESPHOME_PROJECT_NAME "dummy project"
 | 
			
		||||
#define ESPHOME_PROJECT_MANUFACTURER "ESPHome"
 | 
			
		||||
#define ESPHOME_PROJECT_VERSION "v2"
 | 
			
		||||
#define ESPHOME_PROJECT_VERSION_30 "v2"
 | 
			
		||||
#define ESPHOME_VARIANT "ESP32"
 | 
			
		||||
 
 | 
			
		||||
@@ -767,7 +767,8 @@ bool mac_address_is_valid(const uint8_t *mac) {
 | 
			
		||||
  return !(is_all_zeros || is_all_ones);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void delay_microseconds_safe(uint32_t us) {  // avoids CPU locks that could trigger WDT or affect WiFi/BT stability
 | 
			
		||||
void IRAM_ATTR HOT delay_microseconds_safe(uint32_t us) {
 | 
			
		||||
  // avoids CPU locks that could trigger WDT or affect WiFi/BT stability
 | 
			
		||||
  uint32_t start = micros();
 | 
			
		||||
 | 
			
		||||
  const uint32_t lag = 5000;  // microseconds, specifies the maximum time for a CPU busy-loop.
 | 
			
		||||
 
 | 
			
		||||
@@ -108,6 +108,12 @@ def is_authenticated(handler: BaseHandler) -> bool:
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
    if settings.using_auth:
 | 
			
		||||
        if auth_header := handler.request.headers.get("Authorization"):
 | 
			
		||||
            assert isinstance(auth_header, str)
 | 
			
		||||
            if auth_header.startswith("Basic "):
 | 
			
		||||
                auth_decoded = base64.b64decode(auth_header[6:]).decode()
 | 
			
		||||
                username, password = auth_decoded.split(":", 1)
 | 
			
		||||
                return settings.check_password(username, password)
 | 
			
		||||
        return handler.get_secure_cookie(AUTH_COOKIE_NAME) == COOKIE_AUTHENTICATED_YES
 | 
			
		||||
 | 
			
		||||
    return True
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
 | 
			
		||||
[project]
 | 
			
		||||
name        = "esphome"
 | 
			
		||||
license     = {text = "MIT"}
 | 
			
		||||
description = "Make creating custom firmwares for ESP32/ESP8266 super easy."
 | 
			
		||||
description = "ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems."
 | 
			
		||||
readme      = "README.md"
 | 
			
		||||
authors     = [
 | 
			
		||||
  {name = "The ESPHome Authors", email = "esphome@nabucasa.com"}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ pyserial==3.5
 | 
			
		||||
platformio==6.1.16  # When updating platformio, also update Dockerfile
 | 
			
		||||
esptool==4.7.0
 | 
			
		||||
click==8.1.7
 | 
			
		||||
esphome-dashboard==20241120.0
 | 
			
		||||
esphome-dashboard==20241217.1
 | 
			
		||||
aioesphomeapi==24.6.2
 | 
			
		||||
zeroconf==0.132.2
 | 
			
		||||
puremagic==1.27
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								tests/components/adc/test.bk72xx-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/components/adc/test.bk72xx-ard.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
sensor:
 | 
			
		||||
  - platform: adc
 | 
			
		||||
    pin: P23
 | 
			
		||||
    name: Basic ADC Test
 | 
			
		||||
@@ -165,6 +165,11 @@ lvgl:
 | 
			
		||||
              - Nov
 | 
			
		||||
              - Dec
 | 
			
		||||
            selected_index: 1
 | 
			
		||||
            on_change:
 | 
			
		||||
              then:
 | 
			
		||||
                - logger.log:
 | 
			
		||||
                    format: "Roller changed = %d: %s"
 | 
			
		||||
                    args: [x, text.c_str()]
 | 
			
		||||
            on_value:
 | 
			
		||||
              then:
 | 
			
		||||
                - logger.log:
 | 
			
		||||
@@ -451,6 +456,7 @@ lvgl:
 | 
			
		||||
            src: cat_image
 | 
			
		||||
            align: top_left
 | 
			
		||||
            y: "50"
 | 
			
		||||
            mode: real
 | 
			
		||||
        - tileview:
 | 
			
		||||
            id: tileview_id
 | 
			
		||||
            scrollbar_mode: active
 | 
			
		||||
@@ -647,6 +653,7 @@ lvgl:
 | 
			
		||||
                      grid_cell_row_pos: 0
 | 
			
		||||
                      grid_cell_column_pos: 0
 | 
			
		||||
                      src: !lambda return dog_image;
 | 
			
		||||
                      mode: virtual
 | 
			
		||||
                      on_click:
 | 
			
		||||
                        then:
 | 
			
		||||
                          - lvgl.tabview.select:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								tests/components/seeed_mr60bha2/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/components/seeed_mr60bha2/common.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
uart:
 | 
			
		||||
  - id: seeed_mr60fda2_uart
 | 
			
		||||
    tx_pin: ${uart_tx_pin}
 | 
			
		||||
    rx_pin: ${uart_rx_pin}
 | 
			
		||||
    baud_rate: 115200
 | 
			
		||||
    parity: NONE
 | 
			
		||||
    stop_bits: 1
 | 
			
		||||
 | 
			
		||||
seeed_mr60bha2:
 | 
			
		||||
  id: my_seeed_mr60bha2
 | 
			
		||||
 | 
			
		||||
sensor:
 | 
			
		||||
  - platform: seeed_mr60bha2
 | 
			
		||||
    breath_rate:
 | 
			
		||||
      name: "Real-time respiratory rate"
 | 
			
		||||
    heart_rate:
 | 
			
		||||
      name: "Real-time heart rate"
 | 
			
		||||
    distance:
 | 
			
		||||
      name: "Distance to detection object"
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/components/seeed_mr60bha2/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/seeed_mr60bha2/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
substitutions:
 | 
			
		||||
  uart_tx_pin: GPIO5
 | 
			
		||||
  uart_rx_pin: GPIO4
 | 
			
		||||
 | 
			
		||||
<<: !include common.yaml
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/components/seeed_mr60bha2/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/seeed_mr60bha2/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
substitutions:
 | 
			
		||||
  uart_tx_pin: GPIO5
 | 
			
		||||
  uart_rx_pin: GPIO4
 | 
			
		||||
 | 
			
		||||
<<: !include common.yaml
 | 
			
		||||
		Reference in New Issue
	
	Block a user