Skip to content

Commit cb5f1dd

Browse files
committed
Merge branch 'thread/add_local_control' into 'master'
esp_rmaker: Add local control for Thread devices See merge request app-frameworks/esp-rainmaker!473
2 parents 4312ee5 + 3c01922 commit cb5f1dd

File tree

3 files changed

+122
-4
lines changed

3 files changed

+122
-4
lines changed

components/esp_rainmaker/Kconfig.projbuild

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ menu "ESP RainMaker Config"
176176
config ESP_RMAKER_LOCAL_CTRL_FEATURE_ENABLE
177177
bool "ESP RainMaker Local Control Feature"
178178
default n
179-
#TODO: Enable Local Control for Thread devices
180-
depends on ESP_RMAKER_NETWORK_OVER_WIFI
181179
select ESP_HTTPS_SERVER_ENABLE
182180
help
183181
Enabling this allows to discover and control the node over local Wi-Fi network.
@@ -191,7 +189,6 @@ menu "ESP RainMaker Config"
191189
config ESP_RMAKER_LOCAL_CTRL_AUTO_ENABLE
192190
bool "Auto ESP RainMaker Local Control"
193191
default n
194-
depends on ESP_RMAKER_NETWORK_OVER_WIFI
195192
select ESP_RMAKER_LOCAL_CTRL_FEATURE_ENABLE
196193
help
197194
Automatically enabled local control when RainMaker starts.

components/esp_rainmaker/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
## IDF Component Manager Manifest File
2-
version: "1.5.3"
2+
version: "1.5.4"
33
description: ESP RainMaker firmware agent
44
url: https://github.com/espressif/esp-rainmaker/tree/master/components/esp_rainmaker
55
repository: https://github.com/espressif/esp-rainmaker.git

components/esp_rainmaker/src/core/esp_rmaker_local_ctrl.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
#ifdef CONFIG_ESP_RMAKER_NETWORK_OVER_WIFI
2626
#include <mdns.h>
2727
#endif
28+
#ifdef CONFIG_ESP_RMAKER_NETWORK_OVER_THREAD
29+
#include <esp_openthread.h>
30+
#include <esp_openthread_lock.h>
31+
#include <openthread/srp_client.h>
32+
#include <openthread/srp_client_buffers.h>
33+
#endif /* CONFIG_ESP_RMAKER_NETWORK_OVER_THREAD */
2834
#include <esp_rmaker_utils.h>
2935

3036
#include <esp_idf_version.h>
@@ -272,6 +278,112 @@ static esp_err_t esp_rmaker_local_ctrl_service_disable(void)
272278
return ESP_OK;
273279
}
274280

281+
#ifdef CONFIG_ESP_RMAKER_NETWORK_OVER_THREAD
282+
#define SRP_MAX_HOST_NAME_LEN 32
283+
static char srp_host_name[SRP_MAX_HOST_NAME_LEN + 1];
284+
285+
static esp_err_t srp_client_set_host(const char *host_name)
286+
{
287+
if (!host_name || strlen(host_name) > 15) {
288+
return ESP_ERR_INVALID_ARG;
289+
}
290+
// Avoid adding the same host name multiple times
291+
if (strcmp(srp_host_name, host_name) != 0) {
292+
strncpy(srp_host_name, host_name, SRP_MAX_HOST_NAME_LEN);
293+
srp_host_name[strnlen(host_name, SRP_MAX_HOST_NAME_LEN)] = 0;
294+
esp_openthread_lock_acquire(portMAX_DELAY);
295+
otInstance *instance = esp_openthread_get_instance();
296+
if (otSrpClientSetHostName(instance, srp_host_name) != OT_ERROR_NONE) {
297+
esp_openthread_lock_release();
298+
return ESP_FAIL;
299+
}
300+
if (otSrpClientEnableAutoHostAddress(instance) != OT_ERROR_NONE) {
301+
esp_openthread_lock_release();
302+
return ESP_FAIL;
303+
}
304+
esp_openthread_lock_release();
305+
}
306+
return ESP_OK;
307+
}
308+
309+
static esp_err_t srp_client_add_local_ctrl_service(const char *serv_name)
310+
{
311+
static uint8_t rainmaker_node_id_txt_value[30];
312+
char *rmaker_node_id = esp_rmaker_get_node_id();
313+
if (rmaker_node_id == NULL || strlen(rmaker_node_id) > sizeof(rainmaker_node_id_txt_value)) {
314+
return ESP_ERR_INVALID_ARG;
315+
}
316+
memcpy(rainmaker_node_id_txt_value, rmaker_node_id, strlen(rmaker_node_id));
317+
const static uint8_t text_values[3][23] = {
318+
{'/', 'e', 's', 'p', '_', 'l', 'o', 'c', 'a', 'l', '_', 'c', 't', 'r', 'l', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n'},
319+
{'/', 'e', 's', 'p', '_', 'l', 'o', 'c', 'a', 'l', '_', 'c', 't', 'r', 'l', '/', 's', 'e', 's', 's', 'i', 'o', 'n'},
320+
{'/', 'e', 's', 'p', '_', 'l', 'o', 'c', 'a', 'l', '_', 'c', 't', 'r', 'l', '/', 'c', 'o', 'n', 't', 'r', 'o', 'l'}};
321+
static otDnsTxtEntry txt_entries[4] = {
322+
{
323+
.mKey = "version_endpoint",
324+
.mValue = text_values[0],
325+
.mValueLength = 23,
326+
},
327+
{
328+
.mKey = "session_endpoint",
329+
.mValue = text_values[1],
330+
.mValueLength = 23,
331+
},
332+
{
333+
.mKey = "control_endpoint",
334+
.mValue = text_values[2],
335+
.mValueLength = 23,
336+
},
337+
{
338+
.mKey = "node_id",
339+
.mValue = rainmaker_node_id_txt_value,
340+
.mValueLength = sizeof(rainmaker_node_id_txt_value),
341+
}
342+
};
343+
txt_entries[3].mValueLength = (uint16_t)strlen(rmaker_node_id);
344+
static char s_serv_name[30];
345+
strncpy(s_serv_name, serv_name, strnlen(serv_name, sizeof(s_serv_name) - 1));
346+
s_serv_name[strnlen(serv_name, sizeof(s_serv_name) - 1)] = 0;
347+
static otSrpClientService srp_client_service = {
348+
.mName = "_esp_local_ctrl._tcp",
349+
.mInstanceName = (const char*)s_serv_name,
350+
.mTxtEntries = txt_entries,
351+
.mPort = CONFIG_ESP_RMAKER_LOCAL_CTRL_HTTP_PORT,
352+
.mNumTxtEntries = 4,
353+
.mNext = NULL,
354+
.mLease = 0,
355+
.mKeyLease = 0,
356+
};
357+
esp_openthread_lock_acquire(portMAX_DELAY);
358+
otInstance *instance = esp_openthread_get_instance();
359+
// Try to remove the service registered before adding a new service. If the previous service is not removed,
360+
// Adding service will fail with a duplicated instance error. This could happen when the device reboots, which
361+
// might result in the wrong resolved IP addresss on the phone app side.
362+
(void)otSrpClientRemoveService(instance, &srp_client_service);
363+
if (otSrpClientAddService(instance, &srp_client_service) != OT_ERROR_NONE) {
364+
esp_openthread_lock_release();
365+
return ESP_FAIL;
366+
}
367+
otSrpClientEnableAutoStartMode(instance, NULL, NULL);
368+
esp_openthread_lock_release();
369+
return ESP_OK;
370+
}
371+
372+
static esp_err_t srp_client_clean_up()
373+
{
374+
esp_err_t ret = ESP_OK;
375+
esp_openthread_lock_acquire(portMAX_DELAY);
376+
otInstance *instance = esp_openthread_get_instance();
377+
if (otSrpClientRemoveHostAndServices(instance, false, true) != OT_ERROR_NONE) {
378+
ret = ESP_FAIL;
379+
}
380+
memset(srp_host_name, 0, sizeof(srp_host_name));
381+
esp_openthread_lock_release();
382+
return ret;
383+
}
384+
385+
#endif /* CONFIG_ESP_RMAKER_NETWORK_OVER_THREAD */
386+
275387
static esp_err_t __esp_rmaker_start_local_ctrl_service(const char *serv_name)
276388
{
277389
if (!serv_name) {
@@ -292,6 +404,9 @@ static esp_err_t __esp_rmaker_start_local_ctrl_service(const char *serv_name)
292404
mdns_hostname_set(serv_name);
293405
#endif
294406

407+
#ifdef CONFIG_ESP_RMAKER_NETWORK_OVER_THREAD
408+
srp_client_set_host(serv_name);
409+
#endif
295410

296411
esp_local_ctrl_config_t config = {
297412
.transport = ESP_LOCAL_CTRL_TRANSPORT_HTTPD,
@@ -353,6 +468,9 @@ static esp_err_t __esp_rmaker_start_local_ctrl_service(const char *serv_name)
353468
/* Add node_id in mdns */
354469
mdns_service_txt_item_set("_esp_local_ctrl", "_tcp", "node_id", esp_rmaker_get_node_id());
355470
#endif
471+
#ifdef CONFIG_ESP_RMAKER_NETWORK_OVER_THREAD
472+
srp_client_add_local_ctrl_service(serv_name);
473+
#endif
356474

357475
if (pop) {
358476
free(pop);
@@ -511,6 +629,9 @@ esp_err_t esp_rmaker_local_ctrl_disable(void)
511629
}
512630
#ifdef CONFIG_ESP_RMAKER_NETWORK_OVER_WIFI
513631
mdns_free();
632+
#endif
633+
#ifdef CONFIG_ESP_RMAKER_NETWORK_OVER_THREAD
634+
srp_client_clean_up();
514635
#endif
515636
esp_err_t err = esp_local_ctrl_stop();
516637
if (err != ESP_OK) {

0 commit comments

Comments
 (0)