mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 23:21:54 +00:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/dev' into integration
This commit is contained in:
		| @@ -214,10 +214,10 @@ bool ESP32BLE::ble_setup_() { | |||||||
|     name = this->name_.value(); |     name = this->name_.value(); | ||||||
|     if (App.is_name_add_mac_suffix_enabled()) { |     if (App.is_name_add_mac_suffix_enabled()) { | ||||||
|       // MAC address suffix length (last 6 characters of 12-char MAC address string) |       // MAC address suffix length (last 6 characters of 12-char MAC address string) | ||||||
|       constexpr size_t MAC_ADDRESS_SUFFIX_LEN = 6; |       constexpr size_t mac_address_suffix_len = 6; | ||||||
|       const std::string mac_addr = get_mac_address(); |       const std::string mac_addr = get_mac_address(); | ||||||
|       const char *mac_suffix_ptr = mac_addr.c_str() + MAC_ADDRESS_SUFFIX_LEN; |       const char *mac_suffix_ptr = mac_addr.c_str() + mac_address_suffix_len; | ||||||
|       name = make_name_with_suffix(name, '-', mac_suffix_ptr, MAC_ADDRESS_SUFFIX_LEN); |       name = make_name_with_suffix(name, '-', mac_suffix_ptr, mac_address_suffix_len); | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|     name = App.get_name(); |     name = App.get_name(); | ||||||
|   | |||||||
| @@ -692,8 +692,8 @@ void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ | |||||||
| std::string EthernetComponent::get_use_address() const { | std::string EthernetComponent::get_use_address() const { | ||||||
|   if (this->use_address_.empty()) { |   if (this->use_address_.empty()) { | ||||||
|     // ".local" suffix length for mDNS hostnames |     // ".local" suffix length for mDNS hostnames | ||||||
|     constexpr size_t MDNS_LOCAL_SUFFIX_LEN = 5; |     constexpr size_t mdns_local_suffix_len = 5; | ||||||
|     return make_name_with_suffix(App.get_name(), '.', "local", MDNS_LOCAL_SUFFIX_LEN); |     return make_name_with_suffix(App.get_name(), '.', "local", mdns_local_suffix_len); | ||||||
|   } |   } | ||||||
|   return this->use_address_; |   return this->use_address_; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -268,8 +268,8 @@ network::IPAddress WiFiComponent::get_dns_address(int num) { | |||||||
| std::string WiFiComponent::get_use_address() const { | std::string WiFiComponent::get_use_address() const { | ||||||
|   if (this->use_address_.empty()) { |   if (this->use_address_.empty()) { | ||||||
|     // ".local" suffix length for mDNS hostnames |     // ".local" suffix length for mDNS hostnames | ||||||
|     constexpr size_t MDNS_LOCAL_SUFFIX_LEN = 5; |     constexpr size_t mdns_local_suffix_len = 5; | ||||||
|     return make_name_with_suffix(App.get_name(), '.', "local", MDNS_LOCAL_SUFFIX_LEN); |     return make_name_with_suffix(App.get_name(), '.', "local", mdns_local_suffix_len); | ||||||
|   } |   } | ||||||
|   return this->use_address_; |   return this->use_address_; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -103,13 +103,13 @@ class Application { | |||||||
|     this->name_add_mac_suffix_ = name_add_mac_suffix; |     this->name_add_mac_suffix_ = name_add_mac_suffix; | ||||||
|     if (name_add_mac_suffix) { |     if (name_add_mac_suffix) { | ||||||
|       // MAC address suffix length (last 6 characters of 12-char MAC address string) |       // MAC address suffix length (last 6 characters of 12-char MAC address string) | ||||||
|       constexpr size_t MAC_ADDRESS_SUFFIX_LEN = 6; |       constexpr size_t mac_address_suffix_len = 6; | ||||||
|       const std::string mac_addr = get_mac_address(); |       const std::string mac_addr = get_mac_address(); | ||||||
|       // Use pointer + offset to avoid substr() allocation |       // Use pointer + offset to avoid substr() allocation | ||||||
|       const char *mac_suffix_ptr = mac_addr.c_str() + MAC_ADDRESS_SUFFIX_LEN; |       const char *mac_suffix_ptr = mac_addr.c_str() + mac_address_suffix_len; | ||||||
|       this->name_ = make_name_with_suffix(name, '-', mac_suffix_ptr, MAC_ADDRESS_SUFFIX_LEN); |       this->name_ = make_name_with_suffix(name, '-', mac_suffix_ptr, mac_address_suffix_len); | ||||||
|       if (!friendly_name.empty()) { |       if (!friendly_name.empty()) { | ||||||
|         this->friendly_name_ = make_name_with_suffix(friendly_name, ' ', mac_suffix_ptr, MAC_ADDRESS_SUFFIX_LEN); |         this->friendly_name_ = make_name_with_suffix(friendly_name, ' ', mac_suffix_ptr, mac_address_suffix_len); | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       this->name_ = name; |       this->name_ = name; | ||||||
|   | |||||||
| @@ -15,6 +15,8 @@ from esphome.const import ( | |||||||
| from esphome.core import CORE, EsphomeError | from esphome.core import CORE, EsphomeError | ||||||
| from esphome.helpers import ( | from esphome.helpers import ( | ||||||
|     copy_file_if_changed, |     copy_file_if_changed, | ||||||
|  |     get_str_env, | ||||||
|  |     is_ha_addon, | ||||||
|     read_file, |     read_file, | ||||||
|     walk_files, |     walk_files, | ||||||
|     write_file_if_changed, |     write_file_if_changed, | ||||||
| @@ -338,16 +340,21 @@ def clean_build(): | |||||||
| def clean_all(configuration: list[str]): | def clean_all(configuration: list[str]): | ||||||
|     import shutil |     import shutil | ||||||
|  |  | ||||||
|     # Clean entire build dir |     data_dirs = [Path(dir) / ".esphome" for dir in configuration] | ||||||
|     for dir in configuration: |     if is_ha_addon(): | ||||||
|         build_dir = Path(dir) / ".esphome" |         data_dirs.append(Path("/data")) | ||||||
|         if build_dir.is_dir(): |     if "ESPHOME_DATA_DIR" in os.environ: | ||||||
|             _LOGGER.info("Cleaning %s", build_dir) |         data_dirs.append(Path(get_str_env("ESPHOME_DATA_DIR", None))) | ||||||
|             # Don't remove storage as it will cause the dashboard to regenerate all configs |  | ||||||
|             for item in build_dir.iterdir(): |     # Clean build dir | ||||||
|                 if item.is_file(): |     for dir in data_dirs: | ||||||
|  |         if dir.is_dir(): | ||||||
|  |             _LOGGER.info("Cleaning %s", dir) | ||||||
|  |             # Don't remove storage or .json files which are needed by the dashboard | ||||||
|  |             for item in dir.iterdir(): | ||||||
|  |                 if item.is_file() and not item.name.endswith(".json"): | ||||||
|                     item.unlink() |                     item.unlink() | ||||||
|                 elif item.name != "storage" and item.is_dir(): |                 elif item.is_dir() and item.name != "storage": | ||||||
|                     shutil.rmtree(item) |                     shutil.rmtree(item) | ||||||
|  |  | ||||||
|     # Clean PlatformIO project files |     # Clean PlatformIO project files | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ pyserial==3.5 | |||||||
| platformio==6.1.18  # When updating platformio, also update /docker/Dockerfile | platformio==6.1.18  # When updating platformio, also update /docker/Dockerfile | ||||||
| esptool==5.1.0 | esptool==5.1.0 | ||||||
| click==8.1.7 | click==8.1.7 | ||||||
| esphome-dashboard==20251009.0 | esphome-dashboard==20251013.0 | ||||||
| aioesphomeapi==41.14.0 | aioesphomeapi==41.14.0 | ||||||
| zeroconf==0.148.0 | zeroconf==0.148.0 | ||||||
| puremagic==1.30 | puremagic==1.30 | ||||||
|   | |||||||
| @@ -986,3 +986,49 @@ def test_clean_all_removes_non_storage_directories( | |||||||
|     # Verify logging mentions cleaning |     # Verify logging mentions cleaning | ||||||
|     assert "Cleaning" in caplog.text |     assert "Cleaning" in caplog.text | ||||||
|     assert str(build_dir) in caplog.text |     assert str(build_dir) in caplog.text | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @patch("esphome.writer.CORE") | ||||||
|  | def test_clean_all_preserves_json_files( | ||||||
|  |     mock_core: MagicMock, | ||||||
|  |     tmp_path: Path, | ||||||
|  |     caplog: pytest.LogCaptureFixture, | ||||||
|  | ) -> None: | ||||||
|  |     """Test clean_all preserves .json files.""" | ||||||
|  |     # Create build directory with various files | ||||||
|  |     config_dir = tmp_path / "config" | ||||||
|  |     config_dir.mkdir() | ||||||
|  |  | ||||||
|  |     build_dir = config_dir / ".esphome" | ||||||
|  |     build_dir.mkdir() | ||||||
|  |  | ||||||
|  |     # Create .json files (should be preserved) | ||||||
|  |     (build_dir / "config.json").write_text('{"config": "data"}') | ||||||
|  |     (build_dir / "metadata.json").write_text('{"metadata": "info"}') | ||||||
|  |  | ||||||
|  |     # Create non-.json files (should be removed) | ||||||
|  |     (build_dir / "dummy.txt").write_text("x") | ||||||
|  |     (build_dir / "other.log").write_text("log content") | ||||||
|  |  | ||||||
|  |     # Call clean_all | ||||||
|  |     from esphome.writer import clean_all | ||||||
|  |  | ||||||
|  |     with caplog.at_level("INFO"): | ||||||
|  |         clean_all([str(config_dir)]) | ||||||
|  |  | ||||||
|  |     # Verify .esphome directory still exists | ||||||
|  |     assert build_dir.exists() | ||||||
|  |  | ||||||
|  |     # Verify .json files are preserved | ||||||
|  |     assert (build_dir / "config.json").exists() | ||||||
|  |     assert (build_dir / "config.json").read_text() == '{"config": "data"}' | ||||||
|  |     assert (build_dir / "metadata.json").exists() | ||||||
|  |     assert (build_dir / "metadata.json").read_text() == '{"metadata": "info"}' | ||||||
|  |  | ||||||
|  |     # Verify non-.json files were removed | ||||||
|  |     assert not (build_dir / "dummy.txt").exists() | ||||||
|  |     assert not (build_dir / "other.log").exists() | ||||||
|  |  | ||||||
|  |     # Verify logging mentions cleaning | ||||||
|  |     assert "Cleaning" in caplog.text | ||||||
|  |     assert str(build_dir) in caplog.text | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user