起因
笔者的很多服务都启用了mDNS,因此在使用ESP32做一些小制作时,需要使用mDNS来获取服务地址,如mqtt.local
、influxdb.local
等,故有了本文中的代码。
分析
mDNS组件在IDF v5.0大版本中被移除出默认的内部组件库中(详见参考1),因此需要修改之前的基础库代码,手动添加对应支持。在PlatformIO项目中,我将官方的源码下载到了本地,放在了third_party/mdns
目录下,然后在最外层的CMakeLists.txt中添加了一行list(APPEND EXTRA_COMPONENT_DIRS third_party)
来让编译系统知道这个目录下的第三方组件。接着,在看了官方的文档和源码后(详见参考2、参考3),对相关代码进行了封装,形成了自己的库文件,具体实现见下方代码。
实现
mdns.hpp
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #ifndef _mdns_hpp_ #define _mdns_hpp_
#include <string> #include <vector>
#include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "mdns.h"
namespace cubestone_wang {
namespace mdns {
class MDNS { public: static const char *const LOG_TAG; struct TxtItem { std::string Key; std::string Value; }; struct Service{ std::string InstanceName; std::string Type; std::string Proto; uint16_t Port; std::vector<TxtItem> Txt; }; static bool Start(const std::string &hostname, const std::string &instance_name="", const std::vector<Service> &services=std::vector<Service>()); static void Stop(); private: static bool start_flag; static SemaphoreHandle_t mutex; };
}
}
#endif
|
mdns.cpp
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| #include "esp_log.h"
#include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "mdns.h" #include "event_loop.hpp"
#include "mdns.hpp"
namespace cubestone_wang {
namespace mdns {
using namespace event_loop;
const char *const MDNS::LOG_TAG = "MDNS";
bool MDNS::start_flag = false;
SemaphoreHandle_t MDNS::mutex = xSemaphoreCreateMutex();
bool MDNS::Start(const std::string &hostname, const std::string &instance_name, const std::vector<Service> &services) { xSemaphoreTake(mutex, portMAX_DELAY); if (start_flag == true) { ESP_LOGI(LOG_TAG, "this has been started"); xSemaphoreGive(mutex); return false; } EventLoop::Init(); ESP_ERROR_CHECK(mdns_init()); ESP_ERROR_CHECK(mdns_hostname_set(hostname.c_str())); if (0 < instance_name.length()) { ESP_ERROR_CHECK(mdns_instance_name_set(instance_name.c_str())); } Service service; for (uint32_t index=0; index<services.size(); index++) { service = services[index]; ESP_ERROR_CHECK(mdns_service_add(NULL, service.Type.c_str(), service.Proto.c_str(), service.Port, NULL, 0)); for (uint32_t sub_index=0; sub_index<service.Txt.size(); sub_index++) { ESP_ERROR_CHECK(mdns_service_txt_item_set(service.Type.c_str(), service.Proto.c_str(), service.Txt[sub_index].Key.c_str(), service.Txt[sub_index].Key.c_str())); } if (0 < service.InstanceName.length()) { ESP_ERROR_CHECK(mdns_service_instance_name_set(service.Type.c_str(), service.Proto.c_str(), service.InstanceName.c_str())); } } start_flag = true; xSemaphoreGive(mutex); return true; }
void MDNS::Stop() { xSemaphoreTake(mutex, portMAX_DELAY); if (start_flag == false) { ESP_LOGD(LOG_TAG, "this has been stopped"); goto DONE; } mdns_free(); DONE: start_flag = false; xSemaphoreGive(mutex); return; }
}
}
|
主流程中在WiFi连接成功后,即可按需调用如下代码初始化mDNS
1 2 3 4 5 6 7 8 9
| auto mdns_config = (mdns::Config *)config::ConfigManager::Get(Application::mdns_config_name); if(!mdns::MDNS::Start(mdns_config->Hostname, mdns_config->InstanceName, mdns_config->services)) { std::string message = "mdns start failed"; reboot_for_failed_start(message); return; } ESP_LOGI(LOG_TAG, "mdns start success");
|
参考
- IDF mDNS组件移除内部组件库说明
- IDF mDNS组件官方文档
- IDF mDNS组件源码