diff --git a/esphome/components/fota/fota_component.cpp b/esphome/components/fota/fota_component.cpp deleted file mode 100644 index bb2ddfe4f6..0000000000 --- a/esphome/components/fota/fota_component.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "fota_component.h" -#include -#include - -extern "C" void start_smp_bluetooth_adverts(); - -namespace esphome { -namespace fota { - -void FOTAComponent::setup() { - if (IS_ENABLED(CONFIG_USB_DEVICE_STACK)) { - usb_enable(NULL); - } - start_smp_bluetooth_adverts(); -} - -} // namespace fota -} // namespace esphome diff --git a/esphome/components/fota/fota_component.h b/esphome/components/fota/fota_component.h deleted file mode 100644 index d447e66922..0000000000 --- a/esphome/components/fota/fota_component.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "esphome/core/component.h" - -namespace esphome { -namespace fota { - -class FOTAComponent : public Component { - public: - void setup() override; -}; - -} // namespace fota -} // namespace esphome diff --git a/esphome/components/nrf52/zephyr.py b/esphome/components/nrf52/zephyr.py index c6fbc1dfaf..ff1d36ae4f 100644 --- a/esphome/components/nrf52/zephyr.py +++ b/esphome/components/nrf52/zephyr.py @@ -67,8 +67,8 @@ def zephyr_to_code(conf): else: raise NotImplementedError # c++ support - zephyr_add_prj_conf("NEWLIB_LIBC", False) - zephyr_add_prj_conf("NEWLIB_LIBC_NANO", True) + zephyr_add_prj_conf("NEWLIB_LIBC", True) + zephyr_add_prj_conf("CONFIG_FPU", True) zephyr_add_prj_conf("NEWLIB_LIBC_FLOAT_PRINTF", True) zephyr_add_prj_conf("CPLUSPLUS", True) zephyr_add_prj_conf("LIB_CPLUSPLUS", True) diff --git a/esphome/components/zephyr_ble_server/__init__.py b/esphome/components/zephyr_ble_server/__init__.py index a41dc6a18f..67e00398fb 100644 --- a/esphome/components/zephyr_ble_server/__init__.py +++ b/esphome/components/zephyr_ble_server/__init__.py @@ -3,7 +3,6 @@ import esphome.config_validation as cv from esphome.const import ( CONF_ID, ) - from esphome.components.nrf52.zephyr import zephyr_add_prj_conf zephyr_ble_server_ns = cg.esphome_ns.namespace("zephyr_ble_server") @@ -23,5 +22,4 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) zephyr_add_prj_conf("BT", True) zephyr_add_prj_conf("BT_PERIPHERAL", True) - zephyr_add_prj_conf("BT_DEVICE_NAME_DYNAMIC", True) await cg.register_component(var, config) diff --git a/esphome/components/zephyr_ble_server/ble_server.cpp b/esphome/components/zephyr_ble_server/ble_server.cpp index f3e981c91b..b099759737 100644 --- a/esphome/components/zephyr_ble_server/ble_server.cpp +++ b/esphome/components/zephyr_ble_server/ble_server.cpp @@ -1,7 +1,6 @@ #include "ble_server.h" #include "esphome/core/defines.h" #include "esphome/core/log.h" -#include "esphome/core/application.h" #include #include @@ -67,12 +66,6 @@ void BLEServer::setup() { ESP_LOGE(TAG, "Bluetooth enable failed: %d", rc); return; } - rc = bt_set_name(App.get_name().c_str()); - if (rc != 0) { - ESP_LOGE(TAG, "Bluetooth set name failed: %d", rc); - return; - } - } } // namespace zephyr_ble_server diff --git a/esphome/components/zephyr_mcumgr/__init__.py b/esphome/components/zephyr_mcumgr/__init__.py index 4ae230fb52..12447078cd 100644 --- a/esphome/components/zephyr_mcumgr/__init__.py +++ b/esphome/components/zephyr_mcumgr/__init__.py @@ -14,3 +14,7 @@ async def to_code(config): zephyr_add_prj_conf("FLASH", True) zephyr_add_prj_conf("BOOTLOADER_MCUBOOT", True) + + zephyr_add_prj_conf("MCUMGR_MGMT_NOTIFICATION_HOOKS", True) + zephyr_add_prj_conf("MCUMGR_GRP_IMG_STATUS_HOOKS", True) + zephyr_add_prj_conf("MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK", True) diff --git a/esphome/components/zephyr_ota_mcumgr/ota_component.cpp b/esphome/components/zephyr_ota_mcumgr/ota_component.cpp new file mode 100644 index 0000000000..126819c025 --- /dev/null +++ b/esphome/components/zephyr_ota_mcumgr/ota_component.cpp @@ -0,0 +1,83 @@ +#include "ota_component.h" +#include "esphome/core/defines.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" +#include +#include + +struct img_mgmt_upload_action { + /** The total size of the image. */ + unsigned long long size; +}; + +struct img_mgmt_upload_req { + uint32_t image; /* 0 by default */ + size_t off; /* SIZE_MAX if unspecified */ +}; + +namespace esphome { +namespace zephyr_ota_mcumgr { + +static const char *const TAG = "zephyr_ota_mcumgr"; + +static enum mgmt_cb_return mcumgr_img_mgmt_cb(uint32_t event, enum mgmt_cb_return prev_status, int32_t *rc, + uint16_t *group, bool *abort_more, void *data, size_t data_size) { + if (MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK == event) { + const img_mgmt_upload_check &upload = *static_cast(data); + static_cast(ota::global_ota_component)->update_chunk(upload); + } else if (MGMT_EVT_OP_IMG_MGMT_DFU_STARTED == event) { + static_cast(ota::global_ota_component)->update_started(); + } else if (MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK_WRITE_COMPLETE == event) { + static_cast(ota::global_ota_component)->update_chunk_wrote(); + } else if (MGMT_EVT_OP_IMG_MGMT_DFU_PENDING == event) { + static_cast(ota::global_ota_component)->update_pending(); + } else { + ESP_LOGD(TAG, "MCUmgr Image Management Event with the %d ID", u32_count_trailing_zeros(MGMT_EVT_GET_ID(event))); + } + return MGMT_CB_OK; +} + +static struct mgmt_callback img_mgmt_callback = { + .callback = mcumgr_img_mgmt_cb, + .event_id = MGMT_EVT_OP_IMG_MGMT_ALL, +}; + +OTAComponent::OTAComponent() { ota::global_ota_component = this; } + +void OTAComponent::setup() { mgmt_callback_register(&img_mgmt_callback); } + +void OTAComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Over-The-Air Updates:"); +} + +void OTAComponent::update_chunk(const img_mgmt_upload_check &upload) { + _percentage = (upload.req->off * 100.0f) / upload.action->size; +} + +void OTAComponent::update_started() { + ESP_LOGD(TAG, "Starting OTA Update from %s...", "ble"); +#ifdef USE_OTA_STATE_CALLBACK + this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0); +#endif +} + +void OTAComponent::update_chunk_wrote() { + uint32_t now = millis(); + if (now - _last_progress > 1000) { + _last_progress = now; + ESP_LOGD(TAG, "OTA in progress: %0.1f%%", _percentage); +#ifdef USE_OTA_STATE_CALLBACK + this->state_callback_.call(ota::OTA_IN_PROGRESS, _percentage, 0); +#endif + } +} + +void OTAComponent::update_pending() { + ESP_LOGD(TAG, "OTA pending"); +#ifdef USE_OTA_STATE_CALLBACK + this->state_callback_.call(ota::OTA_COMPLETED, 100.0f, 0); +#endif +} + +} // namespace zephyr_ota_mcumgr +} // namespace esphome diff --git a/esphome/components/zephyr_ota_mcumgr/ota_component.h b/esphome/components/zephyr_ota_mcumgr/ota_component.h index b16fe48ff4..278ad5d2cf 100644 --- a/esphome/components/zephyr_ota_mcumgr/ota_component.h +++ b/esphome/components/zephyr_ota_mcumgr/ota_component.h @@ -2,10 +2,25 @@ #include "esphome/components/ota/ota_component.h" +struct img_mgmt_upload_check; + namespace esphome { namespace zephyr_ota_mcumgr { -class OTAComponent : public ota::OTAComponent {}; +class OTAComponent : public ota::OTAComponent { + public: + OTAComponent(); + void setup() override; + void dump_config() override; + void update_chunk(const img_mgmt_upload_check &upload); + void update_started(); + void update_chunk_wrote(); + void update_pending(); + + protected: + uint32_t _last_progress = 0; + float _percentage = 0; +}; } // namespace zephyr_ota_mcumgr } // namespace esphome diff --git a/esphome/core/config.py b/esphome/core/config.py index e4a1fdcafa..95dc148643 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -39,6 +39,7 @@ from esphome.const import ( ) from esphome.core import CORE, coroutine_with_priority from esphome.helpers import copy_file_if_changed, walk_files +from esphome.components.nrf52.zephyr import zephyr_add_prj_conf _LOGGER = logging.getLogger(__name__) @@ -359,6 +360,9 @@ async def to_code(config): ) ) + if CORE.using_zephyr: + zephyr_add_prj_conf("BT_DEVICE_NAME", config[CONF_NAME]) + CORE.add_job(_add_automations, config) cg.add_build_flag("-fno-exceptions") diff --git a/esphome/zephyr_tools.py b/esphome/zephyr_tools.py index 46ca3c0e80..82fa0ede00 100644 --- a/esphome/zephyr_tools.py +++ b/esphome/zephyr_tools.py @@ -82,6 +82,9 @@ async def smpmgr_upload(config, host, firmware): _LOGGER.warning("No images on device!") for image in image_state.images: pprint(image) + if image.active and not image.confirmed: + _LOGGER.error("No free slot") + return 1 if image.hash == image_tlv_sha256: if already_uploaded: _LOGGER.error("Both slots have the same image")