mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'dev' into idf_webserver_ota
This commit is contained in:
		| @@ -34,11 +34,9 @@ from esphome.const import ( | ||||
|     CONF_PORT, | ||||
|     CONF_SUBSTITUTIONS, | ||||
|     CONF_TOPIC, | ||||
|     PLATFORM_BK72XX, | ||||
|     PLATFORM_ESP32, | ||||
|     PLATFORM_ESP8266, | ||||
|     PLATFORM_RP2040, | ||||
|     PLATFORM_RTL87XX, | ||||
|     SECRETS_FILES, | ||||
| ) | ||||
| from esphome.core import CORE, EsphomeError, coroutine | ||||
| @@ -354,7 +352,7 @@ def upload_program(config, args, host): | ||||
|         if CORE.target_platform in (PLATFORM_RP2040): | ||||
|             return upload_using_platformio(config, args.device) | ||||
|  | ||||
|         if CORE.target_platform in (PLATFORM_BK72XX, PLATFORM_RTL87XX): | ||||
|         if CORE.is_libretiny: | ||||
|             return upload_using_platformio(config, host) | ||||
|  | ||||
|         return 1  # Unknown target platform | ||||
|   | ||||
| @@ -1537,6 +1537,8 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { | ||||
|   resp.manufacturer = "Raspberry Pi"; | ||||
| #elif defined(USE_BK72XX) | ||||
|   resp.manufacturer = "Beken"; | ||||
| #elif defined(USE_LN882X) | ||||
|   resp.manufacturer = "Lightning"; | ||||
| #elif defined(USE_RTL87XX) | ||||
|   resp.manufacturer = "Realtek"; | ||||
| #elif defined(USE_HOST) | ||||
|   | ||||
| @@ -5,6 +5,7 @@ from esphome.const import ( | ||||
|     PLATFORM_BK72XX, | ||||
|     PLATFORM_ESP32, | ||||
|     PLATFORM_ESP8266, | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| @@ -14,7 +15,15 @@ CODEOWNERS = ["@OttoWinter"] | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     cv.Schema({}), | ||||
|     cv.only_with_arduino, | ||||
|     cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]), | ||||
|     cv.only_on( | ||||
|         [ | ||||
|             PLATFORM_ESP32, | ||||
|             PLATFORM_ESP8266, | ||||
|             PLATFORM_BK72XX, | ||||
|             PLATFORM_LN882X, | ||||
|             PLATFORM_RTL87XX, | ||||
|         ] | ||||
|     ), | ||||
| ) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ from esphome.const import ( | ||||
|     PLATFORM_BK72XX, | ||||
|     PLATFORM_ESP32, | ||||
|     PLATFORM_ESP8266, | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| @@ -27,7 +28,15 @@ CONFIG_SCHEMA = cv.All( | ||||
|             ), | ||||
|         } | ||||
|     ).extend(cv.COMPONENT_SCHEMA), | ||||
|     cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]), | ||||
|     cv.only_on( | ||||
|         [ | ||||
|             PLATFORM_ESP32, | ||||
|             PLATFORM_ESP8266, | ||||
|             PLATFORM_BK72XX, | ||||
|             PLATFORM_LN882X, | ||||
|             PLATFORM_RTL87XX, | ||||
|         ] | ||||
|     ), | ||||
| ) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -100,6 +100,7 @@ CONFIG_SCHEMA = ( | ||||
|                 esp32=3232, | ||||
|                 rp2040=2040, | ||||
|                 bk72xx=8892, | ||||
|                 ln882x=8820, | ||||
|                 rtl87xx=8892, | ||||
|             ): cv.port, | ||||
|             cv.Optional(CONF_PASSWORD): cv.string, | ||||
|   | ||||
| @@ -50,6 +50,7 @@ KEY_FAMILY = "family" | ||||
|  | ||||
| # COMPONENTS - auto-generated! Do not modify this block. | ||||
| COMPONENT_BK72XX = "bk72xx" | ||||
| COMPONENT_LN882X = "ln882x" | ||||
| COMPONENT_RTL87XX = "rtl87xx" | ||||
| # COMPONENTS - end | ||||
|  | ||||
| @@ -58,6 +59,7 @@ FAMILY_BK7231N = "BK7231N" | ||||
| FAMILY_BK7231Q = "BK7231Q" | ||||
| FAMILY_BK7231T = "BK7231T" | ||||
| FAMILY_BK7251 = "BK7251" | ||||
| FAMILY_LN882H = "LN882H" | ||||
| FAMILY_RTL8710B = "RTL8710B" | ||||
| FAMILY_RTL8720C = "RTL8720C" | ||||
| FAMILIES = [ | ||||
| @@ -65,6 +67,7 @@ FAMILIES = [ | ||||
|     FAMILY_BK7231Q, | ||||
|     FAMILY_BK7231T, | ||||
|     FAMILY_BK7251, | ||||
|     FAMILY_LN882H, | ||||
|     FAMILY_RTL8710B, | ||||
|     FAMILY_RTL8720C, | ||||
| ] | ||||
| @@ -73,6 +76,7 @@ FAMILY_FRIENDLY = { | ||||
|     FAMILY_BK7231Q: "BK7231Q", | ||||
|     FAMILY_BK7231T: "BK7231T", | ||||
|     FAMILY_BK7251: "BK7251", | ||||
|     FAMILY_LN882H: "LN882H", | ||||
|     FAMILY_RTL8710B: "RTL8710B", | ||||
|     FAMILY_RTL8720C: "RTL8720C", | ||||
| } | ||||
| @@ -81,6 +85,7 @@ FAMILY_COMPONENT = { | ||||
|     FAMILY_BK7231Q: COMPONENT_BK72XX, | ||||
|     FAMILY_BK7231T: COMPONENT_BK72XX, | ||||
|     FAMILY_BK7251: COMPONENT_BK72XX, | ||||
|     FAMILY_LN882H: COMPONENT_LN882X, | ||||
|     FAMILY_RTL8710B: COMPONENT_RTL87XX, | ||||
|     FAMILY_RTL8720C: COMPONENT_RTL87XX, | ||||
| } | ||||
|   | ||||
| @@ -94,6 +94,7 @@ PIN_SCHEMA_EXTRA = f"libretiny.BASE_PIN_SCHEMA.extend({VAR_PIN_SCHEMA})" | ||||
| COMPONENT_MAP = { | ||||
|     "rtl87xx": "realtek-amb", | ||||
|     "bk72xx": "beken-72xx", | ||||
|     "ln882x": "lightning-ln882x", | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										52
									
								
								esphome/components/ln882x/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								esphome/components/ln882x/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| # This file was auto-generated by libretiny/generate_components.py | ||||
| # Do not modify its contents. | ||||
| # For custom pin validators, put validate_pin() or validate_usage() | ||||
| # in gpio.py file in this directory. | ||||
| # For changing schema/pin schema, put COMPONENT_SCHEMA or COMPONENT_PIN_SCHEMA | ||||
| # in schema.py file in this directory. | ||||
|  | ||||
| from esphome import pins | ||||
| from esphome.components import libretiny | ||||
| from esphome.components.libretiny.const import ( | ||||
|     COMPONENT_LN882X, | ||||
|     KEY_COMPONENT_DATA, | ||||
|     KEY_LIBRETINY, | ||||
|     LibreTinyComponent, | ||||
| ) | ||||
| from esphome.core import CORE | ||||
|  | ||||
| from .boards import LN882X_BOARD_PINS, LN882X_BOARDS | ||||
|  | ||||
| CODEOWNERS = ["@lamauny"] | ||||
| AUTO_LOAD = ["libretiny"] | ||||
| IS_TARGET_PLATFORM = True | ||||
|  | ||||
| COMPONENT_DATA = LibreTinyComponent( | ||||
|     name=COMPONENT_LN882X, | ||||
|     boards=LN882X_BOARDS, | ||||
|     board_pins=LN882X_BOARD_PINS, | ||||
|     pin_validation=None, | ||||
|     usage_validation=None, | ||||
| ) | ||||
|  | ||||
|  | ||||
| def _set_core_data(config): | ||||
|     CORE.data[KEY_LIBRETINY] = {} | ||||
|     CORE.data[KEY_LIBRETINY][KEY_COMPONENT_DATA] = COMPONENT_DATA | ||||
|     return config | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = libretiny.BASE_SCHEMA | ||||
|  | ||||
| PIN_SCHEMA = libretiny.gpio.BASE_PIN_SCHEMA | ||||
|  | ||||
| CONFIG_SCHEMA.prepend_extra(_set_core_data) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     return await libretiny.component_to_code(config) | ||||
|  | ||||
|  | ||||
| @pins.PIN_SCHEMA_REGISTRY.register("ln882x", PIN_SCHEMA) | ||||
| async def pin_to_code(config): | ||||
|     return await libretiny.gpio.component_pin_to_code(config) | ||||
							
								
								
									
										285
									
								
								esphome/components/ln882x/boards.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								esphome/components/ln882x/boards.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,285 @@ | ||||
| # This file was auto-generated by libretiny/generate_components.py | ||||
| # Do not modify its contents. | ||||
|  | ||||
| from esphome.components.libretiny.const import FAMILY_LN882H | ||||
|  | ||||
| LN882X_BOARDS = { | ||||
|     "wl2s": { | ||||
|         "name": "WL2S Wi-Fi/BLE Module", | ||||
|         "family": FAMILY_LN882H, | ||||
|     }, | ||||
|     "ln-02": { | ||||
|         "name": "LN-02 Wi-Fi/BLE Module", | ||||
|         "family": FAMILY_LN882H, | ||||
|     }, | ||||
|     "generic-ln882hki": { | ||||
|         "name": "Generic - LN882HKI", | ||||
|         "family": FAMILY_LN882H, | ||||
|     }, | ||||
| } | ||||
|  | ||||
| LN882X_BOARD_PINS = { | ||||
|     "wl2s": { | ||||
|         "WIRE0_SCL_0": 7, | ||||
|         "WIRE0_SCL_1": 12, | ||||
|         "WIRE0_SCL_2": 3, | ||||
|         "WIRE0_SCL_3": 10, | ||||
|         "WIRE0_SCL_4": 2, | ||||
|         "WIRE0_SCL_5": 0, | ||||
|         "WIRE0_SCL_6": 19, | ||||
|         "WIRE0_SCL_7": 11, | ||||
|         "WIRE0_SCL_8": 9, | ||||
|         "WIRE0_SCL_9": 24, | ||||
|         "WIRE0_SCL_10": 25, | ||||
|         "WIRE0_SCL_11": 5, | ||||
|         "WIRE0_SCL_12": 1, | ||||
|         "WIRE0_SDA_0": 7, | ||||
|         "WIRE0_SDA_1": 12, | ||||
|         "WIRE0_SDA_2": 3, | ||||
|         "WIRE0_SDA_3": 10, | ||||
|         "WIRE0_SDA_4": 2, | ||||
|         "WIRE0_SDA_5": 0, | ||||
|         "WIRE0_SDA_6": 19, | ||||
|         "WIRE0_SDA_7": 11, | ||||
|         "WIRE0_SDA_8": 9, | ||||
|         "WIRE0_SDA_9": 24, | ||||
|         "WIRE0_SDA_10": 25, | ||||
|         "WIRE0_SDA_11": 5, | ||||
|         "WIRE0_SDA_12": 1, | ||||
|         "SERIAL0_RX": 3, | ||||
|         "SERIAL0_TX": 2, | ||||
|         "SERIAL1_RX": 24, | ||||
|         "SERIAL1_TX": 25, | ||||
|         "ADC2": 0, | ||||
|         "ADC3": 1, | ||||
|         "ADC5": 19, | ||||
|         "PA00": 0, | ||||
|         "PA0": 0, | ||||
|         "PA01": 1, | ||||
|         "PA1": 1, | ||||
|         "PA02": 2, | ||||
|         "PA2": 2, | ||||
|         "PA03": 3, | ||||
|         "PA3": 3, | ||||
|         "PA05": 5, | ||||
|         "PA5": 5, | ||||
|         "PA07": 7, | ||||
|         "PA7": 7, | ||||
|         "PA09": 9, | ||||
|         "PA9": 9, | ||||
|         "PA10": 10, | ||||
|         "PA11": 11, | ||||
|         "PA12": 12, | ||||
|         "PB03": 19, | ||||
|         "PB3": 19, | ||||
|         "PB08": 24, | ||||
|         "PB8": 24, | ||||
|         "PB09": 25, | ||||
|         "PB9": 25, | ||||
|         "RX0": 3, | ||||
|         "RX1": 24, | ||||
|         "SCL0": 1, | ||||
|         "SDA0": 1, | ||||
|         "TX0": 2, | ||||
|         "TX1": 25, | ||||
|         "D0": 7, | ||||
|         "D1": 12, | ||||
|         "D2": 3, | ||||
|         "D3": 10, | ||||
|         "D4": 2, | ||||
|         "D5": 0, | ||||
|         "D6": 19, | ||||
|         "D7": 11, | ||||
|         "D8": 9, | ||||
|         "D9": 24, | ||||
|         "D10": 25, | ||||
|         "D11": 5, | ||||
|         "D12": 1, | ||||
|         "A0": 0, | ||||
|         "A1": 19, | ||||
|         "A2": 1, | ||||
|     }, | ||||
|     "ln-02": { | ||||
|         "WIRE0_SCL_0": 11, | ||||
|         "WIRE0_SCL_1": 19, | ||||
|         "WIRE0_SCL_2": 3, | ||||
|         "WIRE0_SCL_3": 24, | ||||
|         "WIRE0_SCL_4": 2, | ||||
|         "WIRE0_SCL_5": 25, | ||||
|         "WIRE0_SCL_6": 1, | ||||
|         "WIRE0_SCL_7": 0, | ||||
|         "WIRE0_SCL_8": 9, | ||||
|         "WIRE0_SDA_0": 11, | ||||
|         "WIRE0_SDA_1": 19, | ||||
|         "WIRE0_SDA_2": 3, | ||||
|         "WIRE0_SDA_3": 24, | ||||
|         "WIRE0_SDA_4": 2, | ||||
|         "WIRE0_SDA_5": 25, | ||||
|         "WIRE0_SDA_6": 1, | ||||
|         "WIRE0_SDA_7": 0, | ||||
|         "WIRE0_SDA_8": 9, | ||||
|         "SERIAL0_RX": 3, | ||||
|         "SERIAL0_TX": 2, | ||||
|         "SERIAL1_RX": 24, | ||||
|         "SERIAL1_TX": 25, | ||||
|         "ADC2": 0, | ||||
|         "ADC3": 1, | ||||
|         "ADC5": 19, | ||||
|         "PA00": 0, | ||||
|         "PA0": 0, | ||||
|         "PA01": 1, | ||||
|         "PA1": 1, | ||||
|         "PA02": 2, | ||||
|         "PA2": 2, | ||||
|         "PA03": 3, | ||||
|         "PA3": 3, | ||||
|         "PA09": 9, | ||||
|         "PA9": 9, | ||||
|         "PA11": 11, | ||||
|         "PB03": 19, | ||||
|         "PB3": 19, | ||||
|         "PB08": 24, | ||||
|         "PB8": 24, | ||||
|         "PB09": 25, | ||||
|         "PB9": 25, | ||||
|         "RX0": 3, | ||||
|         "RX1": 24, | ||||
|         "SCL0": 9, | ||||
|         "SDA0": 9, | ||||
|         "TX0": 2, | ||||
|         "TX1": 25, | ||||
|         "D0": 11, | ||||
|         "D1": 19, | ||||
|         "D2": 3, | ||||
|         "D3": 24, | ||||
|         "D4": 2, | ||||
|         "D5": 25, | ||||
|         "D6": 1, | ||||
|         "D7": 0, | ||||
|         "D8": 9, | ||||
|         "A0": 19, | ||||
|         "A1": 1, | ||||
|         "A2": 0, | ||||
|     }, | ||||
|     "generic-ln882hki": { | ||||
|         "WIRE0_SCL_0": 0, | ||||
|         "WIRE0_SCL_1": 1, | ||||
|         "WIRE0_SCL_2": 2, | ||||
|         "WIRE0_SCL_3": 3, | ||||
|         "WIRE0_SCL_4": 4, | ||||
|         "WIRE0_SCL_5": 5, | ||||
|         "WIRE0_SCL_6": 6, | ||||
|         "WIRE0_SCL_7": 7, | ||||
|         "WIRE0_SCL_8": 8, | ||||
|         "WIRE0_SCL_9": 9, | ||||
|         "WIRE0_SCL_10": 10, | ||||
|         "WIRE0_SCL_11": 11, | ||||
|         "WIRE0_SCL_12": 12, | ||||
|         "WIRE0_SCL_13": 19, | ||||
|         "WIRE0_SCL_14": 20, | ||||
|         "WIRE0_SCL_15": 21, | ||||
|         "WIRE0_SCL_16": 22, | ||||
|         "WIRE0_SCL_17": 23, | ||||
|         "WIRE0_SCL_18": 24, | ||||
|         "WIRE0_SCL_19": 25, | ||||
|         "WIRE0_SDA_0": 0, | ||||
|         "WIRE0_SDA_1": 1, | ||||
|         "WIRE0_SDA_2": 2, | ||||
|         "WIRE0_SDA_3": 3, | ||||
|         "WIRE0_SDA_4": 4, | ||||
|         "WIRE0_SDA_5": 5, | ||||
|         "WIRE0_SDA_6": 6, | ||||
|         "WIRE0_SDA_7": 7, | ||||
|         "WIRE0_SDA_8": 8, | ||||
|         "WIRE0_SDA_9": 9, | ||||
|         "WIRE0_SDA_10": 10, | ||||
|         "WIRE0_SDA_11": 11, | ||||
|         "WIRE0_SDA_12": 12, | ||||
|         "WIRE0_SDA_13": 19, | ||||
|         "WIRE0_SDA_14": 20, | ||||
|         "WIRE0_SDA_15": 21, | ||||
|         "WIRE0_SDA_16": 22, | ||||
|         "WIRE0_SDA_17": 23, | ||||
|         "WIRE0_SDA_18": 24, | ||||
|         "WIRE0_SDA_19": 25, | ||||
|         "SERIAL0_RX": 3, | ||||
|         "SERIAL0_TX": 2, | ||||
|         "SERIAL1_RX": 24, | ||||
|         "SERIAL1_TX": 25, | ||||
|         "ADC2": 0, | ||||
|         "ADC3": 1, | ||||
|         "ADC4": 4, | ||||
|         "ADC5": 19, | ||||
|         "ADC6": 20, | ||||
|         "ADC7": 21, | ||||
|         "PA00": 0, | ||||
|         "PA0": 0, | ||||
|         "PA01": 1, | ||||
|         "PA1": 1, | ||||
|         "PA02": 2, | ||||
|         "PA2": 2, | ||||
|         "PA03": 3, | ||||
|         "PA3": 3, | ||||
|         "PA04": 4, | ||||
|         "PA4": 4, | ||||
|         "PA05": 5, | ||||
|         "PA5": 5, | ||||
|         "PA06": 6, | ||||
|         "PA6": 6, | ||||
|         "PA07": 7, | ||||
|         "PA7": 7, | ||||
|         "PA08": 8, | ||||
|         "PA8": 8, | ||||
|         "PA09": 9, | ||||
|         "PA9": 9, | ||||
|         "PA10": 10, | ||||
|         "PA11": 11, | ||||
|         "PA12": 12, | ||||
|         "PB03": 19, | ||||
|         "PB3": 19, | ||||
|         "PB04": 20, | ||||
|         "PB4": 20, | ||||
|         "PB05": 21, | ||||
|         "PB5": 21, | ||||
|         "PB06": 22, | ||||
|         "PB6": 22, | ||||
|         "PB07": 23, | ||||
|         "PB7": 23, | ||||
|         "PB08": 24, | ||||
|         "PB8": 24, | ||||
|         "PB09": 25, | ||||
|         "PB9": 25, | ||||
|         "RX0": 3, | ||||
|         "RX1": 24, | ||||
|         "TX0": 2, | ||||
|         "TX1": 25, | ||||
|         "D0": 0, | ||||
|         "D1": 1, | ||||
|         "D2": 2, | ||||
|         "D3": 3, | ||||
|         "D4": 4, | ||||
|         "D5": 5, | ||||
|         "D6": 6, | ||||
|         "D7": 7, | ||||
|         "D8": 8, | ||||
|         "D9": 9, | ||||
|         "D10": 10, | ||||
|         "D11": 11, | ||||
|         "D12": 12, | ||||
|         "D13": 19, | ||||
|         "D14": 20, | ||||
|         "D15": 21, | ||||
|         "D16": 22, | ||||
|         "D17": 23, | ||||
|         "D18": 24, | ||||
|         "D19": 25, | ||||
|         "A2": 0, | ||||
|         "A3": 1, | ||||
|         "A4": 4, | ||||
|         "A5": 19, | ||||
|         "A6": 20, | ||||
|         "A7": 21, | ||||
|     }, | ||||
| } | ||||
|  | ||||
| BOARDS = LN882X_BOARDS | ||||
| @@ -16,7 +16,11 @@ from esphome.components.esp32.const import ( | ||||
|     VARIANT_ESP32S3, | ||||
| ) | ||||
| from esphome.components.libretiny import get_libretiny_component, get_libretiny_family | ||||
| from esphome.components.libretiny.const import COMPONENT_BK72XX, COMPONENT_RTL87XX | ||||
| from esphome.components.libretiny.const import ( | ||||
|     COMPONENT_BK72XX, | ||||
|     COMPONENT_LN882X, | ||||
|     COMPONENT_RTL87XX, | ||||
| ) | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ARGS, | ||||
| @@ -35,6 +39,7 @@ from esphome.const import ( | ||||
|     PLATFORM_BK72XX, | ||||
|     PLATFORM_ESP32, | ||||
|     PLATFORM_ESP8266, | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RP2040, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| @@ -100,6 +105,7 @@ UART_SELECTION_ESP8266 = [UART0, UART0_SWAP, UART1] | ||||
|  | ||||
| UART_SELECTION_LIBRETINY = { | ||||
|     COMPONENT_BK72XX: [DEFAULT, UART1, UART2], | ||||
|     COMPONENT_LN882X: [DEFAULT, UART0, UART1, UART2], | ||||
|     COMPONENT_RTL87XX: [DEFAULT, UART0, UART1, UART2], | ||||
| } | ||||
|  | ||||
| @@ -217,6 +223,7 @@ CONFIG_SCHEMA = cv.All( | ||||
|                 esp32_p4_idf=USB_SERIAL_JTAG, | ||||
|                 rp2040=USB_CDC, | ||||
|                 bk72xx=DEFAULT, | ||||
|                 ln882x=DEFAULT, | ||||
|                 rtl87xx=DEFAULT, | ||||
|             ): cv.All( | ||||
|                 cv.only_on( | ||||
| @@ -225,6 +232,7 @@ CONFIG_SCHEMA = cv.All( | ||||
|                         PLATFORM_ESP32, | ||||
|                         PLATFORM_RP2040, | ||||
|                         PLATFORM_BK72XX, | ||||
|                         PLATFORM_LN882X, | ||||
|                         PLATFORM_RTL87XX, | ||||
|                     ] | ||||
|                 ), | ||||
|   | ||||
| @@ -94,6 +94,7 @@ CONFIG_SCHEMA = remote_base.validate_triggers( | ||||
|                 esp32="10000b", | ||||
|                 esp8266="1000b", | ||||
|                 bk72xx="1000b", | ||||
|                 ln882x="1000b", | ||||
|                 rtl87xx="1000b", | ||||
|             ): cv.validate_bytes, | ||||
|             cv.Optional(CONF_FILTER, default="50us"): cv.All( | ||||
|   | ||||
| @@ -7,6 +7,7 @@ from esphome.const import ( | ||||
|     PLATFORM_BK72XX, | ||||
|     PLATFORM_ESP32, | ||||
|     PLATFORM_ESP8266, | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RP2040, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| @@ -33,6 +34,7 @@ CONFIG_SCHEMA = cv.All( | ||||
|             PLATFORM_ESP8266, | ||||
|             PLATFORM_RP2040, | ||||
|             PLATFORM_BK72XX, | ||||
|             PLATFORM_LN882X, | ||||
|             PLATFORM_RTL87XX, | ||||
|         ] | ||||
|     ), | ||||
|   | ||||
| @@ -16,6 +16,7 @@ CONFIG_SCHEMA = cv.Schema( | ||||
|             esp32=IMPLEMENTATION_BSD_SOCKETS, | ||||
|             rp2040=IMPLEMENTATION_LWIP_TCP, | ||||
|             bk72xx=IMPLEMENTATION_LWIP_SOCKETS, | ||||
|             ln882x=IMPLEMENTATION_LWIP_SOCKETS, | ||||
|             rtl87xx=IMPLEMENTATION_LWIP_SOCKETS, | ||||
|             host=IMPLEMENTATION_BSD_SOCKETS, | ||||
|         ): cv.one_of( | ||||
|   | ||||
| @@ -28,6 +28,7 @@ from esphome.const import ( | ||||
|     PLATFORM_BK72XX, | ||||
|     PLATFORM_ESP32, | ||||
|     PLATFORM_ESP8266, | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| @@ -174,7 +175,15 @@ CONFIG_SCHEMA = cv.All( | ||||
|             cv.Optional(CONF_SORTING_GROUPS): cv.ensure_list(sorting_group), | ||||
|         } | ||||
|     ).extend(cv.COMPONENT_SCHEMA), | ||||
|     cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]), | ||||
|     cv.only_on( | ||||
|         [ | ||||
|             PLATFORM_ESP32, | ||||
|             PLATFORM_ESP8266, | ||||
|             PLATFORM_BK72XX, | ||||
|             PLATFORM_LN882X, | ||||
|             PLATFORM_RTL87XX, | ||||
|         ] | ||||
|     ), | ||||
|     default_url, | ||||
|     validate_local, | ||||
|     validate_sorting_groups, | ||||
|   | ||||
| @@ -49,26 +49,69 @@ static const char *const HEADER_CORS_ALLOW_PNA = "Access-Control-Allow-Private-N | ||||
| UrlMatch match_url(const std::string &url, bool only_domain = false) { | ||||
|   UrlMatch match; | ||||
|   match.valid = false; | ||||
|   size_t domain_end = url.find('/', 1); | ||||
|   if (domain_end == std::string::npos) | ||||
|   match.domain = nullptr; | ||||
|   match.id = nullptr; | ||||
|   match.method = nullptr; | ||||
|   match.domain_len = 0; | ||||
|   match.id_len = 0; | ||||
|   match.method_len = 0; | ||||
|  | ||||
|   const char *url_ptr = url.c_str(); | ||||
|   size_t url_len = url.length(); | ||||
|  | ||||
|   // URL must start with '/' | ||||
|   if (url_len < 2 || url_ptr[0] != '/') | ||||
|     return match; | ||||
|   match.domain = url.substr(1, domain_end - 1); | ||||
|  | ||||
|   // Find domain | ||||
|   size_t domain_start = 1; | ||||
|   size_t domain_end = url.find('/', domain_start); | ||||
|  | ||||
|   if (domain_end == std::string::npos) { | ||||
|     // URL is just "/domain" | ||||
|     match.domain = url_ptr + domain_start; | ||||
|     match.domain_len = url_len - domain_start; | ||||
|     match.valid = true; | ||||
|     return match; | ||||
|   } | ||||
|  | ||||
|   // Set domain | ||||
|   match.domain = url_ptr + domain_start; | ||||
|   match.domain_len = domain_end - domain_start; | ||||
|  | ||||
|   if (only_domain) { | ||||
|     match.valid = true; | ||||
|     return match; | ||||
|   } | ||||
|   if (url.length() == domain_end - 1) | ||||
|  | ||||
|   // Check if there's anything after domain | ||||
|   if (url_len == domain_end + 1) | ||||
|     return match; | ||||
|  | ||||
|   // Find ID | ||||
|   size_t id_begin = domain_end + 1; | ||||
|   size_t id_end = url.find('/', id_begin); | ||||
|  | ||||
|   match.valid = true; | ||||
|  | ||||
|   if (id_end == std::string::npos) { | ||||
|     match.id = url.substr(id_begin, url.length() - id_begin); | ||||
|     // URL is "/domain/id" with no method | ||||
|     match.id = url_ptr + id_begin; | ||||
|     match.id_len = url_len - id_begin; | ||||
|     return match; | ||||
|   } | ||||
|   match.id = url.substr(id_begin, id_end - id_begin); | ||||
|  | ||||
|   // Set ID | ||||
|   match.id = url_ptr + id_begin; | ||||
|   match.id_len = id_end - id_begin; | ||||
|  | ||||
|   // Set method if present | ||||
|   size_t method_begin = id_end + 1; | ||||
|   match.method = url.substr(method_begin, url.length() - method_begin); | ||||
|   if (method_begin < url_len) { | ||||
|     match.method = url_ptr + method_begin; | ||||
|     match.method_len = url_len - method_begin; | ||||
|   } | ||||
|  | ||||
|   return match; | ||||
| } | ||||
|  | ||||
| @@ -388,9 +431,9 @@ void WebServer::on_sensor_update(sensor::Sensor *obj, float state) { | ||||
| } | ||||
| void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (sensor::Sensor *obj : App.get_sensors()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->sensor_json(obj, obj->state, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
| @@ -433,9 +476,9 @@ void WebServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::s | ||||
| } | ||||
| void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (text_sensor::TextSensor *obj : App.get_text_sensors()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->text_sensor_json(obj, obj->state, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
| @@ -471,20 +514,20 @@ void WebServer::on_switch_update(switch_::Switch *obj, bool state) { | ||||
| } | ||||
| void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (switch_::Switch *obj : App.get_switches()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->switch_json(obj, obj->state, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|     } else if (match.method == "toggle") { | ||||
|     } else if (match.method_equals("toggle")) { | ||||
|       this->schedule_([obj]() { obj->toggle(); }); | ||||
|       request->send(200); | ||||
|     } else if (match.method == "turn_on") { | ||||
|     } else if (match.method_equals("turn_on")) { | ||||
|       this->schedule_([obj]() { obj->turn_on(); }); | ||||
|       request->send(200); | ||||
|     } else if (match.method == "turn_off") { | ||||
|     } else if (match.method_equals("turn_off")) { | ||||
|       this->schedule_([obj]() { obj->turn_off(); }); | ||||
|       request->send(200); | ||||
|     } else { | ||||
| @@ -514,13 +557,13 @@ std::string WebServer::switch_json(switch_::Switch *obj, bool value, JsonDetail | ||||
| #ifdef USE_BUTTON | ||||
| void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (button::Button *obj : App.get_buttons()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->button_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|     } else if (match.method == "press") { | ||||
|     } else if (match.method_equals("press")) { | ||||
|       this->schedule_([obj]() { obj->press(); }); | ||||
|       request->send(200); | ||||
|       return; | ||||
| @@ -555,9 +598,9 @@ void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj) { | ||||
| } | ||||
| void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (binary_sensor::BinarySensor *obj : App.get_binary_sensors()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->binary_sensor_json(obj, obj->state, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
| @@ -593,18 +636,18 @@ void WebServer::on_fan_update(fan::Fan *obj) { | ||||
| } | ||||
| void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (fan::Fan *obj : App.get_fans()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->fan_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|     } else if (match.method == "toggle") { | ||||
|     } else if (match.method_equals("toggle")) { | ||||
|       this->schedule_([obj]() { obj->toggle().perform(); }); | ||||
|       request->send(200); | ||||
|     } else if (match.method == "turn_on" || match.method == "turn_off") { | ||||
|       auto call = match.method == "turn_on" ? obj->turn_on() : obj->turn_off(); | ||||
|     } else if (match.method_equals("turn_on") || match.method_equals("turn_off")) { | ||||
|       auto call = match.method_equals("turn_on") ? obj->turn_on() : obj->turn_off(); | ||||
|  | ||||
|       if (request->hasParam("speed_level")) { | ||||
|         auto speed_level = request->getParam("speed_level")->value(); | ||||
| @@ -674,17 +717,17 @@ void WebServer::on_light_update(light::LightState *obj) { | ||||
| } | ||||
| void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (light::LightState *obj : App.get_lights()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->light_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|     } else if (match.method == "toggle") { | ||||
|     } else if (match.method_equals("toggle")) { | ||||
|       this->schedule_([obj]() { obj->toggle().perform(); }); | ||||
|       request->send(200); | ||||
|     } else if (match.method == "turn_on") { | ||||
|     } else if (match.method_equals("turn_on")) { | ||||
|       auto call = obj->turn_on(); | ||||
|       if (request->hasParam("brightness")) { | ||||
|         auto brightness = parse_number<float>(request->getParam("brightness")->value().c_str()); | ||||
| @@ -741,7 +784,7 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa | ||||
|  | ||||
|       this->schedule_([call]() mutable { call.perform(); }); | ||||
|       request->send(200); | ||||
|     } else if (match.method == "turn_off") { | ||||
|     } else if (match.method_equals("turn_off")) { | ||||
|       auto call = obj->turn_off(); | ||||
|       if (request->hasParam("transition")) { | ||||
|         auto transition = parse_number<uint32_t>(request->getParam("transition")->value().c_str()); | ||||
| @@ -790,10 +833,10 @@ void WebServer::on_cover_update(cover::Cover *obj) { | ||||
| } | ||||
| void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (cover::Cover *obj : App.get_covers()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->cover_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
| @@ -801,15 +844,15 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa | ||||
|     } | ||||
|  | ||||
|     auto call = obj->make_call(); | ||||
|     if (match.method == "open") { | ||||
|     if (match.method_equals("open")) { | ||||
|       call.set_command_open(); | ||||
|     } else if (match.method == "close") { | ||||
|     } else if (match.method_equals("close")) { | ||||
|       call.set_command_close(); | ||||
|     } else if (match.method == "stop") { | ||||
|     } else if (match.method_equals("stop")) { | ||||
|       call.set_command_stop(); | ||||
|     } else if (match.method == "toggle") { | ||||
|     } else if (match.method_equals("toggle")) { | ||||
|       call.set_command_toggle(); | ||||
|     } else if (match.method != "set") { | ||||
|     } else if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -871,16 +914,16 @@ void WebServer::on_number_update(number::Number *obj, float state) { | ||||
| } | ||||
| void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (auto *obj : App.get_numbers()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->number_json(obj, obj->state, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|       return; | ||||
|     } | ||||
|     if (match.method != "set") { | ||||
|     if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -942,15 +985,15 @@ void WebServer::on_date_update(datetime::DateEntity *obj) { | ||||
| } | ||||
| void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (auto *obj : App.get_dates()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->date_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|       return; | ||||
|     } | ||||
|     if (match.method != "set") { | ||||
|     if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -1001,15 +1044,15 @@ void WebServer::on_time_update(datetime::TimeEntity *obj) { | ||||
| } | ||||
| void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (auto *obj : App.get_times()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->time_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|       return; | ||||
|     } | ||||
|     if (match.method != "set") { | ||||
|     if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -1059,15 +1102,15 @@ void WebServer::on_datetime_update(datetime::DateTimeEntity *obj) { | ||||
| } | ||||
| void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (auto *obj : App.get_datetimes()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->datetime_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|       return; | ||||
|     } | ||||
|     if (match.method != "set") { | ||||
|     if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -1118,16 +1161,16 @@ void WebServer::on_text_update(text::Text *obj, const std::string &state) { | ||||
| } | ||||
| void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (auto *obj : App.get_texts()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->text_json(obj, obj->state, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|       return; | ||||
|     } | ||||
|     if (match.method != "set") { | ||||
|     if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -1179,17 +1222,17 @@ void WebServer::on_select_update(select::Select *obj, const std::string &state, | ||||
| } | ||||
| void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (auto *obj : App.get_selects()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->select_json(obj, obj->state, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (match.method != "set") { | ||||
|     if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -1238,17 +1281,17 @@ void WebServer::on_climate_update(climate::Climate *obj) { | ||||
| } | ||||
| void WebServer::handle_climate_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (auto *obj : App.get_climates()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->climate_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (match.method != "set") { | ||||
|     if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -1397,20 +1440,20 @@ void WebServer::on_lock_update(lock::Lock *obj) { | ||||
| } | ||||
| void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (lock::Lock *obj : App.get_locks()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->lock_json(obj, obj->state, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|     } else if (match.method == "lock") { | ||||
|     } else if (match.method_equals("lock")) { | ||||
|       this->schedule_([obj]() { obj->lock(); }); | ||||
|       request->send(200); | ||||
|     } else if (match.method == "unlock") { | ||||
|     } else if (match.method_equals("unlock")) { | ||||
|       this->schedule_([obj]() { obj->unlock(); }); | ||||
|       request->send(200); | ||||
|     } else if (match.method == "open") { | ||||
|     } else if (match.method_equals("open")) { | ||||
|       this->schedule_([obj]() { obj->open(); }); | ||||
|       request->send(200); | ||||
|     } else { | ||||
| @@ -1445,10 +1488,10 @@ void WebServer::on_valve_update(valve::Valve *obj) { | ||||
| } | ||||
| void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (valve::Valve *obj : App.get_valves()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->valve_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
| @@ -1456,15 +1499,15 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa | ||||
|     } | ||||
|  | ||||
|     auto call = obj->make_call(); | ||||
|     if (match.method == "open") { | ||||
|     if (match.method_equals("open")) { | ||||
|       call.set_command_open(); | ||||
|     } else if (match.method == "close") { | ||||
|     } else if (match.method_equals("close")) { | ||||
|       call.set_command_close(); | ||||
|     } else if (match.method == "stop") { | ||||
|     } else if (match.method_equals("stop")) { | ||||
|       call.set_command_stop(); | ||||
|     } else if (match.method == "toggle") { | ||||
|     } else if (match.method_equals("toggle")) { | ||||
|       call.set_command_toggle(); | ||||
|     } else if (match.method != "set") { | ||||
|     } else if (!match.method_equals("set")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -1517,10 +1560,10 @@ void WebServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlP | ||||
| } | ||||
| void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (alarm_control_panel::AlarmControlPanel *obj : App.get_alarm_control_panels()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->alarm_control_panel_json(obj, obj->get_state(), detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
| @@ -1532,15 +1575,15 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques | ||||
|       call.set_code(request->getParam("code")->value().c_str());  // NOLINT | ||||
|     } | ||||
|  | ||||
|     if (match.method == "disarm") { | ||||
|     if (match.method_equals("disarm")) { | ||||
|       call.disarm(); | ||||
|     } else if (match.method == "arm_away") { | ||||
|     } else if (match.method_equals("arm_away")) { | ||||
|       call.arm_away(); | ||||
|     } else if (match.method == "arm_home") { | ||||
|     } else if (match.method_equals("arm_home")) { | ||||
|       call.arm_home(); | ||||
|     } else if (match.method == "arm_night") { | ||||
|     } else if (match.method_equals("arm_night")) { | ||||
|       call.arm_night(); | ||||
|     } else if (match.method == "arm_vacation") { | ||||
|     } else if (match.method_equals("arm_vacation")) { | ||||
|       call.arm_vacation(); | ||||
|     } else { | ||||
|       request->send(404); | ||||
| @@ -1584,10 +1627,10 @@ void WebServer::on_event(event::Event *obj, const std::string &event_type) { | ||||
|  | ||||
| void WebServer::handle_event_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (event::Event *obj : App.get_events()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->event_json(obj, "", detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
| @@ -1633,17 +1676,17 @@ void WebServer::on_update(update::UpdateEntity *obj) { | ||||
| } | ||||
| void WebServer::handle_update_request(AsyncWebServerRequest *request, const UrlMatch &match) { | ||||
|   for (update::UpdateEntity *obj : App.get_updates()) { | ||||
|     if (obj->get_object_id() != match.id) | ||||
|     if (!match.id_equals(obj->get_object_id())) | ||||
|       continue; | ||||
|  | ||||
|     if (request->method() == HTTP_GET && match.method.empty()) { | ||||
|     if (request->method() == HTTP_GET && match.method_empty()) { | ||||
|       auto detail = get_request_detail(request); | ||||
|       std::string data = this->update_json(obj, detail); | ||||
|       request->send(200, "application/json", data.c_str()); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (match.method != "install") { | ||||
|     if (!match.method_equals("install")) { | ||||
|       request->send(404); | ||||
|       return; | ||||
|     } | ||||
| @@ -1719,102 +1762,102 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) const { | ||||
|   if (!match.valid) | ||||
|     return false; | ||||
| #ifdef USE_SENSOR | ||||
|   if (request->method() == HTTP_GET && match.domain == "sensor") | ||||
|   if (request->method() == HTTP_GET && match.domain_equals("sensor")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_SWITCH | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "switch") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("switch")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_BUTTON | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "button") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("button")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_BINARY_SENSOR | ||||
|   if (request->method() == HTTP_GET && match.domain == "binary_sensor") | ||||
|   if (request->method() == HTTP_GET && match.domain_equals("binary_sensor")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_FAN | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "fan") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("fan")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_LIGHT | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "light") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("light")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_TEXT_SENSOR | ||||
|   if (request->method() == HTTP_GET && match.domain == "text_sensor") | ||||
|   if (request->method() == HTTP_GET && match.domain_equals("text_sensor")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_COVER | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "cover") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("cover")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_NUMBER | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "number") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("number")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_DATETIME_DATE | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "date") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("date")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_DATETIME_TIME | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "time") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("time")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_DATETIME_DATETIME | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "datetime") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("datetime")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_TEXT | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "text") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("text")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_SELECT | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "select") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("select")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_CLIMATE | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "climate") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("climate")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_LOCK | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "lock") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("lock")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_VALVE | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "valve") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("valve")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_ALARM_CONTROL_PANEL | ||||
|   if ((request->method() == HTTP_GET || request->method() == HTTP_POST) && match.domain == "alarm_control_panel") | ||||
|   if ((request->method() == HTTP_GET || request->method() == HTTP_POST) && match.domain_equals("alarm_control_panel")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_EVENT | ||||
|   if (request->method() == HTTP_GET && match.domain == "event") | ||||
|   if (request->method() == HTTP_GET && match.domain_equals("event")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_UPDATE | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "update") | ||||
|   if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("update")) | ||||
|     return true; | ||||
| #endif | ||||
|  | ||||
| @@ -1856,112 +1899,112 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { | ||||
|  | ||||
|   UrlMatch match = match_url(request->url().c_str());  // NOLINT | ||||
| #ifdef USE_SENSOR | ||||
|   if (match.domain == "sensor") { | ||||
|   if (match.domain_equals("sensor")) { | ||||
|     this->handle_sensor_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_SWITCH | ||||
|   if (match.domain == "switch") { | ||||
|   if (match.domain_equals("switch")) { | ||||
|     this->handle_switch_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_BUTTON | ||||
|   if (match.domain == "button") { | ||||
|   if (match.domain_equals("button")) { | ||||
|     this->handle_button_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_BINARY_SENSOR | ||||
|   if (match.domain == "binary_sensor") { | ||||
|   if (match.domain_equals("binary_sensor")) { | ||||
|     this->handle_binary_sensor_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_FAN | ||||
|   if (match.domain == "fan") { | ||||
|   if (match.domain_equals("fan")) { | ||||
|     this->handle_fan_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_LIGHT | ||||
|   if (match.domain == "light") { | ||||
|   if (match.domain_equals("light")) { | ||||
|     this->handle_light_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_TEXT_SENSOR | ||||
|   if (match.domain == "text_sensor") { | ||||
|   if (match.domain_equals("text_sensor")) { | ||||
|     this->handle_text_sensor_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_COVER | ||||
|   if (match.domain == "cover") { | ||||
|   if (match.domain_equals("cover")) { | ||||
|     this->handle_cover_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_NUMBER | ||||
|   if (match.domain == "number") { | ||||
|   if (match.domain_equals("number")) { | ||||
|     this->handle_number_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_DATETIME_DATE | ||||
|   if (match.domain == "date") { | ||||
|   if (match.domain_equals("date")) { | ||||
|     this->handle_date_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_DATETIME_TIME | ||||
|   if (match.domain == "time") { | ||||
|   if (match.domain_equals("time")) { | ||||
|     this->handle_time_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_DATETIME_DATETIME | ||||
|   if (match.domain == "datetime") { | ||||
|   if (match.domain_equals("datetime")) { | ||||
|     this->handle_datetime_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_TEXT | ||||
|   if (match.domain == "text") { | ||||
|   if (match.domain_equals("text")) { | ||||
|     this->handle_text_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_SELECT | ||||
|   if (match.domain == "select") { | ||||
|   if (match.domain_equals("select")) { | ||||
|     this->handle_select_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_CLIMATE | ||||
|   if (match.domain == "climate") { | ||||
|   if (match.domain_equals("climate")) { | ||||
|     this->handle_climate_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_LOCK | ||||
|   if (match.domain == "lock") { | ||||
|   if (match.domain_equals("lock")) { | ||||
|     this->handle_lock_request(request, match); | ||||
|  | ||||
|     return; | ||||
| @@ -1969,14 +2012,14 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_VALVE | ||||
|   if (match.domain == "valve") { | ||||
|   if (match.domain_equals("valve")) { | ||||
|     this->handle_valve_request(request, match); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_ALARM_CONTROL_PANEL | ||||
|   if (match.domain == "alarm_control_panel") { | ||||
|   if (match.domain_equals("alarm_control_panel")) { | ||||
|     this->handle_alarm_control_panel_request(request, match); | ||||
|  | ||||
|     return; | ||||
| @@ -1984,7 +2027,7 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) { | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_UPDATE | ||||
|   if (match.domain == "update") { | ||||
|   if (match.domain_equals("update")) { | ||||
|     this->handle_update_request(request, match); | ||||
|     return; | ||||
|   } | ||||
|   | ||||
| @@ -40,10 +40,28 @@ namespace web_server { | ||||
|  | ||||
| /// Internal helper struct that is used to parse incoming URLs | ||||
| struct UrlMatch { | ||||
|   std::string domain;  ///< The domain of the component, for example "sensor" | ||||
|   std::string id;      ///< The id of the device that's being accessed, for example "living_room_fan" | ||||
|   std::string method;  ///< The method that's being called, for example "turn_on" | ||||
|   const char *domain;  ///< Pointer to domain within URL, for example "sensor" | ||||
|   const char *id;      ///< Pointer to id within URL, for example "living_room_fan" | ||||
|   const char *method;  ///< Pointer to method within URL, for example "turn_on" | ||||
|   uint8_t domain_len;  ///< Length of domain string | ||||
|   uint8_t id_len;      ///< Length of id string | ||||
|   uint8_t method_len;  ///< Length of method string | ||||
|   bool valid;          ///< Whether this match is valid | ||||
|  | ||||
|   // Helper methods for string comparisons | ||||
|   bool domain_equals(const char *str) const { | ||||
|     return domain && domain_len == strlen(str) && memcmp(domain, str, domain_len) == 0; | ||||
|   } | ||||
|  | ||||
|   bool id_equals(const std::string &str) const { | ||||
|     return id && id_len == str.length() && memcmp(id, str.c_str(), id_len) == 0; | ||||
|   } | ||||
|  | ||||
|   bool method_equals(const char *str) const { | ||||
|     return method && method_len == strlen(str) && memcmp(method, str, method_len) == 0; | ||||
|   } | ||||
|  | ||||
|   bool method_empty() const { return method_len == 0; } | ||||
| }; | ||||
|  | ||||
| #ifdef USE_WEBSERVER_SORTING | ||||
|   | ||||
| @@ -309,6 +309,7 @@ CONFIG_SCHEMA = cv.All( | ||||
|                 rp2040="light", | ||||
|                 bk72xx="none", | ||||
|                 rtl87xx="none", | ||||
|                 ln882x="light", | ||||
|             ): cv.enum(WIFI_POWER_SAVE_MODES, upper=True), | ||||
|             cv.Optional(CONF_FAST_CONNECT, default=False): cv.boolean, | ||||
|             cv.Optional(CONF_USE_ADDRESS): cv.string_strict, | ||||
|   | ||||
| @@ -12,6 +12,7 @@ PLATFORM_ESP32 = "esp32" | ||||
| PLATFORM_ESP8266 = "esp8266" | ||||
| PLATFORM_HOST = "host" | ||||
| PLATFORM_LIBRETINY_OLDSTYLE = "libretiny" | ||||
| PLATFORM_LN882X = "ln882x" | ||||
| PLATFORM_RP2040 = "rp2040" | ||||
| PLATFORM_RTL87XX = "rtl87xx" | ||||
|  | ||||
|   | ||||
| @@ -20,6 +20,7 @@ from esphome.const import ( | ||||
|     PLATFORM_ESP32, | ||||
|     PLATFORM_ESP8266, | ||||
|     PLATFORM_HOST, | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RP2040, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| @@ -661,9 +662,13 @@ class EsphomeCore: | ||||
|     def is_rtl87xx(self): | ||||
|         return self.target_platform == PLATFORM_RTL87XX | ||||
|  | ||||
|     @property | ||||
|     def is_ln882x(self): | ||||
|         return self.target_platform == PLATFORM_LN882X | ||||
|  | ||||
|     @property | ||||
|     def is_libretiny(self): | ||||
|         return self.is_bk72xx or self.is_rtl87xx | ||||
|         return self.is_bk72xx or self.is_rtl87xx or self.is_ln882x | ||||
|  | ||||
|     @property | ||||
|     def is_host(self): | ||||
|   | ||||
| @@ -639,7 +639,11 @@ class DownloadListRequestHandler(BaseHandler): | ||||
|  | ||||
|         if platform.upper() in ESP32_VARIANTS: | ||||
|             platform = "esp32" | ||||
|         elif platform in (const.PLATFORM_RTL87XX, const.PLATFORM_BK72XX): | ||||
|         elif platform in ( | ||||
|             const.PLATFORM_RTL87XX, | ||||
|             const.PLATFORM_BK72XX, | ||||
|             const.PLATFORM_LN882X, | ||||
|         ): | ||||
|             platform = "libretiny" | ||||
|  | ||||
|         try: | ||||
| @@ -837,6 +841,10 @@ class BoardsRequestHandler(BaseHandler): | ||||
|             from esphome.components.bk72xx.boards import BOARDS as BK72XX_BOARDS | ||||
|  | ||||
|             boards = BK72XX_BOARDS | ||||
|         elif platform == const.PLATFORM_LN882X: | ||||
|             from esphome.components.ln882x.boards import BOARDS as LN882X_BOARDS | ||||
|  | ||||
|             boards = LN882X_BOARDS | ||||
|         elif platform == const.PLATFORM_RTL87XX: | ||||
|             from esphome.components.rtl87xx.boards import BOARDS as RTL87XX_BOARDS | ||||
|  | ||||
|   | ||||
| @@ -83,6 +83,11 @@ bk72xx: | ||||
|   board: {board} | ||||
| """ | ||||
|  | ||||
| LN882X_CONFIG = """ | ||||
| ln882x: | ||||
|   board: {board} | ||||
| """ | ||||
|  | ||||
| RTL87XX_CONFIG = """ | ||||
| rtl87xx: | ||||
|   board: {board} | ||||
| @@ -93,6 +98,7 @@ HARDWARE_BASE_CONFIGS = { | ||||
|     "ESP32": ESP32_CONFIG, | ||||
|     "RP2040": RP2040_CONFIG, | ||||
|     "BK72XX": BK72XX_CONFIG, | ||||
|     "LN882X": LN882X_CONFIG, | ||||
|     "RTL87XX": RTL87XX_CONFIG, | ||||
| } | ||||
|  | ||||
| @@ -157,7 +163,7 @@ def wizard_file(**kwargs): | ||||
| """ | ||||
|  | ||||
|     # pylint: disable=consider-using-f-string | ||||
|     if kwargs["platform"] in ["ESP8266", "ESP32", "BK72XX", "RTL87XX"]: | ||||
|     if kwargs["platform"] in ["ESP8266", "ESP32", "BK72XX", "LN882X", "RTL87XX"]: | ||||
|         config += """ | ||||
|   # Enable fallback hotspot (captive portal) in case wifi connection fails | ||||
|   ap: | ||||
| @@ -181,6 +187,7 @@ def wizard_write(path, **kwargs): | ||||
|     from esphome.components.bk72xx import boards as bk72xx_boards | ||||
|     from esphome.components.esp32 import boards as esp32_boards | ||||
|     from esphome.components.esp8266 import boards as esp8266_boards | ||||
|     from esphome.components.ln882x import boards as ln882x_boards | ||||
|     from esphome.components.rp2040 import boards as rp2040_boards | ||||
|     from esphome.components.rtl87xx import boards as rtl87xx_boards | ||||
|  | ||||
| @@ -200,6 +207,8 @@ def wizard_write(path, **kwargs): | ||||
|             platform = "RP2040" | ||||
|         elif board in bk72xx_boards.BOARDS: | ||||
|             platform = "BK72XX" | ||||
|         elif board in ln882x_boards.BOARDS: | ||||
|             platform = "LN882X" | ||||
|         elif board in rtl87xx_boards.BOARDS: | ||||
|             platform = "RTL87XX" | ||||
|         else: | ||||
| @@ -253,6 +262,7 @@ def wizard(path): | ||||
|     from esphome.components.bk72xx import boards as bk72xx_boards | ||||
|     from esphome.components.esp32 import boards as esp32_boards | ||||
|     from esphome.components.esp8266 import boards as esp8266_boards | ||||
|     from esphome.components.ln882x import boards as ln882x_boards | ||||
|     from esphome.components.rp2040 import boards as rp2040_boards | ||||
|     from esphome.components.rtl87xx import boards as rtl87xx_boards | ||||
|  | ||||
| @@ -325,7 +335,7 @@ def wizard(path): | ||||
|         "firmwares for it." | ||||
|     ) | ||||
|  | ||||
|     wizard_platforms = ["ESP32", "ESP8266", "BK72XX", "RTL87XX", "RP2040"] | ||||
|     wizard_platforms = ["ESP32", "ESP8266", "BK72XX", "LN882X", "RTL87XX", "RP2040"] | ||||
|     safe_print( | ||||
|         "Please choose one of the supported microcontrollers " | ||||
|         "(Use ESP8266 for Sonoff devices)." | ||||
| @@ -361,7 +371,7 @@ def wizard(path): | ||||
|         board_link = ( | ||||
|             "https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html" | ||||
|         ) | ||||
|     elif platform in ["BK72XX", "RTL87XX"]: | ||||
|     elif platform in ["BK72XX", "LN882X", "RTL87XX"]: | ||||
|         board_link = "https://docs.libretiny.eu/docs/status/supported/" | ||||
|     else: | ||||
|         raise NotImplementedError("Unknown platform!") | ||||
| @@ -384,6 +394,9 @@ def wizard(path): | ||||
|     elif platform == "BK72XX": | ||||
|         safe_print(f'For example "{color(AnsiFore.BOLD_WHITE, "cb2s")}".') | ||||
|         boards_list = bk72xx_boards.BOARDS.items() | ||||
|     elif platform == "LN882X": | ||||
|         safe_print(f'For example "{color(AnsiFore.BOLD_WHITE, "wl2s")}".') | ||||
|         boards_list = ln882x_boards.BOARDS.items() | ||||
|     elif platform == "RTL87XX": | ||||
|         safe_print(f'For example "{color(AnsiFore.BOLD_WHITE, "wr3")}".') | ||||
|         boards_list = rtl87xx_boards.BOARDS.items() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user