-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathEmotiBitConfigManager.cpp
More file actions
331 lines (319 loc) · 10.6 KB
/
EmotiBitConfigManager.cpp
File metadata and controls
331 lines (319 loc) · 10.6 KB
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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#include <EmotiBitConfigManager.h>
#ifdef ARDUINO_FEATHER_ESP32
bool EmotiBitConfigManager::init(fs::SDFS* sd)
{
SD = sd;
if(SD != nullptr)
{
return true;
}
else
{
return false;
}
}
#else
bool EmotiBitConfigManager::init(SdFat* sd)
{
SD = sd;
if(SD != nullptr)
{
return true;
}
else
{
return false;
}
}
#endif
bool EmotiBitConfigManager::createNewConfigFile(String configFilename, File& file, JsonDocument& configAsJson)
{
#if defined ARDUINO_FEATHER_ESP32
file = SD->open(configFilename, FILE_WRITE);
#else
file = SD->open(configFilename, O_CREAT | O_WRITE);
#endif
if(file)
{
if( serializeJsonPretty(configAsJson, file) == 0)
{
Serial.println("Failed to write to file");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_ADD);
return false;
}
file.close();
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::ACK, EmotiBitPacket::TypeTag::WIFI_ADD);
}
else
{
Serial.println("Failed to create file");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_ADD);
return false;
}
return true;
}
uint8_t EmotiBitConfigManager::loadConfigFile(const String &filename, JsonDocument& jsonDoc)
{
// Open file for reading
File file = SD->open(filename);
if (!file) {
Serial.print("File ");
Serial.print(filename);
Serial.println(" not found");
return (uint8_t) Status::FILE_NOT_FOUND;
}
// Parse the root object
DeserializationError error = deserializeJson(jsonDoc, file);
file.close();
if (error) {
Serial.println(F("Failed to parse config file"));
return (uint8_t) Status::FILE_PARSE_FAIL;
}
return Status::OK;
}
void EmotiBitConfigManager::updateWiFiCredentials(String emotibitFwVersion, String configFilename, const uint8_t maxCreds)
{
// Send EmotiBit Firmware version to host
EmotiBitSerial::sendMessage(EmotiBitFactoryTest::TypeTag::FIRMWARE_VERSION, emotibitFwVersion);
// instructions
Serial.println("Options available:");
Serial.println("1. Add a wifi credential. Send: @WA,{\"ssid\":\"SSSS\",\"password\" : \"PPPP\"}~");
Serial.println(" - Replace SSSS with network name and PPPP with network password");
Serial.println("2. List wifi credentials. Send: @LS~");
Serial.println("3. Delete Wifi Credential. Send: @WD,<credential number>~");
Serial.println(" - use List option to get a wifi list. Then use the number in the list to delete that credential");
Serial.println("4. Reset device. Send @RS~");
Serial.println(" - Restart the device after editing config file");
while (1)
{
if (Serial.available())
{
String msg = Serial.readStringUntil(EmotiBitSerial::MSG_TERM_CHAR); // is ~ is not present, readStringUntil() break after timeout
msg += EmotiBitSerial::MSG_TERM_CHAR;
String typetag, payload;
bool serialParsed = EmotiBitSerial::parseSerialMessage(msg, typetag, payload);
if(serialParsed)
{
File file;
StaticJsonDocument<1024> configAsJson;
DeserializationError parseError;
bool fileExists = false, fileParses = false;
fileExists = SD->exists(configFilename);
if(fileExists)
{
file = SD->open(configFilename);
parseError = deserializeJson(configAsJson, file);
file.close();
if(parseError)
{
// remove broken config file
Serial.println("Config file parse failed. Removing file.");
SD->remove(configFilename);
fileExists = false;
}
}
if (typetag.compareTo(EmotiBitPacket::TypeTag::WIFI_ADD) == 0)
{
String ssid, password, username, userid;
StaticJsonDocument<256> inputJson;
DeserializationError error = deserializeJson(inputJson, payload);
if(error)
{
// user input cannot be parsed
Serial.println("Try again. Cannot parse JSON input.");
Serial.println("Expected format: WA,{\"ssid\":\"SSSS\",\"password\" : \"PPPP\"}");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_ADD);
continue;
}
else
{
// user input parsed correctly
ssid = inputJson["ssid"] | "";
password = inputJson["password"] | "";
username = inputJson["username"] | "";
userid = inputJson["userid"] | "";
//Serial.println("Parsed output: ");
Serial.print("Adding:: ");
Serial.print("ssid: " + ssid); Serial.print(" | ");
Serial.print("password: " + password);
username.compareTo("")!= 0 ? Serial.println("username: " + username) : Serial.println();
userid.compareTo("")!= 0 ? Serial.println("userid: " + userid) : Serial.println();
if(!fileExists)
{
// either config file does not exist or parse failed and it was deleted
Serial.println("Creating new config file");
// create new file
configAsJson.clear();
JsonArray wifiCreds = configAsJson.createNestedArray("WifiCredentials");
JsonObject cred = wifiCreds.createNestedObject();
cred["ssid"] = ssid;
cred["password"] = password;
if (userid.compareTo("") != 0)
{
cred["userid"] = userid;
}
if (username.compareTo("") != 0)
{
cred["username"] = username;
}
bool status = createNewConfigFile(configFilename, file, configAsJson);
if (!status)
{
// error messages are printed in the called function
continue;
}
}
else
{
// config file present!
Serial.println("config file exists. Appending to file.");
// file parsed successfully
if(configAsJson["WifiCredentials"].size() >= maxCreds)
{
Serial.println("Config file already has max num allowed creds. Please delete before adding");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_ADD);
continue;
}
else
{
JsonObject cred = configAsJson["WifiCredentials"].createNestedObject();
cred["ssid"] = ssid;
cred["password"] = password;
if(userid.compareTo("") != 0)
{
cred["userid"] = userid;
}
if(username.compareTo("") != 0)
{
cred["username"] = username;
}
bool status = createNewConfigFile(configFilename, file, configAsJson);
if (!status)
{
// error messages are printed in the called function
continue;
}
else
{
// success. Consider sending ACK response, if it does ont affect UX on teh serial monitor
}
}
}
// read file contents
Serial.println("Updated file contents:");
file = SD->open(configFilename);
configAsJson.clear();
error = deserializeJson(configAsJson, file);
serializeJsonPretty(configAsJson, Serial);
file.close();
Serial.println();
}
}
else if (typetag.compareTo(EmotiBitPacket::TypeTag::WIFI_DELETE) == 0)
{
if(!fileExists)
{
Serial.println("config file does not exist. Aborting delete");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_DELETE);
continue;
}
if(parseError)
{
Serial.println("Cannot parse JSON file. Aborting delete");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_DELETE);
continue;
}
else
{
// file can be parsed!
if(payload.compareTo("") != 0)
{
// delete requested credential
int deleteIndex = payload.toInt();
if(deleteIndex == 0 && payload.compareTo("0") != 0)
{
// toInt() tried to convert invalid string and returned 0 by default
Serial.println("invalid option. Please be careful to avoid blank spaces.");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_DELETE);
continue;
}
if(deleteIndex < configAsJson["WifiCredentials"].size())
{
Serial.print("Deleting entry: " + String(deleteIndex) + ". ");
Serial.println(configAsJson["WifiCredentials"][deleteIndex]["ssid"].as<String>());
configAsJson["WifiCredentials"].remove(deleteIndex);
SD->remove(configFilename);
bool status = createNewConfigFile(configFilename, file, configAsJson);
if(status)
{
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::ACK, EmotiBitPacket::TypeTag::WIFI_DELETE);
}
else
{
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_DELETE);
}
}
else
{
Serial.println("Out of bounds delete. Enter a valid choice.");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_DELETE);
}
}
else
{
Serial.println("Delete needs a parameter. Call LS to get current credential list.");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::WIFI_DELETE);
}
}
}
else if (typetag.compareTo(EmotiBitPacket::TypeTag::LIST) == 0)
{
if(!fileExists)
{
Serial.println("config file does not exist.");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::LIST);
continue;
}
if(parseError)
{
Serial.println("Cannot parse config file. Aborting LIST.");
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::NACK, EmotiBitPacket::TypeTag::LIST);
continue;
}
if(configAsJson["WifiCredentials"].size())
{
Serial.println("##################################");
Serial.println("config file credentials:");
for(int i = 0; i < configAsJson["WifiCredentials"].size(); i++ )
{
Serial.print(i); Serial.print(". " + configAsJson["WifiCredentials"][i]["ssid"].as<String>());
Serial.print(" : "); Serial.print(configAsJson["WifiCredentials"][i]["password"].as<String>());
Serial.println();
}
Serial.println("##################################");
}
else
{
Serial.println("Config file has no credentials. Try WA to add credential first.");
}
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::ACK, EmotiBitPacket::TypeTag::LIST);
}
else if (typetag.compareTo(EmotiBitPacket::TypeTag::RESET) == 0)
{
EmotiBitSerial::sendMessage(EmotiBitPacket::TypeTag::ACK, EmotiBitPacket::TypeTag::RESET);
Serial.println("Restarting MCU");
delay(1000);
#ifdef ARDUINO_FEATHER_ESP32
ESP.restart();
#elif defined ADAFRUIT_FEATHER_M0
NVIC_SystemReset();
#endif
}
}
else
{
Serial.println("Not a valid serial message. Expecting: @TYPETAG,PAYLOAD~ or @TYPETAG~");
}
}
}
}