Refactor entity lookup methods with macros in preparation for device_id support (#9371)

This commit is contained in:
J. Nick Koston 2025-07-07 15:49:23 -05:00 committed by GitHub
parent 3976fd02ea
commit fe258e1007
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 225 deletions

View File

@ -42,6 +42,19 @@ static const char *const TAG = "api.connection";
static const int CAMERA_STOP_STREAM = 5000;
#endif
// Helper macro for entity command handlers - gets entity by key, returns if not found, and creates call object
#define ENTITY_COMMAND_MAKE_CALL(entity_type, entity_var, getter_name) \
entity_type *entity_var = App.get_##getter_name##_by_key(msg.key); \
if ((entity_var) == nullptr) \
return; \
auto call = (entity_var)->make_call();
// Helper macro for entity command handlers that don't use make_call() - gets entity by key and returns if not found
#define ENTITY_COMMAND_GET(entity_type, entity_var, getter_name) \
entity_type *entity_var = App.get_##getter_name##_by_key(msg.key); \
if ((entity_var) == nullptr) \
return;
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
: parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) {
#if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE)
@ -361,11 +374,7 @@ uint16_t APIConnection::try_send_cover_info(EntityBase *entity, APIConnection *c
return encode_message_to_buffer(msg, ListEntitiesCoverResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::cover_command(const CoverCommandRequest &msg) {
cover::Cover *cover = App.get_cover_by_key(msg.key);
if (cover == nullptr)
return;
auto call = cover->make_call();
ENTITY_COMMAND_MAKE_CALL(cover::Cover, cover, cover)
if (msg.has_legacy_command) {
switch (msg.legacy_command) {
case enums::LEGACY_COVER_COMMAND_OPEN:
@ -427,11 +436,7 @@ uint16_t APIConnection::try_send_fan_info(EntityBase *entity, APIConnection *con
return encode_message_to_buffer(msg, ListEntitiesFanResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::fan_command(const FanCommandRequest &msg) {
fan::Fan *fan = App.get_fan_by_key(msg.key);
if (fan == nullptr)
return;
auto call = fan->make_call();
ENTITY_COMMAND_MAKE_CALL(fan::Fan, fan, fan)
if (msg.has_state)
call.set_state(msg.state);
if (msg.has_oscillating)
@ -504,11 +509,7 @@ uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *c
return encode_message_to_buffer(msg, ListEntitiesLightResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::light_command(const LightCommandRequest &msg) {
light::LightState *light = App.get_light_by_key(msg.key);
if (light == nullptr)
return;
auto call = light->make_call();
ENTITY_COMMAND_MAKE_CALL(light::LightState, light, light)
if (msg.has_state)
call.set_state(msg.state);
if (msg.has_brightness)
@ -597,9 +598,7 @@ uint16_t APIConnection::try_send_switch_info(EntityBase *entity, APIConnection *
return encode_message_to_buffer(msg, ListEntitiesSwitchResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::switch_command(const SwitchCommandRequest &msg) {
switch_::Switch *a_switch = App.get_switch_by_key(msg.key);
if (a_switch == nullptr)
return;
ENTITY_COMMAND_GET(switch_::Switch, a_switch, switch)
if (msg.state) {
a_switch->turn_on();
@ -708,11 +707,7 @@ uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection
return encode_message_to_buffer(msg, ListEntitiesClimateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::climate_command(const ClimateCommandRequest &msg) {
climate::Climate *climate = App.get_climate_by_key(msg.key);
if (climate == nullptr)
return;
auto call = climate->make_call();
ENTITY_COMMAND_MAKE_CALL(climate::Climate, climate, climate)
if (msg.has_mode)
call.set_mode(static_cast<climate::ClimateMode>(msg.mode));
if (msg.has_target_temperature)
@ -767,11 +762,7 @@ uint16_t APIConnection::try_send_number_info(EntityBase *entity, APIConnection *
return encode_message_to_buffer(msg, ListEntitiesNumberResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::number_command(const NumberCommandRequest &msg) {
number::Number *number = App.get_number_by_key(msg.key);
if (number == nullptr)
return;
auto call = number->make_call();
ENTITY_COMMAND_MAKE_CALL(number::Number, number, number)
call.set_value(msg.state);
call.perform();
}
@ -801,11 +792,7 @@ uint16_t APIConnection::try_send_date_info(EntityBase *entity, APIConnection *co
return encode_message_to_buffer(msg, ListEntitiesDateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::date_command(const DateCommandRequest &msg) {
datetime::DateEntity *date = App.get_date_by_key(msg.key);
if (date == nullptr)
return;
auto call = date->make_call();
ENTITY_COMMAND_MAKE_CALL(datetime::DateEntity, date, date)
call.set_date(msg.year, msg.month, msg.day);
call.perform();
}
@ -835,11 +822,7 @@ uint16_t APIConnection::try_send_time_info(EntityBase *entity, APIConnection *co
return encode_message_to_buffer(msg, ListEntitiesTimeResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::time_command(const TimeCommandRequest &msg) {
datetime::TimeEntity *time = App.get_time_by_key(msg.key);
if (time == nullptr)
return;
auto call = time->make_call();
ENTITY_COMMAND_MAKE_CALL(datetime::TimeEntity, time, time)
call.set_time(msg.hour, msg.minute, msg.second);
call.perform();
}
@ -871,11 +854,7 @@ uint16_t APIConnection::try_send_datetime_info(EntityBase *entity, APIConnection
return encode_message_to_buffer(msg, ListEntitiesDateTimeResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
datetime::DateTimeEntity *datetime = App.get_datetime_by_key(msg.key);
if (datetime == nullptr)
return;
auto call = datetime->make_call();
ENTITY_COMMAND_MAKE_CALL(datetime::DateTimeEntity, datetime, datetime)
call.set_datetime(msg.epoch_seconds);
call.perform();
}
@ -909,11 +888,7 @@ uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *co
return encode_message_to_buffer(msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::text_command(const TextCommandRequest &msg) {
text::Text *text = App.get_text_by_key(msg.key);
if (text == nullptr)
return;
auto call = text->make_call();
ENTITY_COMMAND_MAKE_CALL(text::Text, text, text)
call.set_value(msg.state);
call.perform();
}
@ -945,11 +920,7 @@ uint16_t APIConnection::try_send_select_info(EntityBase *entity, APIConnection *
return encode_message_to_buffer(msg, ListEntitiesSelectResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::select_command(const SelectCommandRequest &msg) {
select::Select *select = App.get_select_by_key(msg.key);
if (select == nullptr)
return;
auto call = select->make_call();
ENTITY_COMMAND_MAKE_CALL(select::Select, select, select)
call.set_option(msg.state);
call.perform();
}
@ -966,10 +937,7 @@ uint16_t APIConnection::try_send_button_info(EntityBase *entity, APIConnection *
return encode_message_to_buffer(msg, ListEntitiesButtonResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void esphome::api::APIConnection::button_command(const ButtonCommandRequest &msg) {
button::Button *button = App.get_button_by_key(msg.key);
if (button == nullptr)
return;
ENTITY_COMMAND_GET(button::Button, button, button)
button->press();
}
#endif
@ -1000,9 +968,7 @@ uint16_t APIConnection::try_send_lock_info(EntityBase *entity, APIConnection *co
return encode_message_to_buffer(msg, ListEntitiesLockResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::lock_command(const LockCommandRequest &msg) {
lock::Lock *a_lock = App.get_lock_by_key(msg.key);
if (a_lock == nullptr)
return;
ENTITY_COMMAND_GET(lock::Lock, a_lock, lock)
switch (msg.command) {
case enums::LOCK_UNLOCK:
@ -1045,11 +1011,7 @@ uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *c
return encode_message_to_buffer(msg, ListEntitiesValveResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::valve_command(const ValveCommandRequest &msg) {
valve::Valve *valve = App.get_valve_by_key(msg.key);
if (valve == nullptr)
return;
auto call = valve->make_call();
ENTITY_COMMAND_MAKE_CALL(valve::Valve, valve, valve)
if (msg.has_position)
call.set_position(msg.position);
if (msg.stop)
@ -1096,11 +1058,7 @@ uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnec
return encode_message_to_buffer(msg, ListEntitiesMediaPlayerResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
media_player::MediaPlayer *media_player = App.get_media_player_by_key(msg.key);
if (media_player == nullptr)
return;
auto call = media_player->make_call();
ENTITY_COMMAND_MAKE_CALL(media_player::MediaPlayer, media_player, media_player)
if (msg.has_command) {
call.set_command(static_cast<media_player::MediaPlayerCommand>(msg.command));
}
@ -1346,11 +1304,7 @@ uint16_t APIConnection::try_send_alarm_control_panel_info(EntityBase *entity, AP
is_single);
}
void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) {
alarm_control_panel::AlarmControlPanel *a_alarm_control_panel = App.get_alarm_control_panel_by_key(msg.key);
if (a_alarm_control_panel == nullptr)
return;
auto call = a_alarm_control_panel->make_call();
ENTITY_COMMAND_MAKE_CALL(alarm_control_panel::AlarmControlPanel, a_alarm_control_panel, alarm_control_panel)
switch (msg.command) {
case enums::ALARM_CONTROL_PANEL_DISARM:
call.disarm();
@ -1438,9 +1392,7 @@ uint16_t APIConnection::try_send_update_info(EntityBase *entity, APIConnection *
return encode_message_to_buffer(msg, ListEntitiesUpdateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::update_command(const UpdateCommandRequest &msg) {
update::UpdateEntity *update = App.get_update_by_key(msg.key);
if (update == nullptr)
return;
ENTITY_COMMAND_GET(update::UpdateEntity, update, update)
switch (msg.command) {
case enums::UPDATE_COMMAND_UPDATE:

View File

@ -368,6 +368,17 @@ class Application {
uint8_t get_app_state() const { return this->app_state_; }
// Helper macro for entity getter method declarations - reduces code duplication
// When USE_DEVICE_ID is enabled in the future, this can be conditionally compiled to add device_id parameter
#define GET_ENTITY_METHOD(entity_type, entity_name, entities_member) \
entity_type *get_##entity_name##_by_key(uint32_t key, bool include_internal = false) { \
for (auto *obj : this->entities_member##_) { \
if (obj->get_object_id_hash() == key && (include_internal || !obj->is_internal())) \
return obj; \
} \
return nullptr; \
}
#ifdef USE_DEVICES
const std::vector<Device *> &get_devices() { return this->devices_; }
#endif
@ -376,218 +387,92 @@ class Application {
#endif
#ifdef USE_BINARY_SENSOR
const std::vector<binary_sensor::BinarySensor *> &get_binary_sensors() { return this->binary_sensors_; }
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;
}
GET_ENTITY_METHOD(binary_sensor::BinarySensor, binary_sensor, binary_sensors)
#endif
#ifdef USE_SWITCH
const std::vector<switch_::Switch *> &get_switches() { return this->switches_; }
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;
}
GET_ENTITY_METHOD(switch_::Switch, switch, switches)
#endif
#ifdef USE_BUTTON
const std::vector<button::Button *> &get_buttons() { return this->buttons_; }
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;
}
GET_ENTITY_METHOD(button::Button, button, buttons)
#endif
#ifdef USE_SENSOR
const std::vector<sensor::Sensor *> &get_sensors() { return this->sensors_; }
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;
}
GET_ENTITY_METHOD(sensor::Sensor, sensor, sensors)
#endif
#ifdef USE_TEXT_SENSOR
const std::vector<text_sensor::TextSensor *> &get_text_sensors() { return this->text_sensors_; }
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;
}
GET_ENTITY_METHOD(text_sensor::TextSensor, text_sensor, text_sensors)
#endif
#ifdef USE_FAN
const std::vector<fan::Fan *> &get_fans() { return this->fans_; }
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;
}
GET_ENTITY_METHOD(fan::Fan, fan, fans)
#endif
#ifdef USE_COVER
const std::vector<cover::Cover *> &get_covers() { return this->covers_; }
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;
}
GET_ENTITY_METHOD(cover::Cover, cover, covers)
#endif
#ifdef USE_LIGHT
const std::vector<light::LightState *> &get_lights() { return this->lights_; }
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;
}
GET_ENTITY_METHOD(light::LightState, light, lights)
#endif
#ifdef USE_CLIMATE
const std::vector<climate::Climate *> &get_climates() { return this->climates_; }
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;
}
GET_ENTITY_METHOD(climate::Climate, climate, climates)
#endif
#ifdef USE_NUMBER
const std::vector<number::Number *> &get_numbers() { return this->numbers_; }
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;
}
GET_ENTITY_METHOD(number::Number, number, numbers)
#endif
#ifdef USE_DATETIME_DATE
const std::vector<datetime::DateEntity *> &get_dates() { return this->dates_; }
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;
}
GET_ENTITY_METHOD(datetime::DateEntity, date, dates)
#endif
#ifdef USE_DATETIME_TIME
const std::vector<datetime::TimeEntity *> &get_times() { return this->times_; }
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;
}
GET_ENTITY_METHOD(datetime::TimeEntity, time, times)
#endif
#ifdef USE_DATETIME_DATETIME
const std::vector<datetime::DateTimeEntity *> &get_datetimes() { return this->datetimes_; }
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;
}
GET_ENTITY_METHOD(datetime::DateTimeEntity, datetime, datetimes)
#endif
#ifdef USE_TEXT
const std::vector<text::Text *> &get_texts() { return this->texts_; }
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;
}
GET_ENTITY_METHOD(text::Text, text, texts)
#endif
#ifdef USE_SELECT
const std::vector<select::Select *> &get_selects() { return this->selects_; }
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;
}
GET_ENTITY_METHOD(select::Select, select, selects)
#endif
#ifdef USE_LOCK
const std::vector<lock::Lock *> &get_locks() { return this->locks_; }
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;
}
GET_ENTITY_METHOD(lock::Lock, lock, locks)
#endif
#ifdef USE_VALVE
const std::vector<valve::Valve *> &get_valves() { return this->valves_; }
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;
}
GET_ENTITY_METHOD(valve::Valve, valve, valves)
#endif
#ifdef USE_MEDIA_PLAYER
const std::vector<media_player::MediaPlayer *> &get_media_players() { return this->media_players_; }
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;
}
GET_ENTITY_METHOD(media_player::MediaPlayer, media_player, media_players)
#endif
#ifdef USE_ALARM_CONTROL_PANEL
const std::vector<alarm_control_panel::AlarmControlPanel *> &get_alarm_control_panels() {
return this->alarm_control_panels_;
}
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;
}
GET_ENTITY_METHOD(alarm_control_panel::AlarmControlPanel, alarm_control_panel, alarm_control_panels)
#endif
#ifdef USE_EVENT
const std::vector<event::Event *> &get_events() { return this->events_; }
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;
}
GET_ENTITY_METHOD(event::Event, event, events)
#endif
#ifdef USE_UPDATE
const std::vector<update::UpdateEntity *> &get_updates() { return this->updates_; }
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;
}
GET_ENTITY_METHOD(update::UpdateEntity, update, updates)
#endif
Scheduler scheduler;