├── README.md ├── examples ├── mqttSwitchBroker │ └── mqttSwitchBroker.ino ├── mqttqostest │ └── mqttqostest.ino ├── mqtttest │ └── mqtttest.ino └── threadtest │ └── testapps.ino ├── library.properties ├── license.txt └── src ├── MQTT.cpp ├── MQTT.h └── MQTT └── MQTT.h /README.md: -------------------------------------------------------------------------------- 1 | # MQTT for Photon, Spark Core 2 | MQTT publish/subscribe library for Photon, Argon, Tracker One...etc version 0.4.32. 3 | 4 | ## Source Code 5 | This lightweight library source code is only 2 files. firmware -> MQTT.cpp, MQTT.h. 6 | 7 | The application can use QoS 0, 1, 2 and the retain flag when publishing a message. 8 | 9 | ## Example 10 | Some sample sketches for Spark Core and Photon included (firmware/examples/). 11 | - mqtttest.ino : simple pub/sub sample. 12 | - mqttqostest.ino : QoS1, QoS2 publish and callback sample. 13 | - mqttSwitchBroker.ino : Example of how to switch to different brokers. 14 | - threadtest.ino : Example of SYSTEM_THREAD(ENABLED). 15 | 16 | ## developer examples 17 | some applications use MQTT with Photon. here are developer's reference examples. 18 | - Spark Core / Photon and CloudMQTT 19 | - MQTT Publish-Subscribe Using Rpi, ESP and Photon 20 | - Particle Photon on Watson IoT 21 | - Connecting IoT devices to the Watson Conversation Car-Dashboard app 22 | - ThingSpeak MQTT API 23 | - How to Connect a Particle Photon to the Losant IoT Platform 24 | - How I Hacked my Humidor with Losant and a Particle Photon 25 | - How to Build a Photon MQTT Logger 26 | - Particle and Ubidots using MQTT 27 | - Using Twilio Sync with MQTT on a Particle Photon 28 | 29 | ## sample source 30 | ``` 31 | #include "application.h" 32 | #include "MQTT.h" 33 | 34 | void callback(char* topic, byte* payload, unsigned int length); 35 | MQTT client("iot.eclipse.org", 1883, callback); 36 | 37 | // recieve message 38 | void callback(char* topic, byte* payload, unsigned int length) { 39 | char p[length + 1]; 40 | memcpy(p, payload, length); 41 | p[length] = NULL; 42 | 43 | if (!strcmp(p, "RED")) 44 | RGB.color(255, 0, 0); 45 | else if (!strcmp(p, "GREEN")) 46 | RGB.color(0, 255, 0); 47 | else if (!strcmp(p, "BLUE")) 48 | RGB.color(0, 0, 255); 49 | else 50 | RGB.color(255, 255, 255); 51 | delay(1000); 52 | } 53 | 54 | 55 | void setup() { 56 | RGB.control(true); 57 | 58 | // connect to the server(unique id by Time.now()) 59 | client.connect("sparkclient_" + String(Time.now())); 60 | 61 | // publish/subscribe 62 | if (client.isConnected()) { 63 | client.publish("outTopic/message","hello world"); 64 | client.subscribe("inTopic/message"); 65 | } 66 | } 67 | 68 | void loop() { 69 | if (client.isConnected()) 70 | client.loop(); 71 | } 72 | ``` 73 | ## FAQ 74 | ### Can't connect/publish/subscribe to the MQTT server? 75 | - Test your MQTT server and port (default 1883) with the mosquitto_pub/sub command. 76 | - Check your network environments. Make sure your MQTT server can reach the Internet through your firewall. 77 | - Verify your subscribe/publish topic name is correct. 78 | - Perhaps device firmware network stack is failed. check your firmware version and bugs. 79 | - If you are using MQTT-TLS, make sure your RooT CA pem file, client key, certifications is valid. 80 | - Several MQTT servers will disconnect the first connection when you use the same user_id. When the application calls the connect method, use a different user_id on every device as connect method's second argument. Using the MAC address as a user_id is suggested. 81 |
82 | // device.1 83 | client.connect("spark-client", "user_1", "password1"); 84 | // other devices... 85 | client.connect("spark-client", "user_others", "password1"); 86 |87 | 88 | ### I want to change MQTT keepalive timeout. 89 | MQTT keepalive timeout is defined "MQTT_DEFAULT_KEEPALIVE 15"(15 sec) in header file. You can change the keepalive timeout in constructor. 90 |
91 | MQTT client("server_name", 1883, callback); // default: send keepalive packet to MQTT server every 15sec. 92 | MQTT client("server_name", 1883, 256, 30, callback); // keepalive timeout is 30 seconds, default message size also added to be able to access correct constructor 93 |94 | 95 | ### Want to use over the 255 byte message size. 96 | In this library, the maximum MQTT message size is defined as "MQTT_MAX_PACKET_SIZE 255" in the header file. If you want to use over 255 bytes, use the constructor's last argument. 97 |
98 | MQTT client("server_name", 1883, callback); // default 255 bytes 99 | MQTT client("server_name", 1883, 512, callback); // max 512 bytes 100 |101 | 102 | ### Can I use on old firmware? 103 | No, use the default latest firmware. I tested this library on the default latest firmware or the latest pre-release version. If you use an old firmware it may not work well and is not supported. 104 | 105 | ### Bug or Problem? 106 | First, check the Particle community site. But if your problem is not resolved, please create an issue with the problem details. 107 | 108 | ### Pull Request 109 | If you have a bug fix or feature, please send a pull request. 110 | Thanks for all developers' pull requests! 111 | 112 | -------------------------------------------------------------------------------- /examples/mqttSwitchBroker/mqttSwitchBroker.ino: -------------------------------------------------------------------------------- 1 | #include "MQTT.h" 2 | 3 | const char *domain1 = "iot.eclipse.org"; 4 | const char *domain2 = "test.mosquitto.org"; 5 | const uint8_t server1[] = {192,168,1,2}; 6 | const uint8_t server2[] = {192,168,1,3}; 7 | 8 | void callback(char* topic, byte* payload, unsigned int length); 9 | 10 | /** 11 | * if want to use IP address, 12 | * const uint8_t[] = { XXX,XXX,XXX,XXX }; 13 | * MQTT client(server, 1883, callback); 14 | * want to use domain name, 15 | * MQTT client("www.sample.com", 1883, callback); 16 | **/ 17 | MQTT client(server1, 1883, callback); 18 | 19 | // recieve message 20 | void callback(char* topic, byte* payload, unsigned int length) { 21 | char p[length + 1]; 22 | memcpy(p, payload, length); 23 | p[length] = NULL; 24 | 25 | if (!strcmp(p, "RED")) 26 | RGB.color(255, 0, 0); 27 | else if (!strcmp(p, "GREEN")) 28 | RGB.color(0, 255, 0); 29 | else if (!strcmp(p, "BLUE")) 30 | RGB.color(0, 0, 255); 31 | else 32 | RGB.color(255, 255, 255); 33 | 34 | delay(1000); 35 | } 36 | 37 | 38 | void setup() { 39 | Serial.begin(); 40 | RGB.control(true); 41 | client.connect("sparkclient"); 42 | if (client.isConnected()) { 43 | client.publish("192392391/message","hello world"); 44 | client.subscribe("192392391/message"); 45 | } 46 | } 47 | 48 | void loop() { 49 | if (client.isConnected()) { 50 | client.loop(); 51 | } 52 | 53 | if (Serial.available() > 0) { 54 | long incomingChar = Serial.parseInt(); 55 | switch (incomingChar) { 56 | case 1: 57 | client.setBroker(domain1, 1883); 58 | break; 59 | case 2: 60 | client.setBroker(domain2, 1883); 61 | break; 62 | case 3: 63 | client.setBroker(server1, 1883); 64 | break; 65 | case 4: 66 | client.setBroker(server2, 1883); 67 | break; 68 | } 69 | client.connect("sparkclient"); 70 | if (client.isConnected()) { 71 | client.publish("192392391/message","hello world"); 72 | client.subscribe("192392391/message"); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/mqttqostest/mqttqostest.ino: -------------------------------------------------------------------------------- 1 | #include "MQTT.h" 2 | 3 | void callback(char* topic, byte* payload, unsigned int length); 4 | 5 | /** 6 | * if want to use IP address, 7 | * const uint8_t server[] = { XXX,XXX,XXX,XXX }; 8 | * MQTT client(server, 1883, callback); 9 | * want to use domain name, 10 | * exp) iot.eclipse.org is Eclipse Open MQTT Broker: https://iot.eclipse.org/getting-started 11 | * MQTT client("mqtt.eclipse.org", 1883, callback); 12 | **/ 13 | MQTT client("server_name", 1883, callback); 14 | 15 | // for QoS2 MQTTPUBREL message. 16 | // this messageid maybe have store list or array structure. 17 | uint16_t qos2messageid = 0; 18 | 19 | // recieve message 20 | void callback(char* topic, byte* payload, unsigned int length) { 21 | char p[length + 1]; 22 | memcpy(p, payload, length); 23 | p[length] = NULL; 24 | 25 | if (!strcmp(p, "RED")) 26 | RGB.color(255, 0, 0); 27 | else if (!strcmp(p, "GREEN")) 28 | RGB.color(0, 255, 0); 29 | else if (!strcmp(p, "BLUE")) 30 | RGB.color(0, 0, 255); 31 | else 32 | RGB.color(255, 255, 255); 33 | delay(1000); 34 | } 35 | 36 | // QOS ack callback. 37 | // if application use QOS1 or QOS2, MQTT server sendback ack message id. 38 | void qoscallback(unsigned int messageid) { 39 | Serial.print("Ack Message Id:"); 40 | Serial.println(messageid); 41 | } 42 | 43 | void setup() { 44 | Serial.begin(9600); 45 | RGB.control(true); 46 | 47 | // connect to the server 48 | client.connect("sparkclient"); 49 | 50 | // add qos callback. If don't add qoscallback, ACK message from MQTT server is ignored. 51 | client.addQosCallback(qoscallback); 52 | 53 | // publish/subscribe 54 | if (client.isConnected()) { 55 | // get the messageid from parameter at 4. 56 | uint16_t messageid; 57 | client.publish("outTopic/message", "hello world QOS1", MQTT::QOS1, &messageid); 58 | Serial.println(messageid); 59 | 60 | // if 4th parameter don't set or NULL, application can not check the message id to the ACK message from MQTT server. 61 | client.publish("outTopic/message", "hello world QOS1(message is NULL)", MQTT::QOS1); 62 | 63 | // QOS=2 64 | client.publish("outTopic/message", "hello world QOS2", MQTT::QOS2, &messageid); 65 | Serial.println(messageid); 66 | 67 | // save QoS2 message id as global parameter. 68 | qos2messageid = messageid; 69 | 70 | // MQTT subscribe endpoint could have the QoS 71 | client.subscribe("inTopic/message", MQTT::QOS2); 72 | } 73 | } 74 | 75 | void loop() { 76 | if (client.isConnected()) 77 | client.loop(); 78 | } 79 | 80 | -------------------------------------------------------------------------------- /examples/mqtttest/mqtttest.ino: -------------------------------------------------------------------------------- 1 | #include "MQTT.h" 2 | 3 | void callback(char* topic, byte* payload, unsigned int length); 4 | 5 | /** 6 | * if want to use IP address, 7 | * const uint8_t[] = { XXX,XXX,XXX,XXX }; 8 | * MQTT client(server, 1883, callback); 9 | * want to use domain name, 10 | * exp) iot.eclipse.org is Eclipse Open MQTT Broker: https://iot.eclipse.org/getting-started 11 | * MQTT client("mqtt.eclipse.org", 1883, callback); 12 | **/ 13 | MQTT client("server_name", 1883, callback); 14 | 15 | // recieve message 16 | void callback(char* topic, byte* payload, unsigned int length) { 17 | char p[length + 1]; 18 | memcpy(p, payload, length); 19 | p[length] = NULL; 20 | 21 | if (!strcmp(p, "RED")) 22 | RGB.color(255, 0, 0); 23 | else if (!strcmp(p, "GREEN")) 24 | RGB.color(0, 255, 0); 25 | else if (!strcmp(p, "BLUE")) 26 | RGB.color(0, 0, 255); 27 | else 28 | RGB.color(255, 255, 255); 29 | delay(1000); 30 | } 31 | 32 | 33 | void setup() { 34 | RGB.control(true); 35 | 36 | // connect to the server 37 | client.connect("sparkclient"); 38 | 39 | // publish/subscribe 40 | if (client.isConnected()) { 41 | client.publish("outTopic/message","hello world"); 42 | client.subscribe("inTopic/message"); 43 | } 44 | } 45 | 46 | void loop() { 47 | if (client.isConnected()) 48 | client.loop(); 49 | } 50 | -------------------------------------------------------------------------------- /examples/threadtest/testapps.ino: -------------------------------------------------------------------------------- 1 | #include "MQTT.h" 2 | 3 | SYSTEM_THREAD(ENABLED); 4 | void callback(char* topic, byte* payload, unsigned int length); 5 | 6 | /** 7 | * if want to use IP address, 8 | * const uint8_t[] = { XXX,XXX,XXX,XXX }; 9 | * MQTT client(server, 1883, callback); 10 | * want to use domain name, 11 | * exp) iot.eclipse.org is Eclipse Open MQTT Broker: https://iot.eclipse.org/getting-started 12 | * MQTT client("mqtt.eclipse.org", 1883, callback, true); 13 | * 4th parameter : bool thread(default false.) 14 | * SYSTEM_THREAD(ENABLED) settings : thread is true. 15 | **/ 16 | MQTT client("sample.com", 1883, callback, true); 17 | 18 | // recieve message 19 | void callback(char* topic, byte* payload, unsigned int length) { 20 | char p[length + 1]; 21 | memcpy(p, payload, length); 22 | p[length] = NULL; 23 | 24 | if (!strcmp(p, "RED")) 25 | RGB.color(255, 0, 0); 26 | else if (!strcmp(p, "GREEN")) 27 | RGB.color(0, 255, 0); 28 | else if (!strcmp(p, "BLUE")) 29 | RGB.color(0, 0, 255); 30 | else 31 | RGB.color(255, 255, 255); 32 | delay(1000); 33 | } 34 | 35 | 36 | void setup() { 37 | WiFi.on(); 38 | WiFi.setCredentials("ssid", "pass"); 39 | WiFi.connect(); 40 | waitUntil(WiFi.ready); 41 | while (WiFi.localIP() == IPAddress()) { 42 | delay(10); 43 | } 44 | 45 | // set LED control 46 | RGB.control(true); 47 | 48 | // connect to the server 49 | client.connect("sparkclient"); 50 | 51 | // publish/subscribe 52 | if (client.isConnected()) { 53 | client.publish("outTopic/message","hello world"); 54 | client.subscribe("inTopic/message"); 55 | } 56 | } 57 | 58 | void loop() { 59 | if (client.isConnected()) 60 | client.loop(); 61 | delay(100); 62 | } 63 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=MQTT 2 | version=0.4.32 3 | license=MIT 4 | author=hirotakaster 5 | url=https://github.com/hirotakaster/MQTT/ 6 | repository=https://github.com/hirotakaster/MQTT.git 7 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Hirotaka Niisato 2 | This software is released under the MIT License. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | Much of the code was inspired by Arduino Nicholas pubsubclient 24 | sample code bearing this copyright. 25 | //--------------------------------------------------------------------------- 26 | // Copyright (c) 2008-2012 Nicholas O'Leary 27 | // 28 | // Permission is hereby granted, free of charge, to any person obtaining 29 | // a copy of this software and associated documentation files (the 30 | // "Software"), to deal in the Software without restriction, including 31 | // without limitation the rights to use, copy, modify, merge, publish, 32 | // distribute, sublicense, and/or sell copies of the Software, and to 33 | // permit persons to whom the Software is furnished to do so, subject to 34 | // the following conditions: 35 | // 36 | // The above copyright notice and this permission notice shall be 37 | // included in all copies or substantial portions of the Software. 38 | // 39 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 40 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 41 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 42 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 43 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 44 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 45 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 46 | //--------------------------------------------------------------------------- 47 | -------------------------------------------------------------------------------- /src/MQTT.cpp: -------------------------------------------------------------------------------- 1 | #include "MQTT.h" 2 | 3 | #define LOGGING 4 | 5 | #define MQTTQOS0_HEADER_MASK (0 << 1) 6 | #define MQTTQOS1_HEADER_MASK (1 << 1) 7 | #define MQTTQOS2_HEADER_MASK (2 << 1) 8 | 9 | #define DUP_FLAG_OFF_MASK (0<<3) 10 | #define DUP_FLAG_ON_MASK (1<<3) 11 | 12 | MQTT::MQTT(const char* domain, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), 13 | bool thread) { 14 | this->initialize(domain, NULL, port, MQTT_DEFAULT_KEEPALIVE, MQTT_MAX_PACKET_SIZE, callback, thread); 15 | } 16 | 17 | MQTT::MQTT(const char* domain, uint16_t port, int maxpacketsize, void (*callback)(char*,uint8_t*,unsigned int), 18 | bool thread) { 19 | this->initialize(domain, NULL, port, MQTT_DEFAULT_KEEPALIVE, maxpacketsize, callback, thread); 20 | } 21 | 22 | MQTT::MQTT(const uint8_t *ip, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), 23 | bool thread) { 24 | this->initialize(NULL, ip, port, MQTT_DEFAULT_KEEPALIVE, MQTT_MAX_PACKET_SIZE, callback, thread); 25 | } 26 | 27 | MQTT::MQTT(const uint8_t *ip, uint16_t port, int maxpacketsize, void (*callback)(char*,uint8_t*,unsigned int), 28 | bool thread) { 29 | this->initialize(NULL, ip, port, MQTT_DEFAULT_KEEPALIVE, maxpacketsize, callback, thread); 30 | } 31 | 32 | MQTT::MQTT(const char* domain, uint16_t port, int maxpacketsize, int keepalive, void (*callback)(char*,uint8_t*,unsigned int), 33 | bool thread) { 34 | this->initialize(domain, NULL, port, keepalive, maxpacketsize, callback, thread); 35 | } 36 | 37 | MQTT::MQTT(const uint8_t *ip, uint16_t port, int maxpacketsize, int keepalive, void (*callback)(char*,uint8_t*,unsigned int), 38 | bool thread) { 39 | this->initialize(NULL, ip, port, keepalive, maxpacketsize, callback, thread); 40 | } 41 | 42 | MQTT::~MQTT() { 43 | if (isConnected()) { 44 | disconnect(); 45 | } 46 | 47 | if (buffer != NULL) 48 | delete[] buffer; 49 | } 50 | 51 | void MQTT::initialize(const char* domain, const uint8_t *ip, uint16_t port, int keepalive, int maxpacketsize, 52 | void (*callback)(char*,uint8_t*,unsigned int), bool thread) { 53 | if (thread) { 54 | this->thread = true; 55 | os_mutex_create(&mutex_lock); 56 | } 57 | this->callback = callback; 58 | this->qoscallback = NULL; 59 | if (ip != NULL) 60 | this->ip = ip; 61 | if (domain != NULL) 62 | this->domain = domain; 63 | this->port = port; 64 | this->keepalive = keepalive; 65 | 66 | // if maxpacketsize is over MQTT_MAX_PACKET_SIZE. 67 | this->maxpacketsize = (maxpacketsize <= MQTT_MAX_PACKET_SIZE ? MQTT_MAX_PACKET_SIZE : maxpacketsize); 68 | if (buffer != NULL) 69 | delete[] buffer; 70 | buffer = new uint8_t[this->maxpacketsize]; 71 | } 72 | 73 | void MQTT::setBroker(const char* domain, uint16_t port) { 74 | if(isConnected()) { 75 | disconnect(); 76 | } 77 | this->domain = domain; 78 | this->ip = NULL; 79 | this->port = port; 80 | } 81 | 82 | void MQTT::setBroker(const uint8_t *ip, uint16_t port) { 83 | if(isConnected()) { 84 | disconnect(); 85 | } 86 | this->domain = ""; 87 | this->ip = ip; 88 | this->port = port; 89 | } 90 | 91 | 92 | void MQTT::addQosCallback(void (*qoscallback)(unsigned int)) { 93 | this->qoscallback = qoscallback; 94 | } 95 | 96 | 97 | bool MQTT::connect(const char *id) { 98 | return connect(id, NULL, NULL, 0, QOS0, 0, 0, true); 99 | } 100 | 101 | bool MQTT::connect(const char *id, const char *user, const char *pass) { 102 | return connect(id, user, pass, 0, QOS0, 0, 0, true); 103 | } 104 | 105 | bool MQTT::connect(const char *id, const char *user, const char *pass, const char* willTopic, EMQTT_QOS willQos, uint8_t willRetain, const char* willMessage, bool cleanSession, MQTT_VERSION version) { 106 | if (!isConnected()) { 107 | MutexLocker lock(this); 108 | int result = 0; 109 | if (ip == NULL) 110 | result = _client.connect(this->domain.c_str(), this->port); 111 | else 112 | result = _client.connect(this->ip, this->port); 113 | 114 | if (result) { 115 | nextMsgId = 1; 116 | uint16_t length = 5; 117 | 118 | if (version == MQTT_V311) { 119 | const uint8_t MQTT_HEADER_V311[] = {0x00,0x04,'M','Q','T','T',MQTT_V311}; 120 | memcpy(buffer + length, MQTT_HEADER_V311, sizeof(MQTT_HEADER_V311)); 121 | length+=sizeof(MQTT_HEADER_V311); 122 | } else { 123 | const uint8_t MQTT_HEADER_V31[] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_V31}; 124 | memcpy(buffer + length, MQTT_HEADER_V31, sizeof(MQTT_HEADER_V31)); 125 | length+=sizeof(MQTT_HEADER_V31); 126 | } 127 | 128 | uint8_t v = 0; 129 | if (willTopic) { 130 | v = 0x06|(willQos<<3)|(willRetain<<5); 131 | } else { 132 | v = 0x02; 133 | } 134 | 135 | if (!cleanSession) { 136 | v = v&0xfd; 137 | } 138 | 139 | if(user != NULL) { 140 | v = v|0x80; 141 | 142 | if(pass != NULL) { 143 | v = v|(0x80>>1); 144 | } 145 | } 146 | 147 | buffer[length++] = v; 148 | 149 | buffer[length++] = ((this->keepalive) >> 8); 150 | buffer[length++] = ((this->keepalive) & 0xFF); 151 | length = writeString(id, buffer, length); 152 | if (willTopic) { 153 | length = writeString(willTopic, buffer, length); 154 | length = writeString(willMessage, buffer, length); 155 | } 156 | 157 | if(user != NULL) { 158 | length = writeString(user,buffer,length); 159 | if(pass != NULL) { 160 | length = writeString(pass,buffer,length); 161 | } 162 | } 163 | 164 | write(MQTTCONNECT, buffer, length-5); 165 | lastInActivity = lastOutActivity = millis(); 166 | 167 | while (!_client.available()) { 168 | unsigned long t = millis(); 169 | if (t-lastInActivity > this->keepalive*1000UL) { 170 | _client.stop(); 171 | return false; 172 | } 173 | } 174 | uint8_t llen; 175 | uint16_t len = readPacket(&llen); 176 | 177 | if (len == 4) { 178 | if (buffer[3] == CONN_ACCEPT) { 179 | lastInActivity = millis(); 180 | pingOutstanding = false; 181 | debug_print(" Connect success\n"); 182 | return true; 183 | } else { 184 | // check EMQTT_CONNACK_RESPONSE code. 185 | debug_print(" Connect fail. code = [%d]\n", buffer[3]); 186 | } 187 | } 188 | } 189 | _client.stop(); 190 | } 191 | return false; 192 | } 193 | 194 | uint8_t MQTT::readByte() { 195 | while(!_client.available()) {} 196 | return _client.read(); 197 | } 198 | 199 | uint16_t MQTT::readPacket(uint8_t* lengthLength) { 200 | uint16_t len = 0; 201 | buffer[len++] = readByte(); 202 | bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; 203 | uint32_t multiplier = 1; 204 | uint16_t length = 0; 205 | uint8_t digit = 0; 206 | uint16_t skip = 0; 207 | uint8_t start = 0; 208 | 209 | do { 210 | digit = readByte(); 211 | buffer[len++] = digit; 212 | length += (digit & 127) * multiplier; 213 | multiplier *= 128; 214 | } while ((digit & 128) != 0); 215 | *lengthLength = len-1; 216 | 217 | if (isPublish) { 218 | // Read in topic length to calculate bytes to skip over for Stream writing 219 | buffer[len++] = readByte(); 220 | buffer[len++] = readByte(); 221 | skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; 222 | start = 2; 223 | if (buffer[0] & MQTTQOS1_HEADER_MASK) { 224 | // skip message id 225 | skip += 2; 226 | } 227 | } 228 | 229 | for (uint16_t i = start;i