add demo project implementation

This commit is contained in:
Rick Watson 2019-08-09 15:53:39 +01:00
parent aeea0d9aa6
commit df06e58fb0
12 changed files with 182 additions and 34 deletions

View File

@ -0,0 +1,3 @@
{
"blink_speed": 100
}

View File

@ -1 +1 @@
REACT_APP_ENDPOINT_ROOT=http://192.168.0.19/rest/
REACT_APP_ENDPOINT_ROOT=http://192.168.0.20/rest/

View 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
};

View File

@ -1,6 +1,7 @@
import React from 'react';
import { withSnackbar } from 'notistack';
import { redirectingAuthorizedFetch } from '../authentication/Authentication';
/*
* 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;
data[name] = event.target.value;
data[name] = newValue;
this.setState({ data });
};

View File

@ -12,16 +12,16 @@ class SecuritySettings extends Component {
}
render() {
const { data, fetched, errorMessage } = this.props;
const { data, fetched, errorMessage, saveData, loadData, handleValueChange } = this.props;
return (
<SectionContent title="Security Settings">
<SecuritySettingsForm
securitySettings={data}
securitySettingsFetched={fetched}
errorMessage={errorMessage}
onSubmit={this.props.saveData}
onReset={this.props.loadData}
handleValueChange={this.props.handleValueChange}
onSubmit={saveData}
onReset={loadData}
handleValueChange={handleValueChange}
/>
</SectionContent>
)

View File

@ -1,22 +1,78 @@
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
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 {
render() {
componentDidMount() {
this.props.loadData();
}
render() {
const { data, fetched, errorMessage, saveData, loadData, handleValueChange } = this.props;
return (
<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>
)
}
}
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);

View File

@ -7,6 +7,7 @@ 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 => ({

View File

@ -8,7 +8,6 @@ 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';
import Divider from '@material-ui/core/Divider';
class ProjectMenu extends Component {

View File

@ -7,9 +7,10 @@
;
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:node32s]
platform = espressif32
board = node32s
[env:esp12e]
platform = espressif8266
board = esp12e
board_build.f_cpu = 160000000L
extra_scripts = pre:timelib_fix.py

View File

@ -1,9 +1,25 @@
#include <DemoProject.h>
void DemoProject::begin() {
void DemoProject::init(AsyncWebServer* server) {
AdminSettingsService::init(server);
pinMode(BLINK_LED, OUTPUT);
}
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;
}

View File

@ -1,23 +1,35 @@
#ifndef DemoProject_h
#define DemoProject_h
#include <ESPAsyncWebServer.h>
#include <SecurityManager.h>
#include <SettingsService.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:
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();
private:
AsyncWebServer* _server;
SecurityManager* _securityManager;
unsigned long _lastBlink = 0;
uint8_t _blinkSpeed = 255;
protected:
void readFromJsonObject(JsonObject& root);
void writeToJsonObject(JsonObject& root);
};
#endif

View File

@ -7,9 +7,10 @@
AsyncWebServer server(80);
ESP8266React espServer(&SPIFFS);
DemoProject demoProject = DemoProject(&server, espServer.getSecurityManager());
DemoProject demoProject = DemoProject(&SPIFFS, espServer.getSecurityManager());
void setup() {
// start serial and filesystem
Serial.begin(SERIAL_BAUD_RATE);
SPIFFS.begin();
@ -17,15 +18,16 @@ void setup() {
espServer.init(&server);
// begin the demo project
demoProject.begin();
demoProject.init(&server);
// start the server
server.begin();
}
void loop() {
// run the framework loop
// run the framework's loop function
espServer.loop();
// run the demo project loop
// run the demo project's loop function
demoProject.loop();
}