esphome 2025.9.3__py3-none-any.whl → 2025.10.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/__main__.py +87 -31
- esphome/address_cache.py +142 -0
- esphome/automation.py +130 -32
- esphome/build_gen/platformio.py +1 -3
- esphome/codegen.py +1 -0
- esphome/components/animation/animation.cpp +2 -2
- esphome/components/api/__init__.py +166 -3
- esphome/components/api/api_connection.cpp +84 -41
- esphome/components/api/api_connection.h +22 -16
- esphome/components/api/api_frame_helper.cpp +33 -19
- esphome/components/api/api_frame_helper.h +19 -4
- esphome/components/api/api_frame_helper_noise.cpp +41 -53
- esphome/components/api/api_frame_helper_noise.h +1 -1
- esphome/components/api/api_frame_helper_plaintext.cpp +22 -31
- esphome/components/api/api_frame_helper_plaintext.h +1 -1
- esphome/components/api/api_pb2.cpp +189 -15
- esphome/components/api/api_pb2.h +132 -20
- esphome/components/api/api_pb2_dump.cpp +97 -9
- esphome/components/api/api_pb2_service.cpp +118 -160
- esphome/components/api/api_pb2_service.h +31 -3
- esphome/components/api/api_server.cpp +68 -10
- esphome/components/api/api_server.h +32 -4
- esphome/components/api/custom_api_device.h +8 -8
- esphome/components/api/homeassistant_service.h +123 -6
- esphome/components/api/proto.h +6 -2
- esphome/components/api/user_services.h +2 -2
- esphome/components/as7341/sensor.py +1 -1
- esphome/components/audio/__init__.py +1 -1
- esphome/components/audio/audio.cpp +1 -1
- esphome/components/audio/audio_decoder.cpp +9 -9
- esphome/components/bl0906/bl0906.cpp +2 -2
- esphome/components/bl0942/bl0942.cpp +2 -2
- esphome/components/ble_client/__init__.py +1 -1
- esphome/components/bluetooth_proxy/__init__.py +4 -30
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +11 -4
- esphome/components/bluetooth_proxy/bluetooth_connection.h +2 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
- esphome/components/camera_encoder/__init__.py +2 -4
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +4 -2
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +3 -1
- esphome/components/canbus/canbus.cpp +7 -5
- esphome/components/canbus/canbus.h +4 -4
- esphome/components/captive_portal/__init__.py +18 -1
- esphome/components/captive_portal/captive_portal.cpp +40 -46
- esphome/components/captive_portal/captive_portal.h +20 -22
- esphome/components/captive_portal/dns_server_esp32_idf.cpp +205 -0
- esphome/components/captive_portal/dns_server_esp32_idf.h +27 -0
- esphome/components/ccs811/ccs811.cpp +1 -1
- esphome/components/climate/climate.cpp +10 -7
- esphome/components/cm1106/cm1106.cpp +1 -1
- esphome/components/copy/lock/copy_lock.cpp +1 -1
- esphome/components/cover/cover.cpp +1 -0
- esphome/components/daikin_arc/daikin_arc.cpp +19 -12
- esphome/components/deep_sleep/__init__.py +9 -2
- esphome/components/deep_sleep/deep_sleep_component.h +11 -9
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
- esphome/components/ektf2232/touchscreen/__init__.py +8 -5
- esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
- esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
- esphome/components/epaper_spi/__init__.py +1 -0
- esphome/components/epaper_spi/display.py +80 -0
- esphome/components/epaper_spi/epaper_spi.cpp +227 -0
- esphome/components/epaper_spi/epaper_spi.h +93 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
- esphome/components/es7210/es7210.cpp +3 -3
- esphome/components/esp32/__init__.py +254 -339
- esphome/components/esp32/boards.py +81 -0
- esphome/components/esp32/preferences.cpp +23 -17
- esphome/components/esp32_ble/__init__.py +159 -44
- esphome/components/esp32_ble/ble.cpp +47 -3
- esphome/components/esp32_ble/ble.h +18 -0
- esphome/components/esp32_ble/ble_advertising.cpp +7 -3
- esphome/components/esp32_ble/ble_advertising.h +4 -0
- esphome/components/esp32_ble/ble_uuid.cpp +16 -42
- esphome/components/esp32_ble_beacon/__init__.py +3 -4
- esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
- esphome/components/esp32_ble_server/__init__.py +28 -14
- esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
- esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
- esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
- esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
- esphome/components/esp32_ble_server/ble_server.cpp +59 -24
- esphome/components/esp32_ble_server/ble_server.h +38 -20
- esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
- esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
- esphome/components/esp32_ble_tracker/__init__.py +25 -80
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -4
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
- esphome/components/esp32_camera/__init__.py +1 -3
- esphome/components/esp32_can/esp32_can.cpp +22 -4
- esphome/components/esp32_can/esp32_can.h +3 -0
- esphome/components/esp32_hosted/__init__.py +2 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +102 -44
- esphome/components/esp32_improv/esp32_improv_component.h +6 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
- esphome/components/esp8266/__init__.py +3 -3
- esphome/components/esphome/ota/__init__.py +21 -2
- esphome/components/esphome/ota/ota_esphome.cpp +455 -145
- esphome/components/esphome/ota/ota_esphome.h +49 -2
- esphome/components/ethernet/__init__.py +39 -22
- esphome/components/ethernet/ethernet_component.cpp +28 -5
- esphome/components/ethernet/ethernet_component.h +5 -1
- esphome/components/external_components/__init__.py +8 -6
- esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
- esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
- esphome/components/font/__init__.py +5 -5
- esphome/components/graph/graph.cpp +1 -1
- esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
- esphome/components/haier/hon_climate.cpp +2 -2
- esphome/components/haier/hon_climate.h +1 -1
- esphome/components/hdc1080/hdc1080.cpp +42 -34
- esphome/components/hdc1080/hdc1080.h +1 -3
- esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
- esphome/components/http_request/__init__.py +3 -3
- esphome/components/htu21d/htu21d.cpp +13 -18
- esphome/components/htu21d/htu21d.h +1 -1
- esphome/components/i2s_audio/__init__.py +1 -2
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
- esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
- esphome/components/improv_serial/improv_serial_component.cpp +12 -15
- esphome/components/improv_serial/improv_serial_component.h +6 -8
- esphome/components/json/json_util.cpp +35 -43
- esphome/components/json/json_util.h +57 -0
- esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
- esphome/components/key_collector/key_collector.h +4 -4
- esphome/components/libretiny/__init__.py +6 -6
- esphome/components/libretiny/preferences.cpp +23 -16
- esphome/components/light/light_call.cpp +98 -120
- esphome/components/light/light_call.h +17 -7
- esphome/components/lm75b/__init__.py +0 -0
- esphome/components/lm75b/lm75b.cpp +39 -0
- esphome/components/lm75b/lm75b.h +19 -0
- esphome/components/lm75b/sensor.py +34 -0
- esphome/components/lock/lock.h +12 -6
- esphome/components/logger/__init__.py +15 -27
- esphome/components/logger/logger.cpp +10 -20
- esphome/components/logger/logger.h +105 -62
- esphome/components/logger/logger_esp32.cpp +0 -48
- esphome/components/logger/logger_zephyr.cpp +2 -3
- esphome/components/logger/select/logger_level_select.cpp +6 -7
- esphome/components/logger/select/logger_level_select.h +7 -0
- esphome/components/ltr501/ltr501.cpp +7 -6
- esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
- esphome/components/matrix_keypad/matrix_keypad.h +4 -4
- esphome/components/max7219digit/max7219digit.cpp +1 -1
- esphome/components/mcp2515/mcp2515.cpp +31 -3
- esphome/components/mcp2515/mcp2515_defs.h +3 -1
- esphome/components/md5/md5.cpp +0 -26
- esphome/components/md5/md5.h +10 -20
- esphome/components/mdns/__init__.py +19 -6
- esphome/components/mdns/mdns_component.cpp +27 -59
- esphome/components/mdns/mdns_component.h +23 -10
- esphome/components/mdns/mdns_esp32.cpp +7 -7
- esphome/components/mdns/mdns_esp8266.cpp +6 -6
- esphome/components/mdns/mdns_libretiny.cpp +3 -3
- esphome/components/mdns/mdns_rp2040.cpp +3 -3
- esphome/components/mipi/__init__.py +1 -5
- esphome/components/mipi_spi/display.py +24 -8
- esphome/components/mipi_spi/mipi_spi.h +3 -3
- esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
- esphome/components/mmc5603/mmc5603.cpp +3 -3
- esphome/components/modbus/modbus.cpp +27 -13
- esphome/components/modbus/modbus.h +5 -3
- esphome/components/modbus/modbus_definitions.h +86 -0
- esphome/components/modbus_controller/__init__.py +29 -1
- esphome/components/modbus_controller/const.py +4 -0
- esphome/components/modbus_controller/modbus_controller.cpp +38 -13
- esphome/components/modbus_controller/modbus_controller.h +18 -29
- esphome/components/mpr121/mpr121.cpp +41 -42
- esphome/components/mpr121/mpr121.h +0 -1
- esphome/components/nau7802/nau7802.cpp +2 -2
- esphome/components/network/__init__.py +7 -3
- esphome/components/nextion/display.py +4 -4
- esphome/components/nextion/nextion.cpp +8 -8
- esphome/components/number/__init__.py +2 -0
- esphome/components/number/number_call.cpp +23 -12
- esphome/components/number/number_call.h +5 -0
- esphome/components/online_image/bmp_image.cpp +2 -1
- esphome/components/online_image/jpeg_image.cpp +4 -2
- esphome/components/openthread/openthread.cpp +6 -7
- esphome/components/openthread/openthread.h +0 -1
- esphome/components/ota/ota_backend.h +1 -0
- esphome/components/packages/__init__.py +10 -8
- esphome/components/packet_transport/packet_transport.cpp +2 -0
- esphome/components/pid/pid_controller.cpp +1 -1
- esphome/components/prometheus/prometheus_handler.cpp +239 -239
- esphome/components/psram/__init__.py +30 -28
- esphome/components/qmc5883l/qmc5883l.cpp +15 -0
- esphome/components/qmc5883l/qmc5883l.h +3 -0
- esphome/components/qmc5883l/sensor.py +31 -12
- esphome/components/remote_base/gobox_protocol.cpp +3 -3
- esphome/components/remote_receiver/__init__.py +14 -2
- esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
- esphome/components/remote_receiver/remote_receiver.h +4 -0
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
- esphome/components/remote_transmitter/__init__.py +2 -2
- esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
- esphome/components/rp2040/__init__.py +11 -11
- esphome/components/rtttl/rtttl.cpp +2 -2
- esphome/components/scd30/sensor.py +1 -1
- esphome/components/script/__init__.py +1 -1
- esphome/components/script/script.h +7 -7
- esphome/components/select/select.cpp +5 -4
- esphome/components/select/select_call.cpp +1 -1
- esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
- esphome/components/sensor/__init__.py +2 -0
- esphome/components/sha256/__init__.py +22 -0
- esphome/components/sha256/sha256.cpp +116 -0
- esphome/components/sha256/sha256.h +60 -0
- esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
- esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
- esphome/components/spi/__init__.py +0 -3
- esphome/components/split_buffer/__init__.py +5 -0
- esphome/components/split_buffer/split_buffer.cpp +133 -0
- esphome/components/split_buffer/split_buffer.h +40 -0
- esphome/components/sps30/sps30.cpp +14 -10
- esphome/components/sps30/sps30.h +2 -0
- esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
- esphome/components/st7789v/st7789v.cpp +3 -2
- esphome/components/statsd/statsd.cpp +1 -1
- esphome/components/substitutions/__init__.py +3 -1
- esphome/components/substitutions/jinja.py +13 -3
- esphome/components/sx126x/__init__.py +16 -0
- esphome/components/sx126x/sx126x.cpp +15 -1
- esphome/components/sx126x/sx126x.h +9 -1
- esphome/components/sx126x/sx126x_reg.h +2 -0
- esphome/components/text_sensor/text_sensor.cpp +16 -0
- esphome/components/text_sensor/text_sensor.h +3 -10
- esphome/components/tormatic/tormatic_cover.cpp +1 -1
- esphome/components/tuya/select/tuya_select.cpp +1 -1
- esphome/components/tuya/tuya.cpp +29 -4
- esphome/components/uart/__init__.py +36 -26
- esphome/components/uart/uart.h +6 -0
- esphome/components/uart/uart_component.cpp +8 -0
- esphome/components/uart/uart_component.h +28 -0
- esphome/components/uart/uart_component_esp_idf.cpp +64 -10
- esphome/components/uart/uart_component_esp_idf.h +5 -2
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
- esphome/components/usb_host/__init__.py +2 -1
- esphome/components/usb_host/usb_host.h +82 -13
- esphome/components/usb_host/usb_host_client.cpp +180 -24
- esphome/components/usb_host/usb_host_component.cpp +1 -1
- esphome/components/usb_uart/__init__.py +0 -1
- esphome/components/usb_uart/ch34x.cpp +4 -4
- esphome/components/usb_uart/cp210x.cpp +3 -3
- esphome/components/usb_uart/usb_uart.cpp +88 -32
- esphome/components/usb_uart/usb_uart.h +30 -6
- esphome/components/valve/valve.cpp +1 -0
- esphome/components/veml7700/veml7700.cpp +7 -6
- esphome/components/version/version_text_sensor.cpp +2 -1
- esphome/components/voice_assistant/voice_assistant.cpp +3 -2
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
- esphome/components/web_server/list_entities.cpp +3 -4
- esphome/components/web_server/list_entities.h +8 -10
- esphome/components/web_server/ota/__init__.py +1 -1
- esphome/components/web_server/ota/ota_web_server.cpp +9 -3
- esphome/components/web_server/web_server.cpp +509 -404
- esphome/components/web_server/web_server.h +5 -6
- esphome/components/web_server/web_server_v1.cpp +21 -19
- esphome/components/web_server_base/__init__.py +5 -2
- esphome/components/web_server_base/web_server_base.h +27 -7
- esphome/components/web_server_idf/__init__.py +1 -1
- esphome/components/web_server_idf/multipart.cpp +2 -2
- esphome/components/web_server_idf/multipart.h +2 -2
- esphome/components/web_server_idf/utils.cpp +2 -2
- esphome/components/web_server_idf/utils.h +2 -2
- esphome/components/web_server_idf/web_server_idf.cpp +118 -26
- esphome/components/web_server_idf/web_server_idf.h +12 -10
- esphome/components/wifi/__init__.py +13 -11
- esphome/components/wifi/wifi_component.cpp +73 -56
- esphome/components/wifi/wifi_component.h +4 -4
- esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
- esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
- esphome/components/wireguard/__init__.py +1 -1
- esphome/components/wts01/__init__.py +0 -0
- esphome/components/wts01/sensor.py +41 -0
- esphome/components/wts01/wts01.cpp +91 -0
- esphome/components/wts01/wts01.h +27 -0
- esphome/components/zephyr/__init__.py +5 -5
- esphome/components/zwave_proxy/__init__.py +43 -0
- esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
- esphome/components/zwave_proxy/zwave_proxy.h +93 -0
- esphome/config.py +79 -24
- esphome/config_validation.py +13 -15
- esphome/const.py +9 -2
- esphome/core/__init__.py +31 -22
- esphome/core/component.cpp +28 -18
- esphome/core/component_iterator.h +2 -1
- esphome/core/config.py +15 -15
- esphome/core/defines.h +19 -0
- esphome/core/hash_base.h +56 -0
- esphome/core/helpers.cpp +19 -3
- esphome/core/helpers.h +26 -0
- esphome/core/scheduler.cpp +5 -21
- esphome/core/scheduler.h +19 -8
- esphome/core/string_ref.h +1 -1
- esphome/core/time.cpp +5 -5
- esphome/cpp_generator.py +4 -29
- esphome/dashboard/const.py +21 -4
- esphome/dashboard/core.py +10 -8
- esphome/dashboard/dns.py +15 -0
- esphome/dashboard/entries.py +15 -21
- esphome/dashboard/models.py +76 -0
- esphome/dashboard/settings.py +7 -7
- esphome/dashboard/status/mdns.py +46 -2
- esphome/dashboard/web_server.py +367 -93
- esphome/espota2.py +111 -31
- esphome/external_files.py +6 -7
- esphome/git.py +8 -0
- esphome/helpers.py +124 -77
- esphome/loader.py +8 -9
- esphome/platformio_api.py +25 -18
- esphome/storage_json.py +26 -21
- esphome/types.py +30 -2
- esphome/util.py +32 -16
- esphome/vscode.py +8 -8
- esphome/wizard.py +10 -10
- esphome/writer.py +50 -15
- esphome/yaml_util.py +37 -31
- esphome/zeroconf.py +12 -3
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/METADATA +11 -11
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/RECORD +332 -312
- esphome/components/event_emitter/__init__.py +0 -5
- esphome/components/event_emitter/event_emitter.cpp +0 -14
- esphome/components/event_emitter/event_emitter.h +0 -63
- esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
- esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
- esphome/components/uart/uart_component_esp32_arduino.h +0 -60
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
- esphome/core/string_ref.cpp +0 -12
- esphome/dashboard/util/file.py +0 -63
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/top_level.txt +0 -0
esphome/loader.py
CHANGED
@@ -82,11 +82,10 @@ class ComponentManifest:
|
|
82
82
|
return getattr(self.module, "CONFLICTS_WITH", [])
|
83
83
|
|
84
84
|
@property
|
85
|
-
def auto_load(
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
return al
|
85
|
+
def auto_load(
|
86
|
+
self,
|
87
|
+
) -> list[str] | Callable[[], list[str]] | Callable[[ConfigType], list[str]]:
|
88
|
+
return getattr(self.module, "AUTO_LOAD", [])
|
90
89
|
|
91
90
|
@property
|
92
91
|
def codeowners(self) -> list[str]:
|
@@ -192,7 +191,7 @@ def install_custom_components_meta_finder():
|
|
192
191
|
install_meta_finder(custom_components_dir)
|
193
192
|
|
194
193
|
|
195
|
-
def _lookup_module(domain, exception):
|
194
|
+
def _lookup_module(domain: str, exception: bool) -> ComponentManifest | None:
|
196
195
|
if domain in _COMPONENT_CACHE:
|
197
196
|
return _COMPONENT_CACHE[domain]
|
198
197
|
|
@@ -219,16 +218,16 @@ def _lookup_module(domain, exception):
|
|
219
218
|
return manif
|
220
219
|
|
221
220
|
|
222
|
-
def get_component(domain, exception=False):
|
221
|
+
def get_component(domain: str, exception: bool = False) -> ComponentManifest | None:
|
223
222
|
assert "." not in domain
|
224
223
|
return _lookup_module(domain, exception)
|
225
224
|
|
226
225
|
|
227
|
-
def get_platform(domain, platform):
|
226
|
+
def get_platform(domain: str, platform: str) -> ComponentManifest | None:
|
228
227
|
full = f"{platform}.{domain}"
|
229
228
|
return _lookup_module(full, False)
|
230
229
|
|
231
230
|
|
232
|
-
_COMPONENT_CACHE = {}
|
231
|
+
_COMPONENT_CACHE: dict[str, ComponentManifest] = {}
|
233
232
|
CORE_COMPONENTS_PATH = (Path(__file__).parent / "components").resolve()
|
234
233
|
_COMPONENT_CACHE["esphome"] = ComponentManifest(esphome.core.config)
|
esphome/platformio_api.py
CHANGED
@@ -18,23 +18,25 @@ def patch_structhash():
|
|
18
18
|
# removed/added. This might have unintended consequences, but this improves compile
|
19
19
|
# times greatly when adding/removing components and a simple clean build solves
|
20
20
|
# all issues
|
21
|
-
from os import makedirs
|
22
|
-
from os.path import getmtime, isdir, join
|
23
|
-
|
24
21
|
from platformio.run import cli, helpers
|
25
22
|
|
26
23
|
def patched_clean_build_dir(build_dir, *args):
|
27
24
|
from platformio import fs
|
28
25
|
from platformio.project.helpers import get_project_dir
|
29
26
|
|
30
|
-
platformio_ini =
|
27
|
+
platformio_ini = Path(get_project_dir()) / "platformio.ini"
|
28
|
+
|
29
|
+
build_dir = Path(build_dir)
|
31
30
|
|
32
31
|
# if project's config is modified
|
33
|
-
if
|
32
|
+
if (
|
33
|
+
build_dir.is_dir()
|
34
|
+
and platformio_ini.stat().st_mtime > build_dir.stat().st_mtime
|
35
|
+
):
|
34
36
|
fs.rmtree(build_dir)
|
35
37
|
|
36
|
-
if not
|
37
|
-
|
38
|
+
if not build_dir.is_dir():
|
39
|
+
build_dir.mkdir(parents=True)
|
38
40
|
|
39
41
|
helpers.clean_build_dir = patched_clean_build_dir
|
40
42
|
cli.clean_build_dir = patched_clean_build_dir
|
@@ -70,14 +72,19 @@ FILTER_PLATFORMIO_LINES = [
|
|
70
72
|
r" - tool-esptool.* \(.*\)",
|
71
73
|
r" - toolchain-.* \(.*\)",
|
72
74
|
r"Creating BIN file .*",
|
75
|
+
r"Warning! Could not find file \".*.crt\"",
|
76
|
+
r"Warning! Arduino framework as an ESP-IDF component doesn't handle the `variant` field! The default `esp32` variant will be used.",
|
77
|
+
r"Warning: DEPRECATED: 'esptool.py' is deprecated. Please use 'esptool' instead. The '.py' suffix will be removed in a future major release.",
|
78
|
+
r"Warning: esp-idf-size exited with code 2",
|
79
|
+
r"esp_idf_size: error: unrecognized arguments: --ng",
|
73
80
|
]
|
74
81
|
|
75
82
|
|
76
83
|
def run_platformio_cli(*args, **kwargs) -> str | int:
|
77
84
|
os.environ["PLATFORMIO_FORCE_COLOR"] = "true"
|
78
|
-
os.environ["PLATFORMIO_BUILD_DIR"] =
|
85
|
+
os.environ["PLATFORMIO_BUILD_DIR"] = str(CORE.relative_pioenvs_path().absolute())
|
79
86
|
os.environ.setdefault(
|
80
|
-
"PLATFORMIO_LIBDEPS_DIR",
|
87
|
+
"PLATFORMIO_LIBDEPS_DIR", str(CORE.relative_piolibdeps_path().absolute())
|
81
88
|
)
|
82
89
|
# Suppress Python syntax warnings from third-party scripts during compilation
|
83
90
|
os.environ.setdefault("PYTHONWARNINGS", "ignore::SyntaxWarning")
|
@@ -96,7 +103,7 @@ def run_platformio_cli(*args, **kwargs) -> str | int:
|
|
96
103
|
|
97
104
|
|
98
105
|
def run_platformio_cli_run(config, verbose, *args, **kwargs) -> str | int:
|
99
|
-
command = ["run", "-d", CORE.build_path]
|
106
|
+
command = ["run", "-d", str(CORE.build_path)]
|
100
107
|
if verbose:
|
101
108
|
command += ["-v"]
|
102
109
|
command += list(args)
|
@@ -128,8 +135,8 @@ def _run_idedata(config):
|
|
128
135
|
|
129
136
|
|
130
137
|
def _load_idedata(config):
|
131
|
-
platformio_ini =
|
132
|
-
temp_idedata =
|
138
|
+
platformio_ini = CORE.relative_build_path("platformio.ini")
|
139
|
+
temp_idedata = CORE.relative_internal_path("idedata", f"{CORE.name}.json")
|
133
140
|
|
134
141
|
changed = False
|
135
142
|
if (
|
@@ -299,7 +306,7 @@ def process_stacktrace(config, line, backtrace_state):
|
|
299
306
|
|
300
307
|
@dataclass
|
301
308
|
class FlashImage:
|
302
|
-
path:
|
309
|
+
path: Path
|
303
310
|
offset: str
|
304
311
|
|
305
312
|
|
@@ -308,17 +315,17 @@ class IDEData:
|
|
308
315
|
self.raw = raw
|
309
316
|
|
310
317
|
@property
|
311
|
-
def firmware_elf_path(self):
|
312
|
-
return self.raw["prog_path"]
|
318
|
+
def firmware_elf_path(self) -> Path:
|
319
|
+
return Path(self.raw["prog_path"])
|
313
320
|
|
314
321
|
@property
|
315
|
-
def firmware_bin_path(self) ->
|
316
|
-
return
|
322
|
+
def firmware_bin_path(self) -> Path:
|
323
|
+
return self.firmware_elf_path.with_suffix(".bin")
|
317
324
|
|
318
325
|
@property
|
319
326
|
def extra_flash_images(self) -> list[FlashImage]:
|
320
327
|
return [
|
321
|
-
FlashImage(path=entry["path"], offset=entry["offset"])
|
328
|
+
FlashImage(path=Path(entry["path"]), offset=entry["offset"])
|
322
329
|
for entry in self.raw["extra"]["flash_images"]
|
323
330
|
]
|
324
331
|
|
esphome/storage_json.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import binascii
|
4
|
-
import codecs
|
5
4
|
from datetime import datetime
|
6
5
|
import json
|
7
6
|
import logging
|
8
7
|
import os
|
8
|
+
from pathlib import Path
|
9
9
|
|
10
10
|
from esphome import const
|
11
11
|
from esphome.const import CONF_DISABLED, CONF_MDNS
|
@@ -16,30 +16,35 @@ from esphome.types import CoreType
|
|
16
16
|
_LOGGER = logging.getLogger(__name__)
|
17
17
|
|
18
18
|
|
19
|
-
def storage_path() ->
|
20
|
-
return
|
19
|
+
def storage_path() -> Path:
|
20
|
+
return CORE.data_dir / "storage" / f"{CORE.config_filename}.json"
|
21
21
|
|
22
22
|
|
23
|
-
def ext_storage_path(config_filename: str) ->
|
24
|
-
return
|
23
|
+
def ext_storage_path(config_filename: str) -> Path:
|
24
|
+
return CORE.data_dir / "storage" / f"{config_filename}.json"
|
25
25
|
|
26
26
|
|
27
|
-
def esphome_storage_path() ->
|
28
|
-
return
|
27
|
+
def esphome_storage_path() -> Path:
|
28
|
+
return CORE.data_dir / "esphome.json"
|
29
29
|
|
30
30
|
|
31
|
-
def ignored_devices_storage_path() ->
|
32
|
-
return
|
31
|
+
def ignored_devices_storage_path() -> Path:
|
32
|
+
return CORE.data_dir / "ignored-devices.json"
|
33
33
|
|
34
34
|
|
35
|
-
def trash_storage_path() ->
|
35
|
+
def trash_storage_path() -> Path:
|
36
36
|
return CORE.relative_config_path("trash")
|
37
37
|
|
38
38
|
|
39
|
-
def archive_storage_path() ->
|
39
|
+
def archive_storage_path() -> Path:
|
40
40
|
return CORE.relative_config_path("archive")
|
41
41
|
|
42
42
|
|
43
|
+
def _to_path_if_not_none(value: str | None) -> Path | None:
|
44
|
+
"""Convert a string to Path if it's not None."""
|
45
|
+
return Path(value) if value is not None else None
|
46
|
+
|
47
|
+
|
43
48
|
class StorageJSON:
|
44
49
|
def __init__(
|
45
50
|
self,
|
@@ -52,8 +57,8 @@ class StorageJSON:
|
|
52
57
|
address: str,
|
53
58
|
web_port: int | None,
|
54
59
|
target_platform: str,
|
55
|
-
build_path:
|
56
|
-
firmware_bin_path:
|
60
|
+
build_path: Path | None,
|
61
|
+
firmware_bin_path: Path | None,
|
57
62
|
loaded_integrations: set[str],
|
58
63
|
loaded_platforms: set[str],
|
59
64
|
no_mdns: bool,
|
@@ -107,8 +112,8 @@ class StorageJSON:
|
|
107
112
|
"address": self.address,
|
108
113
|
"web_port": self.web_port,
|
109
114
|
"esp_platform": self.target_platform,
|
110
|
-
"build_path": self.build_path,
|
111
|
-
"firmware_bin_path": self.firmware_bin_path,
|
115
|
+
"build_path": str(self.build_path),
|
116
|
+
"firmware_bin_path": str(self.firmware_bin_path),
|
112
117
|
"loaded_integrations": sorted(self.loaded_integrations),
|
113
118
|
"loaded_platforms": sorted(self.loaded_platforms),
|
114
119
|
"no_mdns": self.no_mdns,
|
@@ -176,8 +181,8 @@ class StorageJSON:
|
|
176
181
|
)
|
177
182
|
|
178
183
|
@staticmethod
|
179
|
-
def _load_impl(path:
|
180
|
-
with
|
184
|
+
def _load_impl(path: Path) -> StorageJSON | None:
|
185
|
+
with path.open("r", encoding="utf-8") as f_handle:
|
181
186
|
storage = json.load(f_handle)
|
182
187
|
storage_version = storage["storage_version"]
|
183
188
|
name = storage.get("name")
|
@@ -190,8 +195,8 @@ class StorageJSON:
|
|
190
195
|
address = storage.get("address")
|
191
196
|
web_port = storage.get("web_port")
|
192
197
|
esp_platform = storage.get("esp_platform")
|
193
|
-
build_path = storage.get("build_path")
|
194
|
-
firmware_bin_path = storage.get("firmware_bin_path")
|
198
|
+
build_path = _to_path_if_not_none(storage.get("build_path"))
|
199
|
+
firmware_bin_path = _to_path_if_not_none(storage.get("firmware_bin_path"))
|
195
200
|
loaded_integrations = set(storage.get("loaded_integrations", []))
|
196
201
|
loaded_platforms = set(storage.get("loaded_platforms", []))
|
197
202
|
no_mdns = storage.get("no_mdns", False)
|
@@ -217,7 +222,7 @@ class StorageJSON:
|
|
217
222
|
)
|
218
223
|
|
219
224
|
@staticmethod
|
220
|
-
def load(path:
|
225
|
+
def load(path: Path) -> StorageJSON | None:
|
221
226
|
try:
|
222
227
|
return StorageJSON._load_impl(path)
|
223
228
|
except Exception: # pylint: disable=broad-except
|
@@ -268,7 +273,7 @@ class EsphomeStorageJSON:
|
|
268
273
|
|
269
274
|
@staticmethod
|
270
275
|
def _load_impl(path: str) -> EsphomeStorageJSON | None:
|
271
|
-
with
|
276
|
+
with Path(path).open("r", encoding="utf-8") as f_handle:
|
272
277
|
storage = json.load(f_handle)
|
273
278
|
storage_version = storage["storage_version"]
|
274
279
|
cookie_secret = storage.get("cookie_secret")
|
esphome/types.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
"""This helper module tracks commonly used types in the esphome python codebase."""
|
2
2
|
|
3
|
-
|
3
|
+
import abc
|
4
|
+
from collections.abc import Sequence
|
5
|
+
from typing import Any, TypedDict
|
4
6
|
|
5
|
-
from esphome.core import ID, EsphomeCore, Lambda
|
7
|
+
from esphome.core import ID, EsphomeCore, Lambda, TimePeriod
|
6
8
|
|
7
9
|
ConfigFragmentType = (
|
8
10
|
str
|
@@ -20,6 +22,32 @@ CoreType = EsphomeCore
|
|
20
22
|
ConfigPathType = str | int
|
21
23
|
|
22
24
|
|
25
|
+
class Expression(abc.ABC):
|
26
|
+
__slots__ = ()
|
27
|
+
|
28
|
+
@abc.abstractmethod
|
29
|
+
def __str__(self):
|
30
|
+
"""
|
31
|
+
Convert expression into C++ code
|
32
|
+
"""
|
33
|
+
|
34
|
+
|
35
|
+
SafeExpType = (
|
36
|
+
Expression
|
37
|
+
| bool
|
38
|
+
| str
|
39
|
+
| int
|
40
|
+
| float
|
41
|
+
| TimePeriod
|
42
|
+
| type[bool]
|
43
|
+
| type[int]
|
44
|
+
| type[float]
|
45
|
+
| Sequence[Any]
|
46
|
+
)
|
47
|
+
|
48
|
+
TemplateArgsType = list[tuple[SafeExpType, str]]
|
49
|
+
|
50
|
+
|
23
51
|
class EntityMetadata(TypedDict):
|
24
52
|
"""Metadata stored for each entity to help with duplicate detection."""
|
25
53
|
|
esphome/util.py
CHANGED
@@ -1,20 +1,30 @@
|
|
1
1
|
import collections
|
2
|
+
from collections.abc import Callable
|
2
3
|
import io
|
3
4
|
import logging
|
4
|
-
import os
|
5
5
|
from pathlib import Path
|
6
6
|
import re
|
7
7
|
import subprocess
|
8
8
|
import sys
|
9
|
-
from typing import Any
|
9
|
+
from typing import TYPE_CHECKING, Any
|
10
10
|
|
11
11
|
from esphome import const
|
12
12
|
|
13
13
|
_LOGGER = logging.getLogger(__name__)
|
14
14
|
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from esphome.config_validation import Schema
|
17
|
+
from esphome.cpp_generator import MockObjClass
|
18
|
+
|
15
19
|
|
16
20
|
class RegistryEntry:
|
17
|
-
def __init__(
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
name: str,
|
24
|
+
fun: Callable[..., Any],
|
25
|
+
type_id: "MockObjClass",
|
26
|
+
schema: "Schema",
|
27
|
+
):
|
18
28
|
self.name = name
|
19
29
|
self.fun = fun
|
20
30
|
self.type_id = type_id
|
@@ -39,8 +49,8 @@ class Registry(dict[str, RegistryEntry]):
|
|
39
49
|
self.base_schema = base_schema or {}
|
40
50
|
self.type_id_key = type_id_key
|
41
51
|
|
42
|
-
def register(self, name, type_id, schema):
|
43
|
-
def decorator(fun):
|
52
|
+
def register(self, name: str, type_id: "MockObjClass", schema: "Schema"):
|
53
|
+
def decorator(fun: Callable[..., Any]):
|
44
54
|
self[name] = RegistryEntry(name, fun, type_id, schema)
|
45
55
|
return fun
|
46
56
|
|
@@ -48,8 +58,8 @@ class Registry(dict[str, RegistryEntry]):
|
|
48
58
|
|
49
59
|
|
50
60
|
class SimpleRegistry(dict):
|
51
|
-
def register(self, name, data):
|
52
|
-
def decorator(fun):
|
61
|
+
def register(self, name: str, data: Any):
|
62
|
+
def decorator(fun: Callable[..., Any]):
|
53
63
|
self[name] = (fun, data)
|
54
64
|
return fun
|
55
65
|
|
@@ -86,7 +96,10 @@ def safe_input(prompt=""):
|
|
86
96
|
return input()
|
87
97
|
|
88
98
|
|
89
|
-
def shlex_quote(s):
|
99
|
+
def shlex_quote(s: str | Path) -> str:
|
100
|
+
# Convert Path objects to strings
|
101
|
+
if isinstance(s, Path):
|
102
|
+
s = str(s)
|
90
103
|
if not s:
|
91
104
|
return "''"
|
92
105
|
if re.search(r"[^\w@%+=:,./-]", s) is None:
|
@@ -272,25 +285,28 @@ class OrderedDict(collections.OrderedDict):
|
|
272
285
|
return dict(self).__repr__()
|
273
286
|
|
274
287
|
|
275
|
-
def list_yaml_files(configs: list[str]) -> list[
|
276
|
-
files: list[
|
288
|
+
def list_yaml_files(configs: list[str | Path]) -> list[Path]:
|
289
|
+
files: list[Path] = []
|
277
290
|
for config in configs:
|
278
|
-
|
291
|
+
config = Path(config)
|
292
|
+
if not config.exists():
|
293
|
+
raise FileNotFoundError(f"Config path '{config}' does not exist!")
|
294
|
+
if config.is_file():
|
279
295
|
files.append(config)
|
280
296
|
else:
|
281
|
-
files.extend(
|
297
|
+
files.extend(config.glob("*"))
|
282
298
|
files = filter_yaml_files(files)
|
283
299
|
return sorted(files)
|
284
300
|
|
285
301
|
|
286
|
-
def filter_yaml_files(files: list[
|
302
|
+
def filter_yaml_files(files: list[Path]) -> list[Path]:
|
287
303
|
return [
|
288
304
|
f
|
289
305
|
for f in files
|
290
306
|
if (
|
291
|
-
|
292
|
-
and
|
293
|
-
and not
|
307
|
+
f.suffix in (".yaml", ".yml")
|
308
|
+
and f.name not in ("secrets.yaml", "secrets.yml")
|
309
|
+
and not f.name.startswith(".")
|
294
310
|
)
|
295
311
|
]
|
296
312
|
|
esphome/vscode.py
CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from io import StringIO
|
4
4
|
import json
|
5
|
-
import
|
5
|
+
from pathlib import Path
|
6
6
|
from typing import Any
|
7
7
|
|
8
8
|
from esphome.config import Config, _format_vol_invalid, validate_config
|
@@ -67,24 +67,24 @@ def _read_file_content_from_json_on_stdin() -> str:
|
|
67
67
|
return data["content"]
|
68
68
|
|
69
69
|
|
70
|
-
def _print_file_read_event(path:
|
70
|
+
def _print_file_read_event(path: Path) -> None:
|
71
71
|
"""Print a file read event."""
|
72
72
|
print(
|
73
73
|
json.dumps(
|
74
74
|
{
|
75
75
|
"type": "read_file",
|
76
|
-
"path": path,
|
76
|
+
"path": str(path),
|
77
77
|
}
|
78
78
|
)
|
79
79
|
)
|
80
80
|
|
81
81
|
|
82
|
-
def _request_and_get_stream_on_stdin(fname:
|
82
|
+
def _request_and_get_stream_on_stdin(fname: Path) -> StringIO:
|
83
83
|
_print_file_read_event(fname)
|
84
84
|
return StringIO(_read_file_content_from_json_on_stdin())
|
85
85
|
|
86
86
|
|
87
|
-
def _vscode_loader(fname:
|
87
|
+
def _vscode_loader(fname: Path) -> dict[str, Any]:
|
88
88
|
raw_yaml_stream = _request_and_get_stream_on_stdin(fname)
|
89
89
|
# it is required to set the name on StringIO so document on start_mark
|
90
90
|
# is set properly. Otherwise it is initialized with "<file>"
|
@@ -92,7 +92,7 @@ def _vscode_loader(fname: str) -> dict[str, Any]:
|
|
92
92
|
return parse_yaml(fname, raw_yaml_stream, _vscode_loader)
|
93
93
|
|
94
94
|
|
95
|
-
def _ace_loader(fname:
|
95
|
+
def _ace_loader(fname: Path) -> dict[str, Any]:
|
96
96
|
raw_yaml_stream = _request_and_get_stream_on_stdin(fname)
|
97
97
|
return parse_yaml(fname, raw_yaml_stream)
|
98
98
|
|
@@ -120,10 +120,10 @@ def read_config(args):
|
|
120
120
|
return
|
121
121
|
CORE.vscode = True
|
122
122
|
if args.ace: # Running from ESPHome Compiler dashboard, not vscode
|
123
|
-
CORE.config_path =
|
123
|
+
CORE.config_path = Path(args.configuration) / data["file"]
|
124
124
|
loader = _ace_loader
|
125
125
|
else:
|
126
|
-
CORE.config_path = data["file"]
|
126
|
+
CORE.config_path = Path(data["file"])
|
127
127
|
loader = _vscode_loader
|
128
128
|
|
129
129
|
file_name = CORE.config_path
|
esphome/wizard.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import
|
1
|
+
from pathlib import Path
|
2
2
|
import random
|
3
3
|
import string
|
4
4
|
from typing import Literal, NotRequired, TypedDict, Unpack
|
@@ -213,7 +213,7 @@ class WizardWriteKwargs(TypedDict):
|
|
213
213
|
file_text: NotRequired[str]
|
214
214
|
|
215
215
|
|
216
|
-
def wizard_write(path:
|
216
|
+
def wizard_write(path: Path, **kwargs: Unpack[WizardWriteKwargs]) -> bool:
|
217
217
|
from esphome.components.bk72xx import boards as bk72xx_boards
|
218
218
|
from esphome.components.esp32 import boards as esp32_boards
|
219
219
|
from esphome.components.esp8266 import boards as esp8266_boards
|
@@ -256,13 +256,13 @@ def wizard_write(path: str, **kwargs: Unpack[WizardWriteKwargs]) -> bool:
|
|
256
256
|
file_text = wizard_file(**kwargs)
|
257
257
|
|
258
258
|
# Check if file already exists to prevent overwriting
|
259
|
-
if
|
259
|
+
if path.exists() and path.is_file():
|
260
260
|
safe_print(color(AnsiFore.RED, f'The file "{path}" already exists.'))
|
261
261
|
return False
|
262
262
|
|
263
263
|
write_file(path, file_text)
|
264
264
|
storage = StorageJSON.from_wizard(name, name, f"{name}.local", hardware)
|
265
|
-
storage_path = ext_storage_path(
|
265
|
+
storage_path = ext_storage_path(path.name)
|
266
266
|
storage.save(storage_path)
|
267
267
|
|
268
268
|
return True
|
@@ -301,7 +301,7 @@ def strip_accents(value: str) -> str:
|
|
301
301
|
)
|
302
302
|
|
303
303
|
|
304
|
-
def wizard(path:
|
304
|
+
def wizard(path: Path) -> int:
|
305
305
|
from esphome.components.bk72xx import boards as bk72xx_boards
|
306
306
|
from esphome.components.esp32 import boards as esp32_boards
|
307
307
|
from esphome.components.esp8266 import boards as esp8266_boards
|
@@ -309,14 +309,14 @@ def wizard(path: str) -> int:
|
|
309
309
|
from esphome.components.rp2040 import boards as rp2040_boards
|
310
310
|
from esphome.components.rtl87xx import boards as rtl87xx_boards
|
311
311
|
|
312
|
-
if not
|
312
|
+
if path.suffix not in (".yaml", ".yml"):
|
313
313
|
safe_print(
|
314
|
-
f"Please make your configuration file {color(AnsiFore.CYAN, path)} have the extension .yaml or .yml"
|
314
|
+
f"Please make your configuration file {color(AnsiFore.CYAN, str(path))} have the extension .yaml or .yml"
|
315
315
|
)
|
316
316
|
return 1
|
317
|
-
if
|
317
|
+
if path.exists():
|
318
318
|
safe_print(
|
319
|
-
f"Uh oh, it seems like {color(AnsiFore.CYAN, path)} already exists, please delete that file first or chose another configuration file."
|
319
|
+
f"Uh oh, it seems like {color(AnsiFore.CYAN, str(path))} already exists, please delete that file first or chose another configuration file."
|
320
320
|
)
|
321
321
|
return 2
|
322
322
|
|
@@ -549,7 +549,7 @@ def wizard(path: str) -> int:
|
|
549
549
|
safe_print()
|
550
550
|
safe_print(
|
551
551
|
color(AnsiFore.CYAN, "DONE! I've now written a new configuration file to ")
|
552
|
-
+ color(AnsiFore.BOLD_CYAN, path)
|
552
|
+
+ color(AnsiFore.BOLD_CYAN, str(path))
|
553
553
|
)
|
554
554
|
safe_print()
|
555
555
|
safe_print("Next steps:")
|
esphome/writer.py
CHANGED
@@ -266,7 +266,7 @@ def generate_version_h():
|
|
266
266
|
|
267
267
|
def write_cpp(code_s):
|
268
268
|
path = CORE.relative_src_path("main.cpp")
|
269
|
-
if
|
269
|
+
if path.is_file():
|
270
270
|
text = read_file(path)
|
271
271
|
code_format = find_begin_end(
|
272
272
|
text, CPP_AUTO_GENERATE_BEGIN, CPP_AUTO_GENERATE_END
|
@@ -292,43 +292,79 @@ def write_cpp(code_s):
|
|
292
292
|
|
293
293
|
def clean_cmake_cache():
|
294
294
|
pioenvs = CORE.relative_pioenvs_path()
|
295
|
-
if
|
296
|
-
pioenvs_cmake_path = CORE.
|
297
|
-
if
|
295
|
+
if pioenvs.is_dir():
|
296
|
+
pioenvs_cmake_path = pioenvs / CORE.name / "CMakeCache.txt"
|
297
|
+
if pioenvs_cmake_path.is_file():
|
298
298
|
_LOGGER.info("Deleting %s", pioenvs_cmake_path)
|
299
|
-
|
299
|
+
pioenvs_cmake_path.unlink()
|
300
300
|
|
301
301
|
|
302
302
|
def clean_build():
|
303
303
|
import shutil
|
304
304
|
|
305
|
+
# Allow skipping cache cleaning for integration tests
|
306
|
+
if os.environ.get("ESPHOME_SKIP_CLEAN_BUILD"):
|
307
|
+
_LOGGER.warning("Skipping build cleaning (ESPHOME_SKIP_CLEAN_BUILD set)")
|
308
|
+
return
|
309
|
+
|
305
310
|
pioenvs = CORE.relative_pioenvs_path()
|
306
|
-
if
|
311
|
+
if pioenvs.is_dir():
|
307
312
|
_LOGGER.info("Deleting %s", pioenvs)
|
308
313
|
shutil.rmtree(pioenvs)
|
309
314
|
piolibdeps = CORE.relative_piolibdeps_path()
|
310
|
-
if
|
315
|
+
if piolibdeps.is_dir():
|
311
316
|
_LOGGER.info("Deleting %s", piolibdeps)
|
312
317
|
shutil.rmtree(piolibdeps)
|
313
318
|
dependencies_lock = CORE.relative_build_path("dependencies.lock")
|
314
|
-
if
|
319
|
+
if dependencies_lock.is_file():
|
315
320
|
_LOGGER.info("Deleting %s", dependencies_lock)
|
316
|
-
|
321
|
+
dependencies_lock.unlink()
|
317
322
|
|
318
323
|
# Clean PlatformIO cache to resolve CMake compiler detection issues
|
319
324
|
# This helps when toolchain paths change or get corrupted
|
320
325
|
try:
|
321
|
-
from platformio.project.
|
326
|
+
from platformio.project.config import ProjectConfig
|
322
327
|
except ImportError:
|
323
328
|
# PlatformIO is not available, skip cache cleaning
|
324
329
|
pass
|
325
330
|
else:
|
326
|
-
|
327
|
-
|
331
|
+
config = ProjectConfig.get_instance()
|
332
|
+
cache_dir = Path(config.get("platformio", "cache_dir"))
|
333
|
+
if cache_dir.is_dir():
|
328
334
|
_LOGGER.info("Deleting PlatformIO cache %s", cache_dir)
|
329
335
|
shutil.rmtree(cache_dir)
|
330
336
|
|
331
337
|
|
338
|
+
def clean_all(configuration: list[str]):
|
339
|
+
import shutil
|
340
|
+
|
341
|
+
# Clean entire build dir
|
342
|
+
for dir in configuration:
|
343
|
+
build_dir = Path(dir) / ".esphome"
|
344
|
+
if build_dir.is_dir():
|
345
|
+
_LOGGER.info("Cleaning %s", build_dir)
|
346
|
+
# Don't remove storage as it will cause the dashboard to regenerate all configs
|
347
|
+
for item in build_dir.iterdir():
|
348
|
+
if item.is_file():
|
349
|
+
item.unlink()
|
350
|
+
elif item.name != "storage" and item.is_dir():
|
351
|
+
shutil.rmtree(item)
|
352
|
+
|
353
|
+
# Clean PlatformIO project files
|
354
|
+
try:
|
355
|
+
from platformio.project.config import ProjectConfig
|
356
|
+
except ImportError:
|
357
|
+
# PlatformIO is not available, skip cleaning
|
358
|
+
pass
|
359
|
+
else:
|
360
|
+
config = ProjectConfig.get_instance()
|
361
|
+
for pio_dir in ["cache_dir", "packages_dir", "platforms_dir", "core_dir"]:
|
362
|
+
path = Path(config.get("platformio", pio_dir))
|
363
|
+
if path.is_dir():
|
364
|
+
_LOGGER.info("Deleting PlatformIO %s %s", pio_dir, path)
|
365
|
+
shutil.rmtree(path)
|
366
|
+
|
367
|
+
|
332
368
|
GITIGNORE_CONTENT = """# Gitignore settings for ESPHome
|
333
369
|
# This is an example and may include too much for your use-case.
|
334
370
|
# You can modify this file to suit your needs.
|
@@ -339,6 +375,5 @@ GITIGNORE_CONTENT = """# Gitignore settings for ESPHome
|
|
339
375
|
|
340
376
|
def write_gitignore():
|
341
377
|
path = CORE.relative_config_path(".gitignore")
|
342
|
-
if not
|
343
|
-
|
344
|
-
f.write(GITIGNORE_CONTENT)
|
378
|
+
if not path.is_file():
|
379
|
+
path.write_text(GITIGNORE_CONTENT, encoding="utf-8")
|