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