nrwiersma / configmanager Goto Github PK
View Code? Open in Web Editor NEWESP8266 Wifi connection and configuration manager.
License: MIT License
ESP8266 Wifi connection and configuration manager.
License: MIT License
Is there a way that a sketch can access the config data directly? I was planning on using the library to create/update settings that the device would have access to.
Now that Ive gone through the code a couple times, I dont see a simple way to do this.
Thoughts? Or am I missing something?
Hi! First of all thanks for this great library! Yesterday I have faced an issue when I was trying to store char arrays.
So I made a struct like this:
struct Config {
float nilBitcoin;
float nilEthereum;
float zolBitcoin;
float zolEthereum;
char linehe1[10];
char linehe2[10];
char linehe3[10];
char linehe4[10];
} config;
Floats are stored correctly, but the char arrays not. I am getting garbage when I try to load.
Solution: I have to move char arrays to the top of the struct:
struct Config {
char linehe1[10];
char linehe2[10];
char linehe3[10];
char linehe4[10];
float nilBitcoin;
float nilEthereum;
float zolBitcoin;
float zolEthereum;
} config;
Is it a bug in your library or in the ESP32 framework or my knowledge about structs and EEPROM store is need to be updated? :)
Hi i'm using Platformio and would like to use your library for an ESP8266, but i can't use addParameter for strings, because i will get this error:
src/main.cpp:15:56: error: no matching function for call to 'ConfigManager::addParameter(const char [5], char (*)[20], int)'
Here is the whole error log of the compiling:
src/main.cpp:15:56: note: candidates are:
In file included from src/main.cpp:1:0:
lib/ConfigManager/ConfigManager.h:107:10: note: template<class T> void ConfigManager::addParameter(const char*, T*)
void addParameter(const char *name, T *variable) {
^
lib/ConfigManager/ConfigManager.h:107:10: note: template argument deduction/substitution failed:
src/main.cpp:15:56: note: candidate expects 2 arguments, 3 provided
configManager.addParameter("name", &config.name, 20);
^
In file included from src/main.cpp:1:0:
lib/ConfigManager/ConfigManager.h:110:10: note: void ConfigManager::addParameter(const char*, char*, size_t)
void addParameter(const char *name, char *variable, size_t size) {
^
lib/ConfigManager/ConfigManager.h:110:10: note: no known conversion for argument 2 from 'char (*)[20]' to 'char*'
*** [.pioenvs/nodemcuv2/src/main.o] Error 1
If i'm commenting out the line configManager.addParameter("name", &config.name, 20);
can i compile and use your library without any problems. But then i can't use strings/chars :(
Here is my main.cpp
#include "ConfigManager.h"
struct Config {
char name[20];
bool enabled;
int8 hour;
} config;
ConfigManager configManager;
void setup() {
// Setup config manager
configManager.setAPName("Demo");
configManager.setAPFilename("/index.html");
configManager.addParameter("name", &config.name, 20);
configManager.addParameter("enabled", &config.enabled);
configManager.addParameter("hour", &config.hour);
configManager.begin(config);
//
}
void loop() {
configManager.loop();
}
Can you help find out the problem and/or are you be able to help me for this problem?
There is a cb
function passed, but it does not appear to be used or documented. Is this old code that was never completed or was removed? I can do a PR to clear, if so -- otherwise, with some words, I can make a PR for its use ... ?
https://github.com/nrwiersma/ConfigManager/blob/master/src/ConfigManager.h#L75
ConfigParameter.toJson
ConfigParameter(const char *name, T *ptr, ParameterMode mode = both, std::function<void(const char*)> cb = NULL) {
this->name = name;
this->ptr = ptr;
this->cb = cb;
this->mode = mode;
}
...
void toJson(JsonObject *json) {
json->set(name, *ptr);
if (cb) {
cb(name);
}
}
addParameter
definitions don't appear to have the cb
template<typename T>
void addParameter(const char *name, T *variable) {
parameters.push_back(new ConfigParameter<T>(name, variable));
}
template<typename T>
void addParameter(const char *name, T *variable, ParameterMode mode) {
parameters.push_back(new ConfigParameter<T>(name, variable, mode));
}
void addParameter(const char *name, char *variable, size_t size) {
parameters.push_back(new ConfigStringParameter(name, variable, size));
}
void addParameter(const char *name, char *variable, size_t size, ParameterMode mode) {
parameters.push_back(new ConfigStringParameter(name, variable, size, mode));
}
Hi there,
Merry Christmas :)
I just upgrade to v1.5.1 and try to add bool parameter and int parameter to config but it bool param won't save, int param OK.
EDIT: I found issue with main.js which is not create json data properly.
Here the code I edit. (I'm not expert in anyway so, wait for developer to come up with better solution lol)
$.fn.serializeObject = function() {
var o = {};
var a = this.serializeArray();
$.each(a, function() {
var input = document.getElementsByName(this.name);
var value = this.value;
var dataType = input[0].getAttribute("data-type");
if (dataType == "number") value = parseFloat(value);
//The following line was added
if (dataType == "bool") {
value = (value=="true" || value==1)? true:false;
}
//End
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(value || '');
} else {
o[this.name] = (value==null) ? '' : value; // This line was changed
}
});
return o;
};
not possible to save the value 0 via settings.html
the previously saved value remains
I don't see this parameter being used anywhere, but it is offered in both the simple.ino
and save_config_demo.ino
examples:
struct Config {
char name[255];
bool enabled;
...
What is "enabled" intended for?
Hi,
Could you please provide example like fsbrowser.ino https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino
I try to upload/update html file on spiffs using web browser.
I have custom route for upload
server->on("/upload", HTTPMethod::HTTP_POST, [server](){
server->send(200);
handleFileUpload(server);
});
void handleFileUpload(WebServer *server){ // upload a new file to the SPIFFS
HTTPUpload& upload = server->upload();
if(upload.status == UPLOAD_FILE_START){
String filename = upload.filename;
if(!filename.startsWith("/")) filename = "/"+filename;
Serial.print("handleFileUpload Name: "); Serial.println(filename);
fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist)
filename = String();
} else if(upload.status == UPLOAD_FILE_WRITE){
if(fsUploadFile)
fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file
} else if(upload.status == UPLOAD_FILE_END){
if(fsUploadFile) { // If the file was successfully created
fsUploadFile.close(); // Close the file again
Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize);
server->sendHeader("Location","/success.html"); // Redirect the client to the success page
server->send(303);
} else {
server->send(500, "text/plain", "500: couldn't create file");
}
}
}
I copied handleFileUpload for example and pass server
to the function and change server.xxx
to server->xxx
. It did compiled just fine but it doesn't response at all, just blank page after server->send(200)
.
I think I have no idea how to refer to server
instance.
Thank you,
sam
Hi,
the ConfigManager is the perfect libary for me and the projects in the future.
But one question is in my mind.
From a release before i using the ConfigManager, the ESP32 have send a simple html-site with some values, if i sebd a request to: http://ESP32IP/site .
But with the ConfigManager, there is no result when he loads the page.
Is it possible to send this page ?
Best regards
André
Dear Sir
Have you tried to install this example on a clean nodemcu?
I have spent hours trying to understand the problem but you see I am lost... So I write to you.
I have uploaded the code and try to connect to the "demo" AP trough my mobile, it opens the connection manager address http://192........
and I get file not found...
I have tried to understand as much as I can but I am lost, it seems that it doesnt upload the index.html...
Can you check the code again please?
I am also curious, you say that the SSID and password is saved in the eeprom, what if after that I connect to one access point I would like to connect to another? should I reprogram again the code or is there other way to reset settings?
I want to add text fields in settings.html And read the data, type out via Serial.println (variable) after saving in the form, such as mqtt_host from the example, want to read the data to be stored at the variable
Help explain me
Thank You
Appears the ESP32 really sucks ... Currently running into a Wifi connection only happens every other boot.
Workaround appears to be something like this .. but its gross ...
Thoughts? Can add some flag
to enable this so it doesnt always double tap?
WiFi.begin(ssid, password[0] == '\0' ? NULL : password);
delay(1000);
WiFi.disconnect();
WiFi.begin(ssid, password[0] == '\0' ? NULL : password);
Reading saved configuration
SSID: "BI-12"
E (1003) wifi: Set status to INIT.
========= ABOVE DELAY/CONNECT CODE ==========
Waiting for WiFi to connect...
Connected to BI-12 with 192.168.4.3
Station Mode
Thanks for this great library. I am trying to get it running on an ESP32 via PlatformIO.
In the log I can see this output during boot and when I try to save my Wifi credentials.
Starting Access Point
AP Name: SolarPowerReader
AP IP address: 192.168.1.1
Webserver enabled on port: 80
dhcps: send_offer>>udp_sendto result 0
[E][WebServer.cpp:617] _handleRequest(): request handler not found
Unknown URL: www.msftconnecttest.com
--> at this point I hit save in the browser to store the credentials <--
WiFi Settings cannot be stored before ConfigManager::begin()
ets Jun 8 2016 00:22:57
The code for testing:
#include <Arduino.h>
#include "ConfigManager.h"
struct Config
{
char name[20];
bool enabled;
int8_t hour;
char password[20];
} config;
struct Metadata
{
int8_t version;
} meta;
ConfigManager configManager;
const long interval = 30000;
// the logic should be triggered on the first run and not after the interval
unsigned long previousMillis = millis() - interval;
void setup()
{
DEBUG_MODE = true; // will enable debugging and log to serial monitor
Serial.begin(115200);
Serial.println("\n\nbooting...\n\n");
meta.version = 3;
// Setup config manager
configManager.setAPName("SolarPowerReader");
configManager.setAPFilename("/index.html");
configManager.addParameter("name", config.name, 20);
configManager.addParameter("password", config.password, 20, set);
configManager.addParameter("version", &meta.version, get);
configManager.begin(config);
// configManager.clearWifiSettings(false);
//configManager.save();
}
void loop()
{
configManager.loop();
unsigned long currentMillis = millis();
// query Modbus if interval is reached and Wifi is connected
if (currentMillis - previousMillis >= interval && configManager.getMode() != 0)
{
previousMillis = currentMillis;
Serial.println("do something");
}
}
I think it might have to do with the EPROM. Trying to call clearWifiSettings or save did result in the same behaviour.
I found that adding a small delay before calling ESP.restart()
will allow ConfigManager::handleAPPost()
enough time to send the browser back its response. The use case is that I'm building a front-end that uses AJAX to call the server to reset the wifi credentials, and the device would restart before the browser got the response back.
Hi,
Given that the AP becomes no longer available after connecting the device to WIFI, is there a way to change which WIFI i'm connecting to, in a environment where there are multiple possible WIFIs to connect to?
Thanks!
Thank you for an amazing Library!
Scenario:
Issue:
Request:
Thanks!
The correct status code for Not found
is 404
.
https://github.com/nrwiersma/ConfigManager/blob/master/src/ConfigManager.cpp#L50
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors
I have noticed in my own sketch but also in the example/simple.ino that the "name" (string) and "enable" (boolean) cannot be updated through a PUT call
This is immediately after uploading the sketch
mbp> curl -X GET http://192.168.1.16/settings
{"name":"","enabled":true,"hour":0}
Here I am trying to update the three config options
mbp> curl -X PUT -d '{"name":"something","enabled":false,"hour":2}' http://192.168.1.16/settings
But only the hour (int) changes.
mbp> curl -X GET http://192.168.1.16/settings
{"name":"","enabled":true,"hour":2}
The work-around that I am now using is to only use integers in the configuration.
When I compile the sample - simple.ino I get a compile error !
C:\Users\peter\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.5.0\libraries\DNSServer\src/DNSServer.h:67:13: error: cannot declare field 'DNSServer::_udp' to be of abstract type 'WiFiUDP'
WiFiUDP _udp;
^
Any idea what I did wrong?
Many thanks,
Hi,
my project with an esp32 and a ble - scanner is almost ready to run.
But i have one problem with one parameter. In my case, it is a problem with a char - array from the UI of the ConfigManager.
I convert it to an int with : int zahl = atoi(rssimac1); .
The BLE - Libary uses a class an in this class, i use an if - request. If the scanner scans a known MAC and the RSSI of it, the esp looks to the rssi value from the ConfigManager and decide " Yes, it is a known adress" or not.
The parameter of the mac are okay. He reads this from the configmanager. But the rssi is again zero.
A serial.print in the loop shows the correct value. That's the problem i have.
Before i used your Manage, i had the INIWifimanager. But it was not mine.
Therefore, i want to use your Libary. The code is experimental and i must clean it up.
Here is my code:
`include "ConfigManager.h"
#include <HTTPClient.h>
#include <WebServer.h>
#include <ArduinoOTA.h>
#include <SPIFFS.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <BLEAddress.h>
#include <Ticker.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#define DEBUGGING // Einkommentieren für die Serielle Ausgabe
#ifdef DEBUGGING
#define DEBUG_B(...) Serial.begin(VA_ARGS)
#define DEBUG_P(...) Serial.println(VA_ARGS)
#define DEBUG_F(...) Serial.printf(VA_ARGS)
#else
#define DEBUG_B(...)
#define DEBUG_P(...)
#define DEBUG_F(...)
#endif
WebServer server(80);
const char *settingsHTML = (char *)"/settings.html";
const char *stylesCSS = (char *)"/styles.css";
const char *mainJS = (char *)"/main.js";
struct Config {
char tageins_name[32];
char tagzwei_name[32];
char uuideins_name[50];
char uuidzwei_name[50];
char rssi_werttageins[4];
char rssi_werttagzwei[4];
char rssi_wertibeacon[4];
char webhook_ein[40];
char webhook_aus[40];
int8_t led;
bool enabled;
} config;
struct Metadata {
int8_t version;
} meta;
ConfigManager configManager;
///////////////////////////////////////Variablen werden aus dem ConfigManager - struct extrahiert////////////////////////////////
char* mac1 = config.tageins_name;
char* mac2 = config.tagzwei_name;
char* ibeacon1 = config.uuideins_name;
char* ibeacon2 = config.uuidzwei_name;
char* rssimac1 = config.rssi_werttageins;
char* rssimac2 = config.rssi_werttagzwei;
char* rssiibeacon = config.rssi_wertibeacon;
char* WebhookEin = config.webhook_ein;
char* WebhookAus = config.webhook_aus;
int led = config.led;
int version = meta.version;
int zahl = atoi(rssimac1);
void APCallback(WebServer *server) {
server->on("/styles.css", HTTPMethod::HTTP_GET, server {
configManager.streamFile(stylesCSS, mimeCSS);
});
DebugPrintln(F("AP Mode Enabled. You can call other functions that should run after a mode is enabled ... "));
}
void APICallback(WebServer *server) {
server->on("/disconnect", HTTPMethod::HTTP_GET, server {
configManager.clearWifiSettings(false);
});
server->on("/settings.html", HTTPMethod::HTTP_GET, server {
configManager.streamFile(settingsHTML, mimeHTML);
});
// NOTE: css/js can be embedded in a single page HTML
server->on("/styles.css", HTTPMethod::HTTP_GET, server {
configManager.streamFile(stylesCSS, mimeCSS);
});
server->on("/main.js", HTTPMethod::HTTP_GET, server {
configManager.streamFile(mainJS, mimeJS);
});
server->on("/reboot", HTTPMethod::HTTP_GET, server {
ESP.restart();
});
}
String IDadresseSW = "88bdf79f-59ec-4f47-bf82-39b957c568a"; //UUID SmartWatch
int RelaisPin = 32; // Pin an dem Relais hängt
int Verzoegerung = 15; // Auschaltverzögerung wenn das Signal von BLE ibeacon fehlt
int active_low = 1; // "0" Relais schaltet bei +5V, "1" Relais beim schaltet bei 0V
int Webhook3;
int Webhook4;
int TuerAUFUUID1;
int TuerAUFSWUUID;
boolean variable = true;
int AktuelleZeit;
int LEDGruen = 18;
int LEDRot = 19;
int LEDWeiss = 23;
int Buzzer = 16;
int Hilfsschalter;
int Anwesend;
int MillisFaktor = 1000;
int Anwesendheitspause = 60;
int Schaltpause;
String Scanne;
String Scanne2;
String wsrssi;
String wsrssi2;
int i = 0;
int MACScan;
int MACAktuell;
//Variablenblock für die Speicherung der Adressen
int MACJetzt;
int MACVor1Min;
int MACVor2Min;
int MACVor3Min;
int MACVor4Min;
int MACVor5Min;
int MACVor6Min;
int MACVor7Min;
int MACVor8Min;
int MACVor9Min;
//Stringzuordnung
String MACTendenz;
const long utcOffsetInSeconds = 3600;
char daysOfTheWeek[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
//Millis wird gesetzt
long previousMillis = 0;
long interval = 1200;
int VerzoegerungZaeler = 0;
Ticker Tic;
static BLEAddress *pServerAddress;
static BLEAddress *pServerAddress2;
static BLEAddress *pServerAddress3;
static BLEAddress *pServerAddress4;
static BLEAddress pServerAddress5;
BLEScan pBLEScan ;
int scanTime = 1; //In seconds
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice advertisedDevice) // passiert wenn BLE Device ( beacon ) gefunden wurde
{
Serial.print("iBeacon gefunden : ");
Serial.println(advertisedDevice.toString().c_str()); // ibeacon Adresse anzeigen
Serial.printf(" RSSI: %d ", advertisedDevice.getRSSI());
Scanne = (advertisedDevice.toString().c_str());
wsrssi = (advertisedDevice.getRSSI());
///////////////////////////////////////Testcode//////////////////////////////////////
Serial.println("-------------------------------------");
Serial.println("MAC von G-Tag 1 :");
Serial.println(mac1);
Serial.println("-------------------------------------");
Serial.print("Schaltentfernung G-Tag 1 :");
Serial.println(zahl);
Serial.println("-------------------------------------");
Serial.print("Webhook - Einschaltbefehl :");
Serial.println(WebhookEin);
Serial.println("-------------------------------------");
delay(500);
/////////////////////////////////////////////////////////////////////////////////////
}
};
//Scanne2 = (advertisedDevice.toString().c_str());
//wsrssi2 = (advertisedDevice.getRSSI());
/*
i++;
//Codeblock für fortlaufende Speicherung der Adresse
MACVor9Min = MACVor8Min;
MACVor8Min = MACVor7Min;
MACVor7Min = MACVor6Min;
MACVor6Min = MACVor5Min;
MACVor5Min = MACVor4Min;
MACVor4Min = MACVor3Min;
MACVor3Min = MACVor2Min;
MACVor2Min = MACVor1Min;
MACVor1Min = MACJetzt;
MACJetzt = MACAktuell;
if (advertisedDevice.haveServiceUUID())
{
Serial.printf("UUID: %s ", advertisedDevice.getServiceUUID().toString().c_str());
}
//if (advertisedDevice.getAddress().equals(*pServerAddress) & advertisedDevice.getRSSI() > MinRSSI) // ibeacon Adresse Vergleichen
//if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(cstring) & advertisedDevice.getRSSI() > MinRSSI)
/////////////////////////////////////////////////////////////////Scannen nach Handy UUID's//////////////////////////////////////////////////////////////////////////////////////////////////////////
if (advertisedDevice.getAddress().equals(*pServerAddress3) & advertisedDevice.getRSSI() > rssiibeacon)
//if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(UUID2)& advertisedDevice.getRSSI() > MinRSSI)
//if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(SWUUID)& advertisedDevice.getRSSI() > MinRSSI)
{
Serial.println(" Überwachte Adresse gefunden"); // wenn überwache Adresse gefunden wurde
digitalWrite (RelaisPin, !active_low); // Relais Einschalten
Serial.println("Erfasse Schaltung zum Aufschließen !");
TuerAUFUUID1 = 1;
Anwesend = 1;
VerzoegerungZaeler = 0; // Ausschaltverzögerung zurücksetzen
advertisedDevice.getScan()->stop(); // Scanvorgang beenden
} // Found our server
else
{
TuerAUFUUID1 = 0;
TuerAUFSWUUID = 0;
Anwesend = 0;
}
if (advertisedDevice.getAddress().equals(*pServerAddress4) & advertisedDevice.getRSSI() > rssiibeacon)
//if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(UUID2)& advertisedDevice.getRSSI() > MinRSSI)
//if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(SWUUID)& advertisedDevice.getRSSI() > MinRSSI)
{
Serial.println(" Überwachte Adresse gefunden"); // wenn überwache Adresse gefunden wurde
digitalWrite (RelaisPin, !active_low); // Relais Einschalten
Serial.println("Erfasse Schaltung zum Aufschließen !");
TuerAUFUUID1 = 1;
//TuerAUFSWUUID = 0;
VerzoegerungZaeler = 0; // Ausschaltverzögerung zurücksetzen
advertisedDevice.getScan()->stop(); // Scanvorgang beenden
} // Found our server
else
{
//TuerAUFUUID1 = 0;
//TuerAUFSWUUID = 0;
}
//////////////////////////////////////////////Scannen nach G -Tag's mittels MAC - Adresse////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////Tag One///////////////////////////////////////////////////////////////////////////////////////////////////////////
if (advertisedDevice.getAddress().equals(*pServerAddress) & advertisedDevice.getRSSI() > rssimac1) // ibeacon Adresse Vergleichen
{
Serial.println(" Überwachte MAC - Adresse Tag 1 gefunden"); // wenn überwache Adresse gefunden wurde
digitalWrite (RelaisPin, !active_low); // Relais Einschalten
Serial.println("Erfasse Schaltung zum Aufschließen von Tag 1 !");
TuerAUFUUID1 = 1;
Anwesend = 1;
VerzoegerungZaeler = 0; // Ausschaltverzögerung zurücksetzen
advertisedDevice.getScan()->stop(); // Scanvorgang beenden
}
else
{
TuerAUFUUID1 = 0;
TuerAUFSWUUID = 0;
Anwesend = 0;
}
///////////////////////////////////////////////////////////Tag Two///////////////////////////////////////////////////////////////////////////////////////////////////////////
if (advertisedDevice.getAddress().equals(*pServerAddress2) & advertisedDevice.getRSSI() > rssimac2) // ibeacon Adresse Vergleichen
{
Serial.println(" Überwachte MAC - Adresse Tag 2 gefunden"); // wenn überwache Adresse gefunden wurde
digitalWrite (RelaisPin, !active_low); // Relais Einschalten
Serial.println("Erfasse Schaltung zum Aufschließen von Tag 2 !");
TuerAUFUUID1 = 1;
Anwesend = 1;
VerzoegerungZaeler = 0; // Ausschaltverzögerung zurücksetzen
advertisedDevice.getScan()->stop(); // Scanvorgang beenden
}
else
{
// TuerAUFUUID1 = 0;
// TuerAUFSWUUID = 0;
Anwesend = 0;
}
//////////////////////////////////////////////////////Scannen nach SmartWatch UUID/////////////////////////////////////////////////////////////////////////////
if (advertisedDevice.getAddress().equals(*pServerAddress5) & advertisedDevice.getRSSI() > rssiibeacon) // ibeacon Adresse Vergleichen
{
Serial.println("Zweite überwachte Adresse gefunden"); // wenn überwache Adresse gefunden wurde
digitalWrite (RelaisPin, !active_low); // Relais Einschalten
Serial.println("Erfasse Schaltung zum Aufschließen !");
TuerAUFSWUUID = 1;
//TuerAUFUUID1 = 0;
VerzoegerungZaeler = 0; // Ausschaltverzögerung zurücksetzen
advertisedDevice.getScan()->stop(); // Scanvorgang beenden
} // Found our server
else
{
}
Serial.println("");
}
};
*/
void SekundenTic() // Wird jede Sekunde ausgefüert
{
VerzoegerungZaeler++; // Sekundenzähler
if (VerzoegerungZaeler >= Verzoegerung) digitalWrite (RelaisPin, active_low); // Wenn Verzögerungszeit erreicht wurde Auschalten
}
//#################################################################SETUP##########################################################################################################
void setup() {
Serial.begin(115200);
DEBUG_B(115200);
DEBUG_F("\nSketchname: %s\nBuild: %s\t\tIDE: %d.%d.%d\n\n", FILE, TIMESTAMP, ARDUINO / 10000, ARDUINO % 10000 / 100, ARDUINO % 100 / 10 ? ARDUINO % 100 : ARDUINO % 10);
// spiffs();
// admin();
//Connect();
//individualButton();
// setupTime();
// espboardLed();
// onboardLed();
// bme280();
// dht22(); // Die Tabs die du nutzen möchtest, musst du Einkommentieren
// bh1750();
// setupSchaltUhr();
///////////////////////////////////////////////ConfigManager - Block///////////////////////////////////////////////////////////////////////////////////
meta.version = 3;
// Setup config manager
configManager.setAPName("BTScanner");
configManager.setAPFilename("/index.html");
// Settings variables
configManager.addParameter("tageins_name", config.tageins_name, 32);
configManager.addParameter("tagzwei_name", config.tagzwei_name, 32);
configManager.addParameter("uuideins_name", config.uuideins_name, 50);
configManager.addParameter("uuidzwei_name", config.uuidzwei_name, 50);
configManager.addParameter("rssi_werttageins", config.rssi_werttageins, 4);
configManager.addParameter("rssi_werttagzwei", config.rssi_werttagzwei, 4);
configManager.addParameter("rssi_wertibeacon", config.rssi_wertibeacon, 4);
configManager.addParameter("webhook_ein", config.webhook_ein, 40);
configManager.addParameter("webhook_aus", config.webhook_aus, 40);
configManager.addParameter("led", &config.led);
configManager.addParameter("enabled", &config.enabled);
// Meta Settings
configManager.addParameter("version", &meta.version, get);
// Init Callbacks
configManager.setAPCallback(APCallback);
configManager.setAPICallback(APICallback);
configManager.begin(config);
pinMode (LEDGruen, OUTPUT);
pinMode (LEDRot, OUTPUT);
pinMode (LEDWeiss, OUTPUT);
pinMode (Buzzer, OUTPUT);
///Hilfsschalter wird in Grundstellung geschaltet//////////////////////////////////////
Hilfsschalter = 0;
ArduinoOTA.onStart( {
//save(); //Einkommentieren wenn Werte vor dem Update gesichert werden sollen
});
ArduinoOTA.begin();
timeClient.begin();
AktuelleZeit = (timeClient.getHours() + 1);
server.begin();
DEBUG_P("HTTP Server gestartet\n\n");
///////////////////////////////////Codeblock umwandlung der Variablenwerte vom ConfigManager -> BLE-Scanner///////////////////////////////////////////
String macad1 = String(mac1);
String macad2 = String(mac2);
String ibeaconid1 = String(ibeacon1);
String ibeaconid2 = String(ibeacon2);
//String tageinsrssi = String(rssimac1);
//String tagzweirssi = String(rssimac2);
String whein = String(WebhookEin);
String whaus = String(WebhookAus);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Serial.println("Starte BLE Scanner");
Serial.print("Metadata :");
Serial.println(version);
Serial.println("-------------------------------------");
pServerAddress = new BLEAddress(macad1.c_str());
pServerAddress2 = new BLEAddress(macad2.c_str());
pServerAddress3 = new BLEAddress(ibeaconid1.c_str());
pServerAddress4 = new BLEAddress(ibeaconid2.c_str());
pServerAddress5 = new BLEAddress(IDadresseSW.c_str());
BLEDevice::init("");
}
/*
void Startnullung() //Shelly wird ausgeschaltet - Grundstellung zum Start
{
HTTPClient http;
Serial.println("Schalte Shelly aus...");
http.begin(WebhookAus); //Specify the URL
int httpCode = http.GET(); //Make the request
}
*/
//#################################################################LOOP######################################################################################
void loop() {
configManager.loop(); // Um das der Webseitenaufbau der HTML - Datei sauber erfolgen kann, kein delay im Loop einbauen. Besser Millis !!.
server.handleClient();
timeClient.update();
//if (millis() < 0x2FFF || millis() > 0xFFFFF0FF) runtime(); // Auskommentieren falls du den Admin Tab nicht nutzen möchtest
//String tageinsrssi = String(rssimac1);
//int zahl = atoi(rssimac1);
//zahl = MACAktuell;
//String tagzweirssi = String(rssimac2);
Serial.print("MAC von G-Tag 1 :");
Serial.println(mac1);
Serial.println("-------------------------------------");
Serial.print("MAC von G-Tag 2 :");
Serial.println(mac2);
Serial.println("-------------------------------------");
Serial.print("UUID von iBeacon 1 :");
Serial.println(ibeacon1);
Serial.println("-------------------------------------");
Serial.print("UUID von iBeacon 2 :");
Serial.println(ibeacon2);
Serial.println("-------------------------------------");
Serial.print("Schaltentfernung G-Tag 1 :");
//Serial.println(zahl);
/*Serial.println("-------------------------------------");
Serial.print("Schaltentfernung G-Tag 2 :");
Serial.println(rssimac2);
Serial.println("-------------------------------------");
Serial.print("Schaltentfernung iBeacons :");
Serial.println(rssiibeacon);
*/Serial.println("-------------------------------------");
Serial.print("Webhook - Einschaltbefehl :");
Serial.println(WebhookEin);
Serial.println("-------------------------------------");
Serial.print("Webhook - Ausschaltbefehl :");
Serial.println(WebhookAus);
Serial.println("-------------------------------------");
///////////////////////////////////////////Code - Block ConfigManager//////////////////////////////////
unsigned long currentMillis = millis();
/*
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice advertisedDevice) // passiert wenn BLE Device ( beacon ) gefunden wurde
{
Serial.print("iBeacon gefunden : ");
Serial.print(advertisedDevice.toString().c_str()); // ibeacon Adresse anzeigen
Serial.printf(" RSSI: %d ", advertisedDevice.getRSSI());
Serial.println("---------------------------------");
if (advertisedDevice.getAddress().equals(*pServerAddress)& advertisedDevice.getRSSI() > zahl) // ibeacon Adresse Vergleichen
{
Serial.println(" Überwachte MAC - Adresse Tag 1 gefunden"); // wenn überwache Adresse gefunden wurde
}
}
};
*/
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
Tic.attach( 1, SekundenTic);
pBLEScan->start(scanTime);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////HTTP - Update - Block///////////////////////////////////////////////////////////////////
if ((timeClient.getMinutes() == 30) && (timeClient.getSeconds() >= 00) and (timeClient.getSeconds() <= 05)) //Prüfe immer um halb auf Updates
{
Serial.println();
Serial.println("Prüfe auf HTTP - Update...");
// ESPUpdate();
delay(1000);
}
/////////////////////////////////////Überwachung WiFi - Verbindung////////////////////////////////////////
//Netzwerküberwachung des ESP32
if
(WiFi.status() == WL_CONNECTED) {
//digitalWrite(LEDGruen, HIGH);
}
else
{
digitalWrite(LEDGruen, HIGH);
delay(100);
digitalWrite(LEDGruen, LOW);
delay(100);
digitalWrite(LEDGruen, HIGH);
delay(100);
digitalWrite(LEDGruen, LOW);
delay(100);
digitalWrite(LEDRot, HIGH);
Serial.println("Netzwerk nicht in Reichweite !");
Serial.println("Verbindung wird aufgebaut...");
WiFi.reconnect();
delay(3000);
digitalWrite(LEDRot, LOW);
digitalWrite(LEDGruen, HIGH);
}
///////////////////////////////INFO //////////////////////////////////////////
Serial.print("Aktuelle Minute :");
Serial.println(timeClient.getMinutes());
Serial.println("XXXXXXXXXXXXXXXXXXXXX");
Serial.print("Aktuelle Sekunde :");
Serial.println(timeClient.getSeconds());
pBLEScan->clearResults(); // Buffer wird gelöscht, um Speicher frei zu geben
}`
Hi,
i use example "save_config_demo.ino" from the master branch and have little problems with the variables outside of the struct.
For the float-value in the struct i used
float nameofvariable = config.nameofstructvariable;
So, if i would print it in the serial monitor, He shows only the value 0. I think, the problem in my side.
How can i solve this ?
Another thing is the configuration on the settings site. I write the values in the masks, press "save" and the following screen prints "File not found" message.
Thank you.
Hi @nrwiersma,
Firstly thank you for taking the time to write and share this library. Unfortunately I've stopped using it for the moment as it introduced instability problems into my application, due to memory usage. So I was wondering about some of the architectural choices made with this library. Please correct me if I'm wrong with anything I say here.
I've modified your library to use server->streamFile() instead of server->send(), so the HTML file is streamed directly from flash instead of being read into a string variable before being sent. This has both improved web server performance and reduced impact on heap space, in turn reducing crashes when the HTML file is too big.
I'm also concerned about the security problems of the REST API. Since parameters may include passwords for MQTT brokers, having an open endpoint which freely shows clear text parameter values is a bit of a risk.
The library passes parameters via the REST API using JSON. This creates a large memory overhead and makes it difficult to use standard HTML forms for the PUT, as there is no JSON support built into HTML. Could we not just post server args using multipart/form-data and access each arg without the expensive transformation to and from JSON? Sure it makes it easy on the client where we have the convenience of JavaScript and Ajax, but it's expensive on the ESP8266 side.
Thanks,
Jon
The save_config_demo
example has a settings.html file that uses a CDN-hosted jQuery to update the form and post form results back to the ESP/ConfigManager API.
Currently, requiring CDN-hosted jQuery makes for a less-than-ideal experience. In some cases, internet is not available, and it would be unfortunate if that meant additional settings could not be set between a user and their device.
I'm following your instructions on the readme but when I click on "Tools -> ESP8266 (!) data sketch upload" it says "SPIFFS not supported on ESP32".
How can I upload the index.html file?
I get the following compile error
C:\Users\Rudy\Documents\Arduino\libraries\ConfigManager-master\examples\simple\simple.ino: In function 'void setup()':
simple:10: error: 'configManager' was not declared in this scope
configManager.setAPName("Demo");
^
C:\Users\Rudy\Documents\Arduino\libraries\ConfigManager-master\examples\simple\simple.ino: In function 'void loop()':
simple:20: error: 'configManager' was not declared in this scope
configManager.loop();
^
I try to use an image in html file but the image doesn't show up when I connect the a default webpage.
img src="image.png" alt="logo" style="width:25%;"
PS: I have image.png in data folder.
Hi,
I think single page would be better for user experience since no need to remember to type .../settings.html to get to config page.
Unless, I missing something. After connect to wifi network, I type local IP (http://192.168.1.137
) it still show Wifi Details page. I have to type settings.html to get to config.
I see you have AP and API mode. Why dont we just show settings page by default when we are in API mode.
I think passing mode: ap or api to json data and using this mode to hide/show wifi/settings div on single page. I have no idea how to edit the code to pass this mode to browser.
BTW, I also try to change configHTMLFile = "/index.html"
and rename original settings.html
to index.html
hoping it will show settings page be default but it still show wifi details page which I rename it to wifi.html
which is weird. It seems it doesn't matter which mode web server will start in ap mode (I set setAPFilename("/wifi.html")
)
Thank you in advance,
Sam
PS: Lines with **....**
were changed from example
#include "ConfigManager.h"
const char mimeHTML[] PROGMEM = "text/html";
**const char *configHTMLFile = "/index.html";**
struct Config {
char name[255];
bool enabled;
char mqtt_host[255];
char mqtt_port[10];
char mqtt_username[255];
char mqtt_password[255];
char mqtt_topic[255];
} config;
struct Metadata {
int8_t version;
} meta;
ConfigManager configManager;
void createCustomRoute(WebServer *server) {
**server->on("/", HTTPMethod::HTTP_GET, [server](){**
SPIFFS.begin();
File f = SPIFFS.open(configHTMLFile, "r");
if (!f) {
Serial.println(F("file open failed"));
server->send(404, FPSTR(mimeHTML), F("File not found"));
return;
}
server->streamFile(f, FPSTR(mimeHTML));
f.close();
});
}
void setup() {
Serial.begin(115200);
Serial.println("");
meta.version = 3;
// Setup config manager
configManager.setAPName("Demo");
**configManager.setAPFilename("/wifi.html");**
configManager.addParameter("name", config.name, 255);
configManager.addParameter("mqtt_host", config.mqtt_host, 255);
configManager.addParameter("mqtt_port", config.mqtt_port, 10);
configManager.addParameter("mqtt_username", config.mqtt_username, 255);
configManager.addParameter("mqtt_password", config.mqtt_password, 255);
configManager.addParameter("mqtt_topic", config.mqtt_topic, 255);
configManager.addParameter("enabled", &config.enabled);
configManager.addParameter("version", &meta.version, get);
configManager.setAPICallback(createCustomRoute);
configManager.begin(config);
Serial.print("ESP MODE:");
}
void loop() {
configManager.loop();
}
First I want to say that I like your library. It does what it does without a lot of junk in the way. What I want is a clean way to set the WiFi connection, and to set some other parameters to eeprom. I tried another library but it was doing too much. Has it's own way to make web pages that was "simpler". I thought it only made it harder as I needed to figure out how to work with it.
The minor issue I have with ConfigManager is on a new setup the contents of the eeprom is filled into the the fields in the setup screen. I haven't looked at the code yet, but it would be better to have empty text boxes on the first load. Typing new values into the line does not get rid of the remainder of the line.
I just tried to save. I think it might have saved. But I don't know if it did. Confirmation would be nice. I guess I need to handle it myself. Hey, at least I can do it my way.
I am not sure if this was a design choice or bug but when saving with a PUT to /settings
and then calling the GET on /settings
only the last value is returned.
I was playing with these 2 functions and I do not know enough about c++ to fix but wanted to bring this up.
https://github.com/nrwiersma/ConfigManager/blob/master/src/ConfigManager.h#L82-L88
and
https://github.com/nrwiersma/ConfigManager/blob/master/src/ConfigManager.cpp#L177-L194
I confirmed with the save_config_demo example that it does this as it will only show he meta.version (I removed to test the form code)
I also confirmed it will save the values to EPROMM so it's working in that part.
EDIT: I am going to play with a solution using
https://arduinojson.org/v6/how-to/merge-json-objects/
Thanks
That^
Below is a simple ino that reproduces the issue.
I have a struct that defines my configuration - it has an array of a struct of char *
and a single int. Both the struct and ConfigManager are members of a class I'm writing. Before I call ConfigManager::begin()
my int in the struct is correctly initialized to zero. However, after calling ConfigManager::begin()
the value of the int becomes -1
.
I have tried erasing my flash in case there was previous data being read, but that didn't change anything. I would appreciate any help and/or advice you have on this.
For testing purposes I am using Arduino 1.8.13 and ConfigManager 2.1.0. My device is an esp32 wroom 32D.
#include <ConfigManager.h>
const int CALENDARS = 8;
struct configuration_t {
int calendars;
};
struct metadata_t {
int version;
};
class Config {
public:
Config(): manager(new ConfigManager()) {
manager->addParameter("calendars", &config.calendars);
manager->addParameter("version", &meta.version);
}
void begin() {
Serial.printf("Config::begin(): config.calendars = %d\n", config.calendars);
Serial.printf("Config::begin(): meta.version = %d\n", meta.version);
manager->begin(config);
Serial.printf("Config::begin(): config.calendars = %d\n", config.calendars);
Serial.printf("Config::begin(): meta.version = %d\n", meta.version);
}
private:
configuration_t config{};
metadata_t meta{};
ConfigManager * manager;
};
void setup() {
Serial.begin(115200);
Config * config = new Config();
config->begin();
}
void loop() {
}
Edit: Updated demo code to remove unnecessary code and to add config parameters as in the example code.
Hi Nick, have you considered adding ESP32 support for ConfigManager? Happy to help out once again if you have the time.
I just compiled/uploaded this to a ESP8266, it boots, makest AP, i connected but no way to get in.
Expected urls don't work..
Hi, I tried to set the timeout to 300 on configmanager.h, but esp8266 doesn't reboot.
I have a couple of devices running firmware that includes ConfigManager, in different locations. One of them is very stable. The other seems to go offline randomly. I think I've traced this to transient conditions on the wifi network at one location. The device becomes disconnected due to router issues, tries 20 times to reconnect to the wifi, fails to connect and then launches its AP mode config pages - and sits there forever waiting for a connection until it's manually rebooted.
Could we maybe have an AP timeout? Keep a timestamp of when the last http operation happened and check it in ConfigManager::loop()? Then close down the AP and retry the wifi connection?
Also it might be nice to be able to set the number of wifi connect retries, the wait time and the AP timeout value when starting ConfigManager.
What are your thoughts Nick?
configManager.reset();
The version I am using is: 1.2.0
Hi,
I am new to programming. Thank you for the configmanager.
I want to save/retrieve ESP wifi config and additional parameters from my JS mobile app fetch api REST.
Uploaded simple.ino example sketch.
Tested in my windows machine, curl, this works for config wifi credentials; ESP can connect to my home AP.
Curl -X POST http://192.168.1.1 -d “ssid=my_ssid&password=my_password”
While reconnected to “Demo” AP, This way to save parameters;
curl -H "Content-Type: application/json" -X PUT http://192.168.1.1/settings -d “{here JSON for various types}"
Then this way to see response in console; (always blank)
Curl -X GET http://192.168.1.1/settings
I didn't understand well the structure for various parameter types in sketch OR a wrong syntax in curl lines.
Could you please give an example to save and retrieve a string parameter, “key”:”value”.
Both in sketch and curl statements.
Thanks
I noticed this with an NodeMCU ESP8266 development board. I consider it undesired behaviour that the AP remains available, as it allows anyone to reconfigure the Thing. Let me outline the steps that allow me to reproduce.
When the Thing is not connected to my local wifi network, I see “Starting Access Point” in the serial console and can connect my laptop as follows:
Laptop Wi-Fi is connected to ESP-THING and has the IP address 192.168.1.100.
All is fine and I configure the SSID and Password of my wifi router. In the serial console I can see it connecting. The ESP-THING wifi network shortly disappears, and then reappears. With the Thing connected to my local wifi network, I can again connect to its AP as follows:
Laptop Wi-Fi is connected to ESP-THING and has the IP address 192.168.4.2.
In the latter case (i.e. with the thing connected), I can access the /index.html endpoint at 192.168.1.13 (when I connect my laptop to my router network) and at 192.168.4.1 (when I connect my laptop to the ESP-THING network).
What I do not understand is where the 192.168.4.x network comes from, as there is nothing in the code with this IP address. There is this
IPAddress ip(192, 168, 1, 1);
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(ip, ip, IPAddress(255, 255, 255, 0));
WiFi.softAP(apName);
I do not find in the code where the mode is being switched, but I get the feeling that - once connected - it is in WIFI_AP_STA and not in WIFI_STA mode.
This issue will be used to track to work on v3
of ConfigManager. The idea will evolve and be discussed here.
The ideas around this are from the collaboration between @nrwiersma and @cgmckeever.
Split ConfigManager into roughly 3 parts:
When the Wifi and HTTP sections can we turned off or a custom class used to suit the needs of the user, however a "simple" option should remain leading to the use of ConfigManager as it exists today. This can be achieved using Abstract Classes (interfaces) around the Wifi and HTTP sections.
ssid
and password
?Im trying to make the library (or sketch) to auto reconnect wifi after it connected successfully. Because right now once its connected and if wifi stops working and works again, it won't reconnect and connexions wont work.
I've tried something like this modifiying the library but its not working:
if ((WiFi.status() != WL_CONNECTED)) {
delay(1000);
yield();
char ssid[SSID_LENGTH];
char password[PASSWORD_LENGTH];
EEPROM.get(MAGIC_LENGTH, ssid);
EEPROM.get(MAGIC_LENGTH + SSID_LENGTH, password);
Serial.print("Reconnecting");
WiFi.begin(ssid, password);
}
The GET api passes the contents of all custom field to the client in clear text. Any custom fields which carry sensitive information, e.g. MQTT broker passwords, are therefore easy security breach targets.
I previously suggested:
However, I think it might be sufficient to still store password fields in clear text but send them obscured by filling the field's buffer with asterisks *.
How do you feel about that Nick?
Continued from previous discussion in issue #11
Hi, I came across your library on platformio, and I'm excited at what it has to offer. After following the example in the README, I get the following output and my MCU stays in AP mode waiting to be set up.
Reading saved configuration
MAC: 7C:9E:BD:ED:28:5C
SSID: "��������������������������������"
MagicBytes mismatch - SSID: ������������������������������������������������������������������������������������������������Xvǒ�
Starting Access Point
E (2364) phy_init: store_cal_data_to_nvs_handle: store calibration data failed(0x1105)
AP Name: Desk-Buddy
AP IP address: 192.168.1.1
Webserver enabled on port: 80
[E][WebServer.cpp:617] _handleRequest(): request handler not found
Unknown URL: captive.apple.com
[E][WebServer.cpp:617] _handleRequest(): request handler not found
Unknown URL: captive.apple.com
[E][WebServer.cpp:617] _handleRequest(): request handler not found
Unknown URL: captive.apple.com
[E][WebServer.cpp:617] _handleRequest(): request handler not found
Unknown URL: captive.apple.com
Storing WiFi Settings for SSID: "---------------"
[E][EEPROM.cpp:199] commit(): error in write
EEPROM committed: false
For good measure, I did run ~/Library/Arduino15/packages/esp32/tools/esptool_py/2.6.1/esptool --chip esp32 erase_flash
to make sure that my flash was clean, and I still get the above messages. I am not sure how to proceed, and could use your advice.
Thank you.
Hi,
Perhaps I'm a little confused to the point of Metadata as opposed to Config?
I'm using Config to retain the wifi settings, then was going to use the Metadata struct to contain my user parameters, is this right or not? Does it get saved, and if so do I just call:
configManager.save();
and that will store the meta and config settings?
The settings don't appear to save for the meta part of the code, is this expected behaviour and if so what is the key point of the meta part of this and examples?
My code:
`include <ConfigManager.h>
ConfigManager configManager;
struct Config {
char name[20];
bool enabled;
int8 hour;
char password[20];
} config;
struct Metadata {
int8_t version;
String setting_autoupdate;
} meta;
setup() {
configManager.setAPFilename("/ap-index.html");
configManager.addParameter("name", config.name, 20);
configManager.addParameter("enabled", &config.enabled);
configManager.addParameter("hour", &config.hour);
configManager.addParameter("password", config.password, 20, set);
configManager.addParameter("version", &meta.version, get);
configManager.addParameter("setting_autoupdate", &meta.setting_autoupdate, set);
configManager.begin(config);
};
loop() {
meta.setting_autoupdate="yes";
configManager.save();
`
Got everything up and running with the demo, then entered an SSID with Simplified Chinese Characters in it (喝一点儿茶)
Got the following from the serial monitor
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:952
load:0x40078000,len:6084
load:0x40080000,len:7944
entry 0x40080310
Reading saved configuration
[E][WiFiSTA.cpp:124] begin(): SSID too long or missing!
Waiting for WiFi to connect....................
Connection timed out
Starting Access Point
ets Jun 8 2016 00:22:57```
Hi,
I'm trying to read and write from the config structured data. Am I missing something in the implementation here.
Please see example code below:
`
#include <ConfigManager.h>
ConfigManager configManager;
struct Config {
char name[20];
char setting_autoupdate[1];
char setting_mqttdest[15];
bool enabled;
int8 hour;
char password[20];
} config;
struct Metadata {
int8_t version;
} meta;
setup() {
configManager.setAPFilename("/ap-index.html");
configManager.addParameter("name", config.name, 20);
configManager.addParameter("enabled", &config.enabled);
configManager.addParameter("hour", &config.hour);
configManager.addParameter("password", config.password, 20, set);
configManager.addParameter("version", &meta.version, get);
configManager.addParameter("setting_autoupdate", config.setting_autoupdate, 1);
configManager.addParameter("setting_mqttdest", config.setting_mqttdest, 15);
configManager.begin(config);
if (strlen(config.setting_autoupdate) == 0) {strncpy(config.setting_autoupdate, "0",1);};
if (strlen(config.setting_mqttdest) == 0) {strncpy(config.setting_mqttdest, "0.0.0.0",7);
Serial.println("Settings defaults as meta data empty");
} else {
Serial.println("Reading settings from meta data values");
};
configManager.save();
}
loop() {
DEBUG_PRINT("configmanager mqttdest test: " + String(config.setting_mqttdest));
}
`
The results are, on running the script it shows "Settings defaults as meta data empty", so it's set the defaults as the config.setting_mqttdest length is 0.
It should then save this value.
The loop runs and correctly then shows the value contains 0.0.0.0 as expected.
I then reload the esp8266 so the code restarts from blank.
It does the same, no values stored so it says "Settings defaults as meta data empty" and sets the default value of 0.0.0.0 again.
It never seems to write the values and is blank at each reboot.
What am I doing wrong?
So to write I am doing:
strncpy(config.setting_mqttdest, "0.0.0.0",7); configManager.save();
That is correct?
Thank you!
Discussed here
When putting the wrong type in a config parameter and saving, the memory allocation gets screwy and gets wiped.
Device will no longer have Wifi credentials/etc at next boot.
config.someIntParam = random(300); // where the parameter is an int
configManager.save();
** This may be an odd type cast I came across and doesnt apply to other scenarios.
A better setter for parameters via ConfigManager.
This would particularly be useful since setting a string is not straightforward
strncpy(config.deviceName, "fesp-muppet", DEVICENAMELEN);
Something like:
template <typename T>
void updateParameter(name, T* value) {
// call to the configParameter->update();
}
void updateParameter(name, char* value) {
// call to the configParameter->update();
}
I had zero luck figuring out how to identify a parameter
by name from the std::list<BaseParameter*>
and a tripped over the same trap of Arduino not having std::unordered_map at least twice now ;)
I also tried having the addParameter
call return the ConfigParameter
object and the main project code could track/index it. That got complicated, and compiler errors in the type returns/etc
void loop() {
...
ConfigParameter = configManager.addParameter("randomNumber", &config.randomNumber, get);
Finally .. I came up with this monster that exploits ConfigManagers use of JSON for updating ... worked, but felt icky
template <typename T>
void updateParameter(const char* name, T value) {
std::list<BaseParameter*>::iterator it;
for (it = parameters.begin(); it != parameters.end(); ++it) {
if ((*it)->getName() == name) {
DynamicJsonDocument doc(1024);
JsonObject json = doc.createNestedObject();
json[name] = value;
(*it)->fromJson(&json);
break;
Hi!
A nice addition to the readme page can be an ArduBadge badge, see here: www.ardu-badge.com
For ConfigManager it will look like that:
Markdown:
[![arduino-library-badge](http://www.ardu-badge.com/badge/ConfigManager.svg)](http://www.ardu-badge.com/ConfigManager)
It shows:
What do you think?
The library should either be updated to be compatible with breaking changes in ArduinoJson 6, or the documentation augmented to advise that ArduinoJson 5 be used.
In the meantime, for anyone reading this who uses PlatformIO, you can specify explicit use of the last version of ArduinoJson 5 by adding the following to platformio.ini
:
lib_deps =
[email protected]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.