From c89018a4319ada1a5fe96e6f368e194721cb956c Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Thu, 30 Sep 2021 18:08:15 +0200 Subject: [PATCH] Option to ignore CRC for EFuse MAC address (#2399) * Accept changes as proposed by black. * Added test and implemented optional correctly. * Disable PHY RF full calibration (because it calls the breaking MAC retrieval function). * Disable CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE instead of enable, dummy! * Rename CONF_IGNORE_EFUSE_MAC_CRC to CONF_ESP32_IGNORE_EFUSE_MAC_CRC. * Removed unused import. * Fix ordering of constants. * Moved all MAC address logic to core helpers. * Use pretty MAC address for the log. * Use standard MAC formatter function for debug component. * Fix clang-formatting. * Fix clang-formatting. * Brought wording of comments in line with other function-describing comments. * Processed code review by @OttoWinter * Add USE_ESP32_IGNORE_EFUSE_MAC_CRC to defines.h Co-authored-by: Maurice Makaay --- esphome/components/debug/debug_component.cpp | 5 +-- esphome/components/esp32/__init__.py | 13 +++++++ .../wifi/wifi_component_esp_idf.cpp | 6 ++++ esphome/const.py | 2 ++ esphome/core/defines.h | 1 + esphome/core/helpers.cpp | 34 ++++++++++++++----- esphome/core/helpers.h | 12 ++++++- tests/test5.yaml | 2 ++ 8 files changed, 61 insertions(+), 14 deletions(-) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index 7fd8956148..b856733121 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -104,10 +104,7 @@ void DebugComponent::dump_config() { ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version()); - uint64_t chip_mac = 0LL; - esp_efuse_mac_get_default((uint8_t *) (&chip_mac)); - std::string mac = uint64_to_string(chip_mac); - ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str()); + ESP_LOGD(TAG, "EFuse MAC: %s", get_mac_address_pretty().c_str()); const char *reset_reason; switch (rtc_get_reset_reason(0)) { diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 719b7b5f31..1316c7ccbe 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -10,6 +10,8 @@ from esphome.const import ( CONF_TYPE, CONF_VARIANT, CONF_VERSION, + CONF_ADVANCED, + CONF_IGNORE_EFUSE_MAC_CRC, KEY_CORE, KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, @@ -230,6 +232,11 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All( cv.string_strict: cv.string_strict }, cv.Optional(CONF_PLATFORM_VERSION): cv.string_strict, + cv.Optional(CONF_ADVANCED, default={}): cv.Schema( + { + cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC, default=False): cv.boolean, + } + ), } ), _esp_idf_check_versions, @@ -295,6 +302,12 @@ async def to_code(config): for name, value in conf[CONF_SDKCONFIG_OPTIONS].items(): add_idf_sdkconfig_option(name, RawSdkconfigValue(value)) + if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_MAC_CRC]: + cg.add_define("USE_ESP32_IGNORE_EFUSE_MAC_CRC") + add_idf_sdkconfig_option( + "CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE", False + ) + elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO: cg.add_platformio_option( "platform", f"espressif32 @ {conf[CONF_PLATFORM_VERSION]}" diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 9ec3f80014..7f71b7078c 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -110,6 +110,12 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi } void WiFiComponent::wifi_pre_setup_() { +#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC + uint8_t mac[6]; + get_mac_address_raw(mac); + set_mac_address(mac); + ESP_LOGV(TAG, "Use EFuse MAC without checking CRC: %s", get_mac_address_pretty().c_str()); +#endif esp_err_t err = esp_netif_init(); if (err != ERR_OK) { ESP_LOGE(TAG, "esp_netif_init failed: %s", esp_err_to_name(err)); diff --git a/esphome/const.py b/esphome/const.py index 054f032da4..265576bfbe 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -42,6 +42,7 @@ CONF_ACTION_ID = "action_id" CONF_ACTIVE_POWER = "active_power" CONF_ADDRESS = "address" CONF_ADDRESSABLE_LIGHT_ID = "addressable_light_id" +CONF_ADVANCED = "advanced" CONF_ALPHA = "alpha" CONF_ALTITUDE = "altitude" CONF_AND = "and" @@ -281,6 +282,7 @@ CONF_IDLE_ACTION = "idle_action" CONF_IDLE_LEVEL = "idle_level" CONF_IDLE_TIME = "idle_time" CONF_IF = "if" +CONF_IGNORE_EFUSE_MAC_CRC = "ignore_efuse_mac_crc" CONF_IIR_FILTER = "iir_filter" CONF_ILLUMINANCE = "illuminance" CONF_IMPEDANCE = "impedance" diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 1c3b17d071..7c2261920a 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -50,6 +50,7 @@ #ifdef USE_ESP32 #define USE_ESP32_BLE_SERVER #define USE_ESP32_CAMERA +#define USE_ESP32_IGNORE_EFUSE_MAC_CRC #define USE_IMPROV #define USE_SOCKET_IMPL_BSD_SOCKETS diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 731ee6c8f5..780df3ca6d 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -1,4 +1,5 @@ #include "esphome/core/helpers.h" +#include "esphome/core/defines.h" #include #include #include @@ -14,6 +15,10 @@ #include #include #endif +#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#endif #include "esphome/core/log.h" #include "esphome/core/hal.h" @@ -22,15 +27,27 @@ namespace esphome { static const char *const TAG = "helpers"; -std::string get_mac_address() { - char tmp[20]; - uint8_t mac[6]; +void get_mac_address_raw(uint8_t *mac) { #ifdef USE_ESP32 +#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC + // On some devices, the MAC address that is burnt into EFuse does not + // match the CRC that goes along with it. For those devices, this + // work-around reads and uses the MAC address as-is from EFuse, + // without doing the CRC check. + esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, 48); +#else esp_efuse_mac_get_default(mac); #endif +#endif #ifdef USE_ESP8266 WiFi.macAddress(mac); #endif +} + +std::string get_mac_address() { + char tmp[20]; + uint8_t mac[6]; + get_mac_address_raw(mac); sprintf(tmp, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return std::string(tmp); } @@ -38,16 +55,15 @@ std::string get_mac_address() { std::string get_mac_address_pretty() { char tmp[20]; uint8_t mac[6]; -#ifdef USE_ESP32 - esp_efuse_mac_get_default(mac); -#endif -#ifdef USE_ESP8266 - WiFi.macAddress(mac); -#endif + get_mac_address_raw(mac); sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return std::string(tmp); } +#ifdef USE_ESP32 +void set_mac_address(uint8_t *mac) { esp_base_mac_addr_set(mac); } +#endif + std::string generate_hostname(const std::string &base) { return base + std::string("-") + get_mac_address(); } uint32_t random_uint32() { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 24b55eade0..61cc9a9e4a 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -26,11 +26,21 @@ namespace esphome { /// The characters that are allowed in a hostname. extern const char *const HOSTNAME_CHARACTER_ALLOWLIST; -/// Gets the MAC address as a string, this can be used as way to identify this ESP. +/// Read the raw MAC address into the provided byte array (6 bytes). +void get_mac_address_raw(uint8_t *mac); + +/// Get the MAC address as a string, using lower case hex notation. +/// This can be used as way to identify this ESP. std::string get_mac_address(); +/// Get the MAC address as a string, using colon-separated upper case hex notation. std::string get_mac_address_pretty(); +#ifdef USE_ESP32 +/// Set the MAC address to use from the provided byte array (6 bytes). +void set_mac_address(uint8_t *mac); +#endif + std::string to_string(const std::string &val); std::string to_string(int val); std::string to_string(long val); // NOLINT diff --git a/tests/test5.yaml b/tests/test5.yaml index b22b19550e..aca8434fbf 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -9,6 +9,8 @@ esp32: board: nodemcu-32s framework: type: esp-idf + advanced: + ignore_efuse_mac_crc: true wifi: networks: