1*10465441SEvalZeroMQTT client for lwIP 2*10465441SEvalZero 3*10465441SEvalZeroAuthor: Erik Andersson 4*10465441SEvalZero 5*10465441SEvalZeroDetails of the MQTT protocol can be found at: 6*10465441SEvalZerohttp://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html 7*10465441SEvalZero 8*10465441SEvalZero----------------------------------------------------------------- 9*10465441SEvalZero1. Initial steps, reserve memory and make connection to server: 10*10465441SEvalZero 11*10465441SEvalZero1.1: Provide storage 12*10465441SEvalZero 13*10465441SEvalZeroStatic allocation: 14*10465441SEvalZero mqtt_client_t static_client; 15*10465441SEvalZero example_do_connect(&static_client); 16*10465441SEvalZero 17*10465441SEvalZeroDynamic allocation: 18*10465441SEvalZero mqtt_client_t *client = mqtt_client_new(); 19*10465441SEvalZero if(client != NULL) { 20*10465441SEvalZero example_do_connect(&client); 21*10465441SEvalZero } 22*10465441SEvalZero 23*10465441SEvalZero1.2: Establish Connection with server 24*10465441SEvalZero 25*10465441SEvalZerovoid example_do_connect(mqtt_client_t *client) 26*10465441SEvalZero{ 27*10465441SEvalZero struct mqtt_connect_client_info_t ci; 28*10465441SEvalZero err_t err; 29*10465441SEvalZero 30*10465441SEvalZero /* Setup an empty client info structure */ 31*10465441SEvalZero memset(&ci, 0, sizeof(ci)); 32*10465441SEvalZero 33*10465441SEvalZero /* Minimal amount of information required is client identifier, so set it here */ 34*10465441SEvalZero ci.client_id = "lwip_test"; 35*10465441SEvalZero 36*10465441SEvalZero /* Initiate client and connect to server, if this fails immediately an error code is returned 37*10465441SEvalZero otherwise mqtt_connection_cb will be called with connection result after attempting 38*10465441SEvalZero to establish a connection with the server. 39*10465441SEvalZero For now MQTT version 3.1.1 is always used */ 40*10465441SEvalZero 41*10465441SEvalZero err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci); 42*10465441SEvalZero 43*10465441SEvalZero /* For now just print the result code if something goes wrong 44*10465441SEvalZero if(err != ERR_OK) { 45*10465441SEvalZero printf("mqtt_connect return %d\n", err); 46*10465441SEvalZero } 47*10465441SEvalZero} 48*10465441SEvalZero 49*10465441SEvalZeroConnection to server can also be probed by calling mqtt_client_is_connected(client) 50*10465441SEvalZero 51*10465441SEvalZero----------------------------------------------------------------- 52*10465441SEvalZero2. Implementing the connection status callback 53*10465441SEvalZero 54*10465441SEvalZero 55*10465441SEvalZerostatic void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) 56*10465441SEvalZero{ 57*10465441SEvalZero err_t err; 58*10465441SEvalZero if(status == MQTT_CONNECT_ACCEPTED) { 59*10465441SEvalZero printf("mqtt_connection_cb: Successfully connected\n"); 60*10465441SEvalZero 61*10465441SEvalZero /* Setup callback for incoming publish requests */ 62*10465441SEvalZero mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg); 63*10465441SEvalZero 64*10465441SEvalZero /* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */ 65*10465441SEvalZero err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg); 66*10465441SEvalZero 67*10465441SEvalZero if(err != ERR_OK) { 68*10465441SEvalZero printf("mqtt_subscribe return: %d\n", err); 69*10465441SEvalZero } 70*10465441SEvalZero } else { 71*10465441SEvalZero printf("mqtt_connection_cb: Disconnected, reason: %d\n", status); 72*10465441SEvalZero 73*10465441SEvalZero /* Its more nice to be connected, so try to reconnect */ 74*10465441SEvalZero example_do_connect(client); 75*10465441SEvalZero } 76*10465441SEvalZero} 77*10465441SEvalZero 78*10465441SEvalZerostatic void mqtt_sub_request_cb(void *arg, err_t result) 79*10465441SEvalZero{ 80*10465441SEvalZero /* Just print the result code here for simplicity, 81*10465441SEvalZero normal behaviour would be to take some action if subscribe fails like 82*10465441SEvalZero notifying user, retry subscribe or disconnect from server */ 83*10465441SEvalZero printf("Subscribe result: %d\n", result); 84*10465441SEvalZero} 85*10465441SEvalZero 86*10465441SEvalZero----------------------------------------------------------------- 87*10465441SEvalZero3. Implementing callbacks for incoming publish and data 88*10465441SEvalZero 89*10465441SEvalZero/* The idea is to demultiplex topic and create some reference to be used in data callbacks 90*10465441SEvalZero Example here uses a global variable, better would be to use a member in arg 91*10465441SEvalZero If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of 92*10465441SEvalZero the topic string and use it in mqtt_incoming_data_cb 93*10465441SEvalZero*/ 94*10465441SEvalZerostatic int inpub_id; 95*10465441SEvalZerostatic void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len) 96*10465441SEvalZero{ 97*10465441SEvalZero printf("Incoming publish at topic %s with total length %u\n", topic, (unsigned int)tot_len); 98*10465441SEvalZero 99*10465441SEvalZero /* Decode topic string into a user defined reference */ 100*10465441SEvalZero if(strcmp(topic, "print_payload") == 0) { 101*10465441SEvalZero inpub_id = 0; 102*10465441SEvalZero } else if(topic[0] == 'A') { 103*10465441SEvalZero /* All topics starting with 'A' might be handled at the same way */ 104*10465441SEvalZero inpub_id = 1; 105*10465441SEvalZero } else { 106*10465441SEvalZero /* For all other topics */ 107*10465441SEvalZero inpub_id = 2; 108*10465441SEvalZero } 109*10465441SEvalZero} 110*10465441SEvalZero 111*10465441SEvalZerostatic void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) 112*10465441SEvalZero{ 113*10465441SEvalZero printf("Incoming publish payload with length %d, flags %u\n", len, (unsigned int)flags); 114*10465441SEvalZero 115*10465441SEvalZero if(flags & MQTT_DATA_FLAG_LAST) { 116*10465441SEvalZero /* Last fragment of payload received (or whole part if payload fits receive buffer 117*10465441SEvalZero See MQTT_VAR_HEADER_BUFFER_LEN) */ 118*10465441SEvalZero 119*10465441SEvalZero /* Call function or do action depending on reference, in this case inpub_id */ 120*10465441SEvalZero if(inpub_id == 0) { 121*10465441SEvalZero /* Don't trust the publisher, check zero termination */ 122*10465441SEvalZero if(data[len-1] == 0) { 123*10465441SEvalZero printf("mqtt_incoming_data_cb: %s\n", (const char *)data); 124*10465441SEvalZero } 125*10465441SEvalZero } else if(inpub_id == 1) { 126*10465441SEvalZero /* Call an 'A' function... */ 127*10465441SEvalZero } else { 128*10465441SEvalZero printf("mqtt_incoming_data_cb: Ignoring payload...\n"); 129*10465441SEvalZero } 130*10465441SEvalZero } else { 131*10465441SEvalZero /* Handle fragmented payload, store in buffer, write to file or whatever */ 132*10465441SEvalZero } 133*10465441SEvalZero} 134*10465441SEvalZero 135*10465441SEvalZero----------------------------------------------------------------- 136*10465441SEvalZero4. Using outgoing publish 137*10465441SEvalZero 138*10465441SEvalZero 139*10465441SEvalZerovoid example_publish(mqtt_client_t *client, void *arg) 140*10465441SEvalZero{ 141*10465441SEvalZero const char *pub_payload= "PubSubHubLubJub"; 142*10465441SEvalZero err_t err; 143*10465441SEvalZero u8_t qos = 2; /* 0 1 or 2, see MQTT specification */ 144*10465441SEvalZero u8_t retain = 0; /* No don't retain such crappy payload... */ 145*10465441SEvalZero err = mqtt_publish(client, "pub_topic", pub_payload, strlen(pub_payload), qos, retain, mqtt_pub_request_cb, arg); 146*10465441SEvalZero if(err != ERR_OK) { 147*10465441SEvalZero printf("Publish err: %d\n", err); 148*10465441SEvalZero } 149*10465441SEvalZero} 150*10465441SEvalZero 151*10465441SEvalZero/* Called when publish is complete either with sucess or failure */ 152*10465441SEvalZerostatic void mqtt_pub_request_cb(void *arg, err_t result) 153*10465441SEvalZero{ 154*10465441SEvalZero if(result != ERR_OK) { 155*10465441SEvalZero printf("Publish result: %d\n", result); 156*10465441SEvalZero } 157*10465441SEvalZero} 158*10465441SEvalZero 159*10465441SEvalZero----------------------------------------------------------------- 160*10465441SEvalZero5. Disconnecting 161*10465441SEvalZero 162*10465441SEvalZeroSimply call mqtt_disconnect(client) 163