mqtt.c 16.7 KB
Newer Older
alexandre burton's avatar
alexandre burton committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include "/usr/local/include/mosquitto.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "ext.h"
#include "ext_obex.h"

typedef struct _mqtt {
    t_object p_ob;
    void *p_status_outlet;
    void *p_main_outlet;
    
    struct mosquitto *mosq;     // instance of mosquitto client
alexandre burton's avatar
alexandre burton committed
16
    
alexandre burton's avatar
alexandre burton committed
17
18
    int a_state;                // MQTT connection state
    
alexandre burton's avatar
alexandre burton committed
19
20
21
22
    long a_port;               // MQTT Broker port
    char a_clean;              // Clean session
    char a_verbose;            // verbose chatter in Max windows
    char a_autoconnect;        // auto-connect on object instanciation
alexandre burton's avatar
alexandre burton committed
23
    t_symbol *a_user;           // MQTT username
alexandre burton's avatar
alexandre burton committed
24
25
    t_symbol *a_host;           // MQTT host
    t_symbol *a_password;;      // MQTT password
alexandre burton's avatar
alexandre burton committed
26
    t_symbol *a_id;             // Client ID
27
    
alexandre burton's avatar
alexandre burton committed
28
29
    char payload[1000];           // reusable memory for received payload

alexandre burton's avatar
alexandre burton committed
30
31
32
33
34
35
36
37
38
39
40
41
} t_mqtt;

#define MQTT_DEFAULT_PORT 1883
static long MOSQUITTO_CLIENT_ID = 0;

// download & compile static mosquitto lib (did not fight TLS/https; disabled in cmake)
// /usr/bin/codesign --force --sign 0EFF62FA1517300CC579B619A634293E5A5E7193 --timestamp=none/usr/bin/codesign --force --sign 0EFF62FA1517300CC579B619A634293E5A5E7193 --timestamp=none /Users/brtn/Downloads/max-sdk-8.0.3/externals/mqtt.mxo/Contents/Frameworks/libmosquitto_static.a
// add to max project

void mqtt_change_state(t_mqtt *x, int state) {
    switch (state) {
        case 1:
alexandre burton's avatar
alexandre burton committed
42
            if (x->a_verbose) post("[mqtt] <%s> connection up",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
43
44
45
            x->a_state =1;
            break;
        default:
alexandre burton's avatar
alexandre burton committed
46
            if (x->a_verbose) post("[mqtt] <%s> connecction down",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
47
48
49
50
51
            x->a_state =0;
    }
    outlet_int(x->p_status_outlet, x->a_state);
}

alexandre burton's avatar
alexandre burton committed
52
53
54
55
56
57
void publish_callback(struct mosquitto *mosq, void *obj, int mid)
{
    t_mqtt * x = obj;
    if (x->a_verbose) post("[mqtt] <%s> published topic id#%05i",x->a_id->s_name,mid);
}

alexandre burton's avatar
alexandre burton committed
58
59
60
61
62
63
64
65
void connect_callback(struct mosquitto *mosq, void *obj, int result)
{
    t_mqtt * x = obj;
    switch (result) {
        case 0:
            mqtt_change_state(x, 1);
            break;
        default:
alexandre burton's avatar
alexandre burton committed
66
            error("[mqtt] <%s> Connection Refused, [%s]", x->a_id->s_name, mosquitto_reason_string(result));
alexandre burton's avatar
alexandre burton committed
67
68
69
70
71
72
73
74
75
            mqtt_change_state(x, 0);
            mosquitto_disconnect(mosq);
    }
}

void disconnect_callback(struct mosquitto *mosq, void *obj, int result)
{
    t_mqtt * x = obj;
    if (result ==0) {
alexandre burton's avatar
alexandre burton committed
76
        if (x->a_verbose) post("[mqtt] <%s> disconnected as requested",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
77
    } else {
alexandre burton's avatar
alexandre burton committed
78
        post("[mqtt] <%s> unexpectedly disconnected from broker",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
79
80
81
82
83
84
85
86
    }
    mqtt_change_state(x, 0);
}

void message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
    t_mqtt * x = obj;
    t_atom a[1];
87
88
    
    // asssumes something that fits in a max symbol -- should check for cues or magic numbers and generates json dicts, jitter matrices, or vectors of audio
alexandre burton's avatar
alexandre burton committed
89
90
91
92
    atom_setsym(a+0, gensym((char*) message->payload));
    outlet_anything(x->p_main_outlet, gensym(message->topic), 1,a);
}

alexandre burton's avatar
alexandre burton committed
93
// methods
alexandre burton's avatar
alexandre burton committed
94
95
96
97
98
99
100
void mqtt_assist(t_mqtt *x, void *b, long m, long a, char *s);
void mqtt_subscribe_method(t_mqtt *x, t_symbol *topic);
void mqtt_unsubscribe_method(t_mqtt *x, t_symbol *topic);
void mqtt_publish_method(t_mqtt *x, t_symbol *s, long argc, t_atom *argv);
void mqtt_connect_method(t_mqtt *x, t_symbol *s, long argc, t_atom *argv);
void mqtt_loop_method(t_mqtt *x);

alexandre burton's avatar
alexandre burton committed
101
102
// attribute setters
void mqtt_set_clean(t_mqtt *x, void *attr, long argc, t_atom *argv);
alexandre burton's avatar
alexandre burton committed
103
void mqtt_set_id(t_mqtt *x, void *attr, long argc, t_atom *argv);
alexandre burton's avatar
alexandre burton committed
104
105
106
107
108
void mqtt_set_user(t_mqtt *x, void *attr, long argc, t_atom *argv);
void mqtt_set_port(t_mqtt *x, void *attr, long argc, t_atom *argv);
void mqtt_set_password(t_mqtt *x, void *attr, long argc, t_atom *argv);
void mqtt_set_host(t_mqtt *x, void *attr, long argc, t_atom *argv);
void mqtt_set_autoconnect(t_mqtt *x, void *attr, long argc, t_atom *argv);
alexandre burton's avatar
alexandre burton committed
109
110
111
112

void *mqtt_new(t_symbol *s, long argc, t_atom *argv);

void mosquitto_free_client(t_mqtt *x) {
alexandre burton's avatar
alexandre burton committed
113
    if (x->a_verbose) post("[mqtt] freeing underlying client <%s>", x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
    mosquitto_disconnect(x->mosq);
    mosquitto_loop_stop(x->mosq, true);
    mosquitto_destroy(x->mosq);
}

void mqtt_free(t_mqtt *x)
{
    mosquitto_free_client(x);
}

t_class *mqtt_class;

void ext_main(void *r)
{
    t_class *c;
    
    c = class_new("mqtt", (method)mqtt_new, (method)mqtt_free, sizeof(t_mqtt), 0L, A_GIMME, 0);
    
    class_addmethod(c, (method)mqtt_loop_method,        "bang",       0);
    class_addmethod(c, (method)mqtt_assist,             "assist",     A_CANT, 0);
    class_addmethod(c, (method)mqtt_subscribe_method,   "subscribe",  A_DEFSYM, 0);
    class_addmethod(c, (method)mqtt_unsubscribe_method, "unsubscribe",A_DEFSYM, 0);
    class_addmethod(c, (method)mqtt_publish_method,     "publish",    A_GIMME, 0);
    class_addmethod(c, (method)mqtt_connect_method,     "connect",    A_GIMME, 0);
    
alexandre burton's avatar
alexandre burton committed
139
140
141
142
143
144
145
146
147
    CLASS_ATTR_SYM(c,         "id",           0, t_mqtt, a_id);
    CLASS_ATTR_ACCESSORS(c,   "id",           NULL, mqtt_set_id);
    
    CLASS_ATTR_CHAR(c,         "clean",        0, t_mqtt, a_clean);
    CLASS_ATTR_STYLE_LABEL(c, "clean",        0, "onoff", "Clean Session");
    CLASS_ATTR_ACCESSORS(c,   "clean",        NULL, mqtt_set_clean);
    
    CLASS_ATTR_CHAR(c,        "verbose",      0, t_mqtt, a_verbose);
    CLASS_ATTR_STYLE_LABEL(c, "verbose",      0, "onoff", "Verbose");
148
    
alexandre burton's avatar
alexandre burton committed
149
150
151
    CLASS_ATTR_CHAR(c,        "autoconnect",  0, t_mqtt, a_autoconnect);
    CLASS_ATTR_STYLE_LABEL(c, "autoconnect",  0, "onoff", "Auto-connect");
    CLASS_ATTR_ACCESSORS(c,   "autoconnect",  NULL, mqtt_set_autoconnect);
152
    
alexandre burton's avatar
alexandre burton committed
153
154
    CLASS_ATTR_SYM(c,         "user",         0, t_mqtt, a_user);
    CLASS_ATTR_ACCESSORS(c,   "user",         NULL, mqtt_set_user);
alexandre burton's avatar
alexandre burton committed
155
    
alexandre burton's avatar
alexandre burton committed
156
157
158
159
160
161
162
163
    CLASS_ATTR_SYM(c,         "password",     0, t_mqtt, a_password);
    CLASS_ATTR_ACCESSORS(c,   "password",     NULL, mqtt_set_password);
    
    CLASS_ATTR_SYM(c,         "host",         0, t_mqtt, a_host);
    CLASS_ATTR_ACCESSORS(c,   "host",         NULL, mqtt_set_host);
    
    CLASS_ATTR_LONG(c,        "port",         0, t_mqtt, a_port);
    CLASS_ATTR_ACCESSORS(c,   "port",         NULL, mqtt_set_port);
164
    
alexandre burton's avatar
alexandre burton committed
165
166
167
168
169
    class_register(CLASS_BOX, c);
    mqtt_class = c;
    
    int res = mosquitto_lib_init();
    post("MQTT Client for Max ©2021 https://gitlab.artificiel.org/max/mqtt",0);
alexandre burton's avatar
alexandre burton committed
170
171
    int x,y,z;
    mosquitto_lib_version(&x,&y,&z);
alexandre burton's avatar
alexandre burton committed
172
    if (res==MOSQ_ERR_SUCCESS) {
alexandre burton's avatar
alexandre burton committed
173
        post("Mosquitto MQTT Library %i.%i.%i initialized.",x ,y ,z);
alexandre burton's avatar
alexandre burton committed
174
    } else {
alexandre burton's avatar
alexandre burton committed
175
        error("Mosquitto MQTT Library %i.%i.%i did not correctly initialize!",x ,y ,z);
alexandre burton's avatar
alexandre burton committed
176
177
178
179
180
181
182
183
184
185
186
187
188
    }
}

void mqtt_set_id(t_mqtt *x, void *attr, long argc, t_atom *argv)
{
    if (atom_getsym(argv)->s_name != x->a_id->s_name) {
        x->a_id = atom_getsym(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with id %s", x->a_id->s_name);
        }
    }
}

alexandre burton's avatar
alexandre burton committed
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
void mqtt_set_user(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getsym(argv)->s_name != x->a_user->s_name) {
        x->a_user = atom_getsym(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with user %s", x->a_user->s_name);
        }
    }
}

void mqtt_set_port(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getlong(argv) != x->a_port) {
        x->a_port = atom_getlong(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with port %i", x->a_port);
        }
    }
}

void mqtt_set_password(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getsym(argv)->s_name != x->a_password->s_name) {
        x->a_password = atom_getsym(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with passwoord %s", x->a_password->s_name);
        }
    }
}

void mqtt_set_host(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getsym(argv)->s_name != x->a_host->s_name) {
        x->a_host = atom_getsym(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with host %s", x->a_host->s_name);
        }
    }
}

void mqtt_set_autoconnect(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    x->a_autoconnect = atom_getlong(argv);
    if (x->a_state == 0 && x->a_autoconnect == 1) {
        post("TO IMPLEMENT: should connect when autoconnect is turned on",0);
    }
}

void mqtt_set_clean(t_mqtt *x, void *attr, long argc, t_atom *argv) {
    if (atom_getlong(argv) != x->a_clean) {
        x->a_clean = atom_getlong(argv);
        if (x->a_state == 1) {
            post("TO IMPLEMENT: should reconnect with cleaniness %i", x->a_clean);
        }
    }
}

alexandre burton's avatar
alexandre burton committed
241
void mqtt_connect_method(t_mqtt *x, t_symbol *s, long argc, t_atom *argv) {
alexandre burton's avatar
alexandre burton committed
242
243
    if ((argc < 0 && argc > 4) || argc ==3) {
        error("[mqtt] connect requires 0, 1, 2 or 4 arguments: (host (port (username password)))");
alexandre burton's avatar
alexandre burton committed
244
    } else {
alexandre burton's avatar
alexandre burton committed
245
        if (argv>0) {
alexandre burton's avatar
alexandre burton committed
246
            
alexandre burton's avatar
alexandre burton committed
247
248
249
            if (argv[0].a_type==A_SYM) {
                
                //mosquitto_reinitialise(x->mosq, x->clientid, false, x);
alexandre burton's avatar
alexandre burton committed
250
                
alexandre burton's avatar
alexandre burton committed
251
252
253
254
255
256
257
258
259
                //                char host[100];
                //                int port = MQTT_DEFAULT_PORT;
                //                sprintf(host, "%s", argv[0].a_w.w_sym->s_name);
                //
                x->a_host = argv[0].a_w.w_sym;
                
                if (argc > 1) {
                    if (argv[1].a_type==A_LONG) {
                        x->a_port = argv[1].a_w.w_long;
alexandre burton's avatar
alexandre burton committed
260
                    } else {
alexandre burton's avatar
alexandre burton committed
261
262
263
264
265
266
267
268
269
270
                        error("[mqtt] connect port (arg#2) must be int -- using %i", x->a_port);
                    }
                    
                    if (argc ==4) {
                        if (argv[2].a_type==A_SYM && argv[3].a_type==A_SYM) {
                            x->a_password = gensym(argv[3].a_w.w_sym->s_name);
                            x->a_user = argv[2].a_w.w_sym;
                        } else {
                            error("[mqtt] connect username & password (arg#2-3) must be symbols");
                        }
alexandre burton's avatar
alexandre burton committed
271
272
273
                    }
                }
            }
alexandre burton's avatar
alexandre burton committed
274
275
276
277
278
279
        }
        if (strlen(x->a_host->s_name)) {
            
            if (x->mosq != NULL) {
                mosquitto_free_client(x);
            }
alexandre burton's avatar
alexandre burton committed
280
            
alexandre burton's avatar
alexandre burton committed
281
282
283
            x->mosq = mosquitto_new(x->a_id->s_name, false, x); // pass this object into mosquitto for callbacks
            if (x->a_verbose) post("[mqtt] instance for cliend id <%s> created",x->a_id->s_name);

alexandre burton's avatar
alexandre burton committed
284
285
286
            mosquitto_disconnect_callback_set(x->mosq, disconnect_callback);
            mosquitto_connect_callback_set(x->mosq, connect_callback);
            mosquitto_message_callback_set(x->mosq, message_callback);
alexandre burton's avatar
alexandre burton committed
287
            mosquitto_publish_callback_set(x->mosq, publish_callback);
alexandre burton's avatar
alexandre burton committed
288
            mosquitto_user_data_set(x->mosq, x);
alexandre burton's avatar
alexandre burton committed
289
290
291
292
293
294
295
296
297

            if (strlen(x->a_user->s_name) && strlen(x->a_password->s_name)) {
                mosquitto_username_pw_set(x->mosq, x->a_user->s_name, x->a_password->s_name);
                if (x->a_verbose) post("[mqtt] <%s> attempting connection to %s:%s@%s:%i",
                                       x->a_id->s_name, x->a_user->s_name, x->a_password->s_name, x->a_host->s_name, x->a_port);
            } else {
                if (x->a_verbose) post("[mqtt] <%s> attempting connection to %s:%i",
                                       x->a_id->s_name, x->a_host->s_name, x->a_port);
            }
alexandre burton's avatar
alexandre burton committed
298
299
            
            
alexandre burton's avatar
alexandre burton committed
300
            int res= mosquitto_connect(x->mosq, x->a_host->s_name, x->a_port, 60);
alexandre burton's avatar
alexandre burton committed
301
302
303
304
            
            int rloop;
            switch (res) {
                case MOSQ_ERR_SUCCESS:
305
306
                    rloop = mosquitto_loop_start(x->mosq);
                    if (rloop==MOSQ_ERR_INVAL) {
alexandre burton's avatar
alexandre burton committed
307
                        error("[mqtt] <%s> could not start thread [%02i]:%s", x->a_id->s_name, rloop, mosquitto_reason_string(rloop));
308
                    } else if (rloop==MOSQ_ERR_NOT_SUPPORTED) {
alexandre burton's avatar
alexandre burton committed
309
                        error("[mqtt] <%s> could not start thread [MOSQ_ERR_NOT_SUPPORTED]", x->a_id->s_name);
310
                    } else {
alexandre burton's avatar
alexandre burton committed
311
                        if (x->a_verbose) post("[mqtt] <%s> started event thread",x->a_id->s_name);
312
                    }
alexandre burton's avatar
alexandre burton committed
313
314
                    //                    }
                    break;
alexandre burton's avatar
alexandre burton committed
315
316
                case MOSQ_ERR_INVAL: error("[mqtt] connect: <%s> invalid parameters [MOSQ_ERR_INVAL]", x->a_id->s_name); break;
                case MOSQ_ERR_ERRNO: error("[mqtt] connect: <%s> out of memory [MOSQ_ERR_NOMEM]", x->a_id->s_name); break;
alexandre burton's avatar
alexandre burton committed
317
            }
alexandre burton's avatar
alexandre burton committed
318
            if (x->a_verbose) post("[mqtt] <%s> connection proocess finished.",x->a_id->s_name);
alexandre burton's avatar
alexandre burton committed
319
        } else {
alexandre burton's avatar
alexandre burton committed
320
            error("[mqtt] host not set");
alexandre burton's avatar
alexandre burton committed
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
        }
    }
}

void mqtt_loop_method(t_mqtt * x) {
    post("loop...");
    int res = mosquitto_loop(x->mosq, -1, 1);
    post("loop %i", res);
}

void mqtt_publish_method(t_mqtt *x, t_symbol *s, long argc, t_atom *argv) {
    t_symbol topic;
    
    long qos = 0;
    bool retain = false;
    
    if (argc < 2 || argc > 4) {
alexandre burton's avatar
alexandre burton committed
338
        error("[mqtt] publish requires 2, 3 or 4 arguments: topic payload (qos (retain))");
alexandre burton's avatar
alexandre burton committed
339
340
341
342
343
    } else {
        if (argv[0].a_type==A_SYM) {
            topic = *argv[0].a_w.w_sym;
            
            if (argv[1].a_type==A_LONG) {
alexandre burton's avatar
alexandre burton committed
344
                sprintf(x->payload, "%lli", argv[1].a_w.w_long);
alexandre burton's avatar
alexandre burton committed
345
            } else if (argv[1].a_type==A_FLOAT) {
alexandre burton's avatar
alexandre burton committed
346
                sprintf(x->payload, "%f", argv[1].a_w.w_float);
alexandre burton's avatar
alexandre burton committed
347
            } else if (argv[1].a_type==A_SYM) {
alexandre burton's avatar
alexandre burton committed
348
                sprintf(x->payload, "%s", argv[1].a_w.w_sym->s_name);
alexandre burton's avatar
alexandre burton committed
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
            }
            
            if (argc>2) {
                if (argv[2].a_type==A_LONG) {
                    long q = argv[2].a_w.w_long;
                    if (q <0) q = 0;
                    if (q > 2) q = 2;
                    qos = q;
                }
                if (argc==4) {
                    if (argv[4].a_type==A_LONG) {
                        long q = argv[2].a_w.w_long;
                        if (q <0) q = 0;
                        if (q > 1) q = 1;
                        retain = q;
                    }
                }
            }
            
alexandre burton's avatar
alexandre burton committed
368
            int res = mosquitto_publish(x->mosq, NULL, topic.s_name, strlen(x->payload), x->payload, qos,  retain);
alexandre burton's avatar
alexandre burton committed
369
370
            switch (res) {
                case MOSQ_ERR_SUCCESS: /* silent success */
alexandre burton's avatar
alexandre burton committed
371
                    if (x->a_verbose) post("[mqtt] <%s> published %s with %s",x->a_id->s_name, topic.s_name, x->payload);
alexandre burton's avatar
alexandre burton committed
372
373
                    break;
                default:
alexandre burton's avatar
alexandre burton committed
374
                    error("[mqtt] <%s> can't publish %s [%s]", x->a_id->s_name, topic, mosquitto_reason_string(res));
alexandre burton's avatar
alexandre burton committed
375
376
            }
        } else {
alexandre burton's avatar
alexandre burton committed
377
            error("[mqtt]  publish topic (arg#1) must be string");
alexandre burton's avatar
alexandre burton committed
378
379
380
381
382
383
384
385
        }
    }
}

void mqtt_subscribe_method(t_mqtt *x, t_symbol * topic) {
    int sres = mosquitto_subscribe(x->mosq, NULL, topic->s_name, 0);
    switch (sres) {
        case MOSQ_ERR_SUCCESS:
alexandre burton's avatar
alexandre burton committed
386
            if (x->a_verbose) post("[mqtt] <%s> susbscribed %s", x->a_id->s_name, topic->s_name);
alexandre burton's avatar
alexandre burton committed
387
388
            break;
        default:
alexandre burton's avatar
alexandre burton committed
389
            error("[mqtt] subscribe <%s> failed [%02i: %s]", x->a_id->s_name, sres, mosquitto_reason_string(sres));
alexandre burton's avatar
alexandre burton committed
390
391
392
393
394
395
396
    }
}

void mqtt_unsubscribe_method(t_mqtt *x, t_symbol * topic) {
    int sres = mosquitto_unsubscribe(x->mosq, NULL, topic->s_name);
    switch (sres) {
        case MOSQ_ERR_SUCCESS:
alexandre burton's avatar
alexandre burton committed
397
            if (x->a_verbose) post("[mqtt] <%s> unsusbscribed %s", x->a_id->s_name, topic->s_name);
alexandre burton's avatar
alexandre burton committed
398
399
            break;
        default:
alexandre burton's avatar
alexandre burton committed
400
            error("[mqtt] unsubscribe <%s> failed [%s]]", x->a_id->s_name, mosquitto_reason_string(sres));
alexandre burton's avatar
alexandre burton committed
401
402
403
    }
}

alexandre burton's avatar
alexandre burton committed
404
void *mqtt_new(t_symbol *s, long argc, t_atom *argv)
alexandre burton's avatar
alexandre burton committed
405
406
407
{
    t_mqtt *x;
    x = (t_mqtt *)object_alloc(mqtt_class);
408
    
alexandre burton's avatar
alexandre burton committed
409
410
411
412
    char hostname[100];
    char random_id[100];
    hostname[99] = '\0';
    gethostname(hostname, 1023);
alexandre burton's avatar
alexandre burton committed
413
414
    snprintf(random_id, 99, "%s-%03ld", hostname, MOSQUITTO_CLIENT_ID++);
    
alexandre burton's avatar
alexandre burton committed
415
416
    x->a_id = gensym(random_id);
    x->a_verbose = 0;
alexandre burton's avatar
alexandre burton committed
417
418
419
420
421
422
423
    x->a_clean = 0;
    x->a_autoconnect = 0;
    x->a_port = 1883;
    x->a_host = gensym("");
    x->a_user = gensym("");
    x->a_password = gensym("");
    
alexandre burton's avatar
alexandre burton committed
424
    attr_args_process(x, argc, argv);
425
    
alexandre burton's avatar
alexandre burton committed
426
427
    x->p_status_outlet  = outlet_new(x, NULL);
    x->p_main_outlet = outlet_new(x, NULL);
428
    
alexandre burton's avatar
alexandre burton committed
429
430
431
432
433
434
    return(x);
}

void mqtt_assist(t_mqtt *x, void *b, long m, long a, char *s) // 4 final arguments are always the same for the assistance method
{
    if (m == ASSIST_OUTLET)
alexandre burton's avatar
alexandre burton committed
435
436
437
438
439
440
441
442
        switch (a) {
            case 0:
                sprintf(s,"topic and payload (2 symbols list)");
                break;
            case 1:
                sprintf(s,"connection status (0 or 1)");
                break;
        }
alexandre burton's avatar
alexandre burton committed
443
444
445
    else {
        switch (a) {
            case 0:
alexandre burton's avatar
alexandre burton committed
446
                sprintf(s,"all messages go here");
alexandre burton's avatar
alexandre burton committed
447
448
449
450
451
452
453
                break;
            case 1:
                sprintf(s,"Inlet %ld: Right Operand (Added to Left)", a);
                break;
        }
    }
}