rjwats
5 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 2680 additions and 2128 deletions
-
91README.md
-
3data/config/demoSettings.json
-
6interface/.env
-
4interface/.env.development
-
2520interface/package-lock.json
-
16interface/package.json
-
5interface/src/AppRouting.js
-
3interface/src/authentication/Authentication.js
-
58interface/src/components/LoadingNotification.js
-
12interface/src/components/MenuAppBar.js
-
20interface/src/components/RestComponent.js
-
9interface/src/components/SectionContent.js
-
1interface/src/constants/App.js
-
2interface/src/constants/Endpoints.js
-
3interface/src/constants/Env.js
-
18interface/src/containers/APSettings.js
-
38interface/src/containers/APStatus.js
-
24interface/src/containers/ManageUsers.js
-
18interface/src/containers/NTPSettings.js
-
38interface/src/containers/NTPStatus.js
-
20interface/src/containers/OTASettings.js
-
18interface/src/containers/SecuritySettings.js
-
4interface/src/containers/SignInPage.js
-
38interface/src/containers/SystemStatus.js
-
2interface/src/containers/WiFiNetworkScanner.js
-
20interface/src/containers/WiFiSettings.js
-
40interface/src/containers/WiFiStatus.js
-
52interface/src/forms/APSettingsForm.js
-
34interface/src/forms/ManageUsersForm.js
-
45interface/src/forms/NTPSettingsForm.js
-
44interface/src/forms/OTASettingsForm.js
-
30interface/src/forms/SecuritySettingsForm.js
-
4interface/src/forms/WiFiNetworkSelector.js
-
44interface/src/forms/WiFiSettingsForm.js
-
82interface/src/project/DemoController.js
-
100interface/src/project/DemoInformation.js
-
37interface/src/project/DemoProject.js
-
30interface/src/project/ProjectMenu.js
-
32interface/src/project/ProjectRouting.js
-
1interface/src/sections/NetworkTime.js
-
12lib/framework/APSettingsService.cpp
-
3lib/framework/APSettingsService.h
-
6lib/framework/APStatus.cpp
-
3lib/framework/APStatus.h
-
45lib/framework/AdminSettingsService.h
-
0lib/framework/ArduinoJsonJWT.cpp
-
0lib/framework/ArduinoJsonJWT.h
-
0lib/framework/AsyncArduinoJson6.h
-
0lib/framework/AsyncJsonWebHandler.h
-
3lib/framework/AuthenticationService.cpp
-
3lib/framework/AuthenticationService.h
-
55lib/framework/ESP8266React.cpp
-
59lib/framework/ESP8266React.h
-
0lib/framework/NTPSettingsService.cpp
-
2lib/framework/NTPSettingsService.h
-
6lib/framework/NTPStatus.cpp
-
3lib/framework/NTPStatus.h
-
0lib/framework/OTASettingsService.cpp
-
4lib/framework/OTASettingsService.h
-
0lib/framework/SecurityManager.cpp
-
0lib/framework/SecurityManager.h
-
4lib/framework/SecuritySettingsService.cpp
-
4lib/framework/SecuritySettingsService.h
-
0lib/framework/SettingsPersistence.h
-
57lib/framework/SettingsService.h
-
13lib/framework/SimpleService.h
-
6lib/framework/SystemStatus.cpp
-
3lib/framework/SystemStatus.h
-
8lib/framework/WiFiScanner.cpp
-
2lib/framework/WiFiScanner.h
-
7lib/framework/WiFiSettingsService.cpp
-
2lib/framework/WiFiSettingsService.h
-
6lib/framework/WiFiStatus.cpp
-
3lib/framework/WiFiStatus.h
-
26src/DemoProject.cpp
-
34src/DemoProject.h
-
99src/main.cpp
@ -0,0 +1,3 @@ |
|||
{ |
|||
"blink_speed": 100 |
|||
} |
@ -1 +1,5 @@ |
|||
REACT_APP_NAME=ESP8266 React |
|||
# This is the name of your project. It appears on the sign-in page and in the menu bar. |
|||
REACT_APP_PROJECT_NAME=ESP8266 React |
|||
|
|||
# This is the url path your project will be exposed under. |
|||
REACT_APP_PROJECT_PATH=project |
@ -1 +1,3 @@ |
|||
REACT_APP_ENDPOINT_ROOT=http://192.168.0.11/rest/ |
|||
# Change the IP address to that of your ESP device to enable local development of the UI. |
|||
# Remember to also enable CORS in platformio.ini before uploading the code to the device. |
|||
REACT_APP_ENDPOINT_ROOT=http://192.168.0.20/rest/ |
2520
interface/package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,58 @@ |
|||
import React from 'react'; |
|||
import PropTypes from 'prop-types'; |
|||
|
|||
import { makeStyles } from '@material-ui/core/styles'; |
|||
import Button from '@material-ui/core/Button'; |
|||
import LinearProgress from '@material-ui/core/LinearProgress'; |
|||
import Typography from '@material-ui/core/Typography'; |
|||
|
|||
const useStyles = makeStyles(theme => ({ |
|||
loadingSettings: { |
|||
margin: theme.spacing(0.5), |
|||
}, |
|||
loadingSettingsDetails: { |
|||
margin: theme.spacing(4), |
|||
textAlign: "center" |
|||
}, |
|||
button: { |
|||
marginRight: theme.spacing(2), |
|||
marginTop: theme.spacing(2), |
|||
} |
|||
})); |
|||
|
|||
export default function LoadingNotification(props) { |
|||
const classes = useStyles(); |
|||
const { fetched, errorMessage, onReset, render } = props; |
|||
return ( |
|||
<div> |
|||
{ |
|||
fetched ? |
|||
errorMessage ? |
|||
<div className={classes.loadingSettings}> |
|||
<Typography variant="h6" className={classes.loadingSettingsDetails}> |
|||
{errorMessage} |
|||
</Typography> |
|||
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}> |
|||
Reset |
|||
</Button> |
|||
</div> |
|||
: |
|||
render() |
|||
: |
|||
<div className={classes.loadingSettings}> |
|||
<LinearProgress className={classes.loadingSettingsDetails} /> |
|||
<Typography variant="h6" className={classes.loadingSettingsDetails}> |
|||
Loading... |
|||
</Typography> |
|||
</div> |
|||
} |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
LoadingNotification.propTypes = { |
|||
fetched: PropTypes.bool.isRequired, |
|||
onReset: PropTypes.func.isRequired, |
|||
errorMessage: PropTypes.string, |
|||
render: PropTypes.func.isRequired |
|||
}; |
@ -1 +0,0 @@ |
|||
export const APP_NAME = process.env.REACT_APP_NAME; |
@ -0,0 +1,3 @@ |
|||
export const PROJECT_NAME = process.env.REACT_APP_PROJECT_NAME; |
|||
export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH; |
|||
export const ENDPOINT_ROOT = process.env.REACT_APP_ENDPOINT_ROOT; |
@ -0,0 +1,82 @@ |
|||
import React, { Component } from 'react'; |
|||
import { ValidatorForm } from 'react-material-ui-form-validator'; |
|||
|
|||
import { ENDPOINT_ROOT } from '../constants/Env'; |
|||
import SectionContent from '../components/SectionContent'; |
|||
import { restComponent } from '../components/RestComponent'; |
|||
import LoadingNotification from '../components/LoadingNotification'; |
|||
|
|||
import Button from '@material-ui/core/Button'; |
|||
import Typography from '@material-ui/core/Typography'; |
|||
import Slider from '@material-ui/core/Slider'; |
|||
import { makeStyles } from '@material-ui/core/styles'; |
|||
|
|||
export const DEMO_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "demoSettings"; |
|||
|
|||
const valueToPercentage = (value) => `${Math.round(value / 255 * 100)}%`; |
|||
|
|||
class DemoController extends Component { |
|||
componentDidMount() { |
|||
this.props.loadData(); |
|||
} |
|||
|
|||
render() { |
|||
const { data, fetched, errorMessage, saveData, loadData, handleSliderChange } = this.props; |
|||
return ( |
|||
<SectionContent title="Controller" titleGutter> |
|||
<LoadingNotification |
|||
onReset={loadData} |
|||
fetched={fetched} |
|||
errorMessage={errorMessage} |
|||
render={() => |
|||
<DemoControllerForm |
|||
demoSettings={data} |
|||
onReset={loadData} |
|||
onSubmit={saveData} |
|||
handleSliderChange={handleSliderChange} |
|||
/> |
|||
} |
|||
/> |
|||
</SectionContent> |
|||
) |
|||
} |
|||
} |
|||
|
|||
const useStyles = makeStyles(theme => ({ |
|||
button: { |
|||
marginRight: theme.spacing(2), |
|||
marginTop: theme.spacing(2), |
|||
}, |
|||
blinkSpeedLabel: { |
|||
marginBottom: theme.spacing(5), |
|||
} |
|||
})); |
|||
|
|||
function DemoControllerForm(props) { |
|||
const { demoSettings, onSubmit, onReset, handleSliderChange } = props; |
|||
const classes = useStyles(); |
|||
return ( |
|||
<ValidatorForm onSubmit={onSubmit}> |
|||
<Typography id="blink-speed-slider" className={classes.blinkSpeedLabel}> |
|||
Blink Speed |
|||
</Typography> |
|||
<Slider |
|||
value={demoSettings.blink_speed} |
|||
valueLabelFormat={valueToPercentage} |
|||
aria-labelledby="blink-speed-slider" |
|||
valueLabelDisplay="on" |
|||
min={0} |
|||
max={255} |
|||
onChange={handleSliderChange('blink_speed')} |
|||
/> |
|||
<Button variant="contained" color="primary" className={classes.button} type="submit"> |
|||
Save |
|||
</Button> |
|||
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}> |
|||
Reset |
|||
</Button> |
|||
</ValidatorForm> |
|||
); |
|||
} |
|||
|
|||
export default restComponent(DEMO_SETTINGS_ENDPOINT, DemoController); |
@ -0,0 +1,100 @@ |
|||
import React, { Component } from 'react'; |
|||
|
|||
import { withStyles } from '@material-ui/core/styles'; |
|||
import Table from '@material-ui/core/Table'; |
|||
import TableHead from '@material-ui/core/TableHead'; |
|||
import TableCell from '@material-ui/core/TableCell'; |
|||
import TableBody from '@material-ui/core/TableBody'; |
|||
import TableRow from '@material-ui/core/TableRow'; |
|||
import Typography from '@material-ui/core/Typography'; |
|||
|
|||
import SectionContent from '../components/SectionContent'; |
|||
|
|||
const styles = theme => ({ |
|||
fileTable: { |
|||
marginBottom: theme.spacing(2) |
|||
} |
|||
}); |
|||
|
|||
class DemoInformation extends Component { |
|||
|
|||
render() { |
|||
const { classes } = this.props; |
|||
return ( |
|||
<SectionContent title="Demo Project - Blink Speed Controller" titleGutter> |
|||
<Typography variant="body1" paragraph> |
|||
This simple demo project allows you to control the blink speed of the built-in LED. |
|||
It demonstrates how the esp8266-react framework may be extended for your own IoT project. |
|||
</Typography> |
|||
<Typography variant="body1" paragraph> |
|||
It is recommended that you keep your project interface code under the 'project' directory. |
|||
This serves to isolate your project code from the from the rest of the user interface which should |
|||
simplify merges should you wish to update your project with future framework changes. |
|||
</Typography> |
|||
<Typography variant="body1" paragraph> |
|||
The demo project interface code stored in the interface/project directory: |
|||
</Typography> |
|||
<Table className={classes.fileTable}> |
|||
<TableHead> |
|||
<TableRow> |
|||
<TableCell> |
|||
File |
|||
</TableCell> |
|||
<TableCell> |
|||
Description |
|||
</TableCell> |
|||
</TableRow> |
|||
</TableHead> |
|||
<TableBody> |
|||
<TableRow> |
|||
<TableCell> |
|||
ProjectMenu.js |
|||
</TableCell> |
|||
<TableCell> |
|||
You can add your project's screens to the side bar here. |
|||
</TableCell> |
|||
</TableRow> |
|||
<TableRow> |
|||
<TableCell> |
|||
ProjectRouting.js |
|||
</TableCell> |
|||
<TableCell> |
|||
The routing which controls the screens of your project. |
|||
</TableCell> |
|||
</TableRow> |
|||
<TableRow> |
|||
<TableCell> |
|||
DemoProject.js |
|||
</TableCell> |
|||
<TableCell> |
|||
This screen, with tabs and tab routing. |
|||
</TableCell> |
|||
</TableRow> |
|||
<TableRow> |
|||
<TableCell> |
|||
DemoInformation.js |
|||
</TableCell> |
|||
<TableCell> |
|||
The demo information tab. |
|||
</TableCell> |
|||
</TableRow> |
|||
<TableRow> |
|||
<TableCell> |
|||
DemoController.js |
|||
</TableCell> |
|||
<TableCell> |
|||
The demo controller tab, to control the built-in LED. |
|||
</TableCell> |
|||
</TableRow> |
|||
</TableBody> |
|||
</Table> |
|||
<Typography variant="body1" paragraph> |
|||
See the project <a href="https://github.com/rjwats/esp8266-react/">README</a> for a full description of the demo project. |
|||
</Typography> |
|||
</SectionContent> |
|||
) |
|||
} |
|||
|
|||
} |
|||
|
|||
export default withStyles(styles)(DemoInformation); |
@ -0,0 +1,37 @@ |
|||
import React, { Component } from 'react'; |
|||
import { Redirect, Switch } from 'react-router-dom' |
|||
|
|||
import { PROJECT_PATH } from '../constants/Env'; |
|||
import MenuAppBar from '../components/MenuAppBar'; |
|||
import AuthenticatedRoute from '../authentication/AuthenticatedRoute'; |
|||
import DemoInformation from './DemoInformation'; |
|||
import DemoController from './DemoController'; |
|||
|
|||
import Tabs from '@material-ui/core/Tabs'; |
|||
import Tab from '@material-ui/core/Tab'; |
|||
|
|||
class DemoProject extends Component { |
|||
|
|||
handleTabChange = (event, path) => { |
|||
this.props.history.push(path); |
|||
}; |
|||
|
|||
render() { |
|||
return ( |
|||
<MenuAppBar sectionTitle="Demo Project"> |
|||
<Tabs value={this.props.match.url} onChange={this.handleTabChange} indicatorColor="primary" textColor="primary" variant="fullWidth"> |
|||
<Tab value={`/${PROJECT_PATH}/demo/information`} label="Information" /> |
|||
<Tab value={`/${PROJECT_PATH}/demo/controller`} label="Controller" /> |
|||
</Tabs> |
|||
<Switch> |
|||
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/information`} component={DemoInformation} /> |
|||
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/controller`} component={DemoController} /> |
|||
<Redirect to={`/${PROJECT_PATH}/demo/information`} /> |
|||
</Switch> |
|||
</MenuAppBar> |
|||
) |
|||
} |
|||
|
|||
} |
|||
|
|||
export default DemoProject; |
@ -0,0 +1,30 @@ |
|||
import React, { Component } from 'react'; |
|||
import { Link, withRouter } from 'react-router-dom'; |
|||
|
|||
import { PROJECT_PATH } from '../constants/Env'; |
|||
|
|||
import List from '@material-ui/core/List'; |
|||
import ListItem from '@material-ui/core/ListItem'; |
|||
import ListItemIcon from '@material-ui/core/ListItemIcon'; |
|||
import ListItemText from '@material-ui/core/ListItemText'; |
|||
import SettingsRemoteIcon from '@material-ui/icons/SettingsRemote'; |
|||
|
|||
class ProjectMenu extends Component { |
|||
|
|||
render() { |
|||
const path = this.props.match.url; |
|||
return ( |
|||
<List> |
|||
<ListItem to={`/${PROJECT_PATH}/demo/`} selected={path.startsWith(`/${PROJECT_PATH}/demo/`)} button component={Link}> |
|||
<ListItemIcon> |
|||
<SettingsRemoteIcon /> |
|||
</ListItemIcon> |
|||
<ListItemText primary="Demo Project" /> |
|||
</ListItem> |
|||
</List> |
|||
) |
|||
} |
|||
|
|||
} |
|||
|
|||
export default withRouter(ProjectMenu); |
@ -0,0 +1,32 @@ |
|||
import React, { Component } from 'react'; |
|||
import { Redirect, Switch } from 'react-router'; |
|||
|
|||
import { PROJECT_PATH } from '../constants/Env'; |
|||
import AuthenticatedRoute from '../authentication/AuthenticatedRoute'; |
|||
import DemoProject from './DemoProject'; |
|||
|
|||
class ProjectRouting extends Component { |
|||
|
|||
render() { |
|||
return ( |
|||
<Switch> |
|||
{ |
|||
/* |
|||
* Add your project page routing below. |
|||
*/ |
|||
} |
|||
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/*`} component={DemoProject} /> |
|||
{ |
|||
/* |
|||
* The redirect below caters for the default project route and redirecting invalid paths. |
|||
* The "to" property must match one of the routes above for this to work correctly. |
|||
*/ |
|||
} |
|||
<Redirect to={`/${PROJECT_PATH}/demo/`} /> |
|||
</Switch> |
|||
) |
|||
} |
|||
|
|||
} |
|||
|
|||
export default ProjectRouting; |
@ -1,8 +1,8 @@ |
|||
#include <APStatus.h>
|
|||
|
|||
APStatus::APStatus(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) { |
|||
_server->on(AP_STATUS_SERVICE_PATH, HTTP_GET, |
|||
_securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) |
|||
APStatus::APStatus(AsyncWebServer* server, SecurityManager* securityManager) { |
|||
server->on(AP_STATUS_SERVICE_PATH, HTTP_GET, |
|||
securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) |
|||
); |
|||
} |
|||
|
@ -0,0 +1,45 @@ |
|||
#ifndef AdminSettingsService_h |
|||
#define AdminSettingsService_h |
|||
|
|||
#include <SettingsService.h> |
|||
|
|||
class AdminSettingsService : public SettingsService { |
|||
|
|||
public: |
|||
AdminSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager, char const* servicePath, char const* filePath): |
|||
SettingsService(server, fs, servicePath, filePath), _securityManager(securityManager) {} |
|||
|
|||
protected: |
|||
// will validate the requests with the security manager |
|||
SecurityManager* _securityManager; |
|||
|
|||
void fetchConfig(AsyncWebServerRequest *request) { |
|||
// verify the request against the predicate |
|||
Authentication authentication = _securityManager->authenticateRequest(request); |
|||
if (!getAuthenticationPredicate()(authentication)) { |
|||
request->send(401); |
|||
return; |
|||
} |
|||
// delegate to underlying implemetation |
|||
SettingsService::fetchConfig(request); |
|||
} |
|||
|
|||
void updateConfig(AsyncWebServerRequest *request, JsonDocument &jsonDocument) { |
|||
// verify the request against the predicate |
|||
Authentication authentication = _securityManager->authenticateRequest(request); |
|||
if (!getAuthenticationPredicate()(authentication)) { |
|||
request->send(401); |
|||
return; |
|||
} |
|||
// delegate to underlying implemetation |
|||
SettingsService::updateConfig(request, jsonDocument); |
|||
} |
|||
|
|||
// override this to replace the default authentication predicate, IS_ADMIN |
|||
AuthenticationPredicate getAuthenticationPredicate() { |
|||
return AuthenticationPredicates::IS_ADMIN; |
|||
} |
|||
|
|||
}; |
|||
|
|||
#endif // end AdminSettingsService |
@ -1,7 +1,6 @@ |
|||
#include <AuthenticationService.h>
|
|||
|
|||
AuthenticationService::AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager): |
|||
_server(server), _securityManager(securityManager) { |
|||
AuthenticationService::AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager) : _securityManager(securityManager) { |
|||
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, std::placeholders::_1)); |
|||
|
|||
_signInHandler.setUri(SIGN_IN_PATH); |
@ -0,0 +1,55 @@ |
|||
#include <ESP8266React.h>
|
|||
|
|||
ESP8266React::ESP8266React(AsyncWebServer* server, FS* fs): |
|||
_securitySettingsService(server, fs), |
|||
_wifiSettingsService(server, fs, &_securitySettingsService), |
|||
_apSettingsService(server, fs, &_securitySettingsService), |
|||
_ntpSettingsService(server, fs, &_securitySettingsService), |
|||
_otaSettingsService(server, fs, &_securitySettingsService), |
|||
_authenticationService(server, &_securitySettingsService), |
|||
_wifiScanner(server, &_securitySettingsService), |
|||
_wifiStatus(server, &_securitySettingsService), |
|||
_ntpStatus(server, &_securitySettingsService), |
|||
_apStatus(server, &_securitySettingsService), |
|||
_systemStatus(server, &_securitySettingsService) { |
|||
// Serve static resources from /www/
|
|||
server->serveStatic("/js/", SPIFFS, "/www/js/"); |
|||
server->serveStatic("/css/", SPIFFS, "/www/css/"); |
|||
server->serveStatic("/fonts/", SPIFFS, "/www/fonts/"); |
|||
server->serveStatic("/app/", SPIFFS, "/www/app/"); |
|||
server->serveStatic("/favicon.ico", SPIFFS, "/www/favicon.ico"); |
|||
|
|||
// Serving all other get requests with "/www/index.htm"
|
|||
// OPTIONS get a straight up 200 response
|
|||
server->onNotFound([](AsyncWebServerRequest *request) { |
|||
if (request->method() == HTTP_GET) { |
|||
request->send(SPIFFS, "/www/index.html"); |
|||
} else if (request->method() == HTTP_OPTIONS) { |
|||
request->send(200); |
|||
} else { |
|||
request->send(404); |
|||
} |
|||
}); |
|||
|
|||
// Disable CORS if required
|
|||
#if defined(ENABLE_CORS)
|
|||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", CORS_ORIGIN); |
|||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization"); |
|||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true"); |
|||
#endif
|
|||
} |
|||
|
|||
void ESP8266React::begin() { |
|||
_securitySettingsService.begin(); |
|||
_wifiSettingsService.begin(); |
|||
_apSettingsService.begin(); |
|||
_ntpSettingsService.begin(); |
|||
_otaSettingsService.begin(); |
|||
} |
|||
|
|||
void ESP8266React::loop() { |
|||
_wifiSettingsService.loop(); |
|||
_apSettingsService.loop(); |
|||
_ntpSettingsService.loop(); |
|||
_otaSettingsService.loop(); |
|||
} |
@ -0,0 +1,59 @@ |
|||
#ifndef ESP8266React_h |
|||
#define ESP8266React_h |
|||
|
|||
#include <Arduino.h> |
|||
|
|||
#if defined(ESP8266) |
|||
#include <ESP8266WiFi.h> |
|||
#include <ESPAsyncTCP.h> |
|||
#elif defined(ESP_PLATFORM) |
|||
#include <WiFi.h> |
|||
#include <AsyncTCP.h> |
|||
#include <SPIFFS.h> |
|||
#endif |
|||
|
|||
#include <FS.h> |
|||
#include <SecuritySettingsService.h> |
|||
#include <WiFiSettingsService.h> |
|||
#include <APSettingsService.h> |
|||
#include <NTPSettingsService.h> |
|||
#include <OTASettingsService.h> |
|||
#include <AuthenticationService.h> |
|||
#include <WiFiScanner.h> |
|||
#include <WiFiStatus.h> |
|||
#include <NTPStatus.h> |
|||
#include <APStatus.h> |
|||
#include <SystemStatus.h> |
|||
|
|||
class ESP8266React { |
|||
|
|||
public: |
|||
|
|||
ESP8266React(AsyncWebServer* server, FS* fs); |
|||
|
|||
void begin(); |
|||
void loop(); |
|||
|
|||
SecurityManager* getSecurityManager(){ |
|||
return &_securitySettingsService; |
|||
} |
|||
|
|||
private: |
|||
|
|||
SecuritySettingsService _securitySettingsService; |
|||
|
|||
WiFiSettingsService _wifiSettingsService; |
|||
APSettingsService _apSettingsService; |
|||
NTPSettingsService _ntpSettingsService; |
|||
OTASettingsService _otaSettingsService; |
|||
AuthenticationService _authenticationService; |
|||
|
|||
WiFiScanner _wifiScanner; |
|||
WiFiStatus _wifiStatus; |
|||
NTPStatus _ntpStatus; |
|||
APStatus _apStatus; |
|||
SystemStatus _systemStatus; |
|||
|
|||
}; |
|||
|
|||
#endif |
@ -1,7 +1,7 @@ |
|||
#ifndef NTPSettingsService_h |
|||
#define NTPSettingsService_h |
|||
|
|||
#include <SettingsService.h> |
|||
#include <AdminSettingsService.h> |
|||
|
|||
#include <TimeLib.h> |
|||
#include <NtpClientLib.h> |
@ -1,8 +1,8 @@ |
|||
#include <NTPStatus.h>
|
|||
|
|||
NTPStatus::NTPStatus(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) { |
|||
_server->on(NTP_STATUS_SERVICE_PATH, HTTP_GET, |
|||
_securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) |
|||
NTPStatus::NTPStatus(AsyncWebServer* server, SecurityManager* securityManager) { |
|||
server->on(NTP_STATUS_SERVICE_PATH, HTTP_GET, |
|||
securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) |
|||
); |
|||
} |
|||
|
@ -1,8 +1,8 @@ |
|||
#include <SystemStatus.h>
|
|||
|
|||
SystemStatus::SystemStatus(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) { |
|||
_server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, |
|||
_securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) |
|||
SystemStatus::SystemStatus(AsyncWebServer* server, SecurityManager* securityManager) { |
|||
server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, |
|||
securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) |
|||
); |
|||
} |
|||
|
@ -1,13 +1,13 @@ |
|||
#include <WiFiScanner.h>
|
|||
|
|||
WiFiScanner::WiFiScanner(AsyncWebServer *server, SecurityManager* securityManager) : _server(server) { |
|||
_server->on(SCAN_NETWORKS_SERVICE_PATH, HTTP_GET, |
|||
WiFiScanner::WiFiScanner(AsyncWebServer *server, SecurityManager* securityManager) { |
|||
server->on(SCAN_NETWORKS_SERVICE_PATH, HTTP_GET, |
|||
securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN) |
|||
); |
|||
_server->on(LIST_NETWORKS_SERVICE_PATH, HTTP_GET, |
|||
server->on(LIST_NETWORKS_SERVICE_PATH, HTTP_GET, |
|||
securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN) |
|||
); |
|||
} |
|||
}; |
|||
|
|||
void WiFiScanner::scanNetworks(AsyncWebServerRequest *request) { |
|||
if (WiFi.scanComplete() != -1){ |
@ -1,9 +1,16 @@ |
|||
#include <WiFiSettingsService.h>
|
|||
|
|||
WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, WIFI_SETTINGS_SERVICE_PATH, WIFI_SETTINGS_FILE) { |
|||
// Disable WiFi config persistance and auto reconnect
|
|||
WiFi.persistent(false); |
|||
WiFi.setAutoReconnect(false); |
|||
|
|||
#if defined(ESP8266)
|
|||
_onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); |
|||
#elif defined(ESP_PLATFORM)
|
|||
// Init the wifi driver on ESP32
|
|||
WiFi.mode(WIFI_MODE_MAX); |
|||
WiFi.mode(WIFI_MODE_NULL); |
|||
WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); |
|||
#endif
|
|||
} |
@ -1,7 +1,7 @@ |
|||
#ifndef WiFiSettingsService_h |
|||
#define WiFiSettingsService_h |
|||
|
|||
#include <SettingsService.h> |
|||
#include <AdminSettingsService.h> |
|||
#include <IPAddress.h> |
|||
|
|||
#define WIFI_SETTINGS_FILE "/config/wifiSettings.json" |
@ -1,8 +1,8 @@ |
|||
#include <WiFiStatus.h>
|
|||
|
|||
WiFiStatus::WiFiStatus(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) { |
|||
_server->on(WIFI_STATUS_SERVICE_PATH, HTTP_GET, |
|||
_securityManager->wrapRequest(std::bind(&WiFiStatus::wifiStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) |
|||
WiFiStatus::WiFiStatus(AsyncWebServer* server, SecurityManager* securityManager) { |
|||
server->on(WIFI_STATUS_SERVICE_PATH, HTTP_GET, |
|||
securityManager->wrapRequest(std::bind(&WiFiStatus::wifiStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) |
|||
); |
|||
#if defined(ESP8266)
|
|||
_onStationModeConnectedHandler = WiFi.onStationModeConnected(onStationModeConnected); |
@ -0,0 +1,26 @@ |
|||
#include <DemoProject.h>
|
|||
|
|||
DemoProject::DemoProject(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, DEMO_SETTINGS_PATH, DEMO_SETTINGS_FILE) { |
|||
pinMode(BLINK_LED, OUTPUT); |
|||
} |
|||
|
|||
DemoProject::~DemoProject() {} |
|||
|
|||
void DemoProject::loop() { |
|||
unsigned delay = MAX_DELAY / 255 * (255 - _blinkSpeed); |
|||
unsigned long currentMillis = millis(); |
|||
if (!_lastBlink || (unsigned long)(currentMillis - _lastBlink) >= delay) { |
|||
_lastBlink = currentMillis; |
|||
digitalWrite(BLINK_LED, !digitalRead(BLINK_LED)); |
|||
} |
|||
} |
|||
|
|||
void DemoProject::readFromJsonObject(JsonObject& root) { |
|||
_blinkSpeed = root["blink_speed"] | DEFAULT_BLINK_SPEED; |
|||
} |
|||
|
|||
void DemoProject::writeToJsonObject(JsonObject& root) { |
|||
// connection settings
|
|||
root["blink_speed"] = _blinkSpeed; |
|||
} |
|||
|
@ -0,0 +1,34 @@ |
|||
#ifndef DemoProject_h |
|||
#define DemoProject_h |
|||
|
|||
#include <AdminSettingsService.h> |
|||
|
|||
#define BLINK_LED 2 |
|||
#define MAX_DELAY 1000 |
|||
|
|||
#define DEFAULT_BLINK_SPEED 100 |
|||
#define DEMO_SETTINGS_FILE "/config/demoSettings.json" |
|||
#define DEMO_SETTINGS_PATH "/rest/demoSettings" |
|||
|
|||
class DemoProject : public AdminSettingsService { |
|||
|
|||
public: |
|||
|
|||
DemoProject(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); |
|||
~DemoProject(); |
|||
|
|||
void loop(); |
|||
|
|||
private: |
|||
|
|||
unsigned long _lastBlink = 0; |
|||
uint8_t _blinkSpeed = 255; |
|||
|
|||
protected: |
|||
|
|||
void readFromJsonObject(JsonObject& root); |
|||
void writeToJsonObject(JsonObject& root); |
|||
|
|||
}; |
|||
|
|||
#endif |
@ -1,99 +1,34 @@ |
|||
#include <Arduino.h>
|
|||
|
|||
#if defined(ESP8266)
|
|||
#include <ESP8266WiFi.h>
|
|||
#include <ESPAsyncTCP.h>
|
|||
#elif defined(ESP_PLATFORM)
|
|||
#include <WiFi.h>
|
|||
#include <AsyncTCP.h>
|
|||
#include <SPIFFS.h>
|
|||
#endif
|
|||
|
|||
#include <ESP8266React.h>
|
|||
#include <DemoProject.h>
|
|||
#include <FS.h>
|
|||
#include <SecuritySettingsService.h>
|
|||
#include <WiFiSettingsService.h>
|
|||
#include <APSettingsService.h>
|
|||
#include <NTPSettingsService.h>
|
|||
#include <OTASettingsService.h>
|
|||
#include <AuthenticationService.h>
|
|||
#include <WiFiScanner.h>
|
|||
#include <WiFiStatus.h>
|
|||
#include <NTPStatus.h>
|
|||
#include <APStatus.h>
|
|||
#include <SystemStatus.h>
|
|||
|
|||
#define SERIAL_BAUD_RATE 115200
|
|||
|
|||
AsyncWebServer server(80); |
|||
|
|||
SecuritySettingsService securitySettingsService = SecuritySettingsService(&server, &SPIFFS); |
|||
WiFiSettingsService wifiSettingsService = WiFiSettingsService(&server, &SPIFFS, &securitySettingsService); |
|||
APSettingsService apSettingsService = APSettingsService(&server, &SPIFFS, &securitySettingsService); |
|||
NTPSettingsService ntpSettingsService = NTPSettingsService(&server, &SPIFFS, &securitySettingsService); |
|||
OTASettingsService otaSettingsService = OTASettingsService(&server, &SPIFFS, &securitySettingsService); |
|||
AuthenticationService authenticationService = AuthenticationService(&server, &securitySettingsService); |
|||
|
|||
WiFiScanner wifiScanner = WiFiScanner(&server, &securitySettingsService); |
|||
WiFiStatus wifiStatus = WiFiStatus(&server, &securitySettingsService); |
|||
NTPStatus ntpStatus = NTPStatus(&server, &securitySettingsService); |
|||
APStatus apStatus = APStatus(&server, &securitySettingsService); |
|||
SystemStatus systemStatus = SystemStatus(&server, &securitySettingsService);; |
|||
ESP8266React esp8266React(&server, &SPIFFS); |
|||
DemoProject demoProject = DemoProject(&server, &SPIFFS, esp8266React.getSecurityManager()); |
|||
|
|||
void setup() { |
|||
// Disable wifi config persistance and auto reconnect
|
|||
WiFi.persistent(false); |
|||
WiFi.setAutoReconnect(false); |
|||
|
|||
#if defined(ESP_PLATFORM)
|
|||
// Init the wifi driver on ESP32
|
|||
WiFi.mode(WIFI_MODE_MAX); |
|||
WiFi.mode(WIFI_MODE_NULL); |
|||
#endif
|
|||
|
|||
// start serial and filesystem
|
|||
Serial.begin(SERIAL_BAUD_RATE); |
|||
SPIFFS.begin(); |
|||
|
|||
// Start security settings service first
|
|||
securitySettingsService.begin(); |
|||
|
|||
// Start services
|
|||
ntpSettingsService.begin(); |
|||
otaSettingsService.begin(); |
|||
apSettingsService.begin(); |
|||
wifiSettingsService.begin(); |
|||
|
|||
// Serving static resources from /www/
|
|||
server.serveStatic("/js/", SPIFFS, "/www/js/"); |
|||
server.serveStatic("/css/", SPIFFS, "/www/css/"); |
|||
server.serveStatic("/fonts/", SPIFFS, "/www/fonts/"); |
|||
server.serveStatic("/app/", SPIFFS, "/www/app/"); |
|||
server.serveStatic("/favicon.ico", SPIFFS, "/www/favicon.ico"); |
|||
// start the file system (must be done before starting the framework)
|
|||
SPIFFS.begin(); |
|||
|
|||
// Serving all other get requests with "/www/index.htm"
|
|||
// OPTIONS get a straight up 200 response
|
|||
server.onNotFound([](AsyncWebServerRequest *request) { |
|||
if (request->method() == HTTP_GET) { |
|||
request->send(SPIFFS, "/www/index.html"); |
|||
} else if (request->method() == HTTP_OPTIONS) { |
|||
request->send(200); |
|||
} else { |
|||
request->send(404); |
|||
} |
|||
}); |
|||
// start the framework and demo project
|
|||
esp8266React.begin(); |
|||
|
|||
// Disable CORS if required
|
|||
#if defined(ENABLE_CORS)
|
|||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", CORS_ORIGIN); |
|||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization"); |
|||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true"); |
|||
#endif
|
|||
// start the demo project
|
|||
demoProject.begin(); |
|||
|
|||
// start the server
|
|||
server.begin(); |
|||
} |
|||
|
|||
void loop() { |
|||
wifiSettingsService.loop(); |
|||
apSettingsService.loop(); |
|||
ntpSettingsService.loop(); |
|||
otaSettingsService.loop(); |
|||
// run the framework's loop function
|
|||
esp8266React.loop(); |
|||
|
|||
// run the demo project's loop function
|
|||
demoProject.loop(); |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue