diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index a7e2522fac..cb494ed1bc 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -527,7 +527,7 @@ async def to_code_characteristic(service_var, char_conf): action_conf, char_conf[CONF_CHAR_VALUE_ACTION_ID_], cg.TemplateArguments(), - {}, + [], ) cg.add(value_action.play()) else: diff --git a/esphome/components/esp32_ble_server/ble_characteristic.cpp b/esphome/components/esp32_ble_server/ble_characteristic.cpp index 0482848ea0..a1b1ff94bb 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.cpp +++ b/esphome/components/esp32_ble_server/ble_characteristic.cpp @@ -246,9 +246,27 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt if (this->handle_ != param->write.handle) break; + esp_gatt_status_t status = ESP_GATT_OK; + if (param->write.is_prep) { - this->value_.insert(this->value_.end(), param->write.value, param->write.value + param->write.len); - this->write_event_ = true; + const size_t offset = param->write.offset; + const size_t write_len = param->write.len; + const size_t new_size = offset + write_len; + // Clean the buffer on the first prepared write event + if (offset == 0) { + this->value_.clear(); + } + + if (offset != this->value_.size()) { + status = ESP_GATT_INVALID_OFFSET; + } else if (new_size > ESP_GATT_MAX_ATTR_LEN) { + status = ESP_GATT_INVALID_ATTR_LEN; + } else { + if (this->value_.size() < new_size) { + this->value_.resize(new_size); + } + memcpy(this->value_.data() + offset, param->write.value, write_len); + } } else { this->set_value(ByteBuffer::wrap(param->write.value, param->write.len)); } @@ -263,7 +281,7 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt memcpy(response.attr_value.value, param->write.value, param->write.len); esp_err_t err = - esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, &response); + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, &response); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ble_gatts_send_response failed: %d", err); @@ -280,9 +298,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt } case ESP_GATTS_EXEC_WRITE_EVT: { - if (!this->write_event_) + // BLE stack will guarantee that ESP_GATTS_EXEC_WRITE_EVT is only received after prepared writes + if (this->value_.empty()) break; - this->write_event_ = false; if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { if (this->on_write_callback_) { (*this->on_write_callback_)(this->value_, param->exec_write.conn_id); diff --git a/esphome/components/esp32_ble_server/ble_characteristic.h b/esphome/components/esp32_ble_server/ble_characteristic.h index b913915789..c2cdb1660c 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.h +++ b/esphome/components/esp32_ble_server/ble_characteristic.h @@ -77,7 +77,6 @@ class BLECharacteristic { } protected: - bool write_event_{false}; BLEService *service_{}; ESPBTUUID uuid_; esp_gatt_char_prop_t properties_;