Skip to content

Commit 3593551

Browse files
committed
Unique topic names per device
Disabled by default with MQTT_UNIQUE_TOPIC
1 parent 103a496 commit 3593551

File tree

1 file changed

+59
-20
lines changed

1 file changed

+59
-20
lines changed

pico_w/wifi/mqtt/mqtt_client.c

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@
3232
#include MQTT_CERT_INC
3333
#endif
3434

35+
#ifndef MQTT_TOPIC_LEN
36+
#define MQTT_TOPIC_LEN 100
37+
#endif
38+
3539
typedef struct {
3640
mqtt_client_t* mqtt_client_inst;
3741
struct mqtt_connect_client_info_t mqtt_client_info;
3842
char data[MQTT_OUTPUT_RINGBUF_SIZE];
39-
char topic[100];
43+
char topic[MQTT_TOPIC_LEN];
4044
uint32_t len;
4145
ip_addr_t mqtt_server_address;
4246
bool connect_done;
@@ -79,6 +83,15 @@ typedef struct {
7983
#define MQTT_WILL_MSG "0"
8084
#define MQTT_WILL_QOS 1
8185

86+
#ifndef MQTT_DEVICE_NAME
87+
#define MQTT_DEVICE_NAME "pico"
88+
#endif
89+
90+
// Set to 1 to add the client name to topics, to support multiple devices using the same server
91+
#ifndef MQTT_UNIQUE_TOPIC
92+
#define MQTT_UNIQUE_TOPIC 0
93+
#endif
94+
8295
/* References for this implementation:
8396
* raspberry-pi-pico-c-sdk.pdf, Section '4.1.1. hardware_adc'
8497
* pico-examples/adc/adc_console/adc_console.c */
@@ -105,6 +118,16 @@ static void pub_request_cb(__unused void *arg, err_t err) {
105118
}
106119
}
107120

121+
static const char *full_topic(MQTT_CLIENT_DATA_T *state, const char *name) {
122+
#if MQTT_UNIQUE_TOPIC
123+
static char full_topic[MQTT_TOPIC_LEN];
124+
snprintf(full_topic, sizeof(full_topic), "/%s%s", state->mqtt_client_info.client_id, name);
125+
return full_topic;
126+
#else
127+
return name;
128+
#endif
129+
}
130+
108131
static void control_led(MQTT_CLIENT_DATA_T *state, bool on) {
109132
// Publish state on /state topic and on/off led board
110133
const char* message = on ? "On" : "Off";
@@ -113,14 +136,12 @@ static void control_led(MQTT_CLIENT_DATA_T *state, bool on) {
113136
else
114137
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
115138

116-
char state_topic[128];
117-
snprintf(state_topic, sizeof(state_topic), "%s/state", state->topic);
118-
mqtt_publish(state->mqtt_client_inst, state_topic, message, strlen(message), MQTT_PUBLISH_QOS, MQTT_PUBLISH_RETAIN, pub_request_cb, state);
139+
mqtt_publish(state->mqtt_client_inst, full_topic(state, "/led/state"), message, strlen(message), MQTT_PUBLISH_QOS, MQTT_PUBLISH_RETAIN, pub_request_cb, state);
119140
}
120141

121142
static void publish_temperature(MQTT_CLIENT_DATA_T *state) {
122143
static float old_temperature;
123-
const char temperature_key[] = "/temperature";
144+
const char *temperature_key = full_topic(state, "/temperature");
124145
float temperature = read_onboard_temperature(TEMPERATURE_UNITS);
125146
if (temperature != old_temperature) {
126147
old_temperature = temperature;
@@ -156,32 +177,37 @@ static void unsub_request_cb(void *arg, err_t err) {
156177

157178
static void sub_unsub_topics(MQTT_CLIENT_DATA_T* state, bool sub) {
158179
mqtt_request_cb_t cb = sub ? sub_request_cb : unsub_request_cb;
159-
mqtt_sub_unsub(state->mqtt_client_inst, "/led", MQTT_SUBSCRIBE_QOS, cb, state, sub);
160-
mqtt_sub_unsub(state->mqtt_client_inst, "/print", MQTT_SUBSCRIBE_QOS, cb, state, sub);
161-
mqtt_sub_unsub(state->mqtt_client_inst, "/ping", MQTT_SUBSCRIBE_QOS, cb, state, sub);
162-
mqtt_sub_unsub(state->mqtt_client_inst, "/exit", MQTT_SUBSCRIBE_QOS, cb, state, sub);
180+
mqtt_sub_unsub(state->mqtt_client_inst, full_topic(state, "/led"), MQTT_SUBSCRIBE_QOS, cb, state, sub);
181+
mqtt_sub_unsub(state->mqtt_client_inst, full_topic(state, "/print"), MQTT_SUBSCRIBE_QOS, cb, state, sub);
182+
mqtt_sub_unsub(state->mqtt_client_inst, full_topic(state, "/ping"), MQTT_SUBSCRIBE_QOS, cb, state, sub);
183+
mqtt_sub_unsub(state->mqtt_client_inst, full_topic(state, "/exit"), MQTT_SUBSCRIBE_QOS, cb, state, sub);
163184
}
164185

165186
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) {
166187
MQTT_CLIENT_DATA_T* state = (MQTT_CLIENT_DATA_T*)arg;
188+
#if MQTT_UNIQUE_TOPIC
189+
const char *basic_topic = state->topic + strlen(state->mqtt_client_info.client_id) + 1;
190+
#else
191+
const char *basic_topic = state->topic;
192+
#endif
167193
strncpy(state->data, (const char *)data, len);
168194
state->len = len;
169195
state->data[len] = '\0';
170196

171197
DEBUG_printf("Topic: %s, Message: %s\n", state->topic, state->data);
172-
if (strcmp(state->topic, "/led") == 0)
198+
if (strcmp(basic_topic, "/led") == 0)
173199
{
174-
if (lwip_stricmp((const char *)state->data, "On") == 0)
200+
if (lwip_stricmp((const char *)state->data, "On") == 0 || strcmp((const char *)state->data, "1") == 0)
175201
control_led(state, true);
176-
else if (lwip_stricmp((const char *)state->data, "Off") == 0)
202+
else if (lwip_stricmp((const char *)state->data, "Off") == 0 || strcmp((const char *)state->data, "0") == 0)
177203
control_led(state, false);
178-
} else if (strcmp(state->topic, "/print") == 0) {
204+
} else if (strcmp(basic_topic, "/print") == 0) {
179205
INFO_printf("%.*s\n", len, data);
180-
} else if (strcmp(state->topic, "/ping") == 0) {
206+
} else if (strcmp(basic_topic, "/ping") == 0) {
181207
char buf[11];
182208
snprintf(buf, sizeof(buf), "%u", to_ms_since_boot(get_absolute_time()) / 1000);
183-
mqtt_publish(state->mqtt_client_inst, "/pong", buf, strlen(buf), MQTT_PUBLISH_QOS, MQTT_PUBLISH_RETAIN, pub_request_cb, state);
184-
} else if (strcmp(state->topic, "/exit") == 0) {
209+
mqtt_publish(state->mqtt_client_inst, full_topic(state, "/pong"), buf, strlen(buf), MQTT_PUBLISH_QOS, MQTT_PUBLISH_RETAIN, pub_request_cb, state);
210+
} else if (strcmp(basic_topic, "/exit") == 0) {
185211
state->stop_client = true; // stop the client when ALL subscriptions are stopped
186212
sub_unsub_topics(state, false); // unsubscribe
187213
}
@@ -276,9 +302,20 @@ int main(void) {
276302
panic("Failed to inizialize CYW43");
277303
}
278304

279-
// Use board unique id for the client id
280-
static char client_id_buf[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
281-
pico_get_unique_board_id_string(client_id_buf, sizeof(client_id_buf));
305+
// Use board unique id
306+
char unique_id_buf[5];
307+
pico_get_unique_board_id_string(unique_id_buf, sizeof(unique_id_buf));
308+
for(int i=0; i < sizeof(unique_id_buf) - 1; i++) {
309+
unique_id_buf[i] = tolower(unique_id_buf[i]);
310+
}
311+
312+
// Generate a unique name, e.g. pico1234
313+
char client_id_buf[sizeof(MQTT_DEVICE_NAME) + sizeof(unique_id_buf) - 1];
314+
memcpy(&client_id_buf[0], MQTT_DEVICE_NAME, sizeof(MQTT_DEVICE_NAME) - 1);
315+
memcpy(&client_id_buf[sizeof(MQTT_DEVICE_NAME) - 1], unique_id_buf, sizeof(unique_id_buf) - 1);
316+
client_id_buf[sizeof(client_id_buf) - 1] = 0;
317+
INFO_printf("Device name %s\n", client_id_buf);
318+
282319
state.mqtt_client_info.client_id = client_id_buf;
283320
state.mqtt_client_info.keep_alive = MQTT_KEEP_ALIVE_S; // Keep alive in sec
284321
#if defined(MQTT_USERNAME) && defined(MQTT_PASSWORD)
@@ -288,7 +325,9 @@ int main(void) {
288325
state.mqtt_client_info.client_user = NULL;
289326
state.mqtt_client_info.client_pass = NULL;
290327
#endif
291-
state.mqtt_client_info.will_topic = MQTT_WILL_TOPIC;
328+
static char will_topic[MQTT_TOPIC_LEN];
329+
strncpy(will_topic, full_topic(&state, MQTT_WILL_TOPIC), sizeof(will_topic));
330+
state.mqtt_client_info.will_topic = will_topic;
292331
state.mqtt_client_info.will_msg = MQTT_WILL_MSG;
293332
state.mqtt_client_info.will_qos = MQTT_WILL_QOS;
294333
state.mqtt_client_info.will_retain = true;

0 commit comments

Comments
 (0)