#pragma once #include "esphome/core/component.h" #include "esphome/core/automation.h" #include "api_message.h" namespace esphome { namespace api { enum ServiceArgType { SERVICE_ARG_TYPE_BOOL = 0, SERVICE_ARG_TYPE_INT = 1, SERVICE_ARG_TYPE_FLOAT = 2, SERVICE_ARG_TYPE_STRING = 3, }; class ServiceTypeArgument { public: ServiceTypeArgument(const std::string &name, ServiceArgType type); const std::string &get_name() const; ServiceArgType get_type() const; protected: std::string name_; ServiceArgType type_; }; class ExecuteServiceArgument : public APIMessage { public: APIMessageType message_type() const override; template T get_value(); bool decode_varint(uint32_t field_id, uint32_t value) override; bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override; bool decode_32bit(uint32_t field_id, uint32_t value) override; protected: bool value_bool_{false}; int value_int_{0}; float value_float_{0.0f}; std::string value_string_{}; }; class ExecuteServiceRequest : public APIMessage { public: bool decode_length_delimited(uint32_t field_id, const uint8_t *value, size_t len) override; bool decode_32bit(uint32_t field_id, uint32_t value) override; APIMessageType message_type() const override; uint32_t get_key() const; const std::vector &get_args() const; protected: uint32_t key_; std::vector args_; }; class UserServiceDescriptor { public: virtual void encode_list_service_response(APIBuffer &buffer) = 0; virtual bool execute_service(const ExecuteServiceRequest &req) = 0; }; template class UserService : public UserServiceDescriptor, public Trigger { public: UserService(const std::string &name, const std::array &args); void encode_list_service_response(APIBuffer &buffer) override; bool execute_service(const ExecuteServiceRequest &req) override; protected: template void execute_(std::vector args, seq); std::string name_; uint32_t key_{0}; std::array args_; }; template template void UserService::execute_(std::vector args, seq) { this->trigger((args[S].get_value())...); } template void UserService::encode_list_service_response(APIBuffer &buffer) { // string name = 1; buffer.encode_string(1, this->name_); // fixed32 key = 2; buffer.encode_fixed32(2, this->key_); // repeated ListServicesArgument args = 3; for (auto &arg : this->args_) { auto nested = buffer.begin_nested(3); // string name = 1; buffer.encode_string(1, arg.get_name()); // Type type = 2; buffer.encode_int32(2, arg.get_type()); buffer.end_nested(nested); } } template bool UserService::execute_service(const ExecuteServiceRequest &req) { if (req.get_key() != this->key_) return false; if (req.get_args().size() != this->args_.size()) { return false; } this->execute_(req.get_args(), typename gens::type()); return true; } template UserService::UserService(const std::string &name, const std::array &args) : name_(name), args_(args) { this->key_ = fnv1_hash(this->name_); } template<> bool ExecuteServiceArgument::get_value(); template<> int ExecuteServiceArgument::get_value(); template<> float ExecuteServiceArgument::get_value(); template<> std::string ExecuteServiceArgument::get_value(); } // namespace api } // namespace esphome