diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py deleted file mode 100644 index 1b0cc65bb..000000000 --- a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py +++ /dev/null @@ -1,43 +0,0 @@ -import unittest -import settings - -import time -import mosquitto - -import serial - -def on_message(mosq, obj, msg): - obj.message_queue.append(msg) - -class mqtt_basic(unittest.TestCase): - - message_queue = [] - - @classmethod - def setUpClass(self): - self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self) - self.client.connect(settings.server_ip) - self.client.on_message = on_message - self.client.subscribe("outTopic",0) - - @classmethod - def tearDownClass(self): - self.client.disconnect() - - def test_one(self): - i=30 - while len(self.message_queue) == 0 and i > 0: - self.client.loop() - time.sleep(0.5) - i -= 1 - self.assertTrue(i>0, "message receive timed-out") - self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") - msg = self.message_queue[0] - self.assertEqual(msg.mid,0,"message id not 0") - self.assertEqual(msg.topic,"outTopic","message topic incorrect") - self.assertEqual(msg.payload,"hello world") - self.assertEqual(msg.qos,0,"message qos not 0") - self.assertEqual(msg.retain,False,"message retain flag incorrect") - - - diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py deleted file mode 100644 index 7989f7f17..000000000 --- a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py +++ /dev/null @@ -1,64 +0,0 @@ -import unittest -import settings - -import time -import mosquitto - -import serial - -def on_message(mosq, obj, msg): - obj.message_queue.append(msg) - -class mqtt_publish_in_callback(unittest.TestCase): - - message_queue = [] - - @classmethod - def setUpClass(self): - self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self) - self.client.connect(settings.server_ip) - self.client.on_message = on_message - self.client.subscribe("outTopic",0) - - @classmethod - def tearDownClass(self): - self.client.disconnect() - - def test_connect(self): - i=30 - while len(self.message_queue) == 0 and i > 0: - self.client.loop() - time.sleep(0.5) - i -= 1 - self.assertTrue(i>0, "message receive timed-out") - self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") - msg = self.message_queue.pop(0) - self.assertEqual(msg.mid,0,"message id not 0") - self.assertEqual(msg.topic,"outTopic","message topic incorrect") - self.assertEqual(msg.payload,"hello world") - self.assertEqual(msg.qos,0,"message qos not 0") - self.assertEqual(msg.retain,False,"message retain flag incorrect") - - - def test_publish(self): - self.assertEqual(len(self.message_queue), 0, "message queue not empty") - payload = "abcdefghij" - self.client.publish("inTopic",payload) - - i=30 - while len(self.message_queue) == 0 and i > 0: - self.client.loop() - time.sleep(0.5) - i -= 1 - - self.assertTrue(i>0, "message receive timed-out") - self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") - msg = self.message_queue.pop(0) - self.assertEqual(msg.mid,0,"message id not 0") - self.assertEqual(msg.topic,"outTopic","message topic incorrect") - self.assertEqual(msg.payload,payload) - self.assertEqual(msg.qos,0,"message qos not 0") - self.assertEqual(msg.retain,False,"message retain flag incorrect") - - - diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py deleted file mode 100644 index 0a8e70dfd..000000000 --- a/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py +++ /dev/null @@ -1,179 +0,0 @@ -#!/usr/bin/env python -import os -import os.path -import sys -import shutil -from subprocess import call -import importlib -import unittest -import re - -from testcases import settings - -class Workspace(object): - - def __init__(self): - self.root_dir = os.getcwd() - self.build_dir = os.path.join(self.root_dir,"tmpbin"); - self.log_dir = os.path.join(self.root_dir,"logs"); - self.tests_dir = os.path.join(self.root_dir,"testcases"); - self.examples_dir = os.path.join(self.root_dir,"../PubSubClient/examples") - self.examples = [] - self.tests = [] - if not os.path.isdir("../PubSubClient"): - raise Exception("Cannot find PubSubClient library") - try: - import ino - except: - raise Exception("ino tool not installed") - - def init(self): - if os.path.isdir(self.build_dir): - shutil.rmtree(self.build_dir) - os.mkdir(self.build_dir) - if os.path.isdir(self.log_dir): - shutil.rmtree(self.log_dir) - os.mkdir(self.log_dir) - - os.chdir(self.build_dir) - call(["ino","init"]) - - shutil.copytree("../../PubSubClient","lib/PubSubClient") - - filenames = [] - for root, dirs, files in os.walk(self.examples_dir): - filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")] - filenames.sort() - for e in filenames: - self.examples.append(Sketch(self,e)) - - filenames = [] - for root, dirs, files in os.walk(self.tests_dir): - filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")] - filenames.sort() - for e in filenames: - self.tests.append(Sketch(self,e)) - - def clean(self): - shutil.rmtree(self.build_dir) - -class Sketch(object): - def __init__(self,wksp,fn): - self.w = wksp - self.filename = fn - self.basename = os.path.basename(self.filename) - self.build_log = os.path.join(self.w.log_dir,"%s.log"%(os.path.basename(self.filename),)) - self.build_err_log = os.path.join(self.w.log_dir,"%s.err.log"%(os.path.basename(self.filename),)) - self.build_upload_log = os.path.join(self.w.log_dir,"%s.upload.log"%(os.path.basename(self.filename),)) - - def build(self): - sys.stdout.write(" Build: ") - sys.stdout.flush() - - # Copy sketch over, replacing IP addresses as necessary - fin = open(self.filename,"r") - lines = fin.readlines() - fin.close() - fout = open(os.path.join(self.w.build_dir,"src","sketch.ino"),"w") - for l in lines: - if re.match(r"^byte server\[\] = {",l): - fout.write("byte server[] = { %s };\n"%(settings.server_ip.replace(".",", "),)) - elif re.match(r"^byte ip\[\] = {",l): - fout.write("byte ip[] = { %s };\n"%(settings.arduino_ip.replace(".",", "),)) - else: - fout.write(l) - fout.flush() - fout.close() - - # Run build - fout = open(self.build_log, "w") - ferr = open(self.build_err_log, "w") - rc = call(["ino","build"],stdout=fout,stderr=ferr) - fout.close() - ferr.close() - if rc == 0: - sys.stdout.write("pass") - sys.stdout.write("\n") - return True - else: - sys.stdout.write("fail") - sys.stdout.write("\n") - with open(self.build_err_log) as f: - for line in f: - print " ",line, - return False - - def upload(self): - sys.stdout.write(" Upload: ") - sys.stdout.flush() - fout = open(self.build_upload_log, "w") - rc = call(["ino","upload"],stdout=fout,stderr=fout) - fout.close() - if rc == 0: - sys.stdout.write("pass") - sys.stdout.write("\n") - return True - else: - sys.stdout.write("fail") - sys.stdout.write("\n") - with open(self.build_upload_log) as f: - for line in f: - print " ",line, - return False - - - def test(self): - # import the matching test case, if it exists - try: - basename = os.path.basename(self.filename)[:-4] - i = importlib.import_module("testcases."+basename) - except: - sys.stdout.write(" Test: no tests found") - sys.stdout.write("\n") - return - c = getattr(i,basename) - - testmethods = [m for m in dir(c) if m.startswith("test_")] - testmethods.sort() - tests = [] - for m in testmethods: - tests.append(c(m)) - - result = unittest.TestResult() - c.setUpClass() - if self.upload(): - sys.stdout.write(" Test: ") - sys.stdout.flush() - for t in tests: - t.run(result) - print "%d/%d"%(result.testsRun-len(result.failures)-len(result.errors),result.testsRun) - if not result.wasSuccessful(): - if len(result.failures) > 0: - for f in result.failures: - print "-- %s"%(str(f[0]),) - print f[1] - if len(result.errors) > 0: - print " Errors:" - for f in result.errors: - print "-- %s"%(str(f[0]),) - print f[1] - c.tearDownClass() - -if __name__ == '__main__': - run_tests = True - - w = Workspace() - w.init() - - for e in w.examples: - print "--------------------------------------" - print "[%s]"%(e.basename,) - if e.build() and run_tests: - e.test() - for e in w.tests: - print "--------------------------------------" - print "[%s]"%(e.basename,) - if e.build() and run_tests: - e.test() - - w.clean() diff --git a/lib/PubSubClient-EspEasy-2.6.09/.gitignore b/lib/PubSubClient-EspEasy-2.7.11/.gitignore similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/.gitignore rename to lib/PubSubClient-EspEasy-2.7.11/.gitignore diff --git a/lib/PubSubClient-EspEasy-2.6.09/.travis.yml b/lib/PubSubClient-EspEasy-2.7.11/.travis.yml similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/.travis.yml rename to lib/PubSubClient-EspEasy-2.7.11/.travis.yml diff --git a/lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt b/lib/PubSubClient-EspEasy-2.7.11/CHANGES.txt similarity index 86% rename from lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt rename to lib/PubSubClient-EspEasy-2.7.11/CHANGES.txt index 8c8bef64e..ff4da62ab 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt +++ b/lib/PubSubClient-EspEasy-2.7.11/CHANGES.txt @@ -1,8 +1,16 @@ +2.7 + * Fix remaining-length handling to prevent buffer overrun + * Add large-payload API - beginPublish/write/publish/endPublish + * Add yield call to improve reliability on ESP + * Add Clean Session flag to connect options + * Add ESP32 support for functional callback signature + * Various other fixes + 2.4 * Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely whilst waiting for inbound data * Fixed return code when publishing >256 bytes - + 2.3 * Add publish(topic,payload,retained) function diff --git a/lib/PubSubClient-EspEasy-2.6.09/LICENSE.txt b/lib/PubSubClient-EspEasy-2.7.11/LICENSE.txt similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/LICENSE.txt rename to lib/PubSubClient-EspEasy-2.7.11/LICENSE.txt diff --git a/lib/PubSubClient-EspEasy-2.6.09/README.md b/lib/PubSubClient-EspEasy-2.7.11/README.md similarity index 95% rename from lib/PubSubClient-EspEasy-2.6.09/README.md rename to lib/PubSubClient-EspEasy-2.7.11/README.md index 83176919c..69cbb8f0c 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/README.md +++ b/lib/PubSubClient-EspEasy-2.7.11/README.md @@ -8,7 +8,7 @@ a server that supports MQTT. The library comes with a number of example sketches. See File > Examples > PubSubClient within the Arduino application. -Full API documentation is available here: http://pubsubclient.knolleary.net +Full API documentation is available here: https://pubsubclient.knolleary.net ## Limitations @@ -37,6 +37,7 @@ boards and shields, including: - TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library) - Intel Galileo/Edison - ESP8266 + - ESP32 The library cannot currently be used with hardware based on the ENC28J60 chip – such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_auth/mqtt_auth.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_auth/mqtt_auth.ino similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_auth/mqtt_auth.ino rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_auth/mqtt_auth.ino diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_basic/mqtt_basic.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_basic/mqtt_basic.ino similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_basic/mqtt_basic.ino rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_basic/mqtt_basic.ino diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_esp8266/mqtt_esp8266.ino similarity index 92% rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_esp8266/mqtt_esp8266.ino index e46f85f3e..e7357b507 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -38,14 +38,6 @@ long lastMsg = 0; char msg[50]; int value = 0; -void setup() { - pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_server, 1883); - client.setCallback(callback); -} - void setup_wifi() { delay(10); @@ -61,6 +53,8 @@ void setup_wifi() { Serial.print("."); } + randomSeed(micros()); + Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); @@ -80,7 +74,7 @@ void callback(char* topic, byte* payload, unsigned int length) { if ((char)payload[0] == '1') { digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level // but actually the LED is on; this is because - // it is acive low on the ESP-01) + // it is active low on the ESP-01) } else { digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH } @@ -91,8 +85,11 @@ void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); + // Create a random client ID + String clientId = "ESP8266Client-"; + clientId += String(random(0xffff), HEX); // Attempt to connect - if (client.connect("ESP8266Client")) { + if (client.connect(clientId.c_str())) { Serial.println("connected"); // Once connected, publish an announcement... client.publish("outTopic", "hello world"); @@ -107,6 +104,15 @@ void reconnect() { } } } + +void setup() { + pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_server, 1883); + client.setCallback(callback); +} + void loop() { if (!client.connected()) { @@ -118,7 +124,7 @@ void loop() { if (now - lastMsg > 2000) { lastMsg = now; ++value; - snprintf (msg, 75, "hello world #%ld", value); + snprintf (msg, 50, "hello world #%ld", value); Serial.print("Publish message: "); Serial.println(msg); client.publish("outTopic", msg); diff --git a/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_large_message/mqtt_large_message.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_large_message/mqtt_large_message.ino new file mode 100644 index 000000000..e048c3ed3 --- /dev/null +++ b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_large_message/mqtt_large_message.ino @@ -0,0 +1,179 @@ +/* + Long message ESP8266 MQTT example + + This sketch demonstrates sending arbitrarily large messages in combination + with the ESP8266 board/library. + + It connects to an MQTT server then: + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "greenBottles/#", printing out any messages + it receives. NB - it assumes the received payloads are strings not binary + - If the sub-topic is a number, it publishes a "greenBottles/lyrics" message + with a payload consisting of the lyrics to "10 green bottles", replacing + 10 with the number given in the sub-topic. + + 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 +#include + +// Update these with values suitable for your network. + +const char* ssid = "........"; +const char* password = "........"; +const char* mqtt_server = "broker.mqtt-dashboard.com"; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +void setup_wifi() { + + delay(10); + // We start by connecting to a WiFi network + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(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()); +} + +void callback(char* topic, byte* payload, unsigned int length) { + Serial.print("Message arrived ["); + Serial.print(topic); + Serial.print("] "); + for (int i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } + Serial.println(); + + // Find out how many bottles we should generate lyrics for + String topicStr(topic); + int bottleCount = 0; // assume no bottles unless we correctly parse a value from the topic + if (topicStr.indexOf('/') >= 0) { + // The topic includes a '/', we'll try to read the number of bottles from just after that + topicStr.remove(0, topicStr.indexOf('/')+1); + // Now see if there's a number of bottles after the '/' + bottleCount = topicStr.toInt(); + } + + if (bottleCount > 0) { + // Work out how big our resulting message will be + int msgLen = 0; + for (int i = bottleCount; i > 0; i--) { + String numBottles(i); + msgLen += 2*numBottles.length(); + if (i == 1) { + msgLen += 2*String(" green bottle, standing on the wall\n").length(); + } else { + msgLen += 2*String(" green bottles, standing on the wall\n").length(); + } + msgLen += String("And if one green bottle should accidentally fall\nThere'll be ").length(); + switch (i) { + case 1: + msgLen += String("no green bottles, standing on the wall\n\n").length(); + break; + case 2: + msgLen += String("1 green bottle, standing on the wall\n\n").length(); + break; + default: + numBottles = i-1; + msgLen += numBottles.length(); + msgLen += String(" green bottles, standing on the wall\n\n").length(); + break; + }; + } + + // Now we can start to publish the message + client.beginPublish("greenBottles/lyrics", msgLen, false); + for (int i = bottleCount; i > 0; i--) { + for (int j = 0; j < 2; j++) { + client.print(i); + if (i == 1) { + client.print(" green bottle, standing on the wall\n"); + } else { + client.print(" green bottles, standing on the wall\n"); + } + } + client.print("And if one green bottle should accidentally fall\nThere'll be "); + switch (i) { + case 1: + client.print("no green bottles, standing on the wall\n\n"); + break; + case 2: + client.print("1 green bottle, standing on the wall\n\n"); + break; + default: + client.print(i-1); + client.print(" green bottles, standing on the wall\n\n"); + break; + }; + } + // Now we're done! + client.endPublish(); + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Create a random client ID + String clientId = "ESP8266Client-"; + clientId += String(random(0xffff), HEX); + // Attempt to connect + if (client.connect(clientId.c_str())) { + Serial.println("connected"); + // Once connected, publish an announcement... + client.publish("outTopic", "hello world"); + // ... and resubscribe + client.subscribe("greenBottles/#"); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void setup() { + pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_server, 1883); + client.setCallback(callback); +} + +void loop() { + + if (!client.connected()) { + reconnect(); + } + client.loop(); +} diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_stream/mqtt_stream.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_stream/mqtt_stream.ino similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_stream/mqtt_stream.ino rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_stream/mqtt_stream.ino diff --git a/lib/PubSubClient-EspEasy-2.6.09/keywords.txt b/lib/PubSubClient-EspEasy-2.7.11/keywords.txt similarity index 91% rename from lib/PubSubClient-EspEasy-2.6.09/keywords.txt rename to lib/PubSubClient-EspEasy-2.7.11/keywords.txt index b979588fe..1ee23d0fa 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/keywords.txt +++ b/lib/PubSubClient-EspEasy-2.7.11/keywords.txt @@ -16,6 +16,9 @@ connect KEYWORD2 disconnect KEYWORD2 publish KEYWORD2 publish_P KEYWORD2 +beginPublish KEYWORD2 +endPublish KEYWORD2 +write KEYWORD2 subscribe KEYWORD2 unsubscribe KEYWORD2 loop KEYWORD2 diff --git a/lib/PubSubClient-EspEasy-2.6.09/library.json b/lib/PubSubClient-EspEasy-2.7.11/library.json similarity index 97% rename from lib/PubSubClient-EspEasy-2.6.09/library.json rename to lib/PubSubClient-EspEasy-2.7.11/library.json index b96739078..8a36a1c5e 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/library.json +++ b/lib/PubSubClient-EspEasy-2.7.11/library.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://github.com/knolleary/pubsubclient.git" }, - "version": "2.6", + "version": "2.7", "exclude": "tests", "examples": "examples/*/*.ino", "frameworks": "arduino", diff --git a/lib/PubSubClient-EspEasy-2.6.09/library.properties b/lib/PubSubClient-EspEasy-2.7.11/library.properties similarity index 98% rename from lib/PubSubClient-EspEasy-2.6.09/library.properties rename to lib/PubSubClient-EspEasy-2.7.11/library.properties index 3ceeda81c..1ae97882e 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/library.properties +++ b/lib/PubSubClient-EspEasy-2.7.11/library.properties @@ -1,5 +1,5 @@ name=PubSubClient -version=2.6 +version=2.7 author=Nick O'Leary maintainer=Nick O'Leary sentence=A client library for MQTT messaging. diff --git a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp b/lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.cpp similarity index 79% rename from lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp rename to lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.cpp index 79eb2d52e..9fe15006a 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp +++ b/lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.cpp @@ -102,30 +102,41 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN } 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.length() != 0) { - result = _client->connect(this->domain.c_str(), this->port); + if (_client == nullptr) { + return false; + } + if (_client->connected()) { + result = 1; } else { - result = _client->connect(this->ip, this->port); + if (domain != NULL) { + result = _client->connect(this->domain.c_str(), 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 @@ -141,9 +152,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass 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) { @@ -158,24 +172,31 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass buffer[length++] = ((MQTT_KEEPALIVE) >> 8); buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); + + CHECK_STRING_LENGTH(length,id) length = writeString(id,buffer,length); if (willTopic) { + CHECK_STRING_LENGTH(length,willTopic) length = writeString(willTopic,buffer,length); + CHECK_STRING_LENGTH(length,willMessage) length = writeString(willMessage,buffer,length); } if(user != NULL) { + CHECK_STRING_LENGTH(length,user) length = writeString(user,buffer,length); if(pass != NULL) { + CHECK_STRING_LENGTH(length,pass) length = writeString(pass,buffer,length); } } - write(MQTTCONNECT,buffer,length-5); + write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE); lastInActivity = lastOutActivity = millis(); while (!_client->available()) { + delay(0); // Prevent watchdog crashes unsigned long t = millis(); if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) { _state = MQTT_CONNECTION_TIMEOUT; @@ -207,9 +228,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass // reads a byte into result boolean PubSubClient::readByte(uint8_t * result) { + if (_client == nullptr) { + return false; + } uint32_t previousMillis = millis(); while(!_client->available()) { - delay(1); // Add esp8266 de-blocking (Tasmota #790, EspEasy #1943) + delay(1); // Prevent watchdog crashes uint32_t currentMillis = millis(); if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){ return false; @@ -241,7 +265,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { uint8_t start = 0; do { - if (len == 6) { + if (len == 5) { // Invalid remaining length encoding - kill the connection _state = MQTT_DISCONNECTED; _client->stop(); @@ -353,11 +377,13 @@ boolean PubSubClient::loop() { } boolean PubSubClient::publish(const char* topic, const char* payload) { - return publish(topic,(const uint8_t*)payload,strlen(payload),false); + size_t plength = (payload != nullptr) ? strlen(payload) : 0; + return publish(topic,(const uint8_t*)payload,plength,false); } boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { - return publish(topic,(const uint8_t*)payload,strlen(payload),retained); + size_t plength = (payload != nullptr) ? strlen(payload) : 0; + return publish(topic,(const uint8_t*)payload,plength,retained); } boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { @@ -366,12 +392,12 @@ 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 (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) { // Too long return false; } // Leave room in the buffer for header and variable length field - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; length = writeString(topic,buffer,length); uint16_t i; for (i=0;iwrite(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(); + if (_client == nullptr) { + return 0; + } + return _client->write(data); +} + +size_t PubSubClient::write(const uint8_t *buffer, size_t size) { + lastOutActivity = millis(); + if (_client == nullptr) { + return 0; + } + 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; @@ -450,15 +519,22 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { buf[4-llen] = header; for (int i=0;i 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); @@ -467,9 +543,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 } @@ -487,7 +563,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { } 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; @@ -496,7 +572,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { buffer[length++] = (nextMsgId & 0xFF); length = writeString((char*)topic, buffer,length); buffer[length++] = qos; - return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); + return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } @@ -507,7 +583,7 @@ boolean PubSubClient::unsubscribe(const char* topic) { return false; } if (connected()) { - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; nextMsgId++; if (nextMsgId == 0) { nextMsgId = 1; @@ -515,7 +591,7 @@ boolean PubSubClient::unsubscribe(const char* topic) { buffer[length++] = (nextMsgId >> 8); buffer[length++] = (nextMsgId & 0xFF); length = writeString(topic, buffer,length); - return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); + return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } @@ -523,7 +599,7 @@ boolean PubSubClient::unsubscribe(const char* topic) { void PubSubClient::disconnect() { buffer[0] = MQTTDISCONNECT; buffer[1] = 0; - if (_client != NULL) { + if (_client != nullptr) { _client->write(buffer,2); _client->flush(); _client->stop(); @@ -558,6 +634,8 @@ boolean PubSubClient::connected() { _client->flush(); _client->stop(); } + } else { + return this->_state == MQTT_CONNECTED; } } return rc; diff --git a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h b/lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.h similarity index 76% rename from lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h rename to lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.h index 003df770e..a519f75d7 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h +++ b/lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.h @@ -75,6 +75,9 @@ #define MQTTQOS1 (1 << 1) #define MQTTQOS2 (2 << 1) +// 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 @@ -82,7 +85,9 @@ #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) #endif -class PubSubClient { +#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;} + +class PubSubClient : public Print { private: Client* _client; uint8_t buffer[MQTT_MAX_PACKET_SIZE]; @@ -96,6 +101,11 @@ private: 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; String domain; uint16_t port; @@ -129,12 +139,31 @@ public: 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); diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/.gitignore b/lib/PubSubClient-EspEasy-2.7.11/tests/.gitignore similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/.gitignore rename to lib/PubSubClient-EspEasy-2.7.11/tests/.gitignore diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/Makefile b/lib/PubSubClient-EspEasy-2.7.11/tests/Makefile similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/Makefile rename to lib/PubSubClient-EspEasy-2.7.11/tests/Makefile diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/README.md b/lib/PubSubClient-EspEasy-2.7.11/tests/README.md similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/README.md rename to lib/PubSubClient-EspEasy-2.7.11/tests/README.md diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/connect_spec.cpp similarity index 83% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/connect_spec.cpp index 69f18646f..e27a1f59f 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp +++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/connect_spec.cpp @@ -98,6 +98,33 @@ int test_connect_fails_on_bad_rc() { END_IT } +int test_connect_non_clean_session() { + IT("sends a properly formatted non-clean session connect packet and succeeds"); + ShimClient shimClient; + + shimClient.setAllowConnect(true); + byte expectServer[] = { 172, 16, 0, 2 }; + shimClient.expectConnect(expectServer,1883); + byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x0,0x0,0xf,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); + + int rc = client.connect((char*)"client_test1",0,0,0,0,0,0,0); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + state = client.state(); + IS_TRUE(state == MQTT_CONNECTED); + + END_IT +} + int test_connect_accepts_username_password() { IT("accepts a username and password"); ShimClient shimClient; @@ -133,6 +160,23 @@ int test_connect_accepts_username_no_password() { END_IT } +int test_connect_accepts_username_blank_password() { + IT("accepts a username and blank password"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connect[] = { 0x10,0x20,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x0}; + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; + shimClient.expect(connect,0x26); + shimClient.respond(connack,4); + + PubSubClient client(server, 1883, callback, shimClient); + int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} int test_connect_ignores_password_no_username() { IT("ignores a password but no username"); @@ -239,10 +283,12 @@ int test_connect_disconnect_connect() { int main() { SUITE("Connect"); + test_connect_fails_no_network(); test_connect_fails_on_no_response(); test_connect_properly_formatted(); + test_connect_non_clean_session(); test_connect_accepts_username_password(); test_connect_fails_on_bad_rc(); test_connect_properly_formatted_hostname(); diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/keepalive_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/keepalive_spec.cpp similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/keepalive_spec.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/keepalive_spec.cpp diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Arduino.h similarity index 90% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Arduino.h index c6752801a..2a00f24bc 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h +++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Arduino.h @@ -5,6 +5,7 @@ #include #include #include +#include "Print.h" extern "C"{ @@ -20,4 +21,6 @@ extern "C"{ #define PROGMEM #define pgm_read_byte_near(x) *(x) +#define yield(x) {} + #endif // Arduino_h diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/BDDTest.cpp similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/BDDTest.cpp diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/BDDTest.h similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.h rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/BDDTest.h diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.cpp similarity index 86% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.cpp index 59a2fbbbd..f07759a3a 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp +++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.cpp @@ -2,9 +2,13 @@ #include "Arduino.h" Buffer::Buffer() { + this->pos = 0; + this->length = 0; } Buffer::Buffer(uint8_t* buf, size_t size) { + this->pos = 0; + this->length = 0; this->add(buf,size); } bool Buffer::available() { diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.h similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.h rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.h diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Client.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Client.h similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Client.h rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Client.h diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/IPAddress.cpp similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/IPAddress.cpp diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/IPAddress.h similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.h rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/IPAddress.h diff --git a/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Print.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Print.h new file mode 100644 index 000000000..02ef77c2c --- /dev/null +++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Print.h @@ -0,0 +1,28 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Print_h +#define Print_h + +class Print { + public: + virtual size_t write(uint8_t) = 0; +}; + +#endif diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/ShimClient.cpp similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/ShimClient.cpp diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/ShimClient.h similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.h rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/ShimClient.h diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Stream.cpp similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Stream.cpp diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Stream.h similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.h rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Stream.h diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/trace.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/trace.h similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/trace.h rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/trace.h diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/publish_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/publish_spec.cpp similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/publish_spec.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/publish_spec.cpp diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/receive_spec.cpp similarity index 89% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/receive_spec.cpp index 54a62ee5c..9a18af042 100644 --- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp +++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/receive_spec.cpp @@ -160,6 +160,35 @@ int test_receive_oversized_message() { END_IT } +int test_drop_invalid_remaining_length_message() { + IT("drops invalid remaining length message"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; + shimClient.respond(connack,4); + + PubSubClient client(server, 1883, callback, shimClient); + int rc = client.connect((char*)"client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30,0x92,0x92,0x92,0x92,0x01,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; + shimClient.respond(publish,20); + + rc = client.loop(); + + IS_FALSE(rc); + + IS_FALSE(callback_called); + + IS_FALSE(shimClient.error()); + + END_IT +} + + int test_receive_oversized_stream_message() { IT("drops an oversized message"); reset_callback(); @@ -241,6 +270,7 @@ int main() test_receive_callback(); test_receive_stream(); test_receive_max_sized_message(); + test_drop_invalid_remaining_length_message(); test_receive_oversized_message(); test_receive_oversized_stream_message(); test_receive_qos1(); diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/subscribe_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/subscribe_spec.cpp similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/subscribe_spec.cpp rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/subscribe_spec.cpp diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/__init__.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/__init__.py similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/testcases/__init__.py rename to lib/PubSubClient-EspEasy-2.7.11/tests/testcases/__init__.py diff --git a/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_basic.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_basic.py new file mode 100644 index 000000000..f23ef71c1 --- /dev/null +++ b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_basic.py @@ -0,0 +1,39 @@ +import unittest +import settings +import time +import mosquitto + + +def on_message(mosq, obj, msg): + obj.message_queue.append(msg) + + +class mqtt_basic(unittest.TestCase): + + message_queue = [] + + @classmethod + def setUpClass(self): + self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self) + self.client.connect(settings.server_ip) + self.client.on_message = on_message + self.client.subscribe("outTopic", 0) + + @classmethod + def tearDownClass(self): + self.client.disconnect() + + def test_one(self): + i = 30 + while len(self.message_queue) == 0 and i > 0: + self.client.loop() + time.sleep(0.5) + i -= 1 + self.assertTrue(i > 0, "message receive timed-out") + self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") + msg = self.message_queue[0] + self.assertEqual(msg.mid, 0, "message id not 0") + self.assertEqual(msg.topic, "outTopic", "message topic incorrect") + self.assertEqual(msg.payload, "hello world") + self.assertEqual(msg.qos, 0, "message qos not 0") + self.assertEqual(msg.retain, False, "message retain flag incorrect") diff --git a/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_publish_in_callback.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_publish_in_callback.py new file mode 100644 index 000000000..45b0a8515 --- /dev/null +++ b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_publish_in_callback.py @@ -0,0 +1,59 @@ +import unittest +import settings +import time +import mosquitto + + +def on_message(mosq, obj, msg): + obj.message_queue.append(msg) + + +class mqtt_publish_in_callback(unittest.TestCase): + + message_queue = [] + + @classmethod + def setUpClass(self): + self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self) + self.client.connect(settings.server_ip) + self.client.on_message = on_message + self.client.subscribe("outTopic", 0) + + @classmethod + def tearDownClass(self): + self.client.disconnect() + + def test_connect(self): + i = 30 + while len(self.message_queue) == 0 and i > 0: + self.client.loop() + time.sleep(0.5) + i -= 1 + self.assertTrue(i > 0, "message receive timed-out") + self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") + msg = self.message_queue.pop(0) + self.assertEqual(msg.mid, 0, "message id not 0") + self.assertEqual(msg.topic, "outTopic", "message topic incorrect") + self.assertEqual(msg.payload, "hello world") + self.assertEqual(msg.qos, 0, "message qos not 0") + self.assertEqual(msg.retain, False, "message retain flag incorrect") + + def test_publish(self): + self.assertEqual(len(self.message_queue), 0, "message queue not empty") + payload = "abcdefghij" + self.client.publish("inTopic", payload) + + i = 30 + while len(self.message_queue) == 0 and i > 0: + self.client.loop() + time.sleep(0.5) + i -= 1 + + self.assertTrue(i > 0, "message receive timed-out") + self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") + msg = self.message_queue.pop(0) + self.assertEqual(msg.mid, 0, "message id not 0") + self.assertEqual(msg.topic, "outTopic", "message topic incorrect") + self.assertEqual(msg.payload, payload) + self.assertEqual(msg.qos, 0, "message qos not 0") + self.assertEqual(msg.retain, False, "message retain flag incorrect") diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/settings.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/settings.py similarity index 100% rename from lib/PubSubClient-EspEasy-2.6.09/tests/testcases/settings.py rename to lib/PubSubClient-EspEasy-2.7.11/tests/testcases/settings.py diff --git a/lib/PubSubClient-EspEasy-2.7.11/tests/testsuite.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testsuite.py new file mode 100644 index 000000000..788fc5d97 --- /dev/null +++ b/lib/PubSubClient-EspEasy-2.7.11/tests/testsuite.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python +import os +import os.path +import sys +import shutil +from subprocess import call +import importlib +import unittest +import re + +from testcases import settings + + +class Workspace(object): + + def __init__(self): + self.root_dir = os.getcwd() + self.build_dir = os.path.join(self.root_dir, "tmpbin") + self.log_dir = os.path.join(self.root_dir, "logs") + self.tests_dir = os.path.join(self.root_dir, "testcases") + self.examples_dir = os.path.join(self.root_dir, "../PubSubClient/examples") + self.examples = [] + self.tests = [] + if not os.path.isdir("../PubSubClient"): + raise Exception("Cannot find PubSubClient library") + try: + return __import__('ino') + except ImportError: + raise Exception("ino tool not installed") + + def init(self): + if os.path.isdir(self.build_dir): + shutil.rmtree(self.build_dir) + os.mkdir(self.build_dir) + if os.path.isdir(self.log_dir): + shutil.rmtree(self.log_dir) + os.mkdir(self.log_dir) + + os.chdir(self.build_dir) + call(["ino", "init"]) + + shutil.copytree("../../PubSubClient", "lib/PubSubClient") + + filenames = [] + for root, dirs, files in os.walk(self.examples_dir): + filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")] + filenames.sort() + for e in filenames: + self.examples.append(Sketch(self, e)) + + filenames = [] + for root, dirs, files in os.walk(self.tests_dir): + filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")] + filenames.sort() + for e in filenames: + self.tests.append(Sketch(self, e)) + + def clean(self): + shutil.rmtree(self.build_dir) + + +class Sketch(object): + def __init__(self, wksp, fn): + self.w = wksp + self.filename = fn + self.basename = os.path.basename(self.filename) + self.build_log = os.path.join(self.w.log_dir, "%s.log" % (os.path.basename(self.filename),)) + self.build_err_log = os.path.join(self.w.log_dir, "%s.err.log" % (os.path.basename(self.filename),)) + self.build_upload_log = os.path.join(self.w.log_dir, "%s.upload.log" % (os.path.basename(self.filename),)) + + def build(self): + sys.stdout.write(" Build: ") + sys.stdout.flush() + + # Copy sketch over, replacing IP addresses as necessary + fin = open(self.filename, "r") + lines = fin.readlines() + fin.close() + fout = open(os.path.join(self.w.build_dir, "src", "sketch.ino"), "w") + for l in lines: + if re.match(r"^byte server\[\] = {", l): + fout.write("byte server[] = { %s };\n" % (settings.server_ip.replace(".", ", "),)) + elif re.match(r"^byte ip\[\] = {", l): + fout.write("byte ip[] = { %s };\n" % (settings.arduino_ip.replace(".", ", "),)) + else: + fout.write(l) + fout.flush() + fout.close() + + # Run build + fout = open(self.build_log, "w") + ferr = open(self.build_err_log, "w") + rc = call(["ino", "build"], stdout=fout, stderr=ferr) + fout.close() + ferr.close() + if rc == 0: + sys.stdout.write("pass") + sys.stdout.write("\n") + return True + else: + sys.stdout.write("fail") + sys.stdout.write("\n") + with open(self.build_err_log) as f: + for line in f: + print(" " + line) + return False + + def upload(self): + sys.stdout.write(" Upload: ") + sys.stdout.flush() + fout = open(self.build_upload_log, "w") + rc = call(["ino", "upload"], stdout=fout, stderr=fout) + fout.close() + if rc == 0: + sys.stdout.write("pass") + sys.stdout.write("\n") + return True + else: + sys.stdout.write("fail") + sys.stdout.write("\n") + with open(self.build_upload_log) as f: + for line in f: + print(" " + line) + return False + + def test(self): + # import the matching test case, if it exists + try: + basename = os.path.basename(self.filename)[:-4] + i = importlib.import_module("testcases." + basename) + except: + sys.stdout.write(" Test: no tests found") + sys.stdout.write("\n") + return + c = getattr(i, basename) + + testmethods = [m for m in dir(c) if m.startswith("test_")] + testmethods.sort() + tests = [] + for m in testmethods: + tests.append(c(m)) + + result = unittest.TestResult() + c.setUpClass() + if self.upload(): + sys.stdout.write(" Test: ") + sys.stdout.flush() + for t in tests: + t.run(result) + print(str(result.testsRun - len(result.failures) - len(result.errors)) + "/" + str(result.testsRun)) + if not result.wasSuccessful(): + if len(result.failures) > 0: + for f in result.failures: + print("-- " + str(f[0])) + print(f[1]) + if len(result.errors) > 0: + print(" Errors:") + for f in result.errors: + print("-- " + str(f[0])) + print(f[1]) + c.tearDownClass() + + +if __name__ == '__main__': + run_tests = True + + w = Workspace() + w.init() + + for e in w.examples: + print("--------------------------------------") + print("[" + e.basename + "]") + if e.build() and run_tests: + e.test() + for e in w.tests: + print("--------------------------------------") + print("[" + e.basename + "]") + if e.build() and run_tests: + e.test() + + w.clean()