Skip to content

Commit 38f5624

Browse files
committed
initial commit
1 parent d5136aa commit 38f5624

26 files changed

+1966
-51
lines changed

interface/.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This is the name of your project. It appears on the sign-in page and in the menu bar.
2-
REACT_APP_PROJECT_NAME=ESP8266 React
2+
REACT_APP_PROJECT_NAME=DataLab v2
33

44
# This is the url path your project will be exposed under.
55
REACT_APP_PROJECT_PATH=project

interface/.env.development

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Change the IP address to that of your ESP device to enable local development of the UI.
22
# Remember to also enable CORS in platformio.ini before uploading the code to the device.
3-
REACT_APP_HTTP_ROOT=http://192.168.0.88
4-
REACT_APP_WEB_SOCKET_ROOT=ws://192.168.0.88
3+
REACT_APP_HTTP_ROOT=http://192.168.1.33
4+
REACT_APP_WEB_SOCKET_ROOT=ws://192.168.1.33

interface/public/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
66
<link rel="stylesheet" href="%PUBLIC_URL%/css/roboto.css">
77
<link rel="manifest" href="%PUBLIC_URL%/app/manifest.json">
8-
<title>ESP8266 React</title>
8+
<title>DataLab v2</title>
99
</head>
1010
<body>
1111
<noscript>

interface/src/project/DemoProject.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { MenuAppBar } from '../components';
88
import { AuthenticatedRoute } from '../authentication';
99

1010
import DemoInformation from './DemoInformation';
11+
import ManageSensorsController from './ManageSensorsController';
1112
import LightStateRestController from './LightStateRestController';
1213
import LightStateWebSocketController from './LightStateWebSocketController';
1314
import LightMqttSettingsController from './LightMqttSettingsController';
@@ -20,15 +21,18 @@ class DemoProject extends Component<RouteComponentProps> {
2021

2122
render() {
2223
return (
23-
<MenuAppBar sectionTitle="Demo Project">
24+
<MenuAppBar sectionTitle="DataLab">
2425
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
25-
<Tab value={`/${PROJECT_PATH}/demo/information`} label="Information" />
26+
<Tab value={`/${PROJECT_PATH}/demo/information`} label="Information" />
27+
<Tab value={`/${PROJECT_PATH}/demo/sensors`} label="sensors" />
2628
<Tab value={`/${PROJECT_PATH}/demo/rest`} label="REST Controller" />
2729
<Tab value={`/${PROJECT_PATH}/demo/socket`} label="WebSocket Controller" />
2830
<Tab value={`/${PROJECT_PATH}/demo/mqtt`} label="MQTT Controller" />
2931
</Tabs>
3032
<Switch>
3133
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/information`} component={DemoInformation} />
34+
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/sensors`} component={ManageSensorsController} />
35+
3236
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/rest`} component={LightStateRestController} />
3337
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/socket`} component={LightStateWebSocketController} />
3438
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/mqtt`} component={LightMqttSettingsController} />
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React, { Component } from 'react';
2+
3+
import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
4+
5+
import ManageSensorsForm from './ManageSensorsForm';
6+
import { SensorsSettings } from './types';
7+
import { ENDPOINT_ROOT } from '../api';
8+
export const SENSORS_ENDPOINT = ENDPOINT_ROOT + "sensorsState";
9+
10+
type ManageSensorsControllerProps = RestControllerProps<SensorsSettings>;
11+
12+
class ManageSensorsController extends Component<ManageSensorsControllerProps> {
13+
14+
componentDidMount() {
15+
this.props.loadData();
16+
}
17+
18+
render() {
19+
return (
20+
<SectionContent title="Manage Sensors" titleGutter>
21+
<RestFormLoader
22+
{...this.props}
23+
render={formProps => <ManageSensorsForm {...formProps} />}
24+
/>
25+
</SectionContent>
26+
)
27+
}
28+
29+
}
30+
31+
export default restController(SENSORS_ENDPOINT, ManageSensorsController);
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
import React, { Fragment } from 'react';
2+
import { ValidatorForm } from 'react-material-ui-form-validator';
3+
4+
import { Table, TableBody, TableCell, TableHead, TableFooter, TableRow, withWidth, WithWidthProps, isWidthDown } from '@material-ui/core';
5+
import { Box, Button, Typography, } from '@material-ui/core';
6+
7+
import EditIcon from '@material-ui/icons/Edit';
8+
import DeleteIcon from '@material-ui/icons/Delete';
9+
import CloseIcon from '@material-ui/icons/Close';
10+
import CheckIcon from '@material-ui/icons/Check';
11+
import IconButton from '@material-ui/core/IconButton';
12+
import SaveIcon from '@material-ui/icons/Save';
13+
import CompassCalibration from '@material-ui/icons/CompassCalibration';
14+
15+
import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication';
16+
import { RestFormProps, FormActions, FormButton, extractEventValue } from '../components';
17+
18+
import SensorForm from './SensorForm';
19+
import { SensorsSettings, Sensor } from './types';
20+
21+
22+
23+
24+
function compareSensors(a: Sensor, b: Sensor) {
25+
if (a.name < b.name) {
26+
return -1;
27+
}
28+
if (a.name > b.name) {
29+
return 1;
30+
}
31+
return 0;
32+
}
33+
34+
type ManageSensorsFormProps = RestFormProps<SensorsSettings> & AuthenticatedContextProps & WithWidthProps;
35+
36+
type ManageSensorsFormState = {
37+
creating: boolean;
38+
sensor?: Sensor;
39+
driverlist?: string[];
40+
}
41+
42+
class ManageSensorsForm extends React.Component<ManageSensorsFormProps, ManageSensorsFormState> {
43+
44+
state: ManageSensorsFormState = {
45+
creating: false
46+
};
47+
48+
createSensor = () => {
49+
this.setState({
50+
creating: true,
51+
sensor: new Sensor()
52+
});
53+
};
54+
componentDidMount = ()=> {
55+
console.log("manage sensor mounted");
56+
console.log(this.props.data.sensors);
57+
};
58+
uniqueSensorname = (name: string) => {
59+
60+
return this.props.data.sensors==undefined || !this.props.data.sensors.find(u => u.name === name);
61+
}
62+
63+
// noAdminConfigured = () => {
64+
// return !this.props.data.sensors.find(u => u.enabled);
65+
// }
66+
67+
removeSensor = (sensor: Sensor) => {
68+
const { data } = this.props;
69+
const sensors = data.sensors.filter(u => u.name !== sensor.name);
70+
this.props.setData({ ...data, sensors });
71+
}
72+
73+
startEditingSensor = (sensor: Sensor) => {
74+
this.setState({
75+
creating: false,
76+
sensor: sensor
77+
});
78+
};
79+
80+
cancelEditingSensor = () => {
81+
this.setState({
82+
sensor: undefined
83+
});
84+
}
85+
86+
doneEditingSensor = () => {
87+
const { sensor } = this.state;
88+
console.log("props before", this.props.data);
89+
90+
if (sensor) {
91+
const { data } = this.props;
92+
const sensors = data.sensors.filter(u => u.name !== sensor.name);
93+
// sensors.push(sensor);
94+
sensors.push(JSON.parse(JSON.stringify(sensor)))//need a deep clone here
95+
this.props.setData({ ...data, sensors });
96+
this.setState({
97+
sensor: undefined
98+
});
99+
}
100+
console.log("props before", this.props.data);
101+
};
102+
103+
handleSensorParamChange = (key: string) =>(event: React.ChangeEvent<HTMLInputElement>) => {
104+
let sensor ={ ...this.state.sensor!}
105+
let param = sensor.driver.config as Record<string, any>
106+
param[key]=extractEventValue(event) as string
107+
// param.set(key, extractEventValue(event) as string)
108+
this.setState( {sensor})
109+
};
110+
111+
handleSensorDriverChange = () => (event: React.ChangeEvent<HTMLInputElement>) => {
112+
console.log("Now state is ",this.state)
113+
// const csensor = { ...this.state.sensor}
114+
115+
// csensor["driver"] = this.props.data.drivers[+event.target.value]
116+
// this.setState({ csensor })
117+
this.setState({ sensor: { ...this.state.sensor!, driver: this.props.data.drivers[+event.target.value] } });
118+
console.log("Now state is ",this.state)
119+
};
120+
121+
122+
handleSensorValueChange = (name: keyof Sensor) => (event: React.ChangeEvent<HTMLInputElement>) => {
123+
this.setState({ sensor: { ...this.state.sensor!, [name]: extractEventValue(event) } });
124+
};
125+
126+
onSubmit = () => {
127+
this.props.saveData();
128+
this.props.authenticatedContext.refresh();
129+
}
130+
secondsToHms = (d:number) => {
131+
d = Number(d);
132+
var h = Math.floor(d / 3600);
133+
var m = Math.floor(d % 3600 / 60);
134+
var s = Math.floor(d % 3600 % 60);
135+
136+
var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
137+
var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
138+
var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
139+
return hDisplay + mDisplay + sDisplay;
140+
}
141+
142+
render() {
143+
const { width, data } = this.props;
144+
if (data.sensors == undefined) {
145+
data.sensors = [];
146+
}
147+
const { sensor, creating } = this.state;
148+
149+
let table = <TableRow><TableCell colSpan={6}>No sensor defined</TableCell></TableRow>;
150+
151+
return (
152+
<Fragment>
153+
<ValidatorForm onSubmit={this.onSubmit}>
154+
<Table size="small" padding={isWidthDown('xs', width!) ? "none" : "default"}>
155+
<TableHead>
156+
<TableRow>
157+
<TableCell>Name</TableCell>
158+
<TableCell align="center">Enabled</TableCell>
159+
<TableCell align="center">Interval</TableCell>
160+
<TableCell align="center">Driver</TableCell>
161+
<TableCell align="center">Params</TableCell>
162+
<TableCell />
163+
</TableRow>
164+
</TableHead>
165+
<TableBody>
166+
167+
168+
{(data.sensors != null && data.sensors.length >0) ?
169+
data.sensors.sort(compareSensors).map(csensor => (
170+
<TableRow key={csensor.name}>
171+
<TableCell component="th" scope="row">
172+
{csensor.name}
173+
</TableCell>
174+
<TableCell align="center">
175+
{
176+
csensor.enabled? <CheckIcon /> : <CloseIcon />
177+
}
178+
</TableCell>
179+
<TableCell component="th" align="center" scope="row">
180+
{this.secondsToHms(csensor.interval)}
181+
</TableCell>
182+
<TableCell component="th" scope="row">
183+
{csensor.driver?.name}
184+
</TableCell>
185+
<TableCell component="th" scope="row">
186+
<Table size="small" >
187+
<TableBody>
188+
<TableRow>
189+
190+
{csensor.driver.config && Object.entries(csensor.driver.config as Object).map(([key ,value]) => {
191+
return <TableCell key={csensor.name + key}>{key}: {value}</TableCell>
192+
})}
193+
194+
</TableRow>
195+
</TableBody>
196+
</Table>
197+
</TableCell>
198+
199+
200+
201+
<TableCell align="center">
202+
<IconButton size="small" aria-label="Delete" onClick={() => this.removeSensor(csensor)}>
203+
<DeleteIcon />
204+
</IconButton>
205+
<IconButton size="small" aria-label="Edit" onClick={() => this.startEditingSensor(csensor)}>
206+
<EditIcon />
207+
</IconButton>
208+
</TableCell>
209+
</TableRow>
210+
))
211+
: table
212+
}
213+
</TableBody>
214+
<TableFooter >
215+
<TableRow>
216+
<TableCell colSpan={5} />
217+
<TableCell align="center" padding="default">
218+
<Button startIcon={<CompassCalibration />} variant="contained" color="secondary" onClick={this.createSensor}>
219+
Add Sensor
220+
</Button>
221+
</TableCell>
222+
</TableRow>
223+
</TableFooter>
224+
</Table>
225+
{
226+
// this.noAdminConfigured() &&
227+
// (
228+
// <Box bgcolor="error.main" color="error.contrastText" p={2} mt={2} mb={2}>
229+
// <Typography variant="body1">
230+
// You must have at least one admin sensor configured.
231+
// </Typography>
232+
// </Box>
233+
// )
234+
}
235+
<FormActions>
236+
{/* <FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit" disabled={this.noAdminConfigured()}> */}
237+
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit" >
238+
Save
239+
</FormButton>
240+
</FormActions>
241+
</ValidatorForm>
242+
{
243+
sensor &&
244+
<SensorForm
245+
sensor={sensor}
246+
driverlist={data.drivers}
247+
creating={creating}
248+
onDoneEditing={this.doneEditingSensor}
249+
onCancelEditing={this.cancelEditingSensor}
250+
handleDriverChange={this.handleSensorDriverChange}
251+
handleParamChange={this.handleSensorParamChange}
252+
handleValueChange={this.handleSensorValueChange}
253+
uniqueSensorname={this.uniqueSensorname}
254+
/>
255+
}
256+
</Fragment>
257+
);
258+
}
259+
260+
}
261+
262+
export default withAuthenticatedContext(withWidth()(ManageSensorsForm));

interface/src/project/ProjectMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ProjectMenu extends Component<RouteComponentProps> {
1616
<ListItemIcon>
1717
<SettingsRemoteIcon />
1818
</ListItemIcon>
19-
<ListItemText primary="Demo Project" />
19+
<ListItemText primary="DataLab" />
2020
</ListItem>
2121
</List>
2222
)

0 commit comments

Comments
 (0)