forked from kentaylor/WiFiManager
-
Notifications
You must be signed in to change notification settings - Fork 2
/
ConfigOnSwitchFS.ino
270 lines (219 loc) · 9.2 KB
/
ConfigOnSwitchFS.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#include <FS.h> // this needs to be first
// define ESP8266 or ESP32
#define ESP8266;
//#define ESP32;
#if defined(ESP8266)
#else
#include "SPIFFS.h"
#endif
#include <WiFi32Manager.h> // https://github.com/edumeneses/WiFi32Manager
// already includes:
// Wifi.h (https://github.com/esp8266/Arduino) or ESP8266WiFi.h (https://github.com/esp8266/Arduino)
// AND
// WebServer.h or ESP8266WebServer.h
// AND
// DNSServer.h
#include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson
// Constants
// select wich pin will trigger the configuraton portal when set to LOW
// ESP-01 users please note: the only pins available (0 and 2), are shared
// with the bootloader, so always set them HIGH at power-up
// Onboard LED I/O pin on NodeMCU board
const int PIN_LED = LED_BUILTIN; // D4 on NodeMCU and WeMos. Controls the onboard LED.
/* Trigger for inititating config mode is Pin D3 and also flash button on NodeMCU
* Flash button is convenient to use but if it is pressed it will stuff up the serial port device driver
* until the computer is rebooted on windows machines.
*/
const int TRIGGER_PIN = 27; // D3 on NodeMCU and WeMos.
/*
* Alternative trigger pin. Needs to be connected to a button to use this pin. It must be a momentary connection
* not connected permanently to ground. Either trigger pin will work.
*/
const int TRIGGER_PIN2 = 27; // D7 on NodeMCU and WeMos.
const char* CONFIG_FILE = "/config.json";
// Variables
// Indicates whether ESP has WiFi credentials saved from previous session
bool initialConfig = false;
// Default configuration values
char thingspeakApiKey[17] = "";
bool sensorDht22 = true;
unsigned int pinSda = 2;
unsigned int pinScl = 14;
// Function Prototypes
bool readConfigFile();
bool writeConfigFile();
// Setup function
void setup() {
// Put your setup code here, to run once
Serial.begin(115200);
Serial.println("\n Starting");
// Initialize the LED digital pin as an output.
pinMode(PIN_LED, OUTPUT);
// Initialize trigger pins
pinMode(TRIGGER_PIN, INPUT_PULLUP);
pinMode(TRIGGER_PIN2, INPUT_PULLUP);
// Mount the filesystem
bool result = SPIFFS.begin();
Serial.println("SPIFFS opened: " + result);
if (!readConfigFile()) {
Serial.println("Failed to read configuration file, using default values");
}
if (WiFi.SSID() == "") {
Serial.println("We haven't got any access point credentials, so get them now");
initialConfig = true;
} else {
digitalWrite(PIN_LED, HIGH); // Turn LED off as we are not in configuration mode.
WiFi.mode(WIFI_STA); // Force to station mode because if device was switched off while in access point mode it will start up next time in access point mode.
unsigned long startedAt = millis();
Serial.print("After waiting ");
int connRes = WiFi.waitForConnectResult();
float waited = (millis()- startedAt);
Serial.print(waited/1000);
Serial.print(" secs in setup() connection result is ");
Serial.println(connRes);
}
if (WiFi.status()!=WL_CONNECTED){
Serial.println("Failed to connect, finishing setup anyway");
} else{
Serial.print("Local ip: ");
Serial.println(WiFi.localIP());
}
}
// Loop function
void loop() {
// is configuration portal requested?
if ((digitalRead(TRIGGER_PIN) == LOW) || (digitalRead(TRIGGER_PIN2) == LOW) || (initialConfig)) {
Serial.println("Configuration portal requested");
digitalWrite(PIN_LED, LOW); // turn the LED on by making the voltage LOW to tell us we are in configuration mode.
//Local intialization. Once its business is done, there is no need to keep it around
// Extra parameters to be configured
// After connecting, parameter.getValue() will get you the configured value
// Format: <ID> <Placeholder text> <default value> <length> <custom HTML> <label placement>
// Thingspeak API Key - this is a straight forward string parameter
WiFiManagerParameter p_thingspeakApiKey("thingspeakapikey", "Thingspeak API Key", thingspeakApiKey, 17);
// DHT-22 sensor present or not - bool parameter visualized using checkbox, so couple of things to note
// - value is always 'T' for true. When the HTML form is submitted this is the value that will be
// sent as a parameter. When unchecked, nothing will be sent by the HTML standard.
// - customhtml must be 'type="checkbox"' for obvious reasons. When the default is checked
// append 'checked' too
// - labelplacement parameter is WFM_LABEL_AFTER for checkboxes as label has to be placed after the input field
char customhtml[24] = "type=\"checkbox\"";
if (sensorDht22) {
strcat(customhtml, " checked");
}
WiFiManagerParameter p_sensorDht22("sensordht22", "DHT-22 Sensor", "T", 2, customhtml, WFM_LABEL_AFTER);
// I2C SCL and SDA parameters are integers so we need to convert them to char array but
// no other special considerations
char convertedValue[3];
sprintf(convertedValue, "%d", pinSda);
WiFiManagerParameter p_pinSda("pinsda", "I2C SDA pin", convertedValue, 3);
sprintf(convertedValue, "%d", pinScl);
WiFiManagerParameter p_pinScl("pinscl", "I2C SCL pin", convertedValue, 3);
// Just a quick hint
WiFiManagerParameter p_hint("<small>*Hint: if you want to reuse the currently active WiFi credentials, leave SSID and Password fields empty</small>");
// Initialize WiFIManager
WiFiManager wifiManager;
//add all parameters here
wifiManager.addParameter(&p_hint);
wifiManager.addParameter(&p_thingspeakApiKey);
wifiManager.addParameter(&p_sensorDht22);
wifiManager.addParameter(&p_pinSda);
wifiManager.addParameter(&p_pinScl);
// Sets timeout in seconds until configuration portal gets turned off.
// If not specified device will remain in configuration mode until
// switched off via webserver or device is restarted.
// wifiManager.setConfigPortalTimeout(600);
// It starts an access point
// and goes into a blocking loop awaiting configuration.
// Once the user leaves the portal with the exit button
// processing will continue
if (!wifiManager.startConfigPortal()) {
Serial.println("Not connected to WiFi but continuing anyway.");
} else {
// If you get here you have connected to the WiFi
Serial.println("Connected...yeey :)");
}
// Getting posted form values and overriding local variables parameters
// Config file is written regardless the connection state
strcpy(thingspeakApiKey, p_thingspeakApiKey.getValue());
sensorDht22 = (strncmp(p_sensorDht22.getValue(), "T", 1) == 0);
pinSda = atoi(p_pinSda.getValue());
pinScl = atoi(p_pinScl.getValue());
// Writing JSON config file to flash for next boot
writeConfigFile();
digitalWrite(PIN_LED, HIGH); // Turn LED off as we are not in configuration mode.
// This is a bit crude. For some unknown reason webserver can only be started once per boot up
// so resetting the device allows to go back into config mode again when it reboots.
ESP.reset(); // For ESP8266
//ESP.restart(); // For ESP32
delay(5000);
}
// Configuration portal not requested, so run normal loop
// Put your main code here, to run repeatedly...
}
bool readConfigFile() {
// this opens the config file in read-mode
File f = SPIFFS.open(CONFIG_FILE, "r");
if (!f) {
Serial.println("Configuration file not found");
return false;
} else {
// we could open the file
size_t size = f.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
// Read and store file contents in buf
f.readBytes(buf.get(), size);
// Closing file
f.close();
// Using dynamic JSON buffer which is not the recommended memory model, but anyway
// See https://github.com/bblanchon/ArduinoJson/wiki/Memory%20model
DynamicJsonBuffer jsonBuffer;
// Parse JSON string
JsonObject& json = jsonBuffer.parseObject(buf.get());
// Test if parsing succeeds.
if (!json.success()) {
Serial.println("JSON parseObject() failed");
return false;
}
json.printTo(Serial);
// Parse all config file parameters, override
// local config variables with parsed values
if (json.containsKey("thingspeakApiKey")) {
strcpy(thingspeakApiKey, json["thingspeakApiKey"]);
}
if (json.containsKey("sensorDht22")) {
sensorDht22 = json["sensorDht22"];
}
if (json.containsKey("pinSda")) {
pinSda = json["pinSda"];
}
if (json.containsKey("pinScl")) {
pinScl = json["pinScl"];
}
}
Serial.println("\nConfig file was successfully parsed");
return true;
}
bool writeConfigFile() {
Serial.println("Saving config file");
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
// JSONify local configuration parameters
json["thingspeakApiKey"] = thingspeakApiKey;
json["sensorDht22"] = sensorDht22;
json["pinSda"] = pinSda;
json["pinScl"] = pinScl;
// Open file for writing
File f = SPIFFS.open(CONFIG_FILE, "w");
if (!f) {
Serial.println("Failed to open config file for writing");
return false;
}
json.prettyPrintTo(Serial);
// Write data to file and close it
json.printTo(f);
f.close();
Serial.println("\nConfig file was successfully saved");
return true;
}