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>
|
#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>
|
#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)); |
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, std::placeholders::_1)); |
||||
|
|
||||
_signInHandler.setUri(SIGN_IN_PATH); |
_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 |
#ifndef NTPSettingsService_h |
||||
#define NTPSettingsService_h |
#define NTPSettingsService_h |
||||
|
|
||||
#include <SettingsService.h> |
|
||||
|
#include <AdminSettingsService.h> |
||||
|
|
||||
#include <TimeLib.h> |
#include <TimeLib.h> |
||||
#include <NtpClientLib.h> |
#include <NtpClientLib.h> |
@ -1,8 +1,8 @@ |
|||||
#include <NTPStatus.h>
|
#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>
|
#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>
|
#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) |
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) |
securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN) |
||||
); |
); |
||||
} |
|
||||
|
}; |
||||
|
|
||||
void WiFiScanner::scanNetworks(AsyncWebServerRequest *request) { |
void WiFiScanner::scanNetworks(AsyncWebServerRequest *request) { |
||||
if (WiFi.scanComplete() != -1){ |
if (WiFi.scanComplete() != -1){ |
@ -1,9 +1,16 @@ |
|||||
#include <WiFiSettingsService.h>
|
#include <WiFiSettingsService.h>
|
||||
|
|
||||
WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, WIFI_SETTINGS_SERVICE_PATH, WIFI_SETTINGS_FILE) { |
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)
|
#if defined(ESP8266)
|
||||
_onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); |
_onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); |
||||
#elif defined(ESP_PLATFORM)
|
#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); |
WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); |
||||
#endif
|
#endif
|
||||
} |
} |
@ -1,7 +1,7 @@ |
|||||
#ifndef WiFiSettingsService_h |
#ifndef WiFiSettingsService_h |
||||
#define WiFiSettingsService_h |
#define WiFiSettingsService_h |
||||
|
|
||||
#include <SettingsService.h> |
|
||||
|
#include <AdminSettingsService.h> |
||||
#include <IPAddress.h> |
#include <IPAddress.h> |
||||
|
|
||||
#define WIFI_SETTINGS_FILE "/config/wifiSettings.json" |
#define WIFI_SETTINGS_FILE "/config/wifiSettings.json" |
@ -1,8 +1,8 @@ |
|||||
#include <WiFiStatus.h>
|
#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)
|
#if defined(ESP8266)
|
||||
_onStationModeConnectedHandler = WiFi.onStationModeConnected(onStationModeConnected); |
_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 <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
|
#define SERIAL_BAUD_RATE 115200
|
||||
|
|
||||
AsyncWebServer server(80); |
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() { |
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); |
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(); |
server.begin(); |
||||
} |
} |
||||
|
|
||||
void loop() { |
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