Rewrite interpreter, can handle brokers now
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local broker that accept connections
|
* Console allowing to make any kind of test.
|
||||||
*
|
*
|
||||||
* pros - Reduces internal latency (when publish is received by the same ESP)
|
* pros - Reduces internal latency (when publish is received by the same ESP)
|
||||||
* - Reduces wifi traffic
|
* - Reduces wifi traffic
|
||||||
@@ -25,11 +25,13 @@
|
|||||||
|
|
||||||
std::string topic="sensor/temperature";
|
std::string topic="sensor/temperature";
|
||||||
|
|
||||||
MqttBroker broker(1883);
|
|
||||||
|
|
||||||
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)
|
||||||
{ Serial << "--> " << srce->id().c_str() << ": ======> received " << topic.c_str() << endl; }
|
{ Serial << "--> " << srce->id().c_str() << ": ======> received " << topic.c_str() << endl; }
|
||||||
|
|
||||||
|
std::map<std::string, MqttClient*> clients;
|
||||||
|
std::map<std::string, MqttBroker*> brokers;
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
@@ -46,7 +48,21 @@ void setup()
|
|||||||
|
|
||||||
Serial << "Connected to " << ssid << "IP address: " << WiFi.localIP() << endl;
|
Serial << "Connected to " << ssid << "IP address: " << WiFi.localIP() << endl;
|
||||||
|
|
||||||
broker.begin();
|
MqttBroker* broker = new MqttBroker(1883);
|
||||||
|
broker->begin();
|
||||||
|
brokers["broker"] = broker;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getint(std::string& str, const int if_empty=0, char sep=' ')
|
||||||
|
{
|
||||||
|
std::string sword;
|
||||||
|
while(str.length() && str[0]!=sep)
|
||||||
|
{
|
||||||
|
sword += str[0]; str.erase(0,1);
|
||||||
|
}
|
||||||
|
while(str[0]==sep) str.erase(0,1);
|
||||||
|
if (if_empty and sword.length()==0) sword=if_empty;
|
||||||
|
return atoi(sword.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getword(std::string& str, const char* if_empty=nullptr, char sep=' ')
|
std::string getword(std::string& str, const char* if_empty=nullptr, char sep=' ')
|
||||||
@@ -128,7 +144,7 @@ class automatic
|
|||||||
autop->bon=false;
|
autop->bon=false;
|
||||||
else if (s=="interval")
|
else if (s=="interval")
|
||||||
{
|
{
|
||||||
int32_t i=atol(getword(cmd).c_str());
|
int32_t i=getint(cmd);
|
||||||
if (i)
|
if (i)
|
||||||
autop->interval(atol(s.c_str()));
|
autop->interval(atol(s.c_str()));
|
||||||
else
|
else
|
||||||
@@ -181,35 +197,12 @@ bool compare(std::string s, const char* cmd)
|
|||||||
return strncmp(cmd, s.c_str(), s.length())==0;
|
return strncmp(cmd, s.c_str(), s.length())==0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, MqttClient*> clients;
|
|
||||||
|
|
||||||
using ClientFunction = void(*)(std::string& cmd, MqttClient* publish);
|
using ClientFunction = void(*)(std::string& cmd, MqttClient* publish);
|
||||||
|
|
||||||
void clientCommand(std::string& cmd, ClientFunction func, bool canBeNull=false)
|
|
||||||
{
|
|
||||||
std::string s=getword(cmd);
|
|
||||||
bool found = clients.find(s) != clients.end();
|
|
||||||
|
|
||||||
if (canBeNull && found==false)
|
|
||||||
{
|
|
||||||
cmd += ' ' + s;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found or canBeNull)
|
|
||||||
{
|
|
||||||
MqttClient* publish = publish = clients[s];
|
|
||||||
func(cmd, publish);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial << "client not found (" << s.c_str() << ")" << endl;
|
|
||||||
cmd="";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
broker.loop();
|
for(auto it: brokers)
|
||||||
|
it.second->loop();
|
||||||
|
|
||||||
for(auto it: clients)
|
for(auto it: clients)
|
||||||
it.second->loop();
|
it.second->loop();
|
||||||
@@ -223,7 +216,7 @@ void loop()
|
|||||||
|
|
||||||
if (c==10 or c==14)
|
if (c==10 or c==14)
|
||||||
{
|
{
|
||||||
Serial << "------------------------------------------------------" << endl;
|
Serial << "----------------[ " << cmd.c_str() << " ]--------------" << endl;
|
||||||
static std::string last_cmd;
|
static std::string last_cmd;
|
||||||
if (cmd=="!")
|
if (cmd=="!")
|
||||||
cmd=last_cmd;
|
cmd=last_cmd;
|
||||||
@@ -232,93 +225,169 @@ void loop()
|
|||||||
while(cmd.length())
|
while(cmd.length())
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
|
MqttBroker* broker = nullptr;
|
||||||
|
MqttClient* client = nullptr;
|
||||||
|
|
||||||
// client.function notation
|
// client.function notation
|
||||||
// ("a.fun " becomes "fun a ")
|
// ("a.fun " becomes "fun a ")
|
||||||
if (cmd.find('.') != std::string::npos)
|
if (cmd.find('.') != std::string::npos)
|
||||||
{
|
{
|
||||||
std::string copy(cmd);
|
s=getword(cmd, nullptr, '.');
|
||||||
s=getword(copy, nullptr, '.');
|
|
||||||
|
|
||||||
if (clients.find(s) != clients.end())
|
if (clients.find(s) != clients.end())
|
||||||
{
|
{
|
||||||
std::string s2 = getword(copy);
|
client = clients[s];
|
||||||
cmd=s2+' '+s+' '+copy;
|
}
|
||||||
|
else if (brokers.find(s) != brokers.end())
|
||||||
|
{
|
||||||
|
broker = brokers[s];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial << "Unknown client (" << s.c_str() << ")" << endl;
|
Serial << "Unknown class (" << s.c_str() << ")" << endl;
|
||||||
cmd="";
|
cmd="";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s = getword(cmd);
|
s = getword(cmd);
|
||||||
if (compare(s,"connect"))
|
if (broker)
|
||||||
{
|
{
|
||||||
clientCommand(cmd, [](std::string& cmd, MqttClient* publish)
|
if (compare(s,"connect"))
|
||||||
{ publish->connect(getword(cmd,"192.168.1.40").c_str(), 1883);
|
{
|
||||||
Serial << (publish->connected() ? "connected." : "not connected") << endl;
|
Serial << "NYI" << endl;
|
||||||
});
|
}
|
||||||
|
else if (compare(s, "view"))
|
||||||
|
{
|
||||||
|
broker->dump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (client)
|
||||||
|
{
|
||||||
|
if (compare(s,"connect"))
|
||||||
|
{
|
||||||
|
client->connect(getword(cmd,"192.168.1.40").c_str(), 1883);
|
||||||
|
Serial << (client->connected() ? "connected." : "not connected") << endl;
|
||||||
|
}
|
||||||
|
else if (compare(s,"publish"))
|
||||||
|
{
|
||||||
|
client->publish(getword(cmd, topic.c_str()));
|
||||||
|
}
|
||||||
|
else if (compare(s,"subscribe"))
|
||||||
|
{
|
||||||
|
client->subscribe(getword(cmd, topic.c_str()));
|
||||||
|
}
|
||||||
|
else if (compare(s, "view"))
|
||||||
|
{
|
||||||
|
client->dump();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (compare(s,"publish"))
|
if (compare(s, "delete"))
|
||||||
{
|
{
|
||||||
clientCommand(cmd, [](std::string& cmd, MqttClient* publish)
|
if (client==nullptr && broker==nullptr)
|
||||||
{ publish->publish(getword(cmd, topic.c_str())); });
|
{
|
||||||
}
|
s = getword(cmd);
|
||||||
else if (compare(s,"subscribe"))
|
if (clients.find(s) != clients.end())
|
||||||
{
|
{
|
||||||
clientCommand(cmd, [](std::string& cmd, MqttClient* publish)
|
client = clients[s];
|
||||||
{ publish->subscribe(getword(cmd, topic.c_str())); });
|
}
|
||||||
}
|
else if (brokers.find(s) != brokers.end())
|
||||||
else if (compare(s, "view"))
|
{
|
||||||
{
|
broker = brokers[s];
|
||||||
clientCommand(cmd, [](std::string& cmd, MqttClient* publish)
|
}
|
||||||
{ publish->dump(); });
|
else
|
||||||
|
Serial << "Unable to find (" << s.c_str() << ")" << endl;
|
||||||
|
}
|
||||||
|
if (client)
|
||||||
|
{
|
||||||
|
clients.erase(s);
|
||||||
|
for (auto it: clients)
|
||||||
|
{
|
||||||
|
if (it.second != client) continue;
|
||||||
|
Serial << "deleted" << endl;
|
||||||
|
clients.erase(it.first);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cmd += " ls";
|
||||||
|
}
|
||||||
|
else if (broker)
|
||||||
|
{
|
||||||
|
for(auto it: brokers)
|
||||||
|
{
|
||||||
|
Serial << (int32_t)it.second << '/' << (int32_t)broker << endl;
|
||||||
|
if (broker != it.second) continue;
|
||||||
|
Serial << "deleted" << endl;
|
||||||
|
brokers.erase(it.first);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cmd += " ls";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Serial << "Nothing to delete" << endl;
|
||||||
}
|
}
|
||||||
else if (compare(s, "auto"))
|
else if (compare(s, "auto"))
|
||||||
{
|
{
|
||||||
clientCommand(cmd, [](std::string& cmd, MqttClient* publish)
|
automatic::command(client, cmd);
|
||||||
{ automatic::command(publish, cmd);
|
if (client == nullptr)
|
||||||
if (publish == nullptr)
|
cmd.clear();
|
||||||
cmd.clear();
|
|
||||||
}, true);
|
|
||||||
}
|
}
|
||||||
else if (compare(s, "new"))
|
else if (compare(s, "broker"))
|
||||||
{
|
{
|
||||||
std::string id=getword(cmd);
|
std::string id=getword(cmd);
|
||||||
if (id.length())
|
if (id.length() or brokers.find(id)!=brokers.end())
|
||||||
{
|
{
|
||||||
MqttClient* client = new MqttClient(&broker);
|
int port=getint(cmd, 0);
|
||||||
|
if (port)
|
||||||
|
{
|
||||||
|
MqttBroker* broker = new MqttBroker(port);
|
||||||
|
broker->begin();
|
||||||
|
|
||||||
|
brokers[id] = broker;
|
||||||
|
Serial << "new broker (" << id.c_str() << ")" << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Serial << "Missing port" << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Serial << "Missing or existing broker name (" << id.c_str() << ")" << endl;
|
||||||
|
cmd+=" ls";
|
||||||
|
}
|
||||||
|
else if (compare(s, "client"))
|
||||||
|
{
|
||||||
|
std::string id=getword(cmd);
|
||||||
|
if (id.length() or clients.find(id)!=clients.end())
|
||||||
|
{
|
||||||
|
MqttBroker* broker = nullptr;
|
||||||
|
|
||||||
|
// TODO cmd line broker name
|
||||||
|
if (brokers.size()==1) broker = brokers.begin()->second;
|
||||||
|
Serial << "broker=" << (int32_t)broker << endl;
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
MqttClient* client = new MqttClient(broker);
|
||||||
client->id(id);
|
client->id(id);
|
||||||
clients[id]=client;
|
clients[id]=client;
|
||||||
client->setCallback(onPublish);
|
client->setCallback(onPublish);
|
||||||
client->subscribe(topic);
|
client->subscribe(topic);
|
||||||
|
Serial << "new client (" << id.c_str() << ")" << endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Serial << "missing id" << endl;
|
Serial << "Missing or existing client name" << endl;
|
||||||
cmd+=" ls";
|
cmd+=" ls";
|
||||||
}
|
}
|
||||||
else if (compare(s, "delete"))
|
else if (compare(s, "ls") or compare(s, "view"))
|
||||||
{
|
{
|
||||||
s = getword(cmd);
|
Serial << "--< " << clients.size() << " client/s. >--" << endl;
|
||||||
auto it=clients.find(s);
|
|
||||||
if (it != clients.end())
|
|
||||||
{
|
|
||||||
delete it->second;
|
|
||||||
clients.erase(it);
|
|
||||||
cmd+=" ls";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Serial << "Unknown client (" << s.c_str() << ")" << endl;
|
|
||||||
}
|
|
||||||
else if (compare(s, "ls"))
|
|
||||||
{
|
|
||||||
Serial << "main : " << clients.size() << " client/s." << endl;
|
|
||||||
for(auto it: clients)
|
for(auto it: clients)
|
||||||
{
|
{
|
||||||
Serial << " "; it.second->dump();
|
Serial << " "; it.second->dump();
|
||||||
}
|
}
|
||||||
broker.dump();
|
|
||||||
|
Serial << "--< " << brokers.size() << " brokers/s. >--" << endl;
|
||||||
|
for(auto it: brokers)
|
||||||
|
{
|
||||||
|
Serial << " ==[ Broker: " << it.first.c_str() << " ]== ";
|
||||||
|
it.second->dump();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (compare(s, "reset"))
|
else if (compare(s, "reset"))
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
@@ -327,11 +396,17 @@ void loop()
|
|||||||
else if (compare(s,"help"))
|
else if (compare(s,"help"))
|
||||||
{
|
{
|
||||||
Serial << "syntax:" << endl;
|
Serial << "syntax:" << endl;
|
||||||
Serial << " new/delete $id" << endl;
|
Serial << " MqttBroker:" << endl;
|
||||||
Serial << " connect $id [ip]" << endl;
|
Serial << " broker {name} {port} : create a new broker" << endl;
|
||||||
Serial << " subscribe $id [topic]" << endl;
|
Serial << endl;
|
||||||
Serial << " publish $id [topic]" << endl;
|
Serial << " MqttClient:" << endl;
|
||||||
Serial << " view $id " << endl;
|
Serial << " client {name} : create a client then" << endl;
|
||||||
|
Serial << " name.connect [ip]" << endl;
|
||||||
|
Serial << " name.subscribe [topic]" << endl;
|
||||||
|
Serial << " name.publish [topic]" << endl;
|
||||||
|
Serial << " name.view" << endl;
|
||||||
|
Serial << " name.delete" << endl;
|
||||||
|
|
||||||
automatic::help();
|
automatic::help();
|
||||||
Serial << endl;
|
Serial << endl;
|
||||||
Serial << " help" << endl;
|
Serial << " help" << endl;
|
||||||
@@ -341,8 +416,6 @@ void loop()
|
|||||||
Serial << " $id : name of the client." << endl;
|
Serial << " $id : name of the client." << endl;
|
||||||
Serial << " default topic is '" << topic.c_str() << "'" << endl;
|
Serial << " default topic is '" << topic.c_str() << "'" << endl;
|
||||||
Serial << endl;
|
Serial << endl;
|
||||||
Serial << " 'function client args' can be written 'client.function args'" << endl;
|
|
||||||
Serial << endl;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user