mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +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(); | ||||
|     if (App.is_name_add_mac_suffix_enabled()) { | ||||
|       // 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 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); | ||||
|       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); | ||||
|     } | ||||
|   } else { | ||||
|     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 { | ||||
|   if (this->use_address_.empty()) { | ||||
|     // ".local" suffix length for mDNS hostnames | ||||
|     constexpr size_t MDNS_LOCAL_SUFFIX_LEN = 5; | ||||
|     return make_name_with_suffix(App.get_name(), '.', "local", MDNS_LOCAL_SUFFIX_LEN); | ||||
|     constexpr size_t mdns_local_suffix_len = 5; | ||||
|     return make_name_with_suffix(App.get_name(), '.', "local", mdns_local_suffix_len); | ||||
|   } | ||||
|   return this->use_address_; | ||||
| } | ||||
|   | ||||
| @@ -268,8 +268,8 @@ network::IPAddress WiFiComponent::get_dns_address(int num) { | ||||
| std::string WiFiComponent::get_use_address() const { | ||||
|   if (this->use_address_.empty()) { | ||||
|     // ".local" suffix length for mDNS hostnames | ||||
|     constexpr size_t MDNS_LOCAL_SUFFIX_LEN = 5; | ||||
|     return make_name_with_suffix(App.get_name(), '.', "local", MDNS_LOCAL_SUFFIX_LEN); | ||||
|     constexpr size_t mdns_local_suffix_len = 5; | ||||
|     return make_name_with_suffix(App.get_name(), '.', "local", mdns_local_suffix_len); | ||||
|   } | ||||
|   return this->use_address_; | ||||
| } | ||||
|   | ||||
| @@ -103,13 +103,13 @@ class Application { | ||||
|     this->name_add_mac_suffix_ = name_add_mac_suffix; | ||||
|     if (name_add_mac_suffix) { | ||||
|       // 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(); | ||||
|       // Use pointer + offset to avoid substr() allocation | ||||
|       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); | ||||
|       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); | ||||
|       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 { | ||||
|       this->name_ = name; | ||||
|   | ||||
| @@ -15,6 +15,8 @@ from esphome.const import ( | ||||
| from esphome.core import CORE, EsphomeError | ||||
| from esphome.helpers import ( | ||||
|     copy_file_if_changed, | ||||
|     get_str_env, | ||||
|     is_ha_addon, | ||||
|     read_file, | ||||
|     walk_files, | ||||
|     write_file_if_changed, | ||||
| @@ -338,16 +340,21 @@ def clean_build(): | ||||
| def clean_all(configuration: list[str]): | ||||
|     import shutil | ||||
|  | ||||
|     # Clean entire build dir | ||||
|     for dir in configuration: | ||||
|         build_dir = Path(dir) / ".esphome" | ||||
|         if build_dir.is_dir(): | ||||
|             _LOGGER.info("Cleaning %s", build_dir) | ||||
|             # Don't remove storage as it will cause the dashboard to regenerate all configs | ||||
|             for item in build_dir.iterdir(): | ||||
|                 if item.is_file(): | ||||
|     data_dirs = [Path(dir) / ".esphome" for dir in configuration] | ||||
|     if is_ha_addon(): | ||||
|         data_dirs.append(Path("/data")) | ||||
|     if "ESPHOME_DATA_DIR" in os.environ: | ||||
|         data_dirs.append(Path(get_str_env("ESPHOME_DATA_DIR", None))) | ||||
|  | ||||
|     # Clean build dir | ||||
|     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() | ||||
|                 elif item.name != "storage" and item.is_dir(): | ||||
|                 elif item.is_dir() and item.name != "storage": | ||||
|                     shutil.rmtree(item) | ||||
|  | ||||
|     # Clean PlatformIO project files | ||||
|   | ||||
| @@ -11,7 +11,7 @@ pyserial==3.5 | ||||
| platformio==6.1.18  # When updating platformio, also update /docker/Dockerfile | ||||
| esptool==5.1.0 | ||||
| click==8.1.7 | ||||
| esphome-dashboard==20251009.0 | ||||
| esphome-dashboard==20251013.0 | ||||
| aioesphomeapi==41.14.0 | ||||
| zeroconf==0.148.0 | ||||
| puremagic==1.30 | ||||
|   | ||||
| @@ -986,3 +986,49 @@ def test_clean_all_removes_non_storage_directories( | ||||
|     # Verify logging mentions cleaning | ||||
|     assert "Cleaning" 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