3232#include MQTT_CERT_INC
3333#endif
3434
35+ #ifndef MQTT_TOPIC_LEN
36+ #define MQTT_TOPIC_LEN 100
37+ #endif
38+
3539typedef 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+
108131static 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
121142static 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
157178static 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
165186static 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