Use TinyConsole instead of Serial

This commit is contained in:
Francois BIOT
2022-11-30 20:06:15 +01:00
parent d12096ef51
commit 1fff9fd0e1
4 changed files with 251 additions and 200 deletions

View File

@@ -1,5 +1,6 @@
// vim: ts=2 sw=2
// vim: ts=2 sw=2 expandtab smartindent
#define TINY_MQTT_DEBUG
#include <TinyConsole.h>
#include <TinyMqtt.h> // https://github.com/hsaturn/TinyMqtt
#include <MqttStreaming.h>
#if defined(ESP8266)
@@ -15,6 +16,10 @@
#include <map>
bool echo_on = true;
auto green = TinyConsole::green;
auto red = TinyConsole::red;
auto white = TinyConsole::white;
auto cyan = TinyConsole::cyan;
/** Very complex example
* Console allowing to make any kind of test,
@@ -27,26 +32,26 @@ bool echo_on = true;
* TODO examples of scripts
*/
const char* ssid = "";
const char* password = "";
const char* ssid = "Freebox-786A2F";
const char* password = "usurpavi8dalum64lumine?";
std::string topic="sensor/temperature";
void onPublish(const MqttClient* srce, const Topic& topic, const char* payload, size_t length)
{
Serial << "--> " << srce->id().c_str() << ": ======> received " << topic.c_str();
Console << cyan << "--> " << srce->id().c_str() << ": received " << topic.c_str() << white;
if (payload)
{
Serial << ", payload[" << length << "]=[";
Console << ", payload[" << length << "]=[";
while(length--)
{
const char c=*payload++;
if (c<32)
Serial << '?';
Console << '?';
else
Serial << c;
Console << c;
}
Serial << ']' << endl;
Console << ']' << endl;
}
}
@@ -57,23 +62,26 @@ void setup()
{
WiFi.persistent(false); // https://github.com/esp8266/Arduino/issues/1054
Serial.begin(115200);
Console.begin(Serial);
Console.setPrompt("> ");
Console.setCallback(onCommand);
delay(500);
Serial << endl << endl;
Serial << "***************************************************************" << endl;
Serial << "* Welcome to the TinyMqtt console" << endl;
Serial << endl;
Serial << "* The console allows to test all features of the libraries." << endl;
Serial << endl;
Console.cls();
Console << endl << endl;
Console << yellow
<< "***************************************************************" << endl;
Console << "* Welcome to the TinyMqtt console" << endl;
Console << "* The console allows to test all features of the libraries." << endl;
Console << "* Enter help to view the list of commands." << endl;
Console << "***************************************************************" << endl;
Console << endl;
if (strlen(ssid)==0)
Serial << "* WARNING: You may want to modify ssid/password in order" << endl
<< " to reflect your Wifi configuration." << endl;
Serial << endl;
Serial << "* Enter help to view the list of commands." << endl;
Serial << "***************************************************************" << endl;
Serial << endl;
Console << red << "* ERROR: You must modify ssid/password in order" << endl
<< " to be able to connect to your Wifi network." << endl;
Console << endl << white;
Serial << "Connecting to '" << ssid << "' ";
Console << "Connecting to '" << ssid << "' ";
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
@@ -81,16 +89,16 @@ void setup()
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{ Serial << '-'; delay(500); }
{ Console << '-'; delay(500); }
Serial << endl << "Connected to " << ssid << "IP address: " << WiFi.localIP() << endl;
Console << endl << "Connected to " << ssid << "IP address: " << WiFi.localIP() << endl;
const char* name="tinytest";
Serial << "Starting MDNS, name= " << name;
Console << "Starting MDNS, name= " << name;
if (!MDNS.begin(name))
Serial << " error, not available." << endl;
Console << " error, not available." << endl;
else
Serial << " ok." << endl;
Console << " ok." << endl;
MqttBroker* broker = new MqttBroker(1883);
@@ -144,7 +152,7 @@ std::string getword(std::string& str, const char* if_empty/*=nullptr*/, char sep
{
sword.erase(0,1);
to = getint(sword);
if (sword[0]!=')') Serial << "Missing ')'" << endl;
if (sword[0]!=')') Console << "Missing ')'" << endl;
}
else
{
@@ -155,7 +163,7 @@ std::string getword(std::string& str, const char* if_empty/*=nullptr*/, char sep
}
else
{
Serial << "Missing '('" << endl;
Console << "Missing '('" << endl;
}
}
while(str[0]==' ') str.erase(0,1);
@@ -229,7 +237,7 @@ void convertToCommand(std::string& search)
search = matches;
else if (count>1)
{
Serial << "Ambiguous command: " << matches << endl;
Console << "Ambiguous command: " << matches << endl;
search.clear();
}
}
@@ -268,10 +276,10 @@ void replaceVars(std::string& cmd)
}
// publish at regular interval
class automatic
class Automatic
{
public:
automatic(MqttClient* clt, uint32_t intervl)
Automatic(MqttClient* clt, uint32_t intervl)
: client(clt), topic_(::topic)
{
interval(intervl);
@@ -290,7 +298,7 @@ class automatic
if (!bon) return;
if (interval_ && millis() > timer_)
{
Serial << "AUTO PUBLISH " << interval_ << endl;
Console << "AUTO PUBLISH " << interval_ << endl;
timer_ += interval_;
client->publish(topic_, std::string(String(15+millis()%10).c_str()));
}
@@ -306,7 +314,7 @@ class automatic
static void command(MqttClient* who, std::string cmd)
{
automatic* autop = nullptr;
Automatic* autop = nullptr;
if (autos.find(who) != autos.end())
{
autop=autos[who];
@@ -317,10 +325,10 @@ class automatic
std::string seconds=getword(cmd, "10000");
if (autop) delete autop;
std::string top = getword(cmd, ::topic.c_str());
autos[who] = new automatic(who, atol(seconds.c_str()));
autos[who] = new Automatic(who, atol(seconds.c_str()));
autos[who]->topic(top);
autos[who]->bon=true;
Serial << "New auto (" << seconds.c_str() << " topic:" << top.c_str() << ')' << endl;
Console << "New auto (" << seconds.c_str() << " topic:" << top.c_str() << ')' << endl;
}
else if (autop)
{
@@ -339,18 +347,18 @@ class automatic
if (i)
autop->interval(atol(s.c_str()));
else
Serial << "Bad value" << endl;
Console << "Bad value" << endl;
}
else if (s=="view")
{
Serial << " automatic "
Console << " Automatic "
<< (int32_t)autop->client
<< " interval " << autop->interval_
<< (autop->bon ? " on" : " off") << endl;
}
else
{
Serial << "Unknown auto command (" << s.c_str() << ")" << endl;
Console << "Unknown auto command (" << s.c_str() << ")" << endl;
break;
}
s=getword(cmd);
@@ -362,15 +370,15 @@ class automatic
command(it.first, s+' '+cmd);
}
else
Serial << "what ? (" << s.c_str() << ")" << endl;
Console << "what ? (" << s.c_str() << ")" << endl;
}
static void help()
{
Serial << " auto [$id] on/off" << endl;
Serial << " auto [$id] view" << endl;
Serial << " auto [$id] interval [s]" << endl;
Serial << " auto [$id] create [millis] [topic]" << endl;
Console << " auto [$id] on/off" << endl;
Console << " auto [$id] view" << endl;
Console << " auto [$id] interval [s]" << endl;
Console << " auto [$id] create [millis] [topic]" << endl;
}
private:
@@ -379,10 +387,10 @@ class automatic
uint32_t timer_;
std::string topic_;
bool bon=false;
static std::map<MqttClient*, automatic*> autos;
static std::map<MqttClient*, Automatic*> autos;
float temp=19;
};
std::map<MqttClient*, automatic*> automatic::autos;
std::map<MqttClient*, Automatic*> Automatic::autos;
bool compare(std::string s, const char* cmd)
{
@@ -407,13 +415,18 @@ struct Every
void dump()
{
Serial << (active ? "enabled " : "disabled ");
auto mill=millis();
Serial << ms << "ms [" << cmd << "] next in ";
if (mill > next)
Serial << "now";
if (active)
Console << green << "enabled";
else
Serial << next-mill << "ms";
Console << red << "disabled";
Console << white <<
auto mill=millis();
Console << ms << "ms [" << cmd << "] next in ";
if (mill > next)
Console << "now";
else
Console << next-mill << "ms";
}
};
@@ -425,6 +438,13 @@ int16_t blink;
std::vector<Every> everies;
void onCommand(const std::string& command)
{
std::string cmd=command;
if (cmd.substr(0,3)!="set") replaceVars(cmd);
eval(cmd);
}
void eval(std::string& cmd)
{
while(cmd.length())
@@ -453,7 +473,7 @@ void eval(std::string& cmd)
}
else
{
Serial << "Unknown class (" << s.c_str() << ")" << endl;
Console << red << "Unknown class (" << s.c_str() << ")" << white << endl;
cmd.clear();
}
}
@@ -477,14 +497,14 @@ void eval(std::string& cmd)
broker = brokers[s];
}
else
Serial << "Unable to find (" << s.c_str() << ")" << endl;
Console << red << "Unable to find (" << s.c_str() << ")" << << white << endl;
}
if (client)
{
for (auto it: clients)
{
if (it.second != client) continue;
Serial << "deleted" << endl;
Console << "deleted" << endl;
delete (it.second);
clients.erase(it.first);
break;
@@ -496,7 +516,7 @@ void eval(std::string& cmd)
for(auto it: brokers)
{
if (broker != it.second) continue;
Serial << "deleted" << endl;
Console << "deleted" << endl;
delete (it.second);
brokers.erase(it.first);
break;
@@ -504,13 +524,13 @@ void eval(std::string& cmd)
cmd += " ls";
}
else
Serial << "Nothing to delete" << endl;
Console << "Nothing to delete" << endl;
}
else if (broker)
{
if (compare(s,"connect"))
{
Serial << "NYI" << endl;
Console << "NYI" << endl;
}
else if (compare(s, "view"))
{
@@ -518,7 +538,7 @@ void eval(std::string& cmd)
}
else
{
Serial << "Unknown broker command (" << s << ")" << endl;
Console << "Unknown broker command (" << s << ")" << endl;
s.clear();
}
}
@@ -527,7 +547,7 @@ void eval(std::string& cmd)
if (compare(s,"connect"))
{
client->connect(getip(cmd,"192.168.1.40").c_str(), getint(cmd, 1883), getint(cmd, 60));
Serial << (client->connected() ? "connected." : "not connected") << endl;
Console << (client->connected() ? "connected." : "not connected") << endl;
}
else if (compare(s,"publish"))
{
@@ -547,7 +567,7 @@ void eval(std::string& cmd)
}
else
{
Serial << "Unknown client command (" << s << ")" << endl;
Console << "Unknown client command (" << s << ")" << endl;
s.clear();
}
}
@@ -572,10 +592,10 @@ void eval(std::string& cmd)
echo_on = false;
else
{
Serial << s << ' ';
Console << s << ' ';
while(cmd.length())
{
Serial << getword(cmd) << ' ';
Console << getword(cmd) << ' ';
}
}
}
@@ -592,7 +612,7 @@ void eval(std::string& cmd)
every.next=millis()+ms;
everies.push_back(every);
every.dump();
Serial << endl;
Console << endl;
cmd.clear();
}
}
@@ -607,7 +627,7 @@ void eval(std::string& cmd)
{
if (every.active != active)
{
Serial << "every #" << count << (active ? " on" :" off") << endl;
Console << "every #" << count << (active ? " on" :" off") << endl;
every.active = active;
every.underrun = 0;
}
@@ -618,19 +638,19 @@ void eval(std::string& cmd)
else if (compare(cmd, "list") or cmd.length()==0)
{
getword(cmd);
Serial << "List of everies (ms=" << millis() << ")" << endl;
Console << "List of everies (ms=" << millis() << ")" << endl;
uint8_t count=0;
for(auto& every: everies)
{
Serial << count << ": ";
Console << count << ": ";
every.dump();
Serial << endl;
Console << endl;
count++;
}
}
else if (compare(cmd, "remove"))
{
Serial << "Removing..." << endl;
Console << "Removing..." << endl;
getword(cmd);
int8_t every=getint(cmd, -1);
if (every==-1 and compare(cmd, "last") and everies.size())
@@ -648,10 +668,10 @@ void eval(std::string& cmd)
everies.erase(everies.begin()+every);
}
else
Serial << "Bad colmmand" << endl;
Console << "Bad colmmand" << endl;
}
else
Serial << "Bad command" << endl;
Console << "Bad command" << endl;
}
else if (compare(s, "blink"))
{
@@ -662,7 +682,7 @@ void eval(std::string& cmd)
blink_ms_off[blink_nr]=getint(cmd, blink_ms_on[blink_nr]);
pinMode(blink_nr, OUTPUT);
blink_next[blink_nr] = millis();
Serial << "Blink " << blink_nr << ' ' << (blink_ms_on[blink_nr] ? "on" : "off") << endl;
Console << "Blink " << blink_nr << ' ' << (blink_ms_on[blink_nr] ? "on" : "off") << endl;
if (blink_ms_on[blink_nr])
blink |= 1<< blink_nr;
else
@@ -673,7 +693,7 @@ void eval(std::string& cmd)
}
else if (compare(s, "auto"))
{
automatic::command(client, cmd);
Automatic::command(client, cmd);
if (client == nullptr)
cmd.clear();
}
@@ -682,7 +702,7 @@ void eval(std::string& cmd)
std::string id=getword(cmd);
if (clients.find(id) != clients.end())
{
Serial << "A client already have that name" << endl;
Console << "A client already have that name" << endl;
cmd.clear();
}
else if (id.length() or brokers.find(id)!=brokers.end())
@@ -694,17 +714,17 @@ void eval(std::string& cmd)
broker->begin();
brokers[id] = broker;
Serial << "new broker (" << id.c_str() << ")" << endl;
Console << "new broker (" << id.c_str() << ")" << endl;
}
else
{
Serial << "Missing port" << endl;
Console << "Missing port" << endl;
cmd.clear();
}
}
else
{
Serial << "Missing or existing broker name (" << id.c_str() << ")" << endl;
Console << "Missing or existing broker name (" << id.c_str() << ")" << endl;
cmd.clear();
}
}
@@ -713,7 +733,7 @@ void eval(std::string& cmd)
std::string id=getword(cmd);
if (brokers.find(id) != brokers.end())
{
Serial << "A broker have that name" << endl;
Console << "A broker have that name" << endl;
cmd.clear();
}
else if (id.length() or clients.find(id)!=clients.end())
@@ -728,17 +748,17 @@ void eval(std::string& cmd)
clients[id]=client;
client->setCallback(onPublish);
client->subscribe(topic);
Serial << "new client (" << id.c_str() << ", " << s.c_str() << ')' << endl;
Console << "new client (" << id.c_str() << ", " << s.c_str() << ')' << endl;
}
else if (s.length())
{
Serial << " not found." << endl;
Console << " not found." << endl;
cmd.clear();
}
}
else
{
Serial << "Missing or existing client name" << endl;
Console << "Missing or existing client name" << endl;
cmd.clear();
}
}
@@ -749,12 +769,12 @@ void eval(std::string& cmd)
{
for(auto it: vars)
{
Serial << " " << it.first << " -> " << it.second << endl;
Console << " " << it.first << " -> " << it.second << endl;
}
}
else if (commands.find(name) != commands.end())
{
Serial << "Reserved keyword (" << name << ")" << endl;
Console << "Reserved keyword (" << name << ")" << endl;
cmd.clear();
}
else
@@ -770,66 +790,66 @@ void eval(std::string& cmd)
}
else if (compare(s, "ls") or compare(s, "view"))
{
Serial << "--< " << clients.size() << " client/s. >--" << endl;
Console << "--< " << clients.size() << " client/s. >--" << endl;
for(auto it: clients)
{
it.second->dump(" ");
}
Serial << "--< " << brokers.size() << " brokers/s. >--" << endl;
Console << "--< " << brokers.size() << " brokers/s. >--" << endl;
for(auto it: brokers)
{
Serial << " +-- '" << it.first.c_str() << "' " << it.second->clientsCount() << " client/s."<< endl;
Console << " +-- '" << it.first.c_str() << "' " << it.second->clientsCount() << " client/s."<< endl;
it.second->dump(" ");
}
}
else if (compare(s, "reset"))
ESP.restart();
else if (compare(s, "ip"))
Serial << "IP: " << WiFi.localIP() << endl;
Console << "IP: " << WiFi.localIP() << endl;
else if (compare(s,"help"))
{
Serial << "syntax:" << endl;
Serial << " MqttBroker:" << endl;
Serial << " broker {broker_name} {port} : create a new broker" << endl;
Serial << " broker_name.delete : delete a broker (buggy)" << endl;
Serial << " broker_name.view : dump a broker" << endl;
Serial << endl;
Serial << " MqttClient:" << endl;
Serial << " client {name} {parent broker} : create a client then" << endl;
Serial << " name.connect [ip] [port] [alive]" << endl;
Serial << " name.[un]subscribe [topic]" << endl;
Serial << " name.publish [topic][payload]" << endl;
Serial << " name.view" << endl;
Serial << " name.delete" << endl;
Serial << endl;
Console << "syntax:" << endl;
Console << " MqttBroker:" << endl;
Console << " broker {broker_name} {port} : create a new broker" << endl;
Console << " broker_name.delete : delete a broker (buggy)" << endl;
Console << " broker_name.view : dump a broker" << endl;
Console << endl;
Console << " MqttClient:" << endl;
Console << " client {name} {parent broker} : create a client then" << endl;
Console << " name.connect [ip] [port] [alive]" << endl;
Console << " name.[un]subscribe [topic]" << endl;
Console << " name.publish [topic][payload]" << endl;
Console << " name.view" << endl;
Console << " name.delete" << endl;
Console << endl;
automatic::help();
Serial << endl;
Serial << " help" << endl;
Serial << " blink [Dx on_ms off_ms] : make pin blink" << endl;
Serial << " ls / ip / reset" << endl;
Serial << " set [name][value]" << endl;
Serial << " ! repeat last command" << endl;
Serial << endl;
Serial << " echo [on|off] or strings" << endl;
Serial << " every ms [command]; every list; every remove [nr|all]; every (on|off) [#]" << endl;
Serial << " on {output}; off {output}" << endl;
Serial << " $id : name of the client." << endl;
Serial << " rnd[(min[,max])] random number." << endl;
Serial << " default topic is '" << topic.c_str() << "'" << endl;
Serial << endl;
Automatic::help();
Console << endl;
Console << " help" << endl;
Console << " blink [Dx on_ms off_ms] : make pin blink" << endl;
Console << " ls / ip / reset" << endl;
Console << " set [name][value]" << endl;
Console << " ! repeat last command" << endl;
Console << endl;
Console << " echo [on|off] or strings" << endl;
Console << " every ms [command]; every list; every remove [nr|all]; every (on|off) [#]" << endl;
Console << " on {output}; off {output}" << endl;
Console << " $id : name of the client." << endl;
Console << " rnd[(min[,max])] random number." << endl;
Console << " default topic is '" << topic.c_str() << "'" << endl;
Console << endl;
}
else
{
while(s[0]==' ') s.erase(0,1);
if (s.length())
Serial << "Unknown command (" << s.c_str() << ")" << endl;
Console << "Unknown command (" << s.c_str() << ")" << endl;
}
if (retval != MqttOk)
{
Serial << "# MQTT ERROR " << retval << endl;
Console << "# MQTT ERROR " << retval << endl;
}
}
}
@@ -851,7 +871,7 @@ void loop()
every.next += every.ms;
if (ms > every.next and ms > every.underrun)
{
Serial << "Underrun every #" << e << ", " << (ms - every.next) << "ms late" << endl;
Console << "Underrun every #" << e << ", " << (ms - every.next) << "ms late" << endl;
every.underrun = ms+5000;
}
}
@@ -889,30 +909,6 @@ void loop()
for(auto it: clients)
it.second->loop();
automatic::loop();
if (Serial.available())
{
static std::string cmd;
char c=Serial.read();
if (echo_on)
Serial << c;
if (c==10 or c==13)
{
Serial << "----------------[ " << cmd.c_str() << " ]--------------" << endl;
static std::string last_cmd;
if (cmd=="!")
cmd=last_cmd;
else
last_cmd=cmd;
if (cmd.substr(0,3)!="set") replaceVars(cmd);
eval(cmd);
}
else
{
cmd=cmd+c;
}
}
Automatic::loop();
Console::loop();
}

View File

@@ -7,4 +7,5 @@ paragraph=MQTT is a lightweight messaging protocol ideal for small devices. This
category=Communication
url=https://github.com/hsaturn/TinyMqtt
architectures=*
depends=TinyConsole
includes=TinyMqtt.h

View File

@@ -1,6 +1,16 @@
#include "TinyMqtt.h"
#include <sstream>
static auto green = TinyConsole::green;
static auto cyan = TinyConsole::cyan;
static auto white = TinyConsole::white;
static auto red = TinyConsole::red;
static auto yellow = TinyConsole::yellow;
#ifdef TINY_MQTT_DEBUG
int TinyMqtt::debug=2;
#endif
#ifdef EPOXY_DUINO
std::map<MqttMessage::Type, int> MqttClient::counters;
#endif
@@ -64,6 +74,7 @@ void MqttClient::close(bool bSendDisconnect)
if (bSendDisconnect and client->connected())
{
message.create(MqttMessage::Type::Disconnect);
message.hexdump("close");
message.sendTo(this);
}
client->stop();
@@ -78,13 +89,14 @@ void MqttClient::close(bool bSendDisconnect)
void MqttClient::connect(MqttBroker* parentBroker)
{
debug("MqttClient::connect_1");
close();
parent = parentBroker;
}
void MqttClient::connect(std::string broker, uint16_t port, uint16_t ka)
{
debug("MqttClient::connect");
debug("MqttClient::connect_3");
keep_alive = ka;
close();
if (client) delete client;
@@ -105,11 +117,13 @@ void MqttClient::connect(std::string broker, uint16_t port, uint16_t ka)
void MqttBroker::addClient(MqttClient* client)
{
debug("MqttBroker::addClient");
clients.push_back(client);
}
void MqttBroker::connect(const std::string& host, uint16_t port)
{
debug("MqttBroker::connect_2");
if (broker == nullptr) broker = new MqttClient;
broker->connect(host, port);
broker->parent = this; // Because connect removed the link
@@ -117,6 +131,7 @@ void MqttBroker::connect(const std::string& host, uint16_t port)
void MqttBroker::removeClient(MqttClient* remove)
{
debug("removeClient");
for(auto it=clients.begin(); it!=clients.end(); it++)
{
auto client=*it;
@@ -133,11 +148,12 @@ void MqttBroker::removeClient(MqttClient* remove)
return;
}
}
debug("Error cannot remove client"); // TODO should not occur
debug(red << "Error cannot remove client"); // TODO should not occur
}
void MqttBroker::onClient(void* broker_ptr, TcpClient* client)
{
debug("MqttBroker::onClient");
MqttBroker* broker = static_cast<MqttBroker*>(broker_ptr);
broker->addClient(new MqttClient(broker, client));
@@ -183,6 +199,7 @@ void MqttBroker::loop()
MqttError MqttBroker::subscribe(const Topic& topic, uint8_t qos)
{
debug("MqttBroker::subscribe");
if (broker && broker->connected())
{
return broker->subscribe(topic, qos);
@@ -194,13 +211,13 @@ MqttError MqttBroker::publish(const MqttClient* source, const Topic& topic, Mqtt
{
MqttError retval = MqttOk;
debug("publish ");
debug("MqttBroker::publish");
int i=0;
for(auto client: clients)
{
i++;
#ifdef TINY_MQTT_DEBUG
Serial << "brk_" << (broker && broker->connected() ? "con" : "dis") <<
Console << __LINE__ << " broker:" << (broker && broker->connected() ? "linked" : "alone") <<
" srce=" << (source->isLocal() ? "loc" : "rem") << " clt#" << i << ", local=" << client->isLocal() << ", con=" << client->connected() << endl;
#endif
bool doit = false;
@@ -221,7 +238,7 @@ MqttError MqttBroker::publish(const MqttClient* source, const Topic& topic, Mqtt
doit = true;
}
#ifdef TINY_MQTT_DEBUG
Serial << ", doit=" << doit << ' ';
Console << ", doit=" << doit << ' ';
#endif
if (doit) retval = client->publishIfSubscribed(topic, msg);
@@ -248,6 +265,7 @@ void MqttMessage::getString(const char* &buff, uint16_t& len)
void MqttClient::clientAlive(uint32_t more_seconds)
{
debug("MqttClient::clientAlive");
if (keep_alive)
{
#ifdef EPOXY_DUINO
@@ -266,9 +284,9 @@ void MqttClient::loop()
{
if (parent)
{
debug("timeout client");
debug(red << "timeout client");
close();
debug("closed");
debug(red << "closed");
}
else if (client && client->connected())
{
@@ -297,7 +315,7 @@ void MqttClient::loop()
void MqttClient::onConnect(void *mqttclient_ptr, TcpClient*)
{
MqttClient* mqtt = static_cast<MqttClient*>(mqttclient_ptr);
debug("cnx: connecting");
debug("MqttClient::onConnect");
MqttMessage msg(MqttMessage::Type::Connect);
msg.add("MQTT",4);
msg.add(0x4); // Mqtt protocol version 3.1.1
@@ -354,7 +372,7 @@ void MqttClient::resubscribe()
MqttError MqttClient::subscribe(Topic topic, uint8_t qos)
{
debug("subsribe(" << topic.c_str() << ")");
debug("MqttClient::subsribe(" << topic.c_str() << ")");
MqttError ret = MqttOk;
subscriptions.insert(topic);
@@ -372,6 +390,7 @@ MqttError MqttClient::subscribe(Topic topic, uint8_t qos)
MqttError MqttClient::unsubscribe(Topic topic)
{
debug("MqttClient::unsubscribe");
auto it=subscriptions.find(topic);
if (it != subscriptions.end())
{
@@ -386,6 +405,7 @@ MqttError MqttClient::unsubscribe(Topic topic)
MqttError MqttClient::sendTopic(const Topic& topic, MqttMessage::Type type, uint8_t qos)
{
debug("MqttClient::sendTopic");
MqttMessage msg(type, 2);
// TODO manage packet identifier
@@ -402,16 +422,7 @@ MqttError MqttClient::sendTopic(const Topic& topic, MqttMessage::Type type, uint
void MqttClient::processMessage(MqttMessage* mesg)
{
#ifdef TINY_MQTT_DEBUG
if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::Type::PingResp)
{
#ifdef NOT_ESP_CORE
Serial << "---> INCOMING " << _HEX(mesg->type()) << " client(" << (dbg_ptr)client << ':' << clientId << ") mem=" << " ESP.getFreeHeap() "<< endl;
#else
Serial << "---> INCOMING " << _HEX(mesg->type()) << " client(" << (dbg_ptr)client << ':' << clientId << ") mem=" << ESP.getFreeHeap() << endl;
#endif
// mesg->hexdump("Incoming");
mesg->hexdump("Incoming");
}
#endif
auto header = mesg->getVHeader();
const char* payload;
@@ -472,7 +483,7 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T
}
#ifdef TINY_MQTT_DEBUG
Serial << "Connected client:" << clientId.c_str() << ", keep alive=" << keep_alive << '.' << endl;
Console << yellow << "Client connected :" << clientId.c_str() << ", keep alive=" << keep_alive << '.' << white << endl;
#endif
bclose = false;
mqtt_connected=true;
@@ -507,12 +518,13 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T
if (client)
{
uint16_t pingreq = MqttMessage::Type::PingResp;
debug(cyan << "Ping response to client ");
client->write((const char*)(&pingreq), 2);
bclose = false;
}
else
{
debug("internal pingreq ?");
debug(red << "internal pingreq ?");
}
break;
@@ -569,7 +581,7 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T
case MqttMessage::Type::Publish:
#ifdef TINY_MQTT_DEBUG
Serial << "publish " << mqtt_connected << '/' << (long) client << endl;
Console << "publish " << mqtt_connected << '/' << (long) client << endl;
#endif
if (mqtt_connected or client == nullptr)
{
@@ -578,7 +590,9 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T
mesg->getString(payload, len);
Topic published(payload, len);
payload += len;
// Serial << "Received Publish (" << published.str().c_str() << ") size=" << (int)len
#ifdef TINY_MQTT_DEBUG
Console << "Received Publish (" << published.str().c_str() << ") size=" << (int)len << endl;
#endif
// << '(' << std::string(payload, len).c_str() << ')' << " msglen=" << mesg->length() << endl;
if (qos) payload+=2; // ignore packet identifier if any
len=mesg->end()-payload;
@@ -588,8 +602,8 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T
if (parent==nullptr or client==nullptr) // internal MqttClient receives publish
{
#ifdef TINY_MQTT_DEBUG
Serial << (isSubscribedTo(published) ? "not" : "") << " subscribed.\n";
Serial << "has " << (callback ? "" : "no ") << " callback.\n";
Console << (isSubscribedTo(published) ? "not" : "") << " subscribed.\n";
Console << "has " << (callback ? "" : "no ") << " callback.\n";
#endif
if (callback and isSubscribedTo(published))
{
@@ -620,10 +634,10 @@ if (mesg->type() != MqttMessage::Type::PingReq && mesg->type() != MqttMessage::T
if (bclose)
{
#ifdef TINY_MQTT_DEBUG
Serial << "*************** Error msg 0x" << _HEX(mesg->type());
Console << red << "*************** Error msg 0x" << _HEX(mesg->type());
mesg->hexdump("-------ERROR ------");
dump();
Serial << endl;
Console << white << endl;
#endif
close();
}
@@ -719,7 +733,7 @@ MqttError MqttClient::publishIfSubscribed(const Topic& topic, MqttMessage& msg)
{
MqttError retval=MqttOk;
debug("mqttclient publish " << subscriptions.size());
debug("mqttclient publishIfSubscribed " << topic.c_str() << ' ' << subscriptions.size());
if (isSubscribedTo(topic))
{
if (client)
@@ -729,7 +743,7 @@ MqttError MqttClient::publishIfSubscribed(const Topic& topic, MqttMessage& msg)
processMessage(&msg);
#ifdef TINY_MQTT_DEBUG
Serial << "Should call the callback ?\n";
Console << "Should call the callback ?\n";
#endif
// callback(this, topic, nullptr, 0); // TODO Payload
}
@@ -798,7 +812,7 @@ void MqttMessage::incoming(char in_byte)
case Complete:
default:
#ifdef TINY_MQTT_DEBUG
Serial << "Spurious " << _HEX(in_byte) << endl;
Console << red << "Spurious " << _HEX(in_byte) << white << endl;
hexdump("spurious");
#endif
reset();
@@ -824,6 +838,7 @@ void MqttMessage::add(const char* p, size_t len, bool addLength)
void MqttMessage::encodeLength()
{
debug("encodingLength");
if (state != Complete)
{
int length = buffer.size()-3; // 3 = 1 byte for header + 2 bytes for pre-reserved length field.
@@ -849,14 +864,14 @@ MqttError MqttMessage::sendTo(MqttClient* client)
{
if (buffer.size())
{
debug("sending " << buffer.size() << " bytes");
debug(cyan << "sending " << buffer.size() << " bytes to " << client->id());
encodeLength();
// hexdump("snd");
hexdump("Sending ");
client->write(&buffer[0], buffer.size());
}
else
{
debug("??? Invalid send");
debug(red << "??? Invalid send");
return MqttInvalidMessage;
}
return MqttOk;
@@ -866,6 +881,32 @@ void MqttMessage::hexdump(const char* prefix) const
{
(void)prefix;
#ifdef TINY_MQTT_DEBUG
if (TinyMqtt::debug<2) return;
static std::map<Type, std::string> tts={
{ Connect, "Connect" },
{ ConnAck, "Connack" },
{ Publish, "Publish" },
{ PubAck, "Puback" },
{ Subscribe, "Subscribe" },
{ SubAck, "Suback" },
{ UnSubscribe, "Unsubscribe" },
{ UnSuback, "Unsuback" },
{ PingReq, "Pingreq" },
{ PingResp, "Pingresp" },
{ Disconnect, "Disconnect" }
};
std::string t("Unknown");
Type typ=static_cast<Type>(buffer[0] & 0xF0);
if (tts.find(typ) != tts.end())
t=tts[typ];
Console.fg(cyan);
#ifdef NOT_ESP_CORE
Console << "---> MESSAGE " << t << ' ' << _HEX(typ) << ' ' << (Complete ? "complete" : "uncomplete") << " mem=???" << endl;
#else
Console << "---> MESSAGE " << t << ' ' << _HEX(typ) << ' ' << (Complete ? "complete" : "uncomplete") << " mem=" << ESP.getFreeHeap() << endl;
#endif
Console.fg(white);
uint16_t addr=0;
const int bytes_per_row = 8;
const char* hex_to_str = " | ";
@@ -873,19 +914,19 @@ void MqttMessage::hexdump(const char* prefix) const
const char* half_sep = " - ";
std::string ascii;
Serial << prefix << " size(" << buffer.size() << "), state=" << state << endl;
Console << prefix << " size(" << buffer.size() << "), state=" << state << endl;
for(const char chr: buffer)
{
if ((addr % bytes_per_row) == 0)
{
if (ascii.length()) Serial << hex_to_str << ascii << separator << endl;
if (prefix) Serial << prefix << separator;
if (ascii.length()) Console << hex_to_str << ascii << separator << endl;
if (prefix) Console << prefix << separator;
ascii.clear();
}
addr++;
if (chr<16) Serial << '0';
Serial << _HEX(chr) << ' ';
if (chr<16) Console << '0';
Console << _HEX(chr) << ' ';
ascii += (chr<32 ? '.' : chr);
if (ascii.length() == (bytes_per_row/2)) ascii += half_sep;
@@ -894,12 +935,12 @@ void MqttMessage::hexdump(const char* prefix) const
{
while(ascii.length() < bytes_per_row+strlen(half_sep))
{
Serial << " "; // spaces per hexa byte
Console << " "; // spaces per hexa byte
ascii += ' ';
}
Serial << hex_to_str << ascii << separator;
Console << hex_to_str << ascii << separator;
}
Serial << endl;
Console << endl;
#endif
}

View File

@@ -34,10 +34,14 @@
#include "StringIndexer.h"
#include <MqttStreaming.h>
// #define TINY_MQTT_DEBUG
#ifdef TINY_MQTT_DEBUG
#define debug(what) { Serial << (int)__LINE__ << ' ' << what << endl; delay(100); }
#include <TinyConsole.h> // https://github.com/hsaturn/TinyConsole
struct TinyMqtt
{
static int debug;
};
#define debug(what) { if (TinyMqtt::debug>=1) Console << (int)__LINE__ << ' ' << what << TinyConsole::white << endl; delay(100); }
#else
#define debug(what) {}
#endif
@@ -176,7 +180,9 @@ class MqttClient
(parent!=nullptr and client==nullptr) or
(client and client->connected()); }
void write(const char* buf, size_t length)
{ if (client) client->write(buf, length); }
{
if (client) client->write(buf, length);
}
const std::string& id() const { return clientId; }
void id(std::string& new_id) { clientId = new_id; }
@@ -188,7 +194,7 @@ class MqttClient
{
callback=fun;
#ifdef TINY_MQTT_DEBUG
Serial << "Callback set to " << (long)fun << endl;
Console << TinyConsole::magenta << "Callback set to " << (long)fun << TinyConsole::white << endl;
if (callback) callback(this, "test/topic", "value", 5);
#endif
};
@@ -213,22 +219,29 @@ class MqttClient
(void)indent;
#ifdef TINY_MQTT_DEBUG
uint32_t ms=millis();
Serial << indent << "+-- " << '\'' << clientId.c_str() << "' " << (connected() ? " ON " : " OFF");
Serial << ", alive=" << alive << '/' << ms << ", ka=" << keep_alive << ' ';
Serial << (client && client->connected() ? "" : "dis") << "connected";
Console << indent << "+-- " << '\'' << clientId.c_str() << "' " << (connected() ? " ON " : " OFF");
Console << ", alive=" << alive << '/' << ms << ", ka=" << keep_alive << ' ';
if (client)
{
if (client->connected())
Console << TinyConsole::green << "connected";
else
Console << TinyConsole::red << "disconnected";
Console << TinyConsole::white;
}
if (subscriptions.size())
{
bool c = false;
Serial << " [";
Console << " [";
for(auto s: subscriptions)
{
if (c) Serial << ", ";
Serial << s.str().c_str();
if (c) Console << ", ";
Console << s.str().c_str();
c=true;
}
Serial << ']';
Console << ']';
}
Serial << endl;
Console << TinyConsole::erase_to_end << endl;
#endif
}
@@ -256,7 +269,7 @@ class MqttClient
bool mqtt_connected = false;
char mqtt_flags;
uint32_t keep_alive = 60;
uint32_t keep_alive = 30;
uint32_t alive;
MqttMessage message;
@@ -319,7 +332,7 @@ class MqttBroker
bool compareString(const char* good, const char* str, uint8_t str_len) const;
std::vector<MqttClient*> clients;
TcpServer* server;
TcpServer* server = nullptr;
const char* auth_user = "guest";
const char* auth_password = "guest";