diff --git a/platformio.ini b/platformio.ini index 11ad2ab..2ebb608 100644 --- a/platformio.ini +++ b/platformio.ini @@ -53,6 +53,8 @@ monitor_baud = ${common.monitor_baud} framework = ${common.framework} lib_deps = ${common.lib_deps} painlessMesh + ESP8266mDNS + ArduinoOTA [env:meshMqttBridge] src_filter = +<*> - + diff --git a/src/Plugin.h b/src/Plugin.h index c331e60..c046e3e 100644 --- a/src/Plugin.h +++ b/src/Plugin.h @@ -3,13 +3,16 @@ #include #include +#include class Plugin { protected: Scheduler* scheduler; public: - virtual void enable(Scheduler*, Network*); + virtual void setup(Scheduler*, Network*); + virtual void enable(); virtual void disable(); + virtual void onMessage(MeshMessage msg); }; #endif \ No newline at end of file diff --git a/src/base/MeshMessage.h b/src/base/MeshMessage.h new file mode 100644 index 0000000..6eb8240 --- /dev/null +++ b/src/base/MeshMessage.h @@ -0,0 +1,77 @@ +#ifndef __MESH_MESSAGE__ +#define __MESH_MESSAGE__ + +#include +#include + +#define JSON_DOMAIN "domain" +#define JSON_FROM "from" +#define JSON_TO "target" +#define JSON_MSG "msg" + +struct MeshMessage { + String domain; + String to; + String from; + String msg; + enum MeshMessageType { NONE, SYSTEM, OTA } type; + int valid = 0; + // ------------------------------------------------------------------------------------------ + void init() { + //from = reinterpret_cast(ESP.getChipId()); + } + int verifyJsonObject(JsonObject& json){ + return json.success() + //&& json.containsKey(JSON_DOMAIN) + //&& json.containsKey(JSON_TO) + //&& json.containsKey(JSON_FROM) + && json.containsKey(JSON_MSG); + }; + String toJsonString(){ + //StaticJsonBuffer<200> jsonBuffer; + DynamicJsonBuffer jsonBuffer(JSON_ARRAY_SIZE(300)); + JsonObject& root = jsonBuffer.createObject(); + root[JSON_DOMAIN] = domain; + root[JSON_TO] = to; + root[JSON_FROM] = from; + root[JSON_MSG] = msg; + String jsonString; + root.printTo(jsonString); + return jsonString; + } + String getAttrFromJson(JsonObject& json, const char* attr){ + if(json.containsKey(attr)){ + return json[attr]; + } + return ""; + } + int getIntAttrFromJson(JsonObject& json, const char* attr){ + if(json.containsKey(attr)){ + return json[attr]; + } + return 0; + } + // Map a json object to this struct. + void fromJsonObject(JsonObject& json){ + if(!verifyJsonObject(json)){ + Serial.println("ERROR: cannot parse MeshMessage JSON object"); + valid = 0; + //return; + } + domain = getAttrFromJson(json, JSON_DOMAIN); + to = getAttrFromJson(json, JSON_TO); + from = getAttrFromJson(json, JSON_FROM); + msg = getAttrFromJson(json, JSON_MSG); + type = (MeshMessageType) getIntAttrFromJson(json, "type"); + valid = 1; + }; + // Parse a json string and map parsed object + void fromJsonString(String& str){ + //StaticJsonBuffer<200> jsonBuffer; + DynamicJsonBuffer jsonBuffer(JSON_ARRAY_SIZE(300)); + JsonObject& json = jsonBuffer.parseObject(str); + fromJsonObject(json); + }; +}; + +#endif \ No newline at end of file diff --git a/src/base/MeshSprocket.h b/src/base/MeshSprocket.h index 085bd06..9bed0ab 100644 --- a/src/base/MeshSprocket.h +++ b/src/base/MeshSprocket.h @@ -2,9 +2,11 @@ #define __MESH_SPROCKET__ #define DEBUG_ESP_OTA +#include #include #include #include +#include #include #include "config.h" @@ -14,17 +16,37 @@ using namespace std::placeholders; class MeshSprocket : public Sprocket { public: MeshNet* net; - OtaTcpPlugin* ota; + std::vector plugins; MeshSprocket(SprocketConfig cfg, OtaConfig otaCfg) : Sprocket(cfg) { - ota = new OtaTcpPlugin(otaCfg); + addPlugin(new OtaTcpPlugin(otaCfg)); } + void addPlugin(Plugin* p){ + plugins.reserve(1); + plugins.push_back(p); + } + + void setupPlugins(Scheduler* scheduler, Network* network){ + for(Plugin* p : plugins){ + p->setup(scheduler, network); + } + } + + void dispatchMessageToPlugins(MeshMessage msg){ + for(Plugin* p : plugins){ + if(msg.type != MeshMessage::NONE){ + Serial.println("dispatch to plugins"); + p->onMessage(msg); + } + } + } + Sprocket* activate(Scheduler* scheduler, Network* network) { net = static_cast(network); net->onReceive(bind(&MeshSprocket::dispatch,this, _1, _2)); - // enable plugins - ota->enable(scheduler, network); + // setup plugins + setupPlugins(scheduler, network); return this; } using Sprocket::activate; @@ -34,6 +56,11 @@ class MeshSprocket : public Sprocket { void dispatch( uint32_t from, String &msg ) { // TODO handle OTA before passing to onMessage + MeshMessage mMsg; + mMsg.fromJsonString(msg); + if(mMsg.valid){ + dispatchMessageToPlugins(mMsg); + } onMessage(from, msg); } diff --git a/src/examples/mesh/MeshApp.cpp b/src/examples/mesh/MeshApp.cpp index 81150a6..cb44b72 100644 --- a/src/examples/mesh/MeshApp.cpp +++ b/src/examples/mesh/MeshApp.cpp @@ -28,8 +28,13 @@ class MeshApp : public MeshSprocket { } using MeshSprocket::activate; void heartbeat(MeshNet* network){ - String msg = "{ \"payload \": 1 }"; - network->mesh.sendBroadcast(msg, true); + MeshMessage msg; // = { "wirelos", "broadcast", "local", "alive", 0, }; + msg.domain = "wirelos"; + msg.to = "broadcast"; + msg.msg = "alive"; + String msgStr = msg.toJsonString(); + //String msg = "{ \"domain\": \"wirelos\",\"from\": \"0\",\"target\": \"broadcast\", \"msg \": \"alive\" }"; + network->mesh.sendBroadcast(msgStr, true); } void onMessage( uint32_t from, String &msg ) { Serial.printf("MeshApp onMessage: received from %u msg=%s\n", from, msg.c_str()); diff --git a/src/examples/mesh/config.h b/src/examples/mesh/config.h index ab23017..f958da0 100644 --- a/src/examples/mesh/config.h +++ b/src/examples/mesh/config.h @@ -10,15 +10,15 @@ #define STARTUP_DELAY 3000 // Mesh config -#define STATION_MODE 0 +#define STATION_MODE 1 #define WIFI_CHANNEL 11 #define MESH_PORT 5555 #define MESH_PREFIX "whateverYouLike" #define MESH_PASSWORD "somethingSneaky" -#define STATION_SSID "Th1ngs4P" -#define STATION_PASSWORD "th3r31sn0sp00n" +#define STATION_SSID "tErAx1d" +#define STATION_PASSWORD "ramalamadingdong" #define HOSTNAME "mesh-node" -#define MESH_DEBUG_TYPES ERROR | STARTUP | CONNECTION +#define MESH_DEBUG_TYPES ERROR | STARTUP //ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE // OTA config diff --git a/src/plugins/OtaTcpPlugin.cpp b/src/plugins/OtaTcpPlugin.cpp index 6ff0a1b..4f2d73f 100644 --- a/src/plugins/OtaTcpPlugin.cpp +++ b/src/plugins/OtaTcpPlugin.cpp @@ -18,21 +18,31 @@ class OtaTcpPlugin : public Plugin { private: OtaConfig config; Task otaTask; + MeshNet* network; public: OtaTcpPlugin(OtaConfig cfg){ config = cfg; + } - void enable(Scheduler* userScheduler, Network* network){ - scheduler = userScheduler; - - // connect to network - if(!network->isConnected()){ - // TODO when config is refactored, cast is not necessary anymore - static_cast(network)->config.stationMode = 1; - network->connectStation(); - // TODO set service message to mesh to announce station IP - } + void connectUpdateNetwork(Network* network) { + // if(!network->isConnected()){ + // static_cast(network)->config.stationMode = 1; + // } + network->connectStation(); + } + void enable() { + ArduinoOTA.begin(); + otaTask.enable(); + } + void onMessage(MeshMessage msg) { + //enable(); + Serial.println("OTA msg received"); + } + void setup(Scheduler* userScheduler, Network* network){ + // connect done in network class + //connectUpdateNetwork(network); // setup task + scheduler = userScheduler; otaTask.set(TASK_MILLISECOND * 100, TASK_FOREVER, [](){ ArduinoOTA.handle(); }); @@ -62,8 +72,7 @@ class OtaTcpPlugin : public Plugin { else if (error == OTA_RECEIVE_ERROR) Serial.println("OTA: Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("OTA: End Failed"); }); - ArduinoOTA.begin(); - otaTask.enable(); + enable(); } void disable(){ otaTask.disable();