diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 7f84f2f24..2910643df 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -85,6 +85,7 @@ CONF_HOMEASSISTANT_SERVICES = "homeassistant_services" CONF_HOMEASSISTANT_STATES = "homeassistant_states" CONF_LISTEN_BACKLOG = "listen_backlog" CONF_MAX_SEND_QUEUE = "max_send_queue" +CONF_STATE_SUBSCRIPTION_ONLY = "state_subscription_only" def validate_encryption_key(value): @@ -537,9 +538,24 @@ async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, arg return var -@automation.register_condition("api.connected", APIConnectedCondition, {}) +API_CONNECTED_CONDITION_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.use_id(APIServer), + cv.Optional(CONF_STATE_SUBSCRIPTION_ONLY, default=False): cv.templatable( + cv.boolean + ), + } +) + + +@automation.register_condition( + "api.connected", APIConnectedCondition, API_CONNECTED_CONDITION_SCHEMA +) async def api_connected_to_code(config, condition_id, template_arg, args): - return cg.new_Pvariable(condition_id, template_arg) + var = cg.new_Pvariable(condition_id, template_arg) + templ = await cg.templatable(config[CONF_STATE_SUBSCRIPTION_ONLY], args, cg.bool_) + cg.add(var.set_state_subscription_only(templ)) + return var def FILTER_SOURCE_FILES() -> list[str]: diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 18601d74f..d33c98abc 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -528,7 +528,18 @@ void APIServer::request_time() { } #endif -bool APIServer::is_connected() const { return !this->clients_.empty(); } +bool APIServer::is_connected(bool state_subscription_only) const { + if (!state_subscription_only) { + return !this->clients_.empty(); + } + + for (const auto &client : this->clients_) { + if (client->flags_.state_subscription) { + return true; + } + } + return false; +} void APIServer::on_shutdown() { this->shutting_down_ = true; diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index a3a082e16..786cd63f4 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -150,7 +150,7 @@ class APIServer : public Component, public Controller { void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg); #endif - bool is_connected() const; + bool is_connected(bool state_subscription_only = false) const; #ifdef USE_API_HOMEASSISTANT_STATES struct HomeAssistantStateSubscription { @@ -236,8 +236,11 @@ class APIServer : public Component, public Controller { extern APIServer *global_api_server; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) template class APIConnectedCondition : public Condition { + TEMPLATABLE_VALUE(bool, state_subscription_only) public: - bool check(const Ts &...x) override { return global_api_server->is_connected(); } + bool check(const Ts &...x) override { + return global_api_server->is_connected(this->state_subscription_only_.value(x...)); + } }; } // namespace esphome::api diff --git a/tests/components/api/common-base.yaml b/tests/components/api/common-base.yaml index fc53b8ac7..0416cebf9 100644 --- a/tests/components/api/common-base.yaml +++ b/tests/components/api/common-base.yaml @@ -1,6 +1,10 @@ esphome: on_boot: then: + - wait_until: + condition: + api.connected: + state_subscription_only: true - homeassistant.event: event: esphome.button_pressed data: