Merge branch 'development' of github.com:arendst/Tasmota into pr_tm1638

This commit is contained in:
Ajith Vasudevan 2021-03-19 08:35:23 +05:30
commit b6cb5f203b
57 changed files with 555 additions and 161 deletions

View File

@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file.
## [Unreleased] - Development
## [9.3.1.2]
### Added
- Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) (#5341)
### Changed
- PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12
## [9.3.1.1]
### Added
- Support for CSE7761 energy monitor as used in ESP32 based Sonoff Dual R3 Pow (#10793)
@ -18,8 +25,7 @@ All notable changes to this project will be documented in this file.
- ESP32 Extent BLE (#11212)
- ESP32 support for WS2812 hardware driver via RMT or I2S
- ESP32 support for secondary I2C controller
- Add support for MPU6686 on primary or secondary I2C bus
- Support for MPU6686 on primary or secondary I2C bus
### Changed
- ESP32 core library from v1.0.5-rc6 to v1.0.5

View File

@ -78,8 +78,9 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
[Complete list](BUILDS.md) of available feature and sensors.
## Changelog v9.3.1.1
## Changelog v9.3.1.2
### Added
- Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) [#5341](https://github.com/arendst/Tasmota/issues/5341)
- Command ``Sensor80 1 <0..7>`` to control MFRC522 RFID antenna gain from 18dB (0) to 48dB (7) [#11073](https://github.com/arendst/Tasmota/issues/11073)
- Support for SML VBUS [#11125](https://github.com/arendst/Tasmota/issues/11125)
- Support for NEC and OPTOMA LCD/DLP Projector serial power control by Jan Bubík [#11145](https://github.com/arendst/Tasmota/issues/11145)
@ -93,6 +94,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
### Changed
- TasmotaSerial library from v3.2.0 to v3.3.0
- PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12
- ESP32 core library from v1.0.5-rc6 to v1.0.5
- TuyaMcu dimmer timeout [#11121](https://github.com/arendst/Tasmota/issues/11121)
- Rename epaper 42 commands [#11222](https://github.com/arendst/Tasmota/issues/11222)

View File

@ -1 +0,0 @@
tests/bin

View File

@ -0,0 +1,5 @@
tests/bin
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json

View File

@ -1,3 +1,12 @@
2.8
* Add setBufferSize() to override MQTT_MAX_PACKET_SIZE
* Add setKeepAlive() to override MQTT_KEEPALIVE
* Add setSocketTimeout() to overide MQTT_SOCKET_TIMEOUT
* Added check to prevent subscribe/unsubscribe to empty topics
* Declare wifi mode prior to connect in ESP example
* Use `strnlen` to avoid overruns
* Support pre-connected Client objects
2.7
* Fix remaining-length handling to prevent buffer overrun
* Add large-payload API - beginPublish/write/publish/endPublish

View File

@ -1,4 +1,4 @@
Copyright (c) 2008-2015 Nicholas O'Leary
Copyright (c) 2008-2020 Nicholas O'Leary
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@ -13,10 +13,12 @@ Full API documentation is available here: https://pubsubclient.knolleary.net
## Limitations
- It can only publish QoS 0 messages. It can subscribe at QoS 0 or QoS 1.
- The maximum message size, including header, is **128 bytes** by default. This
is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h`.
- The maximum message size, including header, is **256 bytes** by default. This
is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h` or can be changed
by calling `PubSubClient::setBufferSize(size)`.
- The keepalive interval is set to 15 seconds by default. This is configurable
via `MQTT_KEEPALIVE` in `PubSubClient.h`.
via `MQTT_KEEPALIVE` in `PubSubClient.h` or can be changed by calling
`PubSubClient::setKeepAlive(keepAlive)`.
- The client uses MQTT 3.1.1 by default. It can be changed to use MQTT 3.1 by
changing value of `MQTT_VERSION` in `PubSubClient.h`.

View File

@ -27,9 +27,9 @@ void setup()
{
Ethernet.begin(mac, ip);
// Note - the default maximum packet size is 128 bytes. If the
// combined length of clientId, username and password exceed this,
// you will need to increase the value of MQTT_MAX_PACKET_SIZE in
// PubSubClient.h
// combined length of clientId, username and password exceed this use the
// following to increase the buffer size:
// client.setBufferSize(255);
if (client.connect("arduinoClient", "testuser", "testpass")) {
client.publish("outTopic","hello world");

View File

@ -1,26 +1,21 @@
/*
Basic ESP8266 MQTT example
This sketch demonstrates the capabilities of the pubsub library in combination
with the ESP8266 board/library.
It connects to an MQTT server then:
- publishes "hello world" to the topic "outTopic" every two seconds
- subscribes to the topic "inTopic", printing out any messages
it receives. NB - it assumes the received payloads are strings not binary
- If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
else switch it off
It will reconnect to the server if the connection is lost using a blocking
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
achieve the same result without blocking the main loop.
To install the ESP8266 board, (using Arduino 1.6.4+):
- Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
http://arduino.esp8266.com/stable/package_esp8266com_index.json
- Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
- Select your ESP8266 in "Tools -> Board"
*/
#include <ESP8266WiFi.h>
@ -34,8 +29,9 @@ const char* mqtt_server = "broker.mqtt-dashboard.com";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
void setup_wifi() {
@ -46,6 +42,7 @@ void setup_wifi() {
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
@ -120,11 +117,11 @@ void loop() {
}
client.loop();
long now = millis();
unsigned long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf (msg, 50, "hello world #%ld", value);
snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);

View File

@ -27,6 +27,9 @@ setServer KEYWORD2
setCallback KEYWORD2
setClient KEYWORD2
setStream KEYWORD2
setKeepAlive KEYWORD2
setBufferSize KEYWORD2
setSocketTimeout KEYWORD2
#######################################
# Constants (LITERAL1)

View File

@ -6,9 +6,13 @@
"type": "git",
"url": "https://github.com/knolleary/pubsubclient.git"
},
"version": "2.7",
"version": "2.8",
"exclude": "tests",
"examples": "examples/*/*.ino",
"frameworks": "arduino",
"platforms": ["espressif8266", "espressif32"]
"platforms": [
"atmelavr",
"espressif8266",
"espressif32"
]
}

View File

@ -1,5 +1,5 @@
name=PubSubClient
version=2.7
version=2.8
author=Nick O'Leary <nick.oleary@gmail.com>
maintainer=Nick O'Leary <nick.oleary@gmail.com>
sentence=A client library for MQTT messaging.

View File

@ -12,12 +12,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 +33,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 +54,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 +65,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 +76,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 +97,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 +108,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 +119,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 +140,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,6 +151,14 @@ 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) {
@ -121,18 +181,29 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
if (!connected()) {
int result = 0;
// Start Tasmota patch
if (_client == nullptr) {
return false;
}
if (_client->connected()) {
// End Tasmota patch
if(_client->connected()) {
result = 1;
} else {
// Start Tasmota patch
// if (domain != NULL) {
// result = _client->connect(this->domain, this->port);
if (domain.length() != 0) {
result = _client->connect(this->domain.c_str(), this->port);
// End Tasmota patch
} else {
result = _client->connect(this->ip, this->port);
}
}
if (result == 1) {
nextMsgId = 1;
// Leave room in the buffer for header and variable length field
@ -147,7 +218,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
#define MQTT_HEADER_VERSION_LENGTH 7
#endif
for (j = 0;j<MQTT_HEADER_VERSION_LENGTH;j++) {
buffer[length++] = d[j];
this->buffer[length++] = d[j];
}
uint8_t v;
@ -167,45 +238,48 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
v = v|(0x80>>1);
}
}
this->buffer[length++] = v;
buffer[length++] = v;
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
this->buffer[length++] = ((this->keepAlive) >> 8);
this->buffer[length++] = ((this->keepAlive) & 0xFF);
CHECK_STRING_LENGTH(length,id)
length = writeString(id,buffer,length);
length = writeString(id,this->buffer,length);
if (willTopic) {
CHECK_STRING_LENGTH(length,willTopic)
length = writeString(willTopic,buffer,length);
length = writeString(willTopic,this->buffer,length);
CHECK_STRING_LENGTH(length,willMessage)
length = writeString(willMessage,buffer,length);
length = writeString(willMessage,this->buffer,length);
}
if(user != NULL) {
CHECK_STRING_LENGTH(length,user)
length = writeString(user,buffer,length);
length = writeString(user,this->buffer,length);
if(pass != NULL) {
CHECK_STRING_LENGTH(length,pass)
length = writeString(pass,buffer,length);
length = writeString(pass,this->buffer,length);
}
}
write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE);
write(MQTTCONNECT,this->buffer,length-MQTT_MAX_HEADER_SIZE);
lastInActivity = lastOutActivity = millis();
while (!_client->available()) {
// Start Tasmota patch
delay(0); // Prevent watchdog crashes
// End Tasmota patch
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) {
@ -228,14 +302,24 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
// reads a byte into result
boolean PubSubClient::readByte(uint8_t * result) {
// Start Tasmota patch
if (_client == nullptr) {
return false;
}
// End Tasmota patch
uint32_t previousMillis = millis();
while(!_client->available()) {
// Start Tasmota patch
// yield();
delay(1); // Prevent watchdog crashes
// End Tasmota patch
uint32_t currentMillis = millis();
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
if(currentMillis - previousMillis >= ((int32_t) this->socketTimeout * 1000)){
return false;
}
}
@ -254,15 +338,15 @@ 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) {
@ -272,59 +356,75 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
return 0;
}
if(!readByte(&digit)) return 0;
buffer[len++] = digit;
this->buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
} while ((digit & 128) != 0 && len < (MQTT_MAX_PACKET_SIZE -2));
multiplier <<=7; //multiplier *= 128
// Start Tasmota patch
// } while ((digit & 128) != 0);
} while ((digit & 128) != 0 && len < (this->bufferSize -2));
// End Tasmota patch
*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;i<length;i++) {
for (uint32_t i = start;i<length;i++) {
if(!readByte(&digit)) return 0;
if (this->stream) {
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++;
}
if (!this->stream && len > MQTT_MAX_PACKET_SIZE) {
len = 0; // This will cause the packet to be ignored.
idx++;
}
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;
if (_client->write(buffer,2) != 0) {
this->buffer[0] = MQTTPINGREQ;
this->buffer[1] = 0;
// Start Tasmota patch
// _client->write(this->buffer,2);
// lastOutActivity = t;
// lastInActivity = t;
if (_client->write(this->buffer,2) != 0) {
lastOutActivity = t;
lastInActivity = t;
}
// End Tasmota patch
pingOutstanding = true;
}
}
@ -335,35 +435,42 @@ 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]; /* topic length in bytes */
memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */
buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */
char *topic = (char*) buffer+llen+2;
uint16_t tl = (this->buffer[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);
if (_client->write(buffer,4) != 0) {
this->buffer[0] = MQTTPUBACK;
this->buffer[1] = 2;
this->buffer[2] = (msgId >> 8);
this->buffer[3] = (msgId & 0xFF);
// Start Tasmota patch
// _client->write(this->buffer,4);
// lastOutActivity = t;
if (_client->write(this->buffer,4) != 0) {
lastOutActivity = t;
}
// End Tasmota patch
} 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;
}
@ -378,13 +485,11 @@ boolean PubSubClient::loop() {
}
boolean PubSubClient::publish(const char* topic, const char* payload) {
size_t plength = (payload != nullptr) ? strlen(payload) : 0;
return publish(topic,(const uint8_t*)payload,plength,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) {
size_t plength = (payload != nullptr) ? strlen(payload) : 0;
return publish(topic,(const uint8_t*)payload,plength,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) {
@ -393,29 +498,32 @@ 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 < MQTT_MAX_HEADER_SIZE + 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 = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,buffer,length);
length = writeString(topic,this->buffer,length);
// Add payload
uint16_t i;
for (i=0;i<plength;i++) {
buffer[length++] = payload[i];
this->buffer[length++] = payload[i];
}
// Write the header
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
return write(header,buffer,length-MQTT_MAX_HEADER_SIZE);
return write(header,this->buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) {
size_t plength = (payload != nullptr) ? strlen(payload) : 0;
return publish_P(topic, (const uint8_t*)payload, plength, 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) {
@ -427,42 +535,48 @@ 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;i<plength;i++) {
rc += _client->write((char)pgm_read_byte_near(payload + i));
}
// Start Tasmota patch
// lastOutActivity = millis();
if (rc > 0) {
lastOutActivity = millis();
}
// End Tasmota patch
expectedLength = 1 + llen + 2 + tlen + plength;
// Header (1 byte) + llen + identifier (2 bytes) + topic len + payload len
const unsigned int expectedLength = 1 + llen + 2 + tlen + plength;
return (rc == expectedLength);
}
@ -470,16 +584,22 @@ boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, bool
if (connected()) {
// Send the header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,buffer,length);
length = writeString(topic,this->buffer,length);
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
size_t hlen = buildHeader(header, buffer, plength+length-MQTT_MAX_HEADER_SIZE);
uint16_t rc = _client->write(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen));
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));
// Start Tasmota patch
// lastOutActivity = millis();
if (rc > 0) {
lastOutActivity = millis();
}
// End Tasmota patch
return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen)));
}
return false;
@ -490,6 +610,11 @@ int PubSubClient::endPublish() {
}
size_t PubSubClient::write(uint8_t data) {
// Start Tasmota patch
// lastOutActivity = millis();
// return _client->write(data);
if (_client == nullptr) {
lastOutActivity = millis();
return 0;
@ -499,9 +624,16 @@ size_t PubSubClient::write(uint8_t data) {
lastOutActivity = millis();
}
return rc;
// End Tasmota patch
}
size_t PubSubClient::write(const uint8_t *buffer, size_t size) {
// Start Tasmota patch
// lastOutActivity = millis();
// return _client->write(buffer,size);
if (_client == nullptr) {
lastOutActivity = millis();
return 0;
@ -511,6 +643,8 @@ size_t PubSubClient::write(const uint8_t *buffer, size_t size) {
lastOutActivity = millis();
}
return rc;
// End Tasmota patch
}
size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) {
@ -520,8 +654,9 @@ size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length)
uint8_t pos = 0;
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;
}
@ -546,7 +681,6 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
uint8_t bytesToWrite;
boolean result = true;
while((bytesRemaining > 0) && result) {
delay(0); // Prevent watchdog crashes
bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining;
rc = _client->write(writeBuf,bytesToWrite);
result = (rc == bytesToWrite);
@ -556,9 +690,15 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
return result;
#else
rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen);
// Start Tasmota patch
// lastOutActivity = millis();
if (rc != 0) {
lastOutActivity = millis();
}
// End Tasmota patch
return (rc == hlen+length);
#endif
}
@ -568,10 +708,14 @@ boolean PubSubClient::subscribe(const char* topic) {
}
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
size_t topicLength = strnlen(topic, this->bufferSize);
if (topic == 0) {
return false;
}
if (qos > 1) {
return false;
}
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
if (this->bufferSize < 9 + topicLength) {
// Too long
return false;
}
@ -582,17 +726,21 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
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-MQTT_MAX_HEADER_SIZE);
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;
}
@ -602,25 +750,34 @@ boolean PubSubClient::unsubscribe(const char* topic) {
if (nextMsgId == 0) {
nextMsgId = 1;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, buffer,length);
return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
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(bool disconnect_package) {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
this->buffer[0] = MQTTDISCONNECT;
this->buffer[1] = 0;
// Start Tasmota patch
// _client->write(this->buffer,2);
// _state = MQTT_DISCONNECTED;
// _client->flush();
// _client->stop();
if (_client != nullptr) {
if (disconnect_package) {
_client->write(buffer,2);
_client->write(this->buffer,2);
}
_client->flush();
_client->stop();
}
_state = MQTT_DISCONNECTED;
// End Tasmota patch
lastInActivity = lastOutActivity = millis();
}
@ -628,7 +785,7 @@ uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t po
const char* idp = string;
uint16_t i = 0;
pos += 2;
while (*idp && pos < (MQTT_MAX_PACKET_SIZE - 2)) {
while (*idp) {
buf[pos++] = *idp++;
i++;
}
@ -639,19 +796,27 @@ uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t po
boolean PubSubClient::connected() {
boolean rc;
if (_client == NULL ) {
// Start Tasmota patch
this->_state = MQTT_DISCONNECTED;
return false;
}
if (_client->connected() == 0) {
bool lastStateConnected = this->_state == MQTT_CONNECTED;
this->disconnect();
if (lastStateConnected) {
// End Tasmota patch
rc = false;
} else {
rc = (int)_client->connected();
if (!rc) {
if (this->_state == MQTT_CONNECTED) {
this->_state = MQTT_CONNECTION_LOST;
_client->flush();
_client->stop();
}
return false;
}
} else {
return this->_state == MQTT_CONNECTED;
}
}
return rc;
}
PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) {
@ -662,7 +827,13 @@ PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) {
PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) {
this->ip = ip;
this->port = port;
// Start Tasmota patch
// this->domain = NULL;
this->domain = "";
// End Tasmota patch
return *this;
}
@ -690,3 +861,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;
}

View File

@ -21,24 +21,20 @@
#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 128
//#define MQTT_MAX_PACKET_SIZE 1000 // Tasmota v5.11.1c
//#define MQTT_MAX_PACKET_SIZE 256
#define MQTT_MAX_PACKET_SIZE 1200 // Tasmota v8.1.0.8
#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds
// Keepalive timeout for default MQTT Broker is 10s
// MQTT_KEEPALIVE : keepAlive interval in Seconds. Override with setKeepAlive()
#ifndef MQTT_KEEPALIVE
//#define MQTT_KEEPALIVE 10
#define MQTT_KEEPALIVE 30 // Tasmota v6.5.0.14 enabling AWS-iot
#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
#define MQTT_SOCKET_TIMEOUT 4 // Tasmota 20210120
#define MQTT_SOCKET_TIMEOUT 15
#endif
// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client
@ -88,18 +84,21 @@
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
#endif
#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
#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);
@ -110,7 +109,13 @@ private:
// (MQTT_MAX_HEADER_SIZE - <returned size>) bytes into the buffer
size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
IPAddress ip;
// Start Tasmota patch
// const char* domain;
String domain;
// End Tasmota patch
uint16_t port;
Stream* stream;
int _state;
@ -129,7 +134,8 @@ public:
PubSubClient(const char*, uint16_t, Client& client, Stream&);
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
virtual ~PubSubClient() {}
~PubSubClient();
PubSubClient& setServer(IPAddress ip, uint16_t port);
PubSubClient& setServer(uint8_t * ip, uint16_t port);
@ -137,13 +143,24 @@ public:
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);
// Start Tasmota patch
// void disconnect();
void disconnect(bool disconnect_package = false);
// End Tasmota patch
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);
@ -173,6 +190,7 @@ public:
boolean loop();
boolean connected();
int state();
};

View File

@ -280,6 +280,38 @@ int test_connect_disconnect_connect() {
END_IT
}
int test_connect_custom_keepalive() {
IT("sends a properly formatted connect packet with custom keepalive value");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte expectServer[] = { 172, 16, 0, 2 };
shimClient.expectConnect(expectServer,1883);
// Set keepalive to 300secs == 0x01 0x2c
byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x01,0x2c,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
shimClient.expect(connect,26);
shimClient.respond(connack,4);
PubSubClient client(server, 1883, callback, shimClient);
int state = client.state();
IS_TRUE(state == MQTT_DISCONNECTED);
client.setKeepAlive(300);
int rc = client.connect((char*)"client_test1");
IS_TRUE(rc);
IS_FALSE(shimClient.error());
state = client.state();
IS_TRUE(state == MQTT_CONNECTED);
END_IT
}
int main()
{
SUITE("Connect");
@ -298,5 +330,7 @@ int main()
test_connect_with_will();
test_connect_with_will_username_password();
test_connect_disconnect_connect();
test_connect_custom_keepalive();
FINISH
}

View File

@ -5,7 +5,7 @@
class Buffer {
private:
uint8_t buffer[1024];
uint8_t buffer[2048];
uint16_t pos;
uint16_t length;

View File

@ -134,6 +134,7 @@ int test_publish_too_long() {
shimClient.respond(connack,4);
PubSubClient client(server, 1883, callback, shimClient);
client.setBufferSize(128);
int rc = client.connect((char*)"client_test1");
IS_TRUE(rc);

View File

@ -20,6 +20,7 @@ void reset_callback() {
}
void callback(char* topic, byte* payload, unsigned int length) {
TRACE("Callback received topic=[" << topic << "] length=" << length << "\n")
callback_called = true;
strcpy(lastTopic,topic);
memcpy(lastPayload,payload,length);
@ -102,10 +103,15 @@ int test_receive_max_sized_message() {
shimClient.respond(connack,4);
PubSubClient client(server, 1883, callback, shimClient);
int length = 80; // If this is changed to > 128 then the publish packet below
// is no longer valid as it assumes the remaining length
// is a single-byte. Don't make that mistake like I just
// did and lose a whole evening tracking down the issue.
client.setBufferSize(length);
int rc = client.connect((char*)"client_test1");
IS_TRUE(rc);
int length = MQTT_MAX_PACKET_SIZE;
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
byte bigPublish[length];
memset(bigPublish,'A',length);
@ -137,11 +143,13 @@ int test_receive_oversized_message() {
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
shimClient.respond(connack,4);
int length = 80; // See comment in test_receive_max_sized_message before changing this value
PubSubClient client(server, 1883, callback, shimClient);
client.setBufferSize(length-1);
int rc = client.connect((char*)"client_test1");
IS_TRUE(rc);
int length = MQTT_MAX_PACKET_SIZE+1;
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
byte bigPublish[length];
memset(bigPublish,'A',length);
@ -188,9 +196,58 @@ int test_drop_invalid_remaining_length_message() {
END_IT
}
int test_resize_buffer() {
IT("receives a message larger than the default maximum");
reset_callback();
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
shimClient.respond(connack,4);
int length = 80; // See comment in test_receive_max_sized_message before changing this value
PubSubClient client(server, 1883, callback, shimClient);
client.setBufferSize(length-1);
int rc = client.connect((char*)"client_test1");
IS_TRUE(rc);
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
byte bigPublish[length];
memset(bigPublish,'A',length);
bigPublish[length] = 'B';
memcpy(bigPublish,publish,16);
// Send it twice
shimClient.respond(bigPublish,length);
shimClient.respond(bigPublish,length);
rc = client.loop();
IS_TRUE(rc);
// First message fails as it is too big
IS_FALSE(callback_called);
// Resize the buffer
client.setBufferSize(length);
rc = client.loop();
IS_TRUE(rc);
IS_TRUE(callback_called);
IS_TRUE(strcmp(lastTopic,"topic")==0);
IS_TRUE(lastLength == length-9);
IS_TRUE(memcmp(lastPayload,bigPublish+9,lastLength)==0);
IS_FALSE(shimClient.error());
END_IT
}
int test_receive_oversized_stream_message() {
IT("drops an oversized message");
IT("receive an oversized streamed message");
reset_callback();
Stream stream;
@ -201,11 +258,13 @@ int test_receive_oversized_stream_message() {
byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
shimClient.respond(connack,4);
int length = 80; // See comment in test_receive_max_sized_message before changing this value
PubSubClient client(server, 1883, callback, shimClient, stream);
client.setBufferSize(length-1);
int rc = client.connect((char*)"client_test1");
IS_TRUE(rc);
int length = MQTT_MAX_PACKET_SIZE+1;
byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
byte bigPublish[length];
@ -222,7 +281,8 @@ int test_receive_oversized_stream_message() {
IS_TRUE(callback_called);
IS_TRUE(strcmp(lastTopic,"topic")==0);
IS_TRUE(lastLength == length-9);
IS_TRUE(lastLength == length-10);
IS_FALSE(stream.error());
IS_FALSE(shimClient.error());
@ -272,6 +332,7 @@ int main()
test_receive_max_sized_message();
test_drop_invalid_remaining_length_message();
test_receive_oversized_message();
test_resize_buffer();
test_receive_oversized_stream_message();
test_receive_qos1();

View File

@ -106,6 +106,7 @@ int test_subscribe_too_long() {
shimClient.respond(connack,4);
PubSubClient client(server, 1883, callback, shimClient);
client.setBufferSize(128);
int rc = client.connect((char*)"client_test1");
IS_TRUE(rc);

View File

@ -366,6 +366,8 @@
#define D_CMND_MQTTCLIENT "MqttClient"
#define D_CMND_MQTTUSER "MqttUser"
#define D_CMND_MQTTPASSWORD "MqttPassword"
#define D_CMND_MQTTKEEPALIVE "MqttKeepAlive"
#define D_CMND_MQTTTIMEOUT "MqttTimeout"
#define D_CMND_TLSKEY "TLSKey"
#define D_CMND_FULLTOPIC "FullTopic"
#define D_CMND_PREFIX "Prefix"

View File

@ -101,6 +101,9 @@
// -- MQTT ----------------------------------------
#define MQTT_USE true // [SetOption3] Select default MQTT use (false = Off, true = On)
#define MQTT_KEEPALIVE 30 // [MqttKeepAlive]
#define MQTT_SOCKET_TIMEOUT 4 // [MqttTimeout]
#define MQTT_HOST "" // [MqttHost]
#define MQTT_FINGERPRINT1 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 // [MqttFingerprint1] (auto-learn)
#define MQTT_FINGERPRINT2 0xDA,0x39,0xA3,0xEE,0x5E,0x6B,0x4B,0x0D,0x32,0x55,0xBF,0xEF,0x95,0x60,0x18,0x90,0xAF,0xD8,0x07,0x09 // [MqttFingerprint2] (invalid)

View File

@ -488,7 +488,12 @@ struct {
power_t interlock[MAX_INTERLOCKS_SET]; // 4D0 MAX_INTERLOCKS = MAX_RELAYS / 2
uint8_t free_508[41]; // 508
uint8_t free_508[36]; // 508
uint16_t mqtt_keepalive; // 52C
uint16_t mqtt_socket_timeout; // 52E
uint8_t free_530[1]; // 530
uint8_t ina219_mode; // 531
uint16_t pulse_timer[MAX_PULSETIMERS]; // 532

View File

@ -864,6 +864,8 @@ void SettingsDefaultSet2(void) {
memcpy_P(Settings.mqtt_fingerprint[1], default_fingerprint2, sizeof(default_fingerprint2));
Settings.tele_period = TELE_PERIOD;
Settings.mqttlog_level = MQTT_LOG_LEVEL;
Settings.mqtt_keepalive = MQTT_KEEPALIVE;
Settings.mqtt_socket_timeout = MQTT_SOCKET_TIMEOUT;
// Energy
flag.no_power_on_check |= ENERGY_VOLTAGE_ALWAYS;
@ -1244,6 +1246,10 @@ void SettingsDelta(void) {
if (Settings.version < 0x09020007) {
*(uint32_t *)&Settings.device_group_tie = 0x04030201;
}
if (Settings.version < 0x09030102) {
Settings.mqtt_keepalive = MQTT_KEEPALIVE;
Settings.mqtt_socket_timeout = MQTT_SOCKET_TIMEOUT;
}
Settings.version = VERSION;
SettingsSave(1);

View File

@ -2125,7 +2125,7 @@ void SyslogAsync(bool refresh) {
static uint32_t syslog_host_hash = 0; // Syslog host name hash
static uint32_t index = 1;
if (!TasmotaGlobal.syslog_level) { return; }
if (!TasmotaGlobal.syslog_level || TasmotaGlobal.global_state.network_down) { return; }
if (refresh && !NeedLogRefresh(TasmotaGlobal.syslog_level, index)) { return; }
char* line;
@ -2137,8 +2137,16 @@ void SyslogAsync(bool refresh) {
if (mxtime > 0) {
uint32_t current_hash = GetHash(SettingsText(SET_SYSLOG_HOST), strlen(SettingsText(SET_SYSLOG_HOST)));
if (syslog_host_hash != current_hash) {
IPAddress temp_syslog_host_addr;
int ok = WiFi.hostByName(SettingsText(SET_SYSLOG_HOST), temp_syslog_host_addr); // If sleep enabled this might result in exception so try to do it once using hash
if (!ok || (0xFFFFFFFF == (uint32_t)temp_syslog_host_addr)) { // 255.255.255.255 is assumed a DNS problem
TasmotaGlobal.syslog_level = 0;
TasmotaGlobal.syslog_timer = SYSLOG_TIMER;
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION "Loghost DNS resolve failed (%s). " D_RETRY_IN " %d " D_UNIT_SECOND), SettingsText(SET_SYSLOG_HOST), SYSLOG_TIMER);
return;
}
syslog_host_hash = current_hash;
WiFi.hostByName(SettingsText(SET_SYSLOG_HOST), syslog_host_addr); // If sleep enabled this might result in exception so try to do it once using hash
syslog_host_addr = temp_syslog_host_addr;
}
if (!PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) {
TasmotaGlobal.syslog_level = 0;

View File

@ -529,9 +529,9 @@ void CmndStatus(void)
if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\""
D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"),
D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d,\"SOCKET_TIMEOUT\":%d}}"),
SettingsText(SET_MQTT_HOST), Settings.mqtt_port, EscapeJSONString(SettingsText(SET_MQTT_CLIENT)).c_str(),
TasmotaGlobal.mqtt_client, EscapeJSONString(SettingsText(SET_MQTT_USER)).c_str(), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
TasmotaGlobal.mqtt_client, EscapeJSONString(SettingsText(SET_MQTT_USER)).c_str(), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, Settings.mqtt_keepalive, Settings.mqtt_socket_timeout);
MqttPublishPrefixTopic_P(STAT, PSTR(D_CMND_STATUS "6"));
}

View File

@ -270,8 +270,8 @@ const uint16_t LOG_BUFFER_SIZE = 4000; // Max number of characters in lo
#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 30 // Seconds
#endif
#ifndef MQTT_TIMEOUT
#define MQTT_TIMEOUT 10000 // milli seconds
#ifndef MQTT_SOCKET_TIMEOUT
#define MQTT_SOCKET_TIMEOUT 4 // Seconds
#endif
#ifndef MQTT_CLEAN_SESSION
#define MQTT_CLEAN_SESSION 1 // 0 = No clean session, 1 = Clean session (default)

View File

@ -20,6 +20,6 @@
#ifndef _TASMOTA_VERSION_H_
#define _TASMOTA_VERSION_H_
const uint32_t VERSION = 0x09030101;
const uint32_t VERSION = 0x09030102;
#endif // _TASMOTA_VERSION_H_

View File

@ -23,6 +23,8 @@
#define MQTT_WIFI_CLIENT_TIMEOUT 200 // Wifi TCP connection timeout (default is 5000 mSec)
#endif
#define USE_MQTT_NEW_PUBSUBCLIENT
// #define DEBUG_DUMP_TLS // allow dumping of TLS Flash keys
#ifdef USE_MQTT_TLS
@ -42,7 +44,7 @@ const char kMqttCommands[] PROGMEM = "|" // No prefix
#if defined(USE_MQTT_TLS) && !defined(USE_MQTT_TLS_CA_CERT)
D_CMND_MQTTFINGERPRINT "|"
#endif
D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|"
D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|" D_CMND_MQTTKEEPALIVE "|" D_CMND_MQTTTIMEOUT "|"
#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT)
D_CMND_TLSKEY "|"
#endif
@ -68,7 +70,7 @@ void (* const MqttCommand[])(void) PROGMEM = {
#if defined(USE_MQTT_TLS) && !defined(USE_MQTT_TLS_CA_CERT)
&CmndMqttFingerprint,
#endif
&CmndMqttUser, &CmndMqttPassword,
&CmndMqttUser, &CmndMqttPassword, &CmndMqttKeepAlive, &CmndMqttTimeout,
#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT)
&CmndTlsKey,
#endif
@ -209,6 +211,9 @@ void MqttInit(void) {
#else // USE_MQTT_TLS
MqttClient.setClient(EspClient);
#endif // USE_MQTT_TLS
MqttClient.setKeepAlive(Settings.mqtt_keepalive);
MqttClient.setSocketTimeout(Settings.mqtt_socket_timeout);
}
bool MqttIsConnected(void) {
@ -311,7 +316,7 @@ void MqttUnsubscribe(const char *topic) {
void MqttPublishLoggingAsync(bool refresh) {
static uint32_t index = 1;
if (!Settings.mqttlog_level || !Settings.flag.mqtt_enabled) { return; } // SetOption3 - Enable MQTT
if (!Settings.mqttlog_level || !Settings.flag.mqtt_enabled || !Mqtt.connected) { return; } // SetOption3 - Enable MQTT
if (refresh && !NeedLogRefresh(Settings.mqttlog_level, index)) { return; }
char* line;
@ -829,6 +834,26 @@ void CmndMqttPassword(void) {
}
}
void CmndMqttKeepAlive(void) {
if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 100)) {
Settings.mqtt_keepalive = XdrvMailbox.payload;
#ifdef USE_MQTT_NEW_PUBSUBCLIENT
MqttClient.setKeepAlive(Settings.mqtt_keepalive);
#endif
}
ResponseCmndNumber(Settings.mqtt_keepalive);
}
void CmndMqttTimeout(void) {
if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 100)) {
Settings.mqtt_socket_timeout = XdrvMailbox.payload;
#ifdef USE_MQTT_NEW_PUBSUBCLIENT
MqttClient.setSocketTimeout(Settings.mqtt_socket_timeout);
#endif
}
ResponseCmndNumber(Settings.mqtt_socket_timeout);
}
void CmndMqttlog(void) {
if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) {
Settings.mqttlog_level = XdrvMailbox.payload;

View File

@ -57,6 +57,7 @@ String FormatMetricName(const char *metric) { // cleanup spaces and uppercases
String formatted = metric;
formatted.toLowerCase();
formatted.replace(" ", "_");
formatted.replace(".", "_");
return formatted;
}