diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4d3bbe9..33506d2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -38,6 +38,7 @@ firmware-build:
- pio run --environment basic
- pio run --environment mesh
- pio run --environment meshMqttBridge
+ - pio run --environment standalone
artifacts:
paths:
- .pioenvs/*/firmware.*
diff --git a/data/config.json b/data/config.json
index c7e58b1..ead392c 100644
--- a/data/config.json
+++ b/data/config.json
@@ -4,7 +4,10 @@
"meshPort": 5555,
"meshSSID": "whateverYouLike",
"meshPassword": "somethingSneaky",
+ "apSSID": "MyAP",
+ "apPassword": "myApPwd",
"stationSSID": "tErAx1d",
"stationPassword": "ramalamadingdong",
- "hostname": "dbuggy"
+ "hostname": "dbuggy",
+ "connectTimeout": 10000
}
\ No newline at end of file
diff --git a/data/example.config.json b/data/example.config.json
index e20959f..91562a2 100644
--- a/data/example.config.json
+++ b/data/example.config.json
@@ -6,5 +6,6 @@
"meshPassword": "th3r31sn0sp00n",
"stationSSID": "MyAP",
"stationPassword": "myApPassword",
- "hostname": "mesh-node"
+ "hostname": "mesh-node",
+ "connectTimeout": 10000
}
\ No newline at end of file
diff --git a/platformio.ini b/platformio.ini
index 7a26082..db1c121 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -70,4 +70,16 @@ monitor_baud = ${common.monitor_baud}
framework = ${common.framework}
lib_deps = ${common.lib_deps}
painlessMesh
- PubSubClient
\ No newline at end of file
+ PubSubClient
+
+
+[env:standalone]
+src_filter = +<*> - +
+platform = ${common.platform}
+board = ${common.board}
+upload_speed = ${common.upload_speed}
+monitor_baud = ${common.monitor_baud}
+framework = ${common.framework}
+lib_deps = ${common.lib_deps}
+ ArduinoOTA
+ ESP Async WebServer
\ No newline at end of file
diff --git a/src/MeshNet.cpp b/src/MeshNet.cpp
index 2160e6f..aa28adf 100644
--- a/src/MeshNet.cpp
+++ b/src/MeshNet.cpp
@@ -29,13 +29,14 @@ Network* MeshNet::init(){
return this;
}
-Network* MeshNet::connectStation(int doConnect) {
+int MeshNet::connectStation(int doConnect) {
if(doConnect){
Serial.println("connect station");
mesh.stationManual(config.stationSSID, config.stationPassword);
mesh.setHostname(config.hostname.c_str());
+ return 1;
}
- return this;
+ return 0;
}
void MeshNet::sendTo(uint32_t target, String msg){
mesh.sendSingle(target, msg);
diff --git a/src/MeshNet.h b/src/MeshNet.h
index 6996b1c..6ff9463 100644
--- a/src/MeshNet.h
+++ b/src/MeshNet.h
@@ -22,7 +22,7 @@ class MeshNet : public Network {
MeshSprocketConfig config;
MeshNet(MeshConfig cfg);
Network* init();
- Network* connectStation(int);
+ int connectStation(int);
void configure(MeshSprocketConfig cfg);
void update();
void newConnectionCallback(uint32_t nodeId);
diff --git a/src/Network.h b/src/Network.h
index d559959..62bbec9 100644
--- a/src/Network.h
+++ b/src/Network.h
@@ -12,13 +12,13 @@ class Network {
Scheduler* scheduler;
virtual Network* init() { return this; };
virtual Network* init(Scheduler* s) { scheduler = s; return init(); };
- virtual Network* connect() { return this; };
- virtual Network* connectStation() { return this; };
+ virtual int connect() { return 0; };
+ virtual int connectStation() { return 0; };
virtual int isConnected(){ return 0; };
virtual void update() {};
virtual void broadcast(String msg){};
virtual void sendTo(uint32_t target, String msg) {};
- virtual void onReceive(std::function);
+ virtual void onReceive(std::function) {};
Network* setScheduler(Scheduler* s) {
scheduler = s;
return this;
diff --git a/src/Sprocket.h b/src/Sprocket.h
index d13b4b7..94d39a8 100644
--- a/src/Sprocket.h
+++ b/src/Sprocket.h
@@ -2,6 +2,7 @@
#define __SPROCKET_H__
#include
+//#include
#include
#include
#include "FS.h"
diff --git a/src/WiFiNet.cpp b/src/WiFiNet.cpp
new file mode 100644
index 0000000..039fb43
--- /dev/null
+++ b/src/WiFiNet.cpp
@@ -0,0 +1,77 @@
+#include "WiFiNet.h"
+
+WiFiNet::WiFiNet(
+ int stationMode,
+ const char* stationSSID,
+ const char* stationPassword,
+ const char* apSSID,
+ const char* apPassword,
+ const char* hostname,
+ int connectTimeout){
+ config.stationMode = stationMode;
+ config.stationSSID = String(stationSSID);
+ config.stationPassword = String(stationPassword);
+ config.apSSID = String(apSSID);
+ config.apPassword = String(apPassword);
+ config.hostname = String(hostname);
+ config.connectTimeout = connectTimeout;
+}
+
+Network* WiFiNet::init() {
+ config.fromFile("/config.json");
+ return this;
+}
+int WiFiNet::connect(){
+ if(config.valid){
+ WiFi.hostname(config.hostname);
+ Serial.println("Hostname: " + config.hostname);
+ if(!connectStation()) {
+ createAccessPoint();
+ }
+ startDNS();
+ }
+ return 1;
+}
+
+int WiFiNet::connectStation(){
+ if(config.stationMode == 0) return 0;
+
+ int wifiConnectStart = millis();
+ WiFi.mode(WIFI_STA);
+ WiFi.begin(config.stationSSID.c_str(), config.stationPassword.c_str());
+ Serial.println("connect to " + config.stationSSID);
+
+ while (WiFi.status() != WL_CONNECTED) {
+ delay(500);
+ Serial.print(".");
+ if(millis() - wifiConnectStart >= (uint)config.connectTimeout) {
+ Serial.println("wifi connect timeout");
+ return 0;
+ }
+ }
+ Serial.println("IP address: " + WiFi.localIP().toString());
+ Serial.println(WiFi.localIP().toString());
+ return 1;
+}
+
+int WiFiNet::createAccessPoint(){
+ Serial.println("Starting SoftAP: " + String(config.apSSID));
+ WiFi.disconnect();
+ WiFi.mode(WIFI_AP);
+ WiFi.softAP(config.apSSID.c_str(), config.apPassword.c_str());
+ Serial.println("SoftAP started! IP address: ");
+ Serial.println(WiFi.softAPIP().toString());
+ return 1;
+}
+
+// TODO make user configurable services
+int WiFiNet::startDNS() {
+ if (!MDNS.begin(config.hostname.c_str())) {
+ Serial.println("Error setting up MDNS responder!");
+ return 0;
+ } else {
+ Serial.println("mDNS responder started");
+ MDNS.addService("http", "tcp", 80);
+ }
+ return 1;
+}
\ No newline at end of file
diff --git a/src/WiFiNet.h b/src/WiFiNet.h
new file mode 100644
index 0000000..ffe23e7
--- /dev/null
+++ b/src/WiFiNet.h
@@ -0,0 +1,75 @@
+#ifndef __WIFI_NET__
+#define __WIFI_NET__
+
+#include
+#include
+
+#ifdef ESP32
+#include
+#elif defined(ESP8266)
+#include
+#endif // ESP32
+
+#include "Network.h"
+
+#include
+#include
+#include "JsonStruct.h"
+using namespace std;
+using namespace std::placeholders;
+
+#define JSON_stationMode "stationMode"
+#define JSON_stationSSID "stationSSID"
+#define JSON_apPassword "apPassword"
+#define JSON_apSSID "apSSID"
+#define JSON_stationPassword "stationPassword"
+#define JSON_hostname "hostname"
+#define JSON_connect_timeout "connectTimeout"
+
+struct WiFiConfig : public JsonStruct {
+ int stationMode;
+ String stationSSID;
+ String stationPassword;
+ String apSSID;
+ String apPassword;
+ String hostname;
+ int connectTimeout;
+
+ void mapJsonObject(JsonObject& root) {
+ root[JSON_stationMode] = stationMode;
+ root[JSON_stationSSID] = stationSSID;
+ root[JSON_stationPassword] = stationPassword;
+ root[JSON_apSSID] = apSSID;
+ root[JSON_apPassword] = apPassword;
+ root[JSON_hostname] = hostname;
+ root[JSON_connect_timeout] = connectTimeout;
+ }
+
+ // Map a json object to this struct.
+ void fromJsonObject(JsonObject& json) {
+ stationMode = getIntAttrFromJson(json, JSON_stationMode, stationMode);
+ stationSSID = getAttrFromJson(json, JSON_stationSSID, stationSSID);
+ stationPassword = getAttrFromJson(json, JSON_stationPassword, stationPassword);
+ apSSID = getAttrFromJson(json, JSON_apSSID, apSSID);
+ apPassword = getAttrFromJson(json, JSON_apPassword, apPassword);
+ hostname = getAttrFromJson(json, JSON_hostname, hostname);
+ connectTimeout = getIntAttrFromJson(json, JSON_connect_timeout, connectTimeout);
+ };
+};
+
+class WiFiNet : public Network {
+ public:
+ WiFiConfig config;
+ WiFiNet(int stationMode, const char* stationSSID, const char* stationPassword, const char* apSSID, const char* apPassword, const char* hostname, int connectTimeout);
+ Network* init();
+ int connect();
+ int connectStation();
+ int createAccessPoint();
+ int startDNS();
+ void configure(WiFiConfig);
+ int isConnected(){
+ return WiFi.status() == WL_CONNECTED;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/examples/standalone/WiFiApp.h b/src/examples/standalone/WiFiApp.h
new file mode 100644
index 0000000..46f31ae
--- /dev/null
+++ b/src/examples/standalone/WiFiApp.h
@@ -0,0 +1,46 @@
+
+#ifndef __WIFI_APP__
+#define __WIFI_APP__
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "Mediator.h"
+
+using namespace std;
+using namespace std::placeholders;
+
+AsyncWebServer WEBSERVER(80);
+
+class WiFiApp : public Sprocket {
+ public:
+ Scheduler* ts;
+ Task someTask;
+ WiFiApp(SprocketConfig cfg, OtaConfig otaCfg, WebServerConfig webCfg) : Sprocket(cfg) {
+ //addPlugin(new OtaTcpPlugin(otaCfg));
+ addPlugin(new WebServerPlugin(webCfg, &WEBSERVER));
+ addPlugin(new WebConfigPlugin(&WEBSERVER));
+ ts = new Scheduler();
+ }
+
+ Sprocket* activate(Scheduler* scheduler, Network* network) {
+ Sprocket::activate(ts, network);
+ Serial.println("activate WiFiApp");
+ // add a task
+ someTask.set(TASK_SECOND, TASK_FOREVER, [](){
+ Serial.println("do stuff in task");
+ });
+ //addTask(someTask);
+ return this;
+ } using Sprocket::activate;
+ void loop(){
+ //Sprocket::loop();
+ ts->execute();
+ yield();
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/examples/standalone/config.h b/src/examples/standalone/config.h
new file mode 100644
index 0000000..6e39aeb
--- /dev/null
+++ b/src/examples/standalone/config.h
@@ -0,0 +1,31 @@
+#ifndef __STANDALONE_CONFIG__
+#define __STANDALONE_CONFIG__
+
+// Scheduler config
+#define _TASK_PRIORITY // Support for layered scheduling priority
+#define _TASK_SLEEP_ON_IDLE_RUN
+#define _TASK_STD_FUNCTION
+
+// Chip config
+#define SERIAL_BAUD_RATE 115200
+#define STARTUP_DELAY 3000
+
+// network config
+#define SPROCKET_MODE 0
+#define AP_SSID "MyAP"
+#define AP_PASSWORD "myApPwd"
+#define STATION_SSID "Th1ngs4p"
+#define STATION_PASSWORD "th3r31sn0sp00n"
+#define HOSTNAME "standalone-node"
+#define CONNECT_TIMEOUT 10000
+
+// OTA config
+#define OTA_PORT 8266
+#define OTA_PASSWORD ""
+
+// WebServer
+#define WEB_CONTEXT_PATH "/"
+#define WEB_DOC_ROOT "/www"
+#define WEB_DEFAULT_FILE "index.html"
+
+#endif
\ No newline at end of file
diff --git a/src/examples/standalone/main.cpp b/src/examples/standalone/main.cpp
new file mode 100644
index 0000000..7f263f2
--- /dev/null
+++ b/src/examples/standalone/main.cpp
@@ -0,0 +1,30 @@
+#include "config.h"
+#include "WiFiNet.h"
+#include "WiFiApp.h"
+
+/* WiFiConfig wifiCfg = {
+ .stationMode=SPROCKET_MODE,
+ .stationSSID=STATION_SSID,
+ .stationPassword=STATION_PASSWORD,
+ .apSSID=AP_SSID,
+ .apPassword=AP_PASSWORD,
+ .hostname=HOSTNAME,
+ .connectTimeout=CONNECT_TIMEOUT
+}; */
+
+WiFiNet net(SPROCKET_MODE,STATION_SSID, STATION_PASSWORD,AP_SSID, AP_PASSWORD,HOSTNAME,CONNECT_TIMEOUT);
+WiFiApp sprocket(
+ { STARTUP_DELAY, SERIAL_BAUD_RATE },
+ { OTA_PORT, OTA_PASSWORD },
+ { WEB_CONTEXT_PATH, WEB_DOC_ROOT, WEB_DEFAULT_FILE }
+);
+
+void setup() {
+ delay(3000);
+ sprocket.join(net);
+}
+
+void loop() {
+ sprocket.loop();
+ yield();
+}
\ No newline at end of file
diff --git a/src/plugins/WebConfigPlugin.cpp b/src/plugins/WebConfigPlugin.cpp
index 3f64646..7118b2b 100644
--- a/src/plugins/WebConfigPlugin.cpp
+++ b/src/plugins/WebConfigPlugin.cpp
@@ -4,10 +4,8 @@
#include
#include "TaskSchedulerDeclarations.h"
#include "ArduinoOTA.h"
-#include "MeshNet.h"
#include "Plugin.h"
#include
-#include
using namespace std;
using namespace std::placeholders;
@@ -15,7 +13,6 @@ using namespace std::placeholders;
class WebConfigPlugin : public Plugin {
private:
- MeshNet* net;
AsyncWebServer* server;
public:
WebConfigPlugin(AsyncWebServer* webServer){
@@ -23,9 +20,6 @@ class WebConfigPlugin : public Plugin {
server->serveStatic("/config.json", SPIFFS, "config.json");
}
void activate(Scheduler* userScheduler, Network* network){
-
- net = static_cast(network);
-
server->on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("GET /heap");
request->send(200, "text/plain", String(ESP.getFreeHeap()));
@@ -49,6 +43,7 @@ class WebConfigPlugin : public Plugin {
}
request->redirect("/");
});
+ Serial.println("WebConfig activated");
}
};
diff --git a/src/plugins/WebServerPlugin.cpp b/src/plugins/WebServerPlugin.cpp
index cf6c036..6758e9a 100644
--- a/src/plugins/WebServerPlugin.cpp
+++ b/src/plugins/WebServerPlugin.cpp
@@ -3,7 +3,6 @@
#include
#include "TaskSchedulerDeclarations.h"
-#include "MeshNet.h"
#include "Plugin.h"
#include
@@ -13,7 +12,6 @@ using namespace std::placeholders;
class WebServerPlugin : public Plugin {
private:
WebServerConfig config;
- MeshNet* net;
AsyncWebServer* server;
public:
WebServerPlugin(WebServerConfig cfg, AsyncWebServer* webServer){
@@ -21,7 +19,6 @@ class WebServerPlugin : public Plugin {
server = webServer;
}
void activate(Scheduler* userScheduler, Network* network){
- net = static_cast(network);
server->serveStatic(config.contextPath, SPIFFS, config.docRoot).setDefaultFile(config.defaultFile);
// TODO add auth if configured
// server->setAuthentication("user", "pass");