Merge pull request #4157 from esphome/bump-2022.12.0b1

2022.12.0b1
This commit is contained in:
Jesse Hills 2022-12-07 17:25:12 +13:00 committed by GitHub
commit 4be7cd12a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
286 changed files with 3685 additions and 1679 deletions

View file

@ -177,7 +177,7 @@ jobs:
- name: Run yamllint - name: Run yamllint
if: matrix.id == 'yamllint' if: matrix.id == 'yamllint'
uses: frenck/action-yamllint@v1.3.0 uses: frenck/action-yamllint@v1.3.1
- name: Suggested changes - name: Suggested changes
run: script/ci-suggest-changes run: script/ci-suggest-changes

View file

@ -18,7 +18,7 @@ jobs:
lock: lock:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: dessant/lock-threads@v3 - uses: dessant/lock-threads@v4
with: with:
pr-inactive-days: "1" pr-inactive-days: "1"
pr-lock-reason: "" pr-lock-reason: ""

View file

@ -11,7 +11,7 @@ repos:
- --quiet - --quiet
files: ^((esphome|script|tests)/.+)?[^/]+\.py$ files: ^((esphome|script|tests)/.+)?[^/]+\.py$
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 5.0.4 rev: 6.0.0
hooks: hooks:
- id: flake8 - id: flake8
additional_dependencies: additional_dependencies:
@ -27,7 +27,7 @@ repos:
- --branch=release - --branch=release
- --branch=beta - --branch=beta
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v3.2.0 rev: v3.3.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py39-plus] args: [--py39-plus]

View file

@ -208,6 +208,7 @@ esphome/components/sim800l/* @glmnet
esphome/components/sm2135/* @BoukeHaarsma23 esphome/components/sm2135/* @BoukeHaarsma23
esphome/components/sml/* @alengwenus esphome/components/sml/* @alengwenus
esphome/components/smt100/* @piechade esphome/components/smt100/* @piechade
esphome/components/sn74hc165/* @jesserockz
esphome/components/socket/* @esphome/core esphome/components/socket/* @esphome/core
esphome/components/sonoff_d1/* @anatoly-savchenkov esphome/components/sonoff_d1/* @anatoly-savchenkov
esphome/components/spi/* @esphome/core esphome/components/spi/* @esphome/core

View file

@ -6,17 +6,11 @@
ARG BASEIMGTYPE=docker ARG BASEIMGTYPE=docker
# https://github.com/hassio-addons/addon-debian-base/releases # https://github.com/hassio-addons/addon-debian-base/releases
FROM ghcr.io/hassio-addons/debian-base/amd64:5.3.0 AS base-hassio-amd64 FROM ghcr.io/hassio-addons/debian-base:6.1.3 AS base-hassio
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.3.0 AS base-hassio-arm64
FROM ghcr.io/hassio-addons/debian-base/armv7:5.3.0 AS base-hassio-armv7
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye # https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
FROM debian:bullseye-20220328-slim AS base-docker-amd64 FROM debian:bullseye-20221024-slim AS base-docker
FROM debian:bullseye-20220328-slim AS base-docker-arm64
FROM debian:bullseye-20220328-slim AS base-docker-armv7
# Use TARGETARCH/TARGETVARIANT defined by docker FROM base-${BASEIMGTYPE} AS base
# https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
FROM base-${BASEIMGTYPE}-${TARGETARCH}${TARGETVARIANT} AS base
RUN \ RUN \
apt-get update \ apt-get update \
@ -29,8 +23,8 @@ RUN \
python3-cryptography=3.3.2-1 \ python3-cryptography=3.3.2-1 \
iputils-ping=3:20210202-1 \ iputils-ping=3:20210202-1 \
git=1:2.30.2-1 \ git=1:2.30.2-1 \
curl=7.74.0-1.3+deb11u1 \ curl=7.74.0-1.3+deb11u3 \
openssh-client=1:8.4p1-5 \ openssh-client=1:8.4p1-5+deb11u1 \
&& rm -rf \ && rm -rf \
/tmp/* \ /tmp/* \
/var/{cache,log}/* \ /var/{cache,log}/* \

0
docker/ha-addon-rootfs/etc/cont-init.d/30-dirs.sh Normal file → Executable file
View file

View file

@ -3,7 +3,13 @@
# Community Hass.io Add-ons: ESPHome # Community Hass.io Add-ons: ESPHome
# Take down the S6 supervision tree when ESPHome fails # Take down the S6 supervision tree when ESPHome fails
# ============================================================================== # ==============================================================================
if -n { s6-test $# -ne 0 }
if -n { s6-test ${1} -eq 256 }
s6-svscanctl -t /var/run/s6/services declare APP_EXIT_CODE=${1}
if [[ "${APP_EXIT_CODE}" -ne 0 ]] && [[ "${APP_EXIT_CODE}" -ne 256 ]]; then
bashio::log.warning "Halt add-on with exit code ${APP_EXIT_CODE}"
echo "${APP_EXIT_CODE}" > /run/s6-linux-init-container-results/exitcode
exec /run/s6/basedir/bin/halt
fi
bashio::log.info "Service restart after closing"

View file

@ -22,6 +22,14 @@ if bashio::config.has_value 'relative_url'; then
export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url') export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url')
fi fi
if bashio::config.has_value 'default_compile_process_limit'; then
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=$(bashio::config 'default_compile_process_limit')
else
if grep -q 'Raspberry Pi 3' /proc/cpuinfo; then
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=1;
fi
fi
pio_cache_base=/data/cache/platformio pio_cache_base=/data/cache/platformio
# we can't set core_dir, because the settings file is stored in `core_dir/appstate.json` # we can't set core_dir, because the settings file is stored in `core_dir/appstate.json`
# setting `core_dir` would therefore prevent pio from accessing # setting `core_dir` would therefore prevent pio from accessing

View file

@ -3,7 +3,13 @@
# Community Hass.io Add-ons: ESPHome # Community Hass.io Add-ons: ESPHome
# Take down the S6 supervision tree when NGINX fails # Take down the S6 supervision tree when NGINX fails
# ============================================================================== # ==============================================================================
if -n { s6-test $# -ne 0 }
if -n { s6-test ${1} -eq 256 }
s6-svscanctl -t /var/run/s6/services declare APP_EXIT_CODE=${1}
if [[ "${APP_EXIT_CODE}" -ne 0 ]] && [[ "${APP_EXIT_CODE}" -ne 256 ]]; then
bashio::log.warning "Halt add-on with exit code ${APP_EXIT_CODE}"
echo "${APP_EXIT_CODE}" > /run/s6-linux-init-container-results/exitcode
exec /run/s6/basedir/bin/halt
fi
bashio::log.info "Service restart after closing"

View file

@ -254,8 +254,7 @@ def upload_using_esptool(config, port):
if os.environ.get("ESPHOME_USE_SUBPROCESS") is None: if os.environ.get("ESPHOME_USE_SUBPROCESS") is None:
import esptool import esptool
# pylint: disable=protected-access return run_external_command(esptool.main, *cmd) # pylint: disable=no-member
return run_external_command(esptool._main, *cmd)
return run_external_process(*cmd) return run_external_process(*cmd)
@ -298,6 +297,8 @@ def upload_program(config, args, host):
ota_conf = config[CONF_OTA] ota_conf = config[CONF_OTA]
remote_port = ota_conf[CONF_PORT] remote_port = ota_conf[CONF_PORT]
password = ota_conf.get(CONF_PASSWORD, "") password = ota_conf.get(CONF_PASSWORD, "")
if getattr(args, "file", None) is not None:
return espota2.run_ota(host, remote_port, password, args.file)
return espota2.run_ota(host, remote_port, password, CORE.firmware_bin) return espota2.run_ota(host, remote_port, password, CORE.firmware_bin)
@ -687,6 +688,10 @@ def parse_args(argv):
"--device", "--device",
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.", help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
) )
parser_upload.add_argument(
"--file",
help="Manually specify the binary file to upload.",
)
parser_logs = subparsers.add_parser( parser_logs = subparsers.add_parser(
"logs", "logs",

View file

@ -11,6 +11,10 @@ ADC_MODE(ADC_VCC)
#endif #endif
#endif #endif
#ifdef USE_RP2040
#include <hardware/adc.h>
#endif
namespace esphome { namespace esphome {
namespace adc { namespace adc {
@ -32,9 +36,13 @@ static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 b
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit) static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit)
#endif #endif
void ADCSensor::setup() { #ifdef USE_RP2040
extern "C"
#endif
void
ADCSensor::setup() {
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str()); ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
#ifndef USE_ADC_SENSOR_VCC #if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
pin_->setup(); pin_->setup();
#endif #endif
@ -63,6 +71,16 @@ void ADCSensor::setup() {
} }
#endif // USE_ESP32 #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() { void ADCSensor::dump_config() {
@ -98,6 +116,13 @@ void ADCSensor::dump_config() {
} }
} }
#endif // USE_ESP32 #endif // USE_ESP32
#ifdef USE_RP2040
if (this->is_temperature_) {
ESP_LOGCONFIG(TAG, " Pin: Temperature");
} else {
LOG_PIN(" Pin: ", pin_);
}
#endif
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
} }
@ -175,6 +200,29 @@ float ADCSensor::sample() {
} }
#endif // USE_ESP32 #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);
} else {
uint8_t pin = this->pin_->get_pin();
adc_gpio_init(pin);
adc_select_input(pin - 26);
}
int raw = adc_read();
if (this->is_temperature_) {
adc_set_temp_sensor_enabled(false);
}
if (output_raw_) {
return raw;
}
return raw * 3.3f / 4096.0f;
}
#endif
#ifdef USE_ESP8266 #ifdef USE_ESP8266
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; } std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
#endif #endif

View file

@ -38,10 +38,18 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
std::string unique_id() override; std::string unique_id() override;
#endif #endif
#ifdef USE_RP2040
void set_is_temperature() { is_temperature_ = true; }
#endif
protected: protected:
InternalGPIOPin *pin_; InternalGPIOPin *pin_;
bool output_raw_{false}; bool output_raw_{false};
#ifdef USE_RP2040
bool is_temperature_{false};
#endif
#ifdef USE_ESP32 #ifdef USE_ESP32
adc_atten_t attenuation_{ADC_ATTEN_DB_0}; adc_atten_t attenuation_{ADC_ATTEN_DB_0};
adc1_channel_t channel_{}; adc1_channel_t channel_{};

View file

@ -94,6 +94,9 @@ def validate_adc_pin(value):
if str(value).upper() == "VCC": if str(value).upper() == "VCC":
return cv.only_on_esp8266("VCC") return cv.only_on_esp8266("VCC")
if str(value).upper() == "TEMPERATURE":
return cv.only_on_rp2040("TEMPERATURE")
if CORE.is_esp32: if CORE.is_esp32:
value = pins.internal_gpio_input_pin_number(value) value = pins.internal_gpio_input_pin_number(value)
variant = get_esp32_variant() variant = get_esp32_variant()
@ -117,6 +120,12 @@ def validate_adc_pin(value):
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True {CONF_ANALOG: True, CONF_INPUT: True}, internal=True
)(value) )(value)
if CORE.is_rp2040:
value = pins.internal_gpio_input_pin_number(value)
if value not in (26, 27, 28, 29):
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
return pins.internal_gpio_input_pin_schema(value)
raise NotImplementedError raise NotImplementedError
@ -160,6 +169,8 @@ async def to_code(config):
if config[CONF_PIN] == "VCC": if config[CONF_PIN] == "VCC":
cg.add_define("USE_ADC_SENSOR_VCC") cg.add_define("USE_ADC_SENSOR_VCC")
elif config[CONF_PIN] == "TEMPERATURE":
cg.add(var.set_is_temperature())
else: else:
pin = await cg.gpio_pin_expression(config[CONF_PIN]) pin = await cg.gpio_pin_expression(config[CONF_PIN])
cg.add(var.set_pin(pin)) cg.add(var.set_pin(pin))

View file

@ -5,6 +5,8 @@
#include "esphome/components/display/display_buffer.h" #include "esphome/components/display/display_buffer.h"
#include "esphome/components/light/addressable_light.h" #include "esphome/components/light/addressable_light.h"
#include <vector>
namespace esphome { namespace esphome {
namespace addressable_light { namespace addressable_light {

View file

@ -5,6 +5,8 @@
#include "esphome/components/i2c/i2c.h" #include "esphome/components/i2c/i2c.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include <vector>
namespace esphome { namespace esphome {
namespace ade7953 { namespace ade7953 {

View file

@ -5,6 +5,8 @@
#include "esphome/components/i2c/i2c.h" #include "esphome/components/i2c/i2c.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h" #include "esphome/components/voltage_sampler/voltage_sampler.h"
#include <vector>
namespace esphome { namespace esphome {
namespace ads1115 { namespace ads1115 {

View file

@ -122,8 +122,9 @@ void AHT10Component::update() {
this->temperature_sensor_->publish_state(temperature); this->temperature_sensor_->publish_state(temperature);
} }
if (this->humidity_sensor_ != nullptr) { if (this->humidity_sensor_ != nullptr) {
if (std::isnan(humidity)) if (std::isnan(humidity)) {
ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum"); ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum");
}
this->humidity_sensor_->publish_state(humidity); this->humidity_sensor_->publish_state(humidity);
} }
this->status_clear_warning(); this->status_clear_warning();

View file

@ -104,8 +104,9 @@ void Am43::update() {
auto status = auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status); ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
}
} }
this->current_sensor_++; this->current_sensor_++;
} }

View file

@ -56,8 +56,9 @@ void Am43Component::control(const CoverCall &call) {
auto status = auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) if (status) {
ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status); ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
}
} }
if (call.get_position().has_value()) { if (call.get_position().has_value()) {
auto pos = *call.get_position(); auto pos = *call.get_position();
@ -68,8 +69,9 @@ void Am43Component::control(const CoverCall &call) {
auto status = auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) if (status) {
ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status); ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
}
} }
} }
@ -126,18 +128,21 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
this->char_handle_, packet->length, packet->data, this->char_handle_, packet->length, packet->data,
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) if (status) {
ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status); ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
}
} else { } else {
ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str()); ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str());
} }
} }
if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_) if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_) {
ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str()); ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str());
}
if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_) if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_) {
ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str()); ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str());
}
break; break;
} }
default: default:

View file

@ -37,16 +37,18 @@ void Anova::control(const ClimateCall &call) {
auto status = auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status); ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
}
} }
if (call.get_target_temperature().has_value()) { if (call.get_target_temperature().has_value()) {
auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature()); auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
auto status = auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status); ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
}
} }
} }
@ -143,8 +145,9 @@ void Anova::update() {
auto status = auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status); ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
}
this->current_request_++; this->current_request_++;
} }
} }

View file

@ -915,6 +915,7 @@ message ListEntitiesNumberResponse {
EntityCategory entity_category = 10; EntityCategory entity_category = 10;
string unit_of_measurement = 11; string unit_of_measurement = 11;
NumberMode mode = 12; NumberMode mode = 12;
string device_class = 13;
} }
message NumberStateResponse { message NumberStateResponse {
option (id) = 50; option (id) = 50;
@ -1140,6 +1141,8 @@ message BluetoothLEAdvertisementResponse {
repeated string service_uuids = 4; repeated string service_uuids = 4;
repeated BluetoothServiceData service_data = 5; repeated BluetoothServiceData service_data = 5;
repeated BluetoothServiceData manufacturer_data = 6; repeated BluetoothServiceData manufacturer_data = 6;
uint32 address_type = 7;
} }
enum BluetoothDeviceRequestType { enum BluetoothDeviceRequestType {
@ -1147,6 +1150,8 @@ enum BluetoothDeviceRequestType {
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1; BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2; BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3; BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4;
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5;
} }
message BluetoothDeviceRequest { message BluetoothDeviceRequest {
@ -1156,6 +1161,8 @@ message BluetoothDeviceRequest {
uint64 address = 1; uint64 address = 1;
BluetoothDeviceRequestType request_type = 2; BluetoothDeviceRequestType request_type = 2;
bool has_address_type = 3;
uint32 address_type = 4;
} }
message BluetoothDeviceConnectionResponse { message BluetoothDeviceConnectionResponse {

View file

@ -616,6 +616,7 @@ bool APIConnection::send_number_info(number::Number *number) {
msg.entity_category = static_cast<enums::EntityCategory>(number->get_entity_category()); msg.entity_category = static_cast<enums::EntityCategory>(number->get_entity_category());
msg.unit_of_measurement = number->traits.get_unit_of_measurement(); msg.unit_of_measurement = number->traits.get_unit_of_measurement();
msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode()); msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
msg.device_class = number->traits.get_device_class();
msg.min_value = number->traits.get_min_value(); msg.min_value = number->traits.get_min_value();
msg.max_value = number->traits.get_max_value(); msg.max_value = number->traits.get_max_value();
@ -949,7 +950,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.webserver_port = USE_WEBSERVER_PORT; resp.webserver_port = USE_WEBSERVER_PORT;
#endif #endif
#ifdef USE_BLUETOOTH_PROXY #ifdef USE_BLUETOOTH_PROXY
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 2 : 1; resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 3 : 1;
#endif #endif
return resp; return resp;
} }

View file

@ -7,6 +7,8 @@
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include <vector>
namespace esphome { namespace esphome {
namespace api { namespace api {

View file

@ -6,6 +6,7 @@
namespace esphome { namespace esphome {
namespace api { namespace api {
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) { template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) {
switch (value) { switch (value) {
case enums::ENTITY_CATEGORY_NONE: case enums::ENTITY_CATEGORY_NONE:
@ -18,6 +19,8 @@ template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::Entity
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::LegacyCoverState value) { template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::LegacyCoverState value) {
switch (value) { switch (value) {
case enums::LEGACY_COVER_STATE_OPEN: case enums::LEGACY_COVER_STATE_OPEN:
@ -28,6 +31,8 @@ template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::Lega
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverOperation value) { template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverOperation value) {
switch (value) { switch (value) {
case enums::COVER_OPERATION_IDLE: case enums::COVER_OPERATION_IDLE:
@ -40,6 +45,8 @@ template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverO
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::LegacyCoverCommand value) { template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::LegacyCoverCommand value) {
switch (value) { switch (value) {
case enums::LEGACY_COVER_COMMAND_OPEN: case enums::LEGACY_COVER_COMMAND_OPEN:
@ -52,6 +59,8 @@ template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::Le
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed value) { template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed value) {
switch (value) { switch (value) {
case enums::FAN_SPEED_LOW: case enums::FAN_SPEED_LOW:
@ -64,6 +73,8 @@ template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed val
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirection value) { template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirection value) {
switch (value) { switch (value) {
case enums::FAN_DIRECTION_FORWARD: case enums::FAN_DIRECTION_FORWARD:
@ -74,6 +85,8 @@ template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirec
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::ColorMode>(enums::ColorMode value) { template<> const char *proto_enum_to_string<enums::ColorMode>(enums::ColorMode value) {
switch (value) { switch (value) {
case enums::COLOR_MODE_UNKNOWN: case enums::COLOR_MODE_UNKNOWN:
@ -100,6 +113,8 @@ template<> const char *proto_enum_to_string<enums::ColorMode>(enums::ColorMode v
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::SensorStateClass value) { template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::SensorStateClass value) {
switch (value) { switch (value) {
case enums::STATE_CLASS_NONE: case enums::STATE_CLASS_NONE:
@ -114,6 +129,8 @@ template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::Sens
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::SensorLastResetType value) { template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::SensorLastResetType value) {
switch (value) { switch (value) {
case enums::LAST_RESET_NONE: case enums::LAST_RESET_NONE:
@ -126,6 +143,8 @@ template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::S
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) { template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
switch (value) { switch (value) {
case enums::LOG_LEVEL_NONE: case enums::LOG_LEVEL_NONE:
@ -148,6 +167,8 @@ template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel val
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::ServiceArgType value) { template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::ServiceArgType value) {
switch (value) { switch (value) {
case enums::SERVICE_ARG_TYPE_BOOL: case enums::SERVICE_ARG_TYPE_BOOL:
@ -170,6 +191,8 @@ template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::Servic
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMode value) { template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMode value) {
switch (value) { switch (value) {
case enums::CLIMATE_MODE_OFF: case enums::CLIMATE_MODE_OFF:
@ -190,6 +213,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::ClimateFanMode value) { template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::ClimateFanMode value) {
switch (value) { switch (value) {
case enums::CLIMATE_FAN_ON: case enums::CLIMATE_FAN_ON:
@ -214,6 +239,8 @@ template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::Climat
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::ClimateSwingMode value) { template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::ClimateSwingMode value) {
switch (value) { switch (value) {
case enums::CLIMATE_SWING_OFF: case enums::CLIMATE_SWING_OFF:
@ -228,6 +255,8 @@ template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::Clim
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::ClimateAction value) { template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::ClimateAction value) {
switch (value) { switch (value) {
case enums::CLIMATE_ACTION_OFF: case enums::CLIMATE_ACTION_OFF:
@ -246,6 +275,8 @@ template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::Climate
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::ClimatePreset value) { template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::ClimatePreset value) {
switch (value) { switch (value) {
case enums::CLIMATE_PRESET_NONE: case enums::CLIMATE_PRESET_NONE:
@ -268,6 +299,8 @@ template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::Climate
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode value) { template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode value) {
switch (value) { switch (value) {
case enums::NUMBER_MODE_AUTO: case enums::NUMBER_MODE_AUTO:
@ -280,6 +313,8 @@ template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState value) { template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState value) {
switch (value) { switch (value) {
case enums::LOCK_STATE_NONE: case enums::LOCK_STATE_NONE:
@ -298,6 +333,8 @@ template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState v
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockCommand value) { template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockCommand value) {
switch (value) { switch (value) {
case enums::LOCK_UNLOCK: case enums::LOCK_UNLOCK:
@ -310,6 +347,8 @@ template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockComma
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::MediaPlayerState value) { template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::MediaPlayerState value) {
switch (value) { switch (value) {
case enums::MEDIA_PLAYER_STATE_NONE: case enums::MEDIA_PLAYER_STATE_NONE:
@ -324,6 +363,8 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::Medi
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::MediaPlayerCommand value) { template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::MediaPlayerCommand value) {
switch (value) { switch (value) {
case enums::MEDIA_PLAYER_COMMAND_PLAY: case enums::MEDIA_PLAYER_COMMAND_PLAY:
@ -340,6 +381,8 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::Me
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
#ifdef HAS_PROTO_MESSAGE_DUMP
template<> template<>
const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) { const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
switch (value) { switch (value) {
@ -351,10 +394,15 @@ const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::Bluet
return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR"; return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR: case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR"; return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#endif
bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) { switch (field_id) {
case 2: { case 2: {
@ -3942,6 +3990,10 @@ bool ListEntitiesNumberResponse::decode_length(uint32_t field_id, ProtoLengthDel
this->unit_of_measurement = value.as_string(); this->unit_of_measurement = value.as_string();
return true; return true;
} }
case 13: {
this->device_class = value.as_string();
return true;
}
default: default:
return false; return false;
} }
@ -3981,6 +4033,7 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_enum<enums::EntityCategory>(10, this->entity_category); buffer.encode_enum<enums::EntityCategory>(10, this->entity_category);
buffer.encode_string(11, this->unit_of_measurement); buffer.encode_string(11, this->unit_of_measurement);
buffer.encode_enum<enums::NumberMode>(12, this->mode); buffer.encode_enum<enums::NumberMode>(12, this->mode);
buffer.encode_string(13, this->device_class);
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void ListEntitiesNumberResponse::dump_to(std::string &out) const { void ListEntitiesNumberResponse::dump_to(std::string &out) const {
@ -4037,6 +4090,10 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const {
out.append(" mode: "); out.append(" mode: ");
out.append(proto_enum_to_string<enums::NumberMode>(this->mode)); out.append(proto_enum_to_string<enums::NumberMode>(this->mode));
out.append("\n"); out.append("\n");
out.append(" device_class: ");
out.append("'").append(this->device_class).append("'");
out.append("\n");
out.append("}"); out.append("}");
} }
#endif #endif
@ -4984,6 +5041,10 @@ bool BluetoothLEAdvertisementResponse::decode_varint(uint32_t field_id, ProtoVar
this->rssi = value.as_sint32(); this->rssi = value.as_sint32();
return true; return true;
} }
case 7: {
this->address_type = value.as_uint32();
return true;
}
default: default:
return false; return false;
} }
@ -5023,6 +5084,7 @@ void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->manufacturer_data) { for (auto &it : this->manufacturer_data) {
buffer.encode_message<BluetoothServiceData>(6, it, true); buffer.encode_message<BluetoothServiceData>(6, it, true);
} }
buffer.encode_uint32(7, this->address_type);
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const { void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
@ -5059,6 +5121,11 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
it.dump_to(out); it.dump_to(out);
out.append("\n"); out.append("\n");
} }
out.append(" address_type: ");
sprintf(buffer, "%u", this->address_type);
out.append(buffer);
out.append("\n");
out.append("}"); out.append("}");
} }
#endif #endif
@ -5072,6 +5139,14 @@ bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
this->request_type = value.as_enum<enums::BluetoothDeviceRequestType>(); this->request_type = value.as_enum<enums::BluetoothDeviceRequestType>();
return true; return true;
} }
case 3: {
this->has_address_type = value.as_bool();
return true;
}
case 4: {
this->address_type = value.as_uint32();
return true;
}
default: default:
return false; return false;
} }
@ -5079,6 +5154,8 @@ bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
void BluetoothDeviceRequest::encode(ProtoWriteBuffer buffer) const { void BluetoothDeviceRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address); buffer.encode_uint64(1, this->address);
buffer.encode_enum<enums::BluetoothDeviceRequestType>(2, this->request_type); buffer.encode_enum<enums::BluetoothDeviceRequestType>(2, this->request_type);
buffer.encode_bool(3, this->has_address_type);
buffer.encode_uint32(4, this->address_type);
} }
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDeviceRequest::dump_to(std::string &out) const { void BluetoothDeviceRequest::dump_to(std::string &out) const {
@ -5092,6 +5169,15 @@ void BluetoothDeviceRequest::dump_to(std::string &out) const {
out.append(" request_type: "); out.append(" request_type: ");
out.append(proto_enum_to_string<enums::BluetoothDeviceRequestType>(this->request_type)); out.append(proto_enum_to_string<enums::BluetoothDeviceRequestType>(this->request_type));
out.append("\n"); out.append("\n");
out.append(" has_address_type: ");
out.append(YESNO(this->has_address_type));
out.append("\n");
out.append(" address_type: ");
sprintf(buffer, "%u", this->address_type);
out.append(buffer);
out.append("\n");
out.append("}"); out.append("}");
} }
#endif #endif

View file

@ -160,6 +160,8 @@ enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1, BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2, BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2,
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3, BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4,
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5,
}; };
} // namespace enums } // namespace enums
@ -1004,6 +1006,7 @@ class ListEntitiesNumberResponse : public ProtoMessage {
enums::EntityCategory entity_category{}; enums::EntityCategory entity_category{};
std::string unit_of_measurement{}; std::string unit_of_measurement{};
enums::NumberMode mode{}; enums::NumberMode mode{};
std::string device_class{};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;
@ -1256,6 +1259,7 @@ class BluetoothLEAdvertisementResponse : public ProtoMessage {
std::vector<std::string> service_uuids{}; std::vector<std::string> service_uuids{};
std::vector<BluetoothServiceData> service_data{}; std::vector<BluetoothServiceData> service_data{};
std::vector<BluetoothServiceData> manufacturer_data{}; std::vector<BluetoothServiceData> manufacturer_data{};
uint32_t address_type{0};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;
@ -1269,6 +1273,8 @@ class BluetoothDeviceRequest : public ProtoMessage {
public: public:
uint64_t address{0}; uint64_t address{0};
enums::BluetoothDeviceRequestType request_type{}; enums::BluetoothDeviceRequestType request_type{};
bool has_address_type{false};
uint32_t address_type{0};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;

View file

@ -12,6 +12,8 @@
#include "user_services.h" #include "user_services.h"
#include "api_noise_context.h" #include "api_noise_context.h"
#include <vector>
namespace esphome { namespace esphome {
namespace api { namespace api {

View file

@ -5,6 +5,8 @@
#include "api_pb2.h" #include "api_pb2.h"
#include "api_server.h" #include "api_server.h"
#include <vector>
namespace esphome { namespace esphome {
namespace api { namespace api {

View file

@ -4,6 +4,8 @@
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include <vector>
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
#define HAS_PROTO_MESSAGE_DUMP #define HAS_PROTO_MESSAGE_DUMP
#endif #endif

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <utility> #include <utility>
#include <vector>
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/automation.h" #include "esphome/core/automation.h"

View file

@ -4,6 +4,8 @@
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include <vector>
#ifdef USE_ESP32 #ifdef USE_ESP32
namespace esphome { namespace esphome {

View file

@ -8,6 +8,8 @@
#include "bedjet_child.h" #include "bedjet_child.h"
#include "bedjet_codec.h" #include "bedjet_codec.h"
#include <vector>
#ifdef USE_TIME #ifdef USE_TIME
#include "esphome/components/time/real_time_clock.h" #include "esphome/components/time/real_time_clock.h"
#endif #endif

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <utility> #include <utility>
#include <vector>
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/automation.h" #include "esphome/core/automation.h"

View file

@ -5,6 +5,8 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/components/binary_sensor/filter.h" #include "esphome/components/binary_sensor/filter.h"
#include <vector>
namespace esphome { namespace esphome {
namespace binary_sensor { namespace binary_sensor {

View file

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include <vector>
namespace esphome { namespace esphome {
namespace binary_sensor { namespace binary_sensor {

View file

@ -4,6 +4,8 @@
#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include <vector>
namespace esphome { namespace esphome {
namespace binary_sensor_map { namespace binary_sensor_map {

View file

@ -66,7 +66,7 @@ CONF_BLE_CLIENT_ID = "ble_client_id"
BLE_CLIENT_SCHEMA = cv.Schema( BLE_CLIENT_SCHEMA = cv.Schema(
{ {
cv.Required(CONF_BLE_CLIENT_ID): cv.use_id(BLEClient), cv.GenerateID(CONF_BLE_CLIENT_ID): cv.use_id(BLEClient),
} }
) )
@ -78,7 +78,7 @@ async def register_ble_node(var, config):
BLE_WRITE_ACTION_SCHEMA = cv.Schema( BLE_WRITE_ACTION_SCHEMA = cv.Schema(
{ {
cv.Required(CONF_ID): cv.use_id(BLEClient), cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid, cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid, cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
cv.Required(CONF_VALUE): cv.templatable(cv.ensure_list(cv.hex_uint8_t)), cv.Required(CONF_VALUE): cv.templatable(cv.ensure_list(cv.hex_uint8_t)),

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <utility> #include <utility>
#include <vector>
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
#include "esphome/components/ble_client/ble_client.h" #include "esphome/components/ble_client/ble_client.h"

View file

@ -7,12 +7,13 @@
#ifdef USE_ESP32 #ifdef USE_ESP32
#include <string>
#include <array>
#include <esp_gap_ble_api.h>
#include <esp_gattc_api.h>
#include <esp_bt_defs.h> #include <esp_bt_defs.h>
#include <esp_gap_ble_api.h>
#include <esp_gatt_common_api.h> #include <esp_gatt_common_api.h>
#include <esp_gattc_api.h>
#include <array>
#include <string>
#include <vector>
namespace esphome { namespace esphome {
namespace ble_client { namespace ble_client {

View file

@ -5,6 +5,8 @@
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include <vector>
#ifdef USE_ESP32 #ifdef USE_ESP32
#include <esp_gattc_api.h> #include <esp_gattc_api.h>

View file

@ -34,12 +34,39 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
this->set_address(0); this->set_address(0);
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(), api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
this->proxy_->get_bluetooth_connections_limit()); this->proxy_->get_bluetooth_connections_limit());
} else if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
this->proxy_->get_bluetooth_connections_limit());
} }
this->seen_mtu_or_services_ = false;
break;
}
case ESP_GATTC_CFG_MTU_EVT: {
if (param->cfg_mtu.conn_id != this->conn_id_)
break;
if (!this->seen_mtu_or_services_) {
// We don't know if we will get the MTU or the services first, so
// only send the device connection true if we have already received
// the services.
this->seen_mtu_or_services_ = true;
break;
}
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
this->proxy_->get_bluetooth_connections_limit());
break; break;
} }
case ESP_GATTC_SEARCH_CMPL_EVT: { case ESP_GATTC_SEARCH_CMPL_EVT: {
if (param->search_cmpl.conn_id != this->conn_id_) if (param->search_cmpl.conn_id != this->conn_id_)
break; break;
if (!this->seen_mtu_or_services_) {
// We don't know if we will get the MTU or the services first, so
// only send the device connection true if we have already received
// the mtu.
this->seen_mtu_or_services_ = true;
break;
}
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_); api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(), api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
this->proxy_->get_bluetooth_connections_limit()); this->proxy_->get_bluetooth_connections_limit());
@ -82,8 +109,6 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
break; break;
} }
case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: { case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: {
if (this->get_characteristic(param->unreg_for_notify.handle) == nullptr) // No conn_id in this event
break;
if (param->unreg_for_notify.status != ESP_GATT_OK) { if (param->unreg_for_notify.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "[%d] [%s] Error unregistering notifications for handle 0x%2X, status=%d", ESP_LOGW(TAG, "[%d] [%s] Error unregistering notifications for handle 0x%2X, status=%d",
this->connection_index_, this->address_str_.c_str(), param->unreg_for_notify.handle, this->connection_index_, this->address_str_.c_str(), param->unreg_for_notify.handle,
@ -99,8 +124,6 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
break; break;
} }
case ESP_GATTC_REG_FOR_NOTIFY_EVT: { case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
if (this->get_characteristic(param->reg_for_notify.handle) == nullptr) // No conn_id in this event
break;
if (param->reg_for_notify.status != ESP_GATT_OK) { if (param->reg_for_notify.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "[%d] [%s] Error registering notifications for handle 0x%2X, status=%d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] Error registering notifications for handle 0x%2X, status=%d", this->connection_index_,
this->address_str_.c_str(), param->reg_for_notify.handle, param->reg_for_notify.status); this->address_str_.c_str(), param->reg_for_notify.handle, param->reg_for_notify.status);
@ -141,18 +164,11 @@ esp_err_t BluetoothConnection::read_characteristic(uint16_t handle) {
this->address_str_.c_str()); this->address_str_.c_str());
return ESP_GATT_NOT_CONNECTED; return ESP_GATT_NOT_CONNECTED;
} }
auto *characteristic = this->get_characteristic(handle);
if (characteristic == nullptr) {
ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT characteristic, not found.", this->connection_index_,
this->address_str_.c_str());
return ESP_GATT_INVALID_HANDLE;
}
ESP_LOGV(TAG, "[%d] [%s] Reading GATT characteristic %s", this->connection_index_, this->address_str_.c_str(), ESP_LOGV(TAG, "[%d] [%s] Reading GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
characteristic->uuid.to_string().c_str()); handle);
esp_err_t err = esp_err_t err = esp_ble_gattc_read_char(this->gattc_if_, this->conn_id_, handle, ESP_GATT_AUTH_REQ_NONE);
esp_ble_gattc_read_char(this->gattc_if_, this->conn_id_, characteristic->handle, ESP_GATT_AUTH_REQ_NONE);
if (err != ERR_OK) { if (err != ERR_OK) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char error, err=%d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char error, err=%d", this->connection_index_,
this->address_str_.c_str(), err); this->address_str_.c_str(), err);
@ -167,18 +183,12 @@ esp_err_t BluetoothConnection::write_characteristic(uint16_t handle, const std::
this->address_str_.c_str()); this->address_str_.c_str());
return ESP_GATT_NOT_CONNECTED; return ESP_GATT_NOT_CONNECTED;
} }
auto *characteristic = this->get_characteristic(handle); ESP_LOGV(TAG, "[%d] [%s] Writing GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
if (characteristic == nullptr) { handle);
ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT characteristic, not found.", this->connection_index_,
this->address_str_.c_str());
return ESP_GATT_INVALID_HANDLE;
}
ESP_LOGV(TAG, "[%d] [%s] Writing GATT characteristic %s", this->connection_index_, this->address_str_.c_str(), esp_err_t err =
characteristic->uuid.to_string().c_str()); esp_ble_gattc_write_char(this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
auto err = characteristic->write_value((uint8_t *) data.data(), data.size(),
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP);
if (err != ERR_OK) { if (err != ERR_OK) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char error, err=%d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char error, err=%d", this->connection_index_,
this->address_str_.c_str(), err); this->address_str_.c_str(), err);
@ -193,18 +203,10 @@ esp_err_t BluetoothConnection::read_descriptor(uint16_t handle) {
this->address_str_.c_str()); this->address_str_.c_str());
return ESP_GATT_NOT_CONNECTED; return ESP_GATT_NOT_CONNECTED;
} }
auto *descriptor = this->get_descriptor(handle); ESP_LOGV(TAG, "[%d] [%s] Reading GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
if (descriptor == nullptr) { handle);
ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT descriptor, not found.", this->connection_index_,
this->address_str_.c_str());
return ESP_GATT_INVALID_HANDLE;
}
ESP_LOGV(TAG, "[%d] [%s] Reading GATT descriptor %s", this->connection_index_, this->address_str_.c_str(), esp_err_t err = esp_ble_gattc_read_char_descr(this->gattc_if_, this->conn_id_, handle, ESP_GATT_AUTH_REQ_NONE);
descriptor->uuid.to_string().c_str());
esp_err_t err =
esp_ble_gattc_read_char_descr(this->gattc_if_, this->conn_id_, descriptor->handle, ESP_GATT_AUTH_REQ_NONE);
if (err != ERR_OK) { if (err != ERR_OK) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char_descr error, err=%d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char_descr error, err=%d", this->connection_index_,
this->address_str_.c_str(), err); this->address_str_.c_str(), err);
@ -213,25 +215,18 @@ esp_err_t BluetoothConnection::read_descriptor(uint16_t handle) {
return ESP_OK; return ESP_OK;
} }
esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const std::string &data) { esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const std::string &data, bool response) {
if (!this->connected()) { if (!this->connected()) {
ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT descriptor, not connected.", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT descriptor, not connected.", this->connection_index_,
this->address_str_.c_str()); this->address_str_.c_str());
return ESP_GATT_NOT_CONNECTED; return ESP_GATT_NOT_CONNECTED;
} }
auto *descriptor = this->get_descriptor(handle); ESP_LOGV(TAG, "[%d] [%s] Writing GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
if (descriptor == nullptr) { handle);
ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT descriptor, not found.", this->connection_index_,
this->address_str_.c_str());
return ESP_GATT_INVALID_HANDLE;
}
ESP_LOGV(TAG, "[%d] [%s] Writing GATT descriptor %s", this->connection_index_, this->address_str_.c_str(), esp_err_t err = esp_ble_gattc_write_char_descr(
descriptor->uuid.to_string().c_str()); this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
auto err =
esp_ble_gattc_write_char_descr(this->gattc_if_, this->conn_id_, descriptor->handle, data.size(),
(uint8_t *) data.data(), ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (err != ERR_OK) { if (err != ERR_OK) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char_descr error, err=%d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char_descr error, err=%d", this->connection_index_,
this->address_str_.c_str(), err); this->address_str_.c_str(), err);
@ -246,26 +241,20 @@ esp_err_t BluetoothConnection::notify_characteristic(uint16_t handle, bool enabl
this->address_str_.c_str()); this->address_str_.c_str());
return ESP_GATT_NOT_CONNECTED; return ESP_GATT_NOT_CONNECTED;
} }
auto *characteristic = this->get_characteristic(handle);
if (characteristic == nullptr) {
ESP_LOGW(TAG, "[%d] [%s] Cannot notify GATT characteristic, not found.", this->connection_index_,
this->address_str_.c_str());
return ESP_GATT_INVALID_HANDLE;
}
if (enable) { if (enable) {
ESP_LOGV(TAG, "[%d] [%s] Registering for GATT characteristic notifications %s", this->connection_index_, ESP_LOGV(TAG, "[%d] [%s] Registering for GATT characteristic notifications handle %d", this->connection_index_,
this->address_str_.c_str(), characteristic->uuid.to_string().c_str()); this->address_str_.c_str(), handle);
esp_err_t err = esp_ble_gattc_register_for_notify(this->gattc_if_, this->remote_bda_, characteristic->handle); esp_err_t err = esp_ble_gattc_register_for_notify(this->gattc_if_, this->remote_bda_, handle);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_register_for_notify failed, err=%d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_register_for_notify failed, err=%d", this->connection_index_,
this->address_str_.c_str(), err); this->address_str_.c_str(), err);
return err; return err;
} }
} else { } else {
ESP_LOGV(TAG, "[%d] [%s] Unregistering for GATT characteristic notifications %s", this->connection_index_, ESP_LOGV(TAG, "[%d] [%s] Unregistering for GATT characteristic notifications handle %d", this->connection_index_,
this->address_str_.c_str(), characteristic->uuid.to_string().c_str()); this->address_str_.c_str(), handle);
esp_err_t err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, characteristic->handle); esp_err_t err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, handle);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_unregister_for_notify failed, err=%d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_unregister_for_notify failed, err=%d", this->connection_index_,
this->address_str_.c_str(), err); this->address_str_.c_str(), err);

View file

@ -17,14 +17,15 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase {
esp_err_t read_characteristic(uint16_t handle); esp_err_t read_characteristic(uint16_t handle);
esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response); esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response);
esp_err_t read_descriptor(uint16_t handle); esp_err_t read_descriptor(uint16_t handle);
esp_err_t write_descriptor(uint16_t handle, const std::string &data); esp_err_t write_descriptor(uint16_t handle, const std::string &data, bool response);
esp_err_t notify_characteristic(uint16_t handle, bool enable); esp_err_t notify_characteristic(uint16_t handle, bool enable);
protected: protected:
friend class BluetoothProxy; friend class BluetoothProxy;
bool seen_mtu_or_services_{false};
int16_t send_service_{-1}; int16_t send_service_{-2};
BluetoothProxy *proxy_; BluetoothProxy *proxy_;
}; };

View file

@ -10,6 +10,19 @@ namespace esphome {
namespace bluetooth_proxy { namespace bluetooth_proxy {
static const char *const TAG = "bluetooth_proxy"; static const char *const TAG = "bluetooth_proxy";
static const int DONE_SENDING_SERVICES = -2;
std::vector<uint64_t> get_128bit_uuid_vec(esp_bt_uuid_t uuid_source) {
esp_bt_uuid_t uuid = espbt::ESPBTUUID::from_uuid(uuid_source).as_128bit().get_uuid();
return std::vector<uint64_t>{((uint64_t) uuid.uuid.uuid128[15] << 56) | ((uint64_t) uuid.uuid.uuid128[14] << 48) |
((uint64_t) uuid.uuid.uuid128[13] << 40) | ((uint64_t) uuid.uuid.uuid128[12] << 32) |
((uint64_t) uuid.uuid.uuid128[11] << 24) | ((uint64_t) uuid.uuid.uuid128[10] << 16) |
((uint64_t) uuid.uuid.uuid128[9] << 8) | ((uint64_t) uuid.uuid.uuid128[8]),
((uint64_t) uuid.uuid.uuid128[7] << 56) | ((uint64_t) uuid.uuid.uuid128[6] << 48) |
((uint64_t) uuid.uuid.uuid128[5] << 40) | ((uint64_t) uuid.uuid.uuid128[4] << 32) |
((uint64_t) uuid.uuid.uuid128[3] << 24) | ((uint64_t) uuid.uuid.uuid128[2] << 16) |
((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0])};
}
BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; } BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
@ -26,6 +39,7 @@ bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device)
void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) { void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) {
api::BluetoothLEAdvertisementResponse resp; api::BluetoothLEAdvertisementResponse resp;
resp.address = device.address_uint64(); resp.address = device.address_uint64();
resp.address_type = device.get_address_type();
if (!device.get_name().empty()) if (!device.get_name().empty())
resp.name = device.get_name(); resp.name = device.get_name();
resp.rssi = device.get_rssi(); resp.rssi = device.get_rssi();
@ -52,6 +66,20 @@ void BluetoothProxy::dump_config() {
ESP_LOGCONFIG(TAG, " Active: %s", YESNO(this->active_)); ESP_LOGCONFIG(TAG, " Active: %s", YESNO(this->active_));
} }
int BluetoothProxy::get_bluetooth_connections_free() {
int free = 0;
for (auto *connection : this->connections_) {
if (connection->address_ == 0) {
free++;
ESP_LOGV(TAG, "[%d] Free connection", connection->get_connection_index());
} else {
ESP_LOGV(TAG, "[%d] Used connection by [%s]", connection->get_connection_index(),
connection->address_str().c_str());
}
}
return free;
}
void BluetoothProxy::loop() { void BluetoothProxy::loop() {
if (!api::global_api_server->is_connected()) { if (!api::global_api_server->is_connected()) {
for (auto *connection : this->connections_) { for (auto *connection : this->connections_) {
@ -62,32 +90,87 @@ void BluetoothProxy::loop() {
return; return;
} }
for (auto *connection : this->connections_) { for (auto *connection : this->connections_) {
if (connection->send_service_ == connection->services_.size()) { if (connection->send_service_ == connection->service_count_) {
connection->send_service_ = -1; connection->send_service_ = DONE_SENDING_SERVICES;
api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address()); api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address());
if (connection->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
connection->release_services();
}
} else if (connection->send_service_ >= 0) { } else if (connection->send_service_ >= 0) {
auto &service = connection->services_[connection->send_service_]; esp_gattc_service_elem_t service_result;
uint16_t service_count = 1;
esp_gatt_status_t service_status =
esp_ble_gattc_get_service(connection->get_gattc_if(), connection->get_conn_id(), nullptr, &service_result,
&service_count, connection->send_service_);
connection->send_service_++;
if (service_status != ESP_GATT_OK) {
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service error at offset=%d, status=%d",
connection->get_connection_index(), connection->address_str().c_str(), connection->send_service_ - 1,
service_status);
continue;
}
if (service_count == 0) {
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service missing, service_count=%d",
connection->get_connection_index(), connection->address_str().c_str(), service_count);
continue;
}
api::BluetoothGATTGetServicesResponse resp; api::BluetoothGATTGetServicesResponse resp;
resp.address = connection->get_address(); resp.address = connection->get_address();
api::BluetoothGATTService service_resp; api::BluetoothGATTService service_resp;
service_resp.uuid = {service->uuid.get_128bit_high(), service->uuid.get_128bit_low()}; service_resp.uuid = get_128bit_uuid_vec(service_result.uuid);
service_resp.handle = service->start_handle; service_resp.handle = service_result.start_handle;
for (auto &characteristic : service->characteristics) { uint16_t char_offset = 0;
esp_gattc_char_elem_t char_result;
while (true) { // characteristics
uint16_t char_count = 1;
esp_gatt_status_t char_status = esp_ble_gattc_get_all_char(
connection->get_gattc_if(), connection->get_conn_id(), service_result.start_handle,
service_result.end_handle, &char_result, &char_count, char_offset);
if (char_status == ESP_GATT_INVALID_OFFSET || char_status == ESP_GATT_NOT_FOUND) {
break;
}
if (char_status != ESP_GATT_OK) {
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_char error, status=%d", connection->get_connection_index(),
connection->address_str().c_str(), char_status);
break;
}
if (char_count == 0) {
break;
}
api::BluetoothGATTCharacteristic characteristic_resp; api::BluetoothGATTCharacteristic characteristic_resp;
characteristic_resp.uuid = {characteristic->uuid.get_128bit_high(), characteristic->uuid.get_128bit_low()}; characteristic_resp.uuid = get_128bit_uuid_vec(char_result.uuid);
characteristic_resp.handle = characteristic->handle; characteristic_resp.handle = char_result.char_handle;
characteristic_resp.properties = characteristic->properties; characteristic_resp.properties = char_result.properties;
for (auto &descriptor : characteristic->descriptors) { char_offset++;
uint16_t desc_offset = 0;
esp_gattc_descr_elem_t desc_result;
while (true) { // descriptors
uint16_t desc_count = 1;
esp_gatt_status_t desc_status =
esp_ble_gattc_get_all_descr(connection->get_gattc_if(), connection->get_conn_id(),
char_result.char_handle, &desc_result, &desc_count, desc_offset);
if (desc_status == ESP_GATT_INVALID_OFFSET || desc_status == ESP_GATT_NOT_FOUND) {
break;
}
if (desc_status != ESP_GATT_OK) {
ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_descr error, status=%d", connection->get_connection_index(),
connection->address_str().c_str(), desc_status);
break;
}
if (desc_count == 0) {
break;
}
api::BluetoothGATTDescriptor descriptor_resp; api::BluetoothGATTDescriptor descriptor_resp;
descriptor_resp.uuid = {descriptor->uuid.get_128bit_high(), descriptor->uuid.get_128bit_low()}; descriptor_resp.uuid = get_128bit_uuid_vec(desc_result.uuid);
descriptor_resp.handle = descriptor->handle; descriptor_resp.handle = desc_result.handle;
characteristic_resp.descriptors.push_back(std::move(descriptor_resp)); characteristic_resp.descriptors.push_back(std::move(descriptor_resp));
desc_offset++;
} }
service_resp.characteristics.push_back(std::move(characteristic_resp)); service_resp.characteristics.push_back(std::move(characteristic_resp));
} }
resp.services.push_back(std::move(service_resp)); resp.services.push_back(std::move(service_resp));
api::global_api_server->send_bluetooth_gatt_services(resp); api::global_api_server->send_bluetooth_gatt_services(resp);
connection->send_service_++;
} }
} }
} }
@ -103,7 +186,13 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese
for (auto *connection : this->connections_) { for (auto *connection : this->connections_) {
if (connection->get_address() == 0) { if (connection->get_address() == 0) {
connection->send_service_ = DONE_SENDING_SERVICES;
connection->set_address(address); connection->set_address(address);
// All connections must start at INIT
// We only set the state if we allocate the connection
// to avoid a race where multiple connection attempts
// are made.
connection->set_state(espbt::ClientState::INIT);
return connection; return connection;
} }
} }
@ -113,6 +202,8 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese
void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) { void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {
switch (msg.request_type) { switch (msg.request_type) {
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE:
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: { case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
auto *connection = this->get_connection_(msg.address, true); auto *connection = this->get_connection_(msg.address, true);
if (connection == nullptr) { if (connection == nullptr) {
@ -120,9 +211,63 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
api::global_api_server->send_bluetooth_device_connection(msg.address, false); api::global_api_server->send_bluetooth_device_connection(msg.address, false);
return; return;
} }
ESP_LOGV(TAG, "[%d] [%s] Searching to connect", connection->get_connection_index(), if (connection->state() == espbt::ClientState::CONNECTED ||
connection->address_str().c_str()); connection->state() == espbt::ClientState::ESTABLISHED) {
connection->set_state(espbt::ClientState::SEARCHING); ESP_LOGW(TAG, "[%d] [%s] Connection already established", connection->get_connection_index(),
connection->address_str().c_str());
api::global_api_server->send_bluetooth_device_connection(msg.address, true);
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
this->get_bluetooth_connections_limit());
return;
} else if (connection->state() == espbt::ClientState::SEARCHING) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already searching for device",
connection->get_connection_index(), connection->address_str().c_str());
return;
} else if (connection->state() == espbt::ClientState::DISCOVERED) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device already discovered",
connection->get_connection_index(), connection->address_str().c_str());
return;
} else if (connection->state() == espbt::ClientState::READY_TO_CONNECT) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, waiting in line to connect",
connection->get_connection_index(), connection->address_str().c_str());
return;
} else if (connection->state() == espbt::ClientState::CONNECTING) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already connecting", connection->get_connection_index(),
connection->address_str().c_str());
return;
} else if (connection->state() == espbt::ClientState::DISCONNECTING) {
ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device is disconnecting",
connection->get_connection_index(), connection->address_str().c_str());
return;
} else if (connection->state() != espbt::ClientState::INIT) {
ESP_LOGW(TAG, "[%d] [%s] Connection already in progress", connection->get_connection_index(),
connection->address_str().c_str());
return;
}
if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE) {
connection->set_connection_type(espbt::ConnectionType::V3_WITH_CACHE);
ESP_LOGI(TAG, "[%d] [%s] Connecting v3 with cache", connection->get_connection_index(),
connection->address_str().c_str());
} else if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE) {
connection->set_connection_type(espbt::ConnectionType::V3_WITHOUT_CACHE);
ESP_LOGI(TAG, "[%d] [%s] Connecting v3 without cache", connection->get_connection_index(),
connection->address_str().c_str());
} else {
connection->set_connection_type(espbt::ConnectionType::V1);
ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str());
}
if (msg.has_address_type) {
connection->remote_bda_[0] = (msg.address >> 40) & 0xFF;
connection->remote_bda_[1] = (msg.address >> 32) & 0xFF;
connection->remote_bda_[2] = (msg.address >> 24) & 0xFF;
connection->remote_bda_[3] = (msg.address >> 16) & 0xFF;
connection->remote_bda_[4] = (msg.address >> 8) & 0xFF;
connection->remote_bda_[5] = (msg.address >> 0) & 0xFF;
connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type));
connection->set_state(espbt::ClientState::DISCOVERED);
} else {
connection->set_state(espbt::ClientState::SEARCHING);
}
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(), api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
this->get_bluetooth_connections_limit()); this->get_bluetooth_connections_limit());
break; break;
@ -201,7 +346,7 @@ void BluetoothProxy::bluetooth_gatt_write_descriptor(const api::BluetoothGATTWri
return; return;
} }
auto err = connection->write_descriptor(msg.handle, msg.data); auto err = connection->write_descriptor(msg.handle, msg.data, true);
if (err != ESP_OK) { if (err != ESP_OK) {
api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err); api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err);
} }
@ -214,12 +359,13 @@ void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetSer
api::global_api_server->send_bluetooth_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED); api::global_api_server->send_bluetooth_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED);
return; return;
} }
if (connection->services_.empty()) { if (!connection->service_count_) {
ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str()); ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str());
api::global_api_server->send_bluetooth_gatt_services_done(msg.address); api::global_api_server->send_bluetooth_gatt_services_done(msg.address);
return; return;
} }
if (connection->send_service_ == -1) // Don't start sending services again if we're already sending them if (connection->send_service_ ==
DONE_SENDING_SERVICES) // Only start sending services if we're not already sending them
connection->send_service_ = 0; connection->send_service_ = 0;
} }

View file

@ -3,6 +3,7 @@
#ifdef USE_ESP32 #ifdef USE_ESP32
#include <map> #include <map>
#include <vector>
#include "esphome/components/api/api_pb2.h" #include "esphome/components/api/api_pb2.h"
#include "esphome/components/esp32_ble_client/ble_client_base.h" #include "esphome/components/esp32_ble_client/ble_client_base.h"
@ -40,15 +41,7 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg); void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg);
void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg); void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg);
int get_bluetooth_connections_free() { int get_bluetooth_connections_free();
int free = 0;
for (auto *connection : this->connections_) {
if (connection->address_ == 0) {
free++;
}
}
return free;
}
int get_bluetooth_connections_limit() { return this->connections_.size(); } int get_bluetooth_connections_limit() { return this->connections_.size(); }
void set_active(bool active) { this->active_ = active; } void set_active(bool active) { this->active_ = active; }
@ -59,7 +52,6 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
BluetoothConnection *get_connection_(uint64_t address, bool reserve); BluetoothConnection *get_connection_(uint64_t address, bool reserve);
int16_t send_service_{-1};
bool active_; bool active_;
std::vector<BluetoothConnection *> connections_{}; std::vector<BluetoothConnection *> connections_{};

View file

@ -4,6 +4,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/optional.h" #include "esphome/core/optional.h"
#include <vector>
namespace esphome { namespace esphome {
namespace canbus { namespace canbus {

View file

@ -6,6 +6,8 @@
#include "esphome/components/output/binary_output.h" #include "esphome/components/output/binary_output.h"
#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h"
#include <vector>
namespace esphome { namespace esphome {
namespace cap1188 { namespace cap1188 {

View file

@ -113,7 +113,9 @@ CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).
{ {
cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature, cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature,
cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature, cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature,
cv.Optional(CONF_TEMPERATURE_STEP): cv.temperature, cv.Optional(CONF_TEMPERATURE_STEP): cv.float_with_unit(
"visual_temperature", "(°C|° C|°|C|° K|° K|K|°F|° F|F)?"
),
} }
), ),
cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All( cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All(

View file

@ -540,12 +540,15 @@ void Climate::dump_traits_(const char *tag) {
ESP_LOGCONFIG(tag, " - Min: %.1f", traits.get_visual_min_temperature()); ESP_LOGCONFIG(tag, " - Min: %.1f", traits.get_visual_min_temperature());
ESP_LOGCONFIG(tag, " - Max: %.1f", traits.get_visual_max_temperature()); ESP_LOGCONFIG(tag, " - Max: %.1f", traits.get_visual_max_temperature());
ESP_LOGCONFIG(tag, " - Step: %.1f", traits.get_visual_temperature_step()); ESP_LOGCONFIG(tag, " - Step: %.1f", traits.get_visual_temperature_step());
if (traits.get_supports_current_temperature()) if (traits.get_supports_current_temperature()) {
ESP_LOGCONFIG(tag, " [x] Supports current temperature"); ESP_LOGCONFIG(tag, " [x] Supports current temperature");
if (traits.get_supports_two_point_target_temperature()) }
if (traits.get_supports_two_point_target_temperature()) {
ESP_LOGCONFIG(tag, " [x] Supports two-point target temperature"); ESP_LOGCONFIG(tag, " [x] Supports two-point target temperature");
if (traits.get_supports_action()) }
if (traits.get_supports_action()) {
ESP_LOGCONFIG(tag, " [x] Supports action"); ESP_LOGCONFIG(tag, " [x] Supports action");
}
if (!traits.get_supported_modes().empty()) { if (!traits.get_supported_modes().empty()) {
ESP_LOGCONFIG(tag, " [x] Supported modes:"); ESP_LOGCONFIG(tag, " [x] Supported modes:");
for (ClimateMode m : traits.get_supported_modes()) for (ClimateMode m : traits.get_supported_modes())

View file

@ -179,7 +179,7 @@ bool CurrentBasedCover::is_closing_blocked_() const {
if (this->close_obstacle_current_threshold_ == FLT_MAX) { if (this->close_obstacle_current_threshold_ == FLT_MAX) {
return false; return false;
} }
return this->open_sensor_->get_state() > this->open_obstacle_current_threshold_; return this->close_sensor_->get_state() > this->close_obstacle_current_threshold_;
} }
bool CurrentBasedCover::is_initial_delay_finished_() const { bool CurrentBasedCover::is_initial_delay_finished_() const {
return millis() - this->start_dir_time_ > this->start_sensing_delay_; return millis() - this->start_dir_time_ > this->start_sensing_delay_;

View file

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom { namespace custom {

View file

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/climate/climate.h" #include "esphome/components/climate/climate.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom { namespace custom {

View file

@ -2,6 +2,8 @@
#include "esphome/components/cover/cover.h" #include "esphome/components/cover/cover.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom { namespace custom {

View file

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/light/light_output.h" #include "esphome/components/light/light_output.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom { namespace custom {

View file

@ -4,6 +4,8 @@
#include "esphome/components/output/binary_output.h" #include "esphome/components/output/binary_output.h"
#include "esphome/components/output/float_output.h" #include "esphome/components/output/float_output.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom { namespace custom {

View file

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom { namespace custom {

View file

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/switch/switch.h" #include "esphome/components/switch/switch.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom { namespace custom {

View file

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/text_sensor/text_sensor.h" #include "esphome/components/text_sensor/text_sensor.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom { namespace custom {

View file

@ -3,6 +3,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include <vector>
namespace esphome { namespace esphome {
namespace custom_component { namespace custom_component {

View file

@ -29,8 +29,9 @@ void DAC7678Output::setup() {
ESP_LOGE(TAG, "Reset failed"); ESP_LOGE(TAG, "Reset failed");
this->mark_failed(); this->mark_failed();
return; return;
} else } else {
ESP_LOGV(TAG, "Reset succeeded"); ESP_LOGV(TAG, "Reset succeeded");
}
delayMicroseconds(1000); delayMicroseconds(1000);
@ -40,16 +41,18 @@ void DAC7678Output::setup() {
ESP_LOGE(TAG, "Set internal reference failed"); ESP_LOGE(TAG, "Set internal reference failed");
this->mark_failed(); this->mark_failed();
return; return;
} else } else {
ESP_LOGV(TAG, "Internal reference enabled"); ESP_LOGV(TAG, "Internal reference enabled");
}
} }
} }
void DAC7678Output::dump_config() { void DAC7678Output::dump_config() {
if (this->is_failed()) { if (this->is_failed()) {
ESP_LOGE(TAG, "Setting up DAC7678 failed!"); ESP_LOGE(TAG, "Setting up DAC7678 failed!");
} else } else {
ESP_LOGCONFIG(TAG, "DAC7678 initialised"); ESP_LOGCONFIG(TAG, "DAC7678 initialised");
}
} }
void DAC7678Output::register_channel(DAC7678Channel *channel) { void DAC7678Output::register_channel(DAC7678Channel *channel) {

View file

@ -4,6 +4,8 @@
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esp_one_wire.h" #include "esp_one_wire.h"
#include <vector>
namespace esphome { namespace esphome {
namespace dallas { namespace dallas {

View file

@ -85,9 +85,7 @@ bool HOT IRAM_ATTR ESPOneWire::read_bit() {
// whereas on esp-idf it already happens during the pin_mode(OUTPUT) // whereas on esp-idf it already happens during the pin_mode(OUTPUT)
// manually correct for this with these constants. // manually correct for this with these constants.
#ifdef USE_ESP32_FRAMEWORK_ARDUINO #ifdef USE_ESP32
uint32_t timing_constant = 14;
#elif defined(USE_ESP32_FRAMEWORK_ESP_IDF)
uint32_t timing_constant = 12; uint32_t timing_constant = 12;
#else #else
uint32_t timing_constant = 14; uint32_t timing_constant = 14;

View file

@ -6,6 +6,8 @@
#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/uart/uart.h" #include "esphome/components/uart/uart.h"
#include <vector>
namespace esphome { namespace esphome {
namespace daly_bms { namespace daly_bms {

View file

@ -1,4 +1,5 @@
from pathlib import Path from pathlib import Path
import requests
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
@ -6,6 +7,7 @@ from esphome.components.packages import validate_source_shorthand
from esphome.const import CONF_WIFI from esphome.const import CONF_WIFI
from esphome.wizard import wizard_file from esphome.wizard import wizard_file
from esphome.yaml_util import dump from esphome.yaml_util import dump
from esphome import git
dashboard_import_ns = cg.esphome_ns.namespace("dashboard_import") dashboard_import_ns = cg.esphome_ns.namespace("dashboard_import")
@ -25,9 +27,12 @@ def validate_import_url(value):
CONF_PACKAGE_IMPORT_URL = "package_import_url" CONF_PACKAGE_IMPORT_URL = "package_import_url"
CONF_IMPORT_FULL_CONFIG = "import_full_config"
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
{ {
cv.Required(CONF_PACKAGE_IMPORT_URL): validate_import_url, cv.Required(CONF_PACKAGE_IMPORT_URL): validate_import_url,
cv.Optional(CONF_IMPORT_FULL_CONFIG, default=False): cv.boolean,
} }
) )
@ -41,6 +46,9 @@ wifi:
async def to_code(config): async def to_code(config):
cg.add_define("USE_DASHBOARD_IMPORT") cg.add_define("USE_DASHBOARD_IMPORT")
url = config[CONF_PACKAGE_IMPORT_URL]
if config[CONF_IMPORT_FULL_CONFIG]:
url += "?full_config"
cg.add(dashboard_import_ns.set_package_import_url(config[CONF_PACKAGE_IMPORT_URL])) cg.add(dashboard_import_ns.set_package_import_url(config[CONF_PACKAGE_IMPORT_URL]))
@ -64,17 +72,30 @@ def import_config(
encoding="utf8", encoding="utf8",
) )
else: else:
config = { git_file = git.GitFile.from_shorthand(import_url)
"substitutions": {"name": name},
"packages": {project_name: import_url},
"esphome": {
"name": "${name}",
"name_add_mac_suffix": False,
},
}
output = dump(config)
if network == CONF_WIFI: if git_file.query and "full_config" in git_file.query:
output += WIFI_CONFIG url = git_file.raw_url
try:
req = requests.get(url, timeout=30)
req.raise_for_status()
except requests.exceptions.RequestException as e:
raise ValueError(f"Error while fetching {url}: {e}") from e
p.write_text(output, encoding="utf8") p.write_text(req.text, encoding="utf8")
else:
config = {
"substitutions": {"name": name},
"packages": {project_name: import_url},
"esphome": {
"name": "${name}",
"name_add_mac_suffix": False,
},
}
output = dump(config)
if network == CONF_WIFI:
output += WIFI_CONFIG
p.write_text(output, encoding="utf8")

View file

@ -1,11 +1,15 @@
import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
import esphome.final_validate as fv
from esphome.components import logger
from esphome.const import ( from esphome.const import (
CONF_ID,
CONF_DEVICE,
CONF_FREE,
CONF_FRAGMENTATION,
CONF_BLOCK, CONF_BLOCK,
CONF_DEVICE,
CONF_FRAGMENTATION,
CONF_FREE,
CONF_ID,
CONF_LEVEL,
CONF_LOGGER,
CONF_LOOP_TIME, CONF_LOOP_TIME,
) )
@ -39,6 +43,18 @@ CONFIG_SCHEMA = cv.Schema(
).extend(cv.polling_component_schema("60s")) ).extend(cv.polling_component_schema("60s"))
def _final_validate(_):
logger_conf = fv.full_config.get()[CONF_LOGGER]
severity = logger.LOG_LEVEL_SEVERITY.index(logger_conf[CONF_LEVEL])
if severity < logger.LOG_LEVEL_SEVERITY.index("DEBUG"):
raise cv.Invalid(
"The debug component requires the logger to be at least at DEBUG level"
)
FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)

View file

@ -38,14 +38,9 @@ static uint32_t get_free_heap() {
void DebugComponent::dump_config() { void DebugComponent::dump_config() {
std::string device_info; std::string device_info;
std::string reset_reason;
device_info.reserve(256); device_info.reserve(256);
#ifndef ESPHOME_LOG_HAS_DEBUG
ESP_LOGE(TAG, "Debug Component requires debug log level!");
this->status_set_error();
return;
#endif
ESP_LOGCONFIG(TAG, "Debug component:"); ESP_LOGCONFIG(TAG, "Debug component:");
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
LOG_TEXT_SENSOR(" ", "Device info", this->device_info_); LOG_TEXT_SENSOR(" ", "Device info", this->device_info_);
@ -146,7 +141,6 @@ void DebugComponent::dump_config() {
device_info += "|EFuse MAC: "; device_info += "|EFuse MAC: ";
device_info += mac; device_info += mac;
const char *reset_reason;
switch (rtc_get_reset_reason(0)) { switch (rtc_get_reset_reason(0)) {
case POWERON_RESET: case POWERON_RESET:
reset_reason = "Power On Reset"; reset_reason = "Power On Reset";
@ -196,7 +190,7 @@ void DebugComponent::dump_config() {
default: default:
reset_reason = "Unknown Reset Reason"; reset_reason = "Unknown Reset Reason";
} }
ESP_LOGD(TAG, "Reset Reason: %s", reset_reason); ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
device_info += "|Reset: "; device_info += "|Reset: ";
device_info += reset_reason; device_info += reset_reason;
@ -270,6 +264,8 @@ void DebugComponent::dump_config() {
device_info += ESP.getResetReason().c_str(); device_info += ESP.getResetReason().c_str();
device_info += "|"; device_info += "|";
device_info += ESP.getResetInfo().c_str(); device_info += ESP.getResetInfo().c_str();
reset_reason = ESP.getResetReason().c_str();
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
@ -278,6 +274,9 @@ void DebugComponent::dump_config() {
device_info.resize(255); device_info.resize(255);
this->device_info_->publish_state(device_info); this->device_info_->publish_state(device_info);
} }
if (this->reset_reason_ != nullptr) {
this->reset_reason_->publish_state(reset_reason);
}
#endif // USE_TEXT_SENSOR #endif // USE_TEXT_SENSOR
} }

View file

@ -24,6 +24,7 @@ class DebugComponent : public PollingComponent {
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
void set_device_info_sensor(text_sensor::TextSensor *device_info) { device_info_ = device_info; } void set_device_info_sensor(text_sensor::TextSensor *device_info) { device_info_ = device_info; }
void set_reset_reason_sensor(text_sensor::TextSensor *reset_reason) { reset_reason_ = reset_reason; }
#endif // USE_TEXT_SENSOR #endif // USE_TEXT_SENSOR
#ifdef USE_SENSOR #ifdef USE_SENSOR
void set_free_sensor(sensor::Sensor *free_sensor) { free_sensor_ = free_sensor; } void set_free_sensor(sensor::Sensor *free_sensor) { free_sensor_ = free_sensor; }
@ -50,6 +51,7 @@ class DebugComponent : public PollingComponent {
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
text_sensor::TextSensor *device_info_{nullptr}; text_sensor::TextSensor *device_info_{nullptr};
text_sensor::TextSensor *reset_reason_{nullptr};
#endif // USE_TEXT_SENSOR #endif // USE_TEXT_SENSOR
}; };

View file

@ -1,18 +1,29 @@
from esphome.components import text_sensor from esphome.components import text_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
from esphome.const import CONF_DEVICE, ENTITY_CATEGORY_DIAGNOSTIC from esphome.const import (
CONF_DEVICE,
ENTITY_CATEGORY_DIAGNOSTIC,
ICON_CHIP,
ICON_RESTART,
)
from . import CONF_DEBUG_ID, DebugComponent from . import CONF_DEBUG_ID, DebugComponent
DEPENDENCIES = ["debug"] DEPENDENCIES = ["debug"]
CONF_RESET_REASON = "reset_reason"
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
{ {
cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent), cv.GenerateID(CONF_DEBUG_ID): cv.use_id(DebugComponent),
cv.Optional(CONF_DEVICE): text_sensor.text_sensor_schema( cv.Optional(CONF_DEVICE): text_sensor.text_sensor_schema(
entity_category=ENTITY_CATEGORY_DIAGNOSTIC icon=ICON_CHIP,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
cv.Optional(CONF_RESET_REASON): text_sensor.text_sensor_schema(
icon=ICON_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
), ),
} }
) )
@ -24,3 +35,6 @@ async def to_code(config):
if CONF_DEVICE in config: if CONF_DEVICE in config:
sens = await text_sensor.new_text_sensor(config[CONF_DEVICE]) sens = await text_sensor.new_text_sensor(config[CONF_DEVICE])
cg.add(debug_component.set_device_info_sensor(sens)) cg.add(debug_component.set_device_info_sensor(sens))
if CONF_RESET_REASON in config:
sens = await text_sensor.new_text_sensor(config[CONF_RESET_REASON])
cg.add(debug_component.set_reset_reason_sensor(sens))

View file

@ -114,9 +114,9 @@ void DeepSleepComponent::begin_sleep(bool manual) {
#endif #endif
ESP_LOGI(TAG, "Beginning Deep Sleep"); ESP_LOGI(TAG, "Beginning Deep Sleep");
if (this->sleep_duration_.has_value()) if (this->sleep_duration_.has_value()) {
ESP_LOGI(TAG, "Sleeping for %" PRId64 "us", *this->sleep_duration_); ESP_LOGI(TAG, "Sleeping for %" PRId64 "us", *this->sleep_duration_);
}
App.run_safe_shutdown_hooks(); App.run_safe_shutdown_hooks();
#if defined(USE_ESP32) #if defined(USE_ESP32)
@ -147,7 +147,7 @@ void DeepSleepComponent::begin_sleep(bool manual) {
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) { if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
level = !level; level = !level;
} }
esp_deep_sleep_enable_gpio_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(),
static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level)); static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level));
} }
#endif #endif

View file

@ -77,14 +77,16 @@ void DFPlayer::loop() {
case 0x3A: case 0x3A:
if (argument == 1) { if (argument == 1) {
ESP_LOGI(TAG, "USB loaded"); ESP_LOGI(TAG, "USB loaded");
} else if (argument == 2) } else if (argument == 2) {
ESP_LOGI(TAG, "TF Card loaded"); ESP_LOGI(TAG, "TF Card loaded");
}
break; break;
case 0x3B: case 0x3B:
if (argument == 1) { if (argument == 1) {
ESP_LOGI(TAG, "USB unloaded"); ESP_LOGI(TAG, "USB unloaded");
} else if (argument == 2) } else if (argument == 2) {
ESP_LOGI(TAG, "TF Card unloaded"); ESP_LOGI(TAG, "TF Card unloaded");
}
break; break;
case 0x3F: case 0x3F:
if (argument == 1) { if (argument == 1) {

View file

@ -4,7 +4,9 @@
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
#include "display_color_utils.h" #include "display_color_utils.h"
#include <cstdarg> #include <cstdarg>
#include <vector>
#ifdef USE_TIME #ifdef USE_TIME
#include "esphome/components/time/real_time_clock.h" #include "esphome/components/time/real_time_clock.h"

View file

@ -13,6 +13,8 @@
#include <dsmr/parser.h> #include <dsmr/parser.h>
#include <dsmr/fields.h> #include <dsmr/fields.h>
#include <vector>
namespace esphome { namespace esphome {
namespace dsmr { namespace dsmr {

View file

@ -2,6 +2,8 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <vector>
namespace esphome { namespace esphome {
namespace ektf2232 { namespace ektf2232 {

View file

@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome import pins from esphome import pins
from esphome.components import i2c, touchscreen from esphome.components import i2c, touchscreen
from esphome.const import CONF_ID from esphome.const import CONF_ID, CONF_INTERRUPT_PIN
CODEOWNERS = ["@jesserockz"] CODEOWNERS = ["@jesserockz"]
DEPENDENCIES = ["i2c"] DEPENDENCIES = ["i2c"]
@ -17,10 +17,8 @@ EKTF2232Touchscreen = ektf2232_ns.class_(
) )
CONF_EKTF2232_ID = "ektf2232_id" CONF_EKTF2232_ID = "ektf2232_id"
CONF_INTERRUPT_PIN = "interrupt_pin"
CONF_RTS_PIN = "rts_pin" CONF_RTS_PIN = "rts_pin"
CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend(
cv.Schema( cv.Schema(
{ {

View file

@ -33,7 +33,7 @@ from .const import ( # noqa
VARIANT_FRIENDLY, VARIANT_FRIENDLY,
VARIANTS, VARIANTS,
) )
from .boards import BOARD_TO_VARIANT from .boards import BOARDS
# force import gpio to register pin schema # force import gpio to register pin schema
from .gpio import esp32_pin_to_code # noqa from .gpio import esp32_pin_to_code # noqa
@ -129,27 +129,27 @@ def _format_framework_espidf_version(ver: cv.Version) -> str:
# The default/recommended arduino framework version # The default/recommended arduino framework version
# - https://github.com/espressif/arduino-esp32/releases # - https://github.com/espressif/arduino-esp32/releases
# - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-arduinoespressif32 # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-arduinoespressif32
RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(1, 0, 6) RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(2, 0, 5)
# The platformio/espressif32 version to use for arduino frameworks # The platformio/espressif32 version to use for arduino frameworks
# - https://github.com/platformio/platform-espressif32/releases # - https://github.com/platformio/platform-espressif32/releases
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
ARDUINO_PLATFORM_VERSION = cv.Version(3, 5, 0) ARDUINO_PLATFORM_VERSION = cv.Version(5, 2, 0)
# The default/recommended esp-idf framework version # The default/recommended esp-idf framework version
# - https://github.com/espressif/esp-idf/releases # - https://github.com/espressif/esp-idf/releases
# - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf # - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 3, 2) RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 2)
# The platformio/espressif32 version to use for esp-idf frameworks # The platformio/espressif32 version to use for esp-idf frameworks
# - https://github.com/platformio/platform-espressif32/releases # - https://github.com/platformio/platform-espressif32/releases
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32 # - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
ESP_IDF_PLATFORM_VERSION = cv.Version(3, 5, 0) ESP_IDF_PLATFORM_VERSION = cv.Version(5, 2, 0)
def _arduino_check_versions(value): def _arduino_check_versions(value):
value = value.copy() value = value.copy()
lookups = { lookups = {
"dev": (cv.Version(2, 0, 0), "https://github.com/espressif/arduino-esp32.git"), "dev": (cv.Version(2, 0, 5), "https://github.com/espressif/arduino-esp32.git"),
"latest": (cv.Version(1, 0, 6), None), "latest": (cv.Version(2, 0, 5), None),
"recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None), "recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None),
} }
@ -184,7 +184,7 @@ def _esp_idf_check_versions(value):
value = value.copy() value = value.copy()
lookups = { lookups = {
"dev": (cv.Version(5, 0, 0), "https://github.com/espressif/esp-idf.git"), "dev": (cv.Version(5, 0, 0), "https://github.com/espressif/esp-idf.git"),
"latest": (cv.Version(4, 3, 2), None), "latest": (cv.Version(4, 4, 2), None),
"recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None), "recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None),
} }
@ -230,14 +230,14 @@ def _parse_platform_version(value):
def _detect_variant(value): def _detect_variant(value):
if CONF_VARIANT not in value: if CONF_VARIANT not in value:
board = value[CONF_BOARD] board = value[CONF_BOARD]
if board not in BOARD_TO_VARIANT: if board not in BOARDS:
raise cv.Invalid( raise cv.Invalid(
"This board is unknown, please set the variant manually", "This board is unknown, please set the variant manually",
path=[CONF_BOARD], path=[CONF_BOARD],
) )
value = value.copy() value = value.copy()
value[CONF_VARIANT] = BOARD_TO_VARIANT[board] value[CONF_VARIANT] = BOARDS[board][KEY_VARIANT]
return value return value
@ -327,6 +327,11 @@ async def to_code(config):
"platform_packages", "platform_packages",
[f"platformio/framework-espidf @ {conf[CONF_SOURCE]}"], [f"platformio/framework-espidf @ {conf[CONF_SOURCE]}"],
) )
# platformio/toolchain-esp32ulp does not support linux_aarch64 yet and has not been updated for over 2 years
# This is espressif's own published version which is more up to date.
cg.add_platformio_option(
"platform_packages", ["espressif/toolchain-esp32ulp @ 2.35.0-20220830"]
)
add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_SINGLE_APP", False) add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_SINGLE_APP", False)
add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_CUSTOM", True) add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_CUSTOM", True)
add_idf_sdkconfig_option( add_idf_sdkconfig_option(

View file

@ -1,4 +1,4 @@
from .const import VARIANT_ESP32, VARIANT_ESP32S2, VARIANT_ESP32C3 from .const import VARIANT_ESP32, VARIANT_ESP32S2, VARIANT_ESP32C3, VARIANT_ESP32S3
ESP32_BASE_PINS = { ESP32_BASE_PINS = {
"TX": 1, "TX": 1,
@ -42,6 +42,64 @@ ESP32_BASE_PINS = {
} }
ESP32_BOARD_PINS = { ESP32_BOARD_PINS = {
"adafruit_qtpy_esp32c3": {
"A0": 4,
"A1": 3,
"A2": 1,
"A3": 0,
"SDA": 5,
"SCL": 6,
"MOSI": 7,
"MISO": 8,
"SCK": 10,
"RX": 20,
"TX": 21,
"NEOPIXEL": 2,
"PIN_NEOPIXEL": 2,
"BUTTON": 9,
"SWITCH": 9,
},
"adafruit_qtpy_esp32s2": {
"A0": 18,
"A1": 17,
"A2": 9,
"A3": 8,
"SDA": 7,
"SCL": 6,
"MOSI": 35,
"MISO": 37,
"SCK": 36,
"RX": 16,
"TX": 5,
"SDA1": 41,
"SCL1": 40,
"NEOPIXEL": 39,
"PIN_NEOPIXEL": 39,
"NEOPIXEL_POWER": 38,
"D0": 0,
"BUTTON": 0,
"SWITCH": 0,
},
"adafruit_qtpy_esp32": {
"A0": 26,
"A1": 25,
"A2": 27,
"A3": 15,
"SDA": 4,
"SCL": 33,
"MOSI": 13,
"MISO": 12,
"SCK": 14,
"RX": 7,
"TX": 32,
"SDA1": 22,
"SCL1": 19,
"NEOPIXEL": 5,
"PIN_NEOPIXEL": 5,
"NEOPIXEL_POWER": 8,
"BUTTON": 0,
"SWITCH": 0,
},
"alksesp32": { "alksesp32": {
"A0": 32, "A0": 32,
"A1": 33, "A1": 33,
@ -550,6 +608,25 @@ ESP32_BOARD_PINS = {
}, },
"lolin_d32": {"LED": 5, "_VBAT": 35}, "lolin_d32": {"LED": 5, "_VBAT": 35},
"lolin_d32_pro": {"LED": 5, "_VBAT": 35}, "lolin_d32_pro": {"LED": 5, "_VBAT": 35},
"lolin_s2_mini": {
"TX": 43,
"RX": 44,
"SPICS1": 29,
"SPIHD": 31,
"SPIWP": 32,
"SPICS0": 33,
"SPICLK": 34,
"SPIQ": 35,
"SPID": 36,
"MISO": 9,
"MOSI": 11,
"SCK": 7,
"SCL": 35,
"SDA": 33,
"DAC1": 17,
"DAC2": 18,
"LED": 15,
},
"lopy": { "lopy": {
"A1": 37, "A1": 37,
"A2": 38, "A2": 38,
@ -984,127 +1061,743 @@ ESP32_BOARD_PINS = {
"D13": 2, "D13": 2,
}, },
"xinabox_cw02": {"LED": 27}, "xinabox_cw02": {"LED": 27},
"upesy_wroom": {"LED": 2},
"upesy_wrover": {"LED": 2},
} }
""" """
BOARD_TO_VARIANT generated with: BOARDS generated with:
git clone https://github.com/platformio/platform-espressif32 git clone https://github.com/platformio/platform-espressif32
for x in platform-espressif32/boards/*.json; do for x in platform-espressif32/boards/*.json; do
mcu=$(jq -r .build.mcu <"$x"); mcu=$(jq -r .build.mcu <"$x");
name=$(jq -r .name <"$x");
fname=$(basename "$x") fname=$(basename "$x")
board="${fname%.*}" board="${fname%.*}"
variant=$(echo "$mcu" | tr '[:lower:]' '[:upper:]') variant=$(echo "$mcu" | tr '[:lower:]' '[:upper:]')
echo " \"$board\": VARIANT_${variant}," echo " \"$board\": {\"name\": \"$name\", \"variant\": VARIANT_${variant},},"
done | sort done | sort
""" """
BOARD_TO_VARIANT = { BOARDS = {
"alksesp32": VARIANT_ESP32, "adafruit_feather_esp32s2_tft": {
"az-delivery-devkit-v4": VARIANT_ESP32, "name": "Adafruit Feather ESP32-S2 TFT",
"bpi-bit": VARIANT_ESP32, "variant": VARIANT_ESP32S2,
"briki_abc_esp32": VARIANT_ESP32, },
"briki_mbc-wb_esp32": VARIANT_ESP32, "adafruit_feather_esp32s3": {
"d-duino-32": VARIANT_ESP32, "name": "Adafruit Feather ESP32-S3 2MB PSRAM",
"esp320": VARIANT_ESP32, "variant": VARIANT_ESP32S3,
"esp32-c3-devkitm-1": VARIANT_ESP32C3, },
"esp32cam": VARIANT_ESP32, "adafruit_feather_esp32s3_nopsram": {
"esp32-devkitlipo": VARIANT_ESP32, "name": "Adafruit Feather ESP32-S3 No PSRAM",
"esp32dev": VARIANT_ESP32, "variant": VARIANT_ESP32S3,
"esp32doit-devkit-v1": VARIANT_ESP32, },
"esp32doit-espduino": VARIANT_ESP32, "adafruit_feather_esp32s3_tft": {
"esp32-evb": VARIANT_ESP32, "name": "Adafruit Feather ESP32-S3 TFT",
"esp32-gateway": VARIANT_ESP32, "variant": VARIANT_ESP32S3,
"esp32-poe-iso": VARIANT_ESP32, },
"esp32-poe": VARIANT_ESP32, "adafruit_feather_esp32_v2": {
"esp32-pro": VARIANT_ESP32, "name": "Adafruit Feather ESP32 V2",
"esp32-s2-kaluga-1": VARIANT_ESP32S2, "variant": VARIANT_ESP32,
"esp32-s2-saola-1": VARIANT_ESP32S2, },
"esp32thing_plus": VARIANT_ESP32, "adafruit_funhouse_esp32s2": {
"esp32thing": VARIANT_ESP32, "name": "Adafruit FunHouse",
"esp32vn-iot-uno": VARIANT_ESP32, "variant": VARIANT_ESP32S2,
"espea32": VARIANT_ESP32, },
"espectro32": VARIANT_ESP32, "adafruit_itsybitsy_esp32": {
"espino32": VARIANT_ESP32, "name": "Adafruit ItsyBitsy ESP32",
"esp-wrover-kit": VARIANT_ESP32, "variant": VARIANT_ESP32,
"etboard": VARIANT_ESP32, },
"featheresp32-s2": VARIANT_ESP32S2, "adafruit_magtag29_esp32s2": {
"featheresp32": VARIANT_ESP32, "name": "Adafruit MagTag 2.9",
"firebeetle32": VARIANT_ESP32, "variant": VARIANT_ESP32S2,
"fm-devkit": VARIANT_ESP32, },
"frogboard": VARIANT_ESP32, "adafruit_metro_esp32s2": {
"healthypi4": VARIANT_ESP32, "name": "Adafruit Metro ESP32-S2",
"heltec_wifi_kit_32_v2": VARIANT_ESP32, "variant": VARIANT_ESP32S2,
"heltec_wifi_kit_32": VARIANT_ESP32, },
"heltec_wifi_lora_32_V2": VARIANT_ESP32, "adafruit_qtpy_esp32c3": {
"heltec_wifi_lora_32": VARIANT_ESP32, "name": "Adafruit QT Py ESP32-C3",
"heltec_wireless_stick_lite": VARIANT_ESP32, "variant": VARIANT_ESP32C3,
"heltec_wireless_stick": VARIANT_ESP32, },
"honeylemon": VARIANT_ESP32, "adafruit_qtpy_esp32": {
"hornbill32dev": VARIANT_ESP32, "name": "Adafruit QT Py ESP32",
"hornbill32minima": VARIANT_ESP32, "variant": VARIANT_ESP32,
"imbrios-logsens-v1p1": VARIANT_ESP32, },
"inex_openkb": VARIANT_ESP32, "adafruit_qtpy_esp32s2": {
"intorobot": VARIANT_ESP32, "name": "Adafruit QT Py ESP32-S2",
"iotaap_magnolia": VARIANT_ESP32, "variant": VARIANT_ESP32S2,
"iotbusio": VARIANT_ESP32, },
"iotbusproteus": VARIANT_ESP32, "adafruit_qtpy_esp32s3_nopsram": {
"kits-edu": VARIANT_ESP32, "name": "Adafruit QT Py ESP32-S3 No PSRAM",
"labplus_mpython": VARIANT_ESP32, "variant": VARIANT_ESP32S3,
"lolin32_lite": VARIANT_ESP32, },
"lolin32": VARIANT_ESP32, "airm2m_core_esp32c3": {
"lolin_c3_mini": VARIANT_ESP32C3, "name": "AirM2M CORE ESP32C3",
"lolin_d32_pro": VARIANT_ESP32, "variant": VARIANT_ESP32C3,
"lolin_d32": VARIANT_ESP32, },
"lopy4": VARIANT_ESP32, "alksesp32": {
"lopy": VARIANT_ESP32, "name": "ALKS ESP32",
"m5stack-atom": VARIANT_ESP32, "variant": VARIANT_ESP32,
"m5stack-core2": VARIANT_ESP32, },
"m5stack-core-esp32": VARIANT_ESP32, "atmegazero_esp32s2": {
"m5stack-coreink": VARIANT_ESP32, "name": "EspinalLab ATMegaZero ESP32-S2",
"m5stack-fire": VARIANT_ESP32, "variant": VARIANT_ESP32S2,
"m5stack-grey": VARIANT_ESP32, },
"m5stack-timer-cam": VARIANT_ESP32, "az-delivery-devkit-v4": {
"m5stick-c": VARIANT_ESP32, "name": "AZ-Delivery ESP-32 Dev Kit C V4",
"magicbit": VARIANT_ESP32, "variant": VARIANT_ESP32,
"mgbot-iotik32a": VARIANT_ESP32, },
"mgbot-iotik32b": VARIANT_ESP32, "bee_motion_mini": {
"mhetesp32devkit": VARIANT_ESP32, "name": "Smart Bee Motion Mini",
"mhetesp32minikit": VARIANT_ESP32, "variant": VARIANT_ESP32C3,
"microduino-core-esp32": VARIANT_ESP32, },
"nano32": VARIANT_ESP32, "bee_motion": {
"nina_w10": VARIANT_ESP32, "name": "Smart Bee Motion",
"node32s": VARIANT_ESP32, "variant": VARIANT_ESP32S2,
"nodemcu-32s": VARIANT_ESP32, },
"nscreen-32": VARIANT_ESP32, "bee_motion_s3": {
"odroid_esp32": VARIANT_ESP32, "name": "Smart Bee Motion S3",
"onehorse32dev": VARIANT_ESP32, "variant": VARIANT_ESP32S3,
"oroca_edubot": VARIANT_ESP32, },
"pico32": VARIANT_ESP32, "bee_s3": {
"piranha_esp32": VARIANT_ESP32, "name": "Smart Bee S3",
"pocket_32": VARIANT_ESP32, "variant": VARIANT_ESP32S3,
"pycom_gpy": VARIANT_ESP32, },
"qchip": VARIANT_ESP32, "bpi-bit": {
"quantum": VARIANT_ESP32, "name": "BPI-Bit",
"sensesiot_weizen": VARIANT_ESP32, "variant": VARIANT_ESP32,
"sg-o_airMon": VARIANT_ESP32, },
"s_odi_ultra": VARIANT_ESP32, "briki_abc_esp32": {
"sparkfun_lora_gateway_1-channel": VARIANT_ESP32, "name": "Briki ABC (MBC-WB) - ESP32",
"tinypico": VARIANT_ESP32, "variant": VARIANT_ESP32,
"ttgo-lora32-v1": VARIANT_ESP32, },
"ttgo-lora32-v21": VARIANT_ESP32, "briki_mbc-wb_esp32": {
"ttgo-lora32-v2": VARIANT_ESP32, "name": "Briki MBC-WB - ESP32",
"ttgo-t1": VARIANT_ESP32, "variant": VARIANT_ESP32,
"ttgo-t7-v13-mini32": VARIANT_ESP32, },
"ttgo-t7-v14-mini32": VARIANT_ESP32, "cnrs_aw2eth": {
"ttgo-t-beam": VARIANT_ESP32, "name": "CNRS AW2ETH",
"ttgo-t-watch": VARIANT_ESP32, "variant": VARIANT_ESP32,
"turta_iot_node": VARIANT_ESP32, },
"vintlabs-devkit-v1": VARIANT_ESP32, "connaxio_espoir": {
"wemosbat": VARIANT_ESP32, "name": "Connaxio's Espoir",
"wemos_d1_mini32": VARIANT_ESP32, "variant": VARIANT_ESP32,
"wesp32": VARIANT_ESP32, },
"widora-air": VARIANT_ESP32, "d-duino-32": {
"wifiduino32": VARIANT_ESP32, "name": "D-duino-32",
"xinabox_cw02": VARIANT_ESP32, "variant": VARIANT_ESP32,
},
"deneyapkart1A": {
"name": "Deneyap Kart 1A",
"variant": VARIANT_ESP32,
},
"deneyapkartg": {
"name": "Deneyap Kart G",
"variant": VARIANT_ESP32C3,
},
"deneyapkart": {
"name": "Deneyap Kart",
"variant": VARIANT_ESP32,
},
"deneyapmini": {
"name": "Deneyap Mini",
"variant": VARIANT_ESP32S2,
},
"denky32": {
"name": "Denky32 (WROOM32)",
"variant": VARIANT_ESP32,
},
"denky_d4": {
"name": "Denky D4 (PICO-V3-02)",
"variant": VARIANT_ESP32,
},
"dfrobot_beetle_esp32c3": {
"name": "DFRobot Beetle ESP32-C3",
"variant": VARIANT_ESP32C3,
},
"dfrobot_firebeetle2_esp32s3": {
"name": "DFRobot Firebeetle 2 ESP32-S3",
"variant": VARIANT_ESP32S3,
},
"dpu_esp32": {
"name": "TAMC DPU ESP32",
"variant": VARIANT_ESP32,
},
"esp320": {
"name": "Electronic SweetPeas ESP320",
"variant": VARIANT_ESP32,
},
"esp32-c3-devkitm-1": {
"name": "Espressif ESP32-C3-DevKitM-1",
"variant": VARIANT_ESP32C3,
},
"esp32cam": {
"name": "AI Thinker ESP32-CAM",
"variant": VARIANT_ESP32,
},
"esp32-devkitlipo": {
"name": "OLIMEX ESP32-DevKit-LiPo",
"variant": VARIANT_ESP32,
},
"esp32dev": {
"name": "Espressif ESP32 Dev Module",
"variant": VARIANT_ESP32,
},
"esp32doit-devkit-v1": {
"name": "DOIT ESP32 DEVKIT V1",
"variant": VARIANT_ESP32,
},
"esp32doit-espduino": {
"name": "DOIT ESPduino32",
"variant": VARIANT_ESP32,
},
"esp32-evb": {
"name": "OLIMEX ESP32-EVB",
"variant": VARIANT_ESP32,
},
"esp32-gateway": {
"name": "OLIMEX ESP32-GATEWAY",
"variant": VARIANT_ESP32,
},
"esp32-poe-iso": {
"name": "OLIMEX ESP32-PoE-ISO",
"variant": VARIANT_ESP32,
},
"esp32-poe": {
"name": "OLIMEX ESP32-PoE",
"variant": VARIANT_ESP32,
},
"esp32-pro": {
"name": "OLIMEX ESP32-PRO",
"variant": VARIANT_ESP32,
},
"esp32-s2-franzininho": {
"name": "Franzininho WiFi Board",
"variant": VARIANT_ESP32S2,
},
"esp32-s2-kaluga-1": {
"name": "Espressif ESP32-S2-Kaluga-1 Kit",
"variant": VARIANT_ESP32S2,
},
"esp32-s2-saola-1": {
"name": "Espressif ESP32-S2-Saola-1",
"variant": VARIANT_ESP32S2,
},
"esp32s3box": {
"name": "Espressif ESP32-S3-Box",
"variant": VARIANT_ESP32S3,
},
"esp32s3camlcd": {
"name": "ESP32S3 CAM LCD",
"variant": VARIANT_ESP32S3,
},
"esp32-s3-devkitc-1": {
"name": "Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)",
"variant": VARIANT_ESP32S3,
},
"esp32thing": {
"name": "SparkFun ESP32 Thing",
"variant": VARIANT_ESP32,
},
"esp32thing_plus": {
"name": "SparkFun ESP32 Thing Plus",
"variant": VARIANT_ESP32,
},
"esp32vn-iot-uno": {
"name": "ESP32vn IoT Uno",
"variant": VARIANT_ESP32,
},
"espea32": {
"name": "April Brother ESPea32",
"variant": VARIANT_ESP32,
},
"espectro32": {
"name": "ESPectro32",
"variant": VARIANT_ESP32,
},
"espino32": {
"name": "ESPino32",
"variant": VARIANT_ESP32,
},
"esp-wrover-kit": {
"name": "Espressif ESP-WROVER-KIT",
"variant": VARIANT_ESP32,
},
"etboard": {
"name": "ETBoard",
"variant": VARIANT_ESP32,
},
"featheresp32": {
"name": "Adafruit ESP32 Feather",
"variant": VARIANT_ESP32,
},
"featheresp32-s2": {
"name": "Adafruit ESP32-S2 Feather Development Board",
"variant": VARIANT_ESP32S2,
},
"firebeetle32": {
"name": "FireBeetle-ESP32",
"variant": VARIANT_ESP32,
},
"fm-devkit": {
"name": "ESP32 FM DevKit",
"variant": VARIANT_ESP32,
},
"franzininho_wifi_esp32s2": {
"name": "Franzininho WiFi",
"variant": VARIANT_ESP32S2,
},
"franzininho_wifi_msc_esp32s2": {
"name": "Franzininho WiFi MSC",
"variant": VARIANT_ESP32S2,
},
"frogboard": {
"name": "Frog Board ESP32",
"variant": VARIANT_ESP32,
},
"healthypi4": {
"name": "ProtoCentral HealthyPi 4",
"variant": VARIANT_ESP32,
},
"heltec_wifi_kit_32": {
"name": "Heltec WiFi Kit 32",
"variant": VARIANT_ESP32,
},
"heltec_wifi_kit_32_v2": {
"name": "Heltec WiFi Kit 32 (V2)",
"variant": VARIANT_ESP32,
},
"heltec_wifi_lora_32": {
"name": "Heltec WiFi LoRa 32",
"variant": VARIANT_ESP32,
},
"heltec_wifi_lora_32_V2": {
"name": "Heltec WiFi LoRa 32 (V2)",
"variant": VARIANT_ESP32,
},
"heltec_wireless_stick_lite": {
"name": "Heltec Wireless Stick Lite",
"variant": VARIANT_ESP32,
},
"heltec_wireless_stick": {
"name": "Heltec Wireless Stick",
"variant": VARIANT_ESP32,
},
"honeylemon": {
"name": "HONEYLemon",
"variant": VARIANT_ESP32,
},
"hornbill32dev": {
"name": "Hornbill ESP32 Dev",
"variant": VARIANT_ESP32,
},
"hornbill32minima": {
"name": "Hornbill ESP32 Minima",
"variant": VARIANT_ESP32,
},
"imbrios-logsens-v1p1": {
"name": "Imbrios LogSens V1P1",
"variant": VARIANT_ESP32,
},
"inex_openkb": {
"name": "INEX OpenKB",
"variant": VARIANT_ESP32,
},
"intorobot": {
"name": "IntoRobot Fig",
"variant": VARIANT_ESP32,
},
"iotaap_magnolia": {
"name": "IoTaaP Magnolia",
"variant": VARIANT_ESP32,
},
"iotbusio": {
"name": "oddWires IoT-Bus Io",
"variant": VARIANT_ESP32,
},
"iotbusproteus": {
"name": "oddWires IoT-Bus Proteus",
"variant": VARIANT_ESP32,
},
"kb32-ft": {
"name": "MakerAsia KB32-FT",
"variant": VARIANT_ESP32,
},
"kits-edu": {
"name": "KITS ESP32 EDU",
"variant": VARIANT_ESP32,
},
"labplus_mpython": {
"name": "Labplus mPython",
"variant": VARIANT_ESP32,
},
"lionbit": {
"name": "Lion:Bit Dev Board",
"variant": VARIANT_ESP32,
},
"lolin32_lite": {
"name": "WEMOS LOLIN32 Lite",
"variant": VARIANT_ESP32,
},
"lolin32": {
"name": "WEMOS LOLIN32",
"variant": VARIANT_ESP32,
},
"lolin_c3_mini": {
"name": "WEMOS LOLIN C3 Mini",
"variant": VARIANT_ESP32C3,
},
"lolin_d32": {
"name": "WEMOS LOLIN D32",
"variant": VARIANT_ESP32,
},
"lolin_d32_pro": {
"name": "WEMOS LOLIN D32 PRO",
"variant": VARIANT_ESP32,
},
"lolin_s2_mini": {
"name": "WEMOS LOLIN S2 Mini",
"variant": VARIANT_ESP32S2,
},
"lolin_s2_pico": {
"name": "WEMOS LOLIN S2 PICO",
"variant": VARIANT_ESP32S2,
},
"lolin_s3": {
"name": "WEMOS LOLIN S3",
"variant": VARIANT_ESP32S3,
},
"lopy4": {
"name": "Pycom LoPy4",
"variant": VARIANT_ESP32,
},
"lopy": {
"name": "Pycom LoPy",
"variant": VARIANT_ESP32,
},
"m5stack-atom": {
"name": "M5Stack-ATOM",
"variant": VARIANT_ESP32,
},
"m5stack-core2": {
"name": "M5Stack Core2",
"variant": VARIANT_ESP32,
},
"m5stack-core-esp32": {
"name": "M5Stack Core ESP32",
"variant": VARIANT_ESP32,
},
"m5stack-coreink": {
"name": "M5Stack-Core Ink",
"variant": VARIANT_ESP32,
},
"m5stack-fire": {
"name": "M5Stack FIRE",
"variant": VARIANT_ESP32,
},
"m5stack-grey": {
"name": "M5Stack GREY ESP32",
"variant": VARIANT_ESP32,
},
"m5stack-station": {
"name": "M5Stack Station",
"variant": VARIANT_ESP32,
},
"m5stack-timer-cam": {
"name": "M5Stack Timer CAM",
"variant": VARIANT_ESP32,
},
"m5stick-c": {
"name": "M5Stick-C",
"variant": VARIANT_ESP32,
},
"magicbit": {
"name": "MagicBit",
"variant": VARIANT_ESP32,
},
"mgbot-iotik32a": {
"name": "MGBOT IOTIK 32A",
"variant": VARIANT_ESP32,
},
"mgbot-iotik32b": {
"name": "MGBOT IOTIK 32B",
"variant": VARIANT_ESP32,
},
"mhetesp32devkit": {
"name": "MH ET LIVE ESP32DevKIT",
"variant": VARIANT_ESP32,
},
"mhetesp32minikit": {
"name": "MH ET LIVE ESP32MiniKit",
"variant": VARIANT_ESP32,
},
"microduino-core-esp32": {
"name": "Microduino Core ESP32",
"variant": VARIANT_ESP32,
},
"micros2": {
"name": "microS2",
"variant": VARIANT_ESP32S2,
},
"minimain_esp32s2": {
"name": "Deparment of Alchemy MiniMain ESP32-S2",
"variant": VARIANT_ESP32S2,
},
"nano32": {
"name": "MakerAsia Nano32",
"variant": VARIANT_ESP32,
},
"nina_w10": {
"name": "u-blox NINA-W10 series",
"variant": VARIANT_ESP32,
},
"node32s": {
"name": "Node32s",
"variant": VARIANT_ESP32,
},
"nodemcu-32s2": {
"name": "Ai-Thinker NodeMCU-32S2 (ESP-12K)",
"variant": VARIANT_ESP32S2,
},
"nodemcu-32s": {
"name": "NodeMCU-32S",
"variant": VARIANT_ESP32,
},
"nscreen-32": {
"name": "YeaCreate NSCREEN-32",
"variant": VARIANT_ESP32,
},
"odroid_esp32": {
"name": "ODROID-GO",
"variant": VARIANT_ESP32,
},
"onehorse32dev": {
"name": "Onehorse ESP32 Dev Module",
"variant": VARIANT_ESP32,
},
"oroca_edubot": {
"name": "OROCA EduBot",
"variant": VARIANT_ESP32,
},
"pico32": {
"name": "ESP32 Pico Kit",
"variant": VARIANT_ESP32,
},
"piranha_esp32": {
"name": "Fishino Piranha ESP-32",
"variant": VARIANT_ESP32,
},
"pocket_32": {
"name": "Dongsen Tech Pocket 32",
"variant": VARIANT_ESP32,
},
"pycom_gpy": {
"name": "Pycom GPy",
"variant": VARIANT_ESP32,
},
"qchip": {
"name": "Qchip",
"variant": VARIANT_ESP32,
},
"quantum": {
"name": "Noduino Quantum",
"variant": VARIANT_ESP32,
},
"seeed_xiao_esp32c3": {
"name": "Seeed Studio XIAO ESP32C3",
"variant": VARIANT_ESP32C3,
},
"sensesiot_weizen": {
"name": "LOGISENSES Senses Weizen",
"variant": VARIANT_ESP32,
},
"sg-o_airMon": {
"name": "SG-O AirMon",
"variant": VARIANT_ESP32,
},
"s_odi_ultra": {
"name": "S.ODI Ultra v1",
"variant": VARIANT_ESP32,
},
"sparkfun_esp32_iot_redboard": {
"name": "SparkFun ESP32 IoT RedBoard",
"variant": VARIANT_ESP32,
},
"sparkfun_esp32micromod": {
"name": "SparkFun ESP32 MicroMod",
"variant": VARIANT_ESP32,
},
"sparkfun_esp32s2_thing_plus_c": {
"name": "SparkFun ESP32 Thing Plus C",
"variant": VARIANT_ESP32,
},
"sparkfun_esp32s2_thing_plus": {
"name": "SparkFun ESP32-S2 Thing Plus",
"variant": VARIANT_ESP32S2,
},
"sparkfun_lora_gateway_1-channel": {
"name": "SparkFun LoRa Gateway 1-Channel",
"variant": VARIANT_ESP32,
},
"tamc_termod_s3": {
"name": "TAMC Termod S3",
"variant": VARIANT_ESP32S3,
},
"tinypico": {
"name": "Unexpected Maker TinyPICO",
"variant": VARIANT_ESP32,
},
"trueverit-iot-driver-mk2": {
"name": "Trueverit ESP32 Universal IoT Driver MK II",
"variant": VARIANT_ESP32,
},
"trueverit-iot-driver-mk3": {
"name": "Trueverit ESP32 Universal IoT Driver MK III",
"variant": VARIANT_ESP32,
},
"trueverit-iot-driver": {
"name": "Trueverit ESP32 Universal IoT Driver",
"variant": VARIANT_ESP32,
},
"ttgo-lora32-v1": {
"name": "TTGO LoRa32-OLED V1",
"variant": VARIANT_ESP32,
},
"ttgo-lora32-v21": {
"name": "TTGO LoRa32-OLED v2.1.6",
"variant": VARIANT_ESP32,
},
"ttgo-lora32-v2": {
"name": "TTGO LoRa32-OLED V2",
"variant": VARIANT_ESP32,
},
"ttgo-t1": {
"name": "TTGO T1",
"variant": VARIANT_ESP32,
},
"ttgo-t7-v13-mini32": {
"name": "TTGO T7 V1.3 Mini32",
"variant": VARIANT_ESP32,
},
"ttgo-t7-v14-mini32": {
"name": "TTGO T7 V1.4 Mini32",
"variant": VARIANT_ESP32,
},
"ttgo-t-beam": {
"name": "TTGO T-Beam",
"variant": VARIANT_ESP32,
},
"ttgo-t-oi-plus": {
"name": "TTGO T-OI PLUS RISC-V ESP32-C3",
"variant": VARIANT_ESP32C3,
},
"ttgo-t-watch": {
"name": "TTGO T-Watch",
"variant": VARIANT_ESP32,
},
"turta_iot_node": {
"name": "Turta IoT Node",
"variant": VARIANT_ESP32,
},
"um_feathers2": {
"name": "Unexpected Maker FeatherS2",
"variant": VARIANT_ESP32S2,
},
"um_feathers2_neo": {
"name": "Unexpected Maker FeatherS2 Neo",
"variant": VARIANT_ESP32S2,
},
"um_feathers3": {
"name": "Unexpected Maker FeatherS3",
"variant": VARIANT_ESP32S3,
},
"um_pros3": {
"name": "Unexpected Maker PROS3",
"variant": VARIANT_ESP32S3,
},
"um_rmp": {
"name": "Unexpected Maker RMP",
"variant": VARIANT_ESP32S2,
},
"um_tinys2": {
"name": "Unexpected Maker TinyS2",
"variant": VARIANT_ESP32S2,
},
"um_tinys3": {
"name": "Unexpected Maker TinyS3",
"variant": VARIANT_ESP32S3,
},
"unphone7": {
"name": "unPhone 7",
"variant": VARIANT_ESP32,
},
"unphone8": {
"name": "unPhone 8",
"variant": VARIANT_ESP32S3,
},
"unphone9": {
"name": "unPhone 9",
"variant": VARIANT_ESP32S3,
},
"upesy_wroom": {
"name": "uPesy ESP32 Wroom DevKit",
"variant": VARIANT_ESP32,
},
"upesy_wrover": {
"name": "uPesy ESP32 Wrover DevKit",
"variant": VARIANT_ESP32,
},
"vintlabs-devkit-v1": {
"name": "VintLabs ESP32 Devkit",
"variant": VARIANT_ESP32,
},
"watchy": {
"name": "SQFMI Watchy v2.0",
"variant": VARIANT_ESP32,
},
"wemosbat": {
"name": "WeMos WiFi and Bluetooth Battery",
"variant": VARIANT_ESP32,
},
"wemos_d1_mini32": {
"name": "WEMOS D1 MINI ESP32",
"variant": VARIANT_ESP32,
},
"wemos_d1_uno32": {
"name": "WEMOS D1 R32",
"variant": VARIANT_ESP32,
},
"wesp32": {
"name": "Silicognition wESP32",
"variant": VARIANT_ESP32,
},
"widora-air": {
"name": "Widora AIR",
"variant": VARIANT_ESP32,
},
"wifiduino32c3": {
"name": "Blinker WiFiduinoV2 (ESP32-C3)",
"variant": VARIANT_ESP32C3,
},
"wifiduino32": {
"name": "Blinker WiFiduino32",
"variant": VARIANT_ESP32,
},
"wifiduino32s3": {
"name": "Blinker WiFiduino32S3",
"variant": VARIANT_ESP32S3,
},
"wipy3": {
"name": "Pycom WiPy3",
"variant": VARIANT_ESP32,
},
"wt32-eth01": {
"name": "Wireless-Tag WT32-ETH01 Ethernet Module",
"variant": VARIANT_ESP32,
},
"xinabox_cw02": {
"name": "XinaBox CW02",
"variant": VARIANT_ESP32,
},
} }

View file

@ -1,6 +1,6 @@
#ifdef USE_ESP32_FRAMEWORK_ESP_IDF #ifdef USE_ESP32
#include "gpio_idf.h" #include "gpio.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {
@ -8,13 +8,11 @@ namespace esp32 {
static const char *const TAG = "esp32"; static const char *const TAG = "esp32";
bool IDFInternalGPIOPin::isr_service_installed = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) bool ESP32InternalGPIOPin::isr_service_installed = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static gpio_mode_t IRAM_ATTR flags_to_mode(gpio::Flags flags) { static gpio_mode_t IRAM_ATTR flags_to_mode(gpio::Flags flags) {
flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)); flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN));
if (flags == gpio::FLAG_NONE) { if (flags == gpio::FLAG_INPUT) {
return GPIO_MODE_DISABLE;
} else if (flags == gpio::FLAG_INPUT) {
return GPIO_MODE_INPUT; return GPIO_MODE_INPUT;
} else if (flags == gpio::FLAG_OUTPUT) { } else if (flags == gpio::FLAG_OUTPUT) {
return GPIO_MODE_OUTPUT; return GPIO_MODE_OUTPUT;
@ -25,7 +23,7 @@ static gpio_mode_t IRAM_ATTR flags_to_mode(gpio::Flags flags) {
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_OUTPUT)) { } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_OUTPUT)) {
return GPIO_MODE_INPUT_OUTPUT; return GPIO_MODE_INPUT_OUTPUT;
} else { } else {
// unsupported // unsupported or gpio::FLAG_NONE
return GPIO_MODE_DISABLE; return GPIO_MODE_DISABLE;
} }
} }
@ -35,14 +33,14 @@ struct ISRPinArg {
bool inverted; bool inverted;
}; };
ISRInternalGPIOPin IDFInternalGPIOPin::to_isr() const { ISRInternalGPIOPin ESP32InternalGPIOPin::to_isr() const {
auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory) auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
arg->pin = pin_; arg->pin = pin_;
arg->inverted = inverted_; arg->inverted = inverted_;
return ISRInternalGPIOPin((void *) arg); return ISRInternalGPIOPin((void *) arg);
} }
void IDFInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const { void ESP32InternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const {
gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE; gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE;
switch (type) { switch (type) {
case gpio::INTERRUPT_RISING_EDGE: case gpio::INTERRUPT_RISING_EDGE:
@ -74,13 +72,13 @@ void IDFInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio:
gpio_isr_handler_add(pin_, func, arg); gpio_isr_handler_add(pin_, func, arg);
} }
std::string IDFInternalGPIOPin::dump_summary() const { std::string ESP32InternalGPIOPin::dump_summary() const {
char buffer[32]; char buffer[32];
snprintf(buffer, sizeof(buffer), "GPIO%u", static_cast<uint32_t>(pin_)); snprintf(buffer, sizeof(buffer), "GPIO%u", static_cast<uint32_t>(pin_));
return buffer; return buffer;
} }
void IDFInternalGPIOPin::setup() { void ESP32InternalGPIOPin::setup() {
gpio_config_t conf{}; gpio_config_t conf{};
conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(pin_); conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(pin_);
conf.mode = flags_to_mode(flags_); conf.mode = flags_to_mode(flags_);
@ -88,10 +86,12 @@ void IDFInternalGPIOPin::setup() {
conf.pull_down_en = flags_ & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE; conf.pull_down_en = flags_ & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE;
conf.intr_type = GPIO_INTR_DISABLE; conf.intr_type = GPIO_INTR_DISABLE;
gpio_config(&conf); gpio_config(&conf);
gpio_set_drive_capability(pin_, drive_strength_); if (flags_ & gpio::FLAG_OUTPUT) {
gpio_set_drive_capability(pin_, drive_strength_);
}
} }
void IDFInternalGPIOPin::pin_mode(gpio::Flags flags) { void ESP32InternalGPIOPin::pin_mode(gpio::Flags flags) {
// can't call gpio_config here because that logs in esp-idf which may cause issues // can't call gpio_config here because that logs in esp-idf which may cause issues
gpio_set_direction(pin_, flags_to_mode(flags)); gpio_set_direction(pin_, flags_to_mode(flags));
gpio_pull_mode_t pull_mode = GPIO_FLOATING; gpio_pull_mode_t pull_mode = GPIO_FLOATING;
@ -105,9 +105,9 @@ void IDFInternalGPIOPin::pin_mode(gpio::Flags flags) {
gpio_set_pull_mode(pin_, pull_mode); gpio_set_pull_mode(pin_, pull_mode);
} }
bool IDFInternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; } bool ESP32InternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; }
void IDFInternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); } void ESP32InternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); }
void IDFInternalGPIOPin::detach_interrupt() const { gpio_intr_disable(pin_); } void ESP32InternalGPIOPin::detach_interrupt() const { gpio_intr_disable(pin_); }
} // namespace esp32 } // namespace esp32
@ -140,4 +140,4 @@ void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) {
} // namespace esphome } // namespace esphome
#endif // USE_ESP32_FRAMEWORK_ESP_IDF #endif // USE_ESP32

View file

@ -1,13 +1,13 @@
#pragma once #pragma once
#ifdef USE_ESP32_FRAMEWORK_ESP_IDF #ifdef USE_ESP32
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include <driver/gpio.h> #include <driver/gpio.h>
namespace esphome { namespace esphome {
namespace esp32 { namespace esp32 {
class IDFInternalGPIOPin : public InternalGPIOPin { class ESP32InternalGPIOPin : public InternalGPIOPin {
public: public:
void set_pin(gpio_num_t pin) { pin_ = pin; } void set_pin(gpio_num_t pin) { pin_ = pin; }
void set_inverted(bool inverted) { inverted_ = inverted; } void set_inverted(bool inverted) { inverted_ = inverted; }
@ -37,4 +37,4 @@ class IDFInternalGPIOPin : public InternalGPIOPin {
} // namespace esp32 } // namespace esp32
} // namespace esphome } // namespace esphome
#endif // USE_ESP32_FRAMEWORK_ESP_IDF #endif // USE_ESP32

View file

@ -38,8 +38,7 @@ from .gpio_esp32_s3 import esp32_s3_validate_gpio_pin, esp32_s3_validate_support
from .gpio_esp32_h2 import esp32_h2_validate_gpio_pin, esp32_h2_validate_supports from .gpio_esp32_h2 import esp32_h2_validate_gpio_pin, esp32_h2_validate_supports
IDFInternalGPIOPin = esp32_ns.class_("IDFInternalGPIOPin", cg.InternalGPIOPin) ESP32InternalGPIOPin = esp32_ns.class_("ESP32InternalGPIOPin", cg.InternalGPIOPin)
ArduinoInternalGPIOPin = esp32_ns.class_("ArduinoInternalGPIOPin", cg.InternalGPIOPin)
def _lookup_pin(value): def _lookup_pin(value):
@ -108,6 +107,10 @@ def validate_gpio_pin(value):
board = CORE.data[KEY_ESP32][KEY_BOARD] board = CORE.data[KEY_ESP32][KEY_BOARD]
board_pins = boards.ESP32_BOARD_PINS.get(board, {}) board_pins = boards.ESP32_BOARD_PINS.get(board, {})
# Resolved aliased board pins (shorthand when two boards have the same pin configuration)
while isinstance(board_pins, str):
board_pins = boards.ESP32_BOARD_PINS[board_pins]
if value in board_pins.values(): if value in board_pins.values():
return value return value
@ -169,18 +172,10 @@ DRIVE_STRENGTHS = {
gpio_num_t = cg.global_ns.enum("gpio_num_t") gpio_num_t = cg.global_ns.enum("gpio_num_t")
def _choose_pin_declaration(value):
if CORE.using_esp_idf:
return cv.declare_id(IDFInternalGPIOPin)(value)
if CORE.using_arduino:
return cv.declare_id(ArduinoInternalGPIOPin)(value)
raise NotImplementedError
CONF_DRIVE_STRENGTH = "drive_strength" CONF_DRIVE_STRENGTH = "drive_strength"
ESP32_PIN_SCHEMA = cv.All( ESP32_PIN_SCHEMA = cv.All(
{ {
cv.GenerateID(): _choose_pin_declaration, cv.GenerateID(): cv.declare_id(ESP32InternalGPIOPin),
cv.Required(CONF_NUMBER): validate_gpio_pin, cv.Required(CONF_NUMBER): validate_gpio_pin,
cv.Optional(CONF_MODE, default={}): cv.Schema( cv.Optional(CONF_MODE, default={}): cv.Schema(
{ {
@ -192,8 +187,7 @@ ESP32_PIN_SCHEMA = cv.All(
} }
), ),
cv.Optional(CONF_INVERTED, default=False): cv.boolean, cv.Optional(CONF_INVERTED, default=False): cv.boolean,
cv.SplitDefault(CONF_DRIVE_STRENGTH, esp32_idf="20mA"): cv.All( cv.Optional(CONF_DRIVE_STRENGTH, default="20mA"): cv.All(
cv.only_with_esp_idf,
cv.float_with_unit("current", "mA", optional_unit=True), cv.float_with_unit("current", "mA", optional_unit=True),
cv.enum(DRIVE_STRENGTHS), cv.enum(DRIVE_STRENGTHS),
), ),
@ -206,10 +200,7 @@ ESP32_PIN_SCHEMA = cv.All(
async def esp32_pin_to_code(config): async def esp32_pin_to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
num = config[CONF_NUMBER] num = config[CONF_NUMBER]
if CORE.using_esp_idf: cg.add(var.set_pin(getattr(gpio_num_t, f"GPIO_NUM_{num}")))
cg.add(var.set_pin(getattr(gpio_num_t, f"GPIO_NUM_{num}")))
else:
cg.add(var.set_pin(num))
cg.add(var.set_inverted(config[CONF_INVERTED])) cg.add(var.set_inverted(config[CONF_INVERTED]))
if CONF_DRIVE_STRENGTH in config: if CONF_DRIVE_STRENGTH in config:
cg.add(var.set_drive_strength(config[CONF_DRIVE_STRENGTH])) cg.add(var.set_drive_strength(config[CONF_DRIVE_STRENGTH]))

View file

@ -1,114 +0,0 @@
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
#include "gpio_arduino.h"
#include "esphome/core/log.h"
#include <esp32-hal-gpio.h>
namespace esphome {
namespace esp32 {
static const char *const TAG = "esp32";
static int IRAM_ATTR flags_to_mode(gpio::Flags flags) {
if (flags == gpio::FLAG_INPUT) {
return INPUT;
} else if (flags == gpio::FLAG_OUTPUT) {
return OUTPUT;
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) {
return INPUT_PULLUP;
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) {
return INPUT_PULLDOWN;
} else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
return OUTPUT_OPEN_DRAIN;
} else {
return 0;
}
}
struct ISRPinArg {
uint8_t pin;
bool inverted;
};
ISRInternalGPIOPin ArduinoInternalGPIOPin::to_isr() const {
auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
arg->pin = pin_;
arg->inverted = inverted_;
return ISRInternalGPIOPin((void *) arg);
}
void ArduinoInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const {
uint8_t arduino_mode = DISABLED;
switch (type) {
case gpio::INTERRUPT_RISING_EDGE:
arduino_mode = inverted_ ? FALLING : RISING;
break;
case gpio::INTERRUPT_FALLING_EDGE:
arduino_mode = inverted_ ? RISING : FALLING;
break;
case gpio::INTERRUPT_ANY_EDGE:
arduino_mode = CHANGE;
break;
case gpio::INTERRUPT_LOW_LEVEL:
arduino_mode = inverted_ ? ONHIGH : ONLOW;
break;
case gpio::INTERRUPT_HIGH_LEVEL:
arduino_mode = inverted_ ? ONLOW : ONHIGH;
break;
}
attachInterruptArg(pin_, func, arg, arduino_mode);
}
void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) {
pinMode(pin_, flags_to_mode(flags)); // NOLINT
}
std::string ArduinoInternalGPIOPin::dump_summary() const {
char buffer[32];
snprintf(buffer, sizeof(buffer), "GPIO%u", pin_);
return buffer;
}
bool ArduinoInternalGPIOPin::digital_read() {
return bool(digitalRead(pin_)) != inverted_; // NOLINT
}
void ArduinoInternalGPIOPin::digital_write(bool value) {
digitalWrite(pin_, value != inverted_ ? 1 : 0); // NOLINT
}
void ArduinoInternalGPIOPin::detach_interrupt() const {
detachInterrupt(pin_); // NOLINT
}
} // namespace esp32
using namespace esp32;
bool IRAM_ATTR ISRInternalGPIOPin::digital_read() {
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
return bool(digitalRead(arg->pin)) != arg->inverted; // NOLINT
}
void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) {
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
digitalWrite(arg->pin, value != arg->inverted ? 1 : 0); // NOLINT
}
void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() {
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
#ifdef CONFIG_IDF_TARGET_ESP32C3
GPIO.status_w1tc.val = 1UL << arg->pin;
#else
if (arg->pin < 32) {
GPIO.status_w1tc = 1UL << arg->pin;
} else {
GPIO.status1_w1tc.intr_st = 1UL << (arg->pin - 32);
}
#endif
}
void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) {
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
pinMode(arg->pin, flags_to_mode(flags)); // NOLINT
}
} // namespace esphome
#endif // USE_ESP32_FRAMEWORK_ARDUINO

View file

@ -1,36 +0,0 @@
#pragma once
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
#include "esphome/core/hal.h"
namespace esphome {
namespace esp32 {
class ArduinoInternalGPIOPin : public InternalGPIOPin {
public:
void set_pin(uint8_t pin) { pin_ = pin; }
void set_inverted(bool inverted) { inverted_ = inverted; }
void set_flags(gpio::Flags flags) { flags_ = flags; }
void setup() override { pin_mode(flags_); }
void pin_mode(gpio::Flags flags) override;
bool digital_read() override;
void digital_write(bool value) override;
std::string dump_summary() const override;
void detach_interrupt() const override;
ISRInternalGPIOPin to_isr() const override;
uint8_t get_pin() const override { return pin_; }
bool is_inverted() const override { return inverted_; }
protected:
void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override;
uint8_t pin_;
bool inverted_;
gpio::Flags flags_;
};
} // namespace esp32
} // namespace esphome
#endif // USE_ESP32_FRAMEWORK_ARDUINO

View file

@ -16,7 +16,15 @@ BLECharacteristic::~BLECharacteristic() {
delete desc; // NOLINT(cppcoreguidelines-owning-memory) delete desc; // NOLINT(cppcoreguidelines-owning-memory)
} }
void BLECharacteristic::release_descriptors() {
this->parsed = false;
for (auto &desc : this->descriptors)
delete desc; // NOLINT(cppcoreguidelines-owning-memory)
this->descriptors.clear();
}
void BLECharacteristic::parse_descriptors() { void BLECharacteristic::parse_descriptors() {
this->parsed = true;
uint16_t offset = 0; uint16_t offset = 0;
esp_gattc_descr_elem_t result; esp_gattc_descr_elem_t result;
@ -49,6 +57,8 @@ void BLECharacteristic::parse_descriptors() {
} }
BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) { BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) {
if (!this->parsed)
this->parse_descriptors();
for (auto &desc : this->descriptors) { for (auto &desc : this->descriptors) {
if (desc->uuid == uuid) if (desc->uuid == uuid)
return desc; return desc;
@ -59,6 +69,8 @@ BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) {
return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid)); return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid));
} }
BLEDescriptor *BLECharacteristic::get_descriptor_by_handle(uint16_t handle) { BLEDescriptor *BLECharacteristic::get_descriptor_by_handle(uint16_t handle) {
if (!this->parsed)
this->parse_descriptors();
for (auto &desc : this->descriptors) { for (auto &desc : this->descriptors) {
if (desc->handle == handle) if (desc->handle == handle)
return desc; return desc;

View file

@ -6,6 +6,8 @@
#include "ble_descriptor.h" #include "ble_descriptor.h"
#include <vector>
namespace esphome { namespace esphome {
namespace esp32_ble_client { namespace esp32_ble_client {
@ -16,11 +18,13 @@ class BLEService;
class BLECharacteristic { class BLECharacteristic {
public: public:
~BLECharacteristic(); ~BLECharacteristic();
bool parsed = false;
espbt::ESPBTUUID uuid; espbt::ESPBTUUID uuid;
uint16_t handle; uint16_t handle;
esp_gatt_char_prop_t properties; esp_gatt_char_prop_t properties;
std::vector<BLEDescriptor *> descriptors; std::vector<BLEDescriptor *> descriptors;
void parse_descriptors(); void parse_descriptors();
void release_descriptors();
BLEDescriptor *get_descriptor(espbt::ESPBTUUID uuid); BLEDescriptor *get_descriptor(espbt::ESPBTUUID uuid);
BLEDescriptor *get_descriptor(uint16_t uuid); BLEDescriptor *get_descriptor(uint16_t uuid);
BLEDescriptor *get_descriptor_by_handle(uint16_t handle); BLEDescriptor *get_descriptor_by_handle(uint16_t handle);

View file

@ -9,6 +9,13 @@ namespace esphome {
namespace esp32_ble_client { namespace esp32_ble_client {
static const char *const TAG = "esp32_ble_client"; static const char *const TAG = "esp32_ble_client";
static const esp_bt_uuid_t NOTIFY_DESC_UUID = {
.len = ESP_UUID_LEN_16,
.uuid =
{
.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG,
},
};
void BLEClientBase::setup() { void BLEClientBase::setup() {
static uint8_t connection_index = 0; static uint8_t connection_index = 0;
@ -23,7 +30,9 @@ void BLEClientBase::setup() {
} }
void BLEClientBase::loop() { void BLEClientBase::loop() {
if (this->state_ == espbt::ClientState::DISCOVERED) { // READY_TO_CONNECT means we have discovered the device
// and the scanner has been stopped by the tracker.
if (this->state_ == espbt::ClientState::READY_TO_CONNECT) {
this->connect(); this->connect();
} }
} }
@ -51,7 +60,8 @@ bool BLEClientBase::parse_device(const espbt::ESPBTDevice &device) {
} }
void BLEClientBase::connect() { void BLEClientBase::connect() {
ESP_LOGI(TAG, "[%d] [%s] Attempting BLE connection", this->connection_index_, this->address_str_.c_str()); ESP_LOGI(TAG, "[%d] [%s] 0x%02x Attempting BLE connection", this->connection_index_, this->address_str_.c_str(),
this->remote_addr_type_);
auto ret = esp_ble_gattc_open(this->gattc_if_, this->remote_bda_, this->remote_addr_type_, true); auto ret = esp_ble_gattc_open(this->gattc_if_, this->remote_bda_, this->remote_addr_type_, true);
if (ret) { if (ret) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_open error, status=%d", this->connection_index_, this->address_str_.c_str(), ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_open error, status=%d", this->connection_index_, this->address_str_.c_str(),
@ -63,6 +73,8 @@ void BLEClientBase::connect() {
} }
void BLEClientBase::disconnect() { void BLEClientBase::disconnect() {
if (this->state_ == espbt::ClientState::IDLE || this->state_ == espbt::ClientState::DISCONNECTING)
return;
ESP_LOGI(TAG, "[%d] [%s] Disconnecting.", this->connection_index_, this->address_str_.c_str()); ESP_LOGI(TAG, "[%d] [%s] Disconnecting.", this->connection_index_, this->address_str_.c_str());
auto err = esp_ble_gattc_close(this->gattc_if_, this->conn_id_); auto err = esp_ble_gattc_close(this->gattc_if_, this->conn_id_);
if (err != ESP_OK) { if (err != ESP_OK) {
@ -70,12 +82,22 @@ void BLEClientBase::disconnect() {
err); err);
} }
if (this->state_ == espbt::ClientState::SEARCHING) { if (this->state_ == espbt::ClientState::SEARCHING || this->state_ == espbt::ClientState::READY_TO_CONNECT ||
this->state_ == espbt::ClientState::DISCOVERED) {
this->set_address(0); this->set_address(0);
this->set_state(espbt::ClientState::IDLE); this->set_state(espbt::ClientState::IDLE);
} else {
this->set_state(espbt::ClientState::DISCONNECTING);
} }
} }
void BLEClientBase::release_services() {
for (auto &svc : this->services_)
delete svc; // NOLINT(cppcoreguidelines-owning-memory)
this->services_.clear();
esp_ble_gattc_cache_clean(this->remote_bda_);
}
bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_if, bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_if,
esp_ble_gattc_cb_param_t *param) { esp_ble_gattc_cb_param_t *param) {
if (event == ESP_GATTC_REG_EVT && this->app_id != param->reg.app_id) if (event == ESP_GATTC_REG_EVT && this->app_id != param->reg.app_id)
@ -101,17 +123,24 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
case ESP_GATTC_OPEN_EVT: { case ESP_GATTC_OPEN_EVT: {
ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_OPEN_EVT", this->connection_index_, this->address_str_.c_str()); ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_OPEN_EVT", this->connection_index_, this->address_str_.c_str());
this->conn_id_ = param->open.conn_id; this->conn_id_ = param->open.conn_id;
this->service_count_ = 0;
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) { if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
ESP_LOGW(TAG, "[%d] [%s] Connection failed, status=%d", this->connection_index_, this->address_str_.c_str(), ESP_LOGW(TAG, "[%d] [%s] Connection failed, status=%d", this->connection_index_, this->address_str_.c_str(),
param->open.status); param->open.status);
this->set_state(espbt::ClientState::IDLE); this->set_state(espbt::ClientState::IDLE);
break; break;
} }
if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
this->set_state(espbt::ClientState::CONNECTED);
this->state_ = espbt::ClientState::ESTABLISHED;
break;
}
auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if_, param->open.conn_id); auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if_, param->open.conn_id);
if (ret) { if (ret) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_send_mtu_req failed, status=%x", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_send_mtu_req failed, status=%x", this->connection_index_,
this->address_str_.c_str(), ret); this->address_str_.c_str(), ret);
} }
esp_ble_gattc_search_service(esp_gattc_if, param->cfg_mtu.conn_id, nullptr);
break; break;
} }
case ESP_GATTC_CFG_MTU_EVT: { case ESP_GATTC_CFG_MTU_EVT: {
@ -124,7 +153,6 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
ESP_LOGV(TAG, "[%d] [%s] cfg_mtu status %d, mtu %d", this->connection_index_, this->address_str_.c_str(), ESP_LOGV(TAG, "[%d] [%s] cfg_mtu status %d, mtu %d", this->connection_index_, this->address_str_.c_str(),
param->cfg_mtu.status, param->cfg_mtu.mtu); param->cfg_mtu.status, param->cfg_mtu.mtu);
this->mtu_ = param->cfg_mtu.mtu; this->mtu_ = param->cfg_mtu.mtu;
esp_ble_gattc_search_service(esp_gattc_if, param->cfg_mtu.conn_id, nullptr);
break; break;
} }
case ESP_GATTC_DISCONNECT_EVT: { case ESP_GATTC_DISCONNECT_EVT: {
@ -132,13 +160,17 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
return false; return false;
ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_DISCONNECT_EVT, reason %d", this->connection_index_, ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_DISCONNECT_EVT, reason %d", this->connection_index_,
this->address_str_.c_str(), param->disconnect.reason); this->address_str_.c_str(), param->disconnect.reason);
for (auto &svc : this->services_) this->release_services();
delete svc; // NOLINT(cppcoreguidelines-owning-memory)
this->services_.clear();
this->set_state(espbt::ClientState::IDLE); this->set_state(espbt::ClientState::IDLE);
break; break;
} }
case ESP_GATTC_SEARCH_RES_EVT: { case ESP_GATTC_SEARCH_RES_EVT: {
this->service_count_++;
if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
// V3 clients don't need services initialized since
// they only request by handle after receiving the services.
break;
}
BLEService *ble_service = new BLEService(); // NOLINT(cppcoreguidelines-owning-memory) BLEService *ble_service = new BLEService(); // NOLINT(cppcoreguidelines-owning-memory)
ble_service->uuid = espbt::ESPBTUUID::from_uuid(param->search_res.srvc_id.uuid); ble_service->uuid = espbt::ESPBTUUID::from_uuid(param->search_res.srvc_id.uuid);
ble_service->start_handle = param->search_res.start_handle; ble_service->start_handle = param->search_res.start_handle;
@ -150,27 +182,49 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
case ESP_GATTC_SEARCH_CMPL_EVT: { case ESP_GATTC_SEARCH_CMPL_EVT: {
ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_SEARCH_CMPL_EVT", this->connection_index_, this->address_str_.c_str()); ESP_LOGV(TAG, "[%d] [%s] ESP_GATTC_SEARCH_CMPL_EVT", this->connection_index_, this->address_str_.c_str());
for (auto &svc : this->services_) { for (auto &svc : this->services_) {
ESP_LOGI(TAG, "[%d] [%s] Service UUID: %s", this->connection_index_, this->address_str_.c_str(), ESP_LOGV(TAG, "[%d] [%s] Service UUID: %s", this->connection_index_, this->address_str_.c_str(),
svc->uuid.to_string().c_str()); svc->uuid.to_string().c_str());
ESP_LOGI(TAG, "[%d] [%s] start_handle: 0x%x end_handle: 0x%x", this->connection_index_, ESP_LOGV(TAG, "[%d] [%s] start_handle: 0x%x end_handle: 0x%x", this->connection_index_,
this->address_str_.c_str(), svc->start_handle, svc->end_handle); this->address_str_.c_str(), svc->start_handle, svc->end_handle);
svc->parse_characteristics();
} }
this->set_state(espbt::ClientState::CONNECTED); this->set_state(espbt::ClientState::CONNECTED);
this->state_ = espbt::ClientState::ESTABLISHED; this->state_ = espbt::ClientState::ESTABLISHED;
break; break;
} }
case ESP_GATTC_REG_FOR_NOTIFY_EVT: { case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
auto *descr = this->get_config_descriptor(param->reg_for_notify.handle); if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
if (descr->uuid.get_uuid().len != ESP_UUID_LEN_16 || this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
descr->uuid.get_uuid().uuid.uuid16 != ESP_GATT_UUID_CHAR_CLIENT_CONFIG) { // Client is responsible for flipping the descriptor value
ESP_LOGW(TAG, "[%d] [%s] Handle 0x%x (uuid %s) is not a client config char uuid", this->connection_index_, // when using the cache
this->address_str_.c_str(), param->reg_for_notify.handle, descr->uuid.to_string().c_str());
break; break;
} }
uint16_t notify_en = 1; esp_gattc_descr_elem_t desc_result;
auto status = uint16_t count = 1;
esp_ble_gattc_write_char_descr(this->gattc_if_, this->conn_id_, descr->handle, sizeof(notify_en), esp_gatt_status_t descr_status =
esp_ble_gattc_get_descr_by_char_handle(this->gattc_if_, this->connection_index_, param->reg_for_notify.handle,
NOTIFY_DESC_UUID, &desc_result, &count);
if (descr_status != ESP_GATT_OK) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_get_descr_by_char_handle error, status=%d", this->connection_index_,
this->address_str_.c_str(), descr_status);
break;
}
esp_gattc_char_elem_t char_result;
esp_gatt_status_t char_status =
esp_ble_gattc_get_all_char(this->gattc_if_, this->connection_index_, param->reg_for_notify.handle,
param->reg_for_notify.handle, &char_result, &count, 0);
if (char_status != ESP_GATT_OK) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_get_all_char error, status=%d", this->connection_index_,
this->address_str_.c_str(), char_status);
break;
}
/*
1 = notify
2 = indicate
*/
uint16_t notify_en = char_result.properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY ? 1 : 2;
esp_err_t status =
esp_ble_gattc_write_char_descr(this->gattc_if_, this->conn_id_, desc_result.handle, sizeof(notify_en),
(uint8_t *) &notify_en, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE); (uint8_t *) &notify_en, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) { if (status) {
ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char_descr error, status=%d", this->connection_index_, ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char_descr error, status=%d", this->connection_index_,
@ -287,6 +341,8 @@ BLECharacteristic *BLEClientBase::get_characteristic(uint16_t service, uint16_t
BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) { BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) {
for (auto *svc : this->services_) { for (auto *svc : this->services_) {
if (!svc->parsed)
svc->parse_characteristics();
for (auto *chr : svc->characteristics) { for (auto *chr : svc->characteristics) {
if (chr->handle == handle) if (chr->handle == handle)
return chr; return chr;
@ -298,8 +354,10 @@ BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) {
BLEDescriptor *BLEClientBase::get_config_descriptor(uint16_t handle) { BLEDescriptor *BLEClientBase::get_config_descriptor(uint16_t handle) {
auto *chr = this->get_characteristic(handle); auto *chr = this->get_characteristic(handle);
if (chr != nullptr) { if (chr != nullptr) {
if (!chr->parsed)
chr->parse_descriptors();
for (auto &desc : chr->descriptors) { for (auto &desc : chr->descriptors) {
if (desc->uuid == espbt::ESPBTUUID::from_uint16(0x2902)) if (desc->uuid.get_uuid().uuid.uuid16 == ESP_GATT_UUID_CHAR_CLIENT_CONFIG)
return desc; return desc;
} }
} }
@ -323,7 +381,11 @@ BLEDescriptor *BLEClientBase::get_descriptor(uint16_t service, uint16_t chr, uin
BLEDescriptor *BLEClientBase::get_descriptor(uint16_t handle) { BLEDescriptor *BLEClientBase::get_descriptor(uint16_t handle) {
for (auto *svc : this->services_) { for (auto *svc : this->services_) {
if (!svc->parsed)
svc->parse_characteristics();
for (auto *chr : svc->characteristics) { for (auto *chr : svc->characteristics) {
if (!chr->parsed)
chr->parse_descriptors();
for (auto *desc : chr->descriptors) { for (auto *desc : chr->descriptors) {
if (desc->handle == handle) if (desc->handle == handle)
return desc; return desc;

View file

@ -9,6 +9,7 @@
#include <array> #include <array>
#include <string> #include <string>
#include <vector>
#include <esp_bt_defs.h> #include <esp_bt_defs.h>
#include <esp_gap_ble_api.h> #include <esp_gap_ble_api.h>
@ -33,6 +34,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
void connect() override; void connect() override;
void disconnect(); void disconnect();
void release_services();
bool connected() { return this->state_ == espbt::ClientState::ESTABLISHED; } bool connected() { return this->state_ == espbt::ClientState::ESTABLISHED; }
@ -42,7 +44,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
memset(this->remote_bda_, 0, sizeof(this->remote_bda_)); memset(this->remote_bda_, 0, sizeof(this->remote_bda_));
this->address_str_ = ""; this->address_str_ = "";
} else { } else {
this->address_str_ = str_snprintf("%02x:%02x:%02x:%02x:%02x:%02x", 17, (uint8_t)(this->address_ >> 40) & 0xff, this->address_str_ = str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t)(this->address_ >> 40) & 0xff,
(uint8_t)(this->address_ >> 32) & 0xff, (uint8_t)(this->address_ >> 24) & 0xff, (uint8_t)(this->address_ >> 32) & 0xff, (uint8_t)(this->address_ >> 24) & 0xff,
(uint8_t)(this->address_ >> 16) & 0xff, (uint8_t)(this->address_ >> 8) & 0xff, (uint8_t)(this->address_ >> 16) & 0xff, (uint8_t)(this->address_ >> 8) & 0xff,
(uint8_t)(this->address_ >> 0) & 0xff); (uint8_t)(this->address_ >> 0) & 0xff);
@ -66,11 +68,14 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
int get_gattc_if() const { return this->gattc_if_; } int get_gattc_if() const { return this->gattc_if_; }
uint8_t *get_remote_bda() { return this->remote_bda_; } uint8_t *get_remote_bda() { return this->remote_bda_; }
esp_ble_addr_type_t get_remote_addr_type() const { return this->remote_addr_type_; } esp_ble_addr_type_t get_remote_addr_type() const { return this->remote_addr_type_; }
void set_remote_addr_type(esp_ble_addr_type_t address_type) { this->remote_addr_type_ = address_type; }
uint16_t get_conn_id() const { return this->conn_id_; } uint16_t get_conn_id() const { return this->conn_id_; }
uint64_t get_address() const { return this->address_; } uint64_t get_address() const { return this->address_; }
uint8_t get_connection_index() const { return this->connection_index_; } uint8_t get_connection_index() const { return this->connection_index_; }
virtual void set_connection_type(espbt::ConnectionType ct) { this->connection_type_ = ct; }
protected: protected:
int gattc_if_; int gattc_if_;
esp_bd_addr_t remote_bda_; esp_bd_addr_t remote_bda_;
@ -79,7 +84,9 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
uint64_t address_{0}; uint64_t address_{0};
std::string address_str_{}; std::string address_str_{};
uint8_t connection_index_; uint8_t connection_index_;
int16_t service_count_{0};
uint16_t mtu_{23}; uint16_t mtu_{23};
espbt::ConnectionType connection_type_{espbt::ConnectionType::V1};
std::vector<BLEService *> services_; std::vector<BLEService *> services_;
}; };

View file

@ -11,6 +11,8 @@ namespace esp32_ble_client {
static const char *const TAG = "esp32_ble_client"; static const char *const TAG = "esp32_ble_client";
BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) { BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) {
if (!this->parsed)
this->parse_characteristics();
for (auto &chr : this->characteristics) { for (auto &chr : this->characteristics) {
if (chr->uuid == uuid) if (chr->uuid == uuid)
return chr; return chr;
@ -27,7 +29,15 @@ BLEService::~BLEService() {
delete chr; // NOLINT(cppcoreguidelines-owning-memory) delete chr; // NOLINT(cppcoreguidelines-owning-memory)
} }
void BLEService::release_characteristics() {
this->parsed = false;
for (auto &chr : this->characteristics)
delete chr; // NOLINT(cppcoreguidelines-owning-memory)
this->characteristics.clear();
}
void BLEService::parse_characteristics() { void BLEService::parse_characteristics() {
this->parsed = true;
uint16_t offset = 0; uint16_t offset = 0;
esp_gattc_char_elem_t result; esp_gattc_char_elem_t result;
@ -54,10 +64,9 @@ void BLEService::parse_characteristics() {
characteristic->handle = result.char_handle; characteristic->handle = result.char_handle;
characteristic->service = this; characteristic->service = this;
this->characteristics.push_back(characteristic); this->characteristics.push_back(characteristic);
ESP_LOGI(TAG, "[%d] [%s] characteristic %s, handle 0x%x, properties 0x%x", this->client->get_connection_index(), ESP_LOGV(TAG, "[%d] [%s] characteristic %s, handle 0x%x, properties 0x%x", this->client->get_connection_index(),
this->client->address_str().c_str(), characteristic->uuid.to_string().c_str(), characteristic->handle, this->client->address_str().c_str(), characteristic->uuid.to_string().c_str(), characteristic->handle,
characteristic->properties); characteristic->properties);
characteristic->parse_descriptors();
offset++; offset++;
} }
} }

View file

@ -6,6 +6,8 @@
#include "ble_characteristic.h" #include "ble_characteristic.h"
#include <vector>
namespace esphome { namespace esphome {
namespace esp32_ble_client { namespace esp32_ble_client {
@ -16,12 +18,14 @@ class BLEClientBase;
class BLEService { class BLEService {
public: public:
~BLEService(); ~BLEService();
bool parsed = false;
espbt::ESPBTUUID uuid; espbt::ESPBTUUID uuid;
uint16_t start_handle; uint16_t start_handle;
uint16_t end_handle; uint16_t end_handle;
std::vector<BLECharacteristic *> characteristics; std::vector<BLECharacteristic *> characteristics;
BLEClientBase *client; BLEClientBase *client;
void parse_characteristics(); void parse_characteristics();
void release_characteristics();
BLECharacteristic *get_characteristic(espbt::ESPBTUUID uuid); BLECharacteristic *get_characteristic(espbt::ESPBTUUID uuid);
BLECharacteristic *get_characteristic(uint16_t uuid); BLECharacteristic *get_characteristic(uint16_t uuid);
}; };

View file

@ -12,6 +12,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <vector>
#ifdef USE_ESP32 #ifdef USE_ESP32

View file

@ -3,6 +3,8 @@
#include "ble_characteristic.h" #include "ble_characteristic.h"
#include "esphome/components/esp32_ble/ble_uuid.h" #include "esphome/components/esp32_ble/ble_uuid.h"
#include <vector>
#ifdef USE_ESP32 #ifdef USE_ESP32
#include <esp_gap_ble_api.h> #include <esp_gap_ble_api.h>

View file

@ -238,6 +238,11 @@ async def to_code(config):
if CORE.using_esp_idf: if CORE.using_esp_idf:
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
# https://github.com/espressif/esp-idf/issues/4101
# https://github.com/espressif/esp-idf/issues/2503
# Match arduino CONFIG_BTU_TASK_STACK_SIZE
# https://github.com/espressif/arduino-esp32/blob/fd72cf46ad6fc1a6de99c1d83ba8eba17d80a4ee/tools/sdk/esp32/sdkconfig#L1866
add_idf_sdkconfig_option("CONFIG_BTU_TASK_STACK_SIZE", 8192)
cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts

View file

@ -66,7 +66,11 @@ void ESP32BLETracker::setup() {
#endif #endif
if (this->scan_continuous_) { if (this->scan_continuous_) {
this->start_scan_(true); if (xSemaphoreTake(this->scan_end_lock_, 0L)) {
this->start_scan_(true);
} else {
ESP_LOGW(TAG, "Cannot start scan!");
}
} }
} }
@ -83,86 +87,144 @@ void ESP32BLETracker::loop() {
ble_event = this->ble_events_.pop(); ble_event = this->ble_events_.pop();
} }
if (this->scanner_idle_) { int connecting = 0;
return; int discovered = 0;
} int searching = 0;
int disconnecting = 0;
bool connecting = false;
for (auto *client : this->clients_) { for (auto *client : this->clients_) {
if (client->state() == ClientState::CONNECTING || client->state() == ClientState::DISCOVERED) switch (client->state()) {
connecting = true; case ClientState::DISCONNECTING:
} disconnecting++;
break;
if (!connecting && xSemaphoreTake(this->scan_end_lock_, 0L)) { case ClientState::DISCOVERED:
xSemaphoreGive(this->scan_end_lock_); discovered++;
if (this->scan_continuous_) { break;
this->start_scan_(false); case ClientState::SEARCHING:
} else if (xSemaphoreTake(this->scan_end_lock_, 0L) && !this->scanner_idle_) { searching++;
xSemaphoreGive(this->scan_end_lock_); break;
this->end_of_scan_(); case ClientState::CONNECTING:
return; case ClientState::READY_TO_CONNECT:
connecting++;
break;
default:
break;
} }
} }
bool promote_to_connecting = discovered && !searching && !connecting;
if (xSemaphoreTake(this->scan_result_lock_, 5L / portTICK_PERIOD_MS)) { if (!this->scanner_idle_) {
uint32_t index = this->scan_result_index_; if (this->scan_result_index_ && // if it looks like we have a scan result we will take the lock
xSemaphoreGive(this->scan_result_lock_); xSemaphoreTake(this->scan_result_lock_, 5L / portTICK_PERIOD_MS)) {
uint32_t index = this->scan_result_index_;
if (index) {
if (index >= 16) {
ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up.");
}
for (size_t i = 0; i < index; i++) {
ESPBTDevice device;
device.parse_scan_rst(this->scan_result_buffer_[i]);
if (index >= 16) { bool found = false;
ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up."); for (auto *listener : this->listeners_) {
} if (listener->parse_device(device))
for (size_t i = 0; i < index; i++) { found = true;
ESPBTDevice device; }
device.parse_scan_rst(this->scan_result_buffer_[i]);
bool found = false; for (auto *client : this->clients_) {
for (auto *listener : this->listeners_) { if (client->parse_device(device)) {
if (listener->parse_device(device)) found = true;
found = true; if (!connecting && client->state() == ClientState::DISCOVERED) {
} promote_to_connecting = true;
}
for (auto *client : this->clients_) {
if (client->parse_device(device)) {
found = true;
if (client->state() == ClientState::DISCOVERED) {
esp_ble_gap_stop_scanning();
#ifdef USE_ARDUINO
constexpr TickType_t block_time = 10L / portTICK_PERIOD_MS;
#else
constexpr TickType_t block_time = 0L; // PR #3594
#endif
if (xSemaphoreTake(this->scan_end_lock_, block_time)) {
xSemaphoreGive(this->scan_end_lock_);
} }
} }
if (!found && !this->scan_continuous_) {
this->print_bt_device_info(device);
}
} }
this->scan_result_index_ = 0;
} }
if (!found) {
this->print_bt_device_info(device);
}
}
if (xSemaphoreTake(this->scan_result_lock_, 10L / portTICK_PERIOD_MS)) {
this->scan_result_index_ = 0;
xSemaphoreGive(this->scan_result_lock_); xSemaphoreGive(this->scan_result_lock_);
} }
/*
Avoid starting the scanner if:
- we are already scanning
- we are connecting to a device
- we are disconnecting from a device
Otherwise the scanner could fail to ever start again
and our only way to recover is to reboot.
https://github.com/espressif/esp-idf/issues/6688
*/
if (!connecting && !disconnecting && xSemaphoreTake(this->scan_end_lock_, 0L)) {
if (this->scan_continuous_) {
if (!promote_to_connecting && !this->scan_start_failed_ && !this->scan_set_param_failed_) {
this->start_scan_(false);
} else {
// We didn't start the scan, so we need to release the lock
xSemaphoreGive(this->scan_end_lock_);
}
} else if (!this->scanner_idle_) {
this->end_of_scan_();
return;
}
}
if (this->scan_start_failed_ || this->scan_set_param_failed_) {
if (this->scan_start_fail_count_ == 255) {
ESP_LOGE(TAG, "ESP-IDF BLE scan could not restart after 255 attempts, rebooting to restore BLE stack...");
App.reboot();
}
if (xSemaphoreTake(this->scan_end_lock_, 0L)) {
xSemaphoreGive(this->scan_end_lock_);
} else {
ESP_LOGD(TAG, "Stopping scan after failure...");
esp_ble_gap_stop_scanning();
this->cancel_timeout("scan");
}
if (this->scan_start_failed_) {
ESP_LOGE(TAG, "Scan start failed: %d", this->scan_start_failed_);
this->scan_start_failed_ = ESP_BT_STATUS_SUCCESS;
}
if (this->scan_set_param_failed_) {
ESP_LOGE(TAG, "Scan set param failed: %d", this->scan_set_param_failed_);
this->scan_set_param_failed_ = ESP_BT_STATUS_SUCCESS;
}
}
} }
if (this->scan_set_param_failed_) { // If there is a discovered client and no connecting
ESP_LOGE(TAG, "Scan set param failed: %d", this->scan_set_param_failed_); // clients and no clients using the scanner to search for
this->scan_set_param_failed_ = ESP_BT_STATUS_SUCCESS; // devices, then stop scanning and promote the discovered
} // client to ready to connect.
if (promote_to_connecting) {
if (this->scan_start_failed_) { for (auto *client : this->clients_) {
ESP_LOGE(TAG, "Scan start failed: %d", this->scan_start_failed_); if (client->state() == ClientState::DISCOVERED) {
this->scan_start_failed_ = ESP_BT_STATUS_SUCCESS; if (xSemaphoreTake(this->scan_end_lock_, 0L)) {
// Scanner is not running since we got the
// lock, so we can promote the client.
xSemaphoreGive(this->scan_end_lock_);
// We only want to promote one client at a time.
// once the scanner is fully stopped.
client->set_state(ClientState::READY_TO_CONNECT);
} else {
ESP_LOGD(TAG, "Pausing scan to make connection...");
esp_ble_gap_stop_scanning();
this->cancel_timeout("scan");
}
break;
}
}
} }
} }
void ESP32BLETracker::start_scan() { void ESP32BLETracker::start_scan() {
if (xSemaphoreTake(this->scan_end_lock_, 0L)) { if (xSemaphoreTake(this->scan_end_lock_, 0L)) {
xSemaphoreGive(this->scan_end_lock_);
this->start_scan_(true); this->start_scan_(true);
} else { } else {
ESP_LOGW(TAG, "Scan requested when a scan is already in progress. Ignoring."); ESP_LOGW(TAG, "Scan requested when a scan is already in progress. Ignoring.");
@ -256,8 +318,9 @@ bool ESP32BLETracker::ble_setup() {
} }
void ESP32BLETracker::start_scan_(bool first) { void ESP32BLETracker::start_scan_(bool first) {
if (!xSemaphoreTake(this->scan_end_lock_, 0L)) { // The lock must be held when calling this function.
ESP_LOGW(TAG, "Cannot start scan!"); if (xSemaphoreTake(this->scan_end_lock_, 0L)) {
ESP_LOGE(TAG, "start_scan called without holding scan_end_lock_");
return; return;
} }
@ -278,14 +341,15 @@ void ESP32BLETracker::start_scan_(bool first) {
esp_ble_gap_start_scanning(this->scan_duration_); esp_ble_gap_start_scanning(this->scan_duration_);
this->set_timeout("scan", this->scan_duration_ * 2000, []() { this->set_timeout("scan", this->scan_duration_ * 2000, []() {
ESP_LOGW(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack..."); ESP_LOGE(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack...");
App.reboot(); App.reboot();
}); });
} }
void ESP32BLETracker::end_of_scan_() { void ESP32BLETracker::end_of_scan_() {
if (!xSemaphoreTake(this->scan_end_lock_, 0L)) { // The lock must be held when calling this function.
ESP_LOGW(TAG, "Cannot clean up end of scan!"); if (xSemaphoreTake(this->scan_end_lock_, 0L)) {
ESP_LOGE(TAG, "end_of_scan_ called without holding the scan_end_lock_");
return; return;
} }
@ -337,6 +401,12 @@ void ESP32BLETracker::gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t:
void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param &param) { void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param &param) {
this->scan_start_failed_ = param.status; this->scan_start_failed_ = param.status;
if (param.status == ESP_BT_STATUS_SUCCESS) {
this->scan_start_fail_count_ = 0;
} else {
this->scan_start_fail_count_++;
xSemaphoreGive(this->scan_end_lock_);
}
} }
void ESP32BLETracker::gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param &param) { void ESP32BLETracker::gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param &param) {
@ -449,10 +519,13 @@ ESPBTUUID ESPBTUUID::from_raw(const std::string &data) {
ESPBTUUID ESPBTUUID::from_uuid(esp_bt_uuid_t uuid) { ESPBTUUID ESPBTUUID::from_uuid(esp_bt_uuid_t uuid) {
ESPBTUUID ret; ESPBTUUID ret;
ret.uuid_.len = uuid.len; ret.uuid_.len = uuid.len;
ret.uuid_.uuid.uuid16 = uuid.uuid.uuid16; if (uuid.len == ESP_UUID_LEN_16) {
ret.uuid_.uuid.uuid32 = uuid.uuid.uuid32; ret.uuid_.uuid.uuid16 = uuid.uuid.uuid16;
for (size_t i = 0; i < ESP_UUID_LEN_128; i++) } else if (uuid.len == ESP_UUID_LEN_32) {
ret.uuid_.uuid.uuid128[i] = uuid.uuid.uuid128[i]; ret.uuid_.uuid.uuid32 = uuid.uuid.uuid32;
} else if (uuid.len == ESP_UUID_LEN_128) {
memcpy(ret.uuid_.uuid.uuid128, uuid.uuid.uuid128, ESP_UUID_LEN_128);
}
return ret; return ret;
} }
ESPBTUUID ESPBTUUID::as_128bit() const { ESPBTUUID ESPBTUUID::as_128bit() const {
@ -774,6 +847,9 @@ void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_p
this->service_datas_.push_back(data); this->service_datas_.push_back(data);
break; break;
} }
case ESP_BLE_AD_TYPE_INT_RANGE:
// Avoid logging this as it's very verbose
break;
default: { default: {
ESP_LOGV(TAG, "Unhandled type: advType: 0x%02x", record_type); ESP_LOGV(TAG, "Unhandled type: advType: 0x%02x", record_type);
break; break;
@ -828,8 +904,9 @@ void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) {
} }
ESP_LOGD(TAG, " Address Type: %s", address_type_s); ESP_LOGD(TAG, " Address Type: %s", address_type_s);
if (!device.get_name().empty()) if (!device.get_name().empty()) {
ESP_LOGD(TAG, " Name: '%s'", device.get_name().c_str()); ESP_LOGD(TAG, " Name: '%s'", device.get_name().c_str());
}
for (auto &tx_power : device.get_tx_powers()) { for (auto &tx_power : device.get_tx_powers()) {
ESP_LOGD(TAG, " TX Power: %d", tx_power); ESP_LOGD(TAG, " TX Power: %d", tx_power);
} }

View file

@ -5,10 +5,12 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "queue.h" #include "queue.h"
#include <array>
#include <string>
#include <vector>
#ifdef USE_ESP32 #ifdef USE_ESP32
#include <string>
#include <array>
#include <esp_gap_ble_api.h> #include <esp_gap_ble_api.h>
#include <esp_gattc_api.h> #include <esp_gattc_api.h>
#include <esp_bt_defs.h> #include <esp_bt_defs.h>
@ -143,12 +145,18 @@ class ESPBTDeviceListener {
}; };
enum class ClientState { enum class ClientState {
// Connection is allocated
INIT,
// Client is disconnecting
DISCONNECTING,
// Connection is idle, no device detected. // Connection is idle, no device detected.
IDLE, IDLE,
// Searching for device. // Searching for device.
SEARCHING, SEARCHING,
// Device advertisement found. // Device advertisement found.
DISCOVERED, DISCOVERED,
// Device is discovered and the scanner is stopped
READY_TO_CONNECT,
// Connection in progress. // Connection in progress.
CONNECTING, CONNECTING,
// Initial connection established. // Initial connection established.
@ -157,6 +165,18 @@ enum class ClientState {
ESTABLISHED, ESTABLISHED,
}; };
enum class ConnectionType {
// The default connection type, we hold all the services in ram
// for the duration of the connection.
V1,
// The client has a cache of the services and mtu so we should not
// fetch them again
V3_WITH_CACHE,
// The client does not need the services and mtu once we send them
// so we should wipe them from memory as soon as we send them
V3_WITHOUT_CACHE
};
class ESPBTClient : public ESPBTDeviceListener { class ESPBTClient : public ESPBTDeviceListener {
public: public:
virtual bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, virtual bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
@ -233,6 +253,7 @@ class ESP32BLETracker : public Component {
uint32_t scan_duration_; uint32_t scan_duration_;
uint32_t scan_interval_; uint32_t scan_interval_;
uint32_t scan_window_; uint32_t scan_window_;
uint8_t scan_start_fail_count_;
bool scan_continuous_; bool scan_continuous_;
bool scan_active_; bool scan_active_;
bool scanner_idle_; bool scanner_idle_;

View file

@ -4,9 +4,10 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include <queue>
#include <mutex>
#include <cstring> #include <cstring>
#include <mutex>
#include <queue>
#include <vector>
#include <esp_gap_ble_api.h> #include <esp_gap_ble_api.h>
#include <esp_gattc_api.h> #include <esp_gattc_api.h>

View file

@ -54,7 +54,7 @@ void ESP32Camera::dump_config() {
ESP_LOGCONFIG(TAG, " HREF Pin: %d", conf.pin_href); ESP_LOGCONFIG(TAG, " HREF Pin: %d", conf.pin_href);
ESP_LOGCONFIG(TAG, " Pixel Clock Pin: %d", conf.pin_pclk); ESP_LOGCONFIG(TAG, " Pixel Clock Pin: %d", conf.pin_pclk);
ESP_LOGCONFIG(TAG, " External Clock: Pin:%d Frequency:%u", conf.pin_xclk, conf.xclk_freq_hz); ESP_LOGCONFIG(TAG, " External Clock: Pin:%d Frequency:%u", conf.pin_xclk, conf.xclk_freq_hz);
ESP_LOGCONFIG(TAG, " I2C Pins: SDA:%d SCL:%d", conf.pin_sscb_sda, conf.pin_sscb_scl); ESP_LOGCONFIG(TAG, " I2C Pins: SDA:%d SCL:%d", conf.pin_sccb_sda, conf.pin_sccb_scl);
ESP_LOGCONFIG(TAG, " Reset Pin: %d", conf.pin_reset); ESP_LOGCONFIG(TAG, " Reset Pin: %d", conf.pin_reset);
switch (this->config_.frame_size) { switch (this->config_.frame_size) {
case FRAMESIZE_QQVGA: case FRAMESIZE_QQVGA:
@ -209,8 +209,8 @@ void ESP32Camera::set_external_clock(uint8_t pin, uint32_t frequency) {
this->config_.xclk_freq_hz = frequency; this->config_.xclk_freq_hz = frequency;
} }
void ESP32Camera::set_i2c_pins(uint8_t sda, uint8_t scl) { void ESP32Camera::set_i2c_pins(uint8_t sda, uint8_t scl) {
this->config_.pin_sscb_sda = sda; this->config_.pin_sccb_sda = sda;
this->config_.pin_sscb_scl = scl; this->config_.pin_sccb_scl = scl;
} }
void ESP32Camera::set_reset_pin(uint8_t pin) { this->config_.pin_reset = pin; } void ESP32Camera::set_reset_pin(uint8_t pin) { this->config_.pin_reset = pin; }
void ESP32Camera::set_power_down_pin(uint8_t pin) { this->config_.pin_pwdn = pin; } void ESP32Camera::set_power_down_pin(uint8_t pin) { this->config_.pin_pwdn = pin; }

View file

@ -177,8 +177,9 @@ void ESP32ImprovComponent::set_state_(improv::State state) {
} }
void ESP32ImprovComponent::set_error_(improv::Error error) { void ESP32ImprovComponent::set_error_(improv::Error error) {
if (error != improv::ERROR_NONE) if (error != improv::ERROR_NONE) {
ESP_LOGE(TAG, "Error: %d", error); ESP_LOGE(TAG, "Error: %d", error);
}
if (this->error_->get_value().empty() || this->error_->get_value()[0] != error) { if (this->error_->get_value().empty() || this->error_->get_value()[0] != error) {
uint8_t data[1]{error}; uint8_t data[1]{error};
this->error_->set_value(data, 1); this->error_->set_value(data, 1);

View file

@ -9,6 +9,8 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/preferences.h" #include "esphome/core/preferences.h"
#include <vector>
#ifdef USE_ESP32 #ifdef USE_ESP32
#include <improv.h> #include <improv.h>

View file

@ -6,6 +6,8 @@
#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h"
#include <esp_idf_version.h> #include <esp_idf_version.h>
#include <vector>
#if ESP_IDF_VERSION_MAJOR >= 4 #if ESP_IDF_VERSION_MAJOR >= 4
#include <driver/touch_sensor.h> #include <driver/touch_sensor.h>
#else #else

View file

@ -22,10 +22,11 @@ from .const import (
CONF_EARLY_PIN_INIT, CONF_EARLY_PIN_INIT,
KEY_BOARD, KEY_BOARD,
KEY_ESP8266, KEY_ESP8266,
KEY_FLASH_SIZE,
KEY_PIN_INITIAL_STATES, KEY_PIN_INITIAL_STATES,
esp8266_ns, esp8266_ns,
) )
from .boards import ESP8266_FLASH_SIZES, ESP8266_LD_SCRIPTS from .boards import BOARDS, ESP8266_LD_SCRIPTS
from .gpio import PinInitialState, add_pin_initial_states_array from .gpio import PinInitialState, add_pin_initial_states_array
@ -218,8 +219,8 @@ async def to_code(config):
cg.RawExpression(f"VERSION_CODE({ver.major}, {ver.minor}, {ver.patch})"), cg.RawExpression(f"VERSION_CODE({ver.major}, {ver.minor}, {ver.patch})"),
) )
if config[CONF_BOARD] in ESP8266_FLASH_SIZES: if config[CONF_BOARD] in BOARDS:
flash_size = ESP8266_FLASH_SIZES[config[CONF_BOARD]] flash_size = BOARDS[config[CONF_BOARD]][KEY_FLASH_SIZE]
ld_scripts = ESP8266_LD_SCRIPTS[flash_size] ld_scripts = ESP8266_LD_SCRIPTS[flash_size]
if ver <= cv.Version(2, 3, 0): if ver <= cv.Version(2, 3, 0):

View file

@ -4,50 +4,6 @@ FLASH_SIZE_2_MB = 2 * FLASH_SIZE_1_MB
FLASH_SIZE_4_MB = 4 * FLASH_SIZE_1_MB FLASH_SIZE_4_MB = 4 * FLASH_SIZE_1_MB
FLASH_SIZE_16_MB = 16 * FLASH_SIZE_1_MB FLASH_SIZE_16_MB = 16 * FLASH_SIZE_1_MB
ESP8266_FLASH_SIZES = {
"d1": FLASH_SIZE_4_MB,
"d1_mini": FLASH_SIZE_4_MB,
"d1_mini_lite": FLASH_SIZE_1_MB,
"d1_mini_pro": FLASH_SIZE_16_MB,
"esp01": FLASH_SIZE_512_KB,
"esp01_1m": FLASH_SIZE_1_MB,
"esp07": FLASH_SIZE_4_MB,
"esp12e": FLASH_SIZE_4_MB,
"esp210": FLASH_SIZE_4_MB,
"esp8285": FLASH_SIZE_1_MB,
"esp_wroom_02": FLASH_SIZE_2_MB,
"espduino": FLASH_SIZE_4_MB,
"espectro": FLASH_SIZE_4_MB,
"espino": FLASH_SIZE_4_MB,
"espinotee": FLASH_SIZE_4_MB,
"espmxdevkit": FLASH_SIZE_1_MB,
"espresso_lite_v1": FLASH_SIZE_4_MB,
"espresso_lite_v2": FLASH_SIZE_4_MB,
"gen4iod": FLASH_SIZE_512_KB,
"heltec_wifi_kit_8": FLASH_SIZE_4_MB,
"huzzah": FLASH_SIZE_4_MB,
"inventone": FLASH_SIZE_4_MB,
"modwifi": FLASH_SIZE_2_MB,
"nodemcu": FLASH_SIZE_4_MB,
"nodemcuv2": FLASH_SIZE_4_MB,
"oak": FLASH_SIZE_4_MB,
"phoenix_v1": FLASH_SIZE_4_MB,
"phoenix_v2": FLASH_SIZE_4_MB,
"sonoff_basic": FLASH_SIZE_1_MB,
"sonoff_s20": FLASH_SIZE_1_MB,
"sonoff_sv": FLASH_SIZE_1_MB,
"sonoff_th": FLASH_SIZE_1_MB,
"sparkfunBlynk": FLASH_SIZE_4_MB,
"thing": FLASH_SIZE_512_KB,
"thingdev": FLASH_SIZE_512_KB,
"wifi_slot": FLASH_SIZE_1_MB,
"wifiduino": FLASH_SIZE_4_MB,
"wifinfo": FLASH_SIZE_1_MB,
"wio_link": FLASH_SIZE_4_MB,
"wio_node": FLASH_SIZE_4_MB,
"xinabox_cw01": FLASH_SIZE_4_MB,
}
ESP8266_LD_SCRIPTS = { ESP8266_LD_SCRIPTS = {
FLASH_SIZE_512_KB: ("eagle.flash.512k0.ld", "eagle.flash.512k.ld"), FLASH_SIZE_512_KB: ("eagle.flash.512k0.ld", "eagle.flash.512k.ld"),
FLASH_SIZE_1_MB: ("eagle.flash.1m0.ld", "eagle.flash.1m.ld"), FLASH_SIZE_1_MB: ("eagle.flash.1m0.ld", "eagle.flash.1m.ld"),
@ -206,3 +162,201 @@ ESP8266_BOARD_PINS = {
"wio_node": {"LED": 2, "GROVE": 15, "D0": 3, "D1": 5, "BUTTON": 0}, "wio_node": {"LED": 2, "GROVE": 15, "D0": 3, "D1": 5, "BUTTON": 0},
"xinabox_cw01": {"SDA": 2, "SCL": 14, "LED": 5, "LED_RED": 12, "LED_GREEN": 13}, "xinabox_cw01": {"SDA": 2, "SCL": 14, "LED": 5, "LED_RED": 12, "LED_GREEN": 13},
} }
"""
BOARDS generate with:
git clone https://github.com/platformio/platform-espressif8266
for x in platform-espressif8266/boards/*.json; do
max_size=$(jq -r .upload.maximum_size <"$x")
name=$(jq -r .name <"$x")
fname=$(basename "$x")
board="${fname%.*}"
size_mb=$((max_size / (1024 * 1024)))
if [[ $size_mb -gt 0 ]]; then
size="${size_mb}_MB"
else
size="${$((max_size / 1024))}_KB"
fi
echo " \"$board\": {\"name\": \"$name\", \"flash_size\": FLASH_SIZE_$size,},"
done | sort
"""
BOARDS = {
"agruminolemon": {
"name": "Lifely Agrumino Lemon v4",
"flash_size": FLASH_SIZE_4_MB,
},
"d1_mini_lite": {
"name": "WeMos D1 mini Lite",
"flash_size": FLASH_SIZE_1_MB,
},
"d1_mini": {
"name": "WeMos D1 R2 and mini",
"flash_size": FLASH_SIZE_4_MB,
},
"d1_mini_pro": {
"name": "WeMos D1 mini Pro",
"flash_size": FLASH_SIZE_16_MB,
},
"d1": {
"name": "WEMOS D1 R1",
"flash_size": FLASH_SIZE_4_MB,
},
"eduinowifi": {
"name": "Schirmilabs Eduino WiFi",
"flash_size": FLASH_SIZE_4_MB,
},
"esp01_1m": {
"name": "Espressif Generic ESP8266 ESP-01 1M",
"flash_size": FLASH_SIZE_1_MB,
},
"esp01": {
"name": "Espressif Generic ESP8266 ESP-01 512k",
"flash_size": FLASH_SIZE_512_KB,
},
"esp07": {
"name": "Espressif Generic ESP8266 ESP-07 1MB",
"flash_size": FLASH_SIZE_1_MB,
},
"esp07s": {
"name": "Espressif Generic ESP8266 ESP-07S",
"flash_size": FLASH_SIZE_4_MB,
},
"esp12e": {
"name": "Espressif ESP8266 ESP-12E",
"flash_size": FLASH_SIZE_4_MB,
},
"esp210": {
"name": "SweetPea ESP-210",
"flash_size": FLASH_SIZE_4_MB,
},
"esp8285": {
"name": "Generic ESP8285 Module",
"flash_size": FLASH_SIZE_1_MB,
},
"espduino": {
"name": "ESPDuino (ESP-13 Module)",
"flash_size": FLASH_SIZE_4_MB,
},
"espectro": {
"name": "ESPectro Core",
"flash_size": FLASH_SIZE_4_MB,
},
"espino": {
"name": "ESPino",
"flash_size": FLASH_SIZE_4_MB,
},
"espinotee": {
"name": "ThaiEasyElec ESPino",
"flash_size": FLASH_SIZE_4_MB,
},
"espmxdevkit": {
"name": "ESP-Mx DevKit (ESP8285)",
"flash_size": FLASH_SIZE_1_MB,
},
"espresso_lite_v1": {
"name": "ESPresso Lite 1.0",
"flash_size": FLASH_SIZE_4_MB,
},
"espresso_lite_v2": {
"name": "ESPresso Lite 2.0",
"flash_size": FLASH_SIZE_4_MB,
},
"esp_wroom_02": {
"name": "ESP-WROOM-02",
"flash_size": FLASH_SIZE_2_MB,
},
"gen4iod": {
"name": "4D Systems gen4 IoD Range",
"flash_size": FLASH_SIZE_512_KB,
},
"heltec_wifi_kit_8": {
"name": "Heltec Wifi kit 8",
"flash_size": FLASH_SIZE_4_MB,
},
"huzzah": {
"name": "Adafruit HUZZAH ESP8266",
"flash_size": FLASH_SIZE_4_MB,
},
"inventone": {
"name": "Invent One",
"flash_size": FLASH_SIZE_4_MB,
},
"modwifi": {
"name": "Olimex MOD-WIFI-ESP8266(-DEV)",
"flash_size": FLASH_SIZE_2_MB,
},
"nodemcu": {
"name": "NodeMCU 0.9 (ESP-12 Module)",
"flash_size": FLASH_SIZE_4_MB,
},
"nodemcuv2": {
"name": "NodeMCU 1.0 (ESP-12E Module)",
"flash_size": FLASH_SIZE_4_MB,
},
"oak": {
"name": "DigiStump Oak",
"flash_size": FLASH_SIZE_4_MB,
},
"phoenix_v1": {
"name": "Phoenix 1.0",
"flash_size": FLASH_SIZE_4_MB,
},
"phoenix_v2": {
"name": "Phoenix 2.0",
"flash_size": FLASH_SIZE_4_MB,
},
"sonoff_basic": {
"name": "Sonoff Basic",
"flash_size": FLASH_SIZE_1_MB,
},
"sonoff_s20": {
"name": "Sonoff S20",
"flash_size": FLASH_SIZE_1_MB,
},
"sonoff_sv": {
"name": "Sonoff SV",
"flash_size": FLASH_SIZE_1_MB,
},
"sonoff_th": {
"name": "Sonoff TH",
"flash_size": FLASH_SIZE_1_MB,
},
"sparkfunBlynk": {
"name": "SparkFun Blynk Board",
"flash_size": FLASH_SIZE_4_MB,
},
"thingdev": {
"name": "SparkFun ESP8266 Thing Dev",
"flash_size": FLASH_SIZE_512_KB,
},
"thing": {
"name": "SparkFun ESP8266 Thing",
"flash_size": FLASH_SIZE_512_KB,
},
"wifiduino": {
"name": "WiFiduino",
"flash_size": FLASH_SIZE_4_MB,
},
"wifinfo": {
"name": "WifInfo",
"flash_size": FLASH_SIZE_1_MB,
},
"wifi_slot": {
"name": "WiFi Slot",
"flash_size": FLASH_SIZE_4_MB,
},
"wio_link": {
"name": "Wio Link",
"flash_size": FLASH_SIZE_4_MB,
},
"wio_node": {
"name": "Wio Node",
"flash_size": FLASH_SIZE_4_MB,
},
"xinabox_cw01": {
"name": "XinaBox CW01",
"flash_size": FLASH_SIZE_4_MB,
},
}

View file

@ -5,6 +5,7 @@ KEY_BOARD = "board"
KEY_PIN_INITIAL_STATES = "pin_initial_states" KEY_PIN_INITIAL_STATES = "pin_initial_states"
CONF_RESTORE_FROM_FLASH = "restore_from_flash" CONF_RESTORE_FROM_FLASH = "restore_from_flash"
CONF_EARLY_PIN_INIT = "early_pin_init" CONF_EARLY_PIN_INIT = "early_pin_init"
KEY_FLASH_SIZE = "flash_size"
# esp8266 namespace is already defined by arduino, manually prefix esphome # esp8266 namespace is already defined by arduino, manually prefix esphome
esp8266_ns = cg.global_ns.namespace("esphome").namespace("esp8266") esp8266_ns = cg.global_ns.namespace("esphome").namespace("esp8266")

View file

@ -5,12 +5,14 @@ extern "C" {
#include "spi_flash.h" #include "spi_flash.h"
} }
#include "preferences.h" #include "esphome/core/defines.h"
#include <cstring>
#include "esphome/core/preferences.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/defines.h" #include "esphome/core/preferences.h"
#include "preferences.h"
#include <cstring>
#include <vector>
namespace esphome { namespace esphome {
namespace esp8266 { namespace esp8266 {

View file

@ -30,16 +30,17 @@ CONF_POWER_PIN = "power_pin"
EthernetType = ethernet_ns.enum("EthernetType") EthernetType = ethernet_ns.enum("EthernetType")
ETHERNET_TYPES = { ETHERNET_TYPES = {
"LAN8720": EthernetType.ETHERNET_TYPE_LAN8720, "LAN8720": EthernetType.ETHERNET_TYPE_LAN8720,
"TLK110": EthernetType.ETHERNET_TYPE_TLK110, "RTL8201": EthernetType.ETHERNET_TYPE_RTL8201,
"DP83848": EthernetType.ETHERNET_TYPE_DP83848,
"IP101": EthernetType.ETHERNET_TYPE_IP101, "IP101": EthernetType.ETHERNET_TYPE_IP101,
} }
eth_clock_mode_t = cg.global_ns.enum("eth_clock_mode_t") emac_rmii_clock_gpio_t = cg.global_ns.enum("emac_rmii_clock_gpio_t")
CLK_MODES = { CLK_MODES = {
"GPIO0_IN": eth_clock_mode_t.ETH_CLOCK_GPIO0_IN, "GPIO0_IN": emac_rmii_clock_gpio_t.EMAC_CLK_IN_GPIO,
"GPIO0_OUT": eth_clock_mode_t.ETH_CLOCK_GPIO0_OUT, "GPIO0_OUT": emac_rmii_clock_gpio_t.EMAC_APPL_CLK_OUT_GPIO,
"GPIO16_OUT": eth_clock_mode_t.ETH_CLOCK_GPIO16_OUT, "GPIO16_OUT": emac_rmii_clock_gpio_t.EMAC_CLK_OUT_GPIO,
"GPIO17_OUT": eth_clock_mode_t.ETH_CLOCK_GPIO17_OUT, "GPIO17_OUT": emac_rmii_clock_gpio_t.EMAC_CLK_OUT_180_GPIO,
} }
@ -78,7 +79,7 @@ CONFIG_SCHEMA = cv.All(
CLK_MODES, upper=True, space="_" CLK_MODES, upper=True, space="_"
), ),
cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31), cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31),
cv.Optional(CONF_POWER_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_number,
cv.Optional(CONF_MANUAL_IP): MANUAL_IP_SCHEMA, cv.Optional(CONF_MANUAL_IP): MANUAL_IP_SCHEMA,
cv.Optional(CONF_DOMAIN, default=".local"): cv.domain_name, cv.Optional(CONF_DOMAIN, default=".local"): cv.domain_name,
cv.Optional(CONF_USE_ADDRESS): cv.string_strict, cv.Optional(CONF_USE_ADDRESS): cv.string_strict,
@ -89,7 +90,6 @@ CONFIG_SCHEMA = cv.All(
} }
).extend(cv.COMPONENT_SCHEMA), ).extend(cv.COMPONENT_SCHEMA),
_validate, _validate,
cv.only_with_arduino,
) )
@ -117,13 +117,12 @@ async def to_code(config):
cg.add(var.set_use_address(config[CONF_USE_ADDRESS])) cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))
if CONF_POWER_PIN in config: if CONF_POWER_PIN in config:
pin = await cg.gpio_pin_expression(config[CONF_POWER_PIN]) cg.add(var.set_power_pin(config[CONF_POWER_PIN]))
cg.add(var.set_power_pin(pin))
if CONF_MANUAL_IP in config: if CONF_MANUAL_IP in config:
cg.add(var.set_manual_ip(manual_ip(config[CONF_MANUAL_IP]))) cg.add(var.set_manual_ip(manual_ip(config[CONF_MANUAL_IP])))
cg.add_define("USE_ETHERNET") cg.add_define("USE_ETHERNET")
if CORE.is_esp32: if CORE.using_arduino:
cg.add_library("WiFi", None) cg.add_library("WiFi", None)

Some files were not shown because too many files have changed in this diff Show more