From bcfbcd9578148dc71241a6dd174b47ca4c0fa358 Mon Sep 17 00:00:00 2001 From: Cossid <83468485+Cossid@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:38:52 -0500 Subject: [PATCH] Add area (zone) to esphome core config to be suggested through API and MQTT. (#5602) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/api.proto | 2 ++ esphome/components/api/api_connection.cpp | 1 + esphome/components/api/api_pb2.cpp | 9 +++++++++ esphome/components/api/api_pb2.h | 1 + esphome/components/mqtt/mqtt_component.cpp | 2 ++ esphome/const.py | 1 + esphome/core/__init__.py | 3 +++ esphome/core/application.h | 10 ++++++++-- esphome/core/config.py | 3 +++ tests/dummy_main.cpp | 2 +- 10 files changed, 31 insertions(+), 3 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index ca3071d6d9..2f33750686 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -217,6 +217,8 @@ message DeviceInfoResponse { string friendly_name = 13; uint32 voice_assistant_version = 14; + + string suggested_area = 16; } message ListEntitiesRequest { diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index bc61271e93..03eaa159c7 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1084,6 +1084,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { resp.uses_password = this->parent_->uses_password(); resp.name = App.get_name(); resp.friendly_name = App.get_friendly_name(); + resp.suggested_area = App.get_area(); resp.mac_address = get_mac_address_pretty(); resp.esphome_version = ESPHOME_VERSION; resp.compilation_time = App.get_compilation_time(); diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index c070b3c988..1e97a57bb1 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -761,6 +761,10 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v this->friendly_name = value.as_string(); return true; } + case 16: { + this->suggested_area = value.as_string(); + return true; + } default: return false; } @@ -781,6 +785,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(12, this->manufacturer); buffer.encode_string(13, this->friendly_name); buffer.encode_uint32(14, this->voice_assistant_version); + buffer.encode_string(16, this->suggested_area); } #ifdef HAS_PROTO_MESSAGE_DUMP void DeviceInfoResponse::dump_to(std::string &out) const { @@ -849,6 +854,10 @@ void DeviceInfoResponse::dump_to(std::string &out) const { sprintf(buffer, "%" PRIu32, this->voice_assistant_version); out.append(buffer); out.append("\n"); + + out.append(" suggested_area: "); + out.append("'").append(this->suggested_area).append("'"); + out.append("\n"); out.append("}"); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index b935784831..a63e90b7b7 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -328,6 +328,7 @@ class DeviceInfoResponse : public ProtoMessage { std::string manufacturer{}; std::string friendly_name{}; uint32_t voice_assistant_version{0}; + std::string suggested_area{}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; diff --git a/esphome/components/mqtt/mqtt_component.cpp b/esphome/components/mqtt/mqtt_component.cpp index 571f5c8317..95dc082e84 100644 --- a/esphome/components/mqtt/mqtt_component.cpp +++ b/esphome/components/mqtt/mqtt_component.cpp @@ -136,6 +136,7 @@ bool MQTTComponent::send_discovery_() { if (node_friendly_name.empty()) { node_friendly_name = node_name; } + const std::string &node_area = App.get_area(); JsonObject device_info = root.createNestedObject(MQTT_DEVICE); device_info[MQTT_DEVICE_IDENTIFIERS] = get_mac_address(); @@ -143,6 +144,7 @@ bool MQTTComponent::send_discovery_() { device_info[MQTT_DEVICE_SW_VERSION] = "esphome v" ESPHOME_VERSION " " + App.get_compilation_time(); device_info[MQTT_DEVICE_MODEL] = ESPHOME_BOARD; device_info[MQTT_DEVICE_MANUFACTURER] = "espressif"; + device_info[MQTT_DEVICE_SUGGESTED_AREA] = node_area; }, 0, discovery_info.retain); } diff --git a/esphome/const.py b/esphome/const.py index 47eedc24b7..6dde15303a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -53,6 +53,7 @@ CONF_AND = "and" CONF_AP = "ap" CONF_APPARENT_POWER = "apparent_power" CONF_ARDUINO_VERSION = "arduino_version" +CONF_AREA = "area" CONF_ARGS = "args" CONF_ASSUMED_STATE = "assumed_state" CONF_AT = "at" diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 52c58cb54a..0b597e0c9e 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -464,6 +464,8 @@ class EsphomeCore: self.name: Optional[str] = None # The friendly name of the node self.friendly_name: Optional[str] = None + # The area / zone of the node + self.area: Optional[str] = None # Additional data components can store temporary data in # The first key to this dict should always be the integration name self.data = {} @@ -504,6 +506,7 @@ class EsphomeCore: self.dashboard = False self.name = None self.friendly_name = None + self.area = None self.data = {} self.config_path = None self.build_path = None diff --git a/esphome/core/application.h b/esphome/core/application.h index f2dbaa4db5..059e393912 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -59,8 +59,8 @@ namespace esphome { class Application { public: - void pre_setup(const std::string &name, const std::string &friendly_name, const char *comment, - const char *compilation_time, bool name_add_mac_suffix) { + 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) { arch_init(); this->name_add_mac_suffix_ = name_add_mac_suffix; if (name_add_mac_suffix) { @@ -74,6 +74,7 @@ class Application { this->name_ = name; this->friendly_name_ = friendly_name; } + this->area_ = area; this->comment_ = comment; this->compilation_time_ = compilation_time; } @@ -160,6 +161,10 @@ class Application { /// Get the friendly name of this Application set by pre_setup(). const std::string &get_friendly_name() const { return this->friendly_name_; } + + /// Get the area of this Application set by pre_setup(). + const std::string &get_area() const { return this->area_; } + /// Get the comment of this Application set by pre_setup(). std::string get_comment() const { return this->comment_; } @@ -395,6 +400,7 @@ class Application { std::string name_; std::string friendly_name_; + std::string area_; const char *comment_{nullptr}; const char *compilation_time_{nullptr}; bool name_add_mac_suffix_; diff --git a/esphome/core/config.py b/esphome/core/config.py index 1625644092..e4a1fdcafa 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -8,6 +8,7 @@ import esphome.config_validation as cv from esphome import automation from esphome.const import ( CONF_ARDUINO_VERSION, + CONF_AREA, CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_BUILD_PATH, @@ -126,6 +127,7 @@ CONFIG_SCHEMA = cv.All( { cv.Required(CONF_NAME): cv.valid_name, cv.Optional(CONF_FRIENDLY_NAME, ""): cv.string, + cv.Optional(CONF_AREA, ""): cv.string, cv.Optional(CONF_COMMENT): cv.string, cv.Required(CONF_BUILD_PATH): cv.string, cv.Optional(CONF_PLATFORMIO_OPTIONS, default={}): cv.Schema( @@ -350,6 +352,7 @@ async def to_code(config): cg.App.pre_setup( config[CONF_NAME], config[CONF_FRIENDLY_NAME], + config[CONF_AREA], config.get(CONF_COMMENT, ""), cg.RawExpression('__DATE__ ", " __TIME__'), config[CONF_NAME_ADD_MAC_SUFFIX], diff --git a/tests/dummy_main.cpp b/tests/dummy_main.cpp index 236b9f5fc2..da5c6d10d0 100644 --- a/tests/dummy_main.cpp +++ b/tests/dummy_main.cpp @@ -12,7 +12,7 @@ using namespace esphome; void setup() { - App.pre_setup("livingroom", "LivingRoom", "comment", __DATE__ ", " __TIME__, false); + App.pre_setup("livingroom", "LivingRoom", "LivingRoomArea", "comment", __DATE__ ", " __TIME__, false); auto *log = new logger::Logger(115200, 512); // NOLINT log->pre_setup(); log->set_uart_selection(logger::UART_SELECTION_UART0);