From 12eabcd8045d6db47abe6e2ba61134398f733a52 Mon Sep 17 00:00:00 2001 From: Siddhesh Date: Mon, 2 Nov 2020 19:11:28 +0530 Subject: [PATCH 1/7] added support for TLS on ESP8266 + more --- library.properties | 2 +- src/PubSubClient/PubSubClient.cpp | 387 ++++++++++++++++++++++-------- src/PubSubClient/PubSubClient.h | 56 ++++- src/ThingESP.h | 3 +- src/ThingESP_32.cpp | 5 +- src/ThingESP_8266.cpp | 65 ++++- 6 files changed, 392 insertions(+), 126 deletions(-) diff --git a/library.properties b/library.properties index fdc2deb..07326d5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ThingESP -version=1.2.0 +version=1.2.1 author=SiddheshNan maintainer=SiddheshNan sentence=Arduino library for the ThingsESP Platform. diff --git a/src/PubSubClient/PubSubClient.cpp b/src/PubSubClient/PubSubClient.cpp index 9658c4a..2b48d2b 100644 --- a/src/PubSubClient/PubSubClient.cpp +++ b/src/PubSubClient/PubSubClient.cpp @@ -1,4 +1,5 @@ /* + PubSubClient.cpp - A simple client for MQTT. Nick O'Leary http://knolleary.net @@ -12,12 +13,20 @@ PubSubClient::PubSubClient() { this->_client = NULL; this->stream = NULL; setCallback(NULL); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(Client& client) { this->_state = MQTT_DISCONNECTED; setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { @@ -25,12 +34,20 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { setServer(addr, port); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(addr,port); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -38,6 +55,10 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATUR setCallback(callback); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -45,6 +66,10 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATUR setCallback(callback); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { @@ -52,12 +77,20 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { setServer(ip, port); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(ip,port); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -65,6 +98,10 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, setCallback(callback); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -72,6 +109,10 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, setCallback(callback); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { @@ -79,12 +120,20 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { setServer(domain,port); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(domain,port); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -92,6 +141,10 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN setCallback(callback); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -99,33 +152,51 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN setCallback(callback); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); +} + +PubSubClient::~PubSubClient() { + free(this->buffer); } boolean PubSubClient::connect(const char *id) { - return connect(id,NULL,NULL,0,0,0,0); + return connect(id,NULL,NULL,0,0,0,0,1); } boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { - return connect(id,user,pass,0,0,0,0); + return connect(id,user,pass,0,0,0,0,1); } boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { - return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); + return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1); } boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { + return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1); +} + +boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) { if (!connected()) { int result = 0; - if (domain != NULL) { - result = _client->connect(this->domain, this->port); + + if(_client->connected()) { + result = 1; } else { - result = _client->connect(this->ip, this->port); + if (domain != NULL) { + result = _client->connect(this->domain, this->port); + } else { + result = _client->connect(this->ip, this->port); + } } + if (result == 1) { nextMsgId = 1; // Leave room in the buffer for header and variable length field - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; unsigned int j; #if MQTT_VERSION == MQTT_VERSION_3_1 @@ -136,14 +207,17 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass #define MQTT_HEADER_VERSION_LENGTH 7 #endif for (j = 0;jbuffer[length++] = d[j]; } uint8_t v; if (willTopic) { - v = 0x06|(willQos<<3)|(willRetain<<5); + v = 0x04|(willQos<<3)|(willRetain<<5); } else { - v = 0x02; + v = 0x00; + } + if (cleanSession) { + v = v|0x02; } if(user != NULL) { @@ -153,38 +227,43 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass v = v|(0x80>>1); } } + this->buffer[length++] = v; - buffer[length++] = v; + this->buffer[length++] = ((this->keepAlive) >> 8); + this->buffer[length++] = ((this->keepAlive) & 0xFF); - buffer[length++] = ((MQTT_KEEPALIVE) >> 8); - buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); - length = writeString(id,buffer,length); + CHECK_STRING_LENGTH(length,id) + length = writeString(id,this->buffer,length); if (willTopic) { - length = writeString(willTopic,buffer,length); - length = writeString(willMessage,buffer,length); + CHECK_STRING_LENGTH(length,willTopic) + length = writeString(willTopic,this->buffer,length); + CHECK_STRING_LENGTH(length,willMessage) + length = writeString(willMessage,this->buffer,length); } if(user != NULL) { - length = writeString(user,buffer,length); + CHECK_STRING_LENGTH(length,user) + length = writeString(user,this->buffer,length); if(pass != NULL) { - length = writeString(pass,buffer,length); + CHECK_STRING_LENGTH(length,pass) + length = writeString(pass,this->buffer,length); } } - write(MQTTCONNECT,buffer,length-5); + write(MQTTCONNECT,this->buffer,length-MQTT_MAX_HEADER_SIZE); lastInActivity = lastOutActivity = millis(); while (!_client->available()) { unsigned long t = millis(); - if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) { + if (t-lastInActivity >= ((int32_t) this->socketTimeout*1000UL)) { _state = MQTT_CONNECTION_TIMEOUT; _client->stop(); return false; } } uint8_t llen; - uint16_t len = readPacket(&llen); + uint32_t len = readPacket(&llen); if (len == 4) { if (buffer[3] == 0) { @@ -209,8 +288,9 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass boolean PubSubClient::readByte(uint8_t * result) { uint32_t previousMillis = millis(); while(!_client->available()) { + yield(); uint32_t currentMillis = millis(); - if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){ + if(currentMillis - previousMillis >= ((int32_t) this->socketTimeout * 1000)){ return false; } } @@ -229,68 +309,76 @@ boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){ return false; } -uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { +uint32_t PubSubClient::readPacket(uint8_t* lengthLength) { uint16_t len = 0; - if(!readByte(buffer, &len)) return 0; - bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; + if(!readByte(this->buffer, &len)) return 0; + bool isPublish = (this->buffer[0]&0xF0) == MQTTPUBLISH; uint32_t multiplier = 1; - uint16_t length = 0; + uint32_t length = 0; uint8_t digit = 0; uint16_t skip = 0; - uint8_t start = 0; + uint32_t start = 0; do { + if (len == 5) { + // Invalid remaining length encoding - kill the connection + _state = MQTT_DISCONNECTED; + _client->stop(); + return 0; + } if(!readByte(&digit)) return 0; - buffer[len++] = digit; + this->buffer[len++] = digit; length += (digit & 127) * multiplier; - multiplier *= 128; + multiplier <<=7; //multiplier *= 128 } while ((digit & 128) != 0); *lengthLength = len-1; if (isPublish) { // Read in topic length to calculate bytes to skip over for Stream writing - if(!readByte(buffer, &len)) return 0; - if(!readByte(buffer, &len)) return 0; - skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; + if(!readByte(this->buffer, &len)) return 0; + if(!readByte(this->buffer, &len)) return 0; + skip = (this->buffer[*lengthLength+1]<<8)+this->buffer[*lengthLength+2]; start = 2; - if (buffer[0]&MQTTQOS1) { + if (this->buffer[0]&MQTTQOS1) { // skip message id skip += 2; } } + uint32_t idx = len; - for (uint16_t i = start;istream) { - if (isPublish && len-*lengthLength-2>skip) { + if (isPublish && idx-*lengthLength-2>skip) { this->stream->write(digit); } } - if (len < MQTT_MAX_PACKET_SIZE) { - buffer[len] = digit; + + if (len < this->bufferSize) { + this->buffer[len] = digit; + len++; } - len++; + idx++; } - if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { + if (!this->stream && idx > this->bufferSize) { len = 0; // This will cause the packet to be ignored. } - return len; } boolean PubSubClient::loop() { if (connected()) { unsigned long t = millis(); - if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) { + if ((t - lastInActivity > this->keepAlive*1000UL) || (t - lastOutActivity > this->keepAlive*1000UL)) { if (pingOutstanding) { this->_state = MQTT_CONNECTION_TIMEOUT; _client->stop(); return false; } else { - buffer[0] = MQTTPINGREQ; - buffer[1] = 0; - _client->write(buffer,2); + this->buffer[0] = MQTTPINGREQ; + this->buffer[1] = 0; + _client->write(this->buffer,2); lastOutActivity = t; lastInActivity = t; pingOutstanding = true; @@ -303,40 +391,41 @@ boolean PubSubClient::loop() { uint8_t *payload; if (len > 0) { lastInActivity = t; - uint8_t type = buffer[0]&0xF0; + uint8_t type = this->buffer[0]&0xF0; if (type == MQTTPUBLISH) { if (callback) { - uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; - char topic[tl+1]; - for (uint16_t i=0;ibuffer[llen+1]<<8)+this->buffer[llen+2]; /* topic length in bytes */ + memmove(this->buffer+llen+2,this->buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */ + this->buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */ + char *topic = (char*) this->buffer+llen+2; // msgId only present for QOS>0 - if ((buffer[0]&0x06) == MQTTQOS1) { - msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; - payload = buffer+llen+3+tl+2; + if ((this->buffer[0]&0x06) == MQTTQOS1) { + msgId = (this->buffer[llen+3+tl]<<8)+this->buffer[llen+3+tl+1]; + payload = this->buffer+llen+3+tl+2; callback(topic,payload,len-llen-3-tl-2); - buffer[0] = MQTTPUBACK; - buffer[1] = 2; - buffer[2] = (msgId >> 8); - buffer[3] = (msgId & 0xFF); - _client->write(buffer,4); + this->buffer[0] = MQTTPUBACK; + this->buffer[1] = 2; + this->buffer[2] = (msgId >> 8); + this->buffer[3] = (msgId & 0xFF); + _client->write(this->buffer,4); lastOutActivity = t; } else { - payload = buffer+llen+3+tl; + payload = this->buffer+llen+3+tl; callback(topic,payload,len-llen-3-tl); } } } else if (type == MQTTPINGREQ) { - buffer[0] = MQTTPINGRESP; - buffer[1] = 0; - _client->write(buffer,2); + this->buffer[0] = MQTTPINGRESP; + this->buffer[1] = 0; + _client->write(this->buffer,2); } else if (type == MQTTPINGRESP) { pingOutstanding = false; } + } else if (!connected()) { + // readPacket has closed the connection + return false; } } return true; @@ -345,11 +434,11 @@ boolean PubSubClient::loop() { } boolean PubSubClient::publish(const char* topic, const char* payload) { - return publish(topic,(const uint8_t*)payload,strlen(payload),false); + return publish(topic,(const uint8_t*)payload, payload ? strnlen(payload, this->bufferSize) : 0,false); } boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { - return publish(topic,(const uint8_t*)payload,strlen(payload),retained); + return publish(topic,(const uint8_t*)payload, payload ? strnlen(payload, this->bufferSize) : 0,retained); } boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { @@ -358,26 +447,34 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { if (connected()) { - if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) { + if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2+strnlen(topic, this->bufferSize) + plength) { // Too long return false; } // Leave room in the buffer for header and variable length field - uint16_t length = 5; - length = writeString(topic,buffer,length); + uint16_t length = MQTT_MAX_HEADER_SIZE; + length = writeString(topic,this->buffer,length); + + // Add payload uint16_t i; for (i=0;ibuffer[length++] = payload[i]; } + + // Write the header uint8_t header = MQTTPUBLISH; if (retained) { header |= 1; } - return write(header,buffer,length-5); + return write(header,this->buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } +boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) { + return publish_P(topic, (const uint8_t*)payload, payload ? strnlen(payload, this->bufferSize) : 0, retained); +} + boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { uint8_t llen = 0; uint8_t digit; @@ -387,32 +484,33 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig unsigned int i; uint8_t header; unsigned int len; + int expectedLength; if (!connected()) { return false; } - tlen = strlen(topic); + tlen = strnlen(topic, this->bufferSize); header = MQTTPUBLISH; if (retained) { header |= 1; } - buffer[pos++] = header; + this->buffer[pos++] = header; len = plength + 2 + tlen; do { - digit = len % 128; - len = len / 128; + digit = len & 127; //digit = len %128 + len >>= 7; //len = len / 128 if (len > 0) { digit |= 0x80; } - buffer[pos++] = digit; + this->buffer[pos++] = digit; llen++; } while(len>0); - pos = writeString(topic,buffer,pos); + pos = writeString(topic,this->buffer,pos); - rc += _client->write(buffer,pos); + rc += _client->write(this->buffer,pos); for (i=0;iwrite((char)pgm_read_byte_near(payload + i)); @@ -420,19 +518,52 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig lastOutActivity = millis(); - return rc == tlen + 4 + plength; + expectedLength = 1 + llen + 2 + tlen + plength; + + return (rc == expectedLength); } -boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { +boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, boolean retained) { + if (connected()) { + // Send the header and variable length field + uint16_t length = MQTT_MAX_HEADER_SIZE; + length = writeString(topic,this->buffer,length); + uint8_t header = MQTTPUBLISH; + if (retained) { + header |= 1; + } + size_t hlen = buildHeader(header, this->buffer, plength+length-MQTT_MAX_HEADER_SIZE); + uint16_t rc = _client->write(this->buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen)); + lastOutActivity = millis(); + return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen))); + } + return false; +} + +int PubSubClient::endPublish() { + return 1; +} + +size_t PubSubClient::write(uint8_t data) { + lastOutActivity = millis(); + return _client->write(data); +} + +size_t PubSubClient::write(const uint8_t *buffer, size_t size) { + lastOutActivity = millis(); + return _client->write(buffer,size); +} + +size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) { uint8_t lenBuf[4]; uint8_t llen = 0; uint8_t digit; uint8_t pos = 0; - uint16_t rc; uint16_t len = length; do { - digit = len % 128; - len = len / 128; + + digit = len & 127; //digit = len %128 + len >>= 7; //len = len / 128 if (len > 0) { digit |= 0x80; } @@ -442,12 +573,18 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { buf[4-llen] = header; for (int i=0;i 0) && result) { @@ -459,9 +596,9 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { } return result; #else - rc = _client->write(buf+(4-llen),length+1+llen); + rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen); lastOutActivity = millis(); - return (rc == 1+llen+length); + return (rc == hlen+length); #endif } @@ -470,53 +607,62 @@ boolean PubSubClient::subscribe(const char* topic) { } boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { - if (qos < 0 || qos > 1) { + size_t topicLength = strnlen(topic, this->bufferSize); + if (topic == 0) { return false; } - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + if (qos > 1) { + return false; + } + if (this->bufferSize < 9 + topicLength) { // Too long return false; } if (connected()) { // Leave room in the buffer for header and variable length field - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; nextMsgId++; if (nextMsgId == 0) { nextMsgId = 1; } - buffer[length++] = (nextMsgId >> 8); - buffer[length++] = (nextMsgId & 0xFF); - length = writeString((char*)topic, buffer,length); - buffer[length++] = qos; - return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); + this->buffer[length++] = (nextMsgId >> 8); + this->buffer[length++] = (nextMsgId & 0xFF); + length = writeString((char*)topic, this->buffer,length); + this->buffer[length++] = qos; + return write(MQTTSUBSCRIBE|MQTTQOS1,this->buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } boolean PubSubClient::unsubscribe(const char* topic) { - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + size_t topicLength = strnlen(topic, this->bufferSize); + if (topic == 0) { + return false; + } + if (this->bufferSize < 9 + topicLength) { // Too long return false; } if (connected()) { - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; nextMsgId++; if (nextMsgId == 0) { nextMsgId = 1; } - buffer[length++] = (nextMsgId >> 8); - buffer[length++] = (nextMsgId & 0xFF); - length = writeString(topic, buffer,length); - return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); + this->buffer[length++] = (nextMsgId >> 8); + this->buffer[length++] = (nextMsgId & 0xFF); + length = writeString(topic, this->buffer,length); + return write(MQTTUNSUBSCRIBE|MQTTQOS1,this->buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } void PubSubClient::disconnect() { - buffer[0] = MQTTDISCONNECT; - buffer[1] = 0; - _client->write(buffer,2); + this->buffer[0] = MQTTDISCONNECT; + this->buffer[1] = 0; + _client->write(this->buffer,2); _state = MQTT_DISCONNECTED; + _client->flush(); _client->stop(); lastInActivity = lastOutActivity = millis(); } @@ -547,6 +693,8 @@ boolean PubSubClient::connected() { _client->flush(); _client->stop(); } + } else { + return this->_state == MQTT_CONNECTED; } } return rc; @@ -588,3 +736,34 @@ PubSubClient& PubSubClient::setStream(Stream& stream){ int PubSubClient::state() { return this->_state; } + +boolean PubSubClient::setBufferSize(uint16_t size) { + if (size == 0) { + // Cannot set it back to 0 + return false; + } + if (this->bufferSize == 0) { + this->buffer = (uint8_t*)malloc(size); + } else { + uint8_t* newBuffer = (uint8_t*)realloc(this->buffer, size); + if (newBuffer != NULL) { + this->buffer = newBuffer; + } else { + return false; + } + } + this->bufferSize = size; + return (this->buffer != NULL); +} + +uint16_t PubSubClient::getBufferSize() { + return this->bufferSize; +} +PubSubClient& PubSubClient::setKeepAlive(uint16_t keepAlive) { + this->keepAlive = keepAlive; + return *this; +} +PubSubClient& PubSubClient::setSocketTimeout(uint16_t timeout) { + this->socketTimeout = timeout; + return *this; +} diff --git a/src/PubSubClient/PubSubClient.h b/src/PubSubClient/PubSubClient.h index 2d1b1f6..0a950ac 100644 --- a/src/PubSubClient/PubSubClient.h +++ b/src/PubSubClient/PubSubClient.h @@ -21,17 +21,17 @@ #define MQTT_VERSION MQTT_VERSION_3_1_1 #endif -// MQTT_MAX_PACKET_SIZE : Maximum packet size +// MQTT_MAX_PACKET_SIZE : Maximum packet size. Override with setBufferSize(). #ifndef MQTT_MAX_PACKET_SIZE -#define MQTT_MAX_PACKET_SIZE 512 +#define MQTT_MAX_PACKET_SIZE 1024 #endif -// MQTT_KEEPALIVE : keepAlive interval in Seconds +// MQTT_KEEPALIVE : keepAlive interval in Seconds. Override with setKeepAlive() #ifndef MQTT_KEEPALIVE #define MQTT_KEEPALIVE 15 #endif -// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds +// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds. Override with setSocketTimeout() #ifndef MQTT_SOCKET_TIMEOUT #define MQTT_SOCKET_TIMEOUT 15 #endif @@ -73,27 +73,40 @@ #define MQTTQOS1 (1 << 1) #define MQTTQOS2 (2 << 1) -#ifdef ESP8266 +// Maximum size of fixed header and variable length size header +#define MQTT_MAX_HEADER_SIZE 5 + +#if defined(ESP8266) || defined(ESP32) #include #define MQTT_CALLBACK_SIGNATURE std::function callback #else #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) #endif -class PubSubClient { +#define CHECK_STRING_LENGTH(l,s) if (l+2+strnlen(s, this->bufferSize) > this->bufferSize) {_client->stop();return false;} + +class PubSubClient : public Print { private: Client* _client; - uint8_t buffer[MQTT_MAX_PACKET_SIZE]; + uint8_t* buffer; + uint16_t bufferSize; + uint16_t keepAlive; + uint16_t socketTimeout; uint16_t nextMsgId; unsigned long lastOutActivity; unsigned long lastInActivity; bool pingOutstanding; MQTT_CALLBACK_SIGNATURE; - uint16_t readPacket(uint8_t*); + uint32_t readPacket(uint8_t*); boolean readByte(uint8_t * result); boolean readByte(uint8_t * result, uint16_t * index); boolean write(uint8_t header, uint8_t* buf, uint16_t length); uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); + // Build up the header ready to send + // Returns the size of the header + // Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start + // (MQTT_MAX_HEADER_SIZE - ) bytes into the buffer + size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length); IPAddress ip; const char* domain; uint16_t port; @@ -115,29 +128,56 @@ class PubSubClient { PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); + ~PubSubClient(); + PubSubClient& setServer(IPAddress ip, uint16_t port); PubSubClient& setServer(uint8_t * ip, uint16_t port); PubSubClient& setServer(const char * domain, uint16_t port); PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); PubSubClient& setClient(Client& client); PubSubClient& setStream(Stream& stream); + PubSubClient& setKeepAlive(uint16_t keepAlive); + PubSubClient& setSocketTimeout(uint16_t timeout); + + boolean setBufferSize(uint16_t size); + uint16_t getBufferSize(); boolean connect(const char* id); boolean connect(const char* id, const char* user, const char* pass); boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); + boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession); void disconnect(); boolean publish(const char* topic, const char* payload); boolean publish(const char* topic, const char* payload, boolean retained); boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); + boolean publish_P(const char* topic, const char* payload, boolean retained); boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); + // Start to publish a message. + // This API: + // beginPublish(...) + // one or more calls to write(...) + // endPublish() + // Allows for arbitrarily large payloads to be sent without them having to be copied into + // a new buffer and held in memory at one time + // Returns 1 if the message was started successfully, 0 if there was an error + boolean beginPublish(const char* topic, unsigned int plength, boolean retained); + // Finish off this publish message (started with beginPublish) + // Returns 1 if the packet was sent successfully, 0 if there was an error + int endPublish(); + // Write a single byte of payload (only to be used with beginPublish/endPublish) + virtual size_t write(uint8_t); + // Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish) + // Returns the number of bytes written + virtual size_t write(const uint8_t *buffer, size_t size); boolean subscribe(const char* topic); boolean subscribe(const char* topic, uint8_t qos); boolean unsubscribe(const char* topic); boolean loop(); boolean connected(); int state(); + }; diff --git a/src/ThingESP.h b/src/ThingESP.h index e50e376..b6b341e 100644 --- a/src/ThingESP.h +++ b/src/ThingESP.h @@ -1,6 +1,7 @@ #define MQTT_MAX_PACKET_SIZE 1024 + #if defined(ESP8266) #include "ThingESP_8266.cpp" -#elif defined (ESP32) +#elif defined(ESP32) #include "ThingESP_32.cpp" #endif diff --git a/src/ThingESP_32.cpp b/src/ThingESP_32.cpp index 951e5f9..19b2838 100644 --- a/src/ThingESP_32.cpp +++ b/src/ThingESP_32.cpp @@ -6,6 +6,7 @@ #include "PubSubClient/PubSubClient.h" #include "ArduinoJson.h" + String HandleResponse(String query); class ThingESP32 @@ -118,6 +119,7 @@ class ThingESP32 const char *ssid_password; const char *mqttServer = "thingesp.siddhesh.me"; + int mqttPort = 1893; String topic; @@ -139,9 +141,9 @@ class ThingESP32 Serial.println(); for (int i = 0; i < length; i++) { - Serial.print((char)payload[i]); srr.concat((char)payload[i]); } + Serial.print(srr); this->logic(srr); } @@ -151,6 +153,7 @@ class ThingESP32 Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); + Serial.println(mqttServer); WiFi.begin(ssid, ssid_password); diff --git a/src/ThingESP_8266.cpp b/src/ThingESP_8266.cpp index d8affeb..c4cbc1c 100644 --- a/src/ThingESP_8266.cpp +++ b/src/ThingESP_8266.cpp @@ -1,12 +1,15 @@ #if defined(ESP8266) #include -#elif defined (ESP32) +#elif defined(ESP32) #include #endif - #include "PubSubClient/PubSubClient.h" #include "ArduinoJson.h" +#ifndef _DISABLE_TLS_ +#include +#endif + String HandleResponse(String query); class ThingESP8266 @@ -14,15 +17,25 @@ class ThingESP8266 public: ThingESP8266(String username, String deviceName, String password) { - WiFiClient espClient; - PubSubClient client(espClient); + #ifndef _DISABLE_TLS_ + WiFiClientSecure espClient; + #if !defined(ESP32) + espClient.setInsecure(); + #endif + this->espClient = espClient; + PubSubClient client(this->espClient); + #else + WiFiClient espClient; + PubSubClient client(espClient); + #endif + + delay(2); this->client = client; this->Username = username; this->DeviceName = deviceName; this->Password = password; }; - void SetWiFi(const char *ssID, const char *ssID_password) { this->ssid = ssID; @@ -61,16 +74,14 @@ class ThingESP8266 void initDevice() { - // this->client = client; + // this->client = client; this->topic = this->DeviceName + "/" + this->Username; this->outname = this->DeviceName + "@" + this->Username; - this->char_DeviceName = this->DeviceName.c_str(); this->char_Password = this->Password.c_str(); this->char_outname = this->outname.c_str(); this->char_topic = this->topic.c_str(); this->initiated = true; - this->setupIT(); } @@ -118,8 +129,38 @@ class ThingESP8266 const char *ssid; const char *ssid_password; - const char *mqttServer = "thingesp.siddhesh.me"; + const char *mqttServer = "10.0.0.150"; + + #ifndef _DISABLE_TLS_ + int mqttPort = 1899; + #else int mqttPort = 1893; + #endif + + + /* + #ifndef _THINGESP_SERVER_ + const char *mqttServer = "thingesp.siddhesh.me"; + #else + const char *mqttServer = _THINGESP_SERVER_; + #endif + + + #ifndef _THINGESP_PORT_ + #define _THINGESP_PORT_ 1893 + #endif + + #ifndef _THINGESP_PORT_TLS_ + #define _THINGESP_PORT_TLS_ 1899 + #endif + + #ifndef _DISABLE_TLS_ + int mqttPort = _THINGESP_PORT_TLS_; + #endif + #ifdef _DISABLE_TLS_ + int mqttPort = _THINGESP_PORT_; + #endif +*/ String topic; String outname; @@ -129,6 +170,7 @@ class ThingESP8266 const char *char_topic; PubSubClient client; + WiFiClientSecure espClient; void callback(char *topic, byte *payload, unsigned int length) { @@ -140,9 +182,9 @@ class ThingESP8266 Serial.println(); for (int i = 0; i < length; i++) { - Serial.print((char)payload[i]); srr.concat((char)payload[i]); } + Serial.print(srr); this->logic(srr); } @@ -152,6 +194,7 @@ class ThingESP8266 Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); + Serial.println(mqttPort); WiFi.begin(ssid, ssid_password); @@ -170,7 +213,7 @@ class ThingESP8266 this->client.setServer(this->mqttServer, this->mqttPort); this->client.setCallback([this](char *topic, byte *payload, unsigned int length) { - callback(topic, payload, length); + callback(topic, payload, length); }); } }; From 9598f795e7e921c4429460dfb7ab57feb2c56256 Mon Sep 17 00:00:00 2001 From: Siddhesh Date: Wed, 4 Nov 2020 01:15:20 +0530 Subject: [PATCH 2/7] server dns fixed --- src/ThingESP_8266.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ThingESP_8266.cpp b/src/ThingESP_8266.cpp index c4cbc1c..8348b24 100644 --- a/src/ThingESP_8266.cpp +++ b/src/ThingESP_8266.cpp @@ -129,8 +129,7 @@ class ThingESP8266 const char *ssid; const char *ssid_password; - const char *mqttServer = "10.0.0.150"; - + const char *mqttServer = "thingesp.siddhesh.me"; #ifndef _DISABLE_TLS_ int mqttPort = 1899; #else From 9c6770a4c9b4bbdbd2a9f3ec990816094ac87015 Mon Sep 17 00:00:00 2001 From: Siddhesh Date: Wed, 12 May 2021 19:11:44 +0530 Subject: [PATCH 3/7] fixed ESP32 reset bug & added more examples --- .../ESP32-basic.ino} | 10 +- .../ESP32-send-message/ESP32-send-message.ino | 55 +++++++ .../ESP8266-basic.ino} | 2 - .../ESP8266-send-message.ino | 54 +++++++ library.properties | 2 +- src/ThingESP_32.cpp | 141 ++++++++---------- 6 files changed, 178 insertions(+), 86 deletions(-) rename examples/{ESP32-example/ESP32-example.ino => ESP32-basic/ESP32-basic.ino} (88%) create mode 100644 examples/ESP32-send-message/ESP32-send-message.ino rename examples/{ESP8266-example/ESP8266-example.ino => ESP8266-basic/ESP8266-basic.ino} (99%) create mode 100644 examples/ESP8266-send-message/ESP8266-send-message.ino diff --git a/examples/ESP32-example/ESP32-example.ino b/examples/ESP32-basic/ESP32-basic.ino similarity index 88% rename from examples/ESP32-example/ESP32-example.ino rename to examples/ESP32-basic/ESP32-basic.ino index 81d9a26..76ff5ba 100644 --- a/examples/ESP32-example/ESP32-example.ino +++ b/examples/ESP32-basic/ESP32-basic.ino @@ -3,7 +3,7 @@ ThingESP32 thing("username", "project_name", "credentials"); -int LED = 16; +int LED = 2; void setup() { @@ -23,17 +23,17 @@ String HandleResponse(String query) { if (query == "led on") { - digitalWrite(LED, 0); + digitalWrite(LED, 1); return "Done: LED Turned ON"; } else if (query == "led off") { - digitalWrite(LED, 1); + digitalWrite(LED, 0); return "Done: LED Turned OFF"; } else if (query == "led status") - return digitalRead(LED) ? "LED is OFF" : "LED is ON"; + return digitalRead(LED) ? "LED is ON" : "LED is OFF"; else return "Your query was invalid.."; @@ -45,7 +45,5 @@ String HandleResponse(String query) void loop() { - thing.Handle(); - } \ No newline at end of file diff --git a/examples/ESP32-send-message/ESP32-send-message.ino b/examples/ESP32-send-message/ESP32-send-message.ino new file mode 100644 index 0000000..f4abcbe --- /dev/null +++ b/examples/ESP32-send-message/ESP32-send-message.ino @@ -0,0 +1,55 @@ +#include +#include + +ThingESP32 thing("username", "project_name", "credentials"); + +int LED = 2; + +unsigned long previousMillis = 0; +const long INTERVAL = 6000; + +void setup() +{ + Serial.begin(115200); + + pinMode(LED, OUTPUT); + + thing.SetWiFi("wifi_ssid", "wifi_password"); + + thing.initDevice(); +} + +String HandleResponse(String query) +{ + + if (query == "led on") + { + digitalWrite(LED, 1); + return "Done: LED Turned ON"; + } + + else if (query == "led off") + { + digitalWrite(LED, 0); + return "Done: LED Turned OFF"; + } + + else if (query == "led status") + return digitalRead(LED) ? "LED is ON" : "LED is OFF"; + + else + return "Your query was invalid.."; +} + +void loop() +{ + + // if (millis() - previousMillis >= INTERVAL) + // { + // previousMillis = millis(); + // String msg = digitalRead(LED) ? "LED is ON" : "LED is OFF"; + // thing.sendMsg("PHONE_NUMBER", msg); + // } + + thing.Handle(); +} \ No newline at end of file diff --git a/examples/ESP8266-example/ESP8266-example.ino b/examples/ESP8266-basic/ESP8266-basic.ino similarity index 99% rename from examples/ESP8266-example/ESP8266-example.ino rename to examples/ESP8266-basic/ESP8266-basic.ino index 0b6bcd2..dfbac4f 100644 --- a/examples/ESP8266-example/ESP8266-example.ino +++ b/examples/ESP8266-basic/ESP8266-basic.ino @@ -45,7 +45,5 @@ String HandleResponse(String query) void loop() { - thing.Handle(); - } \ No newline at end of file diff --git a/examples/ESP8266-send-message/ESP8266-send-message.ino b/examples/ESP8266-send-message/ESP8266-send-message.ino new file mode 100644 index 0000000..f5809a5 --- /dev/null +++ b/examples/ESP8266-send-message/ESP8266-send-message.ino @@ -0,0 +1,54 @@ +#include +#include + +ThingESP8266 thing("username", "project_name", "credentials"); + +int LED = LED_BUILTIN; + +unsigned long previousMillis = 0; +const long INTERVAL = 6000; + +void setup() +{ + Serial.begin(115200); + + pinMode(LED, OUTPUT); + + thing.SetWiFi("wifi_ssid", "wifi_password"); + + thing.initDevice(); +} + +String HandleResponse(String query) +{ + + if (query == "led on") + { + digitalWrite(LED, 0); + return "Done: LED Turned ON"; + } + + else if (query == "led off") + { + digitalWrite(LED, 1); + return "Done: LED Turned OFF"; + } + + else if (query == "led status") + return digitalRead(LED) ? "LED is OFF" : "LED is ON"; + + else + return "Your query was invalid.."; +} + +void loop() +{ + // if (millis() - previousMillis >= INTERVAL) + // { + // previousMillis = millis(); + // String msg = digitalRead(LED) ? "LED is OFF" : "LED is ON"; + // thing.sendMsg("PHONE_NUMBER", msg); + // } + + thing.Handle(); +} \ No newline at end of file diff --git a/library.properties b/library.properties index 07326d5..546b106 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ThingESP -version=1.2.1 +version=1.2.2 author=SiddheshNan maintainer=SiddheshNan sentence=Arduino library for the ThingsESP Platform. diff --git a/src/ThingESP_32.cpp b/src/ThingESP_32.cpp index 19b2838..eda5f9a 100644 --- a/src/ThingESP_32.cpp +++ b/src/ThingESP_32.cpp @@ -1,67 +1,32 @@ +#define MQTT_MAX_PACKET_SIZE 1024 #if defined(ESP8266) #include -#elif defined (ESP32) +#elif defined(ESP32) #include #endif #include "PubSubClient/PubSubClient.h" #include "ArduinoJson.h" - String HandleResponse(String query); class ThingESP32 { public: - ThingESP32(String username, String deviceName, String password) + ThingESP32(String username, String deviceName, String password) : g_client(espClient) { - WiFiClient espClient; - PubSubClient client(espClient); - this->client = client; this->Username = username; this->DeviceName = deviceName; this->Password = password; }; - void SetWiFi(const char *ssID, const char *ssID_password) { this->ssid = ssID; this->ssid_password = ssID_password; } - void logic(String data) - { - DynamicJsonDocument data_in(1024); - DynamicJsonDocument data_out(1024); - deserializeJson(data_in, data); - - if (data_in["action"] == "query") - { - data_out["msg_id"] = data_in["msg_id"]; - data_out["action"] = "returned_api_response"; - String query = data_in["query"]; - query.toLowerCase(); - data_out["returned_api_response"] = HandleResponse(query); - String outdata; - serializeJson(data_out, outdata); - publishMSG(outdata.c_str()); - } - }; - - void sendMsg(String number, String msg) - { - DynamicJsonDocument data_out(1024); - data_out["action"] = "device_call"; - data_out["to_number"] = number; - data_out["msg"] = msg; - String outdata; - serializeJson(data_out, outdata); - publishMSG(outdata.c_str()); - } - void initDevice() { - // this->client = client; this->topic = this->DeviceName + "/" + this->Username; this->outname = this->DeviceName + "@" + this->Username; @@ -71,41 +36,66 @@ class ThingESP32 this->char_topic = this->topic.c_str(); this->initiated = true; - this->setupIT(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + Serial.println(mqttServer); + + WiFi.begin(ssid, ssid_password); + + while (WiFi.status() != WL_CONNECTED) + { + delay(500); + Serial.print("."); + } + + randomSeed(micros()); + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + g_client.setServer(this->mqttServer, this->mqttPort); + g_client.setCallback([this](char *topic, byte *payload, unsigned int length) { + callback(topic, payload, length); + }); } void Handle() { - if (!client.connected()) + if (!g_client.connected()) { - while (!client.connected()) + while (!g_client.connected()) { + delay(10); Serial.print("Attempting connection..."); - if (client.connect(this->char_outname, this->char_outname, this->char_Password)) + if (g_client.connect(this->char_outname, this->char_outname, this->char_Password)) { Serial.println("connected"); - client.subscribe(this->char_topic); + g_client.subscribe(this->char_topic); } else { Serial.print("failed, rc="); - Serial.print(this->client.state()); + Serial.print(g_client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } - this->client.loop(); + g_client.loop(); } - void publishMSG(const char *info) - { - client.publish(this->char_topic, info); - } - - void SetHost(const char *host) + void sendMsg(String number, String msg) { - this->mqttServer = host; + DynamicJsonDocument data_out(1024); + data_out["action"] = "device_call"; + data_out["to_number"] = number; + data_out["msg"] = msg; + String outdata; + serializeJson(data_out, outdata); + publishMSG(outdata.c_str()); } private: @@ -119,17 +109,19 @@ class ThingESP32 const char *ssid_password; const char *mqttServer = "thingesp.siddhesh.me"; - + int mqttPort = 1893; String topic; String outname; + const char *char_DeviceName; const char *char_Password; const char *char_outname; const char *char_topic; - PubSubClient client; + WiFiClient espClient; + PubSubClient g_client; void callback(char *topic, byte *payload, unsigned int length) { @@ -144,35 +136,30 @@ class ThingESP32 srr.concat((char)payload[i]); } Serial.print(srr); - this->logic(srr); + onMessage(srr); } - void setupIT() + void onMessage(String data) { + DynamicJsonDocument data_in(1024); + DynamicJsonDocument data_out(1024); + deserializeJson(data_in, data); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - Serial.println(mqttServer); - - WiFi.begin(ssid, ssid_password); - - while (WiFi.status() != WL_CONNECTED) + if (data_in["action"] == "query") { - delay(500); - Serial.print("."); + data_out["msg_id"] = data_in["msg_id"]; + data_out["action"] = "returned_api_response"; + String query = data_in["query"]; + query.toLowerCase(); + data_out["returned_api_response"] = HandleResponse(query); + String outdata; + serializeJson(data_out, outdata); + publishMSG(outdata.c_str()); } + } - randomSeed(micros()); - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - - this->client.setServer(this->mqttServer, this->mqttPort); - this->client.setCallback([this](char *topic, byte *payload, unsigned int length) { - callback(topic, payload, length); - }); + void publishMSG(const char *info) + { + g_client.publish(this->char_topic, info); } }; From 76d3099fdb3d2925b8ef7d903fe613c769d5b8a5 Mon Sep 17 00:00:00 2001 From: Siddhesh Date: Fri, 3 Sep 2021 03:19:59 +0530 Subject: [PATCH 4/7] major code refactor --- src/ThingESP.h | 4 +- src/ThingESP_32.cpp | 274 ++++++++++++++------------- src/ThingESP_8266.cpp | 346 ++++++++++++++++------------------- src/thingesp/Device.cpp | 64 +++++++ src/thingesp/Logger.cpp | 7 + src/thingesp/RateLimiter.cpp | 43 +++++ 6 files changed, 420 insertions(+), 318 deletions(-) create mode 100644 src/thingesp/Device.cpp create mode 100644 src/thingesp/Logger.cpp create mode 100644 src/thingesp/RateLimiter.cpp diff --git a/src/ThingESP.h b/src/ThingESP.h index b6b341e..5a26aa1 100644 --- a/src/ThingESP.h +++ b/src/ThingESP.h @@ -1,7 +1,7 @@ #define MQTT_MAX_PACKET_SIZE 1024 #if defined(ESP8266) -#include "ThingESP_8266.cpp" + #include "ThingESP_8266.cpp" #elif defined(ESP32) -#include "ThingESP_32.cpp" + #include "ThingESP_32.cpp" #endif diff --git a/src/ThingESP_32.cpp b/src/ThingESP_32.cpp index eda5f9a..b684d37 100644 --- a/src/ThingESP_32.cpp +++ b/src/ThingESP_32.cpp @@ -1,165 +1,179 @@ -#define MQTT_MAX_PACKET_SIZE 1024 +#pragma once + #if defined(ESP8266) -#include + #include #elif defined(ESP32) -#include + #include #endif + +#include +#include + #include "PubSubClient/PubSubClient.h" #include "ArduinoJson.h" -String HandleResponse(String query); +#include "thingesp/Logger.cpp" +#include "thingesp/Device.cpp" +#include "thingesp/RateLimiter.cpp" -class ThingESP32 +String HandleResponse(String query) __attribute__((weak)); + +class ThingESP32 : public DeviceData, public RateLimiter { public: - ThingESP32(String username, String deviceName, String password) : g_client(espClient) - { - this->Username = username; - this->DeviceName = deviceName; - this->Password = password; - }; - - void SetWiFi(const char *ssID, const char *ssID_password) - { - this->ssid = ssID; - this->ssid_password = ssID_password; - } - - void initDevice() - { - this->topic = this->DeviceName + "/" + this->Username; - this->outname = this->DeviceName + "@" + this->Username; - - this->char_DeviceName = this->DeviceName.c_str(); - this->char_Password = this->Password.c_str(); - this->char_outname = this->outname.c_str(); - this->char_topic = this->topic.c_str(); - this->initiated = true; - - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - Serial.println(mqttServer); - - WiFi.begin(ssid, ssid_password); - - while (WiFi.status() != WL_CONNECTED) + ThingESP32(const char* _username, const char* _projectName, const char* _credentials) : client(espClient) { - delay(500); - Serial.print("."); - } + username = _username; + projectName = _projectName; + credentials = _credentials; - randomSeed(micros()); + genMetaData(); + }; - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - g_client.setServer(this->mqttServer, this->mqttPort); - g_client.setCallback([this](char *topic, byte *payload, unsigned int length) { - callback(topic, payload, length); - }); - } + void sendMsg(String number, String msg) + { + if (is_rate_limited()) return; + + DynamicJsonDocument data_out(1024); + data_out["action"] = "device_call"; + data_out["to_number"] = number; + data_out["msg"] = msg; + String outdata; + serializeJson(data_out, outdata); + publishMSG(outdata.c_str()); + } - void Handle() - { - if (!g_client.connected()) + void initDevice() { - while (!g_client.connected()) - { - delay(10); - Serial.print("Attempting connection..."); - if (g_client.connect(this->char_outname, this->char_outname, this->char_Password)) - { - Serial.println("connected"); - g_client.subscribe(this->char_topic); + if (wifi_configured) { + + LOG_VALUE("WiFi", "Connecting to: ", ssid) + + WiFi.begin(ssid, ssid_password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + } + + LOG("WiFi", "Connected successfully"); + LOG_VALUE("WiFi","IP address: ", WiFi.localIP()); + + } - else + + randomSeed(micros()); + + client.setServer(MQTT_SERVER, MQTT_PORT); + client.setCallback([this](char *topic, byte *payload, unsigned int length) { + callback(topic, payload, length); + }); + } + + void Handle() + { + if (!client.connected()) { - Serial.print("failed, rc="); - Serial.print(g_client.state()); - Serial.println(" try again in 5 seconds"); - delay(5000); + while (!client.connected()) + { + LOG("SOCKET", "Attempting connection to ThingESP") + + if (client.connect(outName.c_str(), outName.c_str(), credentials)) + { + LOG("SOCKET", "Connected to ThingESP successfully") + client.subscribe(topic.c_str()); + publishMSG(get_rate_limits_msg()); + } + else + { + LOG_VALUE("SOCKET", "Error connecting to ThingESP! Error code: ", client.state()); + if (client.state() == 5) + LOG("SOCKET","Please check your username, project name or credentials! ") + LOG("SOCKET", "Trying again in 10 seconds.."); + delay(10000); + } + } } - } + client.loop(); + } + + + void setCallback( String(*clbk)(String) ){ + this->callbackFunction = clbk; } - g_client.loop(); - } - - void sendMsg(String number, String msg) - { - DynamicJsonDocument data_out(1024); - data_out["action"] = "device_call"; - data_out["to_number"] = number; - data_out["msg"] = msg; - String outdata; - serializeJson(data_out, outdata); - publishMSG(outdata.c_str()); - } private: - String Username; - String DeviceName; - String Password; - bool initiated = false; + /* + * the callback function + */ + String (*callbackFunction)(String); - const char *ssid; - const char *ssid_password; - const char *mqttServer = "thingesp.siddhesh.me"; + /* + * the WiFi Client + */ + WiFiClient espClient; - int mqttPort = 1893; - String topic; - String outname; - const char *char_DeviceName; - const char *char_Password; - const char *char_outname; - const char *char_topic; + /* + * PubSubClient for MQTT + */ + PubSubClient client; - WiFiClient espClient; - PubSubClient g_client; - void callback(char *topic, byte *payload, unsigned int length) - { - String srr; - Serial.println(); - Serial.print("Message arrived ["); - Serial.print(topic); - Serial.print("] "); - Serial.println(); - for (int i = 0; i < length; i++) + void publishMSG(const char* _msg) { - srr.concat((char)payload[i]); + client.publish(topic.c_str(), _msg); } - Serial.print(srr); - onMessage(srr); - } - - void onMessage(String data) - { - DynamicJsonDocument data_in(1024); - DynamicJsonDocument data_out(1024); - deserializeJson(data_in, data); - if (data_in["action"] == "query") + void callback(char *topic, byte *payload, unsigned int length) { - data_out["msg_id"] = data_in["msg_id"]; - data_out["action"] = "returned_api_response"; - String query = data_in["query"]; - query.toLowerCase(); - data_out["returned_api_response"] = HandleResponse(query); - String outdata; - serializeJson(data_out, outdata); - publishMSG(outdata.c_str()); + String msg; + + for (int i = 0; i < length; i++) + msg.concat((char)payload[i]); + + onMessage(msg); } - } - void publishMSG(const char *info) - { - g_client.publish(this->char_topic, info); - } -}; + + void onMessage(String& data) + { + + DynamicJsonDocument data_in(1024); + DynamicJsonDocument data_out(1024); + deserializeJson(data_in, data); + + String incoming_action = data_in["action"]; + + if (incoming_action == "query") + { + data_out["msg_id"] = data_in["msg_id"]; + data_out["action"] = "returned_api_response"; + String query = data_in["query"]; + + #ifndef _DISABLE_LOWER_CASE_ + query.toLowerCase(); + #endif + + LOG_VALUE("MSG", "Query: ", query); + + String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); + + LOG_VALUE("MSG", "Response: ", resp); + + data_out["returned_api_response"] = resp; + + String out_msg; + serializeJson(data_out, out_msg); + publishMSG(out_msg.c_str()); + + } + else if (incoming_action == "RATE_LIMITS_INFO"){ + set_rate_limit((unsigned int)data_in["delay"]); + } + }; + +}; \ No newline at end of file diff --git a/src/ThingESP_8266.cpp b/src/ThingESP_8266.cpp index 8348b24..099717a 100644 --- a/src/ThingESP_8266.cpp +++ b/src/ThingESP_8266.cpp @@ -1,218 +1,192 @@ +#pragma once + #if defined(ESP8266) -#include + #include #elif defined(ESP32) -#include + #include #endif -#include "PubSubClient/PubSubClient.h" -#include "ArduinoJson.h" #ifndef _DISABLE_TLS_ -#include + #include #endif -String HandleResponse(String query); +#include +#include + +#include "PubSubClient/PubSubClient.h" +#include "ArduinoJson.h" + +#include "thingesp/Logger.cpp" +#include "thingesp/Device.cpp" +#include "thingesp/RateLimiter.cpp" -class ThingESP8266 +String HandleResponse(String query) __attribute__((weak)); + +class ThingESP8266 : public DeviceData, public RateLimiter { public: - ThingESP8266(String username, String deviceName, String password) - { - #ifndef _DISABLE_TLS_ - WiFiClientSecure espClient; - #if !defined(ESP32) - espClient.setInsecure(); + ThingESP8266(const char* _username, const char* _projectName, const char* _credentials) : client(espClient) + { + #if !defined(_DISABLE_TLS_) && !defined(ESP32) + espClient.setInsecure(); #endif - this->espClient = espClient; - PubSubClient client(this->espClient); - #else - WiFiClient espClient; - PubSubClient client(espClient); - #endif - - delay(2); - this->client = client; - this->Username = username; - this->DeviceName = deviceName; - this->Password = password; - }; - - void SetWiFi(const char *ssID, const char *ssID_password) - { - this->ssid = ssID; - this->ssid_password = ssID_password; - } - - void logic(String data) - { - DynamicJsonDocument data_in(1024); - DynamicJsonDocument data_out(1024); - deserializeJson(data_in, data); - - if (data_in["action"] == "query") + + delay(2); + + username = _username; + projectName = _projectName; + credentials = _credentials; + + genMetaData(); + }; + + + void sendMsg(String number, String msg) { - data_out["msg_id"] = data_in["msg_id"]; - data_out["action"] = "returned_api_response"; - String query = data_in["query"]; - query.toLowerCase(); - data_out["returned_api_response"] = HandleResponse(query); - String outdata; - serializeJson(data_out, outdata); - publishMSG(outdata.c_str()); + if (is_rate_limited()) return; + + DynamicJsonDocument data_out(1024); + data_out["action"] = "device_call"; + data_out["to_number"] = number; + data_out["msg"] = msg; + String outdata; + serializeJson(data_out, outdata); + publishMSG(outdata.c_str()); } - }; - - void sendMsg(String number, String msg) - { - DynamicJsonDocument data_out(1024); - data_out["action"] = "device_call"; - data_out["to_number"] = number; - data_out["msg"] = msg; - String outdata; - serializeJson(data_out, outdata); - publishMSG(outdata.c_str()); - } - - void initDevice() - { - // this->client = client; - this->topic = this->DeviceName + "/" + this->Username; - this->outname = this->DeviceName + "@" + this->Username; - this->char_DeviceName = this->DeviceName.c_str(); - this->char_Password = this->Password.c_str(); - this->char_outname = this->outname.c_str(); - this->char_topic = this->topic.c_str(); - this->initiated = true; - this->setupIT(); - } - - void Handle() - { - if (!client.connected()) + + void initDevice() { - while (!client.connected()) - { - Serial.print("Attempting connection..."); - if (client.connect(this->char_outname, this->char_outname, this->char_Password)) - { - Serial.println("connected"); - client.subscribe(this->char_topic); + if (wifi_configured) { + + LOG_VALUE("WiFi", "Connecting to: ", ssid) + + WiFi.begin(ssid, ssid_password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + } + + LOG("WiFi", "Connected successfully"); + LOG_VALUE("WiFi","IP address: ", WiFi.localIP()); + + } - else + + randomSeed(micros()); + + client.setServer(MQTT_SERVER, MQTT_PORT); + client.setCallback([this](char *topic, byte *payload, unsigned int length) { + callback(topic, payload, length); + }); + } + + void Handle() + { + if (!client.connected()) { - Serial.print("failed, rc="); - Serial.print(this->client.state()); - Serial.println(" try again in 5 seconds"); - delay(5000); + while (!client.connected()) + { + LOG("SOCKET", "Attempting connection to ThingESP") + + if (client.connect(outName.c_str(), outName.c_str(), credentials)) + { + LOG("SOCKET", "Connected to ThingESP successfully") + client.subscribe(topic.c_str()); + publishMSG(get_rate_limits_msg()); + } + else + { + LOG_VALUE("SOCKET", "Error connecting to ThingESP! Error code: ", client.state()); + if (client.state() == 5) + LOG("SOCKET","Please check your username, project name or credentials! ") + LOG("SOCKET", "Trying again in 10 seconds.."); + delay(10000); + } + } } - } + client.loop(); } - this->client.loop(); - } - void publishMSG(const char *info) - { - client.publish(this->char_topic, info); - } - void SetHost(const char *host) - { - this->mqttServer = host; - } + void setCallback( String(*clbk)(String) ){ + this->callbackFunction = clbk; + } private: - String Username; - String DeviceName; - String Password; - - bool initiated = false; - - const char *ssid; - const char *ssid_password; - - const char *mqttServer = "thingesp.siddhesh.me"; - #ifndef _DISABLE_TLS_ - int mqttPort = 1899; - #else - int mqttPort = 1893; - #endif - - - /* - #ifndef _THINGESP_SERVER_ - const char *mqttServer = "thingesp.siddhesh.me"; - #else - const char *mqttServer = _THINGESP_SERVER_; - #endif - - - #ifndef _THINGESP_PORT_ - #define _THINGESP_PORT_ 1893 - #endif - - #ifndef _THINGESP_PORT_TLS_ - #define _THINGESP_PORT_TLS_ 1899 - #endif - - #ifndef _DISABLE_TLS_ - int mqttPort = _THINGESP_PORT_TLS_; - #endif - #ifdef _DISABLE_TLS_ - int mqttPort = _THINGESP_PORT_; - #endif -*/ - - String topic; - String outname; - const char *char_DeviceName; - const char *char_Password; - const char *char_outname; - const char *char_topic; - - PubSubClient client; - WiFiClientSecure espClient; - - void callback(char *topic, byte *payload, unsigned int length) - { - String srr; - Serial.println(); - Serial.print("Message arrived ["); - Serial.print(topic); - Serial.print("] "); - Serial.println(); - for (int i = 0; i < length; i++) + + /* + * the callback function + */ + String (*callbackFunction)(String); + + + /* + * the WiFi Client + */ + #ifndef _DISABLE_TLS_ + WiFiClientSecure espClient; + #else + WiFiClient espClient; + #endif + + + /* + * PubSubClient for MQTT + */ + PubSubClient client; + + + void publishMSG(const char* _msg) { - srr.concat((char)payload[i]); + client.publish(topic.c_str(), _msg); } - Serial.print(srr); - this->logic(srr); - } - void setupIT() - { + void callback(char *topic, byte *payload, unsigned int length) + { + String msg; - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - Serial.println(mqttPort); + for (int i = 0; i < length; i++) + msg.concat((char)payload[i]); - WiFi.begin(ssid, ssid_password); + onMessage(msg); + } - while (WiFi.status() != WL_CONNECTED) + + void onMessage(String& data) { - delay(500); - Serial.print("."); - } - randomSeed(micros()); + DynamicJsonDocument data_in(1024); + DynamicJsonDocument data_out(1024); + deserializeJson(data_in, data); + + String incoming_action = data_in["action"]; + + if (incoming_action == "query") + { + data_out["msg_id"] = data_in["msg_id"]; + data_out["action"] = "returned_api_response"; + String query = data_in["query"]; + + #ifndef _DISABLE_LOWER_CASE_ + query.toLowerCase(); + #endif + + LOG_VALUE("MSG", "Query: ", query); - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); + String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); + + LOG_VALUE("MSG", "Response: ", resp); + + data_out["returned_api_response"] = resp; + + String out_msg; + serializeJson(data_out, out_msg); + publishMSG(out_msg.c_str()); + + } + else if (incoming_action == "RATE_LIMITS_INFO"){ + set_rate_limit((unsigned int)data_in["delay"]); + } + }; - this->client.setServer(this->mqttServer, this->mqttPort); - this->client.setCallback([this](char *topic, byte *payload, unsigned int length) { - callback(topic, payload, length); - }); - } -}; +}; \ No newline at end of file diff --git a/src/thingesp/Device.cpp b/src/thingesp/Device.cpp new file mode 100644 index 0000000..e70425e --- /dev/null +++ b/src/thingesp/Device.cpp @@ -0,0 +1,64 @@ +#pragma once +#include +#include +#include +#include "../PubSubClient/PubSubClient.h" + +class DeviceData{ +public: + + /* + * Set WiFi SSID and Password + */ + void SetWiFi(const char *_ssid, const char *_ssid_password) + { + wifi_configured = true; + ssid = _ssid; + ssid_password = _ssid_password; + } + + + /* + * Generate DeviceName and Topic Name(s) + */ + void genMetaData(){ + this->outName = projectName + "@" + username; + this->topic = projectName + "/" + username; + } + + String projectName; + const char* username; + const char* credentials; + + String outName; + String topic; + + const char* ssid; + const char* ssid_password; + + bool wifi_configured = false; + + + /* + * Check if TLS Disabled or not + */ + #if !defined(_DISABLE_TLS_) && !defined(ESP32) + unsigned int MQTT_PORT = 1899; // tls port + #else + unsigned int MQTT_PORT = 1893; // non-tls port + #endif + + + + /* + * ThingESP server DNS + */ + #ifndef _THINGESP_SERVER_ + const char *MQTT_SERVER = "thingesp.siddhesh.me"; + #else + const char *MQTT_SERVER = _THINGESP_SERVER_; + #endif + + + +}; \ No newline at end of file diff --git a/src/thingesp/Logger.cpp b/src/thingesp/Logger.cpp new file mode 100644 index 0000000..5bb4331 --- /dev/null +++ b/src/thingesp/Logger.cpp @@ -0,0 +1,7 @@ +#ifndef _LOG_DISABLE_ + #define LOG(type, text) Serial.print("["); Serial.print(F(type)); Serial.print("] "); Serial.println(F(text)); + #define LOG_VALUE(type, text, value) Serial.print("["); Serial.print(F(type)); Serial.print("] "); Serial.print(F(text)); Serial.println(value); +#else + #define LOG(type, text) void(); + #define LOG_VALUE(type, text, value) void(); +#endif \ No newline at end of file diff --git a/src/thingesp/RateLimiter.cpp b/src/thingesp/RateLimiter.cpp new file mode 100644 index 0000000..affa748 --- /dev/null +++ b/src/thingesp/RateLimiter.cpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include "../ArduinoJson.h" +#include "./Logger.cpp" + +class RateLimiter{ +public: + + bool is_rate_limited() { + unsigned int current_millis = millis(); + if (last_called_millis && (last_called_millis+RATE_LIMIT < current_millis)){ + last_called_millis = current_millis; + return false; + } + else { + LOG("RL", "You are getting Rate Limited!") + return true; + } + } + + void set_rate_limit(unsigned int _limit){ + RATE_LIMIT = _limit; + } + + const char* get_rate_limits_msg(){ + +// DynamicJsonDocument data_out(1024); +// data_out["action"] = "GET_RATE_LIMITS"; +// String out_msg; +// serializeJson(data_out, out_msg); +// return out_msg.c_str(); + + return "{\"action\": \"GET_RATE_LIMITS\"}"; + } + + +private: + unsigned int last_called_millis = 0; + unsigned int RATE_LIMIT = 0; +}; \ No newline at end of file From 9f19fec102a2c756bcf58d63dc9f08202b349da7 Mon Sep 17 00:00:00 2001 From: Siddhesh Date: Tue, 7 Sep 2021 03:18:51 +0530 Subject: [PATCH 5/7] added local rate-limiting --- src/ThingESP_32.cpp | 347 +++++++++++++++++------------------ src/ThingESP_8266.cpp | 60 +----- src/thingesp/Logger.cpp | 4 + src/thingesp/Message.cpp | 100 ++++++++++ src/thingesp/RateLimiter.cpp | 32 +++- 5 files changed, 298 insertions(+), 245 deletions(-) create mode 100644 src/thingesp/Message.cpp diff --git a/src/ThingESP_32.cpp b/src/ThingESP_32.cpp index b684d37..232ce42 100644 --- a/src/ThingESP_32.cpp +++ b/src/ThingESP_32.cpp @@ -1,179 +1,168 @@ -#pragma once - -#if defined(ESP8266) - #include -#elif defined(ESP32) - #include -#endif - -#include -#include - -#include "PubSubClient/PubSubClient.h" -#include "ArduinoJson.h" - -#include "thingesp/Logger.cpp" -#include "thingesp/Device.cpp" -#include "thingesp/RateLimiter.cpp" - -String HandleResponse(String query) __attribute__((weak)); - -class ThingESP32 : public DeviceData, public RateLimiter -{ -public: - ThingESP32(const char* _username, const char* _projectName, const char* _credentials) : client(espClient) - { - username = _username; - projectName = _projectName; - credentials = _credentials; - - genMetaData(); - }; - - - void sendMsg(String number, String msg) - { - if (is_rate_limited()) return; - - DynamicJsonDocument data_out(1024); - data_out["action"] = "device_call"; - data_out["to_number"] = number; - data_out["msg"] = msg; - String outdata; - serializeJson(data_out, outdata); - publishMSG(outdata.c_str()); - } - - void initDevice() - { - if (wifi_configured) { - - LOG_VALUE("WiFi", "Connecting to: ", ssid) - - WiFi.begin(ssid, ssid_password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - } - - LOG("WiFi", "Connected successfully"); - LOG_VALUE("WiFi","IP address: ", WiFi.localIP()); - - - } - - randomSeed(micros()); - - client.setServer(MQTT_SERVER, MQTT_PORT); - client.setCallback([this](char *topic, byte *payload, unsigned int length) { - callback(topic, payload, length); - }); - } - - void Handle() - { - if (!client.connected()) - { - while (!client.connected()) - { - LOG("SOCKET", "Attempting connection to ThingESP") - - if (client.connect(outName.c_str(), outName.c_str(), credentials)) - { - LOG("SOCKET", "Connected to ThingESP successfully") - client.subscribe(topic.c_str()); - publishMSG(get_rate_limits_msg()); - } - else - { - LOG_VALUE("SOCKET", "Error connecting to ThingESP! Error code: ", client.state()); - if (client.state() == 5) - LOG("SOCKET","Please check your username, project name or credentials! ") - LOG("SOCKET", "Trying again in 10 seconds.."); - delay(10000); - } - } - } - client.loop(); - } - - - void setCallback( String(*clbk)(String) ){ - this->callbackFunction = clbk; - } - -private: - - /* - * the callback function - */ - String (*callbackFunction)(String); - - - /* - * the WiFi Client - */ - WiFiClient espClient; - - - - /* - * PubSubClient for MQTT - */ - PubSubClient client; - - - void publishMSG(const char* _msg) - { - client.publish(topic.c_str(), _msg); - } - - void callback(char *topic, byte *payload, unsigned int length) - { - String msg; - - for (int i = 0; i < length; i++) - msg.concat((char)payload[i]); - - onMessage(msg); - } - - - void onMessage(String& data) - { - - DynamicJsonDocument data_in(1024); - DynamicJsonDocument data_out(1024); - deserializeJson(data_in, data); - - String incoming_action = data_in["action"]; - - if (incoming_action == "query") - { - data_out["msg_id"] = data_in["msg_id"]; - data_out["action"] = "returned_api_response"; - String query = data_in["query"]; - - #ifndef _DISABLE_LOWER_CASE_ - query.toLowerCase(); - #endif - - LOG_VALUE("MSG", "Query: ", query); - - String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); - - LOG_VALUE("MSG", "Response: ", resp); - - data_out["returned_api_response"] = resp; - - String out_msg; - serializeJson(data_out, out_msg); - publishMSG(out_msg.c_str()); - - } - else if (incoming_action == "RATE_LIMITS_INFO"){ - set_rate_limit((unsigned int)data_in["delay"]); - } - }; - -}; \ No newline at end of file +//#pragma once +// +//#if defined(ESP8266) +// #include +//#elif defined(ESP32) +// #include +//#endif +// +//#include +//#include +// +//#include "PubSubClient/PubSubClient.h" +//#include "ArduinoJson.h" +// +//#include "thingesp/Logger.cpp" +//#include "thingesp/Device.cpp" +//#include "thingesp/RateLimiter.cpp" +// +//String HandleResponse(String query) __attribute__((weak)); +// +//class ThingESP32 : public DeviceData, public RateLimiter +//{ +//public: +// ThingESP32(const char* _username, const char* _projectName, const char* _credentials) : client(espClient) +// { +// username = _username; +// projectName = _projectName; +// credentials = _credentials; +// +// genMetaData(); +// }; +// +// +// +// +// void initDevice() +// { +// if (wifi_configured) { +// +// LOG_VALUE("WiFi", "Connecting to: ", ssid) +// +// WiFi.begin(ssid, ssid_password); +// +// while (WiFi.status() != WL_CONNECTED) { +// delay(500); +// } +// +// LOG("WiFi", "Connected successfully"); +// LOG_VALUE("WiFi","IP address: ", WiFi.localIP()); +// +// +// } +// +// randomSeed(micros()); +// +// client.setServer(MQTT_SERVER, MQTT_PORT); +// client.setCallback([this](char *topic, byte *payload, unsigned int length) { +// callback(topic, payload, length); +// }); +// } +// +// void Handle() +// { +// if (!client.connected()) +// { +// while (!client.connected()) +// { +// LOG("SOCKET", "Attempting connection to ThingESP") +// +// if (client.connect(outName.c_str(), outName.c_str(), credentials)) +// { +// LOG("SOCKET", "Connected to ThingESP successfully") +// client.subscribe(topic.c_str()); +// publishMSG(get_rate_limits_msg()); +// } +// else +// { +// LOG_VALUE("SOCKET", "Error connecting to ThingESP! Error code: ", client.state()); +// if (client.state() == 5) +// LOG("SOCKET","Please check your username, project name or credentials! ") +// LOG("SOCKET", "Trying again in 10 seconds.."); +// delay(10000); +// } +// } +// } +// client.loop(); +// } +// +// +// void setCallback( String(*clbk)(String) ){ +// this->callbackFunction = clbk; +// } +// +//private: +// +// /* +// * the callback function +// */ +// String (*callbackFunction)(String); +// +// +// /* +// * the WiFi Client +// */ +// WiFiClient espClient; +// +// +// +// /* +// * PubSubClient for MQTT +// */ +// PubSubClient client; +// +// +// void publishMSG(const char* _msg) +// { +// client.publish(topic.c_str(), _msg); +// } +// +// void callback(char *topic, byte *payload, unsigned int length) +// { +// String msg; +// +// for (int i = 0; i < length; i++) +// msg.concat((char)payload[i]); +// +// onMessage(msg); +// } +// +// +// void onMessage(String& data) +// { +// +// DynamicJsonDocument data_in(1024); +// DynamicJsonDocument data_out(1024); +// deserializeJson(data_in, data); +// +// String incoming_action = data_in["action"]; +// +// if (incoming_action == "query") +// { +// data_out["msg_id"] = data_in["msg_id"]; +// data_out["action"] = "returned_api_response"; +// String query = data_in["query"]; +// +// #ifndef _DISABLE_LOWER_CASE_ +// query.toLowerCase(); +// #endif +// +// LOG_VALUE("MSG", "Query: ", query); +// +// String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); +// +// LOG_VALUE("MSG", "Response: ", resp); +// +// data_out["returned_api_response"] = resp; +// +// String out_msg; +// serializeJson(data_out, out_msg); +// publishMSG(out_msg.c_str()); +// +// } +// else if (incoming_action == "RATE_LIMITS_INFO"){ +// set_rate_limit((unsigned int)data_in["delay"]); +// } +// }; +// +//}; \ No newline at end of file diff --git a/src/ThingESP_8266.cpp b/src/ThingESP_8266.cpp index 099717a..a2236f5 100644 --- a/src/ThingESP_8266.cpp +++ b/src/ThingESP_8266.cpp @@ -19,10 +19,10 @@ #include "thingesp/Logger.cpp" #include "thingesp/Device.cpp" #include "thingesp/RateLimiter.cpp" +#include "thingesp/Message.cpp" -String HandleResponse(String query) __attribute__((weak)); -class ThingESP8266 : public DeviceData, public RateLimiter +class ThingESP8266 : public DeviceData, public Message { public: ThingESP8266(const char* _username, const char* _projectName, const char* _credentials) : client(espClient) @@ -40,20 +40,6 @@ class ThingESP8266 : public DeviceData, public RateLimiter genMetaData(); }; - - void sendMsg(String number, String msg) - { - if (is_rate_limited()) return; - - DynamicJsonDocument data_out(1024); - data_out["action"] = "device_call"; - data_out["to_number"] = number; - data_out["msg"] = msg; - String outdata; - serializeJson(data_out, outdata); - publishMSG(outdata.c_str()); - } - void initDevice() { if (wifi_configured) { @@ -108,9 +94,6 @@ class ThingESP8266 : public DeviceData, public RateLimiter } - void setCallback( String(*clbk)(String) ){ - this->callbackFunction = clbk; - } private: @@ -136,7 +119,7 @@ class ThingESP8266 : public DeviceData, public RateLimiter PubSubClient client; - void publishMSG(const char* _msg) + void publishMSG(const char* _msg) override { client.publish(topic.c_str(), _msg); } @@ -148,45 +131,10 @@ class ThingESP8266 : public DeviceData, public RateLimiter for (int i = 0; i < length; i++) msg.concat((char)payload[i]); - onMessage(msg); + this->onMessage(msg); } - void onMessage(String& data) - { - - DynamicJsonDocument data_in(1024); - DynamicJsonDocument data_out(1024); - deserializeJson(data_in, data); - - String incoming_action = data_in["action"]; - - if (incoming_action == "query") - { - data_out["msg_id"] = data_in["msg_id"]; - data_out["action"] = "returned_api_response"; - String query = data_in["query"]; - #ifndef _DISABLE_LOWER_CASE_ - query.toLowerCase(); - #endif - - LOG_VALUE("MSG", "Query: ", query); - - String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); - - LOG_VALUE("MSG", "Response: ", resp); - - data_out["returned_api_response"] = resp; - - String out_msg; - serializeJson(data_out, out_msg); - publishMSG(out_msg.c_str()); - - } - else if (incoming_action == "RATE_LIMITS_INFO"){ - set_rate_limit((unsigned int)data_in["delay"]); - } - }; }; \ No newline at end of file diff --git a/src/thingesp/Logger.cpp b/src/thingesp/Logger.cpp index 5bb4331..30420f9 100644 --- a/src/thingesp/Logger.cpp +++ b/src/thingesp/Logger.cpp @@ -1,7 +1,11 @@ +#pragma once + #ifndef _LOG_DISABLE_ #define LOG(type, text) Serial.print("["); Serial.print(F(type)); Serial.print("] "); Serial.println(F(text)); #define LOG_VALUE(type, text, value) Serial.print("["); Serial.print(F(type)); Serial.print("] "); Serial.print(F(text)); Serial.println(value); + #define LOG_WITHOUT_F(type, text) Serial.print("["); Serial.print(type); Serial.print("] "); Serial.println(text); #else #define LOG(type, text) void(); #define LOG_VALUE(type, text, value) void(); + #define LOG_VALUE(type, text) void(); #endif \ No newline at end of file diff --git a/src/thingesp/Message.cpp b/src/thingesp/Message.cpp new file mode 100644 index 0000000..700fcf9 --- /dev/null +++ b/src/thingesp/Message.cpp @@ -0,0 +1,100 @@ +#pragma once + +#include "../ArduinoJson.h" +#include "./RateLimiter.cpp" +#include "./Logger.cpp" + +#if defined(__GNUC__) + String HandleResponse(String query) __attribute__((weak)); +#else + String HandleResponse(String query); +#endif + + +class Message : public RateLimiter { +public: + void sendMsg(String number, String msg) { + if (!is_device_calls_enabled()) { + LOG("ERR", + "Device-calls have not been enabled! Please go to ThingESP console and enable them from project settings."); + return; + } + + if (is_rate_limited()) { + LOG_VALUE("ERR", "This device-call have been rate limited! for (seconds): ", get_rate_limit()); + LOG("ERR", + "to reduce the rate-limiting, email me with your username and your project use-case."); + return; + } + + DynamicJsonDocument data_out(1024); + data_out["action"] = "device_call"; + data_out["to_number"] = number; + data_out["msg"] = msg; + sendResponse(data_out); + } + + void setCallback(String(*clbk)(String)) { + this->callbackFunction = clbk; + } + + +protected: + void onMessage(String &data) { + + DynamicJsonDocument data_in(1024); + DynamicJsonDocument data_out(1024); + deserializeJson(data_in, data); + + String incoming_action = data_in["action"]; + + if (incoming_action == "query") { + + data_out["msg_id"] = (const char *) data_in["msg_id"]; + data_out["action"] = "returned_api_response"; + String query = (const char *) data_in["query"]; + + #ifndef _DISABLE_LOWER_CASE_ + query.toLowerCase(); + #endif + + LOG_VALUE("MSG", "Query: ", query); + String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); + LOG_VALUE("MSG", "Response: ", resp); + data_out["returned_api_response"] = resp; + sendResponse(data_out); + + + } else if (incoming_action == "rate_limits_info") { + + unsigned int delay = (unsigned int) data_in["delay"]; + bool calls_enabled = (bool) data_in["calls_enabled"]; + + LOG_VALUE("INFO", "Device calls: ", calls_enabled ? "enabled" : "disabled"); + LOG_VALUE("INFO", "Got rate-limits (sec): ", delay / 1000); + + set_rate_limit(delay); + set_device_calls_status(calls_enabled); + + } else if (incoming_action == "server_msg") { + + String incoming_msg = (const char *) data_in["msg"]; + LOG_WITHOUT_F("MSG", incoming_msg); + + } + }; + + + void sendResponse(DynamicJsonDocument &json_doc) { + String out_str; + serializeJson(json_doc, out_str); + publishMSG(out_str.c_str()); + } + + + String (*callbackFunction)(String); + + virtual void publishMSG(const char *msg) {}; + + +}; \ No newline at end of file diff --git a/src/thingesp/RateLimiter.cpp b/src/thingesp/RateLimiter.cpp index affa748..ec5576a 100644 --- a/src/thingesp/RateLimiter.cpp +++ b/src/thingesp/RateLimiter.cpp @@ -6,38 +6,50 @@ #include "../ArduinoJson.h" #include "./Logger.cpp" -class RateLimiter{ -public: +class RateLimiter { +protected: bool is_rate_limited() { unsigned int current_millis = millis(); - if (last_called_millis && (last_called_millis+RATE_LIMIT < current_millis)){ + if (current_millis - last_called_millis >= RATE_LIMIT) { last_called_millis = current_millis; return false; - } - else { - LOG("RL", "You are getting Rate Limited!") + } else { + LOG("INFO", "You are getting Rate Limited!") return true; } } - void set_rate_limit(unsigned int _limit){ + void set_rate_limit(unsigned int _limit) { RATE_LIMIT = _limit; } - const char* get_rate_limits_msg(){ + const char *get_rate_limits_msg() { // DynamicJsonDocument data_out(1024); -// data_out["action"] = "GET_RATE_LIMITS"; +// data_out["action"] = "get_rate_limits"; // String out_msg; // serializeJson(data_out, out_msg); // return out_msg.c_str(); - return "{\"action\": \"GET_RATE_LIMITS\"}"; + return "{\"action\": \"get_rate_limits\"}"; + } + + bool is_device_calls_enabled() { + return device_calls_enabled; + } + + void set_device_calls_status(bool is_enabled) { + device_calls_enabled = is_enabled; + } + + unsigned int get_rate_limit() { + return RATE_LIMIT / 1000; } private: + bool device_calls_enabled = false; unsigned int last_called_millis = 0; unsigned int RATE_LIMIT = 0; }; \ No newline at end of file From 0ca73bf968bd0b0c75e239723be71dd6f23b11b6 Mon Sep 17 00:00:00 2001 From: Siddhesh Date: Tue, 14 Sep 2021 16:47:35 +0530 Subject: [PATCH 6/7] refactored bunch of code, & added local-limiting --- keywords.txt | 24 ++--- library.properties | 2 +- src/ThingESP.h | 16 +++- src/ThingESPClient.cpp | 133 +++++++++++++++++++++++++++ src/ThingESP_32.cpp | 168 ----------------------------------- src/ThingESP_8266.cpp | 140 ----------------------------- src/thingesp/Device.cpp | 89 +++++++++---------- src/thingesp/Logger.cpp | 2 +- src/thingesp/Message.cpp | 131 ++++++++++++++------------- src/thingesp/RateLimiter.cpp | 66 +++++++------- 10 files changed, 310 insertions(+), 461 deletions(-) create mode 100644 src/ThingESPClient.cpp delete mode 100644 src/ThingESP_32.cpp delete mode 100644 src/ThingESP_8266.cpp diff --git a/keywords.txt b/keywords.txt index 3a806e8..387729c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -3,23 +3,23 @@ ####################################### ####################################### -# Datatypes (KEYWORD1) Classes +# Datatypes (KEYWORD1) ####################################### -WH_ESP8266 KEYWORD1 +ThingESP32 KEYWORD1 +ThingESP8266 KEYWORD1 ####################################### -# Datatypes (KEYWORD2) Methods +# Methods and Functions (KEYWORD2) ####################################### -DeviceClient KEYWORD2 +SetWiFi KEYWORD2 +initDevice KEYWORD2 +setCallback KEYWORD2 +Handle KEYWORD2 +sendMsg KEYWORD2 +###################################### +# Constants (LITERAL1) ####################################### -# Datatypes (KEYWORD3) Setup & Loop -####################################### - -SetDevice KEYWORD3 -SetWiFi KEYWORD3 -initDevice KEYWORD3 -Handle KEYWORD3 -HandleResponse KEYWORD3 \ No newline at end of file +HandleResponse LITERAL1 diff --git a/library.properties b/library.properties index 546b106..30f9e4c 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ThingESP -version=1.2.2 +version=1.3.0 author=SiddheshNan maintainer=SiddheshNan sentence=Arduino library for the ThingsESP Platform. diff --git a/src/ThingESP.h b/src/ThingESP.h index 5a26aa1..b274bb9 100644 --- a/src/ThingESP.h +++ b/src/ThingESP.h @@ -1,7 +1,19 @@ #define MQTT_MAX_PACKET_SIZE 1024 +#include "./ThingESPClient.cpp" #if defined(ESP8266) - #include "ThingESP_8266.cpp" + class ThingESP8266 : public thing_esp::ThingESPClient { + public: + ThingESP8266(const char* _username, const char* _projectName, const char* _credentials) : ThingESPClient(_username, _projectName, _credentials) + {} + }; #elif defined(ESP32) - #include "ThingESP_32.cpp" + class ThingESP32 : public thing_esp::ThingESPClient { + public: + ThingESP32(const char* _username, const char* _projectName, const char* _credentials) : ThingESPClient(_username, _projectName, _credentials) + {} + }; #endif + + + diff --git a/src/ThingESPClient.cpp b/src/ThingESPClient.cpp new file mode 100644 index 0000000..b521b60 --- /dev/null +++ b/src/ThingESPClient.cpp @@ -0,0 +1,133 @@ +#pragma once + +#if defined(ESP8266) +#include +#elif defined(ESP32) +#include +#endif + +#ifndef _DISABLE_TLS_ + +#include + +#endif + +#include +#include + +#include "PubSubClient/PubSubClient.h" +#include "ArduinoJson.h" + +#include "thingesp/Logger.cpp" +#include "thingesp/Device.cpp" +#include "thingesp/RateLimiter.cpp" +#include "thingesp/Message.cpp" + +namespace thing_esp { + class ThingESPClient : public DeviceData, public Message { + public: + ThingESPClient(const char *_username, const char *_projectName, const char *_credentials) : client(espClient) { + + #if !defined(_DISABLE_TLS_) && !defined(ESP32) + espClient.setInsecure(); + delay(2); + #endif + + username = _username; + projectName = _projectName; + credentials = _credentials; + + genMetaData(); + }; + + void initDevice() { + if (wifi_configured) { + + LOG_VALUE("WiFi", "Connecting to: ", ssid) + + WiFi.begin(ssid, ssid_password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + } + + LOG("WiFi", "Connected successfully"); + LOG_VALUE("WiFi", "IP address: ", WiFi.localIP()); + + + } + + randomSeed(micros()); + + client.setServer(MQTT_SERVER, MQTT_PORT); + client.setCallback([this](char *topic, byte *payload, unsigned int length) { + callback(topic, payload, length); + }); + } + + void Handle() { + if (!client.connected()) { + while (!client.connected()) { + LOG("SOCKET", "Attempting connection to ThingESP") + + if (client.connect(outName.c_str(), outName.c_str(), credentials)) { + LOG("SOCKET", "Connected to ThingESP successfully") + client.subscribe(topic.c_str()); + publishMSG(get_rate_limits_msg()); + } else { + LOG_VALUE("SOCKET", "Error connecting to ThingESP! Error code: ", client.state()); + if (client.state() == 5) { + LOG("SOCKET", "Please check your username, project name or credentials! "); + } + LOG("SOCKET", "Trying again in 10 seconds.."); + delay(10000); + } + } + } + client.loop(); + } + + + protected: + + /* + * the callback function + */ + String (*callbackFunction)(String) + + override; + + + /* + * the WiFi Client + */ + #if !defined(_DISABLE_TLS_) && !defined(ESP32) + WiFiClientSecure espClient; + #else + WiFiClient espClient; + #endif + + + /* + * PubSubClient for MQTT + */ + PubSubClient client; + + + void publishMSG(const char *_msg) override { + client.publish(topic.c_str(), _msg); + } + + void callback(char *topic, byte *payload, unsigned int length) { + String msg; + + for (int i = 0; i < length; i++) + msg.concat((char) payload[i]); + + this->onMessage(msg); + } + + + }; + +} \ No newline at end of file diff --git a/src/ThingESP_32.cpp b/src/ThingESP_32.cpp deleted file mode 100644 index 232ce42..0000000 --- a/src/ThingESP_32.cpp +++ /dev/null @@ -1,168 +0,0 @@ -//#pragma once -// -//#if defined(ESP8266) -// #include -//#elif defined(ESP32) -// #include -//#endif -// -//#include -//#include -// -//#include "PubSubClient/PubSubClient.h" -//#include "ArduinoJson.h" -// -//#include "thingesp/Logger.cpp" -//#include "thingesp/Device.cpp" -//#include "thingesp/RateLimiter.cpp" -// -//String HandleResponse(String query) __attribute__((weak)); -// -//class ThingESP32 : public DeviceData, public RateLimiter -//{ -//public: -// ThingESP32(const char* _username, const char* _projectName, const char* _credentials) : client(espClient) -// { -// username = _username; -// projectName = _projectName; -// credentials = _credentials; -// -// genMetaData(); -// }; -// -// -// -// -// void initDevice() -// { -// if (wifi_configured) { -// -// LOG_VALUE("WiFi", "Connecting to: ", ssid) -// -// WiFi.begin(ssid, ssid_password); -// -// while (WiFi.status() != WL_CONNECTED) { -// delay(500); -// } -// -// LOG("WiFi", "Connected successfully"); -// LOG_VALUE("WiFi","IP address: ", WiFi.localIP()); -// -// -// } -// -// randomSeed(micros()); -// -// client.setServer(MQTT_SERVER, MQTT_PORT); -// client.setCallback([this](char *topic, byte *payload, unsigned int length) { -// callback(topic, payload, length); -// }); -// } -// -// void Handle() -// { -// if (!client.connected()) -// { -// while (!client.connected()) -// { -// LOG("SOCKET", "Attempting connection to ThingESP") -// -// if (client.connect(outName.c_str(), outName.c_str(), credentials)) -// { -// LOG("SOCKET", "Connected to ThingESP successfully") -// client.subscribe(topic.c_str()); -// publishMSG(get_rate_limits_msg()); -// } -// else -// { -// LOG_VALUE("SOCKET", "Error connecting to ThingESP! Error code: ", client.state()); -// if (client.state() == 5) -// LOG("SOCKET","Please check your username, project name or credentials! ") -// LOG("SOCKET", "Trying again in 10 seconds.."); -// delay(10000); -// } -// } -// } -// client.loop(); -// } -// -// -// void setCallback( String(*clbk)(String) ){ -// this->callbackFunction = clbk; -// } -// -//private: -// -// /* -// * the callback function -// */ -// String (*callbackFunction)(String); -// -// -// /* -// * the WiFi Client -// */ -// WiFiClient espClient; -// -// -// -// /* -// * PubSubClient for MQTT -// */ -// PubSubClient client; -// -// -// void publishMSG(const char* _msg) -// { -// client.publish(topic.c_str(), _msg); -// } -// -// void callback(char *topic, byte *payload, unsigned int length) -// { -// String msg; -// -// for (int i = 0; i < length; i++) -// msg.concat((char)payload[i]); -// -// onMessage(msg); -// } -// -// -// void onMessage(String& data) -// { -// -// DynamicJsonDocument data_in(1024); -// DynamicJsonDocument data_out(1024); -// deserializeJson(data_in, data); -// -// String incoming_action = data_in["action"]; -// -// if (incoming_action == "query") -// { -// data_out["msg_id"] = data_in["msg_id"]; -// data_out["action"] = "returned_api_response"; -// String query = data_in["query"]; -// -// #ifndef _DISABLE_LOWER_CASE_ -// query.toLowerCase(); -// #endif -// -// LOG_VALUE("MSG", "Query: ", query); -// -// String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); -// -// LOG_VALUE("MSG", "Response: ", resp); -// -// data_out["returned_api_response"] = resp; -// -// String out_msg; -// serializeJson(data_out, out_msg); -// publishMSG(out_msg.c_str()); -// -// } -// else if (incoming_action == "RATE_LIMITS_INFO"){ -// set_rate_limit((unsigned int)data_in["delay"]); -// } -// }; -// -//}; \ No newline at end of file diff --git a/src/ThingESP_8266.cpp b/src/ThingESP_8266.cpp deleted file mode 100644 index a2236f5..0000000 --- a/src/ThingESP_8266.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#pragma once - -#if defined(ESP8266) - #include -#elif defined(ESP32) - #include -#endif - -#ifndef _DISABLE_TLS_ - #include -#endif - -#include -#include - -#include "PubSubClient/PubSubClient.h" -#include "ArduinoJson.h" - -#include "thingesp/Logger.cpp" -#include "thingesp/Device.cpp" -#include "thingesp/RateLimiter.cpp" -#include "thingesp/Message.cpp" - - -class ThingESP8266 : public DeviceData, public Message -{ -public: - ThingESP8266(const char* _username, const char* _projectName, const char* _credentials) : client(espClient) - { - #if !defined(_DISABLE_TLS_) && !defined(ESP32) - espClient.setInsecure(); - #endif - - delay(2); - - username = _username; - projectName = _projectName; - credentials = _credentials; - - genMetaData(); - }; - - void initDevice() - { - if (wifi_configured) { - - LOG_VALUE("WiFi", "Connecting to: ", ssid) - - WiFi.begin(ssid, ssid_password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - } - - LOG("WiFi", "Connected successfully"); - LOG_VALUE("WiFi","IP address: ", WiFi.localIP()); - - - } - - randomSeed(micros()); - - client.setServer(MQTT_SERVER, MQTT_PORT); - client.setCallback([this](char *topic, byte *payload, unsigned int length) { - callback(topic, payload, length); - }); - } - - void Handle() - { - if (!client.connected()) - { - while (!client.connected()) - { - LOG("SOCKET", "Attempting connection to ThingESP") - - if (client.connect(outName.c_str(), outName.c_str(), credentials)) - { - LOG("SOCKET", "Connected to ThingESP successfully") - client.subscribe(topic.c_str()); - publishMSG(get_rate_limits_msg()); - } - else - { - LOG_VALUE("SOCKET", "Error connecting to ThingESP! Error code: ", client.state()); - if (client.state() == 5) - LOG("SOCKET","Please check your username, project name or credentials! ") - LOG("SOCKET", "Trying again in 10 seconds.."); - delay(10000); - } - } - } - client.loop(); - } - - - -private: - - /* - * the callback function - */ - String (*callbackFunction)(String); - - - /* - * the WiFi Client - */ - #ifndef _DISABLE_TLS_ - WiFiClientSecure espClient; - #else - WiFiClient espClient; - #endif - - - /* - * PubSubClient for MQTT - */ - PubSubClient client; - - - void publishMSG(const char* _msg) override - { - client.publish(topic.c_str(), _msg); - } - - void callback(char *topic, byte *payload, unsigned int length) - { - String msg; - - for (int i = 0; i < length; i++) - msg.concat((char)payload[i]); - - this->onMessage(msg); - } - - - - -}; \ No newline at end of file diff --git a/src/thingesp/Device.cpp b/src/thingesp/Device.cpp index e70425e..dfc1ea9 100644 --- a/src/thingesp/Device.cpp +++ b/src/thingesp/Device.cpp @@ -3,62 +3,61 @@ #include #include #include "../PubSubClient/PubSubClient.h" +namespace thing_esp { + class DeviceData { + public: -class DeviceData{ -public: + /* + * Set WiFi SSID and Password + */ + void SetWiFi(const char *_ssid, const char *_ssid_password) { + wifi_configured = true; + ssid = _ssid; + ssid_password = _ssid_password; + } - /* - * Set WiFi SSID and Password - */ - void SetWiFi(const char *_ssid, const char *_ssid_password) - { - wifi_configured = true; - ssid = _ssid; - ssid_password = _ssid_password; - } + /* + * Generate DeviceName and Topic Name(s) + */ + void genMetaData() { + this->outName = projectName + "@" + username; + this->topic = projectName + "/" + username; + } - /* - * Generate DeviceName and Topic Name(s) - */ - void genMetaData(){ - this->outName = projectName + "@" + username; - this->topic = projectName + "/" + username; - } + String projectName; + const char *username; + const char *credentials; - String projectName; - const char* username; - const char* credentials; + String outName; + String topic; - String outName; - String topic; + const char *ssid; + const char *ssid_password; - const char* ssid; - const char* ssid_password; + bool wifi_configured = false; - bool wifi_configured = false; + /* + * Check if TLS Disabled or not + */ + #if !defined(_DISABLE_TLS_) && !defined(ESP32) + unsigned int MQTT_PORT = 1899; // tls port + #else + unsigned int MQTT_PORT = 1893; // non-tls port + #endif - /* - * Check if TLS Disabled or not - */ - #if !defined(_DISABLE_TLS_) && !defined(ESP32) - unsigned int MQTT_PORT = 1899; // tls port - #else - unsigned int MQTT_PORT = 1893; // non-tls port - #endif + /* + * ThingESP server DNS + */ + #ifndef _THINGESP_SERVER_ + const char *MQTT_SERVER = "thingesp.siddhesh.me"; + #else + const char *MQTT_SERVER = _THINGESP_SERVER_; + #endif - /* - * ThingESP server DNS - */ - #ifndef _THINGESP_SERVER_ - const char *MQTT_SERVER = "thingesp.siddhesh.me"; - #else - const char *MQTT_SERVER = _THINGESP_SERVER_; - #endif - - -}; \ No newline at end of file + }; +} \ No newline at end of file diff --git a/src/thingesp/Logger.cpp b/src/thingesp/Logger.cpp index 30420f9..4bb3449 100644 --- a/src/thingesp/Logger.cpp +++ b/src/thingesp/Logger.cpp @@ -7,5 +7,5 @@ #else #define LOG(type, text) void(); #define LOG_VALUE(type, text, value) void(); - #define LOG_VALUE(type, text) void(); + #define LOG_WITHOUT_F(type, text) void(); #endif \ No newline at end of file diff --git a/src/thingesp/Message.cpp b/src/thingesp/Message.cpp index 700fcf9..88a5a96 100644 --- a/src/thingesp/Message.cpp +++ b/src/thingesp/Message.cpp @@ -4,97 +4,108 @@ #include "./RateLimiter.cpp" #include "./Logger.cpp" -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__GNUG__) || defined(__clang__) String HandleResponse(String query) __attribute__((weak)); #else String HandleResponse(String query); #endif - -class Message : public RateLimiter { -public: - void sendMsg(String number, String msg) { - if (!is_device_calls_enabled()) { - LOG("ERR", - "Device-calls have not been enabled! Please go to ThingESP console and enable them from project settings."); - return; +namespace thing_esp { + class Message : public RateLimiter { + public: + void sendMsg(String number, String msg) { + if (!is_device_calls_enabled()) { + LOG("ERR", + "Device-calls have not been enabled! Please go to ThingESP console and enable them from project settings."); + return; + } + + if (is_rate_limited()) { + LOG_VALUE("ERR", "This device-call have been rate limited! for (seconds): ", get_rate_limit()); + LOG("ERR", + "to reduce the rate-limiting, email me with your username and your project use-case."); + return; + } + + DynamicJsonDocument data_out(1024); + data_out["action"] = "device_call"; + data_out["to_number"] = number; + data_out["msg"] = msg; + sendResponse(data_out); } - if (is_rate_limited()) { - LOG_VALUE("ERR", "This device-call have been rate limited! for (seconds): ", get_rate_limit()); - LOG("ERR", - "to reduce the rate-limiting, email me with your username and your project use-case."); - return; + void setCallback(String(*callback_func)(String)) { + this->callbackFunction = callback_func; } - DynamicJsonDocument data_out(1024); - data_out["action"] = "device_call"; - data_out["to_number"] = number; - data_out["msg"] = msg; - sendResponse(data_out); - } - void setCallback(String(*clbk)(String)) { - this->callbackFunction = clbk; - } + protected: + void onMessage(String &data) { + DynamicJsonDocument data_in(1024); + DynamicJsonDocument data_out(1024); + deserializeJson(data_in, data); -protected: - void onMessage(String &data) { + String incoming_action = data_in["action"]; - DynamicJsonDocument data_in(1024); - DynamicJsonDocument data_out(1024); - deserializeJson(data_in, data); + if (incoming_action == "query") { - String incoming_action = data_in["action"]; + if (!HandleResponse && !callbackFunction){ + LOG("MSG", "Error! No callback was set! Please set HandleResponse or setCallback!"); + return; + } - if (incoming_action == "query") { + data_out["msg_id"] = (const char *) data_in["msg_id"]; + data_out["action"] = "returned_api_response"; + String query = (const char *) data_in["query"]; - data_out["msg_id"] = (const char *) data_in["msg_id"]; - data_out["action"] = "returned_api_response"; - String query = (const char *) data_in["query"]; + #ifndef _DISABLE_LOWER_CASE_ + query.toLowerCase(); + #endif - #ifndef _DISABLE_LOWER_CASE_ - query.toLowerCase(); - #endif + LOG_VALUE("MSG", "Query: ", query); + String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); + LOG_VALUE("MSG", "Response: ", resp); + data_out["returned_api_response"] = resp; + sendResponse(data_out); - LOG_VALUE("MSG", "Query: ", query); - String resp = !!HandleResponse ? HandleResponse(query) : this->callbackFunction(query); - LOG_VALUE("MSG", "Response: ", resp); - data_out["returned_api_response"] = resp; - sendResponse(data_out); + } else if (incoming_action == "rate_limits_info") { - } else if (incoming_action == "rate_limits_info") { + unsigned int delay = (unsigned int) data_in["delay"]; + bool calls_enabled = (bool) data_in["calls_enabled"]; - unsigned int delay = (unsigned int) data_in["delay"]; - bool calls_enabled = (bool) data_in["calls_enabled"]; + LOG_VALUE("INFO", "Device calls: ", calls_enabled ? "enabled" : "disabled"); + LOG_VALUE("INFO", "Got rate-limits (sec): ", delay / 1000); - LOG_VALUE("INFO", "Device calls: ", calls_enabled ? "enabled" : "disabled"); - LOG_VALUE("INFO", "Got rate-limits (sec): ", delay / 1000); + set_rate_limit(delay); + set_device_calls_status(calls_enabled); - set_rate_limit(delay); - set_device_calls_status(calls_enabled); + } else if (incoming_action == "server_msg") { - } else if (incoming_action == "server_msg") { + String incoming_msg = (const char *) data_in["msg"]; + LOG_WITHOUT_F("MSG", incoming_msg); - String incoming_msg = (const char *) data_in["msg"]; - LOG_WITHOUT_F("MSG", incoming_msg); + } + }; + + void sendResponse(DynamicJsonDocument &json_doc) { + String out_str; + serializeJson(json_doc, out_str); + publishMSG(out_str.c_str()); } - }; - void sendResponse(DynamicJsonDocument &json_doc) { - String out_str; - serializeJson(json_doc, out_str); - publishMSG(out_str.c_str()); - } + /* + * Overwritten in the client + */ + String (*callbackFunction)(String); - String (*callbackFunction)(String); + virtual void publishMSG(const char *msg) {}; - virtual void publishMSG(const char *msg) {}; + }; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/thingesp/RateLimiter.cpp b/src/thingesp/RateLimiter.cpp index ec5576a..3ad6783 100644 --- a/src/thingesp/RateLimiter.cpp +++ b/src/thingesp/RateLimiter.cpp @@ -6,25 +6,26 @@ #include "../ArduinoJson.h" #include "./Logger.cpp" -class RateLimiter { -protected: - - bool is_rate_limited() { - unsigned int current_millis = millis(); - if (current_millis - last_called_millis >= RATE_LIMIT) { - last_called_millis = current_millis; - return false; - } else { - LOG("INFO", "You are getting Rate Limited!") - return true; +namespace thing_esp { + class RateLimiter { + protected: + + bool is_rate_limited() { + unsigned int current_millis = millis(); + if (current_millis - last_called_millis >= RATE_LIMIT) { + last_called_millis = current_millis; + return false; + } else { + LOG("INFO", "You are getting Rate Limited!") + return true; + } } - } - void set_rate_limit(unsigned int _limit) { - RATE_LIMIT = _limit; - } + void set_rate_limit(unsigned int _limit) { + RATE_LIMIT = _limit; + } - const char *get_rate_limits_msg() { + const char *get_rate_limits_msg() { // DynamicJsonDocument data_out(1024); // data_out["action"] = "get_rate_limits"; @@ -32,24 +33,25 @@ class RateLimiter { // serializeJson(data_out, out_msg); // return out_msg.c_str(); - return "{\"action\": \"get_rate_limits\"}"; - } + return "{\"action\": \"get_rate_limits\"}"; + } - bool is_device_calls_enabled() { - return device_calls_enabled; - } + bool is_device_calls_enabled() { + return device_calls_enabled; + } - void set_device_calls_status(bool is_enabled) { - device_calls_enabled = is_enabled; - } + void set_device_calls_status(bool is_enabled) { + device_calls_enabled = is_enabled; + } - unsigned int get_rate_limit() { - return RATE_LIMIT / 1000; - } + unsigned int get_rate_limit() { + return RATE_LIMIT / 1000; + } -private: - bool device_calls_enabled = false; - unsigned int last_called_millis = 0; - unsigned int RATE_LIMIT = 0; -}; \ No newline at end of file + private: + bool device_calls_enabled = false; + unsigned int last_called_millis = 0; + unsigned int RATE_LIMIT = 0; + }; +} \ No newline at end of file From 17125cb6079e2f8cce00025d2ad3393b61b547c2 Mon Sep 17 00:00:00 2001 From: Siddhesh Date: Tue, 14 Sep 2021 17:02:17 +0530 Subject: [PATCH 7/7] typo fixes --- src/ThingESPClient.cpp | 18 +++++++----------- src/thingesp/Device.cpp | 18 +++++++++++++++--- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/ThingESPClient.cpp b/src/ThingESPClient.cpp index b521b60..ee0ec45 100644 --- a/src/ThingESPClient.cpp +++ b/src/ThingESPClient.cpp @@ -1,15 +1,13 @@ #pragma once #if defined(ESP8266) -#include + #include #elif defined(ESP32) -#include + #include #endif #ifndef _DISABLE_TLS_ - -#include - + #include #endif #include @@ -37,7 +35,7 @@ namespace thing_esp { projectName = _projectName; credentials = _credentials; - genMetaData(); + this->genMetaData(); }; void initDevice() { @@ -72,7 +70,7 @@ namespace thing_esp { if (client.connect(outName.c_str(), outName.c_str(), credentials)) { LOG("SOCKET", "Connected to ThingESP successfully") - client.subscribe(topic.c_str()); + client.subscribe(c_topic); publishMSG(get_rate_limits_msg()); } else { LOG_VALUE("SOCKET", "Error connecting to ThingESP! Error code: ", client.state()); @@ -93,9 +91,7 @@ namespace thing_esp { /* * the callback function */ - String (*callbackFunction)(String) - - override; + String (*callbackFunction)(String) override; /* @@ -115,7 +111,7 @@ namespace thing_esp { void publishMSG(const char *_msg) override { - client.publish(topic.c_str(), _msg); + client.publish(c_topic, _msg); } void callback(char *topic, byte *payload, unsigned int length) { diff --git a/src/thingesp/Device.cpp b/src/thingesp/Device.cpp index dfc1ea9..90e9501 100644 --- a/src/thingesp/Device.cpp +++ b/src/thingesp/Device.cpp @@ -1,8 +1,12 @@ #pragma once + #include #include #include + #include "../PubSubClient/PubSubClient.h" + + namespace thing_esp { class DeviceData { public: @@ -23,6 +27,7 @@ namespace thing_esp { void genMetaData() { this->outName = projectName + "@" + username; this->topic = projectName + "/" + username; + this->c_topic = topic.c_str(); } String projectName; @@ -31,6 +36,7 @@ namespace thing_esp { String outName; String topic; + const char* c_topic; const char *ssid; const char *ssid_password; @@ -41,10 +47,16 @@ namespace thing_esp { /* * Check if TLS Disabled or not */ - #if !defined(_DISABLE_TLS_) && !defined(ESP32) - unsigned int MQTT_PORT = 1899; // tls port + #if !defined(_MQTT_PORT_) + + #if !defined(_DISABLE_TLS_) && !defined(ESP32) + unsigned int MQTT_PORT = 1899; // tls port + #else + unsigned int MQTT_PORT = 1893; // non-tls port + #endif + #else - unsigned int MQTT_PORT = 1893; // non-tls port + unsigned int MQTT_PORT = _MQTT_PORT_; #endif