remove dependencies to components from core part 1

This commit is contained in:
Tomasz Duda 2024-08-14 01:23:17 +02:00
parent c5b1a8eb81
commit 7e9ed0b5db
30 changed files with 255 additions and 276 deletions

View file

@ -26,6 +26,7 @@ from esphome.cpp_generator import ( # noqa: F401
add_global,
add_library,
add_platformio_option,
define_entity,
get_variable,
get_variable_with_full_id,
is_template,
@ -33,6 +34,7 @@ from esphome.cpp_generator import ( # noqa: F401
new_variable,
process_lambda,
progmem_array,
register_entity,
safe_exp,
statement,
static_const_array,

View file

@ -206,7 +206,7 @@ async def setup_alarm_control_panel_core_(var, config):
async def register_alarm_control_panel(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_alarm_control_panel(var))
cg.register_entity(AlarmControlPanel, var)
await setup_alarm_control_panel_core_(var, config)
@ -315,3 +315,4 @@ async def alarm_control_panel_is_armed_to_code(
async def to_code(config):
cg.add_global(alarm_control_panel_ns.using)
cg.add_define("USE_ALARM_CONTROL_PANEL")
cg.define_entity(AlarmControlPanel)

View file

@ -551,7 +551,7 @@ async def setup_binary_sensor_core_(var, config):
async def register_binary_sensor(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_binary_sensor(var))
cg.register_entity(BinarySensor, var)
await setup_binary_sensor_core_(var, config)
@ -588,3 +588,4 @@ async def binary_sensor_is_off_to_code(config, condition_id, template_arg, args)
async def to_code(config):
cg.add_define("USE_BINARY_SENSOR")
cg.add_global(binary_sensor_ns.using)
cg.define_entity(BinarySensor)

View file

@ -105,7 +105,7 @@ async def setup_button_core_(var, config):
async def register_button(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_button(var))
cg.register_entity(Button, var)
await setup_button_core_(var, config)
@ -132,3 +132,4 @@ async def button_press_to_code(config, action_id, template_arg, args):
async def to_code(config):
cg.add_global(button_ns.using)
cg.add_define("USE_BUTTON")
cg.define_entity(Button)

View file

@ -416,7 +416,7 @@ async def setup_climate_core_(var, config):
async def register_climate(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_climate(var))
cg.register_entity(Climate, var)
await setup_climate_core_(var, config)
@ -485,3 +485,4 @@ async def climate_control_to_code(config, action_id, template_arg, args):
async def to_code(config):
cg.add_define("USE_CLIMATE")
cg.add_global(climate_ns.using)
cg.define_entity(Climate)

View file

@ -160,7 +160,7 @@ async def setup_cover_core_(var, config):
async def register_cover(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_cover(var))
cg.register_entity(Cover, var)
await setup_cover_core_(var, config)
@ -229,3 +229,4 @@ async def cover_control_to_code(config, action_id, template_arg, args):
async def to_code(config):
cg.add_define("USE_COVER")
cg.add_global(cover_ns.using)
cg.define_entity(Cover)

View file

@ -151,9 +151,12 @@ async def setup_datetime_core_(var, config):
async def register_datetime(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(getattr(cg.App, f"register_{config[CONF_TYPE].lower()}")(var))
entity = f"datetime::{str(config[CONF_ID].type).split('Template')[1]}Entity"
print(entity)
cg.register_entity(entity, var)
await setup_datetime_core_(var, config)
cg.add_define(f"USE_DATETIME_{config[CONF_TYPE]}")
cg.define_entity(entity)
async def new_datetime(config, *args):

View file

@ -101,7 +101,7 @@ async def setup_event_core_(var, config, *, event_types: list[str]):
async def register_event(var, config, *, event_types: list[str]):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_event(var))
cg.register_entity(Event, var)
await setup_event_core_(var, config, event_types=event_types)
@ -132,3 +132,4 @@ async def event_fire_to_code(config, action_id, template_arg, args):
async def to_code(config):
cg.add_define("USE_EVENT")
cg.add_global(event_ns.using)
cg.define_entity(Event)

View file

@ -248,7 +248,7 @@ async def setup_fan_core_(var, config):
async def register_fan(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_fan(var))
cg.register_entity(Fan, var)
await setup_fan_core_(var, config)
@ -352,3 +352,4 @@ async def fan_is_on_off_to_code(config, condition_id, template_arg, args):
async def to_code(config):
cg.add_define("USE_FAN")
cg.add_global(fan_ns.using)
cg.define_entity(Fan)

View file

@ -188,7 +188,7 @@ async def setup_light_core_(light_var, output_var, config):
async def register_light(output_var, config):
light_var = cg.new_Pvariable(config[CONF_ID], output_var)
cg.add(cg.App.register_light(light_var))
cg.register_entity(LightState, light_var)
await cg.register_component(light_var, config)
await setup_light_core_(light_var, output_var, config)
@ -197,3 +197,4 @@ async def register_light(output_var, config):
async def to_code(config):
cg.add_define("USE_LIGHT")
cg.add_global(light_ns.using)
cg.define_entity(LightState)

View file

@ -74,7 +74,7 @@ async def setup_lock_core_(var, config):
async def register_lock(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_lock(var))
cg.register_entity(Lock, var)
await setup_lock_core_(var, config)
@ -109,3 +109,4 @@ async def lock_is_off_to_code(config, condition_id, template_arg, args):
async def to_code(config):
cg.add_global(lock_ns.using)
cg.add_define("USE_LOCK")
cg.define_entity(Lock)

View file

@ -85,7 +85,7 @@ async def setup_media_player_core_(var, config):
async def register_media_player(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_media_player(var))
cg.register_entity(MediaPlayer, var)
await setup_media_player_core_(var, config)
@ -191,3 +191,4 @@ async def media_player_volume_set_action(config, action_id, template_arg, args):
async def to_code(config):
cg.add_global(media_player_ns.using)
cg.add_define("USE_MEDIA_PLAYER")
cg.define_entity(MediaPlayer)

View file

@ -265,7 +265,7 @@ async def register_number(
):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_number(var))
cg.register_entity(Number, var)
await setup_number_core_(
var, config, min_value=min_value, max_value=max_value, step=step
)
@ -308,6 +308,7 @@ async def number_in_range_to_code(config, condition_id, template_arg, args):
async def to_code(config):
cg.add_define("USE_NUMBER")
cg.add_global(number_ns.using)
cg.define_entity(Number)
OPERATION_BASE_SCHEMA = cv.Schema(

View file

@ -112,7 +112,7 @@ async def setup_select_core_(var, config, *, options: list[str]):
async def register_select(var, config, *, options: list[str]):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_select(var))
cg.register_entity(Select, var)
await setup_select_core_(var, config, options=options)
@ -126,6 +126,7 @@ async def new_select(config, *, options: list[str]):
async def to_code(config):
cg.add_define("USE_SELECT")
cg.add_global(select_ns.using)
cg.define_entity(Select)
OPERATION_BASE_SCHEMA = cv.Schema(

View file

@ -808,7 +808,7 @@ async def setup_sensor_core_(var, config):
async def register_sensor(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_sensor(var))
cg.register_entity(Sensor, var)
await setup_sensor_core_(var, config)
@ -948,3 +948,4 @@ def _lstsq(a, b):
async def to_code(config):
cg.add_define("USE_SENSOR")
cg.add_global(sensor_ns.using)
cg.define_entity(Sensor)

View file

@ -169,7 +169,7 @@ async def setup_switch_core_(var, config):
async def register_switch(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_switch(var))
cg.register_entity(Switch, var)
await setup_switch_core_(var, config)
@ -210,3 +210,4 @@ async def switch_is_off_to_code(config, condition_id, template_arg, args):
async def to_code(config):
cg.add_global(switch_ns.using)
cg.add_define("USE_SWITCH")
cg.define_entity(Switch)

View file

@ -97,7 +97,7 @@ async def register_text(
):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_text(var))
cg.register_entity(Text, var)
await setup_text_core_(
var, config, min_length=min_length, max_length=max_length, pattern=pattern
)
@ -121,6 +121,7 @@ async def new_text(
async def to_code(config):
cg.add_define("USE_TEXT")
cg.add_global(text_ns.using)
cg.define_entity(Text)
OPERATION_BASE_SCHEMA = cv.Schema(

View file

@ -220,7 +220,7 @@ async def setup_text_sensor_core_(var, config):
async def register_text_sensor(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_text_sensor(var))
cg.register_entity(TextSensor, var)
await setup_text_sensor_core_(var, config)
@ -234,6 +234,7 @@ async def new_text_sensor(config, *args):
async def to_code(config):
cg.add_define("USE_TEXT_SENSOR")
cg.add_global(text_sensor_ns.using)
cg.define_entity(TextSensor)
@automation.register_condition(

View file

@ -81,7 +81,7 @@ async def setup_update_core_(var, config):
async def register_update(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_update(var))
cg.register_entity(UpdateEntity, var)
await setup_update_core_(var, config)
@ -95,6 +95,7 @@ async def new_update(config):
async def to_code(config):
cg.add_define("USE_UPDATE")
cg.add_global(update_ns.using)
cg.define_entity(UpdateEntity)
@automation.register_action(

View file

@ -132,7 +132,7 @@ async def setup_valve_core_(var, config):
async def register_valve(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_valve(var))
cg.register_entity(Valve, var)
await setup_valve_core_(var, config)
@ -203,3 +203,4 @@ async def valve_control_to_code(config, action_id, template_arg, args):
async def to_code(config):
cg.add_define("USE_VALVE")
cg.add_global(valve_ns.using)
cg.define_entity(Valve)

View file

@ -529,6 +529,8 @@ class EsphomeCore:
self.verbose = False
# Whether ESPHome was started in quiet mode
self.quiet = False
# A set of available entities
self.entities: set[str] = set()
def reset(self):
from esphome.pins import PIN_SCHEMA_REGISTRY
@ -553,6 +555,7 @@ class EsphomeCore:
self.loaded_integrations = set()
self.component_ids = set()
PIN_SCHEMA_REGISTRY.reset()
self.entities = set()
@property
def address(self) -> Optional[str]:
@ -779,6 +782,9 @@ class EsphomeCore:
_LOGGER.debug("Adding define: %s", define)
return define
def define_entity(self, class_):
self.entities.add(class_)
def add_platformio_option(self, key: str, value: Union[str, list[str]]) -> None:
new_val = value
old_val = self.platformio_options.get(key)

View file

@ -72,10 +72,16 @@
#ifdef USE_UPDATE
#include "esphome/components/update/update_entity.h"
#endif
#include "esphome/core/entities.h"
namespace esphome {
class Application {
template<typename Tuple> struct entityRegistry;
template<typename... Args> struct entityRegistry<std::tuple<Args...>> {
using type = std::tuple<std::vector<Args>...>;
};
public:
void pre_setup(const std::string &name, const std::string &friendly_name, const std::string &area,
const char *comment, const char *compilation_time, bool name_add_mac_suffix) {
@ -97,93 +103,22 @@ class Application {
this->compilation_time_ = compilation_time;
}
#ifdef USE_BINARY_SENSOR
void register_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
this->binary_sensors_.push_back(binary_sensor);
template<typename Entity> void register_entity(Entity *entity) {
get_by_type<std::vector<Entity *>>(entities_).push_back(entity);
}
#endif
#ifdef USE_SENSOR
void register_sensor(sensor::Sensor *sensor) { this->sensors_.push_back(sensor); }
#endif
#ifdef USE_SWITCH
void register_switch(switch_::Switch *a_switch) { this->switches_.push_back(a_switch); }
#endif
#ifdef USE_BUTTON
void register_button(button::Button *button) { this->buttons_.push_back(button); }
#endif
#ifdef USE_TEXT_SENSOR
void register_text_sensor(text_sensor::TextSensor *sensor) { this->text_sensors_.push_back(sensor); }
#endif
#ifdef USE_FAN
void register_fan(fan::Fan *state) { this->fans_.push_back(state); }
#endif
#ifdef USE_COVER
void register_cover(cover::Cover *cover) { this->covers_.push_back(cover); }
#endif
#ifdef USE_CLIMATE
void register_climate(climate::Climate *climate) { this->climates_.push_back(climate); }
#endif
#ifdef USE_LIGHT
void register_light(light::LightState *light) { this->lights_.push_back(light); }
#endif
#ifdef USE_NUMBER
void register_number(number::Number *number) { this->numbers_.push_back(number); }
#endif
#ifdef USE_DATETIME_DATE
void register_date(datetime::DateEntity *date) { this->dates_.push_back(date); }
#endif
#ifdef USE_DATETIME_TIME
void register_time(datetime::TimeEntity *time) { this->times_.push_back(time); }
#endif
#ifdef USE_DATETIME_DATETIME
void register_datetime(datetime::DateTimeEntity *datetime) { this->datetimes_.push_back(datetime); }
#endif
#ifdef USE_TEXT
void register_text(text::Text *text) { this->texts_.push_back(text); }
#endif
#ifdef USE_SELECT
void register_select(select::Select *select) { this->selects_.push_back(select); }
#endif
#ifdef USE_LOCK
void register_lock(lock::Lock *a_lock) { this->locks_.push_back(a_lock); }
#endif
#ifdef USE_VALVE
void register_valve(valve::Valve *valve) { this->valves_.push_back(valve); }
#endif
#ifdef USE_MEDIA_PLAYER
void register_media_player(media_player::MediaPlayer *media_player) { this->media_players_.push_back(media_player); }
#endif
#ifdef USE_ALARM_CONTROL_PANEL
void register_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
this->alarm_control_panels_.push_back(a_alarm_control_panel);
template<typename Entity> const std::vector<Entity *> &get_entities() {
return get_by_type<std::vector<Entity *>>(entities_);
}
#endif
#ifdef USE_EVENT
void register_event(event::Event *event) { this->events_.push_back(event); }
#endif
#ifdef USE_UPDATE
void register_update(update::UpdateEntity *update) { this->updates_.push_back(update); }
#endif
template<typename Entity> Entity *get_entity_by_key(uint32_t key, bool include_internal) {
for (auto *obj : this->get_entities<Entity>()) {
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) {
return obj;
}
}
return nullptr;
}
/// Register the component in this Application instance.
template<class C> C *register_component(C *c) {
@ -244,197 +179,142 @@ class Application {
uint32_t get_app_state() const { return this->app_state_; }
#ifdef USE_BINARY_SENSOR
const std::vector<binary_sensor::BinarySensor *> &get_binary_sensors() { return this->binary_sensors_; }
const std::vector<binary_sensor::BinarySensor *> &get_binary_sensors() {
return this->get_entities<binary_sensor::BinarySensor>();
}
binary_sensor::BinarySensor *get_binary_sensor_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->binary_sensors_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<binary_sensor::BinarySensor>(key, include_internal);
}
#endif
#ifdef USE_SWITCH
const std::vector<switch_::Switch *> &get_switches() { return this->switches_; }
const std::vector<switch_::Switch *> &get_switches() { return this->get_entities<switch_::Switch>(); }
switch_::Switch *get_switch_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->switches_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<switch_::Switch>(key, include_internal);
}
#endif
#ifdef USE_BUTTON
const std::vector<button::Button *> &get_buttons() { return this->buttons_; }
const std::vector<button::Button *> &get_buttons() { return this->get_entities<button::Button>(); }
button::Button *get_button_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->buttons_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<button::Button>(key, include_internal);
}
#endif
#ifdef USE_SENSOR
const std::vector<sensor::Sensor *> &get_sensors() { return this->sensors_; }
const std::vector<sensor::Sensor *> &get_sensors() { return this->get_entities<sensor::Sensor>(); }
sensor::Sensor *get_sensor_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->sensors_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<sensor::Sensor>(key, include_internal);
}
#endif
#ifdef USE_TEXT_SENSOR
const std::vector<text_sensor::TextSensor *> &get_text_sensors() { return this->text_sensors_; }
const std::vector<text_sensor::TextSensor *> &get_text_sensors() {
return this->get_entities<text_sensor::TextSensor>();
}
text_sensor::TextSensor *get_text_sensor_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->text_sensors_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<text_sensor::TextSensor>(key, include_internal);
}
#endif
#ifdef USE_FAN
const std::vector<fan::Fan *> &get_fans() { return this->fans_; }
const std::vector<fan::Fan *> &get_fans() { return this->get_entities<fan::Fan>(); }
fan::Fan *get_fan_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->fans_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<fan::Fan>(key, include_internal);
}
#endif
#ifdef USE_COVER
const std::vector<cover::Cover *> &get_covers() { return this->covers_; }
const std::vector<cover::Cover *> &get_covers() { return this->get_entities<cover::Cover>(); }
cover::Cover *get_cover_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->covers_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<cover::Cover>(key, include_internal);
}
#endif
#ifdef USE_LIGHT
const std::vector<light::LightState *> &get_lights() { return this->lights_; }
const std::vector<light::LightState *> &get_lights() { return this->get_entities<light::LightState>(); }
light::LightState *get_light_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->lights_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<light::LightState>(key, include_internal);
}
#endif
#ifdef USE_CLIMATE
const std::vector<climate::Climate *> &get_climates() { return this->climates_; }
const std::vector<climate::Climate *> &get_climates() { return this->get_entities<climate::Climate>(); }
climate::Climate *get_climate_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->climates_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<climate::Climate>(key, include_internal);
}
#endif
#ifdef USE_NUMBER
const std::vector<number::Number *> &get_numbers() { return this->numbers_; }
const std::vector<number::Number *> &get_numbers() { return this->get_entities<number::Number>(); }
number::Number *get_number_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->numbers_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<number::Number>(key, include_internal);
}
#endif
#ifdef USE_DATETIME_DATE
const std::vector<datetime::DateEntity *> &get_dates() { return this->dates_; }
const std::vector<datetime::DateEntity *> &get_dates() { return this->get_entities<datetime::DateEntity>(); }
datetime::DateEntity *get_date_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->dates_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<datetime::DateEntity>(key, include_internal);
}
#endif
#ifdef USE_DATETIME_TIME
const std::vector<datetime::TimeEntity *> &get_times() { return this->times_; }
const std::vector<datetime::TimeEntity *> &get_times() { return this->get_entities<datetime::TimeEntity>(); }
datetime::TimeEntity *get_time_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->times_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<datetime::TimeEntity>(key, include_internal);
}
#endif
#ifdef USE_DATETIME_DATETIME
const std::vector<datetime::DateTimeEntity *> &get_datetimes() { return this->datetimes_; }
const std::vector<datetime::DateTimeEntity *> &get_datetimes() {
return this->get_entities<datetime::DateTimeEntity>();
}
datetime::DateTimeEntity *get_datetime_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->datetimes_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<datetime::DateTimeEntity>(key, include_internal);
}
#endif
#ifdef USE_TEXT
const std::vector<text::Text *> &get_texts() { return this->texts_; }
const std::vector<text::Text *> &get_texts() { return this->get_entities<text::Text>(); }
text::Text *get_text_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->texts_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<text::Text>(key, include_internal);
}
#endif
#ifdef USE_SELECT
const std::vector<select::Select *> &get_selects() { return this->selects_; }
const std::vector<select::Select *> &get_selects() { return this->get_entities<select::Select>(); }
select::Select *get_select_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->selects_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<select::Select>(key, include_internal);
}
#endif
#ifdef USE_LOCK
const std::vector<lock::Lock *> &get_locks() { return this->locks_; }
const std::vector<lock::Lock *> &get_locks() { return this->get_entities<lock::Lock>(); }
lock::Lock *get_lock_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->locks_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<lock::Lock>(key, include_internal);
}
#endif
#ifdef USE_VALVE
const std::vector<valve::Valve *> &get_valves() { return this->valves_; }
const std::vector<valve::Valve *> &get_valves() { return this->get_entities<valve::Valve>(); }
valve::Valve *get_valve_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->valves_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<valve::Valve>(key, include_internal);
}
#endif
#ifdef USE_MEDIA_PLAYER
const std::vector<media_player::MediaPlayer *> &get_media_players() { return this->media_players_; }
const std::vector<media_player::MediaPlayer *> &get_media_players() {
return this->get_entities<media_player::MediaPlayer>();
}
media_player::MediaPlayer *get_media_player_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->media_players_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<media_player::MediaPlayer>(key, include_internal);
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
const std::vector<alarm_control_panel::AlarmControlPanel *> &get_alarm_control_panels() {
return this->alarm_control_panels_;
return this->get_entities<alarm_control_panel::AlarmControlPanel>();
}
alarm_control_panel::AlarmControlPanel *get_alarm_control_panel_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->alarm_control_panels_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<alarm_control_panel::AlarmControlPanel>(key, include_internal);
}
#endif
#ifdef USE_EVENT
const std::vector<event::Event *> &get_events() { return this->events_; }
const std::vector<event::Event *> &get_events() { return this->get_entities<event::Event>(); }
event::Event *get_event_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->events_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<event::Event>(key, include_internal);
}
#endif
#ifdef USE_UPDATE
const std::vector<update::UpdateEntity *> &get_updates() { return this->updates_; }
const std::vector<update::UpdateEntity *> &get_updates() { return this->get_entities<update::UpdateEntity>(); }
update::UpdateEntity *get_update_by_key(uint32_t key, bool include_internal = false) {
for (auto *obj : this->updates_)
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal()))
return obj;
return nullptr;
return this->get_entity_by_key<update::UpdateEntity>(key, include_internal);
}
#endif
@ -452,70 +332,6 @@ class Application {
std::vector<Component *> components_{};
std::vector<Component *> looping_components_{};
#ifdef USE_BINARY_SENSOR
std::vector<binary_sensor::BinarySensor *> binary_sensors_{};
#endif
#ifdef USE_SWITCH
std::vector<switch_::Switch *> switches_{};
#endif
#ifdef USE_BUTTON
std::vector<button::Button *> buttons_{};
#endif
#ifdef USE_EVENT
std::vector<event::Event *> events_{};
#endif
#ifdef USE_SENSOR
std::vector<sensor::Sensor *> sensors_{};
#endif
#ifdef USE_TEXT_SENSOR
std::vector<text_sensor::TextSensor *> text_sensors_{};
#endif
#ifdef USE_FAN
std::vector<fan::Fan *> fans_{};
#endif
#ifdef USE_COVER
std::vector<cover::Cover *> covers_{};
#endif
#ifdef USE_CLIMATE
std::vector<climate::Climate *> climates_{};
#endif
#ifdef USE_LIGHT
std::vector<light::LightState *> lights_{};
#endif
#ifdef USE_NUMBER
std::vector<number::Number *> numbers_{};
#endif
#ifdef USE_DATETIME_DATE
std::vector<datetime::DateEntity *> dates_{};
#endif
#ifdef USE_DATETIME_TIME
std::vector<datetime::TimeEntity *> times_{};
#endif
#ifdef USE_DATETIME_DATETIME
std::vector<datetime::DateTimeEntity *> datetimes_{};
#endif
#ifdef USE_SELECT
std::vector<select::Select *> selects_{};
#endif
#ifdef USE_TEXT
std::vector<text::Text *> texts_{};
#endif
#ifdef USE_LOCK
std::vector<lock::Lock *> locks_{};
#endif
#ifdef USE_VALVE
std::vector<valve::Valve *> valves_{};
#endif
#ifdef USE_MEDIA_PLAYER
std::vector<media_player::MediaPlayer *> media_players_{};
#endif
#ifdef USE_ALARM_CONTROL_PANEL
std::vector<alarm_control_panel::AlarmControlPanel *> alarm_control_panels_{};
#endif
#ifdef USE_UPDATE
std::vector<update::UpdateEntity *> updates_{};
#endif
std::string name_;
std::string friendly_name_;
std::string area_;
@ -526,6 +342,7 @@ class Application {
uint32_t loop_interval_{16};
size_t dump_config_at_{SIZE_MAX};
uint32_t app_state_{0};
entityRegistry<entities_t>::type entities_;
};
/// Global storage of Application pointer - only one Application can exist.

78
esphome/core/entities.h Normal file
View file

@ -0,0 +1,78 @@
#pragma once
// This file is not used by the runtime, instead, a version is generated during
// compilation with only the relevant feature flags for the current build.
//
// This file is only used by static analyzers and IDEs.
namespace esphome {
namespace update {
class UpdateEntity;
}
namespace alarm_control_panel {
class AlarmControlPanel;
}
namespace number {
class Number;
}
namespace light {
class LightState;
}
namespace switch_ {
class Switch;
}
namespace climate {
class Climate;
}
namespace fan {
class Fan;
}
namespace datetime {
class DateTimeEntity;
}
namespace binary_sensor {
class BinarySensor;
}
namespace datetime {
class TimeEntity;
}
namespace text {
class Text;
}
namespace lock {
class Lock;
}
namespace event {
class Event;
}
namespace text_sensor {
class TextSensor;
}
namespace datetime {
class DateEntity;
}
namespace cover {
class Cover;
}
namespace sensor {
class Sensor;
}
namespace select {
class Select;
}
namespace valve {
class Valve;
}
namespace button {
class Button;
}
namespace media_player {
class MediaPlayer;
}
using entities_t =
std::tuple<update::UpdateEntity *, alarm_control_panel::AlarmControlPanel *, number::Number *, light::LightState *,
switch_::Switch *, climate::Climate *, fan::Fan *, datetime::DateTimeEntity *,
binary_sensor::BinarySensor *, datetime::TimeEntity *, text::Text *, lock::Lock *, event::Event *,
text_sensor::TextSensor *, datetime::DateEntity *, cover::Cover *, sensor::Sensor *, select::Select *,
valve::Valve *, button::Button *, media_player::MediaPlayer *>;
} // namespace esphome

View file

@ -715,4 +715,22 @@ std::string hexencode(const T &data) {
///@}
namespace detail {
// Helper struct to get the index of a type T in a parameter pack
template<typename T, typename... Args> struct index_of;
template<typename T, typename... Args> struct index_of<T, T, Args...> {
static constexpr size_t value = 0; // NOLINT(readability-identifier-naming)
};
template<typename T, typename U, typename... Args> struct index_of<T, U, Args...> {
static constexpr size_t value = 1 + index_of<T, Args...>::value; // NOLINT(readability-identifier-naming)
};
} // end namespace detail
template<typename T, typename... Args> T &get_by_type(std::tuple<Args...> &tup) {
return std::get<detail::index_of<T, Args...>::value>(tup);
}
} // namespace esphome

View file

@ -619,6 +619,16 @@ def add_define(name: str, value: SafeExpType = None):
CORE.add_define(Define(name, safe_exp(value)))
def register_entity(class_, var):
"""Add an entity to the codegen section."""
add(MockObj(f"App.register_entity<{class_}>")(var))
def define_entity(class_):
"""Add a entity to std::tuple inside the auto-generated entities.h file."""
CORE.define_entity(str(class_))
def add_platformio_option(key: str, value: Union[str, list[str]]):
CORE.add_platformio_option(key, value)

View file

@ -216,8 +216,16 @@ VERSION_H_FORMAT = """\
#define ESPHOME_VERSION "{}"
#define ESPHOME_VERSION_CODE VERSION_CODE({}, {}, {})
"""
ENTITIES_H_FORMAT = """\
#pragma once
namespace esphome {{
{}
using entities_t = std::tuple<{}>;
}}
"""
DEFINES_H_TARGET = "esphome/core/defines.h"
VERSION_H_TARGET = "esphome/core/version.h"
ENTITIES_H_TARGET = "esphome/core/entities.h"
ESPHOME_README_TXT = """
THIS DIRECTORY IS AUTO-GENERATED, DO NOT MODIFY
@ -251,7 +259,9 @@ def copy_src_tree():
include_s = "\n".join(include_l)
source_files_copy = source_files_map.copy()
ignore_targets = [Path(x) for x in (DEFINES_H_TARGET, VERSION_H_TARGET)]
ignore_targets = [
Path(x) for x in (DEFINES_H_TARGET, VERSION_H_TARGET, ENTITIES_H_TARGET)
]
for t in ignore_targets:
source_files_copy.pop(t)
@ -290,6 +300,9 @@ def copy_src_tree():
write_file_if_changed(
CORE.relative_src_path("esphome", "core", "version.h"), generate_version_h()
)
write_file_if_changed(
CORE.relative_src_path("esphome", "core", "entities.h"), generate_entities_h()
)
if CORE.is_esp32:
from esphome.components.esp32 import copy_files
@ -327,6 +340,20 @@ def generate_version_h():
)
def generate_entities_h():
forward_declaration_l = []
entities_l = []
for type in CORE.entities:
namespace = type.split("::")[0]
class_ = type.split("::")[1]
forward_declaration_l += [f"""namespace {namespace} {{class {class_}; }}"""]
entities_l += [f"""{type} *"""]
return ENTITIES_H_FORMAT.format(
"\n".join(forward_declaration_l), ", ".join(entities_l)
)
def write_cpp(code_s):
path = CORE.relative_src_path("main.cpp")
if os.path.isfile(path):

View file

@ -14,7 +14,7 @@ def test_binary_sensor_is_setup(generate_main):
# Then
assert "new gpio::GPIOBinarySensor();" in main_cpp
assert "App.register_binary_sensor" in main_cpp
assert "App.register_entity<binary_sensor::BinarySensor>" in main_cpp
def test_binary_sensor_sets_mandatory_fields(generate_main):

View file

@ -12,7 +12,7 @@ def test_button_is_setup(generate_main):
# Then
assert "new wake_on_lan::WakeOnLanButton();" in main_cpp
assert "App.register_button" in main_cpp
assert "App.register_entity<button::Button>" in main_cpp
assert "App.register_component" in main_cpp

View file

@ -12,7 +12,7 @@ def test_text_is_setup(generate_main):
# Then
assert "new template_::TemplateText();" in main_cpp
assert "App.register_text" in main_cpp
assert "App.register_entity<text::Text>" in main_cpp
def test_text_sets_mandatory_fields(generate_main):

View file

@ -12,7 +12,7 @@ def test_text_sensor_is_setup(generate_main):
# Then
assert "new template_::TemplateTextSensor();" in main_cpp
assert "App.register_text_sensor" in main_cpp
assert "App.register_entity<text_sensor::TextSensor>" in main_cpp
def test_text_sensor_sets_mandatory_fields(generate_main):