1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-09 11:31:50 +00:00

Compare commits

...

61 Commits

Author SHA1 Message Date
Jesse Hills
2d58239b74 Merge pull request #3876 from esphome/bump-2022.9.3
2022.9.3
2022-10-06 09:57:39 +13:00
Jesse Hills
6b52f62531 Bump version to 2022.9.3 2022-10-06 09:22:01 +13:00
Jesse Hills
1001d9c04e Bluetooth Proxy active connections (#3817) 2022-10-06 09:22:00 +13:00
Jesse Hills
119c3f6f46 Merge pull request #3853 from esphome/bump-2022.9.2
2022.9.2
2022-09-29 16:18:21 +13:00
Jesse Hills
d2c1c7507c Bump version to 2022.9.2 2022-09-29 16:00:55 +13:00
Guillermo Ruffino
efdb3d1f40 Bump dashboard to 20220925.0 (#3846) 2022-09-29 16:00:55 +13:00
Jesse Hills
9dbc32b85f Merge pull request #3839 from esphome/bump-2022.9.1
2022.9.1
2022-09-22 07:51:52 +12:00
Jesse Hills
66226abb48 Bump version to 2022.9.1 2022-09-22 07:40:15 +12:00
Jesse Hills
34bef2f2ca Revert "fix spi timing issues" (#3838) 2022-09-22 07:40:15 +12:00
Jesse Hills
fdd4ca6837 Merge pull request #3837 from esphome/bump-2022.9.0
2022.9.0
2022-09-21 15:59:34 +12:00
Jesse Hills
9655362f23 Bump version to 2022.9.0 2022-09-21 15:34:02 +12:00
Jesse Hills
130c9fad22 Merge branch 'beta' into bump-2022.9.0 2022-09-21 15:34:02 +12:00
Jesse Hills
3de0b601bf Merge pull request #3835 from esphome/bump-2022.9.0b5
2022.9.0b5
2022-09-21 15:23:41 +12:00
Jesse Hills
91560ae4e9 Bump version to 2022.9.0b5 2022-09-21 12:38:55 +12:00
Guillermo Ruffino
fd6135aebb Bump dashboard to 20220920.1 (#3834) 2022-09-21 12:38:55 +12:00
Jesse Hills
e5fe5d1249 Merge pull request #3833 from esphome/bump-2022.9.0b4
2022.9.0b4
2022-09-21 09:09:20 +12:00
Jesse Hills
63b42f3608 Bump version to 2022.9.0b4 2022-09-21 07:36:39 +12:00
Paulus Schoutsen
d56107e97f Bump dashboard to 20220920.0 (#3831) 2022-09-21 07:36:39 +12:00
Guillermo Ruffino
33f296e05b Fix-esphome-validation-line-number (#3815) 2022-09-21 07:36:39 +12:00
Jesse Hills
97e067a277 Merge pull request #3829 from esphome/bump-2022.9.0b3
2022.9.0b3
2022-09-20 19:28:27 +12:00
Jesse Hills
5f56cf3128 Bump version to 2022.9.0b3 2022-09-20 17:14:51 +12:00
Paulus Schoutsen
5c4e83ebdc Bump dashboard to 20220919.1 (#3828) 2022-09-20 17:14:51 +12:00
Keith Burzinski
91f1c25fcc Make sprinkler reset_resume() method public (#3824) 2022-09-20 17:14:51 +12:00
h3ndrik
47a7a239ae [BME280] raise standby time (#3804) 2022-09-20 17:14:51 +12:00
Samuel Sieb
fb9984e21f split pronto codes if they are too long (#3812)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2022-09-20 17:14:51 +12:00
Jesse Hills
71dd04b09e Merge pull request #3809 from esphome/bump-2022.9.0b2
2022.9.0b2
2022-09-15 13:35:54 +12:00
Jesse Hills
7deabbb512 Bump version to 2022.9.0b2 2022-09-15 13:02:40 +12:00
Azimath
625a575e49 Remove floating point calculation from ac_dimmer ISR (#3770) 2022-09-15 13:02:39 +12:00
Jesse Hills
df4d0da221 Initialize all child sensors to nullptr (#3808) 2022-09-15 13:02:39 +12:00
RoboMagus
6b23b7cad7 Unify 'nullptr' initalization of class members; (#3805) 2022-09-15 13:02:39 +12:00
Guillermo Ruffino
cea7deab91 Sim800l add calls, multiline sms and ussd (#3630)
Co-authored-by: Matus Ivanecky <matus.ivanecky@gmail.com>
Co-authored-by: Matus Ivanecky <maty535@users.noreply.github.com>
2022-09-15 13:02:39 +12:00
RoboMagus
c61abf6aca null initialize total sensor for pulse counter (#3803)
* null initialize total sensor.

* pedantic styling fix

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
2022-09-15 13:02:39 +12:00
Jesse Hills
041eb8f6cc Merge pull request #3783 from esphome/bump-2022.8.3
2022.8.3
2022-09-06 18:54:28 +12:00
Jesse Hills
733a84df75 Bump version to 2022.8.3 2022-09-06 16:50:17 +12:00
Jesse Hills
acd0b50b40 Fix HA addon auth using HA credentials (#3758) 2022-09-06 16:50:11 +12:00
Jesse Hills
60e46d485e Merge pull request #3781 from esphome/bump-2022.8.2
2022.8.2
2022-09-06 15:38:46 +12:00
Jesse Hills
5bf0c92318 Bump version to 2022.8.2 2022-09-06 13:12:00 +12:00
Avirsaam
39d493c278 Update modbus_controller.cpp (#3768) 2022-09-06 13:12:00 +12:00
anatoly-savchenkov
d2ce62aa13 Ignore NaN states in the integration component (#3767) 2022-09-06 13:12:00 +12:00
Jesse Hills
c8eb30ef27 Initial bluetooth_proxy support (#3736) 2022-09-06 13:11:54 +12:00
Jesse Hills
31ad75d01b Merge pull request #3757 from esphome/bump-2022.8.1
2022.8.1
2022-09-01 13:59:03 +12:00
Jesse Hills
aa2eb29274 Bump version to 2022.8.1 2022-09-01 11:26:52 +12:00
Keith Burzinski
22eb4f9cb9 Fix SPI HW selection for ESP32 variants (#3728) 2022-09-01 11:26:51 +12:00
Samuel Sieb
3acc8e7479 fix grow password setting (#3722)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2022-09-01 11:26:51 +12:00
Jesse Hills
adc8c1aa38 Merge pull request #3721 from esphome/bump-2022.8.0
2022.8.0
2022-08-17 13:31:24 +12:00
Jesse Hills
3a82f500d4 Bump version to 2022.8.0 2022-08-17 12:58:30 +12:00
Jesse Hills
7d1d4831a8 Merge branch 'beta' into bump-2022.8.0 2022-08-17 12:58:29 +12:00
Jesse Hills
ab86ddcf02 Merge pull request #3692 from esphome/bump-2022.6.3
2022.6.3
2022-08-08 11:48:35 +12:00
Jesse Hills
bf8eddb13b Bump version to 2022.6.3 2022-08-08 08:24:12 +12:00
Samuel Sieb
e5eaf7a3fe Use correct struct members. (#3672) 2022-08-08 08:24:12 +12:00
Samuel Sieb
50f32a3aa5 Use application/json instead of text/json (#3671) 2022-08-08 08:24:11 +12:00
Bryan Berg
eb878710c1 Add CO device class to binary_sensor (#3656) 2022-08-08 08:24:11 +12:00
Samuel Sieb
311980e0e4 Update inkbird_ibsth1_mini.cpp (#3664) 2022-08-08 08:24:11 +12:00
Javier Peletier
df73170e5a modbus: fix queue deduplicator erasing custom commands (#3650) 2022-08-08 08:24:11 +12:00
Jesse Hills
ccc13cc9e1 Merge pull request #3596 from esphome/bump-2022.6.2
2022.6.2
2022-06-23 11:30:31 +12:00
Jesse Hills
020b2c05c8 Bump version to 2022.6.2 2022-06-23 10:34:10 +12:00
Joe
4c37c17df1 Fix 2 small issues in BLEClient (#3544) 2022-06-23 10:34:09 +12:00
Sergey Dudanov
8f67acadd8 Media Player: added play_media action (#3579)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2022-06-23 10:34:09 +12:00
kahrendt
ca13c4c1a6 Fix wrong type for voc_state*_ in sgp4x component (#3581)
Co-authored-by: Martin <25747549+martgras@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2022-06-23 10:34:09 +12:00
ShellAddicted
d0c646c721 Fix: Make MQTT over TLS actually work (#3580) 2022-06-23 10:34:09 +12:00
lkomurcu
8a055675af Move gas mbus config option being a define to being a build flag since its used in external libraries. (#3575) 2022-06-23 10:34:09 +12:00
95 changed files with 3425 additions and 856 deletions

View File

@@ -70,6 +70,7 @@ esphome/components/ektf2232/* @jesserockz
esphome/components/ens210/* @itn3rd77
esphome/components/esp32/* @esphome/core
esphome/components/esp32_ble/* @jesserockz
esphome/components/esp32_ble_client/* @jesserockz
esphome/components/esp32_ble_server/* @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron

View File

@@ -121,11 +121,8 @@ void IRAM_ATTR HOT AcDimmerDataStore::gpio_intr() {
// calculate time until enable in µs: (1.0-value)*cycle_time, but with integer arithmetic
// also take into account min_power
auto min_us = this->cycle_time_us * this->min_power / 1000;
// calculate required value to provide a true RMS voltage output
this->enable_time_us =
std::max((uint32_t) 1, (uint32_t)((65535 - (acos(1 - (2 * this->value / 65535.0)) / 3.14159 * 65535)) *
(this->cycle_time_us - min_us)) /
65535);
this->enable_time_us = std::max((uint32_t) 1, ((65535 - this->value) * (this->cycle_time_us - min_us)) / 65535);
if (this->method == DIM_METHOD_LEADING_PULSE) {
// Minimum pulse time should be enough for the triac to trigger when it is close to the ZC zone
// this is for brightness near 99%
@@ -206,6 +203,7 @@ void AcDimmer::setup() {
#endif
}
void AcDimmer::write_state(float state) {
state = std::acos(1 - (2 * state)) / 3.14159; // RMS power compensation
auto new_value = static_cast<uint16_t>(roundf(state * 65535));
if (new_value != 0 && this->store_.value == 0)
this->store_.init_cycle = this->init_with_half_cycle_;

View File

@@ -82,7 +82,7 @@ class ADE7953 : public i2c::I2CDevice, public PollingComponent {
return i2c::ERROR_OK;
}
InternalGPIOPin *irq_pin_ = nullptr;
InternalGPIOPin *irq_pin_{nullptr};
bool is_setup_{false};
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_a_sensor_{nullptr};

View File

@@ -18,8 +18,8 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice {
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
protected:
sensor::Sensor *temperature_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace aht10

View File

@@ -38,7 +38,7 @@ void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
}
case ESP_GATTC_READ_CHAR_EVT: {
if (param->read.conn_id != this->parent()->conn_id)
if (param->read.conn_id != this->parent()->get_conn_id())
break;
if (param->read.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
@@ -88,8 +88,8 @@ void AirthingsWaveMini::update() {
}
void AirthingsWaveMini::request_read_values_() {
auto status =
esp_ble_gattc_read_char(this->parent()->gattc_if, this->parent()->conn_id, this->handle_, ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_,
ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status);
}

View File

@@ -38,7 +38,7 @@ void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
}
case ESP_GATTC_READ_CHAR_EVT: {
if (param->read.conn_id != this->parent()->conn_id)
if (param->read.conn_id != this->parent()->get_conn_id())
break;
if (param->read.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
@@ -109,8 +109,8 @@ void AirthingsWavePlus::update() {
}
void AirthingsWavePlus::request_read_values_() {
auto status =
esp_ble_gattc_read_char(this->parent()->gattc_if, this->parent()->conn_id, this->handle_, ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_,
ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status);
}

View File

@@ -21,8 +21,8 @@ class AM2320Component : public PollingComponent, public i2c::I2CDevice {
bool read_data_(uint8_t *data);
bool read_bytes_(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0);
sensor::Sensor *temperature_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace am2320

View File

@@ -76,9 +76,9 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i
if (this->current_sensor_ > 0) {
if (this->illuminance_ != nullptr) {
auto *packet = this->encoder_->get_light_level_request();
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP,
ESP_GATT_AUTH_REQ_NONE);
auto status = 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);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
status);
@@ -102,8 +102,8 @@ void Am43::update() {
if (this->battery_ != nullptr) {
auto *packet = this->encoder_->get_battery_level_request();
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
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);
if (status)
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
}

View File

@@ -27,8 +27,8 @@ void Am43Component::loop() {
if (this->node_state == espbt::ClientState::ESTABLISHED && !this->logged_in_) {
auto *packet = this->encoder_->get_send_pin_request(this->pin_);
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
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);
ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str());
if (status) {
ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status);
@@ -54,8 +54,8 @@ void Am43Component::control(const CoverCall &call) {
if (call.get_stop()) {
auto *packet = this->encoder_->get_stop_request();
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
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);
if (status)
ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
}
@@ -66,8 +66,8 @@ void Am43Component::control(const CoverCall &call) {
pos = 1 - pos;
auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100));
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, packet->length,
packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
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);
if (status)
ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
}
@@ -92,7 +92,8 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
}
this->char_handle_ = chr->handle;
auto status = esp_ble_gattc_register_for_notify(this->parent_->gattc_if, this->parent_->remote_bda, chr->handle);
auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
chr->handle);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
}
@@ -122,9 +123,9 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
if (this->decoder_->pin_ok_) {
ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str());
auto *packet = this->encoder_->get_position_request();
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP,
ESP_GATT_AUTH_REQ_NONE);
auto status = 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);
if (status)
ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
} else {

View File

@@ -34,14 +34,16 @@ void Anova::control(const ClimateCall &call) {
ESP_LOGW(TAG, "Unsupported mode: %d", mode);
return;
}
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
auto status =
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);
if (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()) {
auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
auto status =
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);
if (status)
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
@@ -65,7 +67,8 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
}
this->char_handle_ = chr->handle;
auto status = esp_ble_gattc_register_for_notify(this->parent_->gattc_if, this->parent_->remote_bda, chr->handle);
auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
chr->handle);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
}
@@ -112,8 +115,8 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
}
if (pkt != nullptr) {
auto status =
esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, pkt->length,
pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
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);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
status);
@@ -137,7 +140,8 @@ void Anova::update() {
auto *pkt = this->codec_->get_read_device_status_request();
if (this->current_request_ == 0)
this->codec_->get_set_unit_request(this->fahrenheit_ ? 'f' : 'c');
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
auto status =
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);
if (status)
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);

View File

@@ -27,7 +27,6 @@ service APIConnection {
rpc subscribe_logs (SubscribeLogsRequest) returns (void) {}
rpc subscribe_homeassistant_services (SubscribeHomeassistantServicesRequest) returns (void) {}
rpc subscribe_home_assistant_states (SubscribeHomeAssistantStatesRequest) returns (void) {}
rpc subscribe_bluetooth_le_advertisements (SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
rpc get_time (GetTimeRequest) returns (GetTimeResponse) {
option (needs_authentication) = false;
}
@@ -44,6 +43,16 @@ service APIConnection {
rpc button_command (ButtonCommandRequest) returns (void) {}
rpc lock_command (LockCommandRequest) returns (void) {}
rpc media_player_command (MediaPlayerCommandRequest) returns (void) {}
rpc subscribe_bluetooth_le_advertisements(SubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
rpc bluetooth_device_request(BluetoothDeviceRequest) returns (void) {}
rpc bluetooth_gatt_get_services(BluetoothGATTGetServicesRequest) returns (void) {}
rpc bluetooth_gatt_read(BluetoothGATTReadRequest) returns (void) {}
rpc bluetooth_gatt_write(BluetoothGATTWriteRequest) returns (void) {}
rpc bluetooth_gatt_read_descriptor(BluetoothGATTReadDescriptorRequest) returns (void) {}
rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {}
rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {}
rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {}
}
@@ -78,6 +87,8 @@ message HelloRequest {
// Not strictly necessary to send but nice for debugging
// purposes.
string client_info = 1;
uint32 api_version_major = 2;
uint32 api_version_minor = 3;
}
// Confirmation of successful connection request.
@@ -192,7 +203,7 @@ message DeviceInfoResponse {
uint32 webserver_port = 10;
bool has_bluetooth_proxy = 11;
uint32 bluetooth_proxy_version = 11;
}
message ListEntitiesRequest {
@@ -1111,7 +1122,8 @@ message SubscribeBluetoothLEAdvertisementsRequest {
message BluetoothServiceData {
string uuid = 1;
repeated uint32 data = 2 [packed=false];
repeated uint32 legacy_data = 2 [deprecated = true];
bytes data = 3; // Changed in proto version 1.7
}
message BluetoothLEAdvertisementResponse {
option (id) = 67;
@@ -1127,3 +1139,162 @@ message BluetoothLEAdvertisementResponse {
repeated BluetoothServiceData service_data = 5;
repeated BluetoothServiceData manufacturer_data = 6;
}
enum BluetoothDeviceRequestType {
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0;
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
}
message BluetoothDeviceRequest {
option (id) = 68;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
BluetoothDeviceRequestType request_type = 2;
}
message BluetoothDeviceConnectionResponse {
option (id) = 69;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
bool connected = 2;
uint32 mtu = 3;
int32 error = 4;
}
message BluetoothGATTGetServicesRequest {
option (id) = 70;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
}
message BluetoothGATTDescriptor {
repeated uint64 uuid = 1;
uint32 handle = 2;
}
message BluetoothGATTCharacteristic {
repeated uint64 uuid = 1;
uint32 handle = 2;
uint32 properties = 3;
repeated BluetoothGATTDescriptor descriptors = 4;
}
message BluetoothGATTService {
repeated uint64 uuid = 1;
uint32 handle = 2;
repeated BluetoothGATTCharacteristic characteristics = 3;
}
message BluetoothGATTGetServicesResponse {
option (id) = 71;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
repeated BluetoothGATTService services = 2;
}
message BluetoothGATTGetServicesDoneResponse {
option (id) = 72;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
}
message BluetoothGATTReadRequest {
option (id) = 73;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
uint32 handle = 2;
}
message BluetoothGATTReadResponse {
option (id) = 74;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
uint32 handle = 2;
bytes data = 3;
}
message BluetoothGATTWriteRequest {
option (id) = 75;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
uint32 handle = 2;
bool response = 3;
bytes data = 4;
}
message BluetoothGATTReadDescriptorRequest {
option (id) = 76;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
uint32 handle = 2;
}
message BluetoothGATTWriteDescriptorRequest {
option (id) = 77;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
uint32 handle = 2;
bytes data = 3;
}
message BluetoothGATTNotifyRequest {
option (id) = 78;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
uint32 handle = 2;
bool enable = 3;
}
message BluetoothGATTNotifyDataResponse {
option (id) = 79;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint64 address = 1;
uint32 handle = 2;
bytes data = 3;
}
message SubscribeBluetoothConnectionsFreeRequest {
option (id) = 80;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
}
message BluetoothConnectionsFreeResponse {
option (id) = 81;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_BLUETOOTH_PROXY";
uint32 free = 1;
uint32 limit = 2;
}

View File

@@ -1,10 +1,10 @@
#include "api_connection.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/log.h"
#include "esphome/components/network/util.h"
#include "esphome/core/version.h"
#include "esphome/core/hal.h"
#include <cerrno>
#include "esphome/components/network/util.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include "esphome/core/version.h"
#ifdef USE_DEEP_SLEEP
#include "esphome/components/deep_sleep/deep_sleep_component.h"
@@ -12,6 +12,9 @@
#ifdef USE_HOMEASSISTANT_TIME
#include "esphome/components/homeassistant/time/homeassistant_time.h"
#endif
#ifdef USE_BLUETOOTH_PROXY
#include "esphome/components/bluetooth_proxy/bluetooth_proxy.h"
#endif
namespace esphome {
namespace api {
@@ -823,6 +826,56 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) {
}
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIConnection::send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg) {
if (!this->bluetooth_le_advertisement_subscription_)
return false;
if (this->client_api_version_major_ < 1 || this->client_api_version_minor_ < 7) {
BluetoothLEAdvertisementResponse resp = msg;
for (auto &service : resp.service_data) {
service.legacy_data.assign(service.data.begin(), service.data.end());
service.data.clear();
}
for (auto &manufacturer_data : resp.manufacturer_data) {
manufacturer_data.legacy_data.assign(manufacturer_data.data.begin(), manufacturer_data.data.end());
manufacturer_data.data.clear();
}
return this->send_bluetooth_le_advertisement_response(resp);
}
return this->send_bluetooth_le_advertisement_response(msg);
}
void APIConnection::bluetooth_device_request(const BluetoothDeviceRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->bluetooth_device_request(msg);
}
void APIConnection::bluetooth_gatt_read(const BluetoothGATTReadRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_read(msg);
}
void APIConnection::bluetooth_gatt_write(const BluetoothGATTWriteRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_write(msg);
}
void APIConnection::bluetooth_gatt_read_descriptor(const BluetoothGATTReadDescriptorRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_read_descriptor(msg);
}
void APIConnection::bluetooth_gatt_write_descriptor(const BluetoothGATTWriteDescriptorRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_write_descriptor(msg);
}
void APIConnection::bluetooth_gatt_get_services(const BluetoothGATTGetServicesRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_send_services(msg);
}
void APIConnection::bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) {
bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_notify(msg);
}
BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_free(
const SubscribeBluetoothConnectionsFreeRequest &msg) {
BluetoothConnectionsFreeResponse resp;
resp.free = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_connections_free();
resp.limit = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_connections_limit();
return resp;
}
#endif
bool APIConnection::send_log_message(int level, const char *tag, const char *line) {
if (this->log_subscription_ < level)
return false;
@@ -840,11 +893,14 @@ bool APIConnection::send_log_message(int level, const char *tag, const char *lin
HelloResponse APIConnection::hello(const HelloRequest &msg) {
this->client_info_ = msg.client_info + " (" + this->helper_->getpeername() + ")";
this->helper_->set_log_info(client_info_);
ESP_LOGV(TAG, "Hello from client: '%s'", this->client_info_.c_str());
this->client_api_version_major_ = msg.api_version_major;
this->client_api_version_minor_ = msg.api_version_minor;
ESP_LOGV(TAG, "Hello from client: '%s' | API Version %d.%d", this->client_info_.c_str(),
this->client_api_version_major_, this->client_api_version_minor_);
HelloResponse resp;
resp.api_version_major = 1;
resp.api_version_minor = 6;
resp.api_version_minor = 7;
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
resp.name = App.get_name();
@@ -888,7 +944,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.webserver_port = USE_WEBSERVER_PORT;
#endif
#ifdef USE_BLUETOOTH_PROXY
resp.has_bluetooth_proxy = true;
resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 2 : 1;
#endif
return resp;
}

View File

@@ -1,15 +1,11 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/application.h"
#include "api_frame_helper.h"
#include "api_pb2.h"
#include "api_pb2_service.h"
#include "api_server.h"
#include "api_frame_helper.h"
#ifdef USE_BLUETOOTH_PROXY
#include "esphome/components/bluetooth_proxy/bluetooth_proxy.h"
#endif
#include "esphome/core/application.h"
#include "esphome/core/component.h"
namespace esphome {
namespace api {
@@ -99,11 +95,18 @@ class APIConnection : public APIServerConnection {
this->send_homeassistant_service_response(call);
}
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call) {
if (!this->bluetooth_le_advertisement_subscription_)
return false;
return this->send_bluetooth_le_advertisement_response(call);
}
bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg);
void bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
void bluetooth_gatt_read(const BluetoothGATTReadRequest &msg) override;
void bluetooth_gatt_write(const BluetoothGATTWriteRequest &msg) override;
void bluetooth_gatt_read_descriptor(const BluetoothGATTReadDescriptorRequest &msg) override;
void bluetooth_gatt_write_descriptor(const BluetoothGATTWriteDescriptorRequest &msg) override;
void bluetooth_gatt_get_services(const BluetoothGATTGetServicesRequest &msg) override;
void bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) override;
BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free(
const SubscribeBluetoothConnectionsFreeRequest &msg) override;
#endif
#ifdef USE_HOMEASSISTANT_TIME
void send_time_request() {
@@ -181,6 +184,8 @@ class APIConnection : public APIServerConnection {
std::unique_ptr<APIFrameHelper> helper_;
std::string client_info_;
uint32_t client_api_version_major_{0};
uint32_t client_api_version_minor_{0};
#ifdef USE_ESP32_CAMERA
esp32_camera::CameraImageReader image_reader_;
#endif
@@ -190,7 +195,7 @@ class APIConnection : public APIServerConnection {
uint32_t last_traffic_;
bool sent_ping_{false};
bool service_call_subscription_{false};
bool bluetooth_le_advertisement_subscription_{true};
bool bluetooth_le_advertisement_subscription_{false};
bool next_close_ = false;
APIServer *parent_;
InitialStateIterator initial_state_iterator_;

View File

@@ -116,9 +116,9 @@ class APINoiseFrameHelper : public APIFrameHelper {
std::vector<uint8_t> prologue_;
std::shared_ptr<APINoiseContext> ctx_;
NoiseHandshakeState *handshake_ = nullptr;
NoiseCipherState *send_cipher_ = nullptr;
NoiseCipherState *recv_cipher_ = nullptr;
NoiseHandshakeState *handshake_{nullptr};
NoiseCipherState *send_cipher_{nullptr};
NoiseCipherState *recv_cipher_{nullptr};
NoiseProtocolId nid_;
enum class State {

View File

@@ -340,6 +340,35 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::Me
return "UNKNOWN";
}
}
template<>
const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
switch (value) {
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR";
case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR";
default:
return "UNKNOWN";
}
}
bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2: {
this->api_version_major = value.as_uint32();
return true;
}
case 3: {
this->api_version_minor = value.as_uint32();
return true;
}
default:
return false;
}
}
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
@@ -350,7 +379,11 @@ bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value)
return false;
}
}
void HelloRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->client_info); }
void HelloRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->client_info);
buffer.encode_uint32(2, this->api_version_major);
buffer.encode_uint32(3, this->api_version_minor);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void HelloRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
@@ -358,6 +391,16 @@ void HelloRequest::dump_to(std::string &out) const {
out.append(" client_info: ");
out.append("'").append(this->client_info).append("'");
out.append("\n");
out.append(" api_version_major: ");
sprintf(buffer, "%u", this->api_version_major);
out.append(buffer);
out.append("\n");
out.append(" api_version_minor: ");
sprintf(buffer, "%u", this->api_version_minor);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
@@ -496,7 +539,7 @@ bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
return true;
}
case 11: {
this->has_bluetooth_proxy = value.as_bool();
this->bluetooth_proxy_version = value.as_uint32();
return true;
}
default:
@@ -548,7 +591,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(8, this->project_name);
buffer.encode_string(9, this->project_version);
buffer.encode_uint32(10, this->webserver_port);
buffer.encode_bool(11, this->has_bluetooth_proxy);
buffer.encode_uint32(11, this->bluetooth_proxy_version);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void DeviceInfoResponse::dump_to(std::string &out) const {
@@ -595,8 +638,9 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
out.append(buffer);
out.append("\n");
out.append(" has_bluetooth_proxy: ");
out.append(YESNO(this->has_bluetooth_proxy));
out.append(" bluetooth_proxy_version: ");
sprintf(buffer, "%u", this->bluetooth_proxy_version);
out.append(buffer);
out.append("\n");
out.append("}");
}
@@ -4872,7 +4916,7 @@ void SubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const
bool BluetoothServiceData::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2: {
this->data.push_back(value.as_uint32());
this->legacy_data.push_back(value.as_uint32());
return true;
}
default:
@@ -4885,15 +4929,20 @@ bool BluetoothServiceData::decode_length(uint32_t field_id, ProtoLengthDelimited
this->uuid = value.as_string();
return true;
}
case 3: {
this->data = value.as_string();
return true;
}
default:
return false;
}
}
void BluetoothServiceData::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->uuid);
for (auto &it : this->data) {
for (auto &it : this->legacy_data) {
buffer.encode_uint32(2, it, true);
}
buffer.encode_string(3, this->data);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothServiceData::dump_to(std::string &out) const {
@@ -4903,12 +4952,16 @@ void BluetoothServiceData::dump_to(std::string &out) const {
out.append("'").append(this->uuid).append("'");
out.append("\n");
for (const auto &it : this->data) {
out.append(" data: ");
for (const auto &it : this->legacy_data) {
out.append(" legacy_data: ");
sprintf(buffer, "%u", it);
out.append(buffer);
out.append("\n");
}
out.append(" data: ");
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
#endif
@@ -5000,6 +5053,699 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
out.append("}");
}
#endif
bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->request_type = value.as_enum<enums::BluetoothDeviceRequestType>();
return true;
}
default:
return false;
}
}
void BluetoothDeviceRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_enum<enums::BluetoothDeviceRequestType>(2, this->request_type);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDeviceRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothDeviceRequest {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" request_type: ");
out.append(proto_enum_to_string<enums::BluetoothDeviceRequestType>(this->request_type));
out.append("\n");
out.append("}");
}
#endif
bool BluetoothDeviceConnectionResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->connected = value.as_bool();
return true;
}
case 3: {
this->mtu = value.as_uint32();
return true;
}
case 4: {
this->error = value.as_int32();
return true;
}
default:
return false;
}
}
void BluetoothDeviceConnectionResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_bool(2, this->connected);
buffer.encode_uint32(3, this->mtu);
buffer.encode_int32(4, this->error);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothDeviceConnectionResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothDeviceConnectionResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" connected: ");
out.append(YESNO(this->connected));
out.append("\n");
out.append(" mtu: ");
sprintf(buffer, "%u", this->mtu);
out.append(buffer);
out.append("\n");
out.append(" error: ");
sprintf(buffer, "%d", this->error);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTGetServicesRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
default:
return false;
}
}
void BluetoothGATTGetServicesRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); }
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTGetServicesRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTGetServicesRequest {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTDescriptor::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->uuid.push_back(value.as_uint64());
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
default:
return false;
}
}
void BluetoothGATTDescriptor::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->uuid) {
buffer.encode_uint64(1, it, true);
}
buffer.encode_uint32(2, this->handle);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTDescriptor::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTDescriptor {\n");
for (const auto &it : this->uuid) {
out.append(" uuid: ");
sprintf(buffer, "%llu", it);
out.append(buffer);
out.append("\n");
}
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTCharacteristic::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->uuid.push_back(value.as_uint64());
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
case 3: {
this->properties = value.as_uint32();
return true;
}
default:
return false;
}
}
bool BluetoothGATTCharacteristic::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 4: {
this->descriptors.push_back(value.as_message<BluetoothGATTDescriptor>());
return true;
}
default:
return false;
}
}
void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->uuid) {
buffer.encode_uint64(1, it, true);
}
buffer.encode_uint32(2, this->handle);
buffer.encode_uint32(3, this->properties);
for (auto &it : this->descriptors) {
buffer.encode_message<BluetoothGATTDescriptor>(4, it, true);
}
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTCharacteristic::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTCharacteristic {\n");
for (const auto &it : this->uuid) {
out.append(" uuid: ");
sprintf(buffer, "%llu", it);
out.append(buffer);
out.append("\n");
}
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append(" properties: ");
sprintf(buffer, "%u", this->properties);
out.append(buffer);
out.append("\n");
for (const auto &it : this->descriptors) {
out.append(" descriptors: ");
it.dump_to(out);
out.append("\n");
}
out.append("}");
}
#endif
bool BluetoothGATTService::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->uuid.push_back(value.as_uint64());
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
default:
return false;
}
}
bool BluetoothGATTService::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 3: {
this->characteristics.push_back(value.as_message<BluetoothGATTCharacteristic>());
return true;
}
default:
return false;
}
}
void BluetoothGATTService::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->uuid) {
buffer.encode_uint64(1, it, true);
}
buffer.encode_uint32(2, this->handle);
for (auto &it : this->characteristics) {
buffer.encode_message<BluetoothGATTCharacteristic>(3, it, true);
}
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTService::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTService {\n");
for (const auto &it : this->uuid) {
out.append(" uuid: ");
sprintf(buffer, "%llu", it);
out.append(buffer);
out.append("\n");
}
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
for (const auto &it : this->characteristics) {
out.append(" characteristics: ");
it.dump_to(out);
out.append("\n");
}
out.append("}");
}
#endif
bool BluetoothGATTGetServicesResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
default:
return false;
}
}
bool BluetoothGATTGetServicesResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2: {
this->services.push_back(value.as_message<BluetoothGATTService>());
return true;
}
default:
return false;
}
}
void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
for (auto &it : this->services) {
buffer.encode_message<BluetoothGATTService>(2, it, true);
}
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTGetServicesResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTGetServicesResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
for (const auto &it : this->services) {
out.append(" services: ");
it.dump_to(out);
out.append("\n");
}
out.append("}");
}
#endif
bool BluetoothGATTGetServicesDoneResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
default:
return false;
}
}
void BluetoothGATTGetServicesDoneResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTGetServicesDoneResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTGetServicesDoneResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTReadRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
default:
return false;
}
}
void BluetoothGATTReadRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTReadRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTReadRequest {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTReadResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
default:
return false;
}
}
bool BluetoothGATTReadResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 3: {
this->data = value.as_string();
return true;
}
default:
return false;
}
}
void BluetoothGATTReadResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTReadResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTReadResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append(" data: ");
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTWriteRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
case 3: {
this->response = value.as_bool();
return true;
}
default:
return false;
}
}
bool BluetoothGATTWriteRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 4: {
this->data = value.as_string();
return true;
}
default:
return false;
}
}
void BluetoothGATTWriteRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_bool(3, this->response);
buffer.encode_string(4, this->data);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTWriteRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTWriteRequest {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append(" response: ");
out.append(YESNO(this->response));
out.append("\n");
out.append(" data: ");
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTReadDescriptorRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
default:
return false;
}
}
void BluetoothGATTReadDescriptorRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTReadDescriptorRequest {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTWriteDescriptorRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
default:
return false;
}
}
bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 3: {
this->data = value.as_string();
return true;
}
default:
return false;
}
}
void BluetoothGATTWriteDescriptorRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTWriteDescriptorRequest {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append(" data: ");
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTNotifyRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
case 3: {
this->enable = value.as_bool();
return true;
}
default:
return false;
}
}
void BluetoothGATTNotifyRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_bool(3, this->enable);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTNotifyRequest::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTNotifyRequest {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append(" enable: ");
out.append(YESNO(this->enable));
out.append("\n");
out.append("}");
}
#endif
bool BluetoothGATTNotifyDataResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->address = value.as_uint64();
return true;
}
case 2: {
this->handle = value.as_uint32();
return true;
}
default:
return false;
}
}
bool BluetoothGATTNotifyDataResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 3: {
this->data = value.as_string();
return true;
}
default:
return false;
}
}
void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothGATTNotifyDataResponse {\n");
out.append(" address: ");
sprintf(buffer, "%llu", this->address);
out.append(buffer);
out.append("\n");
out.append(" handle: ");
sprintf(buffer, "%u", this->handle);
out.append(buffer);
out.append("\n");
out.append(" data: ");
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
#endif
void SubscribeBluetoothConnectionsFreeRequest::encode(ProtoWriteBuffer buffer) const {}
#ifdef HAS_PROTO_MESSAGE_DUMP
void SubscribeBluetoothConnectionsFreeRequest::dump_to(std::string &out) const {
out.append("SubscribeBluetoothConnectionsFreeRequest {}");
}
#endif
bool BluetoothConnectionsFreeResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {
this->free = value.as_uint32();
return true;
}
case 2: {
this->limit = value.as_uint32();
return true;
}
default:
return false;
}
}
void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(1, this->free);
buffer.encode_uint32(2, this->limit);
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void BluetoothConnectionsFreeResponse::dump_to(std::string &out) const {
__attribute__((unused)) char buffer[64];
out.append("BluetoothConnectionsFreeResponse {\n");
out.append(" free: ");
sprintf(buffer, "%u", this->free);
out.append(buffer);
out.append("\n");
out.append(" limit: ");
sprintf(buffer, "%u", this->limit);
out.append(buffer);
out.append("\n");
out.append("}");
}
#endif
} // namespace api
} // namespace esphome

View File

@@ -155,12 +155,20 @@ enum MediaPlayerCommand : uint32_t {
MEDIA_PLAYER_COMMAND_MUTE = 3,
MEDIA_PLAYER_COMMAND_UNMUTE = 4,
};
enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0,
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2,
BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
};
} // namespace enums
class HelloRequest : public ProtoMessage {
public:
std::string client_info{};
uint32_t api_version_major{0};
uint32_t api_version_minor{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -168,6 +176,7 @@ class HelloRequest : public ProtoMessage {
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class HelloResponse : public ProtoMessage {
public:
@@ -263,7 +272,7 @@ class DeviceInfoResponse : public ProtoMessage {
std::string project_name{};
std::string project_version{};
uint32_t webserver_port{0};
bool has_bluetooth_proxy{false};
uint32_t bluetooth_proxy_version{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1227,7 +1236,8 @@ class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
class BluetoothServiceData : public ProtoMessage {
public:
std::string uuid{};
std::vector<uint32_t> data{};
std::vector<uint32_t> legacy_data{};
std::string data{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1254,6 +1264,223 @@ class BluetoothLEAdvertisementResponse : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothDeviceRequest : public ProtoMessage {
public:
uint64_t address{0};
enums::BluetoothDeviceRequestType request_type{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothDeviceConnectionResponse : public ProtoMessage {
public:
uint64_t address{0};
bool connected{false};
uint32_t mtu{0};
int32_t error{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTGetServicesRequest : public ProtoMessage {
public:
uint64_t address{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTDescriptor : public ProtoMessage {
public:
std::vector<uint64_t> uuid{};
uint32_t handle{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTCharacteristic : public ProtoMessage {
public:
std::vector<uint64_t> uuid{};
uint32_t handle{0};
uint32_t properties{0};
std::vector<BluetoothGATTDescriptor> descriptors{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTService : public ProtoMessage {
public:
std::vector<uint64_t> uuid{};
uint32_t handle{0};
std::vector<BluetoothGATTCharacteristic> characteristics{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTGetServicesResponse : public ProtoMessage {
public:
uint64_t address{0};
std::vector<BluetoothGATTService> services{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTGetServicesDoneResponse : public ProtoMessage {
public:
uint64_t address{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTReadRequest : public ProtoMessage {
public:
uint64_t address{0};
uint32_t handle{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTReadResponse : public ProtoMessage {
public:
uint64_t address{0};
uint32_t handle{0};
std::string data{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTWriteRequest : public ProtoMessage {
public:
uint64_t address{0};
uint32_t handle{0};
bool response{false};
std::string data{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTReadDescriptorRequest : public ProtoMessage {
public:
uint64_t address{0};
uint32_t handle{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTWriteDescriptorRequest : public ProtoMessage {
public:
uint64_t address{0};
uint32_t handle{0};
std::string data{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTNotifyRequest : public ProtoMessage {
public:
uint64_t address{0};
uint32_t handle{0};
bool enable{false};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class BluetoothGATTNotifyDataResponse : public ProtoMessage {
public:
uint64_t address{0};
uint32_t handle{0};
std::string data{};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class SubscribeBluetoothConnectionsFreeRequest : public ProtoMessage {
public:
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
class BluetoothConnectionsFreeResponse : public ProtoMessage {
public:
uint32_t free{0};
uint32_t limit{0};
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
} // namespace api
} // namespace esphome

View File

@@ -336,6 +336,71 @@ bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const Blu
return this->send_message_<BluetoothLEAdvertisementResponse>(msg, 67);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_device_connection_response(const BluetoothDeviceConnectionResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_device_connection_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothDeviceConnectionResponse>(msg, 69);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_gatt_get_services_response(const BluetoothGATTGetServicesResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_gatt_get_services_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothGATTGetServicesResponse>(msg, 71);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_gatt_get_services_done_response(
const BluetoothGATTGetServicesDoneResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_gatt_get_services_done_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothGATTGetServicesDoneResponse>(msg, 72);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_gatt_read_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothGATTReadResponse>(msg, 74);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_gatt_notify_data_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothGATTNotifyDataResponse>(msg, 79);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_connections_free_response(const BluetoothConnectionsFreeResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_connections_free_response: %s", msg.dump().c_str());
#endif
return this->send_message_<BluetoothConnectionsFreeResponse>(msg, 81);
}
#endif
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
switch (msg_type) {
case 1: {
@@ -612,6 +677,94 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
this->on_subscribe_bluetooth_le_advertisements_request(msg);
break;
}
case 68: {
#ifdef USE_BLUETOOTH_PROXY
BluetoothDeviceRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_device_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_device_request(msg);
#endif
break;
}
case 70: {
#ifdef USE_BLUETOOTH_PROXY
BluetoothGATTGetServicesRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_get_services_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_get_services_request(msg);
#endif
break;
}
case 73: {
#ifdef USE_BLUETOOTH_PROXY
BluetoothGATTReadRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_read_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_read_request(msg);
#endif
break;
}
case 75: {
#ifdef USE_BLUETOOTH_PROXY
BluetoothGATTWriteRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_write_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_write_request(msg);
#endif
break;
}
case 76: {
#ifdef USE_BLUETOOTH_PROXY
BluetoothGATTReadDescriptorRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_read_descriptor_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_read_descriptor_request(msg);
#endif
break;
}
case 77: {
#ifdef USE_BLUETOOTH_PROXY
BluetoothGATTWriteDescriptorRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_write_descriptor_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_write_descriptor_request(msg);
#endif
break;
}
case 78: {
#ifdef USE_BLUETOOTH_PROXY
BluetoothGATTNotifyRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_notify_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_notify_request(msg);
#endif
break;
}
case 80: {
#ifdef USE_BLUETOOTH_PROXY
SubscribeBluetoothConnectionsFreeRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_bluetooth_connections_free_request(msg);
#endif
break;
}
default:
return false;
}
@@ -708,18 +861,6 @@ void APIServerConnection::on_subscribe_home_assistant_states_request(const Subsc
}
this->subscribe_home_assistant_states(msg);
}
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->subscribe_bluetooth_le_advertisements(msg);
}
void APIServerConnection::on_get_time_request(const GetTimeRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
@@ -884,6 +1025,126 @@ void APIServerConnection::on_media_player_command_request(const MediaPlayerComma
this->media_player_command(msg);
}
#endif
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->subscribe_bluetooth_le_advertisements(msg);
}
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_device_request(const BluetoothDeviceRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->bluetooth_device_request(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->bluetooth_gatt_get_services(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->bluetooth_gatt_read(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->bluetooth_gatt_write(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->bluetooth_gatt_read_descriptor(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->bluetooth_gatt_write_descriptor(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->bluetooth_gatt_notify(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_subscribe_bluetooth_connections_free_request(
const SubscribeBluetoothConnectionsFreeRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
BluetoothConnectionsFreeResponse ret = this->subscribe_bluetooth_connections_free(msg);
if (!this->send_bluetooth_connections_free_response(ret)) {
this->on_fatal_error();
}
}
#endif
} // namespace api
} // namespace esphome

View File

@@ -158,6 +158,48 @@ class APIServerConnectionBase : public ProtoService {
const SubscribeBluetoothLEAdvertisementsRequest &value){};
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_device_request(const BluetoothDeviceRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_device_connection_response(const BluetoothDeviceConnectionResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_gatt_get_services_response(const BluetoothGATTGetServicesResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_gatt_get_services_done_response(const BluetoothGATTGetServicesDoneResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_connections_free_response(const BluetoothConnectionsFreeResponse &msg);
#endif
protected:
bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
@@ -175,7 +217,6 @@ class APIServerConnection : public APIServerConnectionBase {
virtual void subscribe_logs(const SubscribeLogsRequest &msg) = 0;
virtual void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) = 0;
virtual void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) = 0;
virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
virtual GetTimeResponse get_time(const GetTimeRequest &msg) = 0;
virtual void execute_service(const ExecuteServiceRequest &msg) = 0;
#ifdef USE_COVER
@@ -210,6 +251,32 @@ class APIServerConnection : public APIServerConnectionBase {
#endif
#ifdef USE_MEDIA_PLAYER
virtual void media_player_command(const MediaPlayerCommandRequest &msg) = 0;
#endif
virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_device_request(const BluetoothDeviceRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_gatt_get_services(const BluetoothGATTGetServicesRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_gatt_read(const BluetoothGATTReadRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_gatt_write(const BluetoothGATTWriteRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_gatt_read_descriptor(const BluetoothGATTReadDescriptorRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_gatt_write_descriptor(const BluetoothGATTWriteDescriptorRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free(
const SubscribeBluetoothConnectionsFreeRequest &msg) = 0;
#endif
protected:
void on_hello_request(const HelloRequest &msg) override;
@@ -222,7 +289,6 @@ class APIServerConnection : public APIServerConnectionBase {
void on_subscribe_logs_request(const SubscribeLogsRequest &msg) override;
void on_subscribe_homeassistant_services_request(const SubscribeHomeassistantServicesRequest &msg) override;
void on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) override;
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
void on_get_time_request(const GetTimeRequest &msg) override;
void on_execute_service_request(const ExecuteServiceRequest &msg) override;
#ifdef USE_COVER
@@ -257,6 +323,31 @@ class APIServerConnection : public APIServerConnectionBase {
#endif
#ifdef USE_MEDIA_PLAYER
void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override;
#endif
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_gatt_get_services_request(const BluetoothGATTGetServicesRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_gatt_read_request(const BluetoothGATTReadRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_gatt_write_request(const BluetoothGATTWriteRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_gatt_read_descriptor_request(const BluetoothGATTReadDescriptorRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_gatt_write_descriptor_request(const BluetoothGATTWriteDescriptorRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_gatt_notify_request(const BluetoothGATTNotifyRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) override;
#endif
};

View File

@@ -297,6 +297,51 @@ void APIServer::send_bluetooth_le_advertisement(const BluetoothLEAdvertisementRe
client->send_bluetooth_le_advertisement(call);
}
}
void APIServer::send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu, esp_err_t error) {
BluetoothDeviceConnectionResponse call;
call.address = address;
call.connected = connected;
call.mtu = mtu;
call.error = error;
for (auto &client : this->clients_) {
client->send_bluetooth_device_connection_response(call);
}
}
void APIServer::send_bluetooth_connections_free(uint8_t free, uint8_t limit) {
BluetoothConnectionsFreeResponse call;
call.free = free;
call.limit = limit;
for (auto &client : this->clients_) {
client->send_bluetooth_connections_free_response(call);
}
}
void APIServer::send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_read_response(call);
}
}
void APIServer::send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_notify_data_response(call);
}
}
void APIServer::send_bluetooth_gatt_services(const BluetoothGATTGetServicesResponse &call) {
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_get_services_response(call);
}
}
void APIServer::send_bluetooth_gatt_services_done(uint64_t address) {
BluetoothGATTGetServicesDoneResponse call;
call.address = address;
for (auto &client : this->clients_) {
client->send_bluetooth_gatt_get_services_done_response(call);
}
}
#endif
APIServer::APIServer() { global_api_server = this; }
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,

View File

@@ -75,6 +75,12 @@ class APIServer : public Component, public Controller {
void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
#ifdef USE_BLUETOOTH_PROXY
void send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call);
void send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu, esp_err_t error = ESP_OK);
void send_bluetooth_connections_free(uint8_t free, uint8_t limit);
void send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call);
void send_bluetooth_gatt_notify_data_response(const BluetoothGATTNotifyDataResponse &call);
void send_bluetooth_gatt_services(const BluetoothGATTGetServicesResponse &call);
void send_bluetooth_gatt_services_done(uint64_t address);
#endif
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
#ifdef USE_HOMEASSISTANT_TIME

View File

@@ -92,9 +92,9 @@ class AS3935Component : public Component {
virtual void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) = 0;
sensor::Sensor *distance_sensor_;
sensor::Sensor *energy_sensor_;
binary_sensor::BinarySensor *thunder_alert_binary_sensor_;
sensor::Sensor *distance_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
binary_sensor::BinarySensor *thunder_alert_binary_sensor_{nullptr};
GPIOPin *irq_pin_;
bool indoor_;

View File

@@ -128,9 +128,9 @@ uint8_t BedJetHub::write_bedjet_packet_(BedjetPacket *pkt) {
}
return -1;
}
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_cmd_,
pkt->data_length + 1, (uint8_t *) &pkt->command, ESP_GATT_WRITE_TYPE_NO_RSP,
ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
this->char_handle_cmd_, pkt->data_length + 1, (uint8_t *) &pkt->command,
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
return status;
}
@@ -138,13 +138,13 @@ uint8_t BedJetHub::write_bedjet_packet_(BedjetPacket *pkt) {
uint8_t BedJetHub::set_notify_(const bool enable) {
uint8_t status;
if (enable) {
status = esp_ble_gattc_register_for_notify(this->parent_->gattc_if, this->parent_->remote_bda,
status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
this->char_handle_status_);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
}
} else {
status = esp_ble_gattc_unregister_for_notify(this->parent_->gattc_if, this->parent_->remote_bda,
status = esp_ble_gattc_unregister_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
this->char_handle_status_);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_unregister_for_notify failed, status=%d", this->get_name().c_str(), status);
@@ -204,8 +204,8 @@ bool BedJetHub::discover_characteristics_() {
result = false;
} else {
this->char_handle_name_ = chr->handle;
auto status = esp_ble_gattc_read_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_name_,
ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_read_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
this->char_handle_name_, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGI(TAG, "[%s] Unable to read name characteristic: %d", this->get_name().c_str(), status);
}
@@ -230,22 +230,6 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
this->dispatch_state_(false);
break;
}
case ESP_GATTC_OPEN_EVT: {
// FIXME: bug in BLEClient
this->parent_->conn_id = param->open.conn_id;
this->open_conn_id_ = param->open.conn_id;
break;
}
case ESP_GATTC_CONNECT_EVT: {
if (this->parent_->conn_id != param->connect.conn_id && this->open_conn_id_ != 0xff) {
// FIXME: bug in BLEClient
ESP_LOGW(TAG, "[%s] CONNECT_EVT unexpected conn_id; open=%d, parent=%d, param=%d", this->get_name().c_str(),
this->open_conn_id_, this->parent_->conn_id, param->connect.conn_id);
this->parent_->conn_id = this->open_conn_id_;
}
break;
}
case ESP_GATTC_SEARCH_CMPL_EVT: {
auto result = this->discover_characteristics_();
@@ -301,7 +285,7 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
break;
}
case ESP_GATTC_READ_CHAR_EVT: {
if (param->read.conn_id != this->parent_->conn_id)
if (param->read.conn_id != this->parent_->get_conn_id())
break;
if (param->read.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
@@ -358,9 +342,9 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
if (this->processing_)
break;
if (param->notify.conn_id != this->parent_->conn_id) {
if (param->notify.conn_id != this->parent_->get_conn_id()) {
ESP_LOGW(TAG, "[%s] Received notify event for unexpected parent conn: expect %x, got %x",
this->get_name().c_str(), this->parent_->conn_id, param->notify.conn_id);
this->get_name().c_str(), this->parent_->get_conn_id(), param->notify.conn_id);
// FIXME: bug in BLEClient holding wrong conn_id.
}
@@ -394,7 +378,7 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
if (needs_extra) {
// This means the packet was partial, so read the status characteristic to get the second part.
// Ideally this will complete quickly. We won't process additional notification events until it does.
auto status = esp_ble_gattc_read_char(this->parent_->gattc_if, this->parent_->conn_id,
auto status = esp_ble_gattc_read_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
this->char_handle_status_, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGI(TAG, "[%s] Unable to read extended status packet", this->get_name().c_str());
@@ -438,15 +422,15 @@ uint8_t BedJetHub::write_notify_config_descriptor_(bool enable) {
// NOTE: BLEClient uses `uint8_t*` of length 1, but BLE spec requires 16 bits.
uint16_t notify_en = enable ? 1 : 0;
auto status =
esp_ble_gattc_write_char_descr(this->parent_->gattc_if, this->parent_->conn_id, handle, sizeof(notify_en),
(uint8_t *) &notify_en, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_write_char_descr(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), handle,
sizeof(notify_en), (uint8_t *) &notify_en, ESP_GATT_WRITE_TYPE_RSP,
ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "esp_ble_gattc_write_char_descr error, status=%d", status);
return status;
}
ESP_LOGD(TAG, "[%s] wrote notify=%s to status config 0x%04x, for conn %d", this->get_name().c_str(),
enable ? "true" : "false", handle, this->parent_->conn_id);
enable ? "true" : "false", handle, this->parent_->get_conn_id());
return ESP_GATT_OK;
}
@@ -500,7 +484,7 @@ void BedJetHub::update() { this->dispatch_status_(); }
void BedJetHub::dump_config() {
ESP_LOGCONFIG(TAG, "BedJet Hub '%s'", this->get_name().c_str());
ESP_LOGCONFIG(TAG, " ble_client.app_id: %d", this->parent()->app_id);
ESP_LOGCONFIG(TAG, " ble_client.conn_id: %d", this->parent()->conn_id);
ESP_LOGCONFIG(TAG, " ble_client.conn_id: %d", this->parent()->get_conn_id());
LOG_UPDATE_INTERVAL(this)
ESP_LOGCONFIG(TAG, " Child components (%d):", this->children_.size());
for (auto *child : this->children_) {

View File

@@ -167,8 +167,6 @@ class BedJetHub : public esphome::ble_client::BLEClientNode, public PollingCompo
uint16_t char_handle_status_;
uint16_t config_descr_status_;
uint8_t open_conn_id_ = -1;
uint8_t write_notify_config_descriptor_(bool enable);
};

View File

@@ -75,16 +75,16 @@ class BL0939 : public PollingComponent, public uart::UARTDevice {
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_1_;
sensor::Sensor *current_sensor_2_;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_1_{nullptr};
sensor::Sensor *current_sensor_2_{nullptr};
// NB This may be negative as the circuits is seemingly able to measure
// power in both directions
sensor::Sensor *power_sensor_1_;
sensor::Sensor *power_sensor_2_;
sensor::Sensor *energy_sensor_1_;
sensor::Sensor *energy_sensor_2_;
sensor::Sensor *energy_sensor_sum_;
sensor::Sensor *power_sensor_1_{nullptr};
sensor::Sensor *power_sensor_2_{nullptr};
sensor::Sensor *energy_sensor_1_{nullptr};
sensor::Sensor *energy_sensor_2_{nullptr};
sensor::Sensor *energy_sensor_sum_{nullptr};
// Divide by this to turn into Watt
float power_reference_ = BL0939_PREF;

View File

@@ -75,14 +75,14 @@ class BL0940 : public PollingComponent, public uart::UARTDevice {
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
// NB This may be negative as the circuits is seemingly able to measure
// power in both directions
sensor::Sensor *power_sensor_;
sensor::Sensor *energy_sensor_;
sensor::Sensor *internal_temperature_sensor_;
sensor::Sensor *external_temperature_sensor_;
sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
sensor::Sensor *internal_temperature_sensor_{nullptr};
sensor::Sensor *external_temperature_sensor_{nullptr};
// Max difference between two measurements of the temperature. Used to avoid noise.
float max_temperature_diff_{0};

View File

@@ -43,13 +43,13 @@ class BL0942 : public PollingComponent, public uart::UARTDevice {
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
// NB This may be negative as the circuits is seemingly able to measure
// power in both directions
sensor::Sensor *power_sensor_;
sensor::Sensor *energy_sensor_;
sensor::Sensor *frequency_sensor_;
sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
sensor::Sensor *frequency_sensor_{nullptr};
// Divide by this to turn into Watt
float power_reference_ = BL0942_PREF;

View File

@@ -1,6 +1,6 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import esp32_ble_tracker
from esphome.components import esp32_ble_tracker, esp32_ble_client
from esphome.const import (
CONF_CHARACTERISTIC_UUID,
CONF_ID,
@@ -14,13 +14,12 @@ from esphome.const import (
)
from esphome import automation
AUTO_LOAD = ["esp32_ble_client"]
CODEOWNERS = ["@buxtronix"]
DEPENDENCIES = ["esp32_ble_tracker"]
ble_client_ns = cg.esphome_ns.namespace("ble_client")
BLEClient = ble_client_ns.class_(
"BLEClient", cg.Component, esp32_ble_tracker.ESPBTClient
)
BLEClient = ble_client_ns.class_("BLEClient", esp32_ble_client.BLEClientBase)
BLEClientNode = ble_client_ns.class_("BLEClientNode")
BLEClientNodeConstRef = BLEClientNode.operator("ref").operator("const")
# Triggers

View File

@@ -1,8 +1,8 @@
#include "automation.h"
#include <esp_bt_defs.h>
#include <esp_gap_ble_api.h>
#include <esp_gattc_api.h>
#include <esp_bt_defs.h>
#include "esphome/core/log.h"
@@ -31,8 +31,8 @@ void BLEWriterClientNode::write(const std::vector<uint8_t> &value) {
}
ESP_LOGVV(TAG, "Will write %d bytes: %s", value.size(), format_hex_pretty(value).c_str());
esp_err_t err =
esp_ble_gattc_write_char(this->parent()->gattc_if, this->parent()->conn_id, this->ble_char_handle_, value.size(),
const_cast<uint8_t *>(value.data()), write_type, ESP_GATT_AUTH_REQ_NONE);
esp_ble_gattc_write_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->ble_char_handle_,
value.size(), const_cast<uint8_t *>(value.data()), write_type, ESP_GATT_AUTH_REQ_NONE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error writing to characteristic: %s!", esp_err_to_name(err));
}

View File

@@ -28,7 +28,8 @@ class BLEClientDisconnectTrigger : public Trigger<>, public BLEClientNode {
void loop() override {}
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override {
if (event == ESP_GATTC_DISCONNECT_EVT && memcmp(param->disconnect.remote_bda, this->parent_->remote_bda, 6) == 0)
if (event == ESP_GATTC_DISCONNECT_EVT &&
memcmp(param->disconnect.remote_bda, this->parent_->get_remote_bda(), 6) == 0)
this->trigger();
if (event == ESP_GATTC_SEARCH_CMPL_EVT)
this->node_state = espbt::ClientState::ESTABLISHED;

View File

@@ -1,8 +1,9 @@
#include "esphome/core/log.h"
#include "ble_client.h"
#include "esphome/components/esp32_ble_client/ble_client_base.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "ble_client.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
@@ -11,22 +12,13 @@ namespace ble_client {
static const char *const TAG = "ble_client";
float BLEClient::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; }
void BLEClient::setup() {
auto ret = esp_ble_gattc_app_register(this->app_id);
if (ret) {
ESP_LOGE(TAG, "gattc app register failed. app_id=%d code=%d", this->app_id, ret);
this->mark_failed();
}
this->set_states_(espbt::ClientState::IDLE);
BLEClientBase::setup();
this->enabled = true;
}
void BLEClient::loop() {
if (this->state() == espbt::ClientState::DISCOVERED) {
this->connect();
}
BLEClientBase::loop();
for (auto *node : this->nodes_)
node->loop();
}
@@ -39,34 +31,7 @@ void BLEClient::dump_config() {
bool BLEClient::parse_device(const espbt::ESPBTDevice &device) {
if (!this->enabled)
return false;
if (device.address_uint64() != this->address)
return false;
if (this->state() != espbt::ClientState::IDLE)
return false;
ESP_LOGD(TAG, "Found device at MAC address [%s]", device.address_str().c_str());
this->set_states_(espbt::ClientState::DISCOVERED);
auto addr = device.address_uint64();
this->remote_bda[0] = (addr >> 40) & 0xFF;
this->remote_bda[1] = (addr >> 32) & 0xFF;
this->remote_bda[2] = (addr >> 24) & 0xFF;
this->remote_bda[3] = (addr >> 16) & 0xFF;
this->remote_bda[4] = (addr >> 8) & 0xFF;
this->remote_bda[5] = (addr >> 0) & 0xFF;
this->remote_addr_type = device.get_address_type();
return true;
}
std::string BLEClient::address_str() const {
char buf[20];
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", (uint8_t)(this->address >> 40) & 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 >> 0) & 0xff);
std::string ret;
ret = buf;
return ret;
return BLEClientBase::parse_device(device);
}
void BLEClient::set_enabled(bool enabled) {
@@ -74,7 +39,7 @@ void BLEClient::set_enabled(bool enabled) {
return;
if (!enabled && this->state() != espbt::ClientState::IDLE) {
ESP_LOGI(TAG, "[%s] Disabling BLE client.", this->address_str().c_str());
auto ret = esp_ble_gattc_close(this->gattc_if, this->conn_id);
auto ret = esp_ble_gattc_close(this->gattc_if_, this->conn_id_);
if (ret) {
ESP_LOGW(TAG, "esp_ble_gattc_close error, address=%s status=%d", this->address_str().c_str(), ret);
}
@@ -82,125 +47,12 @@ void BLEClient::set_enabled(bool enabled) {
this->enabled = enabled;
}
void BLEClient::connect() {
ESP_LOGI(TAG, "Attempting BLE connection to %s", this->address_str().c_str());
auto ret = esp_ble_gattc_open(this->gattc_if, this->remote_bda, this->remote_addr_type, true);
if (ret) {
ESP_LOGW(TAG, "esp_ble_gattc_open error, address=%s status=%d", this->address_str().c_str(), ret);
this->set_states_(espbt::ClientState::IDLE);
} else {
this->set_states_(espbt::ClientState::CONNECTING);
}
}
void BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_if,
esp_ble_gattc_cb_param_t *param) {
if (event == ESP_GATTC_REG_EVT && this->app_id != param->reg.app_id)
return;
if (event != ESP_GATTC_REG_EVT && esp_gattc_if != ESP_GATT_IF_NONE && esp_gattc_if != this->gattc_if)
return;
bool all_established = this->all_nodes_established_();
switch (event) {
case ESP_GATTC_REG_EVT: {
if (param->reg.status == ESP_GATT_OK) {
ESP_LOGV(TAG, "gattc registered app id %d", this->app_id);
this->gattc_if = esp_gattc_if;
} else {
ESP_LOGE(TAG, "gattc app registration failed id=%d code=%d", param->reg.app_id, param->reg.status);
}
break;
}
case ESP_GATTC_OPEN_EVT: {
ESP_LOGV(TAG, "[%s] ESP_GATTC_OPEN_EVT", this->address_str().c_str());
this->conn_id = param->open.conn_id;
if (param->open.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "connect to %s failed, status=%d", this->address_str().c_str(), param->open.status);
this->set_states_(espbt::ClientState::IDLE);
break;
}
break;
}
case ESP_GATTC_CONNECT_EVT: {
ESP_LOGV(TAG, "[%s] ESP_GATTC_CONNECT_EVT", this->address_str().c_str());
if (this->conn_id != param->connect.conn_id) {
ESP_LOGD(TAG, "[%s] Unexpected conn_id in CONNECT_EVT: param conn=%d, open conn=%d",
this->address_str().c_str(), param->connect.conn_id, this->conn_id);
}
auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if, param->connect.conn_id);
if (ret) {
ESP_LOGW(TAG, "esp_ble_gattc_send_mtu_req failed, status=%x", ret);
}
break;
}
case ESP_GATTC_CFG_MTU_EVT: {
if (param->cfg_mtu.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "cfg_mtu to %s failed, mtu %d, status %d", this->address_str().c_str(), param->cfg_mtu.mtu,
param->cfg_mtu.status);
this->set_states_(espbt::ClientState::IDLE);
break;
}
ESP_LOGV(TAG, "cfg_mtu status %d, mtu %d", param->cfg_mtu.status, param->cfg_mtu.mtu);
esp_ble_gattc_search_service(esp_gattc_if, param->cfg_mtu.conn_id, nullptr);
break;
}
case ESP_GATTC_DISCONNECT_EVT: {
if (memcmp(param->disconnect.remote_bda, this->remote_bda, 6) != 0) {
return;
}
ESP_LOGV(TAG, "[%s] ESP_GATTC_DISCONNECT_EVT, reason %d", this->address_str().c_str(), param->disconnect.reason);
for (auto &svc : this->services_)
delete svc; // NOLINT(cppcoreguidelines-owning-memory)
this->services_.clear();
this->set_states_(espbt::ClientState::IDLE);
break;
}
case ESP_GATTC_SEARCH_RES_EVT: {
BLEService *ble_service = new BLEService(); // NOLINT(cppcoreguidelines-owning-memory)
ble_service->uuid = espbt::ESPBTUUID::from_uuid(param->search_res.srvc_id.uuid);
ble_service->start_handle = param->search_res.start_handle;
ble_service->end_handle = param->search_res.end_handle;
ble_service->client = this;
this->services_.push_back(ble_service);
break;
}
case ESP_GATTC_SEARCH_CMPL_EVT: {
ESP_LOGV(TAG, "[%s] ESP_GATTC_SEARCH_CMPL_EVT", this->address_str().c_str());
for (auto &svc : this->services_) {
ESP_LOGI(TAG, "Service UUID: %s", svc->uuid.to_string().c_str());
ESP_LOGI(TAG, " start_handle: 0x%x end_handle: 0x%x", svc->start_handle, svc->end_handle);
svc->parse_characteristics();
}
this->set_states_(espbt::ClientState::CONNECTED);
this->set_state(espbt::ClientState::ESTABLISHED);
break;
}
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
auto *descr = this->get_config_descriptor(param->reg_for_notify.handle);
if (descr == nullptr) {
ESP_LOGW(TAG, "No descriptor found for notify of handle 0x%x", param->reg_for_notify.handle);
break;
}
if (descr->uuid.get_uuid().len != ESP_UUID_LEN_16 ||
descr->uuid.get_uuid().uuid.uuid16 != ESP_GATT_UUID_CHAR_CLIENT_CONFIG) {
ESP_LOGW(TAG, "Handle 0x%x (uuid %s) is not a client config char uuid", param->reg_for_notify.handle,
descr->uuid.to_string().c_str());
break;
}
uint16_t notify_en = 1;
auto status =
esp_ble_gattc_write_char_descr(this->gattc_if, this->conn_id, descr->handle, sizeof(notify_en),
(uint8_t *) &notify_en, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "esp_ble_gattc_write_char_descr error, status=%d", status);
}
break;
}
BLEClientBase::gattc_event_handler(event, esp_gattc_if, param);
default:
break;
}
for (auto *node : this->nodes_)
node->gattc_event_handler(event, esp_gattc_if, param);
@@ -212,237 +64,20 @@ void BLEClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t es
}
}
void BLEClient::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
switch (event) {
// This event is sent by the server when it requests security
case ESP_GAP_BLE_SEC_REQ_EVT:
ESP_LOGV(TAG, "ESP_GAP_BLE_SEC_REQ_EVT %x", event);
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
break;
// This event is sent once authentication has completed
case ESP_GAP_BLE_AUTH_CMPL_EVT:
esp_bd_addr_t bd_addr;
memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));
ESP_LOGI(TAG, "auth complete. remote BD_ADDR: %s", format_hex(bd_addr, 6).c_str());
if (!param->ble_security.auth_cmpl.success) {
ESP_LOGE(TAG, "auth fail reason = 0x%x", param->ble_security.auth_cmpl.fail_reason);
} else {
ESP_LOGV(TAG, "auth success. address type = %d auth mode = %d", param->ble_security.auth_cmpl.addr_type,
param->ble_security.auth_cmpl.auth_mode);
}
break;
// There are other events we'll want to implement at some point to support things like pass key
// https://github.com/espressif/esp-idf/blob/cba69dd088344ed9d26739f04736ae7a37541b3a/examples/bluetooth/bluedroid/ble/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md
default:
break;
}
void BLEClient::set_state(espbt::ClientState state) {
BLEClientBase::set_state(state);
for (auto &node : nodes_)
node->node_state = state;
}
// Parse GATT values into a float for a sensor.
// Ref: https://www.bluetooth.com/specifications/assigned-numbers/format-types/
float BLEClient::parse_char_value(uint8_t *value, uint16_t length) {
// A length of one means a single octet value.
if (length == 0)
return 0;
if (length == 1)
return (float) ((uint8_t) value[0]);
switch (value[0]) {
case 0x1: // boolean.
case 0x2: // 2bit.
case 0x3: // nibble.
case 0x4: // uint8.
return (float) ((uint8_t) value[1]);
case 0x5: // uint12.
case 0x6: // uint16.
if (length > 2) {
return (float) ((uint16_t)(value[1] << 8) + (uint16_t) value[2]);
bool BLEClient::all_nodes_established_() {
if (this->state() != espbt::ClientState::ESTABLISHED)
return false;
for (auto &node : nodes_) {
if (node->node_state != espbt::ClientState::ESTABLISHED)
return false;
}
case 0x7: // uint24.
if (length > 3) {
return (float) ((uint32_t)(value[1] << 16) + (uint32_t)(value[2] << 8) + (uint32_t)(value[3]));
}
case 0x8: // uint32.
if (length > 4) {
return (float) ((uint32_t)(value[1] << 24) + (uint32_t)(value[2] << 16) + (uint32_t)(value[3] << 8) +
(uint32_t)(value[4]));
}
case 0xC: // int8.
return (float) ((int8_t) value[1]);
case 0xD: // int12.
case 0xE: // int16.
if (length > 2) {
return (float) ((int16_t)(value[1] << 8) + (int16_t) value[2]);
}
case 0xF: // int24.
if (length > 3) {
return (float) ((int32_t)(value[1] << 16) + (int32_t)(value[2] << 8) + (int32_t)(value[3]));
}
case 0x10: // int32.
if (length > 4) {
return (float) ((int32_t)(value[1] << 24) + (int32_t)(value[2] << 16) + (int32_t)(value[3] << 8) +
(int32_t)(value[4]));
}
}
ESP_LOGW(TAG, "Cannot parse characteristic value of type 0x%x length %d", value[0], length);
return NAN;
}
BLEService *BLEClient::get_service(espbt::ESPBTUUID uuid) {
for (auto *svc : this->services_) {
if (svc->uuid == uuid)
return svc;
}
return nullptr;
}
BLEService *BLEClient::get_service(uint16_t uuid) { return this->get_service(espbt::ESPBTUUID::from_uint16(uuid)); }
BLECharacteristic *BLEClient::get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr) {
auto *svc = this->get_service(service);
if (svc == nullptr)
return nullptr;
return svc->get_characteristic(chr);
}
BLECharacteristic *BLEClient::get_characteristic(uint16_t service, uint16_t chr) {
return this->get_characteristic(espbt::ESPBTUUID::from_uint16(service), espbt::ESPBTUUID::from_uint16(chr));
}
BLEDescriptor *BLEClient::get_config_descriptor(uint16_t handle) {
for (auto &svc : this->services_) {
for (auto &chr : svc->characteristics) {
if (chr->handle == handle) {
for (auto &desc : chr->descriptors) {
if (desc->uuid == espbt::ESPBTUUID::from_uint16(0x2902))
return desc;
}
}
}
}
return nullptr;
}
BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) {
for (auto &chr : this->characteristics) {
if (chr->uuid == uuid)
return chr;
}
return nullptr;
}
BLECharacteristic *BLEService::get_characteristic(uint16_t uuid) {
return this->get_characteristic(espbt::ESPBTUUID::from_uint16(uuid));
}
BLEDescriptor *BLEClient::get_descriptor(espbt::ESPBTUUID service, espbt::ESPBTUUID chr, espbt::ESPBTUUID descr) {
auto *svc = this->get_service(service);
if (svc == nullptr)
return nullptr;
auto *ch = svc->get_characteristic(chr);
if (ch == nullptr)
return nullptr;
return ch->get_descriptor(descr);
}
BLEDescriptor *BLEClient::get_descriptor(uint16_t service, uint16_t chr, uint16_t descr) {
return this->get_descriptor(espbt::ESPBTUUID::from_uint16(service), espbt::ESPBTUUID::from_uint16(chr),
espbt::ESPBTUUID::from_uint16(descr));
}
BLEService::~BLEService() {
for (auto &chr : this->characteristics)
delete chr; // NOLINT(cppcoreguidelines-owning-memory)
}
void BLEService::parse_characteristics() {
uint16_t offset = 0;
esp_gattc_char_elem_t result;
while (true) {
uint16_t count = 1;
esp_gatt_status_t status = esp_ble_gattc_get_all_char(
this->client->gattc_if, this->client->conn_id, this->start_handle, this->end_handle, &result, &count, offset);
if (status == ESP_GATT_INVALID_OFFSET || status == ESP_GATT_NOT_FOUND) {
break;
}
if (status != ESP_GATT_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_get_all_char error, status=%d", status);
break;
}
if (count == 0) {
break;
}
BLECharacteristic *characteristic = new BLECharacteristic(); // NOLINT(cppcoreguidelines-owning-memory)
characteristic->uuid = espbt::ESPBTUUID::from_uuid(result.uuid);
characteristic->properties = result.properties;
characteristic->handle = result.char_handle;
characteristic->service = this;
this->characteristics.push_back(characteristic);
ESP_LOGI(TAG, " characteristic %s, handle 0x%x, properties 0x%x", characteristic->uuid.to_string().c_str(),
characteristic->handle, characteristic->properties);
characteristic->parse_descriptors();
offset++;
}
}
BLECharacteristic::~BLECharacteristic() {
for (auto &desc : this->descriptors)
delete desc; // NOLINT(cppcoreguidelines-owning-memory)
}
void BLECharacteristic::parse_descriptors() {
uint16_t offset = 0;
esp_gattc_descr_elem_t result;
while (true) {
uint16_t count = 1;
esp_gatt_status_t status = esp_ble_gattc_get_all_descr(
this->service->client->gattc_if, this->service->client->conn_id, this->handle, &result, &count, offset);
if (status == ESP_GATT_INVALID_OFFSET || status == ESP_GATT_NOT_FOUND) {
break;
}
if (status != ESP_GATT_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_get_all_descr error, status=%d", status);
break;
}
if (count == 0) {
break;
}
BLEDescriptor *desc = new BLEDescriptor(); // NOLINT(cppcoreguidelines-owning-memory)
desc->uuid = espbt::ESPBTUUID::from_uuid(result.uuid);
desc->handle = result.handle;
desc->characteristic = this;
this->descriptors.push_back(desc);
ESP_LOGV(TAG, " descriptor %s, handle 0x%x", desc->uuid.to_string().c_str(), desc->handle);
offset++;
}
}
BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) {
for (auto &desc : this->descriptors) {
if (desc->uuid == uuid)
return desc;
}
return nullptr;
}
BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) {
return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid));
}
void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size, esp_gatt_write_type_t write_type) {
auto *client = this->service->client;
auto status = esp_ble_gattc_write_char(client->gattc_if, client->conn_id, this->handle, new_val_size, new_val,
write_type, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "Error sending write value to BLE gattc server, status=%d", status);
}
}
void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size) {
write_value(new_val, new_val_size, ESP_GATT_WRITE_TYPE_NO_RSP);
return true;
}
} // namespace ble_client

View File

@@ -1,8 +1,9 @@
#pragma once
#include "esphome/components/esp32_ble_client/ble_client_base.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#ifdef USE_ESP32
@@ -18,9 +19,9 @@ namespace ble_client {
namespace espbt = esphome::esp32_ble_tracker;
using namespace esp32_ble_client;
class BLEClient;
class BLEService;
class BLECharacteristic;
class BLEClientNode {
public:
@@ -42,57 +43,15 @@ class BLEClientNode {
uint64_t address_;
};
class BLEDescriptor {
public:
espbt::ESPBTUUID uuid;
uint16_t handle;
BLECharacteristic *characteristic;
};
class BLECharacteristic {
public:
~BLECharacteristic();
espbt::ESPBTUUID uuid;
uint16_t handle;
esp_gatt_char_prop_t properties;
std::vector<BLEDescriptor *> descriptors;
void parse_descriptors();
BLEDescriptor *get_descriptor(espbt::ESPBTUUID uuid);
BLEDescriptor *get_descriptor(uint16_t uuid);
void write_value(uint8_t *new_val, int16_t new_val_size);
void write_value(uint8_t *new_val, int16_t new_val_size, esp_gatt_write_type_t write_type);
BLEService *service;
};
class BLEService {
public:
~BLEService();
espbt::ESPBTUUID uuid;
uint16_t start_handle;
uint16_t end_handle;
std::vector<BLECharacteristic *> characteristics;
BLEClient *client;
void parse_characteristics();
BLECharacteristic *get_characteristic(espbt::ESPBTUUID uuid);
BLECharacteristic *get_characteristic(uint16_t uuid);
};
class BLEClient : public espbt::ESPBTClient, public Component {
class BLEClient : public BLEClientBase {
public:
void setup() override;
void dump_config() override;
void loop() override;
float get_setup_priority() const override;
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
bool parse_device(const espbt::ESPBTDevice &device) override;
void on_scan_end() override {}
void connect() override;
void set_address(uint64_t address) { this->address = address; }
void set_enabled(bool enabled);
@@ -102,43 +61,14 @@ class BLEClient : public espbt::ESPBTClient, public Component {
this->nodes_.push_back(node);
}
BLEService *get_service(espbt::ESPBTUUID uuid);
BLEService *get_service(uint16_t uuid);
BLECharacteristic *get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr);
BLECharacteristic *get_characteristic(uint16_t service, uint16_t chr);
BLEDescriptor *get_descriptor(espbt::ESPBTUUID service, espbt::ESPBTUUID chr, espbt::ESPBTUUID descr);
BLEDescriptor *get_descriptor(uint16_t service, uint16_t chr, uint16_t descr);
// Get the configuration descriptor for the given characteristic handle.
BLEDescriptor *get_config_descriptor(uint16_t handle);
float parse_char_value(uint8_t *value, uint16_t length);
int gattc_if;
esp_bd_addr_t remote_bda;
esp_ble_addr_type_t remote_addr_type;
uint16_t conn_id;
uint64_t address;
bool enabled;
std::string address_str() const;
void set_state(espbt::ClientState state) override;
protected:
void set_states_(espbt::ClientState st) {
this->set_state(st);
for (auto &node : nodes_)
node->node_state = st;
}
bool all_nodes_established_() {
if (this->state() != espbt::ClientState::ESTABLISHED)
return false;
for (auto &node : nodes_) {
if (node->node_state != espbt::ClientState::ESTABLISHED)
return false;
}
return true;
}
bool all_nodes_established_();
std::vector<BLEClientNode *> nodes_;
std::vector<BLEService *> services_;
};
} // namespace ble_client

View File

@@ -19,7 +19,8 @@ class BLESensorNotifyTrigger : public Trigger<float>, public BLESensor {
break;
}
case ESP_GATTC_NOTIFY_EVT: {
if (param->notify.conn_id != this->sensor_->parent()->conn_id || param->notify.handle != this->sensor_->handle)
if (param->notify.conn_id != this->sensor_->parent()->get_conn_id() ||
param->notify.handle != this->sensor_->handle)
break;
this->trigger(this->sensor_->parent()->parse_char_value(param->notify.value, param->notify.value_len));
}

View File

@@ -63,8 +63,8 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
this->handle = descr->handle;
}
if (this->notify_) {
auto status =
esp_ble_gattc_register_for_notify(this->parent()->gattc_if, this->parent()->remote_bda, chr->handle);
auto status = esp_ble_gattc_register_for_notify(this->parent()->get_gattc_if(),
this->parent()->get_remote_bda(), chr->handle);
if (status) {
ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status);
}
@@ -74,7 +74,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
break;
}
case ESP_GATTC_READ_CHAR_EVT: {
if (param->read.conn_id != this->parent()->conn_id)
if (param->read.conn_id != this->parent()->get_conn_id())
break;
if (param->read.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
@@ -87,7 +87,7 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
break;
}
case ESP_GATTC_NOTIFY_EVT: {
if (param->notify.conn_id != this->parent()->conn_id || param->notify.handle != this->handle)
if (param->notify.conn_id != this->parent()->get_conn_id() || param->notify.handle != this->handle)
break;
ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
param->notify.handle, param->notify.value[0]);
@@ -122,8 +122,8 @@ void BLESensor::update() {
return;
}
auto status =
esp_ble_gattc_read_char(this->parent()->gattc_if, this->parent()->conn_id, this->handle, ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle,
ESP_GATT_AUTH_REQ_NONE);
if (status) {
this->status_set_warning();
this->publish_state(NAN);

View File

@@ -19,7 +19,8 @@ class BLETextSensorNotifyTrigger : public Trigger<std::string>, public BLETextSe
break;
}
case ESP_GATTC_NOTIFY_EVT: {
if (param->notify.conn_id != this->sensor_->parent()->conn_id || param->notify.handle != this->sensor_->handle)
if (param->notify.conn_id != this->sensor_->parent()->get_conn_id() ||
param->notify.handle != this->sensor_->handle)
break;
this->trigger(this->sensor_->parse_data(param->notify.value, param->notify.value_len));
}

View File

@@ -66,8 +66,8 @@ void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
this->handle = descr->handle;
}
if (this->notify_) {
auto status =
esp_ble_gattc_register_for_notify(this->parent()->gattc_if, this->parent()->remote_bda, chr->handle);
auto status = esp_ble_gattc_register_for_notify(this->parent()->get_gattc_if(),
this->parent()->get_remote_bda(), chr->handle);
if (status) {
ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status);
}
@@ -77,7 +77,7 @@ void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
break;
}
case ESP_GATTC_READ_CHAR_EVT: {
if (param->read.conn_id != this->parent()->conn_id)
if (param->read.conn_id != this->parent()->get_conn_id())
break;
if (param->read.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
@@ -90,7 +90,7 @@ void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
break;
}
case ESP_GATTC_NOTIFY_EVT: {
if (param->notify.conn_id != this->parent()->conn_id || param->notify.handle != this->handle)
if (param->notify.conn_id != this->parent()->get_conn_id() || param->notify.handle != this->handle)
break;
ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
param->notify.handle, param->notify.value[0]);
@@ -121,8 +121,8 @@ void BLETextSensor::update() {
return;
}
auto status =
esp_ble_gattc_read_char(this->parent()->gattc_if, this->parent()->conn_id, this->handle, ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle,
ESP_GATT_AUTH_REQ_NONE);
if (status) {
this->status_set_warning();
this->publish_state(EMPTY);

View File

@@ -1,19 +1,23 @@
from esphome.components import esp32_ble_tracker
from esphome.components import esp32_ble_tracker, esp32_ble_client
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_ID
from esphome.const import CONF_ACTIVE, CONF_ID
DEPENDENCIES = ["esp32", "esp32_ble_tracker"]
AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"]
DEPENDENCIES = ["esp32"]
CODEOWNERS = ["@jesserockz"]
bluetooth_proxy_ns = cg.esphome_ns.namespace("bluetooth_proxy")
BluetoothProxy = bluetooth_proxy_ns.class_("BluetoothProxy", cg.Component)
BluetoothProxy = bluetooth_proxy_ns.class_(
"BluetoothProxy", esp32_ble_client.BLEClientBase
)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(BluetoothProxy),
cv.Optional(CONF_ACTIVE, default=False): cv.boolean,
}
).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
@@ -22,6 +26,8 @@ async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await esp32_ble_tracker.register_ble_device(var, config)
cg.add(var.set_active(config[CONF_ACTIVE]))
await esp32_ble_tracker.register_client(var, config)
cg.add_define("USE_BLUETOOTH_PROXY")

View File

@@ -1,22 +1,39 @@
#include "bluetooth_proxy.h"
#ifdef USE_API
#include "esphome/components/api/api_pb2.h"
#include "esphome/components/api/api_server.h"
#endif // USE_API
#include "esphome/core/log.h"
#ifdef USE_ESP32
#ifdef USE_API
#include "esphome/components/api/api_server.h"
#endif
namespace esphome {
namespace bluetooth_proxy {
static const char *const TAG = "bluetooth_proxy";
BluetoothProxy::BluetoothProxy() {
global_bluetooth_proxy = this;
this->address_ = 0;
}
bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
ESP_LOGV(TAG, "Proxying packet from %s - %s. RSSI: %d dB", device.get_name().c_str(), device.address_str().c_str(),
device.get_rssi());
this->send_api_packet_(device);
this->address_type_map_[device.address_uint64()] = device.get_address_type();
if (this->address_ == 0)
return true;
if (this->state_ == espbt::ClientState::DISCOVERED) {
ESP_LOGV(TAG, "Connecting to address %s", this->address_str().c_str());
return true;
}
BLEClientBase::parse_device(device);
return true;
}
@@ -35,23 +52,309 @@ void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &devi
for (auto &data : device.get_service_datas()) {
api::BluetoothServiceData service_data;
service_data.uuid = data.uuid.to_string();
for (auto d : data.data)
service_data.data.push_back(d);
resp.service_data.push_back(service_data);
service_data.data.assign(data.data.begin(), data.data.end());
resp.service_data.push_back(std::move(service_data));
}
for (auto &data : device.get_manufacturer_datas()) {
api::BluetoothServiceData manufacturer_data;
manufacturer_data.uuid = data.uuid.to_string();
for (auto d : data.data)
manufacturer_data.data.push_back(d);
resp.manufacturer_data.push_back(manufacturer_data);
manufacturer_data.data.assign(data.data.begin(), data.data.end());
resp.manufacturer_data.push_back(std::move(manufacturer_data));
}
api::global_api_server->send_bluetooth_le_advertisement(resp);
#endif
}
void BluetoothProxy::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) {
BLEClientBase::gattc_event_handler(event, gattc_if, param);
switch (event) {
case ESP_GATTC_DISCONNECT_EVT: {
#ifdef USE_API
api::global_api_server->send_bluetooth_device_connection(this->address_, false, this->mtu_,
param->disconnect.reason);
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
this->get_bluetooth_connections_limit());
#endif
this->address_ = 0;
}
case ESP_GATTC_OPEN_EVT: {
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
#ifdef USE_API
api::global_api_server->send_bluetooth_device_connection(this->address_, false, this->mtu_, param->open.status);
#endif
break;
}
break;
}
case ESP_GATTC_SEARCH_CMPL_EVT: {
#ifdef USE_API
api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
this->get_bluetooth_connections_limit());
#endif
break;
}
case ESP_GATTC_READ_DESCR_EVT:
case ESP_GATTC_READ_CHAR_EVT: {
if (param->read.conn_id != this->conn_id_)
break;
if (param->read.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "Error reading char/descriptor at handle %d, status=%d", param->read.handle, param->read.status);
break;
}
#ifdef USE_API
api::BluetoothGATTReadResponse resp;
resp.address = this->address_;
resp.handle = param->read.handle;
resp.data.reserve(param->read.value_len);
for (uint16_t i = 0; i < param->read.value_len; i++) {
resp.data.push_back(param->read.value[i]);
}
api::global_api_server->send_bluetooth_gatt_read_response(resp);
#endif
break;
}
case ESP_GATTC_NOTIFY_EVT: {
if (param->notify.conn_id != this->conn_id_)
break;
ESP_LOGV(TAG, "ESP_GATTC_NOTIFY_EVT: handle=0x%x", param->notify.handle);
#ifdef USE_API
api::BluetoothGATTNotifyDataResponse resp;
resp.address = this->address_;
resp.handle = param->notify.handle;
resp.data.reserve(param->notify.value_len);
for (uint16_t i = 0; i < param->notify.value_len; i++) {
resp.data.push_back(param->notify.value[i]);
}
api::global_api_server->send_bluetooth_gatt_notify_data_response(resp);
#endif
break;
}
default:
break;
}
}
void BluetoothProxy::dump_config() { ESP_LOGCONFIG(TAG, "Bluetooth Proxy:"); }
void BluetoothProxy::loop() {
BLEClientBase::loop();
#ifdef USE_API
if (this->state_ != espbt::ClientState::IDLE && !api::global_api_server->is_connected()) {
ESP_LOGI(TAG, "[%s] Disconnecting.", this->address_str().c_str());
auto err = esp_ble_gattc_close(this->gattc_if_, this->conn_id_);
if (err != ERR_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_close error, address=%s err=%d", this->address_str().c_str(), err);
}
}
if (this->send_service_ == this->services_.size()) {
this->send_service_ = -1;
api::global_api_server->send_bluetooth_gatt_services_done(this->address_);
} else if (this->send_service_ >= 0) {
auto &service = this->services_[this->send_service_];
api::BluetoothGATTGetServicesResponse resp;
resp.address = this->address_;
api::BluetoothGATTService service_resp;
service_resp.uuid = {service->uuid.get_128bit_high(), service->uuid.get_128bit_low()};
service_resp.handle = service->start_handle;
for (auto &characteristic : service->characteristics) {
api::BluetoothGATTCharacteristic characteristic_resp;
characteristic_resp.uuid = {characteristic->uuid.get_128bit_high(), characteristic->uuid.get_128bit_low()};
characteristic_resp.handle = characteristic->handle;
characteristic_resp.properties = characteristic->properties;
for (auto &descriptor : characteristic->descriptors) {
api::BluetoothGATTDescriptor descriptor_resp;
descriptor_resp.uuid = {descriptor->uuid.get_128bit_high(), descriptor->uuid.get_128bit_low()};
descriptor_resp.handle = descriptor->handle;
characteristic_resp.descriptors.push_back(std::move(descriptor_resp));
}
service_resp.characteristics.push_back(std::move(characteristic_resp));
}
resp.services.push_back(std::move(service_resp));
api::global_api_server->send_bluetooth_gatt_services(resp);
this->send_service_++;
}
#endif
}
#ifdef USE_API
void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {
switch (msg.request_type) {
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
this->address_ = msg.address;
if (this->address_type_map_.find(this->address_) != this->address_type_map_.end()) {
// Utilise the address type cache
this->remote_addr_type_ = this->address_type_map_[this->address_];
} else {
this->remote_addr_type_ = BLE_ADDR_TYPE_PUBLIC;
}
this->remote_bda_[0] = (this->address_ >> 40) & 0xFF;
this->remote_bda_[1] = (this->address_ >> 32) & 0xFF;
this->remote_bda_[2] = (this->address_ >> 24) & 0xFF;
this->remote_bda_[3] = (this->address_ >> 16) & 0xFF;
this->remote_bda_[4] = (this->address_ >> 8) & 0xFF;
this->remote_bda_[5] = (this->address_ >> 0) & 0xFF;
this->set_state(espbt::ClientState::DISCOVERED);
esp_ble_gap_stop_scanning();
break;
}
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT: {
if (this->state() != espbt::ClientState::IDLE) {
ESP_LOGI(TAG, "[%s] Disconnecting.", this->address_str().c_str());
auto err = esp_ble_gattc_close(this->gattc_if_, this->conn_id_);
if (err != ERR_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_close error, address=%s err=%d", this->address_str().c_str(), err);
}
}
break;
}
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR:
case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
break;
}
}
void BluetoothProxy::bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg) {
if (this->state_ != espbt::ClientState::ESTABLISHED) {
ESP_LOGW(TAG, "Cannot read GATT characteristic, not connected.");
return;
}
if (this->address_ != msg.address) {
ESP_LOGW(TAG, "Address mismatch for read GATT characteristic request");
return;
}
auto *characteristic = this->get_characteristic(msg.handle);
if (characteristic == nullptr) {
ESP_LOGW(TAG, "Cannot read GATT characteristic, not found.");
return;
}
ESP_LOGV(TAG, "Reading GATT characteristic %s", characteristic->uuid.to_string().c_str());
esp_err_t err =
esp_ble_gattc_read_char(this->gattc_if_, this->conn_id_, characteristic->handle, ESP_GATT_AUTH_REQ_NONE);
if (err != ERR_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_read_char error, err=%d", err);
}
}
void BluetoothProxy::bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg) {
if (this->state_ != espbt::ClientState::ESTABLISHED) {
ESP_LOGW(TAG, "Cannot write GATT characteristic, not connected.");
return;
}
if (this->address_ != msg.address) {
ESP_LOGW(TAG, "Address mismatch for write GATT characteristic request");
return;
}
auto *characteristic = this->get_characteristic(msg.handle);
if (characteristic == nullptr) {
ESP_LOGW(TAG, "Cannot write GATT characteristic, not found.");
return;
}
ESP_LOGV(TAG, "Writing GATT characteristic %s", characteristic->uuid.to_string().c_str());
characteristic->write_value((uint8_t *) msg.data.data(), msg.data.size(),
msg.response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP);
}
void BluetoothProxy::bluetooth_gatt_read_descriptor(const api::BluetoothGATTReadDescriptorRequest &msg) {
if (this->state_ != espbt::ClientState::ESTABLISHED) {
ESP_LOGW(TAG, "Cannot read GATT characteristic descriptor, not connected.");
return;
}
if (this->address_ != msg.address) {
ESP_LOGW(TAG, "Address mismatch for read GATT characteristic descriptor request");
return;
}
auto *descriptor = this->get_descriptor(msg.handle);
if (descriptor == nullptr) {
ESP_LOGW(TAG, "Cannot read GATT characteristic descriptor, not found.");
return;
}
ESP_LOGV(TAG, "Reading GATT characteristic descriptor %s -> %s", descriptor->characteristic->uuid.to_string().c_str(),
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) {
ESP_LOGW(TAG, "esp_ble_gattc_read_char error, err=%d", err);
}
}
void BluetoothProxy::bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg) {
if (this->state_ != espbt::ClientState::ESTABLISHED) {
ESP_LOGW(TAG, "Cannot write GATT characteristic descriptor, not connected.");
return;
}
if (this->address_ != msg.address) {
ESP_LOGW(TAG, "Address mismatch for write GATT characteristic descriptor request");
return;
}
auto *descriptor = this->get_descriptor(msg.handle);
if (descriptor == nullptr) {
ESP_LOGW(TAG, "Cannot write GATT characteristic descriptor, not found.");
return;
}
ESP_LOGV(TAG, "Writing GATT characteristic descriptor %s -> %s", descriptor->characteristic->uuid.to_string().c_str(),
descriptor->uuid.to_string().c_str());
esp_err_t err =
esp_ble_gattc_write_char_descr(this->gattc_if_, this->conn_id_, descriptor->handle, msg.data.size(),
(uint8_t *) msg.data.data(), ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (err != ERR_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_write_char_descr error, err=%d", err);
}
}
void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg) {
if (this->address_ != msg.address) {
ESP_LOGW(TAG, "Address mismatch for service list request");
return;
}
this->send_service_ = 0;
}
void BluetoothProxy::bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg) {
if (this->address_ != msg.address) {
ESP_LOGW(TAG, "Address mismatch for notify");
return;
}
auto *characteristic = this->get_characteristic(msg.handle);
if (characteristic == nullptr) {
ESP_LOGW(TAG, "Cannot notify GATT characteristic, not found.");
return;
}
esp_err_t err;
if (msg.enable) {
err = esp_ble_gattc_register_for_notify(this->gattc_if_, this->remote_bda_, characteristic->handle);
if (err != ESP_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, err=%d", err);
}
} else {
err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, characteristic->handle);
if (err != ESP_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_unregister_for_notify failed, err=%d", err);
}
}
}
#endif
BluetoothProxy *global_bluetooth_proxy = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace bluetooth_proxy
} // namespace esphome

View File

@@ -4,22 +4,59 @@
#include <map>
#include "esphome/components/esp32_ble_client/ble_client_base.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include <map>
#ifdef USE_API
#include "esphome/components/api/api_pb2.h"
#endif // USE_API
namespace esphome {
namespace bluetooth_proxy {
class BluetoothProxy : public Component, public esp32_ble_tracker::ESPBTDeviceListener {
using namespace esp32_ble_client;
class BluetoothProxy : public BLEClientBase {
public:
BluetoothProxy();
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override;
void loop() override;
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
#ifdef USE_API
void bluetooth_device_request(const api::BluetoothDeviceRequest &msg);
void bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg);
void bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg);
void bluetooth_gatt_read_descriptor(const api::BluetoothGATTReadDescriptorRequest &msg);
void bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg);
void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg);
void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg);
#endif
int get_bluetooth_connections_free() { return this->state_ == espbt::ClientState::IDLE ? 1 : 0; }
int get_bluetooth_connections_limit() { return 1; }
void set_active(bool active) { this->active_ = active; }
bool has_active() { return this->active_; }
protected:
void send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device);
std::map<uint64_t, esp_ble_addr_type_t> address_type_map_;
int16_t send_service_{-1};
bool active_;
};
extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace bluetooth_proxy
} // namespace esphome

View File

@@ -163,7 +163,7 @@ void BME280Component::setup() {
return;
}
config_register &= ~0b11111100;
config_register |= 0b000 << 5; // 0.5 ms standby time
config_register |= 0b101 << 5; // 1000 ms standby time
config_register |= (this->iir_filter_ & 0b111) << 2;
if (!this->write_byte(BME280_REGISTER_CONFIG, config_register)) {
this->mark_failed();

View File

@@ -96,9 +96,9 @@ class BME280Component : public PollingComponent, public i2c::I2CDevice {
BME280Oversampling pressure_oversampling_{BME280_OVERSAMPLING_16X};
BME280Oversampling humidity_oversampling_{BME280_OVERSAMPLING_16X};
BME280IIRFilter iir_filter_{BME280_IIR_FILTER_OFF};
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,

View File

@@ -129,10 +129,10 @@ class BME680Component : public PollingComponent, public i2c::I2CDevice {
uint16_t heater_temperature_{320};
uint16_t heater_duration_{150};
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *gas_resistance_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
sensor::Sensor *gas_resistance_sensor_{nullptr};
};
} // namespace bme680

View File

@@ -100,15 +100,15 @@ class BME680BSECComponent : public Component, public i2c::I2CDevice {
SampleRate pressure_sample_rate_{SAMPLE_RATE_DEFAULT};
SampleRate humidity_sample_rate_{SAMPLE_RATE_DEFAULT};
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *gas_resistance_sensor_;
sensor::Sensor *iaq_sensor_;
text_sensor::TextSensor *iaq_accuracy_text_sensor_;
sensor::Sensor *iaq_accuracy_sensor_;
sensor::Sensor *co2_equivalent_sensor_;
sensor::Sensor *breath_voc_equivalent_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
sensor::Sensor *gas_resistance_sensor_{nullptr};
sensor::Sensor *iaq_sensor_{nullptr};
text_sensor::TextSensor *iaq_accuracy_text_sensor_{nullptr};
sensor::Sensor *iaq_accuracy_sensor_{nullptr};
sensor::Sensor *co2_equivalent_sensor_{nullptr};
sensor::Sensor *breath_voc_equivalent_sensor_{nullptr};
};
#endif
} // namespace bme680_bsec

View File

@@ -81,8 +81,8 @@ class BMP280Component : public PollingComponent, public i2c::I2CDevice {
BMP280Oversampling temperature_oversampling_{BMP280_OVERSAMPLING_16X};
BMP280Oversampling pressure_oversampling_{BMP280_OVERSAMPLING_16X};
BMP280IIRFilter iir_filter_{BMP280_IIR_FILTER_OFF};
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,

View File

@@ -125,8 +125,8 @@ class BMP3XXComponent : public PollingComponent, public i2c::I2CDevice {
Oversampling pressure_oversampling_{OVERSAMPLING_X16};
IIRFilter iir_filter_{IIR_FILTER_OFF};
OperationMode operation_mode_{FORCED_MODE};
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
ERROR_COMMUNICATION_FAILED,

View File

@@ -20,8 +20,8 @@ class DHT12Component : public PollingComponent, public i2c::I2CDevice {
protected:
bool read_data_(uint8_t *data);
sensor::Sensor *temperature_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace dht12

View File

@@ -53,8 +53,8 @@ class DPS310Component : public PollingComponent, public i2c::I2CDevice {
void calculate_values_(int32_t raw_temperature, int32_t raw_pressure);
static int32_t twos_complement(int32_t val, uint8_t bits);
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
int32_t raw_pressure_, raw_temperature_, c00_, c10_;
int16_t c0_, c1_, c01_, c11_, c20_, c21_, c30_;
uint8_t prod_rev_id_;

View File

@@ -31,8 +31,8 @@ class ENS210Component : public PollingComponent, public i2c::I2CDevice {
bool set_low_power_(bool enable);
void extract_measurement_(uint32_t val, int *data, int *status);
sensor::Sensor *temperature_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace ens210

View File

@@ -0,0 +1,12 @@
import esphome.codegen as cg
from esphome.components import esp32_ble_tracker
AUTO_LOAD = ["esp32_ble_tracker"]
CODEOWNERS = ["@jesserockz"]
DEPENDENCIES = ["esp32"]
esp32_ble_client_ns = cg.esphome_ns.namespace("esp32_ble_client")
BLEClientBase = esp32_ble_client_ns.class_(
"BLEClientBase", esp32_ble_tracker.ESPBTClient, cg.Component
)

View File

@@ -0,0 +1,83 @@
#include "ble_characteristic.h"
#include "ble_client_base.h"
#include "ble_service.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
namespace esphome {
namespace esp32_ble_client {
static const char *const TAG = "esp32_ble_client.characteristic";
BLECharacteristic::~BLECharacteristic() {
for (auto &desc : this->descriptors)
delete desc; // NOLINT(cppcoreguidelines-owning-memory)
}
void BLECharacteristic::parse_descriptors() {
uint16_t offset = 0;
esp_gattc_descr_elem_t result;
while (true) {
uint16_t count = 1;
esp_gatt_status_t status =
esp_ble_gattc_get_all_descr(this->service->client->get_gattc_if(), this->service->client->get_conn_id(),
this->handle, &result, &count, offset);
if (status == ESP_GATT_INVALID_OFFSET || status == ESP_GATT_NOT_FOUND) {
break;
}
if (status != ESP_GATT_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_get_all_descr error, status=%d", status);
break;
}
if (count == 0) {
break;
}
BLEDescriptor *desc = new BLEDescriptor(); // NOLINT(cppcoreguidelines-owning-memory)
desc->uuid = espbt::ESPBTUUID::from_uuid(result.uuid);
desc->handle = result.handle;
desc->characteristic = this;
this->descriptors.push_back(desc);
ESP_LOGV(TAG, " descriptor %s, handle 0x%x", desc->uuid.to_string().c_str(), desc->handle);
offset++;
}
}
BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) {
for (auto &desc : this->descriptors) {
if (desc->uuid == uuid)
return desc;
}
return nullptr;
}
BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) {
return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid));
}
BLEDescriptor *BLECharacteristic::get_descriptor_by_handle(uint16_t handle) {
for (auto &desc : this->descriptors) {
if (desc->handle == handle)
return desc;
}
return nullptr;
}
void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size, esp_gatt_write_type_t write_type) {
auto *client = this->service->client;
auto status = esp_ble_gattc_write_char(client->get_gattc_if(), client->get_conn_id(), this->handle, new_val_size,
new_val, write_type, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "Error sending write value to BLE gattc server, status=%d", status);
}
}
void BLECharacteristic::write_value(uint8_t *new_val, int16_t new_val_size) {
write_value(new_val, new_val_size, ESP_GATT_WRITE_TYPE_NO_RSP);
}
} // namespace esp32_ble_client
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,35 @@
#pragma once
#ifdef USE_ESP32
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "ble_descriptor.h"
namespace esphome {
namespace esp32_ble_client {
namespace espbt = esphome::esp32_ble_tracker;
class BLEService;
class BLECharacteristic {
public:
~BLECharacteristic();
espbt::ESPBTUUID uuid;
uint16_t handle;
esp_gatt_char_prop_t properties;
std::vector<BLEDescriptor *> descriptors;
void parse_descriptors();
BLEDescriptor *get_descriptor(espbt::ESPBTUUID uuid);
BLEDescriptor *get_descriptor(uint16_t uuid);
BLEDescriptor *get_descriptor_by_handle(uint16_t handle);
void write_value(uint8_t *new_val, int16_t new_val_size);
void write_value(uint8_t *new_val, int16_t new_val_size, esp_gatt_write_type_t write_type);
BLEService *service;
};
} // namespace esp32_ble_client
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,324 @@
#include "ble_client_base.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
namespace esphome {
namespace esp32_ble_client {
static const char *const TAG = "esp32_ble_client";
void BLEClientBase::setup() {
auto ret = esp_ble_gattc_app_register(this->app_id);
if (ret) {
ESP_LOGE(TAG, "gattc app register failed. app_id=%d code=%d", this->app_id, ret);
this->mark_failed();
}
this->set_state(espbt::ClientState::IDLE);
}
void BLEClientBase::loop() {
if (this->state_ == espbt::ClientState::DISCOVERED) {
this->connect();
}
}
float BLEClientBase::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; }
bool BLEClientBase::parse_device(const espbt::ESPBTDevice &device) {
if (device.address_uint64() != this->address_)
return false;
if (this->state_ != espbt::ClientState::IDLE)
return false;
ESP_LOGD(TAG, "Found device at MAC address [%s]", device.address_str().c_str());
this->set_state(espbt::ClientState::DISCOVERED);
auto addr = device.address_uint64();
this->remote_bda_[0] = (addr >> 40) & 0xFF;
this->remote_bda_[1] = (addr >> 32) & 0xFF;
this->remote_bda_[2] = (addr >> 24) & 0xFF;
this->remote_bda_[3] = (addr >> 16) & 0xFF;
this->remote_bda_[4] = (addr >> 8) & 0xFF;
this->remote_bda_[5] = (addr >> 0) & 0xFF;
this->remote_addr_type_ = device.get_address_type();
return true;
}
std::string BLEClientBase::address_str() const {
return 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_ >> 16) & 0xff, (uint8_t)(this->address_ >> 8) & 0xff,
(uint8_t)(this->address_ >> 0) & 0xff);
}
void BLEClientBase::connect() {
ESP_LOGI(TAG, "Attempting BLE connection to %s", this->address_str().c_str());
auto ret = esp_ble_gattc_open(this->gattc_if_, this->remote_bda_, this->remote_addr_type_, true);
if (ret) {
ESP_LOGW(TAG, "esp_ble_gattc_open error, address=%s status=%d", this->address_str().c_str(), ret);
this->set_state(espbt::ClientState::IDLE);
} else {
this->set_state(espbt::ClientState::CONNECTING);
}
}
void BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_if,
esp_ble_gattc_cb_param_t *param) {
if (event == ESP_GATTC_REG_EVT && this->app_id != param->reg.app_id)
return;
if (event != ESP_GATTC_REG_EVT && esp_gattc_if != ESP_GATT_IF_NONE && esp_gattc_if != this->gattc_if_)
return;
switch (event) {
case ESP_GATTC_REG_EVT: {
if (param->reg.status == ESP_GATT_OK) {
ESP_LOGV(TAG, "gattc registered app id %d", this->app_id);
this->gattc_if_ = esp_gattc_if;
} else {
ESP_LOGE(TAG, "gattc app registration failed id=%d code=%d", param->reg.app_id, param->reg.status);
}
break;
}
case ESP_GATTC_OPEN_EVT: {
ESP_LOGV(TAG, "[%s] ESP_GATTC_OPEN_EVT", this->address_str().c_str());
this->conn_id_ = param->open.conn_id;
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
ESP_LOGW(TAG, "connect to %s failed, status=%d", this->address_str().c_str(), param->open.status);
this->set_state(espbt::ClientState::IDLE);
break;
}
break;
}
case ESP_GATTC_CONNECT_EVT: {
ESP_LOGV(TAG, "[%s] ESP_GATTC_CONNECT_EVT", this->address_str().c_str());
if (this->conn_id_ != param->connect.conn_id) {
ESP_LOGD(TAG, "[%s] Unexpected conn_id in CONNECT_EVT: param conn=%d, open conn=%d",
this->address_str().c_str(), param->connect.conn_id, this->conn_id_);
}
auto ret = esp_ble_gattc_send_mtu_req(this->gattc_if_, param->connect.conn_id);
if (ret) {
ESP_LOGW(TAG, "esp_ble_gattc_send_mtu_req failed, status=%x", ret);
}
break;
}
case ESP_GATTC_CFG_MTU_EVT: {
if (param->cfg_mtu.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "cfg_mtu to %s failed, mtu %d, status %d", this->address_str().c_str(), param->cfg_mtu.mtu,
param->cfg_mtu.status);
this->set_state(espbt::ClientState::IDLE);
break;
}
ESP_LOGV(TAG, "cfg_mtu status %d, mtu %d", param->cfg_mtu.status, 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;
}
case ESP_GATTC_DISCONNECT_EVT: {
if (memcmp(param->disconnect.remote_bda, this->remote_bda_, 6) != 0) {
return;
}
ESP_LOGV(TAG, "[%s] ESP_GATTC_DISCONNECT_EVT, reason %d", this->address_str().c_str(), param->disconnect.reason);
for (auto &svc : this->services_)
delete svc; // NOLINT(cppcoreguidelines-owning-memory)
this->services_.clear();
this->set_state(espbt::ClientState::IDLE);
break;
}
case ESP_GATTC_SEARCH_RES_EVT: {
BLEService *ble_service = new BLEService(); // NOLINT(cppcoreguidelines-owning-memory)
ble_service->uuid = espbt::ESPBTUUID::from_uuid(param->search_res.srvc_id.uuid);
ble_service->start_handle = param->search_res.start_handle;
ble_service->end_handle = param->search_res.end_handle;
ble_service->client = this;
this->services_.push_back(ble_service);
break;
}
case ESP_GATTC_SEARCH_CMPL_EVT: {
ESP_LOGV(TAG, "[%s] ESP_GATTC_SEARCH_CMPL_EVT", this->address_str().c_str());
for (auto &svc : this->services_) {
ESP_LOGI(TAG, "Service UUID: %s", svc->uuid.to_string().c_str());
ESP_LOGI(TAG, " start_handle: 0x%x end_handle: 0x%x", svc->start_handle, svc->end_handle);
svc->parse_characteristics();
}
this->set_state(espbt::ClientState::CONNECTED);
this->state_ = espbt::ClientState::ESTABLISHED;
break;
}
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
auto *descr = this->get_config_descriptor(param->reg_for_notify.handle);
if (descr == nullptr) {
ESP_LOGW(TAG, "No descriptor found for notify of handle 0x%x", param->reg_for_notify.handle);
break;
}
if (descr->uuid.get_uuid().len != ESP_UUID_LEN_16 ||
descr->uuid.get_uuid().uuid.uuid16 != ESP_GATT_UUID_CHAR_CLIENT_CONFIG) {
ESP_LOGW(TAG, "Handle 0x%x (uuid %s) is not a client config char uuid", param->reg_for_notify.handle,
descr->uuid.to_string().c_str());
break;
}
uint16_t notify_en = 1;
auto status =
esp_ble_gattc_write_char_descr(this->gattc_if_, this->conn_id_, descr->handle, sizeof(notify_en),
(uint8_t *) &notify_en, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "esp_ble_gattc_write_char_descr error, status=%d", status);
}
break;
}
default:
break;
}
}
void BLEClientBase::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
switch (event) {
// This event is sent by the server when it requests security
case ESP_GAP_BLE_SEC_REQ_EVT:
ESP_LOGV(TAG, "ESP_GAP_BLE_SEC_REQ_EVT %x", event);
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
break;
// This event is sent once authentication has completed
case ESP_GAP_BLE_AUTH_CMPL_EVT:
esp_bd_addr_t bd_addr;
memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));
ESP_LOGI(TAG, "auth complete. remote BD_ADDR: %s", format_hex(bd_addr, 6).c_str());
if (!param->ble_security.auth_cmpl.success) {
ESP_LOGE(TAG, "auth fail reason = 0x%x", param->ble_security.auth_cmpl.fail_reason);
} else {
ESP_LOGV(TAG, "auth success. address type = %d auth mode = %d", param->ble_security.auth_cmpl.addr_type,
param->ble_security.auth_cmpl.auth_mode);
}
break;
// There are other events we'll want to implement at some point to support things like pass key
// https://github.com/espressif/esp-idf/blob/cba69dd088344ed9d26739f04736ae7a37541b3a/examples/bluetooth/bluedroid/ble/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md
default:
break;
}
}
// Parse GATT values into a float for a sensor.
// Ref: https://www.bluetooth.com/specifications/assigned-numbers/format-types/
float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) {
// A length of one means a single octet value.
if (length == 0)
return 0;
if (length == 1)
return (float) ((uint8_t) value[0]);
switch (value[0]) {
case 0x1: // boolean.
case 0x2: // 2bit.
case 0x3: // nibble.
case 0x4: // uint8.
return (float) ((uint8_t) value[1]);
case 0x5: // uint12.
case 0x6: // uint16.
if (length > 2) {
return (float) encode_uint16(value[1], value[2]);
}
case 0x7: // uint24.
if (length > 3) {
return (float) encode_uint24(value[1], value[2], value[3]);
}
case 0x8: // uint32.
if (length > 4) {
return (float) encode_uint32(value[1], value[2], value[3], value[4]);
}
case 0xC: // int8.
return (float) ((int8_t) value[1]);
case 0xD: // int12.
case 0xE: // int16.
if (length > 2) {
return (float) ((int16_t)(value[1] << 8) + (int16_t) value[2]);
}
case 0xF: // int24.
if (length > 3) {
return (float) ((int32_t)(value[1] << 16) + (int32_t)(value[2] << 8) + (int32_t)(value[3]));
}
case 0x10: // int32.
if (length > 4) {
return (float) ((int32_t)(value[1] << 24) + (int32_t)(value[2] << 16) + (int32_t)(value[3] << 8) +
(int32_t)(value[4]));
}
}
ESP_LOGW(TAG, "Cannot parse characteristic value of type 0x%x length %d", value[0], length);
return NAN;
}
BLEService *BLEClientBase::get_service(espbt::ESPBTUUID uuid) {
for (auto *svc : this->services_) {
if (svc->uuid == uuid)
return svc;
}
return nullptr;
}
BLEService *BLEClientBase::get_service(uint16_t uuid) { return this->get_service(espbt::ESPBTUUID::from_uint16(uuid)); }
BLECharacteristic *BLEClientBase::get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr) {
auto *svc = this->get_service(service);
if (svc == nullptr)
return nullptr;
return svc->get_characteristic(chr);
}
BLECharacteristic *BLEClientBase::get_characteristic(uint16_t service, uint16_t chr) {
return this->get_characteristic(espbt::ESPBTUUID::from_uint16(service), espbt::ESPBTUUID::from_uint16(chr));
}
BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) {
for (auto *svc : this->services_) {
for (auto *chr : svc->characteristics) {
if (chr->handle == handle)
return chr;
}
}
return nullptr;
}
BLEDescriptor *BLEClientBase::get_config_descriptor(uint16_t handle) {
auto *chr = this->get_characteristic(handle);
if (chr != nullptr) {
for (auto &desc : chr->descriptors) {
if (desc->uuid == espbt::ESPBTUUID::from_uint16(0x2902))
return desc;
}
}
return nullptr;
}
BLEDescriptor *BLEClientBase::get_descriptor(espbt::ESPBTUUID service, espbt::ESPBTUUID chr, espbt::ESPBTUUID descr) {
auto *svc = this->get_service(service);
if (svc == nullptr)
return nullptr;
auto *ch = svc->get_characteristic(chr);
if (ch == nullptr)
return nullptr;
return ch->get_descriptor(descr);
}
BLEDescriptor *BLEClientBase::get_descriptor(uint16_t service, uint16_t chr, uint16_t descr) {
return this->get_descriptor(espbt::ESPBTUUID::from_uint16(service), espbt::ESPBTUUID::from_uint16(chr),
espbt::ESPBTUUID::from_uint16(descr));
}
BLEDescriptor *BLEClientBase::get_descriptor(uint16_t handle) {
for (auto *svc : this->services_) {
for (auto *chr : svc->characteristics) {
for (auto *desc : chr->descriptors) {
if (desc->handle == handle)
return desc;
}
}
}
return nullptr;
}
} // namespace esp32_ble_client
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,72 @@
#pragma once
#ifdef USE_ESP32
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/core/component.h"
#include "ble_service.h"
#include <array>
#include <string>
#include <esp_bt_defs.h>
#include <esp_gap_ble_api.h>
#include <esp_gatt_common_api.h>
#include <esp_gattc_api.h>
namespace esphome {
namespace esp32_ble_client {
namespace espbt = esphome::esp32_ble_tracker;
class BLEClientBase : public espbt::ESPBTClient, public Component {
public:
void setup() override;
void loop() override;
float get_setup_priority() const override;
bool parse_device(const espbt::ESPBTDevice &device) override;
void on_scan_end() override {}
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_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 set_address(uint64_t address) { this->address_ = address; }
std::string address_str() const;
BLEService *get_service(espbt::ESPBTUUID uuid);
BLEService *get_service(uint16_t uuid);
BLECharacteristic *get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr);
BLECharacteristic *get_characteristic(uint16_t service, uint16_t chr);
BLECharacteristic *get_characteristic(uint16_t handle);
BLEDescriptor *get_descriptor(espbt::ESPBTUUID service, espbt::ESPBTUUID chr, espbt::ESPBTUUID descr);
BLEDescriptor *get_descriptor(uint16_t service, uint16_t chr, uint16_t descr);
BLEDescriptor *get_descriptor(uint16_t handle);
// Get the configuration descriptor for the given characteristic handle.
BLEDescriptor *get_config_descriptor(uint16_t handle);
float parse_char_value(uint8_t *value, uint16_t length);
int get_gattc_if() const { return this->gattc_if_; }
uint8_t *get_remote_bda() { return this->remote_bda_; }
esp_ble_addr_type_t get_remote_addr_type() const { return this->remote_addr_type_; }
uint16_t get_conn_id() const { return this->conn_id_; }
uint64_t get_address() const { return this->address_; }
protected:
int gattc_if_;
esp_bd_addr_t remote_bda_;
esp_ble_addr_type_t remote_addr_type_;
uint16_t conn_id_;
uint64_t address_;
uint16_t mtu_{23};
std::vector<BLEService *> services_;
};
} // namespace esp32_ble_client
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,25 @@
#pragma once
#ifdef USE_ESP32
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
namespace esphome {
namespace esp32_ble_client {
namespace espbt = esphome::esp32_ble_tracker;
class BLECharacteristic;
class BLEDescriptor {
public:
espbt::ESPBTUUID uuid;
uint16_t handle;
BLECharacteristic *characteristic;
};
} // namespace esp32_ble_client
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,66 @@
#include "ble_service.h"
#include "ble_client_base.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
namespace esphome {
namespace esp32_ble_client {
static const char *const TAG = "esp32_ble_client.service";
BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) {
for (auto &chr : this->characteristics) {
if (chr->uuid == uuid)
return chr;
}
return nullptr;
}
BLECharacteristic *BLEService::get_characteristic(uint16_t uuid) {
return this->get_characteristic(espbt::ESPBTUUID::from_uint16(uuid));
}
BLEService::~BLEService() {
for (auto &chr : this->characteristics)
delete chr; // NOLINT(cppcoreguidelines-owning-memory)
}
void BLEService::parse_characteristics() {
uint16_t offset = 0;
esp_gattc_char_elem_t result;
while (true) {
uint16_t count = 1;
esp_gatt_status_t status =
esp_ble_gattc_get_all_char(this->client->get_gattc_if(), this->client->get_conn_id(), this->start_handle,
this->end_handle, &result, &count, offset);
if (status == ESP_GATT_INVALID_OFFSET || status == ESP_GATT_NOT_FOUND) {
break;
}
if (status != ESP_GATT_OK) {
ESP_LOGW(TAG, "esp_ble_gattc_get_all_char error, status=%d", status);
break;
}
if (count == 0) {
break;
}
BLECharacteristic *characteristic = new BLECharacteristic(); // NOLINT(cppcoreguidelines-owning-memory)
characteristic->uuid = espbt::ESPBTUUID::from_uuid(result.uuid);
characteristic->properties = result.properties;
characteristic->handle = result.char_handle;
characteristic->service = this;
this->characteristics.push_back(characteristic);
ESP_LOGI(TAG, " characteristic %s, handle 0x%x, properties 0x%x", characteristic->uuid.to_string().c_str(),
characteristic->handle, characteristic->properties);
characteristic->parse_descriptors();
offset++;
}
}
} // namespace esp32_ble_client
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,32 @@
#pragma once
#ifdef USE_ESP32
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "ble_characteristic.h"
namespace esphome {
namespace esp32_ble_client {
namespace espbt = esphome::esp32_ble_tracker;
class BLEClientBase;
class BLEService {
public:
~BLEService();
espbt::ESPBTUUID uuid;
uint16_t start_handle;
uint16_t end_handle;
std::vector<BLECharacteristic *> characteristics;
BLEClientBase *client;
void parse_characteristics();
BLECharacteristic *get_characteristic(espbt::ESPBTUUID uuid);
BLECharacteristic *get_characteristic(uint16_t uuid);
};
} // namespace esp32_ble_client
} // namespace esphome
#endif // USE_ESP32

View File

@@ -3,6 +3,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.const import (
CONF_ACTIVE,
CONF_ID,
CONF_INTERVAL,
CONF_DURATION,
@@ -22,7 +23,6 @@ DEPENDENCIES = ["esp32"]
CONF_ESP32_BLE_ID = "esp32_ble_id"
CONF_SCAN_PARAMETERS = "scan_parameters"
CONF_WINDOW = "window"
CONF_ACTIVE = "active"
CONF_CONTINUOUS = "continuous"
CONF_ON_SCAN_END = "on_scan_end"
esp32_ble_tracker_ns = cg.esphome_ns.namespace("esp32_ble_tracker")

View File

@@ -518,28 +518,39 @@ bool ESPBTUUID::operator==(const ESPBTUUID &uuid) const {
}
esp_bt_uuid_t ESPBTUUID::get_uuid() const { return this->uuid_; }
std::string ESPBTUUID::to_string() const {
char sbuf[64];
switch (this->uuid_.len) {
case ESP_UUID_LEN_16:
sprintf(sbuf, "0x%02X%02X", this->uuid_.uuid.uuid16 >> 8, this->uuid_.uuid.uuid16 & 0xff);
break;
return str_snprintf("0x%02X%02X", 6, this->uuid_.uuid.uuid16 >> 8, this->uuid_.uuid.uuid16 & 0xff);
case ESP_UUID_LEN_32:
sprintf(sbuf, "0x%02X%02X%02X%02X", this->uuid_.uuid.uuid32 >> 24, (this->uuid_.uuid.uuid32 >> 16 & 0xff),
(this->uuid_.uuid.uuid32 >> 8 & 0xff), this->uuid_.uuid.uuid32 & 0xff);
break;
return str_snprintf("0x%02X%02X%02X%02X", 10, this->uuid_.uuid.uuid32 >> 24,
(this->uuid_.uuid.uuid32 >> 16 & 0xff), (this->uuid_.uuid.uuid32 >> 8 & 0xff),
this->uuid_.uuid.uuid32 & 0xff);
default:
case ESP_UUID_LEN_128:
char *bpos = sbuf;
std::string buf;
for (int8_t i = 15; i >= 0; i--) {
sprintf(bpos, "%02X", this->uuid_.uuid.uuid128[i]);
bpos += 2;
buf += str_snprintf("%02X", 2, this->uuid_.uuid.uuid128[i]);
if (i == 6 || i == 8 || i == 10 || i == 12)
sprintf(bpos++, "-");
buf += "-";
}
sbuf[47] = '\0';
break;
return buf;
}
return sbuf;
return "";
}
uint64_t ESPBTUUID::get_128bit_high() const {
esp_bt_uuid_t uuid = this->as_128bit().get_uuid();
return ((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 ESPBTUUID::get_128bit_low() const {
esp_bt_uuid_t uuid = this->as_128bit().get_uuid();
return ((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]);
}
ESPBLEiBeacon::ESPBLEiBeacon(const uint8_t *data) { memcpy(&this->beacon_data_, data, sizeof(beacon_data_)); }

View File

@@ -41,6 +41,9 @@ class ESPBTUUID {
std::string to_string() const;
uint64_t get_128bit_high() const;
uint64_t get_128bit_low() const;
protected:
esp_bt_uuid_t uuid_;
};
@@ -158,7 +161,7 @@ class ESPBTClient : public ESPBTDeviceListener {
esp_ble_gattc_cb_param_t *param) = 0;
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0;
virtual void connect() = 0;
void set_state(ClientState st) { this->state_ = st; }
virtual void set_state(ClientState st) { this->state_ = st; }
ClientState state() const { return state_; }
int app_id;

View File

@@ -72,13 +72,13 @@ class BLEEvent {
// Need to also make a copy of relevant event data.
switch (e) {
case ESP_GATTC_NOTIFY_EVT:
memcpy(this->event_.gattc.data, p->notify.value, p->notify.value_len);
this->event_.gattc.gattc_param.notify.value = this->event_.gattc.data;
this->data.assign(p->notify.value, p->notify.value + p->notify.value_len);
this->event_.gattc.gattc_param.notify.value = this->data.data();
break;
case ESP_GATTC_READ_CHAR_EVT:
case ESP_GATTC_READ_DESCR_EVT:
memcpy(this->event_.gattc.data, p->read.value, p->read.value_len);
this->event_.gattc.gattc_param.read.value = this->event_.gattc.data;
this->data.assign(p->read.value, p->read.value + p->read.value_len);
this->event_.gattc.gattc_param.read.value = this->data.data();
break;
default:
break;
@@ -96,9 +96,9 @@ class BLEEvent {
esp_gattc_cb_event_t gattc_event;
esp_gatt_if_t gattc_if;
esp_ble_gattc_cb_param_t gattc_param;
uint8_t data[64];
} gattc;
} event_;
std::vector<uint8_t> data{};
uint8_t type_; // 0=gap 1=gattc
};

View File

@@ -21,8 +21,8 @@ class HDC1080Component : public PollingComponent, public i2c::I2CDevice {
float get_setup_priority() const override;
protected:
sensor::Sensor *temperature_;
sensor::Sensor *humidity_;
sensor::Sensor *temperature_{nullptr};
sensor::Sensor *humidity_{nullptr};
};
} // namespace hdc1080

View File

@@ -54,10 +54,10 @@ class HMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
HMC5883LOversampling oversampling_{HMC5883L_OVERSAMPLING_1};
HMC5883LDatarate datarate_{HMC5883L_DATARATE_15_0_HZ};
HMC5883LRange range_{HMC5883L_RANGE_130_UT};
sensor::Sensor *x_sensor_;
sensor::Sensor *y_sensor_;
sensor::Sensor *z_sensor_;
sensor::Sensor *heading_sensor_;
sensor::Sensor *x_sensor_{nullptr};
sensor::Sensor *y_sensor_{nullptr};
sensor::Sensor *z_sensor_{nullptr};
sensor::Sensor *heading_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,

View File

@@ -29,8 +29,8 @@ class HONEYWELLABPSensor : public PollingComponent,
uint8_t status_ = 0; // byte to hold status information.
int pressure_count_ = 0; // hold raw pressure data (14 - bit, 0 - 16384)
int temperature_count_ = 0; // hold raw temperature data (11 - bit, 0 - 2048)
sensor::Sensor *pressure_sensor_;
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_{nullptr};
sensor::Sensor *temperature_sensor_{nullptr};
uint8_t readsensor_();
uint8_t readstatus_();
int rawpressure_();

View File

@@ -58,9 +58,9 @@ class HydreonRGxxComponent : public PollingComponent, public uart::UARTDevice {
sensor::Sensor *sensors_[NUM_SENSORS] = {nullptr};
#ifdef USE_BINARY_SENSOR
binary_sensor::BinarySensor *too_cold_sensor_ = nullptr;
binary_sensor::BinarySensor *lens_bad_sensor_ = nullptr;
binary_sensor::BinarySensor *em_sat_sensor_ = nullptr;
binary_sensor::BinarySensor *too_cold_sensor_{nullptr};
binary_sensor::BinarySensor *lens_bad_sensor_{nullptr};
binary_sensor::BinarySensor *em_sat_sensor_{nullptr};
#endif
int16_t boot_count_ = 0;

View File

@@ -52,7 +52,7 @@ class MLX90393Cls : public PollingComponent, public i2c::I2CDevice, public MLX90
uint8_t temperature_oversampling_ = 0;
uint8_t filter_;
uint8_t resolutions_[3] = {0};
GPIOPin *drdy_pin_ = nullptr;
GPIOPin *drdy_pin_{nullptr};
};
} // namespace mlx90393

View File

@@ -22,8 +22,8 @@ class MS5611Component : public PollingComponent, public i2c::I2CDevice {
void read_pressure_(uint32_t raw_temperature);
void calculate_values_(uint32_t raw_temperature, uint32_t raw_pressure);
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
uint16_t prom_[6];
};

View File

@@ -59,8 +59,8 @@ class PIDClimate : public climate::Climate, public Component {
/// The sensor used for getting the current temperature
sensor::Sensor *sensor_;
output::FloatOutput *cool_output_ = nullptr;
output::FloatOutput *heat_output_ = nullptr;
output::FloatOutput *cool_output_{nullptr};
output::FloatOutput *heat_output_{nullptr};
PIDController controller_;
/// Output value as reported by the PID controller, for PIDClimateSensor
float output_value_;

View File

@@ -81,7 +81,7 @@ class PulseCounterSensor : public sensor::Sensor, public PollingComponent {
PulseCounterStorageBase &storage_;
uint32_t last_time_{0};
uint32_t current_total_{0};
sensor::Sensor *total_sensor_;
sensor::Sensor *total_sensor_{nullptr};
};
} // namespace pulse_counter

View File

@@ -31,11 +31,11 @@ class PulseMeterSensor : public sensor::Sensor, public Component {
protected:
static void gpio_intr(PulseMeterSensor *sensor);
InternalGPIOPin *pin_ = nullptr;
InternalGPIOPin *pin_{nullptr};
ISRInternalGPIOPin isr_pin_;
uint32_t filter_us_ = 0;
uint32_t timeout_us_ = 1000000UL * 60UL * 5UL;
sensor::Sensor *total_sensor_ = nullptr;
sensor::Sensor *total_sensor_{nullptr};
InternalFilterMode filter_mode_{FILTER_EDGE};
Deduplicator<uint32_t> pulse_width_dedupe_;

View File

@@ -102,8 +102,9 @@ void PVVXDisplay::send_to_setup_char_(uint8_t *blk, size_t size) {
ESP_LOGW(TAG, "[%s] Not connected to BLE client.", this->parent_->address_str().c_str());
return;
}
auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, size, blk,
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, size,
blk, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
} else {

View File

@@ -114,7 +114,7 @@ class PVVXDisplay : public ble_client::BLEClientNode, public PollingComponent {
void delayed_disconnect_();
#ifdef USE_TIME
void sync_time_();
time::RealTimeClock *time_ = nullptr;
time::RealTimeClock *time_{nullptr};
#endif
uint16_t char_handle_ = 0;
bool connection_established_ = false;

View File

@@ -23,10 +23,10 @@ class PZEM004T : public PollingComponent, public uart::UARTDevice {
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;
sensor::Sensor *power_sensor_;
sensor::Sensor *energy_sensor_;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
enum PZEM004TReadState {
SET_ADDRESS = 0xB4,

View File

@@ -27,12 +27,12 @@ class PZEMAC : public PollingComponent, public modbus::ModbusDevice {
protected:
template<typename... Ts> friend class ResetEnergyAction;
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;
sensor::Sensor *power_sensor_;
sensor::Sensor *energy_sensor_;
sensor::Sensor *frequency_sensor_;
sensor::Sensor *power_factor_sensor_;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
sensor::Sensor *frequency_sensor_{nullptr};
sensor::Sensor *power_factor_sensor_{nullptr};
void reset_energy_();
};

View File

@@ -22,11 +22,11 @@ class PZEMDC : public PollingComponent, public modbus::ModbusDevice {
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;
sensor::Sensor *power_sensor_;
sensor::Sensor *frequency_sensor_;
sensor::Sensor *power_factor_sensor_;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *frequency_sensor_{nullptr};
sensor::Sensor *power_factor_sensor_{nullptr};
};
} // namespace pzemdc

View File

@@ -45,10 +45,10 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
QMC5883LDatarate datarate_{QMC5883L_DATARATE_10_HZ};
QMC5883LRange range_{QMC5883L_RANGE_200_UT};
QMC5883LOversampling oversampling_{QMC5883L_SAMPLING_512};
sensor::Sensor *x_sensor_;
sensor::Sensor *y_sensor_;
sensor::Sensor *z_sensor_;
sensor::Sensor *heading_sensor_;
sensor::Sensor *x_sensor_{nullptr};
sensor::Sensor *y_sensor_{nullptr};
sensor::Sensor *z_sensor_{nullptr};
sensor::Sensor *heading_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,

View File

@@ -91,8 +91,8 @@ class QMP6988Component : public PollingComponent, public i2c::I2CDevice {
protected:
qmp6988_data_t qmp6988_data_;
sensor::Sensor *temperature_sensor_;
sensor::Sensor *pressure_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *pressure_sensor_{nullptr};
QMP6988Oversampling temperature_oversampling_{QMP6988_OVERSAMPLING_16X};
QMP6988Oversampling pressure_oversampling_{QMP6988_OVERSAMPLING_16X};

View File

@@ -50,7 +50,7 @@ void RadonEyeRD200::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
}
case ESP_GATTC_READ_CHAR_EVT: {
if (param->read.conn_id != this->parent()->conn_id)
if (param->read.conn_id != this->parent()->get_conn_id())
break;
if (param->read.status != ESP_GATT_OK) {
ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
@@ -146,17 +146,17 @@ void RadonEyeRD200::update() {
void RadonEyeRD200::write_query_message_() {
ESP_LOGV(TAG, "writing 0x50 to write service");
int request = 0x50;
auto status = esp_ble_gattc_write_char_descr(this->parent()->gattc_if, this->parent()->conn_id, this->write_handle_,
sizeof(request), (uint8_t *) &request, ESP_GATT_WRITE_TYPE_NO_RSP,
ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_write_char_descr(this->parent()->get_gattc_if(), this->parent()->get_conn_id(),
this->write_handle_, sizeof(request), (uint8_t *) &request,
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "Error sending write request for sensor, status=%d", status);
}
}
void RadonEyeRD200::request_read_values_() {
auto status = esp_ble_gattc_read_char(this->parent()->gattc_if, this->parent()->conn_id, this->read_handle_,
ESP_GATT_AUTH_REQ_NONE);
auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(),
this->read_handle_, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status);
}

View File

@@ -227,7 +227,18 @@ optional<ProntoData> ProntoProtocol::decode(RemoteReceiveData src) {
return out;
}
void ProntoProtocol::dump(const ProntoData &data) { ESP_LOGD(TAG, "Received Pronto: data=%s", data.data.c_str()); }
void ProntoProtocol::dump(const ProntoData &data) {
std::string first, rest;
if (data.data.size() < 230) {
first = data.data;
} else {
first = data.data.substr(0, 229);
rest = data.data.substr(230);
}
ESP_LOGD(TAG, "Received Pronto: data=%s", first.c_str());
if (!rest.empty())
ESP_LOGD(TAG, "%s", rest.c_str());
}
} // namespace remote_base
} // namespace esphome

View File

@@ -19,8 +19,8 @@ class SHT3XDComponent : public PollingComponent, public sensirion_common::Sensir
void update() override;
protected:
sensor::Sensor *temperature_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace sht3xd

View File

@@ -26,8 +26,8 @@ class SHTCXComponent : public PollingComponent, public sensirion_common::Sensiri
protected:
SHTCXType type_;
uint16_t sensor_id_;
sensor::Sensor *temperature_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace shtcx

View File

@@ -18,15 +18,42 @@ Sim800LReceivedMessageTrigger = sim800l_ns.class_(
"Sim800LReceivedMessageTrigger",
automation.Trigger.template(cg.std_string, cg.std_string),
)
Sim800LIncomingCallTrigger = sim800l_ns.class_(
"Sim800LIncomingCallTrigger",
automation.Trigger.template(cg.std_string),
)
Sim800LCallConnectedTrigger = sim800l_ns.class_(
"Sim800LCallConnectedTrigger",
automation.Trigger.template(),
)
Sim800LCallDisconnectedTrigger = sim800l_ns.class_(
"Sim800LCallDisconnectedTrigger",
automation.Trigger.template(),
)
Sim800LReceivedUssdTrigger = sim800l_ns.class_(
"Sim800LReceivedUssdTrigger",
automation.Trigger.template(cg.std_string),
)
# Actions
Sim800LSendSmsAction = sim800l_ns.class_("Sim800LSendSmsAction", automation.Action)
Sim800LSendUssdAction = sim800l_ns.class_("Sim800LSendUssdAction", automation.Action)
Sim800LDialAction = sim800l_ns.class_("Sim800LDialAction", automation.Action)
Sim800LConnectAction = sim800l_ns.class_("Sim800LConnectAction", automation.Action)
Sim800LDisconnectAction = sim800l_ns.class_(
"Sim800LDisconnectAction", automation.Action
)
CONF_SIM800L_ID = "sim800l_id"
CONF_ON_SMS_RECEIVED = "on_sms_received"
CONF_ON_USSD_RECEIVED = "on_ussd_received"
CONF_ON_INCOMING_CALL = "on_incoming_call"
CONF_ON_CALL_CONNECTED = "on_call_connected"
CONF_ON_CALL_DISCONNECTED = "on_call_disconnected"
CONF_RECIPIENT = "recipient"
CONF_MESSAGE = "message"
CONF_USSD = "ussd"
CONFIG_SCHEMA = cv.All(
cv.Schema(
@@ -39,6 +66,34 @@ CONFIG_SCHEMA = cv.All(
),
}
),
cv.Optional(CONF_ON_INCOMING_CALL): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
Sim800LIncomingCallTrigger
),
}
),
cv.Optional(CONF_ON_CALL_CONNECTED): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
Sim800LCallConnectedTrigger
),
}
),
cv.Optional(CONF_ON_CALL_DISCONNECTED): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
Sim800LCallDisconnectedTrigger
),
}
),
cv.Optional(CONF_ON_USSD_RECEIVED): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
Sim800LReceivedUssdTrigger
),
}
),
}
)
.extend(cv.polling_component_schema("5s"))
@@ -59,6 +114,19 @@ async def to_code(config):
await automation.build_automation(
trigger, [(cg.std_string, "message"), (cg.std_string, "sender")], conf
)
for conf in config.get(CONF_ON_INCOMING_CALL, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(cg.std_string, "caller_id")], conf)
for conf in config.get(CONF_ON_CALL_CONNECTED, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_CALL_DISCONNECTED, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_USSD_RECEIVED, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(cg.std_string, "ussd")], conf)
SIM800L_SEND_SMS_SCHEMA = cv.Schema(
@@ -98,3 +166,44 @@ async def sim800l_dial_to_code(config, action_id, template_arg, args):
template_ = await cg.templatable(config[CONF_RECIPIENT], args, cg.std_string)
cg.add(var.set_recipient(template_))
return var
@automation.register_action(
"sim800l.connect",
Sim800LConnectAction,
cv.Schema({cv.GenerateID(): cv.use_id(Sim800LComponent)}),
)
async def sim800l_connect_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
return var
SIM800L_SEND_USSD_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(Sim800LComponent),
cv.Required(CONF_USSD): cv.templatable(cv.string_strict),
}
)
@automation.register_action(
"sim800l.send_ussd", Sim800LSendUssdAction, SIM800L_SEND_USSD_SCHEMA
)
async def sim800l_send_ussd_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_USSD], args, cg.std_string)
cg.add(var.set_ussd(template_))
return var
@automation.register_action(
"sim800l.disconnect",
Sim800LDisconnectAction,
cv.Schema({cv.GenerateID(): cv.use_id(Sim800LComponent)}),
)
async def sim800l_disconnect_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
return var

View File

@@ -16,20 +16,38 @@ void Sim800LComponent::update() {
this->write(26);
}
if (this->expect_ack_)
return;
if (state_ == STATE_INIT) {
if (this->registered_ && this->send_pending_) {
this->send_cmd_("AT+CSCS=\"GSM\"");
this->state_ = STATE_SENDINGSMS1;
this->state_ = STATE_SENDING_SMS_1;
} else if (this->registered_ && this->dial_pending_) {
this->send_cmd_("AT+CSCS=\"GSM\"");
this->state_ = STATE_DIALING1;
} else if (this->registered_ && this->connect_pending_) {
this->connect_pending_ = false;
ESP_LOGI(TAG, "Connecting...");
this->send_cmd_("ATA");
this->state_ = STATE_ATA_SENT;
} else if (this->registered_ && this->send_ussd_pending_) {
this->send_cmd_("AT+CSCS=\"GSM\"");
this->state_ = STATE_SEND_USSD1;
} else if (this->registered_ && this->disconnect_pending_) {
this->disconnect_pending_ = false;
ESP_LOGI(TAG, "Disconnecting...");
this->send_cmd_("ATH");
} else if (this->registered_ && this->call_state_ != 6) {
send_cmd_("AT+CLCC");
this->state_ = STATE_CHECK_CALL;
return;
} else {
this->send_cmd_("AT");
this->state_ = STATE_CHECK_AT;
this->state_ = STATE_SETUP_CMGF;
}
this->expect_ack_ = true;
}
if (state_ == STATE_RECEIVEDSMS) {
} else if (state_ == STATE_RECEIVED_SMS) {
// Serial Buffer should have flushed.
// Send cmd to delete received sms
char delete_cmd[20];
@@ -49,16 +67,29 @@ void Sim800LComponent::send_cmd_(const std::string &message) {
}
void Sim800LComponent::parse_cmd_(std::string message) {
ESP_LOGV(TAG, "R: %s - %d", message.c_str(), this->state_);
if (message.empty())
return;
if (this->expect_ack_) {
ESP_LOGV(TAG, "R: %s - %d", message.c_str(), this->state_);
if (this->state_ != STATE_RECEIVE_SMS) {
if (message == "RING") {
// Incoming call...
this->state_ = STATE_PARSE_CLIP;
this->expect_ack_ = false;
} else if (message == "NO CARRIER") {
if (this->call_state_ != 6) {
this->call_state_ = 6;
this->call_disconnected_callback_.call();
}
}
}
bool ok = message == "OK";
if (this->expect_ack_) {
this->expect_ack_ = false;
if (!ok) {
if (this->state_ == STATE_CHECK_AT && message == "AT") {
if (this->state_ == STATE_SETUP_CMGF && message == "AT") {
// Expected ack but AT echo received
this->state_ = STATE_DISABLE_ECHO;
this->expect_ack_ = true;
@@ -68,6 +99,10 @@ void Sim800LComponent::parse_cmd_(std::string message) {
return;
}
}
} else if (ok && (this->state_ != STATE_PARSE_SMS_RESPONSE && this->state_ != STATE_CHECK_CALL &&
this->state_ != STATE_RECEIVE_SMS && this->state_ != STATE_DIALING2)) {
ESP_LOGW(TAG, "Received unexpected OK. Ignoring");
return;
}
switch (this->state_) {
@@ -75,30 +110,88 @@ void Sim800LComponent::parse_cmd_(std::string message) {
// While we were waiting for update to check for messages, this notifies a message
// is available.
bool message_available = message.compare(0, 6, "+CMTI:") == 0;
if (!message_available)
if (!message_available) {
if (message == "RING") {
// Incoming call...
this->state_ = STATE_PARSE_CLIP;
} else if (message == "NO CARRIER") {
if (this->call_state_ != 6) {
this->call_state_ = 6;
this->call_disconnected_callback_.call();
}
} else if (message.compare(0, 6, "+CUSD:") == 0) {
// Incoming USSD MESSAGE
this->state_ = STATE_CHECK_USSD;
}
break;
}
// Else fall thru ...
}
case STATE_CHECK_SMS:
send_cmd_("AT+CMGL=\"ALL\"");
this->state_ = STATE_PARSE_SMS;
this->state_ = STATE_PARSE_SMS_RESPONSE;
this->parse_index_ = 0;
break;
case STATE_DISABLE_ECHO:
send_cmd_("ATE0");
this->state_ = STATE_CHECK_AT;
this->state_ = STATE_SETUP_CMGF;
this->expect_ack_ = true;
break;
case STATE_CHECK_AT:
case STATE_SETUP_CMGF:
send_cmd_("AT+CMGF=1");
this->state_ = STATE_SETUP_CLIP;
this->expect_ack_ = true;
break;
case STATE_SETUP_CLIP:
send_cmd_("AT+CLIP=1");
this->state_ = STATE_CREG;
this->expect_ack_ = true;
break;
case STATE_SETUP_USSD:
send_cmd_("AT+CUSD=1");
this->state_ = STATE_CREG;
this->expect_ack_ = true;
break;
case STATE_SEND_USSD1:
this->send_cmd_("AT+CUSD=1, \"" + this->ussd_ + "\"");
this->state_ = STATE_SEND_USSD2;
break;
case STATE_SEND_USSD2:
ESP_LOGD(TAG, "SendUssd2: '%s'", message.c_str());
if (message == "OK") {
// Dialing
ESP_LOGD(TAG, "Dialing ussd code: '%s' done.", this->ussd_.c_str());
this->state_ = STATE_CHECK_USSD;
this->send_ussd_pending_ = false;
} else {
this->set_registered_(false);
this->state_ = STATE_INIT;
this->send_cmd_("AT+CMEE=2");
this->write(26);
}
break;
case STATE_CHECK_USSD:
ESP_LOGD(TAG, "Check ussd code: '%s'", message.c_str());
if (message.compare(0, 6, "+CUSD:") == 0) {
this->state_ = STATE_RECEIVED_USSD;
this->ussd_ = "";
size_t start = 10;
size_t end = message.find_last_of(',');
if (end > start) {
this->ussd_ = message.substr(start + 1, end - start - 2);
this->ussd_received_callback_.call(this->ussd_);
}
}
// Otherwise we receive another OK, we do nothing just wait polling to continuously check for SMS
if (message == "OK")
this->state_ = STATE_INIT;
break;
case STATE_CREG:
send_cmd_("AT+CREG?");
this->state_ = STATE_CREGWAIT;
this->state_ = STATE_CREG_WAIT;
break;
case STATE_CREGWAIT: {
case STATE_CREG_WAIT: {
// Response: "+CREG: 0,1" -- the one there means registered ok
// "+CREG: -,-" means not registered ok
bool registered = message.compare(0, 6, "+CREG:") == 0 && (message[9] == '1' || message[9] == '5');
@@ -112,10 +205,10 @@ void Sim800LComponent::parse_cmd_(std::string message) {
if (message[7] == '0') { // Network registration is disable, enable it
send_cmd_("AT+CREG=1");
this->expect_ack_ = true;
this->state_ = STATE_CHECK_AT;
this->state_ = STATE_SETUP_CMGF;
} else {
// Keep waiting registration
this->state_ = STATE_CREG;
this->state_ = STATE_INIT;
}
}
set_registered_(registered);
@@ -145,9 +238,6 @@ void Sim800LComponent::parse_cmd_(std::string message) {
this->expect_ack_ = true;
this->state_ = STATE_CHECK_SMS;
break;
case STATE_PARSE_SMS:
this->state_ = STATE_PARSE_SMS_RESPONSE;
break;
case STATE_PARSE_SMS_RESPONSE:
if (message.compare(0, 6, "+CMGL:") == 0 && this->parse_index_ == 0) {
size_t start = 7;
@@ -158,10 +248,11 @@ void Sim800LComponent::parse_cmd_(std::string message) {
if (item == 1) { // Slot Index
this->parse_index_ = parse_number<uint8_t>(message.substr(start, end - start)).value_or(0);
}
// item 2 = STATUS, usually "REC UNERAD"
// item 2 = STATUS, usually "REC UNREAD"
if (item == 3) { // recipient
// Add 1 and remove 2 from substring to get rid of "quotes"
this->sender_ = message.substr(start + 1, end - start - 2);
this->message_.clear();
break;
}
// item 4 = ""
@@ -174,42 +265,83 @@ void Sim800LComponent::parse_cmd_(std::string message) {
ESP_LOGD(TAG, "Invalid message %d %s", this->state_, message.c_str());
return;
}
this->state_ = STATE_RECEIVESMS;
this->state_ = STATE_RECEIVE_SMS;
}
// Otherwise we receive another OK
if (ok) {
send_cmd_("AT+CLCC");
this->state_ = STATE_CHECK_CALL;
}
break;
case STATE_CHECK_CALL:
if (message.compare(0, 6, "+CLCC:") == 0 && this->parse_index_ == 0) {
this->expect_ack_ = true;
size_t start = 7;
size_t end = message.find(',', start);
uint8_t item = 0;
while (end != start) {
item++;
// item 1 call index for +CHLD
// item 2 dir 0 Mobile originated; 1 Mobile terminated
if (item == 3) { // stat
uint8_t current_call_state = parse_number<uint8_t>(message.substr(start, end - start)).value_or(6);
if (current_call_state != this->call_state_) {
ESP_LOGD(TAG, "Call state is now: %d", current_call_state);
if (current_call_state == 0)
this->call_connected_callback_.call();
}
this->call_state_ = current_call_state;
break;
}
// item 4 = ""
// item 5 = Received timestamp
start = end + 1;
end = message.find(',', start);
}
if (item < 2) {
ESP_LOGD(TAG, "Invalid message %d %s", this->state_, message.c_str());
return;
}
} else if (ok) {
if (this->call_state_ != 6) {
// no call in progress
this->call_state_ = 6; // Disconnect
this->call_disconnected_callback_.call();
}
}
// Otherwise we receive another OK, we do nothing just wait polling to continuously check for SMS
if (message == "OK")
this->state_ = STATE_INIT;
break;
case STATE_RECEIVESMS:
case STATE_RECEIVE_SMS:
/* Our recipient is set and the message body is in message
kick ESPHome callback now
*/
if (ok || message.compare(0, 6, "+CMGL:") == 0) {
ESP_LOGD(TAG, "Received SMS from: %s", this->sender_.c_str());
ESP_LOGD(TAG, "%s", message.c_str());
this->callback_.call(message, this->sender_);
/* If the message is multiline, next lines will contain message data.
If there were other messages in the list, next line will be +CMGL: ...
At the end of the list the new line and the OK should be received.
To keep this simple just first line of message if considered, then
the next state will swallow all received data and in next poll event
this message index is marked for deletion.
*/
this->state_ = STATE_RECEIVEDSMS;
ESP_LOGD(TAG, "%s", this->message_.c_str());
this->sms_received_callback_.call(this->message_, this->sender_);
this->state_ = STATE_RECEIVED_SMS;
} else {
if (this->message_.length() > 0)
this->message_ += "\n";
this->message_ += message;
}
break;
case STATE_RECEIVEDSMS:
case STATE_RECEIVED_SMS:
case STATE_RECEIVED_USSD:
// Let the buffer flush. Next poll will request to delete the parsed index message.
break;
case STATE_SENDINGSMS1:
case STATE_SENDING_SMS_1:
this->send_cmd_("AT+CMGS=\"" + this->recipient_ + "\"");
this->state_ = STATE_SENDINGSMS2;
this->state_ = STATE_SENDING_SMS_2;
break;
case STATE_SENDINGSMS2:
case STATE_SENDING_SMS_2:
if (message == ">") {
// Send sms body
ESP_LOGD(TAG, "Sending message: '%s'", this->outgoing_message_.c_str());
ESP_LOGI(TAG, "Sending to %s message: '%s'", this->recipient_.c_str(), this->outgoing_message_.c_str());
this->write_str(this->outgoing_message_.c_str());
this->write(26);
this->state_ = STATE_SENDINGSMS3;
this->state_ = STATE_SENDING_SMS_3;
} else {
set_registered_(false);
this->state_ = STATE_INIT;
@@ -217,7 +349,7 @@ void Sim800LComponent::parse_cmd_(std::string message) {
this->write(26);
}
break;
case STATE_SENDINGSMS3:
case STATE_SENDING_SMS_3:
if (message.compare(0, 6, "+CMGS:") == 0) {
ESP_LOGD(TAG, "SMS Sent OK: %s", message.c_str());
this->send_pending_ = false;
@@ -230,23 +362,55 @@ void Sim800LComponent::parse_cmd_(std::string message) {
this->state_ = STATE_DIALING2;
break;
case STATE_DIALING2:
if (message == "OK") {
// Dialing
ESP_LOGD(TAG, "Dialing: '%s'", this->recipient_.c_str());
this->state_ = STATE_INIT;
if (ok) {
ESP_LOGI(TAG, "Dialing: '%s'", this->recipient_.c_str());
this->dial_pending_ = false;
} else {
this->set_registered_(false);
this->state_ = STATE_INIT;
this->send_cmd_("AT+CMEE=2");
this->write(26);
}
this->state_ = STATE_INIT;
break;
default:
ESP_LOGD(TAG, "Unhandled: %s - %d", message.c_str(), this->state_);
case STATE_PARSE_CLIP:
if (message.compare(0, 6, "+CLIP:") == 0) {
std::string caller_id;
size_t start = 7;
size_t end = message.find(',', start);
uint8_t item = 0;
while (end != start) {
item++;
if (item == 1) { // Slot Index
// Add 1 and remove 2 from substring to get rid of "quotes"
caller_id = message.substr(start + 1, end - start - 2);
break;
}
}
// item 4 = ""
// item 5 = Received timestamp
start = end + 1;
end = message.find(',', start);
}
if (this->call_state_ != 4) {
this->call_state_ = 4;
ESP_LOGI(TAG, "Incoming call from %s", caller_id.c_str());
incoming_call_callback_.call(caller_id);
}
this->state_ = STATE_INIT;
}
break;
case STATE_ATA_SENT:
ESP_LOGI(TAG, "Call connected");
if (this->call_state_ != 0) {
this->call_state_ = 0;
this->call_connected_callback_.call();
}
this->state_ = STATE_INIT;
break;
default:
ESP_LOGW(TAG, "Unhandled: %s - %d", message.c_str(), this->state_);
break;
}
} // namespace sim800l
void Sim800LComponent::loop() {
// Read message
@@ -265,7 +429,7 @@ void Sim800LComponent::loop() {
byte = '?'; // need to be valid utf8 string for log functions.
this->read_buffer_[this->read_pos_] = byte;
if (this->state_ == STATE_SENDINGSMS2 && this->read_pos_ == 0 && byte == '>')
if (this->state_ == STATE_SENDING_SMS_2 && this->read_pos_ == 0 && byte == '>')
this->read_buffer_[++this->read_pos_] = ASCII_LF;
if (this->read_buffer_[this->read_pos_] == ASCII_LF) {
@@ -276,13 +440,23 @@ void Sim800LComponent::loop() {
this->read_pos_++;
}
}
if (state_ == STATE_INIT && this->registered_ &&
(this->call_state_ != 6 // A call is in progress
|| this->send_pending_ || this->dial_pending_ || this->connect_pending_ || this->disconnect_pending_)) {
this->update();
}
}
void Sim800LComponent::send_sms(const std::string &recipient, const std::string &message) {
ESP_LOGD(TAG, "Sending to %s: %s", recipient.c_str(), message.c_str());
this->recipient_ = recipient;
this->outgoing_message_ = message;
this->send_pending_ = true;
}
void Sim800LComponent::send_ussd(const std::string &ussd_code) {
ESP_LOGD(TAG, "Sending USSD code: %s", ussd_code.c_str());
this->ussd_ = ussd_code;
this->send_ussd_pending_ = true;
this->update();
}
void Sim800LComponent::dump_config() {
@@ -295,11 +469,11 @@ void Sim800LComponent::dump_config() {
#endif
}
void Sim800LComponent::dial(const std::string &recipient) {
ESP_LOGD(TAG, "Dialing %s", recipient.c_str());
this->recipient_ = recipient;
this->dial_pending_ = true;
this->update();
}
void Sim800LComponent::connect() { this->connect_pending_ = true; }
void Sim800LComponent::disconnect() { this->disconnect_pending_ = true; }
void Sim800LComponent::set_registered_(bool registered) {
this->registered_ = registered;

View File

@@ -16,31 +16,35 @@
namespace esphome {
namespace sim800l {
const uint8_t SIM800L_READ_BUFFER_LENGTH = 255;
const uint16_t SIM800L_READ_BUFFER_LENGTH = 1024;
enum State {
STATE_IDLE = 0,
STATE_INIT,
STATE_CHECK_AT,
STATE_SETUP_CMGF,
STATE_SETUP_CLIP,
STATE_CREG,
STATE_CREGWAIT,
STATE_CREG_WAIT,
STATE_CSQ,
STATE_CSQ_RESPONSE,
STATE_IDLEWAIT,
STATE_SENDINGSMS1,
STATE_SENDINGSMS2,
STATE_SENDINGSMS3,
STATE_SENDING_SMS_1,
STATE_SENDING_SMS_2,
STATE_SENDING_SMS_3,
STATE_CHECK_SMS,
STATE_PARSE_SMS,
STATE_PARSE_SMS_RESPONSE,
STATE_RECEIVESMS,
STATE_READSMS,
STATE_RECEIVEDSMS,
STATE_DELETEDSMS,
STATE_RECEIVE_SMS,
STATE_RECEIVED_SMS,
STATE_DISABLE_ECHO,
STATE_PARSE_SMS_OK,
STATE_DIALING1,
STATE_DIALING2
STATE_DIALING2,
STATE_PARSE_CLIP,
STATE_ATA_SENT,
STATE_CHECK_CALL,
STATE_SETUP_USSD,
STATE_SEND_USSD1,
STATE_SEND_USSD2,
STATE_CHECK_USSD,
STATE_RECEIVED_USSD
};
class Sim800LComponent : public uart::UARTDevice, public PollingComponent {
@@ -58,10 +62,25 @@ class Sim800LComponent : public uart::UARTDevice, public PollingComponent {
void set_rssi_sensor(sensor::Sensor *rssi_sensor) { rssi_sensor_ = rssi_sensor; }
#endif
void add_on_sms_received_callback(std::function<void(std::string, std::string)> callback) {
this->callback_.add(std::move(callback));
this->sms_received_callback_.add(std::move(callback));
}
void add_on_incoming_call_callback(std::function<void(std::string)> callback) {
this->incoming_call_callback_.add(std::move(callback));
}
void add_on_call_connected_callback(std::function<void()> callback) {
this->call_connected_callback_.add(std::move(callback));
}
void add_on_call_disconnected_callback(std::function<void()> callback) {
this->call_disconnected_callback_.add(std::move(callback));
}
void add_on_ussd_received_callback(std::function<void(std::string)> callback) {
this->ussd_received_callback_.add(std::move(callback));
}
void send_sms(const std::string &recipient, const std::string &message);
void send_ussd(const std::string &ussd_code);
void dial(const std::string &recipient);
void connect();
void disconnect();
protected:
void send_cmd_(const std::string &message);
@@ -76,6 +95,7 @@ class Sim800LComponent : public uart::UARTDevice, public PollingComponent {
sensor::Sensor *rssi_sensor_{nullptr};
#endif
std::string sender_;
std::string message_;
char read_buffer_[SIM800L_READ_BUFFER_LENGTH];
size_t read_pos_{0};
uint8_t parse_index_{0};
@@ -86,10 +106,19 @@ class Sim800LComponent : public uart::UARTDevice, public PollingComponent {
std::string recipient_;
std::string outgoing_message_;
std::string ussd_;
bool send_pending_;
bool dial_pending_;
bool connect_pending_;
bool disconnect_pending_;
bool send_ussd_pending_;
uint8_t call_state_{6};
CallbackManager<void(std::string, std::string)> callback_;
CallbackManager<void(std::string, std::string)> sms_received_callback_;
CallbackManager<void(std::string)> incoming_call_callback_;
CallbackManager<void()> call_connected_callback_;
CallbackManager<void()> call_disconnected_callback_;
CallbackManager<void(std::string)> ussd_received_callback_;
};
class Sim800LReceivedMessageTrigger : public Trigger<std::string, std::string> {
@@ -100,6 +129,33 @@ class Sim800LReceivedMessageTrigger : public Trigger<std::string, std::string> {
}
};
class Sim800LIncomingCallTrigger : public Trigger<std::string> {
public:
explicit Sim800LIncomingCallTrigger(Sim800LComponent *parent) {
parent->add_on_incoming_call_callback([this](const std::string &caller_id) { this->trigger(caller_id); });
}
};
class Sim800LCallConnectedTrigger : public Trigger<> {
public:
explicit Sim800LCallConnectedTrigger(Sim800LComponent *parent) {
parent->add_on_call_connected_callback([this]() { this->trigger(); });
}
};
class Sim800LCallDisconnectedTrigger : public Trigger<> {
public:
explicit Sim800LCallDisconnectedTrigger(Sim800LComponent *parent) {
parent->add_on_call_disconnected_callback([this]() { this->trigger(); });
}
};
class Sim800LReceivedUssdTrigger : public Trigger<std::string> {
public:
explicit Sim800LReceivedUssdTrigger(Sim800LComponent *parent) {
parent->add_on_ussd_received_callback([this](const std::string &ussd) { this->trigger(ussd); });
}
};
template<typename... Ts> class Sim800LSendSmsAction : public Action<Ts...> {
public:
Sim800LSendSmsAction(Sim800LComponent *parent) : parent_(parent) {}
@@ -116,6 +172,20 @@ template<typename... Ts> class Sim800LSendSmsAction : public Action<Ts...> {
Sim800LComponent *parent_;
};
template<typename... Ts> class Sim800LSendUssdAction : public Action<Ts...> {
public:
Sim800LSendUssdAction(Sim800LComponent *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(std::string, ussd)
void play(Ts... x) {
auto ussd_code = this->ussd_.value(x...);
this->parent_->send_ussd(ussd_code);
}
protected:
Sim800LComponent *parent_;
};
template<typename... Ts> class Sim800LDialAction : public Action<Ts...> {
public:
Sim800LDialAction(Sim800LComponent *parent) : parent_(parent) {}
@@ -129,6 +199,25 @@ template<typename... Ts> class Sim800LDialAction : public Action<Ts...> {
protected:
Sim800LComponent *parent_;
};
template<typename... Ts> class Sim800LConnectAction : public Action<Ts...> {
public:
Sim800LConnectAction(Sim800LComponent *parent) : parent_(parent) {}
void play(Ts... x) { this->parent_->connect(); }
protected:
Sim800LComponent *parent_;
};
template<typename... Ts> class Sim800LDisconnectAction : public Action<Ts...> {
public:
Sim800LDisconnectAction(Sim800LComponent *parent) : parent_(parent) {}
void play(Ts... x) { this->parent_->disconnect(); }
protected:
Sim800LComponent *parent_;
};
} // namespace sim800l
} // namespace esphome

View File

@@ -195,11 +195,6 @@ class SPIComponent : public Component {
template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, uint32_t DATA_RATE>
void enable(GPIOPin *cs) {
if (cs != nullptr) {
this->active_cs_ = cs;
this->active_cs_->digital_write(false);
}
#ifdef USE_SPI_ARDUINO_BACKEND
if (this->hw_spi_ != nullptr) {
uint8_t data_mode = SPI_MODE0;
@@ -220,6 +215,11 @@ class SPIComponent : public Component {
#ifdef USE_SPI_ARDUINO_BACKEND
}
#endif // USE_SPI_ARDUINO_BACKEND
if (cs != nullptr) {
this->active_cs_ = cs;
this->active_cs_->digital_write(false);
}
}
void disable();

View File

@@ -769,7 +769,7 @@ void Sprinkler::resume() {
ESP_LOGD(TAG, "Resuming valve %u with %u seconds remaining", this->paused_valve_.value_or(0),
this->resume_duration_.value_or(0));
this->fsm_request_(this->paused_valve_.value(), this->resume_duration_.value());
this->reset_resume_();
this->reset_resume();
} else {
ESP_LOGD(TAG, "No valve to resume!");
}
@@ -783,6 +783,11 @@ void Sprinkler::resume_or_start_full_cycle() {
}
}
void Sprinkler::reset_resume() {
this->paused_valve_.reset();
this->resume_duration_.reset();
}
const char *Sprinkler::valve_name(const size_t valve_number) {
if (this->is_a_valid_valve(valve_number)) {
return this->valve_[valve_number].controller_switch->get_name().c_str();
@@ -1101,11 +1106,6 @@ void Sprinkler::reset_cycle_states_() {
}
}
void Sprinkler::reset_resume_() {
this->paused_valve_.reset();
this->resume_duration_.reset();
}
void Sprinkler::fsm_request_(size_t requested_valve, uint32_t requested_run_duration) {
this->next_req_.set_valve(requested_valve);
this->next_req_.set_run_duration(requested_run_duration);

View File

@@ -308,6 +308,9 @@ class Sprinkler : public Component, public EntityBase {
/// if a cycle was suspended using pause(), resumes it. otherwise calls start_full_cycle()
void resume_or_start_full_cycle();
/// resets resume state
void reset_resume();
/// returns a pointer to a valve's name string object; returns nullptr if valve_number is invalid
const char *valve_name(size_t valve_number);
@@ -401,9 +404,6 @@ class Sprinkler : public Component, public EntityBase {
/// resets the cycle state for all valves
void reset_cycle_states_();
/// resets resume state
void reset_resume_();
/// make a request of the state machine
void fsm_request_(size_t requested_valve, uint32_t requested_run_duration = 0);

View File

@@ -245,10 +245,10 @@ class TSL2591Component : public PollingComponent, public i2c::I2CDevice {
protected:
const char *name_;
sensor::Sensor *full_spectrum_sensor_;
sensor::Sensor *infrared_sensor_;
sensor::Sensor *visible_sensor_;
sensor::Sensor *calculated_lux_sensor_;
sensor::Sensor *full_spectrum_sensor_{nullptr};
sensor::Sensor *infrared_sensor_{nullptr};
sensor::Sensor *visible_sensor_{nullptr};
sensor::Sensor *calculated_lux_sensor_{nullptr};
TSL2591IntegrationTime integration_time_;
TSL2591ComponentGain component_gain_;
TSL2591Gain gain_;

View File

@@ -43,8 +43,8 @@ class Tx20Component : public Component {
std::string wind_cardinal_direction_;
InternalGPIOPin *pin_;
sensor::Sensor *wind_speed_sensor_;
sensor::Sensor *wind_direction_degrees_sensor_;
sensor::Sensor *wind_speed_sensor_{nullptr};
sensor::Sensor *wind_direction_degrees_sensor_{nullptr};
Tx20ComponentStore store_;
};

View File

@@ -165,15 +165,19 @@ class Config(OrderedDict, fv.FinalValidateConfig):
return err
return None
def get_deepest_document_range_for_path(self, path):
# type: (ConfigPath) -> Optional[ESPHomeDataBase]
def get_deepest_document_range_for_path(self, path, get_key=False):
# type: (ConfigPath, bool) -> Optional[ESPHomeDataBase]
data = self
doc_range = None
for item_index in path:
for index, path_item in enumerate(path):
try:
if item_index in data:
doc_range = [x for x in data.keys() if x == item_index][0].esp_range
data = data[item_index]
if path_item in data:
key_data = [x for x in data.keys() if x == path_item][0]
if isinstance(key_data, ESPHomeDataBase):
doc_range = key_data.esp_range
if get_key and index == len(path) - 1:
return doc_range
data = data[path_item]
except (KeyError, IndexError, TypeError, AttributeError):
return doc_range
if isinstance(data, core.ID):
@@ -281,7 +285,7 @@ class ConfigValidationStep(abc.ABC):
class LoadValidationStep(ConfigValidationStep):
"""Load step, this step is called once for each domain config fragment.
Responsibilties:
Responsibilities:
- Load component code
- Ensure all AUTO_LOADs are added
- Set output paths of result
@@ -738,6 +742,10 @@ def validate_config(config, command_line_substitutions) -> Config:
result.add_validation_step(LoadValidationStep(key, config[key]))
result.run_validation_steps()
if result.errors:
# do not try to validate further as we don't know what the target is
return result
for domain, conf in config.items():
result.add_validation_step(LoadValidationStep(domain, conf))
result.add_validation_step(IDPassValidationStep())

View File

@@ -1,6 +1,6 @@
"""Constants used by esphome."""
__version__ = "2022.9.0b1"
__version__ = "2022.9.3"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
@@ -23,6 +23,7 @@ CONF_ACCURACY = "accuracy"
CONF_ACCURACY_DECIMALS = "accuracy_decimals"
CONF_ACTION_ID = "action_id"
CONF_ACTION_STATE_TOPIC = "action_state_topic"
CONF_ACTIVE = "active"
CONF_ACTIVE_POWER = "active_power"
CONF_ADDRESS = "address"
CONF_ADDRESSABLE_LIGHT_ID = "addressable_light_id"

View File

@@ -176,7 +176,7 @@ template<typename... Ts> class Action {
return this->next_->is_running();
}
Action<Ts...> *next_ = nullptr;
Action<Ts...> *next_{nullptr};
/// The number of instances of this sequence in the list of actions
/// that is currently being executed.

View File

@@ -254,7 +254,7 @@ class Component {
uint32_t component_state_{0x0000}; ///< State of this component.
float setup_priority_override_{NAN};
const char *component_source_ = nullptr;
const char *component_source_{nullptr};
};
/** This class simplifies creating components that periodically check a state.

View File

@@ -179,7 +179,11 @@ def preload_core_config(config, result):
]
if not has_oldstyle and not newstyle_found:
raise cv.Invalid("Platform missing for core options!", [CONF_ESPHOME])
raise cv.Invalid(
"Platform missing. You must include one of the available platform keys: "
+ ", ".join(TARGET_PLATFORMS),
[CONF_ESPHOME],
)
if has_oldstyle and newstyle_found:
raise cv.Invalid(
f"Please remove the `platform` key from the [esphome] block. You're already using the new style with the [{conf[CONF_PLATFORM]}] block",

View File

@@ -73,7 +73,7 @@ class ISRInternalGPIOPin {
void pin_mode(gpio::Flags flags);
protected:
void *arg_ = nullptr;
void *arg_{nullptr};
};
class InternalGPIOPin : public GPIOPin {

View File

@@ -12,7 +12,9 @@ from typing import Optional
def _get_invalid_range(res, invalid):
# type: (Config, cv.Invalid) -> Optional[DocumentRange]
return res.get_deepest_document_range_for_path(invalid.path)
return res.get_deepest_document_range_for_path(
invalid.path, invalid.error_message == "extra keys not allowed"
)
def _dump_range(range):

View File

@@ -9,7 +9,7 @@ pyserial==3.5
platformio==6.0.2 # When updating platformio, also update Dockerfile
esptool==3.3.1
click==8.1.3
esphome-dashboard==20220508.0
esphome-dashboard==20220925.0
aioesphomeapi==10.13.0
zeroconf==0.39.1