Skip to content

Commit 39a86b0

Browse files
authored
External config
Allow config to be accessed from outside the framework core code.
1 parent 0ca9530 commit 39a86b0

19 files changed

+422
-251
lines changed

README.md

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,22 @@ Alternatively you can extend [AdminSettingsService.h](lib/framework/AdminSetting
349349

350350
## Extending the framework
351351

352+
It is recommend that you explore the framework code to gain a better understanding of how to use it's features. The framework provides APIs so you can add your own services or features or, if required, directly configure or observe changes to core framework features. Some of these capabilities are detailed below.
353+
354+
### Adding a service with persistant settings
355+
356+
The following code demonstrates how you might extend the framework with a feature which requires a username and password to be configured to drive an unspecified feature.
357+
352358
```cpp
353359
#include <SettingsService.h>
354360

355-
class ExampleSettingsService : public SettingsService {
361+
class ExampleSettings {
362+
public:
363+
String username;
364+
String password;
365+
};
366+
367+
class ExampleSettingsService : public SettingsService<ExampleSettings> {
356368

357369
public:
358370

@@ -364,20 +376,15 @@ class ExampleSettingsService : public SettingsService {
364376
protected:
365377

366378
void readFromJsonObject(JsonObject& root) {
367-
_username = root["username"] | "";
368-
_password = root["password"] | "";
379+
_settings.username = root["username"] | "";
380+
_settings.password = root["password"] | "";
369381
}
370382

371383
void writeToJsonObject(JsonObject& root) {
372-
root["username"] = _username;
373-
root["password"] = _password;
384+
root["username"] = _settings.username;
385+
root["password"] = _settings.password;
374386
}
375387

376-
private:
377-
378-
String _username;
379-
String _password;
380-
381388
};
382389
```
383390
@@ -391,7 +398,7 @@ exampleSettingsService.begin();
391398

392399
There will now be a REST service exposed on "/exampleSettings" for reading and writing (GET/POST) the settings. Any modifications will be persisted in SPIFFS, in this case to "/config/exampleSettings.json"
393400

394-
Sometimes you need to perform an action when the settings are updated, you can achieve this by overriding the onConfigUpdated() function which gets called every time the settings are updated. You can also perform an action when the service starts by overriding the begin() function, being sure to call SettingsService::begin():
401+
Sometimes you need to perform an action when the settings are updated, you can achieve this by overriding the onConfigUpdated() function which gets called every time the settings are updated. You can also perform an action when the service starts by overriding the begin() function, being sure to call SettingsService::begin(). You can also provide a "loop" function in order to allow your service class continuously perform an action, calling this from the main loop.
395402

396403
```cpp
397404

@@ -409,14 +416,56 @@ void reconfigureTheService() {
409416
// do whatever is required to react to the new settings
410417
}
411418

419+
void loop() {
420+
// execute somthing as part of the main loop
421+
}
422+
423+
```
424+
425+
### Accessing settings and services
426+
427+
The framework supplies access to it's SettingsService instances and the SecurityManager via getter functions:
428+
429+
SettingsService | Description
430+
---------------------------- | ----------------------------------------------
431+
getSecurityManager() | The security manager - detailed above
432+
getSecuritySettingsService() | Configures the users and other security settings
433+
getWiFiSettingsService() | Configures and manages the WiFi network connection
434+
getAPSettingsService() | Configures and manages the Access Point
435+
getNTPSettingsService() | Configures and manages the network time
436+
getOTASettingsService() | Configures and manages the Over-The-Air update feature
437+
438+
These can be used to observe changes to settings. They can also be used to fetch or update settings directly via objects, JSON strings and JsonObjects. Here are some examples of how you may use this.
439+
440+
Inspect the current WiFi settings:
441+
442+
```cpp
443+
WiFiSettings wifiSettings = esp8266React.getWiFiSettingsService()->fetch();
444+
Serial.print("The ssid is:");
445+
Serial.println(wifiSettings.ssid);
446+
```
447+
448+
Configure the SSID and password:
449+
450+
```cpp
451+
WiFiSettings wifiSettings = esp8266React->getWiFiSettingsService()->fetch();
452+
wifiSettings.ssid = "MyNetworkSSID";
453+
wifiSettings.password = "MySuperSecretPassword";
454+
esp8266React.getWiFiSettingsService()->update(wifiSettings);
455+
```
456+
457+
Observe changes to the WiFiSettings:
458+
459+
```cpp
460+
esp8266React.getWiFiSettingsService()->addUpdateHandler([]() {
461+
Serial.println("The WiFi Settings were updated!");
462+
});
412463
```
413464

414465
## Libraries Used
415466

416467
* [React](https://reactjs.org/)
417468
* [Material-UI](https://material-ui-next.com/)
418469
* [notistack](https://github.com/iamhosseindhv/notistack)
419-
* [Time](https://github.com/PaulStoffregen/Time)
420-
* [NtpClient](https://github.com/gmag11/NtpClient)
421470
* [ArduinoJson](https://github.com/bblanchon/ArduinoJson)
422471
* [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer)

lib/framework/APSettingsService.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ APSettingsService::~APSettingsService() {
99

1010
void APSettingsService::begin() {
1111
SettingsService::begin();
12-
onConfigUpdated();
12+
reconfigureAP();
13+
}
14+
15+
void APSettingsService::reconfigureAP() {
16+
_lastManaged = millis() - MANAGE_NETWORK_DELAY;
1317
}
1418

1519
void APSettingsService::loop() {
@@ -24,7 +28,8 @@ void APSettingsService::loop() {
2428

2529
void APSettingsService::manageAP() {
2630
WiFiMode_t currentWiFiMode = WiFi.getMode();
27-
if (_provisionMode == AP_MODE_ALWAYS || (_provisionMode == AP_MODE_DISCONNECTED && WiFi.status() != WL_CONNECTED)) {
31+
if (_settings.provisionMode == AP_MODE_ALWAYS ||
32+
(_settings.provisionMode == AP_MODE_DISCONNECTED && WiFi.status() != WL_CONNECTED)) {
2833
if (currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) {
2934
startAP();
3035
}
@@ -37,7 +42,7 @@ void APSettingsService::manageAP() {
3742

3843
void APSettingsService::startAP() {
3944
Serial.println("Starting software access point");
40-
WiFi.softAP(_ssid.c_str(), _password.c_str());
45+
WiFi.softAP(_settings.ssid.c_str(), _settings.password.c_str());
4146
if (!_dnsServer) {
4247
IPAddress apIp = WiFi.softAPIP();
4348
Serial.print("Starting captive portal on ");
@@ -65,25 +70,25 @@ void APSettingsService::handleDNS() {
6570
}
6671

6772
void APSettingsService::readFromJsonObject(JsonObject& root) {
68-
_provisionMode = root["provision_mode"] | AP_MODE_ALWAYS;
69-
switch (_provisionMode) {
73+
_settings.provisionMode = root["provision_mode"] | AP_MODE_ALWAYS;
74+
switch (_settings.provisionMode) {
7075
case AP_MODE_ALWAYS:
7176
case AP_MODE_DISCONNECTED:
7277
case AP_MODE_NEVER:
7378
break;
7479
default:
75-
_provisionMode = AP_MODE_ALWAYS;
80+
_settings.provisionMode = AP_MODE_ALWAYS;
7681
}
77-
_ssid = root["ssid"] | AP_DEFAULT_SSID;
78-
_password = root["password"] | AP_DEFAULT_PASSWORD;
82+
_settings.ssid = root["ssid"] | AP_DEFAULT_SSID;
83+
_settings.password = root["password"] | AP_DEFAULT_PASSWORD;
7984
}
8085

8186
void APSettingsService::writeToJsonObject(JsonObject& root) {
82-
root["provision_mode"] = _provisionMode;
83-
root["ssid"] = _ssid;
84-
root["password"] = _password;
87+
root["provision_mode"] = _settings.provisionMode;
88+
root["ssid"] = _settings.ssid;
89+
root["password"] = _settings.password;
8590
}
8691

8792
void APSettingsService::onConfigUpdated() {
88-
_lastManaged = millis() - MANAGE_NETWORK_DELAY;
89-
}
93+
reconfigureAP();
94+
}

lib/framework/APSettingsService.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@
1919
#define AP_SETTINGS_FILE "/config/apSettings.json"
2020
#define AP_SETTINGS_SERVICE_PATH "/rest/apSettings"
2121

22-
class APSettingsService : public AdminSettingsService {
22+
class APSettings {
23+
public:
24+
uint8_t provisionMode;
25+
String ssid;
26+
String password;
27+
};
28+
29+
class APSettingsService : public AdminSettingsService<APSettings> {
2330
public:
2431
APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager);
2532
~APSettingsService();
@@ -33,17 +40,13 @@ class APSettingsService : public AdminSettingsService {
3340
void onConfigUpdated();
3441

3542
private:
36-
// access point settings
37-
uint8_t _provisionMode;
38-
String _ssid;
39-
String _password;
40-
4143
// for the mangement delay loop
4244
unsigned long _lastManaged;
4345

4446
// for the captive portal
4547
DNSServer* _dnsServer;
4648

49+
void reconfigureAP();
4750
void manageAP();
4851
void startAP();
4952
void stopAP();

lib/framework/AdminSettingsService.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33

44
#include <SettingsService.h>
55

6-
class AdminSettingsService : public SettingsService {
6+
template <class T>
7+
class AdminSettingsService : public SettingsService<T> {
78
public:
89
AdminSettingsService(AsyncWebServer* server,
910
FS* fs,
1011
SecurityManager* securityManager,
1112
char const* servicePath,
1213
char const* filePath) :
13-
SettingsService(server, fs, servicePath, filePath),
14+
SettingsService<T>(server, fs, servicePath, filePath),
1415
_securityManager(securityManager) {
1516
}
1617

@@ -26,7 +27,7 @@ class AdminSettingsService : public SettingsService {
2627
return;
2728
}
2829
// delegate to underlying implemetation
29-
SettingsService::fetchConfig(request);
30+
SettingsService<T>::fetchConfig(request);
3031
}
3132

3233
void updateConfig(AsyncWebServerRequest* request, JsonDocument& jsonDocument) {
@@ -37,7 +38,7 @@ class AdminSettingsService : public SettingsService {
3738
return;
3839
}
3940
// delegate to underlying implemetation
40-
SettingsService::updateConfig(request, jsonDocument);
41+
SettingsService<T>::updateConfig(request, jsonDocument);
4142
}
4243

4344
// override this to replace the default authentication predicate, IS_ADMIN

lib/framework/AuthenticationService.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ AuthenticationService::~AuthenticationService() {
2121
*/
2222
void AuthenticationService::verifyAuthorization(AsyncWebServerRequest* request) {
2323
Authentication authentication = _securityManager->authenticateRequest(request);
24-
request->send(authentication.isAuthenticated() ? 200 : 401);
24+
request->send(authentication.authenticated ? 200 : 401);
2525
}
2626

2727
/**
@@ -33,8 +33,8 @@ void AuthenticationService::signIn(AsyncWebServerRequest* request, JsonDocument&
3333
String username = jsonDocument["username"];
3434
String password = jsonDocument["password"];
3535
Authentication authentication = _securityManager->authenticate(username, password);
36-
if (authentication.isAuthenticated()) {
37-
User* user = authentication.getUser();
36+
if (authentication.authenticated) {
37+
User* user = authentication.user;
3838
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_AUTHENTICATION_SIZE);
3939
JsonObject jsonObject = response->getRoot();
4040
jsonObject["access_token"] = _securityManager->generateJWT(user);

lib/framework/ESP8266React.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,41 @@ class ESP8266React {
4141
return &_securitySettingsService;
4242
}
4343

44+
SettingsService<SecuritySettings>* getSecuritySettingsService() {
45+
return &_securitySettingsService;
46+
}
47+
48+
SettingsService<WiFiSettings>* getWiFiSettingsService() {
49+
return &_wifiSettingsService;
50+
}
51+
52+
SettingsService<APSettings>* getAPSettingsService() {
53+
return &_apSettingsService;
54+
}
55+
56+
SettingsService<NTPSettings>* getNTPSettingsService() {
57+
return &_ntpSettingsService;
58+
}
59+
60+
SettingsService<OTASettings>* getOTASettingsService() {
61+
return &_otaSettingsService;
62+
}
63+
4464
private:
4565
SecuritySettingsService _securitySettingsService;
46-
4766
WiFiSettingsService _wifiSettingsService;
4867
APSettingsService _apSettingsService;
4968
NTPSettingsService _ntpSettingsService;
5069
OTASettingsService _otaSettingsService;
5170
RestartService _restartService;
71+
5272
AuthenticationService _authenticationService;
5373

5474
WiFiScanner _wifiScanner;
5575
WiFiStatus _wifiStatus;
5676
NTPStatus _ntpStatus;
5777
APStatus _apStatus;
5878
SystemStatus _systemStatus;
59-
6079
};
6180

6281
#endif

lib/framework/NTPSettingsService.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ void NTPSettingsService::loop() {
2828
}
2929

3030
void NTPSettingsService::readFromJsonObject(JsonObject& root) {
31-
_enabled = root["enabled"] | NTP_SETTINGS_SERVICE_DEFAULT_ENABLED;
32-
_server = root["server"] | NTP_SETTINGS_SERVICE_DEFAULT_SERVER;
33-
_tzLabel = root["tz_label"] | NTP_SETTINGS_SERVICE_DEFAULT_TIME_ZONE_LABEL;
34-
_tzFormat = root["tz_format"] | NTP_SETTINGS_SERVICE_DEFAULT_TIME_ZONE_FORMAT;
31+
_settings.enabled = root["enabled"] | NTP_SETTINGS_SERVICE_DEFAULT_ENABLED;
32+
_settings.server = root["server"] | NTP_SETTINGS_SERVICE_DEFAULT_SERVER;
33+
_settings.tzLabel = root["tz_label"] | NTP_SETTINGS_SERVICE_DEFAULT_TIME_ZONE_LABEL;
34+
_settings.tzFormat = root["tz_format"] | NTP_SETTINGS_SERVICE_DEFAULT_TIME_ZONE_FORMAT;
3535
}
3636

3737
void NTPSettingsService::writeToJsonObject(JsonObject& root) {
38-
root["enabled"] = _enabled;
39-
root["server"] = _server;
40-
root["tz_label"] = _tzLabel;
41-
root["tz_format"] = _tzFormat;
38+
root["enabled"] = _settings.enabled;
39+
root["server"] = _settings.server;
40+
root["tz_label"] = _settings.tzLabel;
41+
root["tz_format"] = _settings.tzFormat;
4242
}
4343

4444
void NTPSettingsService::onConfigUpdated() {
@@ -47,37 +47,37 @@ void NTPSettingsService::onConfigUpdated() {
4747

4848
#ifdef ESP32
4949
void NTPSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
50-
Serial.printf("Got IP address, starting NTP Synchronization\n");
50+
Serial.println("Got IP address, starting NTP Synchronization");
5151
_reconfigureNTP = true;
5252
}
5353

5454
void NTPSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
55-
Serial.printf("WiFi connection dropped, stopping NTP.\n");
55+
Serial.println("WiFi connection dropped, stopping NTP.");
5656
_reconfigureNTP = false;
5757
sntp_stop();
5858
}
5959
#elif defined(ESP8266)
6060
void NTPSettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP& event) {
61-
Serial.printf("Got IP address, starting NTP Synchronization\n");
61+
Serial.println("Got IP address, starting NTP Synchronization");
6262
_reconfigureNTP = true;
6363
}
6464

6565
void NTPSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) {
66-
Serial.printf("WiFi connection dropped, stopping NTP.\n");
66+
Serial.println("WiFi connection dropped, stopping NTP.");
6767
_reconfigureNTP = false;
6868
sntp_stop();
6969
}
7070
#endif
7171

7272
void NTPSettingsService::configureNTP() {
7373
Serial.println("Configuring NTP...");
74-
if (_enabled) {
74+
if (_settings.enabled) {
7575
#ifdef ESP32
76-
configTzTime(_tzFormat.c_str(), _server.c_str());
76+
configTzTime(_settings.tzFormat.c_str(), _settings.server.c_str());
7777
#elif defined(ESP8266)
78-
configTime(_tzFormat.c_str(), _server.c_str());
78+
configTime(_settings.tzFormat.c_str(), _settings.server.c_str());
7979
#endif
8080
} else {
81-
sntp_stop();
81+
sntp_stop();
8282
}
8383
}

0 commit comments

Comments
 (0)