mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'integration' into memory_api
This commit is contained in:
		| @@ -391,8 +391,7 @@ async def build_action(full_config, template_arg, args): | |||||||
|     ) |     ) | ||||||
|     action_id = full_config[CONF_TYPE_ID] |     action_id = full_config[CONF_TYPE_ID] | ||||||
|     builder = registry_entry.coroutine_fun |     builder = registry_entry.coroutine_fun | ||||||
|     ret = await builder(config, action_id, template_arg, args) |     return await builder(config, action_id, template_arg, args) | ||||||
|     return ret |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def build_action_list(config, templ, arg_type): | async def build_action_list(config, templ, arg_type): | ||||||
| @@ -409,8 +408,7 @@ async def build_condition(full_config, template_arg, args): | |||||||
|     ) |     ) | ||||||
|     action_id = full_config[CONF_TYPE_ID] |     action_id = full_config[CONF_TYPE_ID] | ||||||
|     builder = registry_entry.coroutine_fun |     builder = registry_entry.coroutine_fun | ||||||
|     ret = await builder(config, action_id, template_arg, args) |     return await builder(config, action_id, template_arg, args) | ||||||
|     return ret |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def build_condition_list(config, templ, args): | async def build_condition_list(config, templ, args): | ||||||
|   | |||||||
| @@ -301,8 +301,7 @@ async def alarm_action_disarm_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def alarm_action_pending_to_code(config, action_id, template_arg, args): | async def alarm_action_pending_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -310,8 +309,7 @@ async def alarm_action_pending_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def alarm_action_trigger_to_code(config, action_id, template_arg, args): | async def alarm_action_trigger_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -319,8 +317,7 @@ async def alarm_action_trigger_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def alarm_action_chime_to_code(config, action_id, template_arg, args): | async def alarm_action_chime_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -333,8 +330,7 @@ async def alarm_action_chime_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def alarm_action_ready_to_code(config, action_id, template_arg, args): | async def alarm_action_ready_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_condition( | @automation.register_condition( | ||||||
|   | |||||||
| @@ -175,8 +175,7 @@ BLE_REMOVE_BOND_ACTION_SCHEMA = cv.Schema( | |||||||
| ) | ) | ||||||
| async def ble_disconnect_to_code(config, action_id, template_arg, args): | async def ble_disconnect_to_code(config, action_id, template_arg, args): | ||||||
|     parent = await cg.get_variable(config[CONF_ID]) |     parent = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, parent) |     return cg.new_Pvariable(action_id, template_arg, parent) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -184,8 +183,7 @@ async def ble_disconnect_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def ble_connect_to_code(config, action_id, template_arg, args): | async def ble_connect_to_code(config, action_id, template_arg, args): | ||||||
|     parent = await cg.get_variable(config[CONF_ID]) |     parent = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, parent) |     return cg.new_Pvariable(action_id, template_arg, parent) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -282,9 +280,7 @@ async def passkey_reply_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def remove_bond_to_code(config, action_id, template_arg, args): | async def remove_bond_to_code(config, action_id, template_arg, args): | ||||||
|     parent = await cg.get_variable(config[CONF_ID]) |     parent = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, parent) |     return cg.new_Pvariable(action_id, template_arg, parent) | ||||||
|  |  | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|   | |||||||
| @@ -892,7 +892,7 @@ def get_arduino_partition_csv(flash_size): | |||||||
|     eeprom_partition_start = app1_partition_start + app_partition_size |     eeprom_partition_start = app1_partition_start + app_partition_size | ||||||
|     spiffs_partition_start = eeprom_partition_start + eeprom_partition_size |     spiffs_partition_start = eeprom_partition_start + eeprom_partition_size | ||||||
|  |  | ||||||
|     partition_csv = f"""\ |     return f"""\ | ||||||
| nvs,      data, nvs,     0x9000, 0x5000, | nvs,      data, nvs,     0x9000, 0x5000, | ||||||
| otadata,  data, ota,     0xE000, 0x2000, | otadata,  data, ota,     0xE000, 0x2000, | ||||||
| app0,     app,  ota_0,   0x{app0_partition_start:X}, 0x{app_partition_size:X}, | app0,     app,  ota_0,   0x{app0_partition_start:X}, 0x{app_partition_size:X}, | ||||||
| @@ -900,20 +900,18 @@ app1,     app,  ota_1,   0x{app1_partition_start:X}, 0x{app_partition_size:X}, | |||||||
| eeprom,   data, 0x99,    0x{eeprom_partition_start:X}, 0x{eeprom_partition_size:X}, | eeprom,   data, 0x99,    0x{eeprom_partition_start:X}, 0x{eeprom_partition_size:X}, | ||||||
| spiffs,   data, spiffs,  0x{spiffs_partition_start:X}, 0x{spiffs_partition_size:X} | spiffs,   data, spiffs,  0x{spiffs_partition_start:X}, 0x{spiffs_partition_size:X} | ||||||
| """ | """ | ||||||
|     return partition_csv |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_idf_partition_csv(flash_size): | def get_idf_partition_csv(flash_size): | ||||||
|     app_partition_size = APP_PARTITION_SIZES[flash_size] |     app_partition_size = APP_PARTITION_SIZES[flash_size] | ||||||
|  |  | ||||||
|     partition_csv = f"""\ |     return f"""\ | ||||||
| otadata,  data, ota,     ,        0x2000, | otadata,  data, ota,     ,        0x2000, | ||||||
| phy_init, data, phy,     ,        0x1000, | phy_init, data, phy,     ,        0x1000, | ||||||
| app0,     app,  ota_0,   ,        0x{app_partition_size:X}, | app0,     app,  ota_0,   ,        0x{app_partition_size:X}, | ||||||
| app1,     app,  ota_1,   ,        0x{app_partition_size:X}, | app1,     app,  ota_1,   ,        0x{app_partition_size:X}, | ||||||
| nvs,      data, nvs,     ,        0x6D000, | nvs,      data, nvs,     ,        0x6D000, | ||||||
| """ | """ | ||||||
|     return partition_csv |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def _format_sdkconfig_val(value: SdkconfigValueType) -> str: | def _format_sdkconfig_val(value: SdkconfigValueType) -> str: | ||||||
|   | |||||||
| @@ -187,8 +187,7 @@ def validate_supports(value): | |||||||
|             "Open-drain only works with output mode", [CONF_MODE, CONF_OPEN_DRAIN] |             "Open-drain only works with output mode", [CONF_MODE, CONF_OPEN_DRAIN] | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|     value = _esp32_validations[variant].usage_validation(value) |     return _esp32_validations[variant].usage_validation(value) | ||||||
|     return value |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # https://docs.espressif.com/projects/esp-idf/en/v3.3.5/api-reference/peripherals/gpio.html#_CPPv416gpio_drive_cap_t | # https://docs.espressif.com/projects/esp-idf/en/v3.3.5/api-reference/peripherals/gpio.html#_CPPv416gpio_drive_cap_t | ||||||
|   | |||||||
| @@ -628,5 +628,4 @@ async def ble_server_descriptor_set_value(config, action_id, template_arg, args) | |||||||
| ) | ) | ||||||
| async def ble_server_characteristic_notify(config, action_id, template_arg, args): | async def ble_server_characteristic_notify(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|   | |||||||
| @@ -330,8 +330,7 @@ HAIER_HON_BASE_ACTION_SCHEMA = automation.maybe_simple_id( | |||||||
| ) | ) | ||||||
| async def display_action_to_code(config, action_id, template_arg, args): | async def display_action_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -342,8 +341,7 @@ async def display_action_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def beeper_action_to_code(config, action_id, template_arg, args): | async def beeper_action_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Start self cleaning or steri-cleaning action action | # Start self cleaning or steri-cleaning action action | ||||||
| @@ -359,8 +357,7 @@ async def beeper_action_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def start_cleaning_to_code(config, action_id, template_arg, args): | async def start_cleaning_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Set vertical airflow direction action | # Set vertical airflow direction action | ||||||
| @@ -417,8 +414,7 @@ async def haier_set_horizontal_airflow_to_code(config, action_id, template_arg, | |||||||
| ) | ) | ||||||
| async def health_action_to_code(config, action_id, template_arg, args): | async def health_action_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -432,8 +428,7 @@ async def health_action_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def power_action_to_code(config, action_id, template_arg, args): | async def power_action_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def _final_validate(config): | def _final_validate(config): | ||||||
|   | |||||||
| @@ -353,10 +353,9 @@ async def addressable_lambda_effect_to_code(config, effect_id): | |||||||
|         (bool, "initial_run"), |         (bool, "initial_run"), | ||||||
|     ] |     ] | ||||||
|     lambda_ = await cg.process_lambda(config[CONF_LAMBDA], args, return_type=cg.void) |     lambda_ = await cg.process_lambda(config[CONF_LAMBDA], args, return_type=cg.void) | ||||||
|     var = cg.new_Pvariable( |     return cg.new_Pvariable( | ||||||
|         effect_id, config[CONF_NAME], lambda_, config[CONF_UPDATE_INTERVAL] |         effect_id, config[CONF_NAME], lambda_, config[CONF_UPDATE_INTERVAL] | ||||||
|     ) |     ) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @register_addressable_effect( | @register_addressable_effect( | ||||||
|   | |||||||
| @@ -85,8 +85,7 @@ async def action_to_code( | |||||||
|     async with LambdaContext(parameters=args, where=action_id) as context: |     async with LambdaContext(parameters=args, where=action_id) as context: | ||||||
|         for widget in widgets: |         for widget in widgets: | ||||||
|             await action(widget) |             await action(widget) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) |     return cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def update_to_code(config, action_id, template_arg, args): | async def update_to_code(config, action_id, template_arg, args): | ||||||
| @@ -354,8 +353,7 @@ async def widget_focus(config, action_id, template_arg, args): | |||||||
|  |  | ||||||
|         if config[CONF_FREEZE]: |         if config[CONF_FREEZE]: | ||||||
|             lv.group_focus_freeze(group, True) |             lv.group_focus_freeze(group, True) | ||||||
|         var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) |         return cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) | ||||||
|         return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
|   | |||||||
| @@ -271,8 +271,7 @@ padding = LValidator(padding_validator, int32, retmapper=literal) | |||||||
|  |  | ||||||
|  |  | ||||||
| def zoom_validator(value): | def zoom_validator(value): | ||||||
|     value = cv.float_range(0.1, 10.0)(value) |     return cv.float_range(0.1, 10.0)(value) | ||||||
|     return value |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def zoom_retmapper(value): | def zoom_retmapper(value): | ||||||
|   | |||||||
| @@ -66,8 +66,7 @@ async def style_update_to_code(config, action_id, template_arg, args): | |||||||
|     async with LambdaContext(parameters=args, where=action_id) as context: |     async with LambdaContext(parameters=args, where=action_id) as context: | ||||||
|         await style_set(style, config) |         await style_set(style, config) | ||||||
|  |  | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) |     return cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def theme_to_code(config): | async def theme_to_code(config): | ||||||
|   | |||||||
| @@ -189,7 +189,7 @@ class Widget: | |||||||
|         for matrix buttons |         for matrix buttons | ||||||
|         :return: |         :return: | ||||||
|         """ |         """ | ||||||
|         return None |         return | ||||||
|  |  | ||||||
|     def get_max(self): |     def get_max(self): | ||||||
|         return self.type.get_max(self.config) |         return self.type.get_max(self.config) | ||||||
|   | |||||||
| @@ -193,7 +193,7 @@ class ButtonMatrixType(WidgetType): | |||||||
|     async def to_code(self, w: Widget, config): |     async def to_code(self, w: Widget, config): | ||||||
|         lvgl_components_required.add("BUTTONMATRIX") |         lvgl_components_required.add("BUTTONMATRIX") | ||||||
|         if CONF_ROWS not in config: |         if CONF_ROWS not in config: | ||||||
|             return [] |             return | ||||||
|         text_list, ctrl_list, width_list, key_list = await get_button_data( |         text_list, ctrl_list, width_list, key_list = await get_button_data( | ||||||
|             config[CONF_ROWS], w |             config[CONF_ROWS], w | ||||||
|         ) |         ) | ||||||
|   | |||||||
| @@ -312,14 +312,13 @@ CONFIG_SCHEMA = cv.All( | |||||||
| def exp_mqtt_message(config): | def exp_mqtt_message(config): | ||||||
|     if config is None: |     if config is None: | ||||||
|         return cg.optional(cg.TemplateArguments(MQTTMessage)) |         return cg.optional(cg.TemplateArguments(MQTTMessage)) | ||||||
|     exp = cg.StructInitializer( |     return cg.StructInitializer( | ||||||
|         MQTTMessage, |         MQTTMessage, | ||||||
|         ("topic", config[CONF_TOPIC]), |         ("topic", config[CONF_TOPIC]), | ||||||
|         ("payload", config.get(CONF_PAYLOAD, "")), |         ("payload", config.get(CONF_PAYLOAD, "")), | ||||||
|         ("qos", config[CONF_QOS]), |         ("qos", config[CONF_QOS]), | ||||||
|         ("retain", config[CONF_RETAIN]), |         ("retain", config[CONF_RETAIN]), | ||||||
|     ) |     ) | ||||||
|     return exp |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @coroutine_with_priority(40.0) | @coroutine_with_priority(40.0) | ||||||
|   | |||||||
| @@ -18,13 +18,12 @@ def one_wire_device_schema(): | |||||||
|  |  | ||||||
|     :return: The 1-wire device schema, `extend` this in your config schema. |     :return: The 1-wire device schema, `extend` this in your config schema. | ||||||
|     """ |     """ | ||||||
|     schema = cv.Schema( |     return cv.Schema( | ||||||
|         { |         { | ||||||
|             cv.GenerateID(CONF_ONE_WIRE_ID): cv.use_id(OneWireBus), |             cv.GenerateID(CONF_ONE_WIRE_ID): cv.use_id(OneWireBus), | ||||||
|             cv.Optional(CONF_ADDRESS): cv.hex_uint64_t, |             cv.Optional(CONF_ADDRESS): cv.hex_uint64_t, | ||||||
|         } |         } | ||||||
|     ) |     ) | ||||||
|     return schema |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def register_one_wire_device(var, config): | async def register_one_wire_device(var, config): | ||||||
|   | |||||||
| @@ -186,8 +186,7 @@ def _process_package(package_config, config): | |||||||
|         package_config = _process_base_package(package_config) |         package_config = _process_base_package(package_config) | ||||||
|     if isinstance(package_config, dict): |     if isinstance(package_config, dict): | ||||||
|         recursive_package = do_packages_pass(package_config) |         recursive_package = do_packages_pass(package_config) | ||||||
|     config = merge_config(recursive_package, config) |     return merge_config(recursive_package, config) | ||||||
|     return config |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def do_packages_pass(config: dict): | def do_packages_pass(config: dict): | ||||||
|   | |||||||
| @@ -114,8 +114,7 @@ PMWCS3_CALIBRATION_SCHEMA = cv.Schema( | |||||||
| ) | ) | ||||||
| async def pmwcs3_calibration_to_code(config, action_id, template_arg, args): | async def pmwcs3_calibration_to_code(config, action_id, template_arg, args): | ||||||
|     parent = await cg.get_variable(config[CONF_ID]) |     parent = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, parent) |     return cg.new_Pvariable(action_id, template_arg, parent) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| PMWCS3_NEW_I2C_ADDRESS_SCHEMA = cv.maybe_simple_value( | PMWCS3_NEW_I2C_ADDRESS_SCHEMA = cv.maybe_simple_value( | ||||||
|   | |||||||
| @@ -136,8 +136,7 @@ RFBRIDGE_ID_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(RFBridgeComponent)}) | |||||||
| @automation.register_action("rf_bridge.learn", RFBridgeLearnAction, RFBRIDGE_ID_SCHEMA) | @automation.register_action("rf_bridge.learn", RFBridgeLearnAction, RFBRIDGE_ID_SCHEMA) | ||||||
| async def rf_bridge_learnx_to_code(config, action_id, template_args, args): | async def rf_bridge_learnx_to_code(config, action_id, template_args, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_args, paren) |     return cg.new_Pvariable(action_id, template_args, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -149,8 +148,7 @@ async def rf_bridge_start_advanced_sniffing_to_code( | |||||||
|     config, action_id, template_args, args |     config, action_id, template_args, args | ||||||
| ): | ): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_args, paren) |     return cg.new_Pvariable(action_id, template_args, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -162,8 +160,7 @@ async def rf_bridge_stop_advanced_sniffing_to_code( | |||||||
|     config, action_id, template_args, args |     config, action_id, template_args, args | ||||||
| ): | ): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_args, paren) |     return cg.new_Pvariable(action_id, template_args, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -175,8 +172,7 @@ async def rf_bridge_start_bucket_sniffing_to_code( | |||||||
|     config, action_id, template_args, args |     config, action_id, template_args, args | ||||||
| ): | ): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_args, paren) |     return cg.new_Pvariable(action_id, template_args, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| RFBRIDGE_SEND_ADVANCED_CODE_SCHEMA = cv.Schema( | RFBRIDGE_SEND_ADVANCED_CODE_SCHEMA = cv.Schema( | ||||||
|   | |||||||
| @@ -125,8 +125,7 @@ writezero: | |||||||
|  |  | ||||||
| def time_to_cycles(time_us): | def time_to_cycles(time_us): | ||||||
|     cycles_per_us = 57.5 |     cycles_per_us = 57.5 | ||||||
|     cycles = round(float(time_us) * cycles_per_us) |     return round(float(time_us) * cycles_per_us) | ||||||
|     return cycles |  | ||||||
|  |  | ||||||
|  |  | ||||||
| CONF_PIO = "pio" | CONF_PIO = "pio" | ||||||
|   | |||||||
| @@ -256,6 +256,7 @@ OffsetFilter = sensor_ns.class_("OffsetFilter", Filter) | |||||||
| MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter) | MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter) | ||||||
| FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter) | FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter) | ||||||
| ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter) | ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter) | ||||||
|  | ThrottleWithPriorityFilter = sensor_ns.class_("ThrottleWithPriorityFilter", Filter) | ||||||
| TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component) | TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component) | ||||||
| DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component) | DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component) | ||||||
| HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component) | HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component) | ||||||
| @@ -595,6 +596,25 @@ async def throttle_filter_to_code(config, filter_id): | |||||||
|     return cg.new_Pvariable(filter_id, config) |     return cg.new_Pvariable(filter_id, config) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | TIMEOUT_WITH_PRIORITY_SCHEMA = cv.maybe_simple_value( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_TIMEOUT): cv.positive_time_period_milliseconds, | ||||||
|  |         cv.Optional(CONF_VALUE, default="nan"): cv.ensure_list(cv.float_), | ||||||
|  |     }, | ||||||
|  |     key=CONF_TIMEOUT, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @FILTER_REGISTRY.register( | ||||||
|  |     "throttle_with_priority", | ||||||
|  |     ThrottleWithPriorityFilter, | ||||||
|  |     TIMEOUT_WITH_PRIORITY_SCHEMA, | ||||||
|  | ) | ||||||
|  | async def throttle_with_priority_filter_to_code(config, filter_id): | ||||||
|  |     template_ = [await cg.templatable(x, [], float) for x in config[CONF_VALUE]] | ||||||
|  |     return cg.new_Pvariable(filter_id, config[CONF_TIMEOUT], template_) | ||||||
|  |  | ||||||
|  |  | ||||||
| @FILTER_REGISTRY.register( | @FILTER_REGISTRY.register( | ||||||
|     "heartbeat", HeartbeatFilter, cv.positive_time_period_milliseconds |     "heartbeat", HeartbeatFilter, cv.positive_time_period_milliseconds | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #include "filter.h" | #include "filter.h" | ||||||
| #include <cmath> | #include <cmath> | ||||||
|  | #include "esphome/core/application.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include "sensor.h" | #include "sensor.h" | ||||||
| @@ -332,6 +333,40 @@ optional<float> ThrottleFilter::new_value(float value) { | |||||||
|   return {}; |   return {}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ThrottleWithPriorityFilter | ||||||
|  | ThrottleWithPriorityFilter::ThrottleWithPriorityFilter(uint32_t min_time_between_inputs, | ||||||
|  |                                                        std::vector<TemplatableValue<float>> prioritized_values) | ||||||
|  |     : min_time_between_inputs_(min_time_between_inputs), prioritized_values_(std::move(prioritized_values)) {} | ||||||
|  |  | ||||||
|  | optional<float> ThrottleWithPriorityFilter::new_value(float value) { | ||||||
|  |   bool is_prioritized_value = false; | ||||||
|  |   int8_t accuracy = this->parent_->get_accuracy_decimals(); | ||||||
|  |   float accuracy_mult = powf(10.0f, accuracy); | ||||||
|  |   const uint32_t now = App.get_loop_component_start_time(); | ||||||
|  |   // First, determine if the new value is one of the prioritized values | ||||||
|  |   for (auto prioritized_value : this->prioritized_values_) { | ||||||
|  |     if (std::isnan(prioritized_value.value())) { | ||||||
|  |       if (std::isnan(value)) { | ||||||
|  |         is_prioritized_value = true; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     float rounded_prioritized_value = roundf(accuracy_mult * prioritized_value.value()); | ||||||
|  |     float rounded_value = roundf(accuracy_mult * value); | ||||||
|  |     if (rounded_prioritized_value == rounded_value) { | ||||||
|  |       is_prioritized_value = true; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   // Finally, determine if the new value should be throttled and pass it through if not | ||||||
|  |   if (this->last_input_ == 0 || now - this->last_input_ >= min_time_between_inputs_ || is_prioritized_value) { | ||||||
|  |     this->last_input_ = now; | ||||||
|  |     return value; | ||||||
|  |   } | ||||||
|  |   return {}; | ||||||
|  | } | ||||||
|  |  | ||||||
| // DeltaFilter | // DeltaFilter | ||||||
| DeltaFilter::DeltaFilter(float delta, bool percentage_mode) | DeltaFilter::DeltaFilter(float delta, bool percentage_mode) | ||||||
|     : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {} |     : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {} | ||||||
|   | |||||||
| @@ -314,6 +314,20 @@ class ThrottleFilter : public Filter { | |||||||
|   uint32_t min_time_between_inputs_; |   uint32_t min_time_between_inputs_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /// Same as 'throttle' but will immediately publish values contained in `value_to_prioritize`. | ||||||
|  | class ThrottleWithPriorityFilter : public Filter { | ||||||
|  |  public: | ||||||
|  |   explicit ThrottleWithPriorityFilter(uint32_t min_time_between_inputs, | ||||||
|  |                                       std::vector<TemplatableValue<float>> prioritized_values); | ||||||
|  |  | ||||||
|  |   optional<float> new_value(float value) override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   uint32_t last_input_{0}; | ||||||
|  |   uint32_t min_time_between_inputs_; | ||||||
|  |   std::vector<TemplatableValue<float>> prioritized_values_; | ||||||
|  | }; | ||||||
|  |  | ||||||
| class TimeoutFilter : public Filter, public Component { | class TimeoutFilter : public Filter, public Component { | ||||||
|  public: |  public: | ||||||
|   explicit TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value); |   explicit TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value); | ||||||
|   | |||||||
| @@ -171,8 +171,7 @@ async def sim800l_dial_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def sim800l_connect_to_code(config, action_id, template_arg, args): | async def sim800l_connect_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| SIM800L_SEND_USSD_SCHEMA = cv.Schema( | SIM800L_SEND_USSD_SCHEMA = cv.Schema( | ||||||
| @@ -201,5 +200,4 @@ async def sim800l_send_ussd_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def sim800l_disconnect_to_code(config, action_id, template_arg, args): | async def sim800l_disconnect_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|   | |||||||
| @@ -122,5 +122,4 @@ UFIRE_EC_RESET_SCHEMA = cv.Schema( | |||||||
| ) | ) | ||||||
| async def ufire_ec_reset_to_code(config, action_id, template_arg, args): | async def ufire_ec_reset_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|   | |||||||
| @@ -123,5 +123,4 @@ UFIRE_ISE_RESET_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(UFireISEComponent | |||||||
| ) | ) | ||||||
| async def ufire_ise_reset_to_code(config, action_id, template_arg, args): | async def ufire_ise_reset_to_code(config, action_id, template_arg, args): | ||||||
|     paren = await cg.get_variable(config[CONF_ID]) |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, paren) |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|     return var |  | ||||||
|   | |||||||
| @@ -474,8 +474,20 @@ const char *get_disconnect_reason_str(uint8_t reason) { | |||||||
|       return "Handshake Failed"; |       return "Handshake Failed"; | ||||||
|     case WIFI_REASON_CONNECTION_FAIL: |     case WIFI_REASON_CONNECTION_FAIL: | ||||||
|       return "Connection Failed"; |       return "Connection Failed"; | ||||||
|  |     case WIFI_REASON_AP_TSF_RESET: | ||||||
|  |       return "AP TSF reset"; | ||||||
|     case WIFI_REASON_ROAMING: |     case WIFI_REASON_ROAMING: | ||||||
|       return "Station Roaming"; |       return "Station Roaming"; | ||||||
|  |     case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG: | ||||||
|  |       return "Association comeback time too long"; | ||||||
|  |     case WIFI_REASON_SA_QUERY_TIMEOUT: | ||||||
|  |       return "SA query timeout"; | ||||||
|  |     case WIFI_REASON_NO_AP_FOUND_W_COMPATIBLE_SECURITY: | ||||||
|  |       return "No AP found with compatible security"; | ||||||
|  |     case WIFI_REASON_NO_AP_FOUND_IN_AUTHMODE_THRESHOLD: | ||||||
|  |       return "No AP found in auth mode threshold"; | ||||||
|  |     case WIFI_REASON_NO_AP_FOUND_IN_RSSI_THRESHOLD: | ||||||
|  |       return "No AP found in RSSI threshold"; | ||||||
|     case WIFI_REASON_UNSPECIFIED: |     case WIFI_REASON_UNSPECIFIED: | ||||||
|     default: |     default: | ||||||
|       return "Unspecified"; |       return "Unspecified"; | ||||||
|   | |||||||
| @@ -640,8 +640,20 @@ const char *get_disconnect_reason_str(uint8_t reason) { | |||||||
|       return "Handshake Failed"; |       return "Handshake Failed"; | ||||||
|     case WIFI_REASON_CONNECTION_FAIL: |     case WIFI_REASON_CONNECTION_FAIL: | ||||||
|       return "Connection Failed"; |       return "Connection Failed"; | ||||||
|  |     case WIFI_REASON_AP_TSF_RESET: | ||||||
|  |       return "AP TSF reset"; | ||||||
|     case WIFI_REASON_ROAMING: |     case WIFI_REASON_ROAMING: | ||||||
|       return "Station Roaming"; |       return "Station Roaming"; | ||||||
|  |     case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG: | ||||||
|  |       return "Association comeback time too long"; | ||||||
|  |     case WIFI_REASON_SA_QUERY_TIMEOUT: | ||||||
|  |       return "SA query timeout"; | ||||||
|  |     case WIFI_REASON_NO_AP_FOUND_W_COMPATIBLE_SECURITY: | ||||||
|  |       return "No AP found with compatible security"; | ||||||
|  |     case WIFI_REASON_NO_AP_FOUND_IN_AUTHMODE_THRESHOLD: | ||||||
|  |       return "No AP found in auth mode threshold"; | ||||||
|  |     case WIFI_REASON_NO_AP_FOUND_IN_RSSI_THRESHOLD: | ||||||
|  |       return "No AP found in RSSI threshold"; | ||||||
|     case WIFI_REASON_UNSPECIFIED: |     case WIFI_REASON_UNSPECIFIED: | ||||||
|     default: |     default: | ||||||
|       return "Unspecified"; |       return "Unspecified"; | ||||||
|   | |||||||
| @@ -111,8 +111,7 @@ def merge_config(full_old, full_new): | |||||||
|                     else: |                     else: | ||||||
|                         ids[new_id] = len(res) |                         ids[new_id] = len(res) | ||||||
|                 res.append(v) |                 res.append(v) | ||||||
|             res = [v for i, v in enumerate(res) if i not in ids_to_delete] |             return [v for i, v in enumerate(res) if i not in ids_to_delete] | ||||||
|             return res |  | ||||||
|         if new is None: |         if new is None: | ||||||
|             return old |             return old | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1868,7 +1868,7 @@ def validate_registry_entry(name, registry): | |||||||
|  |  | ||||||
| def none(value): | def none(value): | ||||||
|     if value in ("none", "None"): |     if value in ("none", "None"): | ||||||
|         return None |         return | ||||||
|     raise Invalid("Must be none") |     raise Invalid("Must be none") | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -115,7 +115,7 @@ async def build_registry_list(registry, config): | |||||||
|  |  | ||||||
| async def past_safe_mode(): | async def past_safe_mode(): | ||||||
|     if CONF_SAFE_MODE not in CORE.config: |     if CONF_SAFE_MODE not in CORE.config: | ||||||
|         return |         return None | ||||||
|  |  | ||||||
|     def _safe_mode_generator(): |     def _safe_mode_generator(): | ||||||
|         while True: |         while True: | ||||||
|   | |||||||
| @@ -36,7 +36,7 @@ _LOGGER = logging.getLogger(__name__) | |||||||
|  |  | ||||||
|  |  | ||||||
| def config_from_env(): | def config_from_env(): | ||||||
|     config = { |     return { | ||||||
|         CONF_MQTT: { |         CONF_MQTT: { | ||||||
|             CONF_USERNAME: get_str_env("ESPHOME_DASHBOARD_MQTT_USERNAME"), |             CONF_USERNAME: get_str_env("ESPHOME_DASHBOARD_MQTT_USERNAME"), | ||||||
|             CONF_PASSWORD: get_str_env("ESPHOME_DASHBOARD_MQTT_PASSWORD"), |             CONF_PASSWORD: get_str_env("ESPHOME_DASHBOARD_MQTT_PASSWORD"), | ||||||
| @@ -44,7 +44,6 @@ def config_from_env(): | |||||||
|             CONF_PORT: get_int_env("ESPHOME_DASHBOARD_MQTT_PORT", 1883), |             CONF_PORT: get_int_env("ESPHOME_DASHBOARD_MQTT_PORT", 1883), | ||||||
|         }, |         }, | ||||||
|     } |     } | ||||||
|     return config |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def initialize( | def initialize( | ||||||
|   | |||||||
| @@ -81,8 +81,7 @@ def _print_file_read_event(path: str) -> None: | |||||||
|  |  | ||||||
| def _request_and_get_stream_on_stdin(fname: str) -> StringIO: | def _request_and_get_stream_on_stdin(fname: str) -> StringIO: | ||||||
|     _print_file_read_event(fname) |     _print_file_read_event(fname) | ||||||
|     raw_yaml_stream = StringIO(_read_file_content_from_json_on_stdin()) |     return StringIO(_read_file_content_from_json_on_stdin()) | ||||||
|     return raw_yaml_stream |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def _vscode_loader(fname: str) -> dict[str, Any]: | def _vscode_loader(fname: str) -> dict[str, Any]: | ||||||
|   | |||||||
| @@ -305,8 +305,7 @@ class ESPHomeLoaderMixin: | |||||||
|         result = self.yaml_loader(self._rel_path(file)) |         result = self.yaml_loader(self._rel_path(file)) | ||||||
|         if not vars: |         if not vars: | ||||||
|             vars = {} |             vars = {} | ||||||
|         result = substitute_vars(result, vars) |         return substitute_vars(result, vars) | ||||||
|         return result |  | ||||||
|  |  | ||||||
|     @_add_data_ref |     @_add_data_ref | ||||||
|     def construct_include_dir_list(self, node: yaml.Node) -> list[dict[str, Any]]: |     def construct_include_dir_list(self, node: yaml.Node) -> list[dict[str, Any]]: | ||||||
|   | |||||||
| @@ -118,6 +118,7 @@ select = [ | |||||||
|   "PERF", # performance |   "PERF", # performance | ||||||
|   "PL",   # pylint |   "PL",   # pylint | ||||||
|   "SIM",  # flake8-simplify |   "SIM",  # flake8-simplify | ||||||
|  |   "RET",  # flake8-ret | ||||||
|   "UP",   # pyupgrade |   "UP",   # pyupgrade | ||||||
| ] | ] | ||||||
|  |  | ||||||
|   | |||||||
| @@ -539,8 +539,7 @@ class BoolType(TypeInfo): | |||||||
|     wire_type = WireType.VARINT  # Uses wire type 0 |     wire_type = WireType.VARINT  # Uses wire type 0 | ||||||
|  |  | ||||||
|     def dump(self, name: str) -> str: |     def dump(self, name: str) -> str: | ||||||
|         o = f"out.append(YESNO({name}));" |         return f"out.append(YESNO({name}));" | ||||||
|         return o |  | ||||||
|  |  | ||||||
|     def get_size_calculation(self, name: str, force: bool = False) -> str: |     def get_size_calculation(self, name: str, force: bool = False) -> str: | ||||||
|         return self._get_simple_size_calculation(name, force, "add_bool") |         return self._get_simple_size_calculation(name, force, "add_bool") | ||||||
| @@ -592,7 +591,6 @@ class StringType(TypeInfo): | |||||||
|         if no_zero_copy: |         if no_zero_copy: | ||||||
|             # Use the std::string directly |             # Use the std::string directly | ||||||
|             return f"buffer.encode_string({self.number}, this->{self.field_name});" |             return f"buffer.encode_string({self.number}, this->{self.field_name});" | ||||||
|         else: |  | ||||||
|         # Use the StringRef |         # Use the StringRef | ||||||
|         return f"buffer.encode_string({self.number}, this->{self.field_name}_ref_);" |         return f"buffer.encode_string({self.number}, this->{self.field_name}_ref_);" | ||||||
|  |  | ||||||
| @@ -716,8 +714,7 @@ class MessageType(TypeInfo): | |||||||
|         return f"case {self.number}: value.decode_to_message(this->{self.field_name}); break;" |         return f"case {self.number}: value.decode_to_message(this->{self.field_name}); break;" | ||||||
|  |  | ||||||
|     def dump(self, name: str) -> str: |     def dump(self, name: str) -> str: | ||||||
|         o = f"{name}.dump_to(out);" |         return f"{name}.dump_to(out);" | ||||||
|         return o |  | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def dump_content(self) -> str: |     def dump_content(self) -> str: | ||||||
| @@ -865,8 +862,7 @@ class FixedArrayBytesType(TypeInfo): | |||||||
|         return f"buffer.encode_bytes({self.number}, this->{self.field_name}, this->{self.field_name}_len);" |         return f"buffer.encode_bytes({self.number}, this->{self.field_name}, this->{self.field_name}_len);" | ||||||
|  |  | ||||||
|     def dump(self, name: str) -> str: |     def dump(self, name: str) -> str: | ||||||
|         o = f"out.append(format_hex_pretty({name}, {name}_len));" |         return f"out.append(format_hex_pretty({name}, {name}_len));" | ||||||
|         return o |  | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def dump_content(self) -> str: |     def dump_content(self) -> str: | ||||||
| @@ -883,7 +879,6 @@ class FixedArrayBytesType(TypeInfo): | |||||||
|         if force: |         if force: | ||||||
|             # For repeated fields, always calculate size (no zero check) |             # For repeated fields, always calculate size (no zero check) | ||||||
|             return f"size.add_length_force({field_id_size}, {length_field});" |             return f"size.add_length_force({field_id_size}, {length_field});" | ||||||
|         else: |  | ||||||
|         # For non-repeated fields, add_length already checks for zero |         # For non-repeated fields, add_length already checks for zero | ||||||
|         return f"size.add_length({field_id_size}, {length_field});" |         return f"size.add_length({field_id_size}, {length_field});" | ||||||
|  |  | ||||||
| @@ -940,8 +935,7 @@ class EnumType(TypeInfo): | |||||||
|         return f"buffer.{self.encode_func}({self.number}, static_cast<uint32_t>(this->{self.field_name}));" |         return f"buffer.{self.encode_func}({self.number}, static_cast<uint32_t>(this->{self.field_name}));" | ||||||
|  |  | ||||||
|     def dump(self, name: str) -> str: |     def dump(self, name: str) -> str: | ||||||
|         o = f"out.append(proto_enum_to_string<{self.cpp_type}>({name}));" |         return f"out.append(proto_enum_to_string<{self.cpp_type}>({name}));" | ||||||
|         return o |  | ||||||
|  |  | ||||||
|     def dump_field_value(self, value: str) -> str: |     def dump_field_value(self, value: str) -> str: | ||||||
|         # Enums need explicit cast for the template |         # Enums need explicit cast for the template | ||||||
| @@ -1110,13 +1104,12 @@ class FixedArrayRepeatedType(TypeInfo): | |||||||
|         def encode_element(element: str) -> str: |         def encode_element(element: str) -> str: | ||||||
|             if isinstance(self._ti, EnumType): |             if isinstance(self._ti, EnumType): | ||||||
|                 return f"buffer.{self._ti.encode_func}({self.number}, static_cast<uint32_t>({element}), true);" |                 return f"buffer.{self._ti.encode_func}({self.number}, static_cast<uint32_t>({element}), true);" | ||||||
|             else: |  | ||||||
|             return f"buffer.{self._ti.encode_func}({self.number}, {element}, true);" |             return f"buffer.{self._ti.encode_func}({self.number}, {element}, true);" | ||||||
|  |  | ||||||
|         # Unroll small arrays for efficiency |         # Unroll small arrays for efficiency | ||||||
|         if self.array_size == 1: |         if self.array_size == 1: | ||||||
|             return encode_element(f"this->{self.field_name}[0]") |             return encode_element(f"this->{self.field_name}[0]") | ||||||
|         elif self.array_size == 2: |         if self.array_size == 2: | ||||||
|             return ( |             return ( | ||||||
|                 encode_element(f"this->{self.field_name}[0]") |                 encode_element(f"this->{self.field_name}[0]") | ||||||
|                 + "\n  " |                 + "\n  " | ||||||
| @@ -1195,7 +1188,6 @@ class RepeatedTypeInfo(TypeInfo): | |||||||
|             # use it as-is, otherwise append the element type |             # use it as-is, otherwise append the element type | ||||||
|             if "<" in self._container_type and ">" in self._container_type: |             if "<" in self._container_type and ">" in self._container_type: | ||||||
|                 return f"const {self._container_type}*" |                 return f"const {self._container_type}*" | ||||||
|             else: |  | ||||||
|             return f"const {self._container_type}<{self._ti.cpp_type}>*" |             return f"const {self._container_type}<{self._ti.cpp_type}>*" | ||||||
|         return f"std::vector<{self._ti.cpp_type}>" |         return f"std::vector<{self._ti.cpp_type}>" | ||||||
|  |  | ||||||
| @@ -1282,7 +1274,6 @@ class RepeatedTypeInfo(TypeInfo): | |||||||
|                 o += f"  buffer.{self._ti.encode_func}({self.number}, it, true);\n" |                 o += f"  buffer.{self._ti.encode_func}({self.number}, it, true);\n" | ||||||
|             o += "}" |             o += "}" | ||||||
|             return o |             return o | ||||||
|         else: |  | ||||||
|         o = f"for (auto {'' if self._ti_is_bool else '&'}it : this->{self.field_name}) {{\n" |         o = f"for (auto {'' if self._ti_is_bool else '&'}it : this->{self.field_name}) {{\n" | ||||||
|         if isinstance(self._ti, EnumType): |         if isinstance(self._ti, EnumType): | ||||||
|             o += f"  buffer.{self._ti.encode_func}({self.number}, static_cast<uint32_t>(it), true);\n" |             o += f"  buffer.{self._ti.encode_func}({self.number}, static_cast<uint32_t>(it), true);\n" | ||||||
|   | |||||||
| @@ -444,8 +444,7 @@ def get_str_path_schema(strPath): | |||||||
|     if len(parts) > 2: |     if len(parts) > 2: | ||||||
|         parts[0] += "." + parts[1] |         parts[0] += "." + parts[1] | ||||||
|         parts[1] = parts[2] |         parts[1] = parts[2] | ||||||
|     s1 = output.get(parts[0], {}).get(S_SCHEMAS, {}).get(parts[1], {}) |     return output.get(parts[0], {}).get(S_SCHEMAS, {}).get(parts[1], {}) | ||||||
|     return s1 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def pop_str_path_schema(strPath): | def pop_str_path_schema(strPath): | ||||||
|   | |||||||
| @@ -42,12 +42,11 @@ CONFIG_NEWLIB_LIBC=y | |||||||
|  |  | ||||||
|     def extract_defines(command): |     def extract_defines(command): | ||||||
|         define_pattern = re.compile(r"-D\s*([^\s]+)") |         define_pattern = re.compile(r"-D\s*([^\s]+)") | ||||||
|         defines = [ |         return [ | ||||||
|             match |             match | ||||||
|             for match in define_pattern.findall(command) |             for match in define_pattern.findall(command) | ||||||
|             if match not in ("_ASMLANGUAGE") |             if match not in ("_ASMLANGUAGE") | ||||||
|         ] |         ] | ||||||
|         return defines |  | ||||||
|  |  | ||||||
|     def find_cxx_path(commands): |     def find_cxx_path(commands): | ||||||
|         for entry in commands: |         for entry in commands: | ||||||
| @@ -56,6 +55,7 @@ CONFIG_NEWLIB_LIBC=y | |||||||
|             if not cxx_path.endswith("++"): |             if not cxx_path.endswith("++"): | ||||||
|                 continue |                 continue | ||||||
|             return cxx_path |             return cxx_path | ||||||
|  |         return None | ||||||
|  |  | ||||||
|     def get_builtin_include_paths(compiler): |     def get_builtin_include_paths(compiler): | ||||||
|         result = subprocess.run( |         result = subprocess.run( | ||||||
| @@ -83,11 +83,10 @@ CONFIG_NEWLIB_LIBC=y | |||||||
|         flag_pattern = re.compile( |         flag_pattern = re.compile( | ||||||
|             r"(-O[0-3s]|-g|-std=[^\s]+|-Wall|-Wextra|-Werror|--[^\s]+|-f[^\s]+|-m[^\s]+|-imacros\s*[^\s]+)" |             r"(-O[0-3s]|-g|-std=[^\s]+|-Wall|-Wextra|-Werror|--[^\s]+|-f[^\s]+|-m[^\s]+|-imacros\s*[^\s]+)" | ||||||
|         ) |         ) | ||||||
|         flags = [ |         return [ | ||||||
|             match.replace("-imacros ", "-imacros") |             match.replace("-imacros ", "-imacros") | ||||||
|             for match in flag_pattern.findall(command) |             for match in flag_pattern.findall(command) | ||||||
|         ] |         ] | ||||||
|         return flags |  | ||||||
|  |  | ||||||
|     def transform_to_idedata_format(compile_commands): |     def transform_to_idedata_format(compile_commands): | ||||||
|         cxx_path = find_cxx_path(compile_commands) |         cxx_path = find_cxx_path(compile_commands) | ||||||
|   | |||||||
| @@ -1,44 +1,3 @@ | |||||||
| sensor: |  | ||||||
|   - platform: template |  | ||||||
|     name: "Template Sensor" |  | ||||||
|     id: template_sens |  | ||||||
|     lambda: |- |  | ||||||
|       if (id(some_binary_sensor).state) { |  | ||||||
|         return 42.0; |  | ||||||
|       } else { |  | ||||||
|         return 0.0; |  | ||||||
|       } |  | ||||||
|     update_interval: 60s |  | ||||||
|     filters: |  | ||||||
|       - offset: 10 |  | ||||||
|       - multiply: 1 |  | ||||||
|       - offset: !lambda return 10; |  | ||||||
|       - multiply: !lambda return 2; |  | ||||||
|       - filter_out: |  | ||||||
|           - 10 |  | ||||||
|           - 20 |  | ||||||
|           - !lambda return 10; |  | ||||||
|       - filter_out: 10 |  | ||||||
|       - filter_out: !lambda return NAN; |  | ||||||
|       - timeout: |  | ||||||
|           timeout: 10s |  | ||||||
|           value: !lambda return 10; |  | ||||||
|       - timeout: |  | ||||||
|           timeout: 1h |  | ||||||
|           value: 20.0 |  | ||||||
|       - timeout: |  | ||||||
|           timeout: 1d |  | ||||||
|       - to_ntc_resistance: |  | ||||||
|           calibration: |  | ||||||
|             - 10.0kOhm -> 25°C |  | ||||||
|             - 27.219kOhm -> 0°C |  | ||||||
|             - 14.674kOhm -> 15°C |  | ||||||
|       - to_ntc_temperature: |  | ||||||
|           calibration: |  | ||||||
|             - 10.0kOhm -> 25°C |  | ||||||
|             - 27.219kOhm -> 0°C |  | ||||||
|             - 14.674kOhm -> 15°C |  | ||||||
|  |  | ||||||
| esphome: | esphome: | ||||||
|   on_boot: |   on_boot: | ||||||
|     - sensor.template.publish: |     - sensor.template.publish: | ||||||
| @@ -82,6 +41,123 @@ binary_sensor: | |||||||
|       sensor.in_range: |       sensor.in_range: | ||||||
|         id: template_sens |         id: template_sens | ||||||
|         below: 30.0 |         below: 30.0 | ||||||
|  |     filters: | ||||||
|  |       - invert: | ||||||
|  |       - delayed_on: 100ms | ||||||
|  |       - delayed_off: 100ms | ||||||
|  |       - delayed_on_off: !lambda "if (id(test_switch).state) return 1000; else return 0;" | ||||||
|  |       - delayed_on_off: | ||||||
|  |           time_on: 10s | ||||||
|  |           time_off: !lambda "if (id(test_switch).state) return 1000; else return 0;" | ||||||
|  |       - autorepeat: | ||||||
|  |           - delay: 1s | ||||||
|  |             time_off: 100ms | ||||||
|  |             time_on: 900ms | ||||||
|  |           - delay: 5s | ||||||
|  |             time_off: 100ms | ||||||
|  |             time_on: 400ms | ||||||
|  |       - lambda: |- | ||||||
|  |           if (id(other_binary_sensor).state) { | ||||||
|  |             return x; | ||||||
|  |           } else { | ||||||
|  |             return {}; | ||||||
|  |           } | ||||||
|  |       - settle: 500ms | ||||||
|  |       - timeout: 5s | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: template | ||||||
|  |     name: "Template Sensor" | ||||||
|  |     id: template_sens | ||||||
|  |     lambda: |- | ||||||
|  |       if (id(some_binary_sensor).state) { | ||||||
|  |         return 42.0; | ||||||
|  |       } else { | ||||||
|  |         return 0.0; | ||||||
|  |       } | ||||||
|  |     update_interval: 60s | ||||||
|  |     filters: | ||||||
|  |       - calibrate_linear: | ||||||
|  |           - 0.0 -> 0.0 | ||||||
|  |           - 40.0 -> 45.0 | ||||||
|  |           - 100.0 -> 102.5 | ||||||
|  |       - calibrate_polynomial: | ||||||
|  |           degree: 2 | ||||||
|  |           datapoints: | ||||||
|  |             # Map 0.0 (from sensor) to 0.0 (true value) | ||||||
|  |             - 0.0 -> 0.0 | ||||||
|  |             - 10.0 -> 12.1 | ||||||
|  |             - 13.0 -> 14.0 | ||||||
|  |       - clamp: | ||||||
|  |           max_value: 10.0 | ||||||
|  |           min_value: -10.0 | ||||||
|  |       - debounce: 0.1s | ||||||
|  |       - delta: 5.0 | ||||||
|  |       - exponential_moving_average: | ||||||
|  |           alpha: 0.1 | ||||||
|  |           send_every: 15 | ||||||
|  |       - filter_out: | ||||||
|  |           - 10 | ||||||
|  |           - 20 | ||||||
|  |           - !lambda return 10; | ||||||
|  |       - filter_out: 10 | ||||||
|  |       - filter_out: !lambda return NAN; | ||||||
|  |       - heartbeat: 5s | ||||||
|  |       - lambda: return x * (9.0/5.0) + 32.0; | ||||||
|  |       - max: | ||||||
|  |           window_size: 10 | ||||||
|  |           send_every: 2 | ||||||
|  |           send_first_at: 1 | ||||||
|  |       - median: | ||||||
|  |           window_size: 7 | ||||||
|  |           send_every: 4 | ||||||
|  |           send_first_at: 3 | ||||||
|  |       - min: | ||||||
|  |           window_size: 10 | ||||||
|  |           send_every: 2 | ||||||
|  |           send_first_at: 1 | ||||||
|  |       - multiply: 1 | ||||||
|  |       - multiply: !lambda return 2; | ||||||
|  |       - offset: 10 | ||||||
|  |       - offset: !lambda return 10; | ||||||
|  |       - or: | ||||||
|  |           - quantile: | ||||||
|  |               window_size: 7 | ||||||
|  |               send_every: 4 | ||||||
|  |               send_first_at: 3 | ||||||
|  |               quantile: .9 | ||||||
|  |           - round: 1 | ||||||
|  |       - round_to_multiple_of: 0.25 | ||||||
|  |       - skip_initial: 3 | ||||||
|  |       - sliding_window_moving_average: | ||||||
|  |           window_size: 15 | ||||||
|  |           send_every: 15 | ||||||
|  |       - throttle: 1s | ||||||
|  |       - throttle_average: 2s | ||||||
|  |       - throttle_with_priority: 5s | ||||||
|  |       - throttle_with_priority: | ||||||
|  |           timeout: 3s | ||||||
|  |           value: | ||||||
|  |             - 42.0 | ||||||
|  |             - nan | ||||||
|  |       - timeout: | ||||||
|  |           timeout: 10s | ||||||
|  |           value: !lambda return 10; | ||||||
|  |       - timeout: | ||||||
|  |           timeout: 1h | ||||||
|  |           value: 20.0 | ||||||
|  |       - timeout: | ||||||
|  |           timeout: 1d | ||||||
|  |       - to_ntc_resistance: | ||||||
|  |           calibration: | ||||||
|  |             - 10.0kOhm -> 25°C | ||||||
|  |             - 27.219kOhm -> 0°C | ||||||
|  |             - 14.674kOhm -> 15°C | ||||||
|  |       - to_ntc_temperature: | ||||||
|  |           calibration: | ||||||
|  |             - 10.0kOhm -> 25°C | ||||||
|  |             - 27.219kOhm -> 0°C | ||||||
|  |             - 14.674kOhm -> 15°C | ||||||
|  |  | ||||||
| output: | output: | ||||||
|   - platform: template |   - platform: template | ||||||
| @@ -92,6 +168,7 @@ output: | |||||||
|  |  | ||||||
| switch: | switch: | ||||||
|   - platform: template |   - platform: template | ||||||
|  |     id: test_switch | ||||||
|     name: "Template Switch" |     name: "Template Switch" | ||||||
|     lambda: |- |     lambda: |- | ||||||
|       if (id(some_binary_sensor).state) { |       if (id(some_binary_sensor).state) { | ||||||
|   | |||||||
| @@ -31,8 +31,7 @@ class DashboardTestHelper: | |||||||
|         else: |         else: | ||||||
|             url = f"http://127.0.0.1:{self.port}{path}" |             url = f"http://127.0.0.1:{self.port}{path}" | ||||||
|         future = self.client.fetch(url, raise_error=True, **kwargs) |         future = self.client.fetch(url, raise_error=True, **kwargs) | ||||||
|         result = await future |         return await future | ||||||
|         return result |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest_asyncio.fixture() | @pytest_asyncio.fixture() | ||||||
|   | |||||||
| @@ -251,14 +251,13 @@ async def compile_esphome( | |||||||
|             if proc.returncode == 0: |             if proc.returncode == 0: | ||||||
|                 # Success! |                 # Success! | ||||||
|                 break |                 break | ||||||
|             elif proc.returncode == -11 and attempt < max_retries - 1: |             if proc.returncode == -11 and attempt < max_retries - 1: | ||||||
|                 # Segfault (-11 = SIGSEGV), retry |                 # Segfault (-11 = SIGSEGV), retry | ||||||
|                 print( |                 print( | ||||||
|                     f"Compilation segfaulted (attempt {attempt + 1}/{max_retries}), retrying..." |                     f"Compilation segfaulted (attempt {attempt + 1}/{max_retries}), retrying..." | ||||||
|                 ) |                 ) | ||||||
|                 await asyncio.sleep(1)  # Brief pause before retry |                 await asyncio.sleep(1)  # Brief pause before retry | ||||||
|                 continue |                 continue | ||||||
|             else: |  | ||||||
|             # Other error or final retry |             # Other error or final retry | ||||||
|             raise RuntimeError( |             raise RuntimeError( | ||||||
|                 f"Failed to compile {config_path}, return code: {proc.returncode}. " |                 f"Failed to compile {config_path}, return code: {proc.returncode}. " | ||||||
|   | |||||||
| @@ -72,8 +72,7 @@ DisableAction = loop_test_component_ns.class_("DisableAction", automation.Action | |||||||
| ) | ) | ||||||
| async def enable_to_code(config, action_id, template_arg, args): | async def enable_to_code(config, action_id, template_arg, args): | ||||||
|     parent = await cg.get_variable(config[CONF_ID]) |     parent = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, parent) |     return cg.new_Pvariable(action_id, template_arg, parent) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @automation.register_action( | @automation.register_action( | ||||||
| @@ -87,8 +86,7 @@ async def enable_to_code(config, action_id, template_arg, args): | |||||||
| ) | ) | ||||||
| async def disable_to_code(config, action_id, template_arg, args): | async def disable_to_code(config, action_id, template_arg, args): | ||||||
|     parent = await cg.get_variable(config[CONF_ID]) |     parent = await cg.get_variable(config[CONF_ID]) | ||||||
|     var = cg.new_Pvariable(action_id, template_arg, parent) |     return cg.new_Pvariable(action_id, template_arg, parent) | ||||||
|     return var |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|   | |||||||
| @@ -69,7 +69,7 @@ def test_calculate_clang_tidy_hash() -> None: | |||||||
|         def read_file_mock(path: Path) -> bytes: |         def read_file_mock(path: Path) -> bytes: | ||||||
|             if ".clang-tidy" in str(path): |             if ".clang-tidy" in str(path): | ||||||
|                 return clang_tidy_content |                 return clang_tidy_content | ||||||
|             elif "platformio.ini" in str(path): |             if "platformio.ini" in str(path): | ||||||
|                 return platformio_content |                 return platformio_content | ||||||
|             return b"" |             return b"" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -315,7 +315,6 @@ def test_local_development_no_remotes_configured(monkeypatch: MonkeyPatch) -> No | |||||||
|         def side_effect_func(*args): |         def side_effect_func(*args): | ||||||
|             if args == ("git", "remote"): |             if args == ("git", "remote"): | ||||||
|                 return "origin\nupstream\n" |                 return "origin\nupstream\n" | ||||||
|             else: |  | ||||||
|             # All merge-base attempts fail |             # All merge-base attempts fail | ||||||
|             raise Exception("Command failed") |             raise Exception("Command failed") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,10 +18,9 @@ def sort_dicts(obj): | |||||||
|     """Recursively sort dictionaries for order-insensitive comparison.""" |     """Recursively sort dictionaries for order-insensitive comparison.""" | ||||||
|     if isinstance(obj, dict): |     if isinstance(obj, dict): | ||||||
|         return {k: sort_dicts(obj[k]) for k in sorted(obj)} |         return {k: sort_dicts(obj[k]) for k in sorted(obj)} | ||||||
|     elif isinstance(obj, list): |     if isinstance(obj, list): | ||||||
|         # Lists are not sorted; we preserve order |         # Lists are not sorted; we preserve order | ||||||
|         return [sort_dicts(i) for i in obj] |         return [sort_dicts(i) for i in obj] | ||||||
|     else: |  | ||||||
|     return obj |     return obj | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,8 +22,7 @@ def _run_repl_test(input_data): | |||||||
|             call[0][0] for call in mock_stdout.write.call_args_list |             call[0][0] for call in mock_stdout.write.call_args_list | ||||||
|         ).strip() |         ).strip() | ||||||
|         splitted_output = full_output.split("\n") |         splitted_output = full_output.split("\n") | ||||||
|         remove_version = splitted_output[1:]  # remove first entry with version info |         return splitted_output[1:]  # remove first entry with version info | ||||||
|         return remove_version |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def _validate(file_path: str): | def _validate(file_path: str): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user