From d3a26bcd0beebe9b7b0beeac25597068d3b9a0df Mon Sep 17 00:00:00 2001
From: Yudi Ludkevich <urx.forever@gmail.com>
Date: Sat, 2 Jan 2016 10:41:28 +0300
Subject: [PATCH] MQTT client api and example

This code based on ESP8266 port of the embedded C client in Eclipse Paho project
(http://www.eclipse.org/paho/) and it port for espressif
ESP8266_RTOS_SDK by baoshi (https://github.com/baoshi/ESP-RTOS-Paho.git)
---
 examples/mqtt_client/Makefile        |   5 +
 examples/mqtt_client/mqtt_client.c   | 249 ++++++++++++
 extras/paho/MQTTClient.c             | 551 +++++++++++++++++++++++++++
 extras/paho/MQTTClient.h             |  91 +++++
 extras/paho/MQTTConnect.h            | 136 +++++++
 extras/paho/MQTTConnectClient.c      | 214 +++++++++++
 extras/paho/MQTTDeserializePublish.c | 107 ++++++
 extras/paho/MQTTESP8266.c            | 252 ++++++++++++
 extras/paho/MQTTESP8266.h            |  59 +++
 extras/paho/MQTTFormat.h             |  37 ++
 extras/paho/MQTTPacket.c             | 409 ++++++++++++++++++++
 extras/paho/MQTTPacket.h             | 133 +++++++
 extras/paho/MQTTPublish.h            |  38 ++
 extras/paho/MQTTSerializePublish.c   | 169 ++++++++
 extras/paho/MQTTSubscribe.h          |  39 ++
 extras/paho/MQTTSubscribeClient.c    | 137 +++++++
 extras/paho/MQTTUnsubscribe.h        |  38 ++
 extras/paho/MQTTUnsubscribeClient.c  | 106 ++++++
 extras/paho/StackTrace.h             |  77 ++++
 extras/paho/component.mk             |   9 +
 20 files changed, 2856 insertions(+)
 create mode 100644 examples/mqtt_client/Makefile
 create mode 100644 examples/mqtt_client/mqtt_client.c
 create mode 100644 extras/paho/MQTTClient.c
 create mode 100644 extras/paho/MQTTClient.h
 create mode 100644 extras/paho/MQTTConnect.h
 create mode 100644 extras/paho/MQTTConnectClient.c
 create mode 100644 extras/paho/MQTTDeserializePublish.c
 create mode 100644 extras/paho/MQTTESP8266.c
 create mode 100644 extras/paho/MQTTESP8266.h
 create mode 100644 extras/paho/MQTTFormat.h
 create mode 100644 extras/paho/MQTTPacket.c
 create mode 100644 extras/paho/MQTTPacket.h
 create mode 100644 extras/paho/MQTTPublish.h
 create mode 100644 extras/paho/MQTTSerializePublish.c
 create mode 100644 extras/paho/MQTTSubscribe.h
 create mode 100644 extras/paho/MQTTSubscribeClient.c
 create mode 100644 extras/paho/MQTTUnsubscribe.h
 create mode 100644 extras/paho/MQTTUnsubscribeClient.c
 create mode 100644 extras/paho/StackTrace.h
 create mode 100644 extras/paho/component.mk

diff --git a/examples/mqtt_client/Makefile b/examples/mqtt_client/Makefile
new file mode 100644
index 0000000..72225a9
--- /dev/null
+++ b/examples/mqtt_client/Makefile
@@ -0,0 +1,5 @@
+#!/bin/make
+
+PROGRAM=mqtt_client
+EXTRA_COMPONENTS = extras/paho
+include ../../common.mk
diff --git a/examples/mqtt_client/mqtt_client.c b/examples/mqtt_client/mqtt_client.c
new file mode 100644
index 0000000..d0cd03a
--- /dev/null
+++ b/examples/mqtt_client/mqtt_client.c
@@ -0,0 +1,249 @@
+
+#include "espressif/esp_common.h"
+#include "esp/uart.h"
+
+#include <string.h>
+
+#include <FreeRTOS.h>
+#include <task.h>
+#include <ssid_config.h>
+
+#include <espressif/esp_sta.h>
+#include <espressif/esp_wifi.h>
+
+#include <paho/MQTTESP8266.h>
+#include <paho/MQTTClient.h>
+
+#include <semphr.h>
+
+#define MQTT_HOST ("192.168.1.4")
+#define MQTT_PORT 6666
+
+#define MQTT_USER "user"
+#define MQTT_PASS "pass"
+
+xSemaphoreHandle wifi_alive;
+xQueueHandle publish_queue;
+#define PUB_MSG_LEN 16
+
+static void ICACHE_FLASH_ATTR beat_task(void *pvParameters)
+{
+	portTickType xLastWakeTime = xTaskGetTickCount();
+	char msg[PUB_MSG_LEN];
+	int count = 0;
+
+	while (1) {
+		vTaskDelayUntil(&xLastWakeTime, 10000 / portTICK_RATE_MS);
+		printf("beat\r\n");
+		snprintf(msg, PUB_MSG_LEN, "Beat %d\r\n", count++);
+		if (xQueueSend(publish_queue, (void *)msg, 0) == pdFALSE) {
+			printf("Publish queue overflow.\r\n");
+		}
+	}
+}
+
+static void ICACHE_FLASH_ATTR topic_received(MessageData *md)
+{
+	int i;
+	MQTTMessage *message = md->message;
+	printf("Received: ");
+	for( i = 0; i < md->topic->lenstring.len; ++i)
+		printf("%c", md->topic->lenstring.data[ i ]);
+
+	printf(" = ");
+	for( i = 0; i < (int)message->payloadlen; ++i)
+		printf("%c", ((char *)(message->payload))[i]);
+
+	printf("\r\n");
+}
+
+LOCAL const char * ICACHE_FLASH_ATTR get_my_id(void)
+{
+    // Use MAC address for Station as unique ID
+    static char my_id[13];
+    static bool my_id_done = false;
+    int8_t i;
+    uint8_t x;
+    if (my_id_done)
+        return my_id;
+    if (!sdk_wifi_get_macaddr(STATION_IF, (uint8_t *)my_id))
+        return NULL;
+    for (i = 5; i >= 0; --i)
+    {
+        x = my_id[i] & 0x0F;
+        if (x > 9) x += 7;
+        my_id[i * 2 + 1] = x + '0';
+        x = my_id[i] >> 4;
+        if (x > 9) x += 7;
+        my_id[i * 2] = x + '0';
+    }
+    my_id[12] = '\0';
+    my_id_done = true;
+    return my_id;
+}
+
+static void ICACHE_FLASH_ATTR mqtt_task(void *pvParameters)
+{
+	int ret			= 0;
+	struct Network network;
+	MQTTClient client	= DefaultClient;
+	char mqtt_client_id[20];
+	uint8_t mqtt_buf[100];
+	uint8_t mqtt_readbuf[100];
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+
+	NewNetwork( &network );
+	memset(mqtt_client_id, 0, sizeof(mqtt_client_id));
+	strcpy(mqtt_client_id, "ESP-");
+	strcat(mqtt_client_id, get_my_id());
+
+	while(1) {
+		xSemaphoreTake(wifi_alive, portMAX_DELAY);
+		printf("%s: started\n\r", __func__);
+		printf("%s: (Re)connecting to MQTT server %s ... ",__func__,
+			       	MQTT_HOST);
+		ret = ConnectNetwork(&network, MQTT_HOST, MQTT_PORT);
+		if( ret ){
+			printf("error: %d\n\r", ret);
+			taskYIELD();
+			continue;
+		}
+		printf("done\n\r");
+		NewMQTTClient(&client, &network, 5000, mqtt_buf, 100, 
+				mqtt_readbuf, 100);
+
+		data.willFlag		= 0;
+		data.MQTTVersion	= 3;
+		data.clientID.cstring	= mqtt_client_id;
+		data.username.cstring	= MQTT_USER;
+		data.password.cstring	= MQTT_PASS;
+		data.keepAliveInterval	= 10;
+		data.cleansession	= 0;
+		printf("Send MQTT connect ... ");
+		ret = MQTTConnect(&client, &data);
+		if(ret){
+			printf("error: %d\n\r", ret);
+			DisconnectNetwork(&network);
+			taskYIELD();
+			continue;
+		}
+		printf("done\r\n");
+		MQTTSubscribe(&client, "/esptopic", QOS1, topic_received);
+		xQueueReset(publish_queue);
+
+		while(1){
+
+			char msg[PUB_MSG_LEN - 1] = "\0";
+			while(xQueueReceive(publish_queue, (void *)msg, 0) ==
+					pdTRUE){
+				printf("got message to publish\r\n");
+				MQTTMessage message;
+				message.payload	= msg;
+				message.payloadlen = PUB_MSG_LEN;
+				message.dup = 0;
+				message.qos = QOS1;
+				message.retained = 0;
+				ret = MQTTPublish(&client, "/beat", &message);
+				if (ret != SUCCESS ){
+					printf("error while publishing message: %d\n", ret );
+					break;
+				}
+			}
+
+			ret = MQTTYield(&client, 1000);
+			if (ret == DISCONNECTED)
+				break;
+		}
+		printf("Connection dropped, request restart\n\r");
+		taskYIELD();
+	}
+}
+
+static void ICACHE_FLASH_ATTR wifi_task(void *pvParameters)
+{
+	uint8_t status	= 0;
+	uint8_t retries = 30;
+	struct sdk_station_config config = {
+		.ssid = WIFI_SSID,
+		.password = WIFI_PASS,
+	};
+
+	printf("WiFi: connecting to WiFi\n\r");
+	sdk_wifi_set_opmode(STATION_MODE);
+	sdk_wifi_station_set_config(&config);
+
+	while(1)
+	{
+		while ((status != STATION_GOT_IP) && (retries)){
+			status = sdk_wifi_station_get_connect_status();
+			printf("%s: status = %d\n\r", __func__, status );
+			if( status == STATION_WRONG_PASSWORD ){
+				printf("WiFi: wrong password\n\r");
+				break;
+			} else if( status == STATION_NO_AP_FOUND ) {
+				printf("WiFi: AP not found\n\r");
+				break;
+			} else if( status == STATION_CONNECT_FAIL ) {
+				printf("WiFi: connection failed\r\n");
+				break;
+			}
+			vTaskDelay( 1000 / portTICK_RATE_MS );
+			--retries;
+		}
+		if (status == STATION_GOT_IP) {
+			printf("WiFi: Connected\n\r");
+			xSemaphoreGive( wifi_alive );
+			taskYIELD();
+		}
+
+		while ((status = sdk_wifi_station_get_connect_status()) == STATION_GOT_IP) {
+			xSemaphoreGive( wifi_alive );
+			taskYIELD();
+		}
+		printf("WiFi: disconnected\n\r");
+		sdk_wifi_station_disconnect();
+		vTaskDelay( 1000 / portTICK_RATE_MS );
+	}
+}
+
+#if 0
+void mqtt_stuff(void *pvParameters)
+{
+	struct Network network;
+	uint8_t mqtt_buf[100];
+	uint8_t mqtt_readbuf[100];
+	MQTTClient client = DefaultClient;
+	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+
+	printf("configuring network\r\n");
+	NewNetwork(&network);
+	printf("connecting to mqtt host\r\n");
+	ConnectNetwork(&network, MQTT_HOST, MQTT_PORT);
+	printf("creating mqtt client\r\n");
+	NewMQTTClient(&client, &network, 5000, mqtt_buf, 100, mqtt_readbuf, 100);
+
+	data.willFlag			= 0;
+	data.MQTTVersion		= 3;
+	data.clientID.cstring		= mqtt_client_id;
+	data.username.cstring		= MQTT_USER;
+	data.password.cstring		= MQTT_PASS;
+	data.keepAliveInterval		= 10;
+	data.cleansession		= 0;
+	printf("connecting client\r\n");
+	printf("heap: %d\n\r", xPortGetFreeHeapSize());
+	MQTTConnect(&client, &data);
+
+	printf("mqtt_stuff done\r\n");
+}
+#endif
+void user_init(void)
+{
+    uart_set_baud(0, 115200);
+    printf("SDK version:%s\n", sdk_system_get_sdk_version());
+
+    vSemaphoreCreateBinary(wifi_alive);
+    publish_queue = xQueueCreate(3, PUB_MSG_LEN);
+    xTaskCreate(&wifi_task, (int8_t *)"wifi_task",  256, NULL, 2, NULL);
+    xTaskCreate(&beat_task, (int8_t *)"beat_task", 256, NULL, 3, NULL);
+    xTaskCreate(&mqtt_task, (int8_t *)"mqtt_task", 1024, NULL, 4, NULL);
+}
diff --git a/extras/paho/MQTTClient.c b/extras/paho/MQTTClient.c
new file mode 100644
index 0000000..b964250
--- /dev/null
+++ b/extras/paho/MQTTClient.c
@@ -0,0 +1,551 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+#include <espressif/esp_common.h>
+#include <lwip/arch.h>
+#include "MQTTClient.h"
+
+void  NewMessageData(MessageData* md, MQTTString* aTopicName, MQTTMessage* aMessgage) {
+    md->topic = aTopicName;
+    md->message = aMessgage;
+}
+
+
+int  getNextPacketId(MQTTClient *c) {
+    return c->next_packetid = (c->next_packetid == MAX_PACKET_ID) ? 1 : c->next_packetid + 1;
+}
+
+
+int  sendPacket(MQTTClient* c, int length, Timer* timer)
+{
+    int rc = FAILURE,
+        sent = 0;
+
+    while (sent < length && !expired(timer))
+    {
+        rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length, left_ms(timer));
+        if (rc < 0)  // there was an error writing the data
+            break;
+        sent += rc;
+    }
+    if (sent == length)
+    {
+        countdown(&(c->ping_timer), c->keepAliveInterval); // record the fact that we have successfully sent the packet
+        rc = SUCCESS;
+    }
+    else
+        rc = FAILURE;
+    return rc;
+}
+
+
+int  decodePacket(MQTTClient* c, int* value, int timeout)
+{
+    unsigned char i;
+    int multiplier = 1;
+    int len = 0;
+    const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+    *value = 0;
+    do
+    {
+        int rc = MQTTPACKET_READ_ERROR;
+
+        if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+        {
+            rc = MQTTPACKET_READ_ERROR; /* bad data */
+            goto exit;
+        }
+        rc = c->ipstack->mqttread(c->ipstack, &i, 1, timeout);
+        if (rc != 1)
+            goto exit;
+        *value += (i & 127) * multiplier;
+        multiplier *= 128;
+    } while ((i & 128) != 0);
+exit:
+    return len;
+}
+
+
+int  readPacket(MQTTClient* c, Timer* timer)
+{
+    int rc = FAILURE;
+    MQTTHeader header = {0};
+    int len = 0;
+    int rem_len = 0;
+
+    /* 1. read the header byte.  This has the packet type in it */
+    if (c->ipstack->mqttread(c->ipstack, c->readbuf, 1, left_ms(timer)) != 1)
+        goto exit;
+
+    len = 1;
+    /* 2. read the remaining length.  This is variable in itself */
+    decodePacket(c, &rem_len, left_ms(timer));
+    len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+    /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+    if (rem_len > 0 && (c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, left_ms(timer)) != rem_len))
+        goto exit;
+
+    header.byte = c->readbuf[0];
+    rc = header.bits.type;
+exit:
+    //dmsg_printf("readPacket=%d\r\n", rc);
+    return rc;
+}
+
+
+// assume topic filter and name is in correct format
+// # can only be at end
+// + and # can only be next to separator
+char  isTopicMatched(char* topicFilter, MQTTString* topicName)
+{
+    char* curf = topicFilter;
+    char* curn = topicName->lenstring.data;
+    char* curn_end = curn + topicName->lenstring.len;
+
+    while (*curf && curn < curn_end)
+    {
+        if (*curn == '/' && *curf != '/')
+            break;
+        if (*curf != '+' && *curf != '#' && *curf != *curn)
+            break;
+        if (*curf == '+')
+        {   // skip until we meet the next separator, or end of string
+            char* nextpos = curn + 1;
+            while (nextpos < curn_end && *nextpos != '/')
+                nextpos = ++curn + 1;
+        }
+        else if (*curf == '#')
+            curn = curn_end - 1;    // skip until end of string
+        curf++;
+        curn++;
+    };
+
+    return (curn == curn_end) && (*curf == '\0');
+}
+
+
+int  deliverMessage(MQTTClient* c, MQTTString* topicName, MQTTMessage* message)
+{
+    int i;
+    int rc = FAILURE;
+
+    // we have to find the right message handler - indexed by topic
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        if (c->messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(topicName, (char*)c->messageHandlers[i].topicFilter) ||
+                isTopicMatched((char*)c->messageHandlers[i].topicFilter, topicName)))
+        {
+            if (c->messageHandlers[i].fp != NULL)
+            {
+                MessageData md;
+                NewMessageData(&md, topicName, message);
+                c->messageHandlers[i].fp(&md);
+                rc = SUCCESS;
+            }
+        }
+    }
+
+    if (rc == FAILURE && c->defaultMessageHandler != NULL)
+    {
+        MessageData md;
+        NewMessageData(&md, topicName, message);
+        c->defaultMessageHandler(&md);
+        rc = SUCCESS;
+    }
+
+    return rc;
+}
+
+
+int  keepalive(MQTTClient* c)
+{
+    int rc = SUCCESS;
+
+    if (c->keepAliveInterval == 0)
+    {
+        rc = SUCCESS;
+        goto exit;
+    }
+
+    if (expired(&(c->ping_timer)))
+    {
+        if (c->ping_outstanding)
+        {
+            // if ping failure accumulated above MAX_FAIL_ALLOWED, the connection is broken
+            ++(c->fail_count);
+            if (c->fail_count >= MAX_FAIL_ALLOWED)
+            {
+                rc = DISCONNECTED;
+                goto exit;
+            }
+        }
+        else
+        {
+            Timer timer;
+            InitTimer(&timer);
+            countdown_ms(&timer, 1000);
+            c->ping_outstanding = 1;
+            int len = MQTTSerialize_pingreq(c->buf, c->buf_size);
+            if (len > 0)
+                sendPacket(c, len, &timer);
+        }
+        // re-arm ping counter
+        countdown(&(c->ping_timer), c->keepAliveInterval);
+    }
+
+exit:
+    return rc;
+}
+
+
+int  cycle(MQTTClient* c, Timer* timer)
+{
+    // read the socket, see what work is due
+    unsigned short packet_type = readPacket(c, timer);
+
+    int len = 0,
+        rc = SUCCESS;
+
+    switch (packet_type)
+    {
+        case CONNACK:
+        case PUBACK:
+        case SUBACK:
+            break;
+        case PUBLISH:
+        {
+            MQTTString topicName;
+            MQTTMessage msg;
+            if (MQTTDeserialize_publish((unsigned char*)&msg.dup, (int*)&msg.qos, (unsigned char*)&msg.retained, (unsigned short*)&msg.id, &topicName,
+               (unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
+                goto exit;
+            deliverMessage(c, &topicName, &msg);
+            if (msg.qos != QOS0)
+            {
+                if (msg.qos == QOS1)
+                    len = MQTTSerialize_ack(c->buf, c->buf_size, PUBACK, 0, msg.id);
+                else if (msg.qos == QOS2)
+                    len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREC, 0, msg.id);
+                if (len <= 0)
+                    rc = FAILURE;
+                else
+                    rc = sendPacket(c, len, timer);
+                if (rc == FAILURE)
+                    goto exit; // there was a problem
+            }
+            break;
+        }
+        case PUBREC:
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+            else if ((len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREL, 0, mypacketid)) <= 0)
+                rc = FAILURE;
+            else if ((rc = sendPacket(c, len, timer)) != SUCCESS) // send the PUBREL packet
+                rc = FAILURE; // there was a problem
+            if (rc == FAILURE)
+                goto exit; // there was a problem
+            break;
+        }
+        case PUBCOMP:
+            break;
+        case PINGRESP:
+            {
+                c->ping_outstanding = 0;
+                c->fail_count = 0;
+            }
+            break;
+    }
+    if (c->isconnected)
+        rc = keepalive(c);
+exit:
+    if (rc == SUCCESS)
+        rc = packet_type;
+    return rc;
+}
+
+
+void  NewMQTTClient(MQTTClient* c, Network* network, unsigned int command_timeout_ms, unsigned char* buf, size_t buf_size, unsigned char* readbuf, size_t readbuf_size)
+{
+    int i;
+    c->ipstack = network;
+
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+        c->messageHandlers[i].topicFilter = 0;
+    c->command_timeout_ms = command_timeout_ms;
+    c->buf = buf;
+    c->buf_size = buf_size;
+    c->readbuf = readbuf;
+    c->readbuf_size = readbuf_size;
+    c->isconnected = 0;
+    c->ping_outstanding = 0;
+    c->fail_count = 0;
+    c->defaultMessageHandler = NULL;
+    InitTimer(&(c->ping_timer));
+}
+
+
+int  MQTTYield(MQTTClient* c, int timeout_ms)
+{
+    int rc = SUCCESS;
+    Timer timer;
+
+    InitTimer(&timer);
+    countdown_ms(&timer, timeout_ms);
+    while (!expired(&timer))
+    {
+        rc = cycle(c, &timer);
+        // cycle could return 0 or packet_type or 65535 if nothing is read
+        // cycle returns DISCONNECTED only if keepalive() fails.
+        if (rc == DISCONNECTED)
+            break;
+        rc = SUCCESS;
+    }
+    return rc;
+}
+
+
+// only used in single-threaded mode where one command at a time is in process
+int  waitfor(MQTTClient* c, int packet_type, Timer* timer)
+{
+    int rc = FAILURE;
+
+    do
+    {
+        if (expired(timer))
+            break; // we timed out
+    }
+    while ((rc = cycle(c, timer)) != packet_type);
+
+    return rc;
+}
+
+
+int  MQTTConnect(MQTTClient* c, MQTTPacket_connectData* options)
+{
+    Timer connect_timer;
+    int rc = FAILURE;
+    MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
+    int len = 0;
+
+    InitTimer(&connect_timer);
+    countdown_ms(&connect_timer, c->command_timeout_ms);
+
+    if (c->isconnected) // don't send connect packet again if we are already connected
+        goto exit;
+
+    if (options == 0)
+        options = &default_options; // set default options if none were supplied
+
+    c->keepAliveInterval = options->keepAliveInterval;
+    countdown(&(c->ping_timer), c->keepAliveInterval);
+
+    if ((len = MQTTSerialize_connect(c->buf, c->buf_size, options)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &connect_timer)) != SUCCESS)  // send the connect packet
+        goto exit; // there was a problem
+
+    // this will be a blocking call, wait for the connack
+    if (waitfor(c, CONNACK, &connect_timer) == CONNACK)
+    {
+        unsigned char connack_rc = 255;
+        char sessionPresent = 0;
+        if (MQTTDeserialize_connack((unsigned char*)&sessionPresent, &connack_rc, c->readbuf, c->readbuf_size) == 1)
+            rc = connack_rc;
+        else
+            rc = FAILURE;
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    if (rc == SUCCESS)
+        c->isconnected = 1;
+    return rc;
+}
+
+
+int  MQTTSubscribe(MQTTClient* c, const char* topic, enum QoS qos, messageHandler handler)
+{
+    int rc = FAILURE;
+    Timer timer;
+    int len = 0;
+    MQTTString topicStr = MQTTString_initializer;
+    topicStr.cstring = (char *)topic;
+
+    InitTimer(&timer);
+    countdown_ms(&timer, c->command_timeout_ms);
+    if (!c->isconnected)
+        goto exit;
+
+    len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topicStr, (int*)&qos);
+    if (len <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+    {
+        goto exit;             // there was a problem
+    }
+
+    if (waitfor(c, SUBACK, &timer) == SUBACK)      // wait for suback
+    {
+        int count = 0, grantedQoS = -1;
+        unsigned short mypacketid;
+        if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, c->readbuf, c->readbuf_size) == 1)
+            rc = grantedQoS; // 0, 1, 2 or 0x80
+        if (rc != 0x80)
+        {
+            int i;
+            for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+            {
+                if (c->messageHandlers[i].topicFilter == 0)
+                {
+                    c->messageHandlers[i].topicFilter = topic;
+                    c->messageHandlers[i].fp = handler;
+                    rc = 0;
+                    break;
+                }
+            }
+        }
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    return rc;
+}
+
+
+int  MQTTUnsubscribe(MQTTClient* c, const char* topicFilter)
+{
+    int rc = FAILURE;
+    Timer timer;
+    MQTTString topic = MQTTString_initializer;
+    topic.cstring = (char *)topicFilter;
+    int len = 0;
+
+    InitTimer(&timer);
+    countdown_ms(&timer, c->command_timeout_ms);
+
+    if (!c->isconnected)
+        goto exit;
+
+    if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+        goto exit; // there was a problem
+
+    if (waitfor(c, UNSUBACK, &timer) == UNSUBACK)
+    {
+        unsigned short mypacketid;  // should be the same as the packetid above
+        if (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1)
+            rc = 0;
+    }
+    else
+        rc = FAILURE;
+
+exit:
+    return rc;
+}
+
+
+int  MQTTPublish(MQTTClient* c, const char* topic, MQTTMessage* message)
+{
+    int rc = FAILURE;
+    Timer timer;
+    MQTTString topicStr = MQTTString_initializer;
+    topicStr.cstring = (char *)topic;
+    int len = 0;
+
+    InitTimer(&timer);
+    countdown_ms(&timer, c->command_timeout_ms);
+
+    if (!c->isconnected)
+        goto exit;
+
+    if (message->qos == QOS1 || message->qos == QOS2)
+        message->id = getNextPacketId(c);
+
+    len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id, 
+              topicStr, (unsigned char*)message->payload, message->payloadlen);
+    if (len <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+    {
+        goto exit; // there was a problem
+    }
+
+    if (message->qos == QOS1)
+    {
+        if (waitfor(c, PUBACK, &timer) == PUBACK)
+        {
+            // We still can receive from broker, treat as recoverable
+            c->fail_count = 0;
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+            else
+                rc = SUCCESS;
+        }
+        else
+        {
+            rc = FAILURE;
+        }
+
+    }
+    else if (message->qos == QOS2)
+    {
+        if (waitfor(c, PUBCOMP, &timer) == PUBCOMP)
+        {
+            // We still can receive from broker, treat as recoverable
+            c->fail_count = 0;
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+            else
+                rc = SUCCESS;
+        }
+        else
+        {
+            rc = FAILURE;
+        }
+    }
+
+exit:
+    return rc;
+}
+
+
+int  MQTTDisconnect(MQTTClient* c)
+{
+    int rc = FAILURE;
+    Timer timer;     // we might wait for incomplete incoming publishes to complete
+    int len = MQTTSerialize_disconnect(c->buf, c->buf_size);
+
+    InitTimer(&timer);
+    countdown_ms(&timer, c->command_timeout_ms);
+
+    if (len > 0)
+        rc = sendPacket(c, len, &timer);            // send the disconnect packet
+
+    c->isconnected = 0;
+    return rc;
+}
+
diff --git a/extras/paho/MQTTClient.h b/extras/paho/MQTTClient.h
new file mode 100644
index 0000000..f7ea424
--- /dev/null
+++ b/extras/paho/MQTTClient.h
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef __MQTT_CLIENT_C_
+#define __MQTT_CLIENT_C_
+
+#include "MQTTPacket.h"
+#include "MQTTESP8266.h"
+
+#define MAX_PACKET_ID 65535
+#define MAX_MESSAGE_HANDLERS 5
+#define MAX_FAIL_ALLOWED  2
+
+enum QoS { QOS0, QOS1, QOS2 };
+
+// all failure return codes must be negative
+enum returnCode {DISCONNECTED = -3, BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
+
+void NewTimer(Timer*);
+
+typedef struct _MQTTMessage
+{
+    enum QoS qos;
+    char retained;
+    char dup;
+    unsigned short id;
+    void *payload;
+    size_t payloadlen;
+} MQTTMessage;
+
+typedef struct _MessageData
+{
+    MQTTString* topic;
+    MQTTMessage* message;
+} MessageData;
+
+typedef void (*messageHandler)(MessageData*);
+
+struct _MQTTClient
+{
+    unsigned int next_packetid;
+    unsigned int command_timeout_ms;
+    size_t buf_size, readbuf_size;
+    unsigned char *buf;
+    unsigned char *readbuf;
+    unsigned int keepAliveInterval;
+    char ping_outstanding;
+    int fail_count;
+    int isconnected;
+
+    struct MessageHandlers
+    {
+        const char* topicFilter;
+        void (*fp) (MessageData*);
+    } messageHandlers[MAX_MESSAGE_HANDLERS];      // Message handlers are indexed by subscription topic
+
+    void (*defaultMessageHandler) (MessageData*);
+
+    Network* ipstack;
+    Timer ping_timer;
+};
+
+
+typedef struct _MQTTClient MQTTClient;
+
+
+int MQTTConnect(MQTTClient* c, MQTTPacket_connectData* options);
+int MQTTPublish(MQTTClient* c, const char* topic, MQTTMessage* message);
+int MQTTSubscribe(MQTTClient* c, const char* topic, enum QoS qos, messageHandler handler);
+int MQTTUnsubscribe(MQTTClient* c, const char* topic);
+int MQTTDisconnect(MQTTClient* c);
+int MQTTYield(MQTTClient* c, int timeout_ms);
+
+void NewMQTTClient(MQTTClient*, Network*, unsigned int, unsigned char*, size_t, unsigned char*, size_t);
+
+#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}
+
+#endif
diff --git a/extras/paho/MQTTConnect.h b/extras/paho/MQTTConnect.h
new file mode 100644
index 0000000..3d8addd
--- /dev/null
+++ b/extras/paho/MQTTConnect.h
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTCONNECT_H_
+#define MQTTCONNECT_H_
+
+#if !defined(DLLImport)
+  #define DLLImport
+#endif
+#if !defined(DLLExport)
+  #define DLLExport
+#endif
+
+
+typedef union
+{
+	unsigned char all;	/**< all connect flags */
+#if defined(REVERSED)
+	struct
+	{
+		unsigned int username : 1;			/**< 3.1 user name */
+		unsigned int password : 1; 			/**< 3.1 password */
+		unsigned int willRetain : 1;		/**< will retain setting */
+		unsigned int willQoS : 2;				/**< will QoS value */
+		unsigned int will : 1;			    /**< will flag */
+		unsigned int cleansession : 1;	  /**< clean session flag */
+		unsigned int : 1;	  	          /**< unused */
+	} bits;
+#else
+	struct
+	{
+		unsigned int : 1;	     					/**< unused */
+		unsigned int cleansession : 1;	  /**< cleansession flag */
+		unsigned int will : 1;			    /**< will flag */
+		unsigned int willQoS : 2;				/**< will QoS value */
+		unsigned int willRetain : 1;		/**< will retain setting */
+		unsigned int password : 1; 			/**< 3.1 password */
+		unsigned int username : 1;			/**< 3.1 user name */
+	} bits;
+#endif
+} MQTTConnectFlags;	/**< connect flags byte */
+
+
+
+/**
+ * Defines the MQTT "Last Will and Testament" (LWT) settings for
+ * the connect packet.
+ */
+typedef struct
+{
+	/** The eyecatcher for this structure.  must be MQTW. */
+	char struct_id[4];
+	/** The version number of this structure.  Must be 0 */
+	int struct_version;
+	/** The LWT topic to which the LWT message will be published. */
+	MQTTString topicName;
+	/** The LWT payload. */
+	MQTTString message;
+	/**
+      * The retained flag for the LWT message (see MQTTAsync_message.retained).
+      */
+	unsigned char retained;
+	/**
+      * The quality of service setting for the LWT message (see
+      * MQTTAsync_message.qos and @ref qos).
+      */
+	char qos;
+} MQTTPacket_willOptions;
+
+
+#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
+
+
+typedef struct
+{
+	/** The eyecatcher for this structure.  must be MQTC. */
+	char struct_id[4];
+	/** The version number of this structure.  Must be 0 */
+	int struct_version;
+	/** Version of MQTT to be used.  3 = 3.1 4 = 3.1.1
+	  */
+	unsigned char MQTTVersion;
+	MQTTString clientID;
+	unsigned short keepAliveInterval;
+	unsigned char cleansession;
+	unsigned char willFlag;
+	MQTTPacket_willOptions will;
+	MQTTString username;
+	MQTTString password;
+} MQTTPacket_connectData;
+
+typedef union
+{
+	unsigned char all;	/**< all connack flags */
+#if defined(REVERSED)
+	struct
+	{
+		unsigned int sessionpresent : 1;    /**< session present flag */
+		unsigned int : 7;	  	          /**< unused */
+	} bits;
+#else
+	struct
+	{
+		unsigned int : 7;	     			/**< unused */
+		unsigned int sessionpresent : 1;    /**< session present flag */
+	} bits;
+#endif
+} MQTTConnackFlags;	/**< connack flags byte */
+
+#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
+		MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
+
+DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
+DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
+DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
+
+DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
+DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
+
+#endif /* MQTTCONNECT_H_ */
diff --git a/extras/paho/MQTTConnectClient.c b/extras/paho/MQTTConnectClient.c
new file mode 100644
index 0000000..4c1e862
--- /dev/null
+++ b/extras/paho/MQTTConnectClient.c
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+#include <espressif/esp_common.h>
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+  * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
+  * @param options the options to be used to build the connect packet
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int  MQTTSerialize_connectLength(MQTTPacket_connectData* options)
+{
+	int len = 0;
+
+	FUNC_ENTRY;
+
+	if (options->MQTTVersion == 3)
+		len = 12; /* variable depending on MQTT or MQIsdp */
+	else if (options->MQTTVersion == 4)
+		len = 10;
+
+	len += MQTTstrlen(options->clientID)+2;
+	if (options->willFlag)
+		len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
+	if (options->username.cstring || options->username.lenstring.data)
+		len += MQTTstrlen(options->username)+2;
+	if (options->password.cstring || options->password.lenstring.data)
+		len += MQTTstrlen(options->password)+2;
+
+	FUNC_EXIT_RC(len);
+	return len;
+}
+
+
+/**
+  * Serializes the connect options into the buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param len the length in bytes of the supplied buffer
+  * @param options the options to be used to build the connect packet
+  * @return serialized length, or error if 0
+  */
+int  MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
+{
+	unsigned char *ptr = buf;
+	MQTTHeader header = {0};
+	MQTTConnectFlags flags = {0};
+	int len = 0;
+	int rc = -1;
+
+	FUNC_ENTRY;
+	if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	header.byte = 0;
+	header.bits.type = CONNECT;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
+
+	if (options->MQTTVersion == 4)
+	{
+		writeCString(&ptr, "MQTT");
+		writeChar(&ptr, (char) 4);
+	}
+	else
+	{
+		writeCString(&ptr, "MQIsdp");
+		writeChar(&ptr, (char) 3);
+	}
+
+	flags.all = 0;
+	flags.bits.cleansession = options->cleansession;
+	flags.bits.will = (options->willFlag) ? 1 : 0;
+	if (flags.bits.will)
+	{
+		flags.bits.willQoS = options->will.qos;
+		flags.bits.willRetain = options->will.retained;
+	}
+
+	if (options->username.cstring || options->username.lenstring.data)
+		flags.bits.username = 1;
+	if (options->password.cstring || options->password.lenstring.data)
+		flags.bits.password = 1;
+
+	writeChar(&ptr, flags.all);
+	writeInt(&ptr, options->keepAliveInterval);
+	writeMQTTString(&ptr, options->clientID);
+	if (options->willFlag)
+	{
+		writeMQTTString(&ptr, options->will.topicName);
+		writeMQTTString(&ptr, options->will.message);
+	}
+	if (flags.bits.username)
+		writeMQTTString(&ptr, options->username);
+	if (flags.bits.password)
+		writeMQTTString(&ptr, options->password);
+
+	rc = ptr - buf;
+
+	exit: FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into connack data - return code
+  * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
+  * @param connack_rc returned integer value of the connack return code
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param len the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int  MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+	MQTTConnackFlags flags = {0};
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != CONNACK)
+		goto exit;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+	if (enddata - curdata < 2)
+		goto exit;
+
+	flags.all = readChar(&curdata);
+	*sessionPresent = flags.bits.sessionpresent;
+	*connack_rc = readChar(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+  * @param packettype the message type
+  * @return serialized length, or error if 0
+  */
+int  MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
+{
+	MQTTHeader header = {0};
+	int rc = -1;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 2)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	header.byte = 0;
+	header.bits.type = packettype;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+  * @return serialized length, or error if 0
+  */
+int  MQTTSerialize_disconnect(unsigned char* buf, int buflen)
+{
+	return MQTTSerialize_zero(buf, buflen, DISCONNECT);
+}
+
+
+/**
+  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+  * @return serialized length, or error if 0
+  */
+int  MQTTSerialize_pingreq(unsigned char* buf, int buflen)
+{
+	return MQTTSerialize_zero(buf, buflen, PINGREQ);
+}
diff --git a/extras/paho/MQTTDeserializePublish.c b/extras/paho/MQTTDeserializePublish.c
new file mode 100644
index 0000000..21b7314
--- /dev/null
+++ b/extras/paho/MQTTDeserializePublish.c
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+#include <espressif/esp_common.h>
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? 1 : 0)
+
+/**
+  * Deserializes the supplied (wire) buffer into publish data
+  * @param dup returned integer - the MQTT dup flag
+  * @param qos returned integer - the MQTT QoS value
+  * @param retained returned integer - the MQTT retained flag
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param topicName returned MQTTString - the MQTT topic in the publish
+  * @param payload returned byte buffer - the MQTT publish payload
+  * @param payloadlen returned integer - the length of the MQTT payload
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success
+  */
+int  MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
+		unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen = 0;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != PUBLISH)
+		goto exit;
+	*dup = header.bits.dup;
+	*qos = header.bits.qos;
+	*retained = header.bits.retain;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+
+	if (!readMQTTLenString(topicName, &curdata, enddata) ||
+		enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
+		goto exit;
+
+	if (*qos > 0)
+		*packetid = readInt(&curdata);
+
+	*payloadlen = enddata - curdata;
+	*payload = curdata;
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Deserializes the supplied (wire) buffer into an ack
+  * @param packettype returned integer - the MQTT packet type
+  * @param dup returned integer - the MQTT dup flag
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int  MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	*dup = header.bits.dup;
+	*packettype = header.bits.type;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+
+	if (enddata - curdata < 2)
+		goto exit;
+	*packetid = readInt(&curdata);
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
diff --git a/extras/paho/MQTTESP8266.c b/extras/paho/MQTTESP8266.c
new file mode 100644
index 0000000..22ac87c
--- /dev/null
+++ b/extras/paho/MQTTESP8266.c
@@ -0,0 +1,252 @@
+/**
+  ******************************************************************************
+  * @file    MQTTESP8266.c
+  * @author  Baoshi <mail(at)ba0sh1(dot)com>
+  * @version 0.1
+  * @date    Sep 9, 2015
+  * @brief   Eclipse Paho ported to ESP8266 RTOS
+  *
+  ******************************************************************************
+  * @copyright
+  *
+  * Copyright (c) 2015, Baoshi Zhu. All rights reserved.
+  * Use of this source code is governed by a BSD-style license that can be
+  * found in the LICENSE.txt file.
+  *
+  * THIS SOFTWARE IS PROVIDED 'AS-IS', WITHOUT ANY EXPRESS OR IMPLIED
+  * WARRANTY.  IN NO EVENT WILL THE AUTHOR(S) BE HELD LIABLE FOR ANY DAMAGES
+  * ARISING FROM THE USE OF THIS SOFTWARE.
+  *
+  */
+
+#include <espressif/esp_common.h>
+#include <lwip/sockets.h>
+#include <lwip/inet.h>
+#include <lwip/netdb.h>
+#include <lwip/sys.h>
+#include <string.h>
+
+#include "MQTTESP8266.h"
+
+char  expired(Timer* timer)
+{
+    portTickType now = xTaskGetTickCount();
+	int32_t left = timer->end_time - now;
+	return (left < 0);
+}
+
+
+void  countdown_ms(Timer* timer, unsigned int timeout)
+{
+    portTickType now = xTaskGetTickCount();
+	timer->end_time = now + timeout / portTICK_RATE_MS;
+}
+
+
+void  countdown(Timer* timer, unsigned int timeout)
+{
+    countdown_ms(timer, timeout * 1000);
+}
+
+
+int  left_ms(Timer* timer)
+{
+    portTickType now = xTaskGetTickCount();
+    int32_t left = timer->end_time - now;
+	return (left < 0) ? 0 : left / portTICK_RATE_MS;
+}
+
+
+void  InitTimer(Timer* timer)
+{
+	timer->end_time = 0;
+}
+
+
+
+int  mqtt_esp_read(Network* n, unsigned char* buffer, int len, int timeout_ms)
+{
+    struct timeval tv;
+    fd_set fdset;
+    int rc = 0;
+    int rcvd = 0;
+    FD_ZERO(&fdset);
+    FD_SET(n->my_socket, &fdset);
+    // It seems tv_sec actually means FreeRTOS tick
+    tv.tv_sec = timeout_ms / portTICK_RATE_MS;
+    tv.tv_usec = 0;
+    rc = select(n->my_socket + 1, &fdset, 0, 0, &tv);
+    if ((rc > 0) && (FD_ISSET(n->my_socket, &fdset)))
+    {
+        rcvd = recv(n->my_socket, buffer, len, 0);
+    }
+    else
+    {
+        // select fail
+        return -1;
+    }
+    return rcvd;
+}
+
+
+int  mqtt_esp_write(Network* n, unsigned char* buffer, int len, int timeout_ms)
+{
+	struct timeval tv;
+	fd_set fdset;
+	int rc = 0;
+
+	FD_ZERO(&fdset);
+	FD_SET(n->my_socket, &fdset);
+	// It seems tv_sec actually means FreeRTOS tick
+    tv.tv_sec = timeout_ms / portTICK_RATE_MS;
+    tv.tv_usec = 0;
+	rc = select(n->my_socket + 1, 0, &fdset, 0, &tv);
+	if ((rc > 0) && (FD_ISSET(n->my_socket, &fdset)))
+	{
+	    rc = send(n->my_socket, buffer, len, 0);
+	}
+	else
+	{
+	    // select fail
+	    return -1;
+	}
+	return rc;
+}
+
+
+
+void  NewNetwork(Network* n)
+{
+	n->my_socket = -1;
+	n->mqttread = mqtt_esp_read;
+	n->mqttwrite = mqtt_esp_write;
+}
+
+
+#if 0
+int TLSConnectNetwork(Network *n, char* addr, int port, SlSockSecureFiles_t* certificates, unsigned char sec_method, unsigned int cipher, char server_verify) {
+	SlSockAddrIn_t sAddr;
+	int addrSize;
+	int retVal;
+	unsigned long ipAddress;
+
+	retVal = sl_NetAppDnsGetHostByName(addr, strlen(addr), &ipAddress, AF_INET);
+	if (retVal < 0) {
+		return -1;
+	}
+
+	sAddr.sin_family = AF_INET;
+	sAddr.sin_port = sl_Htons((unsigned short)port);
+	sAddr.sin_addr.s_addr = sl_Htonl(ipAddress);
+
+	addrSize = sizeof(SlSockAddrIn_t);
+
+	n->my_socket = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, SL_SEC_SOCKET);
+	if (n->my_socket < 0) {
+		return -1;
+	}
+
+	SlSockSecureMethod method;
+	method.secureMethod = sec_method;
+	retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method));
+	if (retVal < 0) {
+		return retVal;
+	}
+
+	SlSockSecureMask mask;
+	mask.secureMask = cipher;
+	retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_MASK, &mask, sizeof(mask));
+	if (retVal < 0) {
+		return retVal;
+	}
+
+	if (certificates != NULL) {
+		retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_FILES, certificates->secureFiles, sizeof(SlSockSecureFiles_t));
+		if(retVal < 0)
+		{
+			return retVal;
+		}
+	}
+
+	retVal = sl_Connect(n->my_socket, ( SlSockAddr_t *)&sAddr, addrSize);
+	if( retVal < 0 ) {
+		if (server_verify || retVal != -453) {
+			sl_Close(n->my_socket);
+			return retVal;
+		}
+	}
+
+	SysTickIntRegister(SysTickIntHandler);
+	SysTickPeriodSet(80000);
+	SysTickEnable();
+
+	return retVal;
+}
+
+
+#endif
+
+
+LOCAL int  host2addr(const char *hostname , struct in_addr *in)
+{
+    struct addrinfo hints, *servinfo, *p;
+    struct sockaddr_in *h;
+    int rv;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    rv = getaddrinfo(hostname, 0 , &hints , &servinfo);
+    if (rv != 0)
+    {
+        return rv;
+    }
+
+    // loop through all the results and get the first resolve
+    for (p = servinfo; p != 0; p = p->ai_next)
+    {
+        h = (struct sockaddr_in *)p->ai_addr;
+        in->s_addr = h->sin_addr.s_addr;
+    }
+    freeaddrinfo(servinfo); // all done with this structure
+    return 0;
+}
+
+
+int  ConnectNetwork(Network* n, const char* host, int port)
+{
+    struct sockaddr_in addr;
+    int ret;
+
+    if (host2addr(host, &(addr.sin_addr)) != 0)
+    {
+        return -1;
+    }
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+
+    n->my_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if( n->my_socket < 0 )
+    {
+        // error
+        return -1;
+    }
+    ret = connect(n->my_socket, ( struct sockaddr *)&addr, sizeof(struct sockaddr_in));
+    if( ret < 0 )
+    {
+        // error
+        close(n->my_socket);
+        return ret;
+    }
+
+    return ret;
+}
+
+
+int  DisconnectNetwork(Network* n)
+{
+    close(n->my_socket);
+    n->my_socket = -1;
+    return 0;
+}
diff --git a/extras/paho/MQTTESP8266.h b/extras/paho/MQTTESP8266.h
new file mode 100644
index 0000000..f29921e
--- /dev/null
+++ b/extras/paho/MQTTESP8266.h
@@ -0,0 +1,59 @@
+/**
+  ******************************************************************************
+  * @file    MQTTESP8266.h
+  * @author  Baoshi <mail(at)ba0sh1(dot)com>
+  * @version 0.1
+  * @date    Sep 9, 2015
+  * @brief   Eclipse Paho ported to ESP8266 RTOS
+  *
+  ******************************************************************************
+  * @copyright
+  *
+  * Copyright (c) 2015, Baoshi Zhu. All rights reserved.
+  * Use of this source code is governed by a BSD-style license that can be
+  * found in the LICENSE.txt file.
+  *
+  * THIS SOFTWARE IS PROVIDED 'AS-IS', WITHOUT ANY EXPRESS OR IMPLIED
+  * WARRANTY.  IN NO EVENT WILL THE AUTHOR(S) BE HELD LIABLE FOR ANY DAMAGES
+  * ARISING FROM THE USE OF THIS SOFTWARE.
+  *
+  */
+#ifndef _MQTT_ESP8266_H_
+#define _MQTT_ESP8266_H_
+
+#include <FreeRTOS.h>
+#include <portmacro.h>
+
+typedef struct Timer Timer;
+
+struct Timer
+{
+    portTickType end_time;
+};
+
+typedef struct Network Network;
+
+struct Network
+{
+	int my_socket;
+	int (*mqttread) (Network*, unsigned char*, int, int);
+	int (*mqttwrite) (Network*, unsigned char*, int, int);
+};
+
+char expired(Timer*);
+void countdown_ms(Timer*, unsigned int);
+void countdown(Timer*, unsigned int);
+int left_ms(Timer*);
+
+void InitTimer(Timer*);
+
+int mqtt_esp_read(Network*, unsigned char*, int, int);
+int mqtt_esp_write(Network*, unsigned char*, int, int);
+void mqtt_esp_disconnect(Network*);
+
+void NewNetwork(Network* n);
+int ConnectNetwork(Network* n, const char* host, int port);
+int DisconnectNetwork(Network* n);
+
+
+#endif /* _MQTT_ESP8266_H_ */
diff --git a/extras/paho/MQTTFormat.h b/extras/paho/MQTTFormat.h
new file mode 100644
index 0000000..47b0c41
--- /dev/null
+++ b/extras/paho/MQTTFormat.h
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTFORMAT_H)
+#define MQTTFORMAT_H
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+const char* MQTTPacket_getName(unsigned short packetid);
+int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
+int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
+int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
+		unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
+int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
+int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
+		MQTTString topicFilters[], int requestedQoSs[]);
+int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
+int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[]);
+char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
+char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
+
+#endif
diff --git a/extras/paho/MQTTPacket.c b/extras/paho/MQTTPacket.c
new file mode 100644
index 0000000..eb36a50
--- /dev/null
+++ b/extras/paho/MQTTPacket.c
@@ -0,0 +1,409 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Sergio R. Caprile - non-blocking packet read functions for stream transport
+ *******************************************************************************/
+#include <espressif/esp_common.h>
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+/**
+ * Encodes the message length according to the MQTT algorithm
+ * @param buf the buffer into which the encoded data is written
+ * @param length the length to be encoded
+ * @return the number of bytes written to buffer
+ */
+int  MQTTPacket_encode(unsigned char* buf, int length)
+{
+	int rc = 0;
+
+	FUNC_ENTRY;
+	do
+	{
+		char d = length % 128;
+		length /= 128;
+		/* if there are more digits to encode, set the top bit of this digit */
+		if (length > 0)
+			d |= 0x80;
+		buf[rc++] = d;
+	} while (length > 0);
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+ * Decodes the message length according to the MQTT algorithm
+ * @param getcharfn pointer to function to read the next character from the data source
+ * @param value the decoded length returned
+ * @return the number of bytes read from the socket
+ */
+int  MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
+{
+	unsigned char c;
+	int multiplier = 1;
+	int len = 0;
+#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
+
+	FUNC_ENTRY;
+	*value = 0;
+	do
+	{
+		int rc = MQTTPACKET_READ_ERROR;
+
+		if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+		{
+			rc = MQTTPACKET_READ_ERROR;	/* bad data */
+			goto exit;
+		}
+		rc = (*getcharfn)(&c, 1);
+		if (rc != 1)
+			goto exit;
+		*value += (c & 127) * multiplier;
+		multiplier *= 128;
+	} while ((c & 128) != 0);
+exit:
+	FUNC_EXIT_RC(len);
+	return len;
+}
+
+
+int  MQTTPacket_len(int rem_len)
+{
+	rem_len += 1; /* header byte */
+
+	/* now remaining_length field */
+	if (rem_len < 128)
+		rem_len += 1;
+	else if (rem_len < 16384)
+		rem_len += 2;
+	else if (rem_len < 2097151)
+		rem_len += 3;
+	else
+		rem_len += 4;
+	return rem_len;
+}
+
+
+static unsigned char* bufptr;
+
+int  bufchar(unsigned char* c, int count)
+{
+	int i;
+
+	for (i = 0; i < count; ++i)
+		*c = *bufptr++;
+	return count;
+}
+
+
+int  MQTTPacket_decodeBuf(unsigned char* buf, int* value)
+{
+	bufptr = buf;
+	return MQTTPacket_decode(bufchar, value);
+}
+
+
+/**
+ * Calculates an integer from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the integer value calculated
+ */
+int  readInt(unsigned char** pptr)
+{
+	unsigned char* ptr = *pptr;
+	int len = 256*(*ptr) + (*(ptr+1));
+	*pptr += 2;
+	return len;
+}
+
+
+/**
+ * Reads one character from the input buffer.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the character read
+ */
+char  readChar(unsigned char** pptr)
+{
+	char c = **pptr;
+	(*pptr)++;
+	return c;
+}
+
+
+/**
+ * Writes one character to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param c the character to write
+ */
+void  writeChar(unsigned char** pptr, char c)
+{
+	**pptr = c;
+	(*pptr)++;
+}
+
+
+/**
+ * Writes an integer as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write
+ */
+void  writeInt(unsigned char** pptr, int anInt)
+{
+	**pptr = (unsigned char)(anInt / 256);
+	(*pptr)++;
+	**pptr = (unsigned char)(anInt % 256);
+	(*pptr)++;
+}
+
+
+/**
+ * Writes a "UTF" string to an output buffer.  Converts C string to length-delimited.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param string the C string to write
+ */
+void  writeCString(unsigned char** pptr, const char* string)
+{
+	int len = strlen(string);
+	writeInt(pptr, len);
+	memcpy(*pptr, string, len);
+	*pptr += len;
+}
+
+
+int  getLenStringLen(char* ptr)
+{
+	int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
+	return len;
+}
+
+
+void  writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
+{
+	if (mqttstring.lenstring.len > 0)
+	{
+		writeInt(pptr, mqttstring.lenstring.len);
+		memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
+		*pptr += mqttstring.lenstring.len;
+	}
+	else if (mqttstring.cstring)
+		writeCString(pptr, mqttstring.cstring);
+	else
+		writeInt(pptr, 0);
+}
+
+
+/**
+ * @param mqttstring the MQTTString structure into which the data is to be read
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param enddata pointer to the end of the data: do not read beyond
+ * @return 1 if successful, 0 if not
+ */
+int  readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
+{
+	int rc = 0;
+
+	FUNC_ENTRY;
+	/* the first two bytes are the length of the string */
+	if (enddata - (*pptr) > 1) /* enough length to read the integer? */
+	{
+		mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
+		if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
+		{
+			mqttstring->lenstring.data = (char*)*pptr;
+			*pptr += mqttstring->lenstring.len;
+			rc = 1;
+		}
+	}
+	mqttstring->cstring = NULL;
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+ * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
+ * @param mqttstring the string to return the length of
+ * @return the length of the string
+ */
+int  MQTTstrlen(MQTTString mqttstring)
+{
+	int rc = 0;
+
+	if (mqttstring.cstring)
+		rc = strlen(mqttstring.cstring);
+	else
+		rc = mqttstring.lenstring.len;
+	return rc;
+}
+
+
+/**
+ * Compares an MQTTString to a C string
+ * @param a the MQTTString to compare
+ * @param bptr the C string to compare
+ * @return boolean - equal or not
+ */
+int  MQTTPacket_equals(MQTTString* a, char* bptr)
+{
+	int alen = 0,
+		blen = 0;
+	char *aptr;
+
+	if (a->cstring)
+	{
+		aptr = a->cstring;
+		alen = strlen(a->cstring);
+	}
+	else
+	{
+		aptr = a->lenstring.data;
+		alen = a->lenstring.len;
+	}
+	blen = strlen(bptr);
+
+	return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
+}
+
+
+/**
+ * Helper function to read packet data from some source into a buffer
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param getfn pointer to a function which will read any number of bytes from the needed source
+ * @return integer MQTT packet type, or -1 on error
+ * @note  the whole message must fit into the caller's buffer
+ */
+int  MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
+{
+	int rc = -1;
+	MQTTHeader header = {0};
+	int len = 0;
+	int rem_len = 0;
+
+	/* 1. read the header byte.  This has the packet type in it */
+	if ((*getfn)(buf, 1) != 1)
+		goto exit;
+
+	len = 1;
+	/* 2. read the remaining length.  This is variable in itself */
+	MQTTPacket_decode(getfn, &rem_len);
+	len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+	/* 3. read the rest of the buffer using a callback to supply the rest of the data */
+	if((rem_len + len) > buflen)
+		goto exit;
+	if ((*getfn)(buf + len, rem_len) != rem_len)
+		goto exit;
+
+	header.byte = buf[0];
+	rc = header.bits.type;
+exit:
+	return rc;
+}
+
+/**
+ * Decodes the message length according to the MQTT algorithm, non-blocking
+ * @param trp pointer to a transport structure holding what is needed to solve getting data from it
+ * @param value the decoded length returned
+ * @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
+ */
+static int  MQTTPacket_decodenb(MQTTTransport *trp)
+{
+	unsigned char c;
+	int rc = MQTTPACKET_READ_ERROR;
+
+	FUNC_ENTRY;
+	if(trp->len == 0){		/* initialize on first call */
+		trp->multiplier = 1;
+		trp->rem_len = 0;
+	}
+	do {
+		int frc;
+		if (++(trp->len) > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+			goto exit;
+		if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
+			goto exit;
+		if (frc == 0){
+			rc = 0;
+			goto exit;
+		}
+		trp->rem_len += (c & 127) * trp->multiplier;
+		trp->multiplier *= 128;
+	} while ((c & 128) != 0);
+	rc = trp->len;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+/**
+ * Helper function to read packet data from some source into a buffer, non-blocking
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param trp pointer to a transport structure holding what is needed to solve getting data from it
+ * @return integer MQTT packet type, 0 for call again, or -1 on error
+ * @note  the whole message must fit into the caller's buffer
+ */
+int  MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
+{
+	int rc = -1, frc;
+	MQTTHeader header = {0};
+
+	switch(trp->state){
+	default:
+		trp->state = 0;
+		/*FALLTHROUGH*/
+	case 0:
+		/* read the header byte.  This has the packet type in it */
+		if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
+			goto exit;
+		if (frc == 0)
+			return 0;
+		trp->len = 0;
+		++trp->state;
+		/*FALLTHROUGH*/
+		/* read the remaining length.  This is variable in itself */
+	case 1:
+		if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
+			goto exit;
+		if(frc == 0)
+			return 0;
+		trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
+		if((trp->rem_len + trp->len) > buflen)
+			goto exit;
+		++trp->state;
+		/*FALLTHROUGH*/
+	case 2:
+		/* read the rest of the buffer using a callback to supply the rest of the data */
+		if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
+			goto exit;
+		if (frc == 0)
+			return 0;
+		trp->rem_len -= frc;
+		trp->len += frc;
+		if(trp->rem_len)
+			return 0;
+
+		header.byte = buf[0];
+		rc = header.bits.type;
+		break;
+	}
+
+exit:
+	trp->state = 0;
+	return rc;
+}
+
diff --git a/extras/paho/MQTTPacket.h b/extras/paho/MQTTPacket.h
new file mode 100644
index 0000000..c7909d9
--- /dev/null
+++ b/extras/paho/MQTTPacket.h
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTPACKET_H_
+#define MQTTPACKET_H_
+
+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
+extern "C" {
+#endif
+
+#if defined(WIN32_DLL) || defined(WIN64_DLL)
+  #define DLLImport __declspec(dllimport)
+  #define DLLExport __declspec(dllexport)
+#elif defined(LINUX_SO)
+  #define DLLImport extern
+  #define DLLExport  __attribute__ ((visibility ("default")))
+#else
+  #define DLLImport
+  #define DLLExport 
+#endif
+
+enum errors
+{
+	MQTTPACKET_BUFFER_TOO_SHORT = -2,
+	MQTTPACKET_READ_ERROR = -1,
+	MQTTPACKET_READ_COMPLETE
+};
+
+enum msgTypes
+{
+	CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
+	PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
+	PINGREQ, PINGRESP, DISCONNECT
+};
+
+/**
+ * Bitfields for the MQTT header byte.
+ */
+typedef union
+{
+	unsigned char byte;	                /**< the whole byte */
+#if defined(REVERSED)
+	struct
+	{
+		unsigned int type : 4;			/**< message type nibble */
+		unsigned int dup : 1;				/**< DUP flag bit */
+		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */
+		unsigned int retain : 1;		/**< retained flag bit */
+	} bits;
+#else
+	struct
+	{
+		unsigned int retain : 1;		/**< retained flag bit */
+		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */
+		unsigned int dup : 1;				/**< DUP flag bit */
+		unsigned int type : 4;			/**< message type nibble */
+	} bits;
+#endif
+} MQTTHeader;
+
+typedef struct
+{
+	int len;
+	char* data;
+} MQTTLenString;
+
+typedef struct
+{
+	char* cstring;
+	MQTTLenString lenstring;
+} MQTTString;
+
+#define MQTTString_initializer {NULL, {0, NULL}}
+
+int MQTTstrlen(MQTTString mqttstring);
+
+#include "MQTTConnect.h"
+#include "MQTTPublish.h"
+#include "MQTTSubscribe.h"
+#include "MQTTUnsubscribe.h"
+#include "MQTTFormat.h"
+
+int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
+int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
+
+int MQTTPacket_len(int rem_len);
+int MQTTPacket_equals(MQTTString* a, char* b);
+
+int MQTTPacket_encode(unsigned char* buf, int length);
+int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
+int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
+
+int readInt(unsigned char** pptr);
+char readChar(unsigned char** pptr);
+void writeChar(unsigned char** pptr, char c);
+void writeInt(unsigned char** pptr, int anInt);
+int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
+void writeCString(unsigned char** pptr, const char* string);
+void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
+
+DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
+
+typedef struct {
+	int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
+	void *sck;	/* pointer to whatever the system may use to identify the transport */
+	int multiplier;
+	int rem_len;
+	int len;
+	char state;
+}MQTTTransport;
+
+int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+
+#endif /* MQTTPACKET_H_ */
diff --git a/extras/paho/MQTTPublish.h b/extras/paho/MQTTPublish.h
new file mode 100644
index 0000000..ffd8752
--- /dev/null
+++ b/extras/paho/MQTTPublish.h
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTPUBLISH_H_
+#define MQTTPUBLISH_H_
+
+#if !defined(DLLImport)
+  #define DLLImport
+#endif
+#if !defined(DLLExport)
+  #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+		MQTTString topicName, unsigned char* payload, int payloadlen);
+
+DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
+		unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
+DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
+DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
+
+#endif /* MQTTPUBLISH_H_ */
diff --git a/extras/paho/MQTTSerializePublish.c b/extras/paho/MQTTSerializePublish.c
new file mode 100644
index 0000000..c3343c8
--- /dev/null
+++ b/extras/paho/MQTTSerializePublish.c
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
+ *******************************************************************************/
+#include <espressif/esp_common.h>
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+  * Determines the length of the MQTT publish packet that would be produced using the supplied parameters
+  * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
+  * @param topicName the topic name to be used in the publish
+  * @param payloadlen the length of the payload to be sent
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int  MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
+{
+	int len = 0;
+
+	len += 2 + MQTTstrlen(topicName) + payloadlen;
+	if (qos > 0)
+		len += 2; /* packetid */
+	return len;
+}
+
+
+/**
+  * Serializes the supplied publish data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param qos integer - the MQTT QoS value
+  * @param retained integer - the MQTT retained flag
+  * @param packetid integer - the MQTT packet identifier
+  * @param topicName MQTTString - the MQTT topic in the publish
+  * @param payload byte buffer - the MQTT publish payload
+  * @param payloadlen integer - the length of the MQTT payload
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int   MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+		MQTTString topicName, unsigned char* payload, int payloadlen)
+{
+	unsigned char *ptr = buf;
+	MQTTHeader header = {0};
+	int rem_len = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	header.bits.type = PUBLISH;
+	header.bits.dup = dup;
+	header.bits.qos = qos;
+	header.bits.retain = retained;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+	writeMQTTString(&ptr, topicName);
+
+	if (qos > 0)
+		writeInt(&ptr, packetid);
+
+	memcpy(ptr, payload, payloadlen);
+	ptr += payloadlen;
+
+	rc = ptr - buf;
+
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Serializes the ack packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param type the MQTT packet type
+  * @param dup the MQTT dup flag
+  * @param packetid the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int  MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
+{
+	MQTTHeader header = {0};
+	int rc = 0;
+	unsigned char *ptr = buf;
+
+	FUNC_ENTRY;
+	if (buflen < 4)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+	header.bits.type = packettype;
+	header.bits.dup = dup;
+	header.bits.qos = (packettype == PUBREL) ? 1 : 0;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+	writeInt(&ptr, packetid);
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Serializes a puback packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int  MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
+}
+
+
+/**
+  * Serializes a pubrel packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int  MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
+}
+
+
+/**
+  * Serializes a pubrel packet into the supplied buffer.
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied buffer
+  * @param packetid integer - the MQTT packet identifier
+  * @return serialized length, or error if 0
+  */
+int  MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
+{
+	return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
+}
+
+
diff --git a/extras/paho/MQTTSubscribe.h b/extras/paho/MQTTSubscribe.h
new file mode 100644
index 0000000..9b8511d
--- /dev/null
+++ b/extras/paho/MQTTSubscribe.h
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTSUBSCRIBE_H_
+#define MQTTSUBSCRIBE_H_
+
+#if !defined(DLLImport)
+  #define DLLImport
+#endif
+#if !defined(DLLExport)
+  #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[], int requestedQoSs[]);
+
+DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
+		int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
+
+DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);
+
+
+#endif /* MQTTSUBSCRIBE_H_ */
diff --git a/extras/paho/MQTTSubscribeClient.c b/extras/paho/MQTTSubscribeClient.c
new file mode 100644
index 0000000..a76a4d3
--- /dev/null
+++ b/extras/paho/MQTTSubscribeClient.c
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+#include <espressif/esp_common.h>
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+  * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
+  * @param count the number of topic filter strings in topicFilters
+  * @param topicFilters the array of topic filter strings to be used in the publish
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int  MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
+{
+	int i;
+	int len = 2; /* packetid */
+
+	for (i = 0; i < count; ++i)
+		len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
+	return len;
+}
+
+
+/**
+  * Serializes the supplied subscribe data into the supplied buffer, ready for sending
+  * @param buf the buffer into which the packet will be serialized
+  * @param buflen the length in bytes of the supplied bufferr
+  * @param dup integer - the MQTT dup flag
+  * @param packetid integer - the MQTT packet identifier
+  * @param count - number of members in the topicFilters and reqQos arrays
+  * @param topicFilters - array of topic filter names
+  * @param requestedQoSs - array of requested QoS
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int  MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
+		MQTTString topicFilters[], int requestedQoSs[])
+{
+	unsigned char *ptr = buf;
+	MQTTHeader header = {0};
+	int rem_len = 0;
+	int rc = 0;
+	int i = 0;
+
+	FUNC_ENTRY;
+	if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	header.byte = 0;
+	header.bits.type = SUBSCRIBE;
+	header.bits.dup = dup;
+	header.bits.qos = 1;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+	writeInt(&ptr, packetid);
+
+	for (i = 0; i < count; ++i)
+	{
+		writeMQTTString(&ptr, topicFilters[i]);
+		writeChar(&ptr, requestedQoSs[i]);
+	}
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+
+/**
+  * Deserializes the supplied (wire) buffer into suback data
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param maxcount - the maximum number of members allowed in the grantedQoSs array
+  * @param count returned integer - number of members in the grantedQoSs array
+  * @param grantedQoSs returned array of integers - the granted qualities of service
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int  MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)
+{
+	MQTTHeader header = {0};
+	unsigned char* curdata = buf;
+	unsigned char* enddata = NULL;
+	int rc = 0;
+	int mylen;
+
+	FUNC_ENTRY;
+	header.byte = readChar(&curdata);
+	if (header.bits.type != SUBACK)
+		goto exit;
+
+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+	enddata = curdata + mylen;
+	if (enddata - curdata < 2)
+		goto exit;
+
+	*packetid = readInt(&curdata);
+
+	*count = 0;
+	while (curdata < enddata)
+	{
+		if (*count > maxcount)
+		{
+			rc = -1;
+			goto exit;
+		}
+		grantedQoSs[(*count)++] = readChar(&curdata);
+	}
+
+	rc = 1;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
diff --git a/extras/paho/MQTTUnsubscribe.h b/extras/paho/MQTTUnsubscribe.h
new file mode 100644
index 0000000..2f8e829
--- /dev/null
+++ b/extras/paho/MQTTUnsubscribe.h
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTUNSUBSCRIBE_H_
+#define MQTTUNSUBSCRIBE_H_
+
+#if !defined(DLLImport)
+  #define DLLImport
+#endif
+#if !defined(DLLExport)
+  #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[]);
+
+DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
+		unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
+
+DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
+
+#endif /* MQTTUNSUBSCRIBE_H_ */
diff --git a/extras/paho/MQTTUnsubscribeClient.c b/extras/paho/MQTTUnsubscribeClient.c
new file mode 100644
index 0000000..40b4733
--- /dev/null
+++ b/extras/paho/MQTTUnsubscribeClient.c
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+#include <espressif/esp_common.h>
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+  * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
+  * @param count the number of topic filter strings in topicFilters
+  * @param topicFilters the array of topic filter strings to be used in the publish
+  * @return the length of buffer needed to contain the serialized version of the packet
+  */
+int  MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
+{
+	int i;
+	int len = 2; /* packetid */
+
+	for (i = 0; i < count; ++i)
+		len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
+	return len;
+}
+
+
+/**
+  * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @param dup integer - the MQTT dup flag
+  * @param packetid integer - the MQTT packet identifier
+  * @param count - number of members in the topicFilters array
+  * @param topicFilters - array of topic filter names
+  * @return the length of the serialized data.  <= 0 indicates error
+  */
+int  MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+		int count, MQTTString topicFilters[])
+{
+	unsigned char *ptr = buf;
+	MQTTHeader header = {0};
+	int rem_len = 0;
+	int rc = -1;
+	int i = 0;
+
+	FUNC_ENTRY;
+	if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
+	{
+		rc = MQTTPACKET_BUFFER_TOO_SHORT;
+		goto exit;
+	}
+
+	header.byte = 0;
+	header.bits.type = UNSUBSCRIBE;
+	header.bits.dup = dup;
+	header.bits.qos = 1;
+	writeChar(&ptr, header.byte); /* write header */
+
+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+	writeInt(&ptr, packetid);
+
+	for (i = 0; i < count; ++i)
+		writeMQTTString(&ptr, topicFilters[i]);
+
+	rc = ptr - buf;
+exit:
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
+/**
+  * Deserializes the supplied (wire) buffer into unsuback data
+  * @param packetid returned integer - the MQTT packet identifier
+  * @param buf the raw buffer data, of the correct length determined by the remaining length field
+  * @param buflen the length in bytes of the data in the supplied buffer
+  * @return error code.  1 is success, 0 is failure
+  */
+int  MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
+{
+	unsigned char type = 0;
+	unsigned char dup = 0;
+	int rc = 0;
+
+	FUNC_ENTRY;
+	rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
+	if (type == UNSUBACK)
+		rc = 1;
+	FUNC_EXIT_RC(rc);
+	return rc;
+}
+
+
diff --git a/extras/paho/StackTrace.h b/extras/paho/StackTrace.h
new file mode 100644
index 0000000..517d437
--- /dev/null
+++ b/extras/paho/StackTrace.h
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Ian Craggs - initial API and implementation and/or initial documentation
+ *    Ian Craggs - fix for bug #434081
+ *******************************************************************************/
+
+#ifndef STACKTRACE_H_
+#define STACKTRACE_H_
+
+#define NOSTACKTRACE 1
+
+#if defined(NOSTACKTRACE)
+#define FUNC_ENTRY
+#define FUNC_ENTRY_NOLOG
+#define FUNC_ENTRY_MED
+#define FUNC_ENTRY_MAX
+#define FUNC_EXIT
+#define FUNC_EXIT_NOLOG
+#define FUNC_EXIT_MED
+#define FUNC_EXIT_MAX
+#define FUNC_EXIT_RC(x)
+#define FUNC_EXIT_MED_RC(x)
+#define FUNC_EXIT_MAX_RC(x)
+
+#else
+
+#if defined(WIN32)
+#define inline __inline
+#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
+#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
+#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
+#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
+#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
+#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
+#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
+#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
+#else
+#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
+#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
+#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
+#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
+#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
+#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
+#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
+#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
+
+void StackTrace_entry(const char* name, int line, int trace);
+void StackTrace_exit(const char* name, int line, void* return_value, int trace);
+
+void StackTrace_printStack(FILE* dest);
+char* StackTrace_get(unsigned long);
+
+#endif
+
+#endif
+
+
+
+
+#endif /* STACKTRACE_H_ */
diff --git a/extras/paho/component.mk b/extras/paho/component.mk
new file mode 100644
index 0000000..4ddd4f7
--- /dev/null
+++ b/extras/paho/component.mk
@@ -0,0 +1,9 @@
+# Component makefile for extras/paho
+
+# expected anyone using bmp driver includes it as 'paho/MQTT*.h'
+INC_DIRS += $(paho_ROOT)..
+
+# args for passing into compile rule generation
+paho_SRC_DIR =  $(paho_ROOT)
+
+$(eval $(call component_compile_rules,paho))