Compare commits

...

6 Commits
0.9.2 ... 0.9.3

Author SHA1 Message Date
hsaturn
883f1e27e6 Release 0.9.3 2022-10-30 21:47:58 +01:00
hsaturn
e7fc147424 Changed tab to spaces 2022-10-30 21:43:45 +01:00
hsaturn
2147b147fc [Readme] Some minor changes 2022-10-30 21:42:59 +01:00
hsaturn
f5e9a43461 [StringIndexer] Fix compare bug and moved strToIndex to private
strToIndex is dangerous because it can increment the use of a string, or
create a new string. This method should only be called by IndexedString.
2022-10-30 21:41:52 +01:00
hsaturn
cabb56fc8c [tests] Added -g3 for tests for debugging purposes 2022-10-30 20:44:44 +01:00
hsaturn
58786eb6d9 Release 0.9.2 2022-10-30 19:48:04 +01:00
7 changed files with 127 additions and 107 deletions

View File

@@ -22,6 +22,12 @@ TinyMqtt is a small, fast and capable Mqtt Broker and Client for Esp8266 / Esp32
proxy for clients that are connected to it. proxy for clients that are connected to it.
- zeroconf, this is a strange but very powerful mode where - zeroconf, this is a strange but very powerful mode where
all brokers tries to connect together on the same local network. all brokers tries to connect together on the same local network.
- small memory footprint (very efficient topic storage)
## Limitations
- Max of 255 different topics can be stored (change index_t type to allow more)
- No Qos because messages are not queued but immediately sent to clients
## Quickstart ## Quickstart

View File

@@ -1,5 +1,5 @@
name=TinyMqtt name=TinyMqtt
version=0.9.1 version=0.9.3
author=Francois BIOT, HSaturn, <hsaturn@gmail.com> author=Francois BIOT, HSaturn, <hsaturn@gmail.com>
maintainer=Francois BIOT, HSaturn, <hsaturn@gmail.com> maintainer=Francois BIOT, HSaturn, <hsaturn@gmail.com>
sentence=A tiny broker and client library for MQTT messaging. sentence=A tiny broker and client library for MQTT messaging.
@@ -8,4 +8,3 @@ category=Communication
url=https://github.com/hsaturn/TinyMqtt url=https://github.com/hsaturn/TinyMqtt
architectures=* architectures=*
includes=TinyMqtt.h includes=TinyMqtt.h
depends=AsyncTCP

View File

@@ -26,32 +26,9 @@ class StringIndexer
#endif #endif
}; };
public: public:
using index_t=uint8_t; using index_t = uint8_t;
static index_t strToIndex(const char* str, uint8_t len) static const std::string& str(const index_t& index)
{
for(auto it=strings.begin(); it!=strings.end(); it++)
{
if (strncmp(it->second.str.c_str(), str, len)==0)
{
it->second.used++;
return it->first;
}
}
for(index_t index=1; index; index++)
{
if (strings.find(index)==strings.end())
{
strings[index].str = std::string(str, len);
strings[index].used++;
// Serial << "Creating index " << index << " for (" << strings[index].str.c_str() << ") len=" << len << endl;
return index;
}
}
return 0; // TODO out of indexes
}
static const std::string& str(const index_t& index)
{ {
static std::string dummy; static std::string dummy;
const auto& it=strings.find(index); const auto& it=strings.find(index);
@@ -82,6 +59,32 @@ class StringIndexer
static uint16_t count() { return strings.size(); } static uint16_t count() { return strings.size(); }
private: private:
friend class IndexedString;
// increment use of str or create a new index
static index_t strToIndex(const char* str, uint8_t len)
{
for(auto it=strings.begin(); it!=strings.end(); it++)
{
if (it->second.str.length() == len && strcmp(it->second.str.c_str(), str)==0)
{
it->second.used++;
return it->first;
}
}
for(index_t index=1; index; index++)
{
if (strings.find(index)==strings.end())
{
strings[index].str = std::string(str, len);
strings[index].used++;
// Serial << "Creating index " << index << " for (" << strings[index].str.c_str() << ") len=" << len << endl;
return index;
}
}
return 0; // TODO out of indexes
}
static std::map<index_t, StringCounter> strings; static std::map<index_t, StringCounter> strings;
}; };

View File

@@ -1,6 +1,8 @@
# See https://github.com/bxparks/EpoxyDuino for documentation about this # See https://github.com/bxparks/EpoxyDuino for documentation about this
# Makefile to compile and run Arduino programs natively on Linux or MacOS. # Makefile to compile and run Arduino programs natively on Linux or MacOS.
EXTRA_CXXFLAGS=-g3 -O0
APP_NAME := length-tests APP_NAME := length-tests
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsyncTCP
ARDUINO_LIB_DIRS := ../../../EspMock/libraries ARDUINO_LIB_DIRS := ../../../EspMock/libraries

View File

@@ -4,148 +4,148 @@
#include <map> #include <map>
/** /**
* TinyMqtt local unit tests. * TinyMqtt local unit tests.
* *
* Clients are connected to pseudo remote broker * Clients are connected to pseudo remote broker
* The remote should be 127.0.0.1:1883 <--- But this does not work due to Esp network limitations * The remote should be 127.0.0.1:1883 <--- But this does not work due to Esp network limitations
* We are using 127.0.0.1 because this is simpler to test with a single ESP * We are using 127.0.0.1 because this is simpler to test with a single ESP
* Also, this will allow to mock and thus run Action on github * Also, this will allow to mock and thus run Action on github
**/ **/
using namespace std; using namespace std;
MqttBroker broker(1883); MqttBroker broker(1883);
std::map<std::string, std::map<Topic, int>> published; // map[client_id] => map[topic] = count std::map<std::string, std::map<Topic, int>> published; // map[client_id] => map[topic] = count
const char* lastPayload; const char* lastPayload;
size_t lastLength; size_t lastLength;
void onPublish(const MqttClient* srce, const Topic& topic, const char* payload, size_t length) void onPublish(const MqttClient* srce, const Topic& topic, const char* payload, size_t length)
{ {
if (srce) if (srce)
published[srce->id()][topic]++; published[srce->id()][topic]++;
lastPayload = payload; lastPayload = payload;
lastLength = length; lastLength = length;
} }
test(local_client_should_unregister_when_destroyed) test(local_client_should_unregister_when_destroyed)
{ {
assertEqual(broker.clientsCount(), (size_t)0); assertEqual(broker.clientsCount(), (size_t)0);
{ {
assertEqual(broker.clientsCount(), (size_t)0); // Ensure client is not yet connected assertEqual(broker.clientsCount(), (size_t)0); // Ensure client is not yet connected
MqttClient client(&broker); MqttClient client(&broker);
assertEqual(broker.clientsCount(), (size_t)1); // Ensure client is now connected assertEqual(broker.clientsCount(), (size_t)1); // Ensure client is now connected
} }
assertEqual(broker.clientsCount(), (size_t)0); assertEqual(broker.clientsCount(), (size_t)0);
} }
#if 0 #if 0
test(local_connect) test(local_connect)
{ {
assertEqual(broker.clientsCount(), (size_t)0); assertEqual(broker.clientsCount(), (size_t)0);
MqttClient client; MqttClient client;
assertTrue(client.connected()); assertTrue(client.connected());
assertEqual(broker.clientsCount(), (size_t)1); assertEqual(broker.clientsCount(), (size_t)1);
} }
test(local_publish_should_be_dispatched) test(local_publish_should_be_dispatched)
{ {
published.clear(); published.clear();
assertEqual(broker.clientsCount(), (size_t)0); assertEqual(broker.clientsCount(), (size_t)0);
MqttClient subscriber; MqttClient subscriber;
subscriber.subscribe("a/b"); subscriber.subscribe("a/b");
subscriber.subscribe("a/c"); subscriber.subscribe("a/c");
subscriber.setCallback(onPublish); subscriber.setCallback(onPublish);
MqttClient publisher; MqttClient publisher;
publisher.publish("a/b"); publisher.publish("a/b");
publisher.publish("a/c"); publisher.publish("a/c");
publisher.publish("a/c"); publisher.publish("a/c");
assertEqual(published.size(), (size_t)1); // 1 client has received something assertEqual(published.size(), (size_t)1); // 1 client has received something
assertEqual(published[""]["a/b"], 1); assertEqual(published[""]["a/b"], 1);
assertEqual(published[""]["a/c"], 2); assertEqual(published[""]["a/c"], 2);
} }
test(local_publish_should_be_dispatched_to_local_clients) test(local_publish_should_be_dispatched_to_local_clients)
{ {
published.clear(); published.clear();
assertEqual(broker.clientsCount(), (size_t)0); assertEqual(broker.clientsCount(), (size_t)0);
MqttClient subscriber_a("A"); MqttClient subscriber_a("A");
subscriber_a.setCallback(onPublish); subscriber_a.setCallback(onPublish);
subscriber_a.subscribe("a/b"); subscriber_a.subscribe("a/b");
subscriber_a.subscribe("a/c"); subscriber_a.subscribe("a/c");
MqttClient subscriber_b("B"); MqttClient subscriber_b("B");
subscriber_b.setCallback(onPublish); subscriber_b.setCallback(onPublish);
subscriber_b.subscribe("a/b"); subscriber_b.subscribe("a/b");
MqttClient publisher; MqttClient publisher;
publisher.publish("a/b"); publisher.publish("a/b");
publisher.publish("a/c"); publisher.publish("a/c");
assertEqual(published.size(), (size_t)2); // 2 clients have received something assertEqual(published.size(), (size_t)2); // 2 clients have received something
assertEqual(published["A"]["a/b"], 1); assertEqual(published["A"]["a/b"], 1);
assertEqual(published["A"]["a/c"], 1); assertEqual(published["A"]["a/c"], 1);
assertEqual(published["B"]["a/b"], 1); assertEqual(published["B"]["a/b"], 1);
assertEqual(published["B"]["a/c"], 0); assertEqual(published["B"]["a/c"], 0);
} }
test(local_unsubscribe) test(local_unsubscribe)
{ {
published.clear(); published.clear();
assertEqual(broker.clientsCount(), (size_t)0); assertEqual(broker.clientsCount(), (size_t)0);
MqttClient subscriber; MqttClient subscriber;
subscriber.setCallback(onPublish); subscriber.setCallback(onPublish);
subscriber.subscribe("a/b"); subscriber.subscribe("a/b");
MqttClient publisher; MqttClient publisher;
publisher.publish("a/b"); publisher.publish("a/b");
subscriber.unsubscribe("a/b"); subscriber.unsubscribe("a/b");
publisher.publish("a/b"); publisher.publish("a/b");
publisher.publish("a/b"); publisher.publish("a/b");
assertEqual(published[""]["a/b"], 1); // Only one publish has been received assertEqual(published[""]["a/b"], 1); // Only one publish has been received
} }
test(local_nocallback_when_destroyed) test(local_nocallback_when_destroyed)
{ {
published.clear(); published.clear();
assertEqual(broker.clientsCount(), (size_t)0); assertEqual(broker.clientsCount(), (size_t)0);
MqttClient publisher; MqttClient publisher;
{ {
MqttClient subscriber; MqttClient subscriber;
subscriber.setCallback(onPublish); subscriber.setCallback(onPublish);
subscriber.subscribe("a/b"); subscriber.subscribe("a/b");
publisher.publish("a/b"); publisher.publish("a/b");
} }
publisher.publish("a/b"); publisher.publish("a/b");
assertEqual(published.size(), (size_t)1); // Only one publish has been received assertEqual(published.size(), (size_t)1); // Only one publish has been received
} }
#endif #endif
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// setup() and loop() // setup() and loop()
void setup() { void setup() {
delay(1000); delay(1000);
Serial.begin(115200); Serial.begin(115200);
while(!Serial); while(!Serial);
Serial.println("=============[ LOCAL TinyMqtt TESTS ]========================"); Serial.println("=============[ LOCAL TinyMqtt TESTS ]========================");
} }
void loop() { void loop() {
aunit::TestRunner::run(); aunit::TestRunner::run();
if (Serial.available()) ESP.reset(); if (Serial.available()) ESP.reset();
} }

View File

@@ -1,6 +1,8 @@
# See https://github.com/bxparks/EpoxyDuino for documentation about this # See https://github.com/bxparks/EpoxyDuino for documentation about this
# Makefile to compile and run Arduino programs natively on Linux or MacOS. # Makefile to compile and run Arduino programs natively on Linux or MacOS.
EXTRA_CXXFLAGS=-g3 -O0
APP_NAME := string-indexer-tests APP_NAME := string-indexer-tests
ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsync ARDUINO_LIBS := AUnit AceCommon AceTime TinyMqtt EspMock ESP8266WiFi ESPAsync
ARDUINO_LIB_DIRS := ../../../EspMock/libraries ARDUINO_LIB_DIRS := ../../../EspMock/libraries

View File

@@ -62,6 +62,14 @@ test(indexer_same_strings_should_equal)
assertTrue(one == two); assertTrue(one == two);
} }
test(indexer_compare_strings_with_same_beginning)
{
IndexedString two("one_two");
IndexedString one("one");
assertNotEqual(one.getIndex(), two.getIndex());
}
test(indexer_indexed_operator_eq) test(indexer_indexed_operator_eq)
{ {
IndexedString one("one"); IndexedString one("one");