add demo project implementation
This commit is contained in:
parent
aeea0d9aa6
commit
df06e58fb0
3
data/config/demoSettings.json
Normal file
3
data/config/demoSettings.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"blink_speed": 100
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
REACT_APP_ENDPOINT_ROOT=http://192.168.0.19/rest/
|
REACT_APP_ENDPOINT_ROOT=http://192.168.0.20/rest/
|
||||||
|
57
interface/src/components/LoadingNotification.js
Normal file
57
interface/src/components/LoadingNotification.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
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, children } = props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
fetched ?
|
||||||
|
errorMessage ?
|
||||||
|
<div className={classes.loadingSettings}>
|
||||||
|
<Typography variant="h4" className={classes.loadingSettingsDetails}>
|
||||||
|
{errorMessage}
|
||||||
|
</Typography>
|
||||||
|
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
children
|
||||||
|
:
|
||||||
|
<div className={classes.loadingSettings}>
|
||||||
|
<LinearProgress className={classes.loadingSettingsDetails} />
|
||||||
|
<Typography variant="h4" className={classes.loadingSettingsDetails}>
|
||||||
|
Loading...
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadingNotification.propTypes = {
|
||||||
|
fetched: PropTypes.bool.isRequired,
|
||||||
|
onReset: PropTypes.func.isRequired,
|
||||||
|
errorMessage: PropTypes.string
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { withSnackbar } from 'notistack';
|
import { withSnackbar } from 'notistack';
|
||||||
import { redirectingAuthorizedFetch } from '../authentication/Authentication';
|
import { redirectingAuthorizedFetch } from '../authentication/Authentication';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It is unlikely this application will grow complex enough to require redux.
|
* It is unlikely this application will grow complex enough to require redux.
|
||||||
*
|
*
|
||||||
@ -86,9 +87,9 @@ export const restComponent = (endpointUrl, FormComponent) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleValueChange = name => event => {
|
handleValueChange = name => (event, newValue) => {
|
||||||
const { data } = this.state;
|
const { data } = this.state;
|
||||||
data[name] = event.target.value;
|
data[name] = newValue;
|
||||||
this.setState({ data });
|
this.setState({ data });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,16 +12,16 @@ class SecuritySettings extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { data, fetched, errorMessage } = this.props;
|
const { data, fetched, errorMessage, saveData, loadData, handleValueChange } = this.props;
|
||||||
return (
|
return (
|
||||||
<SectionContent title="Security Settings">
|
<SectionContent title="Security Settings">
|
||||||
<SecuritySettingsForm
|
<SecuritySettingsForm
|
||||||
securitySettings={data}
|
securitySettings={data}
|
||||||
securitySettingsFetched={fetched}
|
securitySettingsFetched={fetched}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
onSubmit={this.props.saveData}
|
onSubmit={saveData}
|
||||||
onReset={this.props.loadData}
|
onReset={loadData}
|
||||||
handleValueChange={this.props.handleValueChange}
|
handleValueChange={handleValueChange}
|
||||||
/>
|
/>
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
)
|
)
|
||||||
|
@ -1,22 +1,78 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
|
||||||
import SectionContent from '../components/SectionContent';
|
import SectionContent from '../components/SectionContent';
|
||||||
|
import { restComponent } from '../components/RestComponent';
|
||||||
|
import LoadingNotification from '../components/LoadingNotification';
|
||||||
|
|
||||||
const styles = theme => ({
|
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';
|
||||||
|
import { ValidatorForm } from 'react-material-ui-form-validator';
|
||||||
|
|
||||||
});
|
export const DEMO_SETTINGS_ENDPOINT = process.env.REACT_APP_ENDPOINT_ROOT + "demoSettings";
|
||||||
|
|
||||||
|
const valueToPercentage = (value) => `${Math.round(value / 255 * 100)}%`;
|
||||||
|
|
||||||
class DemoController extends Component {
|
class DemoController extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { data, fetched, errorMessage, saveData, loadData, handleValueChange } = this.props;
|
||||||
return (
|
return (
|
||||||
<SectionContent title="Controller" titleGutter>
|
<SectionContent title="Controller" titleGutter>
|
||||||
TODO - This will contain a form which controls the speed of the built in LED.
|
<LoadingNotification
|
||||||
|
onReset={loadData}
|
||||||
|
fetched={fetched}
|
||||||
|
errorMessage={errorMessage}>
|
||||||
|
<DemoControllerForm
|
||||||
|
demoSettings={data}
|
||||||
|
onReset={loadData}
|
||||||
|
onSubmit={saveData}
|
||||||
|
handleValueChange={handleValueChange}
|
||||||
|
/>
|
||||||
|
</LoadingNotification>
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles(styles)(DemoController);
|
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, handleValueChange } = 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={handleValueChange('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);
|
||||||
|
@ -7,6 +7,7 @@ import TableCell from '@material-ui/core/TableCell';
|
|||||||
import TableBody from '@material-ui/core/TableBody';
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
import TableRow from '@material-ui/core/TableRow';
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
import SectionContent from '../components/SectionContent';
|
import SectionContent from '../components/SectionContent';
|
||||||
|
|
||||||
const styles = theme => ({
|
const styles = theme => ({
|
||||||
|
@ -8,7 +8,6 @@ import ListItem from '@material-ui/core/ListItem';
|
|||||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import ListItemText from '@material-ui/core/ListItemText';
|
import ListItemText from '@material-ui/core/ListItemText';
|
||||||
import SettingsRemoteIcon from '@material-ui/icons/SettingsRemote';
|
import SettingsRemoteIcon from '@material-ui/icons/SettingsRemote';
|
||||||
import Divider from '@material-ui/core/Divider';
|
|
||||||
|
|
||||||
class ProjectMenu extends Component {
|
class ProjectMenu extends Component {
|
||||||
|
|
||||||
|
@ -7,9 +7,10 @@
|
|||||||
;
|
;
|
||||||
; Please visit documentation for the other options and examples
|
; Please visit documentation for the other options and examples
|
||||||
; http://docs.platformio.org/page/projectconf.html
|
; http://docs.platformio.org/page/projectconf.html
|
||||||
[env:node32s]
|
[env:esp12e]
|
||||||
platform = espressif32
|
platform = espressif8266
|
||||||
board = node32s
|
board = esp12e
|
||||||
|
board_build.f_cpu = 160000000L
|
||||||
|
|
||||||
extra_scripts = pre:timelib_fix.py
|
extra_scripts = pre:timelib_fix.py
|
||||||
|
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
#include <DemoProject.h>
|
#include <DemoProject.h>
|
||||||
|
|
||||||
void DemoProject::begin() {
|
void DemoProject::init(AsyncWebServer* server) {
|
||||||
|
AdminSettingsService::init(server);
|
||||||
|
pinMode(BLINK_LED, OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemoProject::loop() {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,34 @@
|
|||||||
#ifndef DemoProject_h
|
#ifndef DemoProject_h
|
||||||
#define DemoProject_h
|
#define DemoProject_h
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <SettingsService.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
|
||||||
class DemoProject {
|
#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:
|
public:
|
||||||
|
|
||||||
DemoProject(AsyncWebServer *server, SecurityManager* securityManager) : _server(server), _securityManager(securityManager) {}
|
DemoProject(FS* fs, SecurityManager* securityManager) : AdminSettingsService(fs, securityManager, DEMO_SETTINGS_PATH, DEMO_SETTINGS_FILE) {}
|
||||||
|
~DemoProject() {}
|
||||||
|
|
||||||
void begin();
|
void init(AsyncWebServer* server);
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
AsyncWebServer* _server;
|
unsigned long _lastBlink = 0;
|
||||||
SecurityManager* _securityManager;
|
uint8_t _blinkSpeed = 255;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void readFromJsonObject(JsonObject& root);
|
||||||
|
void writeToJsonObject(JsonObject& root);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
10
src/main.cpp
10
src/main.cpp
@ -7,9 +7,10 @@
|
|||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
ESP8266React espServer(&SPIFFS);
|
ESP8266React espServer(&SPIFFS);
|
||||||
|
|
||||||
DemoProject demoProject = DemoProject(&server, espServer.getSecurityManager());
|
DemoProject demoProject = DemoProject(&SPIFFS, espServer.getSecurityManager());
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
// start serial and filesystem
|
||||||
Serial.begin(SERIAL_BAUD_RATE);
|
Serial.begin(SERIAL_BAUD_RATE);
|
||||||
SPIFFS.begin();
|
SPIFFS.begin();
|
||||||
|
|
||||||
@ -17,15 +18,16 @@ void setup() {
|
|||||||
espServer.init(&server);
|
espServer.init(&server);
|
||||||
|
|
||||||
// begin the demo project
|
// begin the demo project
|
||||||
demoProject.begin();
|
demoProject.init(&server);
|
||||||
|
|
||||||
|
// start the server
|
||||||
server.begin();
|
server.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
// run the framework loop
|
// run the framework's loop function
|
||||||
espServer.loop();
|
espServer.loop();
|
||||||
|
|
||||||
// run the demo project loop
|
// run the demo project's loop function
|
||||||
demoProject.loop();
|
demoProject.loop();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user