mirror of
https://github.com/esphome/esphome.git
synced 2025-09-26 07:02:21 +01:00
Merge branch 'core_api_no_allocate' into integration
This commit is contained in:
@@ -15,7 +15,10 @@ from esphome.const import (
|
|||||||
CONF_TYPE_ID,
|
CONF_TYPE_ID,
|
||||||
CONF_UPDATE_INTERVAL,
|
CONF_UPDATE_INTERVAL,
|
||||||
)
|
)
|
||||||
|
from esphome.core import ID
|
||||||
|
from esphome.cpp_generator import MockObj, MockObjClass, TemplateArgsType
|
||||||
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
||||||
|
from esphome.types import ConfigType
|
||||||
from esphome.util import Registry
|
from esphome.util import Registry
|
||||||
|
|
||||||
|
|
||||||
@@ -49,11 +52,11 @@ def maybe_conf(conf, *validators):
|
|||||||
return validate
|
return validate
|
||||||
|
|
||||||
|
|
||||||
def register_action(name, action_type, schema):
|
def register_action(name: str, action_type: MockObjClass, schema: cv.Schema):
|
||||||
return ACTION_REGISTRY.register(name, action_type, schema)
|
return ACTION_REGISTRY.register(name, action_type, schema)
|
||||||
|
|
||||||
|
|
||||||
def register_condition(name, condition_type, schema):
|
def register_condition(name: str, condition_type: MockObjClass, schema: cv.Schema):
|
||||||
return CONDITION_REGISTRY.register(name, condition_type, schema)
|
return CONDITION_REGISTRY.register(name, condition_type, schema)
|
||||||
|
|
||||||
|
|
||||||
@@ -164,43 +167,78 @@ XorCondition = cg.esphome_ns.class_("XorCondition", Condition)
|
|||||||
|
|
||||||
|
|
||||||
@register_condition("and", AndCondition, validate_condition_list)
|
@register_condition("and", AndCondition, validate_condition_list)
|
||||||
async def and_condition_to_code(config, condition_id, template_arg, args):
|
async def and_condition_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
condition_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
conditions = await build_condition_list(config, template_arg, args)
|
conditions = await build_condition_list(config, template_arg, args)
|
||||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||||
|
|
||||||
|
|
||||||
@register_condition("or", OrCondition, validate_condition_list)
|
@register_condition("or", OrCondition, validate_condition_list)
|
||||||
async def or_condition_to_code(config, condition_id, template_arg, args):
|
async def or_condition_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
condition_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
conditions = await build_condition_list(config, template_arg, args)
|
conditions = await build_condition_list(config, template_arg, args)
|
||||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||||
|
|
||||||
|
|
||||||
@register_condition("all", AndCondition, validate_condition_list)
|
@register_condition("all", AndCondition, validate_condition_list)
|
||||||
async def all_condition_to_code(config, condition_id, template_arg, args):
|
async def all_condition_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
condition_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
conditions = await build_condition_list(config, template_arg, args)
|
conditions = await build_condition_list(config, template_arg, args)
|
||||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||||
|
|
||||||
|
|
||||||
@register_condition("any", OrCondition, validate_condition_list)
|
@register_condition("any", OrCondition, validate_condition_list)
|
||||||
async def any_condition_to_code(config, condition_id, template_arg, args):
|
async def any_condition_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
condition_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
conditions = await build_condition_list(config, template_arg, args)
|
conditions = await build_condition_list(config, template_arg, args)
|
||||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||||
|
|
||||||
|
|
||||||
@register_condition("not", NotCondition, validate_potentially_and_condition)
|
@register_condition("not", NotCondition, validate_potentially_and_condition)
|
||||||
async def not_condition_to_code(config, condition_id, template_arg, args):
|
async def not_condition_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
condition_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
condition = await build_condition(config, template_arg, args)
|
condition = await build_condition(config, template_arg, args)
|
||||||
return cg.new_Pvariable(condition_id, template_arg, condition)
|
return cg.new_Pvariable(condition_id, template_arg, condition)
|
||||||
|
|
||||||
|
|
||||||
@register_condition("xor", XorCondition, validate_condition_list)
|
@register_condition("xor", XorCondition, validate_condition_list)
|
||||||
async def xor_condition_to_code(config, condition_id, template_arg, args):
|
async def xor_condition_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
condition_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
conditions = await build_condition_list(config, template_arg, args)
|
conditions = await build_condition_list(config, template_arg, args)
|
||||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||||
|
|
||||||
|
|
||||||
@register_condition("lambda", LambdaCondition, cv.returning_lambda)
|
@register_condition("lambda", LambdaCondition, cv.returning_lambda)
|
||||||
async def lambda_condition_to_code(config, condition_id, template_arg, args):
|
async def lambda_condition_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
condition_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
lambda_ = await cg.process_lambda(config, args, return_type=bool)
|
lambda_ = await cg.process_lambda(config, args, return_type=bool)
|
||||||
return cg.new_Pvariable(condition_id, template_arg, lambda_)
|
return cg.new_Pvariable(condition_id, template_arg, lambda_)
|
||||||
|
|
||||||
@@ -217,7 +255,12 @@ async def lambda_condition_to_code(config, condition_id, template_arg, args):
|
|||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
)
|
)
|
||||||
async def for_condition_to_code(config, condition_id, template_arg, args):
|
async def for_condition_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
condition_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
condition = await build_condition(
|
condition = await build_condition(
|
||||||
config[CONF_CONDITION], cg.TemplateArguments(), []
|
config[CONF_CONDITION], cg.TemplateArguments(), []
|
||||||
)
|
)
|
||||||
@@ -231,7 +274,12 @@ async def for_condition_to_code(config, condition_id, template_arg, args):
|
|||||||
@register_action(
|
@register_action(
|
||||||
"delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds)
|
"delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds)
|
||||||
)
|
)
|
||||||
async def delay_action_to_code(config, action_id, template_arg, args):
|
async def delay_action_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
var = cg.new_Pvariable(action_id, template_arg)
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
await cg.register_component(var, {})
|
await cg.register_component(var, {})
|
||||||
template_ = await cg.templatable(config, args, cg.uint32)
|
template_ = await cg.templatable(config, args, cg.uint32)
|
||||||
@@ -256,10 +304,15 @@ async def delay_action_to_code(config, action_id, template_arg, args):
|
|||||||
cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL),
|
cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
async def if_action_to_code(config, action_id, template_arg, args):
|
async def if_action_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION))
|
cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION))
|
||||||
conditions = await build_condition(config[cond_conf], template_arg, args)
|
condition = await build_condition(config[cond_conf], template_arg, args)
|
||||||
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
var = cg.new_Pvariable(action_id, template_arg, condition)
|
||||||
if CONF_THEN in config:
|
if CONF_THEN in config:
|
||||||
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
||||||
cg.add(var.add_then(actions))
|
cg.add(var.add_then(actions))
|
||||||
@@ -279,9 +332,14 @@ async def if_action_to_code(config, action_id, template_arg, args):
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
async def while_action_to_code(config, action_id, template_arg, args):
|
async def while_action_to_code(
|
||||||
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
|
config: ConfigType,
|
||||||
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
|
condition = await build_condition(config[CONF_CONDITION], template_arg, args)
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg, condition)
|
||||||
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
||||||
cg.add(var.add_then(actions))
|
cg.add(var.add_then(actions))
|
||||||
return var
|
return var
|
||||||
@@ -297,7 +355,12 @@ async def while_action_to_code(config, action_id, template_arg, args):
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
async def repeat_action_to_code(config, action_id, template_arg, args):
|
async def repeat_action_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
var = cg.new_Pvariable(action_id, template_arg)
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
count_template = await cg.templatable(config[CONF_COUNT], args, cg.uint32)
|
count_template = await cg.templatable(config[CONF_COUNT], args, cg.uint32)
|
||||||
cg.add(var.set_count(count_template))
|
cg.add(var.set_count(count_template))
|
||||||
@@ -320,9 +383,14 @@ _validate_wait_until = cv.maybe_simple_value(
|
|||||||
|
|
||||||
|
|
||||||
@register_action("wait_until", WaitUntilAction, _validate_wait_until)
|
@register_action("wait_until", WaitUntilAction, _validate_wait_until)
|
||||||
async def wait_until_action_to_code(config, action_id, template_arg, args):
|
async def wait_until_action_to_code(
|
||||||
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
|
config: ConfigType,
|
||||||
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
|
condition = await build_condition(config[CONF_CONDITION], template_arg, args)
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg, condition)
|
||||||
if CONF_TIMEOUT in config:
|
if CONF_TIMEOUT in config:
|
||||||
template_ = await cg.templatable(config[CONF_TIMEOUT], args, cg.uint32)
|
template_ = await cg.templatable(config[CONF_TIMEOUT], args, cg.uint32)
|
||||||
cg.add(var.set_timeout_value(template_))
|
cg.add(var.set_timeout_value(template_))
|
||||||
@@ -331,7 +399,12 @@ async def wait_until_action_to_code(config, action_id, template_arg, args):
|
|||||||
|
|
||||||
|
|
||||||
@register_action("lambda", LambdaAction, cv.lambda_)
|
@register_action("lambda", LambdaAction, cv.lambda_)
|
||||||
async def lambda_action_to_code(config, action_id, template_arg, args):
|
async def lambda_action_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
lambda_ = await cg.process_lambda(config, args, return_type=cg.void)
|
lambda_ = await cg.process_lambda(config, args, return_type=cg.void)
|
||||||
return cg.new_Pvariable(action_id, template_arg, lambda_)
|
return cg.new_Pvariable(action_id, template_arg, lambda_)
|
||||||
|
|
||||||
@@ -345,7 +418,12 @@ async def lambda_action_to_code(config, action_id, template_arg, args):
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
async def component_update_action_to_code(config, action_id, template_arg, args):
|
async def component_update_action_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
comp = await cg.get_variable(config[CONF_ID])
|
comp = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, comp)
|
return cg.new_Pvariable(action_id, template_arg, comp)
|
||||||
|
|
||||||
@@ -359,7 +437,12 @@ async def component_update_action_to_code(config, action_id, template_arg, args)
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
async def component_suspend_action_to_code(config, action_id, template_arg, args):
|
async def component_suspend_action_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
comp = await cg.get_variable(config[CONF_ID])
|
comp = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, comp)
|
return cg.new_Pvariable(action_id, template_arg, comp)
|
||||||
|
|
||||||
@@ -376,7 +459,12 @@ async def component_suspend_action_to_code(config, action_id, template_arg, args
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
async def component_resume_action_to_code(config, action_id, template_arg, args):
|
async def component_resume_action_to_code(
|
||||||
|
config: ConfigType,
|
||||||
|
action_id: ID,
|
||||||
|
template_arg: cg.TemplateArguments,
|
||||||
|
args: TemplateArgsType,
|
||||||
|
) -> MockObj:
|
||||||
comp = await cg.get_variable(config[CONF_ID])
|
comp = await cg.get_variable(config[CONF_ID])
|
||||||
var = cg.new_Pvariable(action_id, template_arg, comp)
|
var = cg.new_Pvariable(action_id, template_arg, comp)
|
||||||
if CONF_UPDATE_INTERVAL in config:
|
if CONF_UPDATE_INTERVAL in config:
|
||||||
@@ -385,7 +473,9 @@ async def component_resume_action_to_code(config, action_id, template_arg, args)
|
|||||||
return var
|
return var
|
||||||
|
|
||||||
|
|
||||||
async def build_action(full_config, template_arg, args):
|
async def build_action(
|
||||||
|
full_config: ConfigType, template_arg: cg.TemplateArguments, args: TemplateArgsType
|
||||||
|
) -> MockObj:
|
||||||
registry_entry, config = cg.extract_registry_entry_config(
|
registry_entry, config = cg.extract_registry_entry_config(
|
||||||
ACTION_REGISTRY, full_config
|
ACTION_REGISTRY, full_config
|
||||||
)
|
)
|
||||||
@@ -394,15 +484,19 @@ async def build_action(full_config, template_arg, args):
|
|||||||
return await builder(config, action_id, template_arg, args)
|
return await builder(config, action_id, template_arg, args)
|
||||||
|
|
||||||
|
|
||||||
async def build_action_list(config, templ, arg_type):
|
async def build_action_list(
|
||||||
actions = []
|
config: list[ConfigType], templ: cg.TemplateArguments, arg_type: TemplateArgsType
|
||||||
|
) -> list[MockObj]:
|
||||||
|
actions: list[MockObj] = []
|
||||||
for conf in config:
|
for conf in config:
|
||||||
action = await build_action(conf, templ, arg_type)
|
action = await build_action(conf, templ, arg_type)
|
||||||
actions.append(action)
|
actions.append(action)
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
|
||||||
async def build_condition(full_config, template_arg, args):
|
async def build_condition(
|
||||||
|
full_config: ConfigType, template_arg: cg.TemplateArguments, args: TemplateArgsType
|
||||||
|
) -> MockObj:
|
||||||
registry_entry, config = cg.extract_registry_entry_config(
|
registry_entry, config = cg.extract_registry_entry_config(
|
||||||
CONDITION_REGISTRY, full_config
|
CONDITION_REGISTRY, full_config
|
||||||
)
|
)
|
||||||
@@ -411,15 +505,19 @@ async def build_condition(full_config, template_arg, args):
|
|||||||
return await builder(config, action_id, template_arg, args)
|
return await builder(config, action_id, template_arg, args)
|
||||||
|
|
||||||
|
|
||||||
async def build_condition_list(config, templ, args):
|
async def build_condition_list(
|
||||||
conditions = []
|
config: ConfigType, templ: cg.TemplateArguments, args: TemplateArgsType
|
||||||
|
) -> list[MockObj]:
|
||||||
|
conditions: list[MockObj] = []
|
||||||
for conf in config:
|
for conf in config:
|
||||||
condition = await build_condition(conf, templ, args)
|
condition = await build_condition(conf, templ, args)
|
||||||
conditions.append(condition)
|
conditions.append(condition)
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
|
|
||||||
async def build_automation(trigger, args, config):
|
async def build_automation(
|
||||||
|
trigger: MockObj, args: TemplateArgsType, config: ConfigType
|
||||||
|
) -> MockObj:
|
||||||
arg_types = [arg[0] for arg in args]
|
arg_types = [arg[0] for arg in args]
|
||||||
templ = cg.TemplateArguments(*arg_types)
|
templ = cg.TemplateArguments(*arg_types)
|
||||||
obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)
|
obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)
|
||||||
|
@@ -102,7 +102,7 @@ message HelloRequest {
|
|||||||
// For example "Home Assistant"
|
// For example "Home Assistant"
|
||||||
// Not strictly necessary to send but nice for debugging
|
// Not strictly necessary to send but nice for debugging
|
||||||
// purposes.
|
// purposes.
|
||||||
string client_info = 1;
|
string client_info = 1 [(pointer_to_buffer) = true];
|
||||||
uint32 api_version_major = 2;
|
uint32 api_version_major = 2;
|
||||||
uint32 api_version_minor = 3;
|
uint32 api_version_minor = 3;
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ message AuthenticationRequest {
|
|||||||
option (ifdef) = "USE_API_PASSWORD";
|
option (ifdef) = "USE_API_PASSWORD";
|
||||||
|
|
||||||
// The password to log in with
|
// The password to log in with
|
||||||
string password = 1;
|
string password = 1 [(pointer_to_buffer) = true];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirmation of successful connection. After this the connection is available for all traffic.
|
// Confirmation of successful connection. After this the connection is available for all traffic.
|
||||||
@@ -824,7 +824,7 @@ message GetTimeResponse {
|
|||||||
option (no_delay) = true;
|
option (no_delay) = true;
|
||||||
|
|
||||||
fixed32 epoch_seconds = 1;
|
fixed32 epoch_seconds = 1;
|
||||||
string timezone = 2;
|
string timezone = 2 [(pointer_to_buffer) = true];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== USER-DEFINES SERVICES ====================
|
// ==================== USER-DEFINES SERVICES ====================
|
||||||
@@ -1571,7 +1571,7 @@ message BluetoothGATTWriteRequest {
|
|||||||
uint32 handle = 2;
|
uint32 handle = 2;
|
||||||
bool response = 3;
|
bool response = 3;
|
||||||
|
|
||||||
bytes data = 4 [(pointer_to_buffer) = true];
|
bytes data = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message BluetoothGATTReadDescriptorRequest {
|
message BluetoothGATTReadDescriptorRequest {
|
||||||
@@ -1591,7 +1591,7 @@ message BluetoothGATTWriteDescriptorRequest {
|
|||||||
uint64 address = 1;
|
uint64 address = 1;
|
||||||
uint32 handle = 2;
|
uint32 handle = 2;
|
||||||
|
|
||||||
bytes data = 3 [(pointer_to_buffer) = true];
|
bytes data = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message BluetoothGATTNotifyRequest {
|
message BluetoothGATTNotifyRequest {
|
||||||
|
@@ -1078,8 +1078,14 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) {
|
|||||||
if (homeassistant::global_homeassistant_time != nullptr) {
|
if (homeassistant::global_homeassistant_time != nullptr) {
|
||||||
homeassistant::global_homeassistant_time->set_epoch_time(value.epoch_seconds);
|
homeassistant::global_homeassistant_time->set_epoch_time(value.epoch_seconds);
|
||||||
#ifdef USE_TIME_TIMEZONE
|
#ifdef USE_TIME_TIMEZONE
|
||||||
if (!value.timezone.empty() && value.timezone != homeassistant::global_homeassistant_time->get_timezone()) {
|
if (value.timezone_len > 0) {
|
||||||
homeassistant::global_homeassistant_time->set_timezone(value.timezone);
|
const std::string ¤t_tz = homeassistant::global_homeassistant_time->get_timezone();
|
||||||
|
// Compare without allocating a string
|
||||||
|
if (current_tz.length() != value.timezone_len ||
|
||||||
|
memcmp(current_tz.c_str(), value.timezone, value.timezone_len) != 0) {
|
||||||
|
homeassistant::global_homeassistant_time->set_timezone(
|
||||||
|
std::string(reinterpret_cast<const char *>(value.timezone), value.timezone_len));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1374,7 +1380,7 @@ void APIConnection::complete_authentication_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool APIConnection::send_hello_response(const HelloRequest &msg) {
|
bool APIConnection::send_hello_response(const HelloRequest &msg) {
|
||||||
this->client_info_.name = msg.client_info;
|
this->client_info_.name.assign(reinterpret_cast<const char *>(msg.client_info), msg.client_info_len);
|
||||||
this->client_info_.peername = this->helper_->getpeername();
|
this->client_info_.peername = this->helper_->getpeername();
|
||||||
this->client_api_version_major_ = msg.api_version_major;
|
this->client_api_version_major_ = msg.api_version_major;
|
||||||
this->client_api_version_minor_ = msg.api_version_minor;
|
this->client_api_version_minor_ = msg.api_version_minor;
|
||||||
@@ -1402,7 +1408,7 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) {
|
|||||||
bool APIConnection::send_authenticate_response(const AuthenticationRequest &msg) {
|
bool APIConnection::send_authenticate_response(const AuthenticationRequest &msg) {
|
||||||
AuthenticationResponse resp;
|
AuthenticationResponse resp;
|
||||||
// bool invalid_password = 1;
|
// bool invalid_password = 1;
|
||||||
resp.invalid_password = !this->parent_->check_password(msg.password);
|
resp.invalid_password = !this->parent_->check_password(msg.password, msg.password_len);
|
||||||
if (!resp.invalid_password) {
|
if (!resp.invalid_password) {
|
||||||
this->complete_authentication_();
|
this->complete_authentication_();
|
||||||
}
|
}
|
||||||
|
@@ -22,9 +22,12 @@ bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
|||||||
}
|
}
|
||||||
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||||
switch (field_id) {
|
switch (field_id) {
|
||||||
case 1:
|
case 1: {
|
||||||
this->client_info = value.as_string();
|
// Use raw data directly to avoid allocation
|
||||||
|
this->client_info = value.data();
|
||||||
|
this->client_info_len = value.size();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -45,9 +48,12 @@ void HelloResponse::calculate_size(ProtoSize &size) const {
|
|||||||
#ifdef USE_API_PASSWORD
|
#ifdef USE_API_PASSWORD
|
||||||
bool AuthenticationRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
bool AuthenticationRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||||
switch (field_id) {
|
switch (field_id) {
|
||||||
case 1:
|
case 1: {
|
||||||
this->password = value.as_string();
|
// Use raw data directly to avoid allocation
|
||||||
|
this->password = value.data();
|
||||||
|
this->password_len = value.size();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -917,9 +923,12 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel
|
|||||||
#endif
|
#endif
|
||||||
bool GetTimeResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
bool GetTimeResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||||
switch (field_id) {
|
switch (field_id) {
|
||||||
case 2:
|
case 2: {
|
||||||
this->timezone = value.as_string();
|
// Use raw data directly to avoid allocation
|
||||||
|
this->timezone = value.data();
|
||||||
|
this->timezone_len = value.size();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2028,12 +2037,9 @@ bool BluetoothGATTWriteRequest::decode_varint(uint32_t field_id, ProtoVarInt val
|
|||||||
}
|
}
|
||||||
bool BluetoothGATTWriteRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
bool BluetoothGATTWriteRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||||
switch (field_id) {
|
switch (field_id) {
|
||||||
case 4: {
|
case 4:
|
||||||
// Use raw data directly to avoid allocation
|
this->data = value.as_string();
|
||||||
this->data = value.data();
|
|
||||||
this->data_len = value.size();
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2067,12 +2073,9 @@ bool BluetoothGATTWriteDescriptorRequest::decode_varint(uint32_t field_id, Proto
|
|||||||
}
|
}
|
||||||
bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||||
switch (field_id) {
|
switch (field_id) {
|
||||||
case 3: {
|
case 3:
|
||||||
// Use raw data directly to avoid allocation
|
this->data = value.as_string();
|
||||||
this->data = value.data();
|
|
||||||
this->data_len = value.size();
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -330,11 +330,12 @@ class CommandProtoMessage : public ProtoDecodableMessage {
|
|||||||
class HelloRequest final : public ProtoDecodableMessage {
|
class HelloRequest final : public ProtoDecodableMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t MESSAGE_TYPE = 1;
|
static constexpr uint8_t MESSAGE_TYPE = 1;
|
||||||
static constexpr uint8_t ESTIMATED_SIZE = 17;
|
static constexpr uint8_t ESTIMATED_SIZE = 27;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "hello_request"; }
|
const char *message_name() const override { return "hello_request"; }
|
||||||
#endif
|
#endif
|
||||||
std::string client_info{};
|
const uint8_t *client_info{nullptr};
|
||||||
|
uint16_t client_info_len{0};
|
||||||
uint32_t api_version_major{0};
|
uint32_t api_version_major{0};
|
||||||
uint32_t api_version_minor{0};
|
uint32_t api_version_minor{0};
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
@@ -370,11 +371,12 @@ class HelloResponse final : public ProtoMessage {
|
|||||||
class AuthenticationRequest final : public ProtoDecodableMessage {
|
class AuthenticationRequest final : public ProtoDecodableMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t MESSAGE_TYPE = 3;
|
static constexpr uint8_t MESSAGE_TYPE = 3;
|
||||||
static constexpr uint8_t ESTIMATED_SIZE = 9;
|
static constexpr uint8_t ESTIMATED_SIZE = 19;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "authentication_request"; }
|
const char *message_name() const override { return "authentication_request"; }
|
||||||
#endif
|
#endif
|
||||||
std::string password{};
|
const uint8_t *password{nullptr};
|
||||||
|
uint16_t password_len{0};
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void dump_to(std::string &out) const override;
|
void dump_to(std::string &out) const override;
|
||||||
#endif
|
#endif
|
||||||
@@ -1188,12 +1190,13 @@ class GetTimeRequest final : public ProtoMessage {
|
|||||||
class GetTimeResponse final : public ProtoDecodableMessage {
|
class GetTimeResponse final : public ProtoDecodableMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t MESSAGE_TYPE = 37;
|
static constexpr uint8_t MESSAGE_TYPE = 37;
|
||||||
static constexpr uint8_t ESTIMATED_SIZE = 14;
|
static constexpr uint8_t ESTIMATED_SIZE = 24;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "get_time_response"; }
|
const char *message_name() const override { return "get_time_response"; }
|
||||||
#endif
|
#endif
|
||||||
uint32_t epoch_seconds{0};
|
uint32_t epoch_seconds{0};
|
||||||
std::string timezone{};
|
const uint8_t *timezone{nullptr};
|
||||||
|
uint16_t timezone_len{0};
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void dump_to(std::string &out) const override;
|
void dump_to(std::string &out) const override;
|
||||||
#endif
|
#endif
|
||||||
@@ -1985,15 +1988,14 @@ class BluetoothGATTReadResponse final : public ProtoMessage {
|
|||||||
class BluetoothGATTWriteRequest final : public ProtoDecodableMessage {
|
class BluetoothGATTWriteRequest final : public ProtoDecodableMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t MESSAGE_TYPE = 75;
|
static constexpr uint8_t MESSAGE_TYPE = 75;
|
||||||
static constexpr uint8_t ESTIMATED_SIZE = 29;
|
static constexpr uint8_t ESTIMATED_SIZE = 19;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "bluetooth_gatt_write_request"; }
|
const char *message_name() const override { return "bluetooth_gatt_write_request"; }
|
||||||
#endif
|
#endif
|
||||||
uint64_t address{0};
|
uint64_t address{0};
|
||||||
uint32_t handle{0};
|
uint32_t handle{0};
|
||||||
bool response{false};
|
bool response{false};
|
||||||
const uint8_t *data{nullptr};
|
std::string data{};
|
||||||
uint16_t data_len{0};
|
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void dump_to(std::string &out) const override;
|
void dump_to(std::string &out) const override;
|
||||||
#endif
|
#endif
|
||||||
@@ -2021,14 +2023,13 @@ class BluetoothGATTReadDescriptorRequest final : public ProtoDecodableMessage {
|
|||||||
class BluetoothGATTWriteDescriptorRequest final : public ProtoDecodableMessage {
|
class BluetoothGATTWriteDescriptorRequest final : public ProtoDecodableMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t MESSAGE_TYPE = 77;
|
static constexpr uint8_t MESSAGE_TYPE = 77;
|
||||||
static constexpr uint8_t ESTIMATED_SIZE = 27;
|
static constexpr uint8_t ESTIMATED_SIZE = 17;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "bluetooth_gatt_write_descriptor_request"; }
|
const char *message_name() const override { return "bluetooth_gatt_write_descriptor_request"; }
|
||||||
#endif
|
#endif
|
||||||
uint64_t address{0};
|
uint64_t address{0};
|
||||||
uint32_t handle{0};
|
uint32_t handle{0};
|
||||||
const uint8_t *data{nullptr};
|
std::string data{};
|
||||||
uint16_t data_len{0};
|
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void dump_to(std::string &out) const override;
|
void dump_to(std::string &out) const override;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -670,7 +670,9 @@ template<> const char *proto_enum_to_string<enums::ZWaveProxyRequestType>(enums:
|
|||||||
|
|
||||||
void HelloRequest::dump_to(std::string &out) const {
|
void HelloRequest::dump_to(std::string &out) const {
|
||||||
MessageDumpHelper helper(out, "HelloRequest");
|
MessageDumpHelper helper(out, "HelloRequest");
|
||||||
dump_field(out, "client_info", this->client_info);
|
out.append(" client_info: ");
|
||||||
|
out.append(format_hex_pretty(this->client_info, this->client_info_len));
|
||||||
|
out.append("\n");
|
||||||
dump_field(out, "api_version_major", this->api_version_major);
|
dump_field(out, "api_version_major", this->api_version_major);
|
||||||
dump_field(out, "api_version_minor", this->api_version_minor);
|
dump_field(out, "api_version_minor", this->api_version_minor);
|
||||||
}
|
}
|
||||||
@@ -682,7 +684,12 @@ void HelloResponse::dump_to(std::string &out) const {
|
|||||||
dump_field(out, "name", this->name_ref_);
|
dump_field(out, "name", this->name_ref_);
|
||||||
}
|
}
|
||||||
#ifdef USE_API_PASSWORD
|
#ifdef USE_API_PASSWORD
|
||||||
void AuthenticationRequest::dump_to(std::string &out) const { dump_field(out, "password", this->password); }
|
void AuthenticationRequest::dump_to(std::string &out) const {
|
||||||
|
MessageDumpHelper helper(out, "AuthenticationRequest");
|
||||||
|
out.append(" password: ");
|
||||||
|
out.append(format_hex_pretty(this->password, this->password_len));
|
||||||
|
out.append("\n");
|
||||||
|
}
|
||||||
void AuthenticationResponse::dump_to(std::string &out) const {
|
void AuthenticationResponse::dump_to(std::string &out) const {
|
||||||
MessageDumpHelper helper(out, "AuthenticationResponse");
|
MessageDumpHelper helper(out, "AuthenticationResponse");
|
||||||
dump_field(out, "invalid_password", this->invalid_password);
|
dump_field(out, "invalid_password", this->invalid_password);
|
||||||
@@ -1136,7 +1143,9 @@ void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeReques
|
|||||||
void GetTimeResponse::dump_to(std::string &out) const {
|
void GetTimeResponse::dump_to(std::string &out) const {
|
||||||
MessageDumpHelper helper(out, "GetTimeResponse");
|
MessageDumpHelper helper(out, "GetTimeResponse");
|
||||||
dump_field(out, "epoch_seconds", this->epoch_seconds);
|
dump_field(out, "epoch_seconds", this->epoch_seconds);
|
||||||
dump_field(out, "timezone", this->timezone);
|
out.append(" timezone: ");
|
||||||
|
out.append(format_hex_pretty(this->timezone, this->timezone_len));
|
||||||
|
out.append("\n");
|
||||||
}
|
}
|
||||||
#ifdef USE_API_SERVICES
|
#ifdef USE_API_SERVICES
|
||||||
void ListEntitiesServicesArgument::dump_to(std::string &out) const {
|
void ListEntitiesServicesArgument::dump_to(std::string &out) const {
|
||||||
@@ -1649,7 +1658,7 @@ void BluetoothGATTWriteRequest::dump_to(std::string &out) const {
|
|||||||
dump_field(out, "handle", this->handle);
|
dump_field(out, "handle", this->handle);
|
||||||
dump_field(out, "response", this->response);
|
dump_field(out, "response", this->response);
|
||||||
out.append(" data: ");
|
out.append(" data: ");
|
||||||
out.append(format_hex_pretty(this->data, this->data_len));
|
out.append(format_hex_pretty(reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size()));
|
||||||
out.append("\n");
|
out.append("\n");
|
||||||
}
|
}
|
||||||
void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const {
|
void BluetoothGATTReadDescriptorRequest::dump_to(std::string &out) const {
|
||||||
@@ -1662,7 +1671,7 @@ void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const {
|
|||||||
dump_field(out, "address", this->address);
|
dump_field(out, "address", this->address);
|
||||||
dump_field(out, "handle", this->handle);
|
dump_field(out, "handle", this->handle);
|
||||||
out.append(" data: ");
|
out.append(" data: ");
|
||||||
out.append(format_hex_pretty(this->data, this->data_len));
|
out.append(format_hex_pretty(reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size()));
|
||||||
out.append("\n");
|
out.append("\n");
|
||||||
}
|
}
|
||||||
void BluetoothGATTNotifyRequest::dump_to(std::string &out) const {
|
void BluetoothGATTNotifyRequest::dump_to(std::string &out) const {
|
||||||
|
@@ -217,12 +217,12 @@ void APIServer::dump_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_API_PASSWORD
|
#ifdef USE_API_PASSWORD
|
||||||
bool APIServer::check_password(const std::string &password) const {
|
bool APIServer::check_password(const uint8_t *password_data, size_t password_len) const {
|
||||||
// depend only on input password length
|
// depend only on input password length
|
||||||
const char *a = this->password_.c_str();
|
const char *a = this->password_.c_str();
|
||||||
uint32_t len_a = this->password_.length();
|
uint32_t len_a = this->password_.length();
|
||||||
const char *b = password.c_str();
|
const char *b = reinterpret_cast<const char *>(password_data);
|
||||||
uint32_t len_b = password.length();
|
uint32_t len_b = password_len;
|
||||||
|
|
||||||
// disable optimization with volatile
|
// disable optimization with volatile
|
||||||
volatile uint32_t length = len_b;
|
volatile uint32_t length = len_b;
|
||||||
@@ -245,6 +245,7 @@ bool APIServer::check_password(const std::string &password) const {
|
|||||||
|
|
||||||
return result == 0;
|
return result == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void APIServer::handle_disconnect(APIConnection *conn) {}
|
void APIServer::handle_disconnect(APIConnection *conn) {}
|
||||||
|
@@ -37,7 +37,7 @@ class APIServer : public Component, public Controller {
|
|||||||
void on_shutdown() override;
|
void on_shutdown() override;
|
||||||
bool teardown() override;
|
bool teardown() override;
|
||||||
#ifdef USE_API_PASSWORD
|
#ifdef USE_API_PASSWORD
|
||||||
bool check_password(const std::string &password) const;
|
bool check_password(const uint8_t *password_data, size_t password_len) const;
|
||||||
void set_password(const std::string &password);
|
void set_password(const std::string &password);
|
||||||
#endif
|
#endif
|
||||||
void set_port(uint16_t port);
|
void set_port(uint16_t port);
|
||||||
|
@@ -514,8 +514,7 @@ esp_err_t BluetoothConnection::read_characteristic(uint16_t handle) {
|
|||||||
return this->check_and_log_error_("esp_ble_gattc_read_char", err);
|
return this->check_and_log_error_("esp_ble_gattc_read_char", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t BluetoothConnection::write_characteristic(uint16_t handle, const uint8_t *data, size_t length,
|
esp_err_t BluetoothConnection::write_characteristic(uint16_t handle, const std::string &data, bool response) {
|
||||||
bool response) {
|
|
||||||
if (!this->connected()) {
|
if (!this->connected()) {
|
||||||
this->log_gatt_not_connected_("write", "characteristic");
|
this->log_gatt_not_connected_("write", "characteristic");
|
||||||
return ESP_GATT_NOT_CONNECTED;
|
return ESP_GATT_NOT_CONNECTED;
|
||||||
@@ -523,11 +522,8 @@ esp_err_t BluetoothConnection::write_characteristic(uint16_t handle, const uint8
|
|||||||
ESP_LOGV(TAG, "[%d] [%s] Writing GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
|
ESP_LOGV(TAG, "[%d] [%s] Writing GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||||
handle);
|
handle);
|
||||||
|
|
||||||
// ESP-IDF's API requires a non-const uint8_t* but it doesn't modify the data
|
|
||||||
// The BTC layer immediately copies the data to its own buffer (see btc_gattc.c)
|
|
||||||
// const_cast is safe here and was previously hidden by a C-style cast
|
|
||||||
esp_err_t err =
|
esp_err_t err =
|
||||||
esp_ble_gattc_write_char(this->gattc_if_, this->conn_id_, handle, length, const_cast<uint8_t *>(data),
|
esp_ble_gattc_write_char(this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
|
||||||
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
return this->check_and_log_error_("esp_ble_gattc_write_char", err);
|
return this->check_and_log_error_("esp_ble_gattc_write_char", err);
|
||||||
}
|
}
|
||||||
@@ -544,7 +540,7 @@ esp_err_t BluetoothConnection::read_descriptor(uint16_t handle) {
|
|||||||
return this->check_and_log_error_("esp_ble_gattc_read_char_descr", err);
|
return this->check_and_log_error_("esp_ble_gattc_read_char_descr", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const uint8_t *data, size_t length, bool response) {
|
esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const std::string &data, bool response) {
|
||||||
if (!this->connected()) {
|
if (!this->connected()) {
|
||||||
this->log_gatt_not_connected_("write", "descriptor");
|
this->log_gatt_not_connected_("write", "descriptor");
|
||||||
return ESP_GATT_NOT_CONNECTED;
|
return ESP_GATT_NOT_CONNECTED;
|
||||||
@@ -552,11 +548,8 @@ esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const uint8_t *
|
|||||||
ESP_LOGV(TAG, "[%d] [%s] Writing GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
|
ESP_LOGV(TAG, "[%d] [%s] Writing GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
|
||||||
handle);
|
handle);
|
||||||
|
|
||||||
// ESP-IDF's API requires a non-const uint8_t* but it doesn't modify the data
|
|
||||||
// The BTC layer immediately copies the data to its own buffer (see btc_gattc.c)
|
|
||||||
// const_cast is safe here and was previously hidden by a C-style cast
|
|
||||||
esp_err_t err = esp_ble_gattc_write_char_descr(
|
esp_err_t err = esp_ble_gattc_write_char_descr(
|
||||||
this->gattc_if_, this->conn_id_, handle, length, const_cast<uint8_t *>(data),
|
this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
|
||||||
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||||
return this->check_and_log_error_("esp_ble_gattc_write_char_descr", err);
|
return this->check_and_log_error_("esp_ble_gattc_write_char_descr", err);
|
||||||
}
|
}
|
||||||
|
@@ -18,9 +18,9 @@ class BluetoothConnection final : public esp32_ble_client::BLEClientBase {
|
|||||||
esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override;
|
esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override;
|
||||||
|
|
||||||
esp_err_t read_characteristic(uint16_t handle);
|
esp_err_t read_characteristic(uint16_t handle);
|
||||||
esp_err_t write_characteristic(uint16_t handle, const uint8_t *data, size_t length, bool response);
|
esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response);
|
||||||
esp_err_t read_descriptor(uint16_t handle);
|
esp_err_t read_descriptor(uint16_t handle);
|
||||||
esp_err_t write_descriptor(uint16_t handle, const uint8_t *data, size_t length, bool response);
|
esp_err_t write_descriptor(uint16_t handle, const std::string &data, bool response);
|
||||||
|
|
||||||
esp_err_t notify_characteristic(uint16_t handle, bool enable);
|
esp_err_t notify_characteristic(uint16_t handle, bool enable);
|
||||||
|
|
||||||
|
@@ -305,7 +305,7 @@ void BluetoothProxy::bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto err = connection->write_characteristic(msg.handle, msg.data, msg.data_len, msg.response);
|
auto err = connection->write_characteristic(msg.handle, msg.data, msg.response);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
this->send_gatt_error(msg.address, msg.handle, err);
|
this->send_gatt_error(msg.address, msg.handle, err);
|
||||||
}
|
}
|
||||||
@@ -331,7 +331,7 @@ void BluetoothProxy::bluetooth_gatt_write_descriptor(const api::BluetoothGATTWri
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto err = connection->write_descriptor(msg.handle, msg.data, msg.data_len, true);
|
auto err = connection->write_descriptor(msg.handle, msg.data, true);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
this->send_gatt_error(msg.address, msg.handle, err);
|
this->send_gatt_error(msg.address, msg.handle, err);
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import abc
|
import abc
|
||||||
from collections.abc import Callable, Sequence
|
from collections.abc import Callable
|
||||||
import inspect
|
import inspect
|
||||||
import math
|
import math
|
||||||
import re
|
import re
|
||||||
@@ -13,7 +13,6 @@ from esphome.core import (
|
|||||||
HexInt,
|
HexInt,
|
||||||
Lambda,
|
Lambda,
|
||||||
Library,
|
Library,
|
||||||
TimePeriod,
|
|
||||||
TimePeriodMicroseconds,
|
TimePeriodMicroseconds,
|
||||||
TimePeriodMilliseconds,
|
TimePeriodMilliseconds,
|
||||||
TimePeriodMinutes,
|
TimePeriodMinutes,
|
||||||
@@ -21,35 +20,11 @@ from esphome.core import (
|
|||||||
TimePeriodSeconds,
|
TimePeriodSeconds,
|
||||||
)
|
)
|
||||||
from esphome.helpers import cpp_string_escape, indent_all_but_first_and_last
|
from esphome.helpers import cpp_string_escape, indent_all_but_first_and_last
|
||||||
|
from esphome.types import Expression, SafeExpType, TemplateArgsType
|
||||||
from esphome.util import OrderedDict
|
from esphome.util import OrderedDict
|
||||||
from esphome.yaml_util import ESPHomeDataBase
|
from esphome.yaml_util import ESPHomeDataBase
|
||||||
|
|
||||||
|
|
||||||
class Expression(abc.ABC):
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def __str__(self):
|
|
||||||
"""
|
|
||||||
Convert expression into C++ code
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
SafeExpType = (
|
|
||||||
Expression
|
|
||||||
| bool
|
|
||||||
| str
|
|
||||||
| str
|
|
||||||
| int
|
|
||||||
| float
|
|
||||||
| TimePeriod
|
|
||||||
| type[bool]
|
|
||||||
| type[int]
|
|
||||||
| type[float]
|
|
||||||
| Sequence[Any]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class RawExpression(Expression):
|
class RawExpression(Expression):
|
||||||
__slots__ = ("text",)
|
__slots__ = ("text",)
|
||||||
|
|
||||||
@@ -575,7 +550,7 @@ def Pvariable(id_: ID, rhs: SafeExpType, type_: "MockObj" = None) -> "MockObj":
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
def new_Pvariable(id_: ID, *args: SafeExpType) -> Pvariable:
|
def new_Pvariable(id_: ID, *args: SafeExpType) -> "MockObj":
|
||||||
"""Declare a new pointer variable in the code generation by calling it's constructor
|
"""Declare a new pointer variable in the code generation by calling it's constructor
|
||||||
with the given arguments.
|
with the given arguments.
|
||||||
|
|
||||||
@@ -681,7 +656,7 @@ async def get_variable_with_full_id(id_: ID) -> tuple[ID, "MockObj"]:
|
|||||||
|
|
||||||
async def process_lambda(
|
async def process_lambda(
|
||||||
value: Lambda,
|
value: Lambda,
|
||||||
parameters: list[tuple[SafeExpType, str]],
|
parameters: TemplateArgsType,
|
||||||
capture: str = "=",
|
capture: str = "=",
|
||||||
return_type: SafeExpType = None,
|
return_type: SafeExpType = None,
|
||||||
) -> LambdaExpression | None:
|
) -> LambdaExpression | None:
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
"""This helper module tracks commonly used types in the esphome python codebase."""
|
"""This helper module tracks commonly used types in the esphome python codebase."""
|
||||||
|
|
||||||
from typing import TypedDict
|
import abc
|
||||||
|
from collections.abc import Sequence
|
||||||
|
from typing import Any, TypedDict
|
||||||
|
|
||||||
from esphome.core import ID, EsphomeCore, Lambda
|
from esphome.core import ID, EsphomeCore, Lambda, TimePeriod
|
||||||
|
|
||||||
ConfigFragmentType = (
|
ConfigFragmentType = (
|
||||||
str
|
str
|
||||||
@@ -20,6 +22,32 @@ CoreType = EsphomeCore
|
|||||||
ConfigPathType = str | int
|
ConfigPathType = str | int
|
||||||
|
|
||||||
|
|
||||||
|
class Expression(abc.ABC):
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def __str__(self):
|
||||||
|
"""
|
||||||
|
Convert expression into C++ code
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
SafeExpType = (
|
||||||
|
Expression
|
||||||
|
| bool
|
||||||
|
| str
|
||||||
|
| int
|
||||||
|
| float
|
||||||
|
| TimePeriod
|
||||||
|
| type[bool]
|
||||||
|
| type[int]
|
||||||
|
| type[float]
|
||||||
|
| Sequence[Any]
|
||||||
|
)
|
||||||
|
|
||||||
|
TemplateArgsType = list[tuple[SafeExpType, str]]
|
||||||
|
|
||||||
|
|
||||||
class EntityMetadata(TypedDict):
|
class EntityMetadata(TypedDict):
|
||||||
"""Metadata stored for each entity to help with duplicate detection."""
|
"""Metadata stored for each entity to help with duplicate detection."""
|
||||||
|
|
||||||
|
@@ -1,19 +1,30 @@
|
|||||||
import collections
|
import collections
|
||||||
|
from collections.abc import Callable
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from esphome import const
|
from esphome import const
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from esphome.config_validation import Schema
|
||||||
|
from esphome.cpp_generator import MockObjClass
|
||||||
|
|
||||||
|
|
||||||
class RegistryEntry:
|
class RegistryEntry:
|
||||||
def __init__(self, name, fun, type_id, schema):
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
fun: Callable[..., Any],
|
||||||
|
type_id: "MockObjClass",
|
||||||
|
schema: "Schema",
|
||||||
|
):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.fun = fun
|
self.fun = fun
|
||||||
self.type_id = type_id
|
self.type_id = type_id
|
||||||
@@ -38,8 +49,8 @@ class Registry(dict[str, RegistryEntry]):
|
|||||||
self.base_schema = base_schema or {}
|
self.base_schema = base_schema or {}
|
||||||
self.type_id_key = type_id_key
|
self.type_id_key = type_id_key
|
||||||
|
|
||||||
def register(self, name, type_id, schema):
|
def register(self, name: str, type_id: "MockObjClass", schema: "Schema"):
|
||||||
def decorator(fun):
|
def decorator(fun: Callable[..., Any]):
|
||||||
self[name] = RegistryEntry(name, fun, type_id, schema)
|
self[name] = RegistryEntry(name, fun, type_id, schema)
|
||||||
return fun
|
return fun
|
||||||
|
|
||||||
@@ -47,8 +58,8 @@ class Registry(dict[str, RegistryEntry]):
|
|||||||
|
|
||||||
|
|
||||||
class SimpleRegistry(dict):
|
class SimpleRegistry(dict):
|
||||||
def register(self, name, data):
|
def register(self, name: str, data: Any):
|
||||||
def decorator(fun):
|
def decorator(fun: Callable[..., Any]):
|
||||||
self[name] = (fun, data)
|
self[name] = (fun, data)
|
||||||
return fun
|
return fun
|
||||||
|
|
||||||
|
@@ -373,6 +373,14 @@ def create_field_type_info(
|
|||||||
# Traditional fixed array approach with copy
|
# Traditional fixed array approach with copy
|
||||||
return FixedArrayBytesType(field, fixed_size)
|
return FixedArrayBytesType(field, fixed_size)
|
||||||
|
|
||||||
|
# Check for pointer_to_buffer option on string fields
|
||||||
|
if field.type == 9:
|
||||||
|
has_pointer_to_buffer = get_field_opt(field, pb.pointer_to_buffer, False)
|
||||||
|
|
||||||
|
if has_pointer_to_buffer:
|
||||||
|
# Zero-copy pointer approach for strings
|
||||||
|
return PointerToBytesBufferType(field, None)
|
||||||
|
|
||||||
# Special handling for bytes fields
|
# Special handling for bytes fields
|
||||||
if field.type == 12:
|
if field.type == 12:
|
||||||
return BytesType(field, needs_decode, needs_encode)
|
return BytesType(field, needs_decode, needs_encode)
|
||||||
|
Reference in New Issue
Block a user