mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
eslint
This commit is contained in:
@@ -1,23 +1,24 @@
|
||||
import React from 'react';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
|
||||
type BoardProfiles = {
|
||||
[name: string]: string
|
||||
[name: string]: string;
|
||||
};
|
||||
|
||||
export const BOARD_PROFILES: BoardProfiles = {
|
||||
"S32": "BBQKees Gateway S32",
|
||||
"E32": "BBQKees Gateway E32",
|
||||
"NODEMCU": "NodeMCU 32S",
|
||||
"MH-ET": "MH-ET Live D1 Mini",
|
||||
"LOLIN": "Lolin D32",
|
||||
"OLIMEX": "Olimex ESP32-EVB",
|
||||
"TLK110": "Generic Ethernet (TLK110)",
|
||||
"LAN8720": "Generic Ethernet (LAN8720)"
|
||||
}
|
||||
S32: 'BBQKees Gateway S32',
|
||||
E32: 'BBQKees Gateway E32',
|
||||
NODEMCU: 'NodeMCU 32S',
|
||||
'MH-ET': 'MH-ET Live D1 Mini',
|
||||
LOLIN: 'Lolin D32',
|
||||
OLIMEX: 'Olimex ESP32-EVB',
|
||||
TLK110: 'Generic Ethernet (TLK110)',
|
||||
LAN8720: 'Generic Ethernet (LAN8720)'
|
||||
};
|
||||
|
||||
export function boardProfileSelectItems() {
|
||||
return Object.keys(BOARD_PROFILES).map(code => (
|
||||
<MenuItem key={code} value={code}>{BOARD_PROFILES[code]}</MenuItem>
|
||||
));
|
||||
return Object.keys(BOARD_PROFILES).map((code) => (
|
||||
<MenuItem key={code} value={code}>
|
||||
{BOARD_PROFILES[code]}
|
||||
</MenuItem>
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom'
|
||||
import { Component } from 'react';
|
||||
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
import { Tabs, Tab } from '@material-ui/core';
|
||||
|
||||
@@ -12,30 +12,43 @@ import EMSESPDevicesController from './EMSESPDevicesController';
|
||||
import EMSESPHelp from './EMSESPHelp';
|
||||
|
||||
class EMSESP extends Component<RouteComponentProps> {
|
||||
|
||||
handleTabChange = (event: React.ChangeEvent<{}>, path: string) => {
|
||||
handleTabChange = (path: string) => {
|
||||
this.props.history.push(path);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MenuAppBar sectionTitle="Dashboard">
|
||||
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
|
||||
<Tabs
|
||||
value={this.props.match.url}
|
||||
onChange={(e, path) => this.handleTabChange(path)}
|
||||
variant="fullWidth"
|
||||
>
|
||||
<Tab value={`/${PROJECT_PATH}/devices`} label="Devices & Sensors" />
|
||||
<Tab value={`/${PROJECT_PATH}/status`} label="EMS Status" />
|
||||
<Tab value={`/${PROJECT_PATH}/help`} label="EMS-ESP Help" />
|
||||
</Tabs>
|
||||
<Switch>
|
||||
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/devices`} component={EMSESPDevicesController} />
|
||||
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/status`} component={EMSESPStatusController} />
|
||||
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/help`} component={EMSESPHelp} />
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path={`/${PROJECT_PATH}/devices`}
|
||||
component={EMSESPDevicesController}
|
||||
/>
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path={`/${PROJECT_PATH}/status`}
|
||||
component={EMSESPStatusController}
|
||||
/>
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path={`/${PROJECT_PATH}/help`}
|
||||
component={EMSESPHelp}
|
||||
/>
|
||||
<Redirect to={`/${PROJECT_PATH}/devices`} />
|
||||
</Switch>
|
||||
</MenuAppBar>
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default EMSESP;
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
|
||||
import {
|
||||
restController,
|
||||
RestControllerProps,
|
||||
RestFormLoader,
|
||||
SectionContent
|
||||
} from '../components';
|
||||
import { ENDPOINT_ROOT } from '../api';
|
||||
import EMSESPDevicesForm from './EMSESPDevicesForm';
|
||||
import { EMSESPDevices } from './EMSESPtypes';
|
||||
|
||||
export const EMSESP_DEVICES_ENDPOINT = ENDPOINT_ROOT + "allDevices";
|
||||
export const EMSESP_DEVICES_ENDPOINT = ENDPOINT_ROOT + 'allDevices';
|
||||
|
||||
type EMSESPDevicesControllerProps = RestControllerProps<EMSESPDevices>;
|
||||
|
||||
class EMSESPDevicesController extends Component<EMSESPDevicesControllerProps> {
|
||||
componentDidMount() {
|
||||
this.props.loadData();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.loadData();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SectionContent title="Devices & Sensors">
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={formProps => <EMSESPDevicesForm {...formProps} />}
|
||||
/>
|
||||
</SectionContent>
|
||||
)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<SectionContent title="Devices & Sensors">
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={(formProps) => <EMSESPDevicesForm {...formProps} />}
|
||||
/>
|
||||
</SectionContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default restController(EMSESP_DEVICES_ENDPOINT, EMSESPDevicesController);
|
||||
|
||||
@@ -1,38 +1,62 @@
|
||||
import React, { Component, Fragment } from "react";
|
||||
import { withStyles, Theme, createStyles } from "@material-ui/core/styles";
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { withStyles, Theme, createStyles } from '@material-ui/core/styles';
|
||||
|
||||
import {
|
||||
Table, TableBody, TableCell, TableHead, TableRow, TableContainer, withWidth, WithWidthProps, isWidthDown,
|
||||
Button, Tooltip, DialogTitle, DialogContent, DialogActions, Box, Dialog, Typography
|
||||
} from "@material-ui/core";
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableContainer,
|
||||
withWidth,
|
||||
WithWidthProps,
|
||||
isWidthDown,
|
||||
Button,
|
||||
Tooltip,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Box,
|
||||
Dialog,
|
||||
Typography
|
||||
} from '@material-ui/core';
|
||||
|
||||
import RefreshIcon from "@material-ui/icons/Refresh";
|
||||
import ListIcon from "@material-ui/icons/List";
|
||||
import RefreshIcon from '@material-ui/icons/Refresh';
|
||||
import ListIcon from '@material-ui/icons/List';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
|
||||
import { redirectingAuthorizedFetch, withAuthenticatedContext, AuthenticatedContextProps } from "../authentication";
|
||||
import { RestFormProps, FormButton, extractEventValue } from "../components";
|
||||
import {
|
||||
redirectingAuthorizedFetch,
|
||||
withAuthenticatedContext,
|
||||
AuthenticatedContextProps
|
||||
} from '../authentication';
|
||||
import { RestFormProps, FormButton, extractEventValue } from '../components';
|
||||
|
||||
import { EMSESPDevices, EMSESPDeviceData, Device, DeviceValue } from "./EMSESPtypes";
|
||||
import {
|
||||
EMSESPDevices,
|
||||
EMSESPDeviceData,
|
||||
Device,
|
||||
DeviceValue
|
||||
} from './EMSESPtypes';
|
||||
|
||||
import ValueForm from './ValueForm';
|
||||
|
||||
import { ENDPOINT_ROOT } from "../api";
|
||||
import { ENDPOINT_ROOT } from '../api';
|
||||
|
||||
export const SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + "scanDevices";
|
||||
export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + "deviceData";
|
||||
export const WRITE_VALUE_ENDPOINT = ENDPOINT_ROOT + "writeValue";
|
||||
export const SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + 'scanDevices';
|
||||
export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + 'deviceData';
|
||||
export const WRITE_VALUE_ENDPOINT = ENDPOINT_ROOT + 'writeValue';
|
||||
|
||||
const StyledTableCell = withStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
head: {
|
||||
backgroundColor: theme.palette.common.black,
|
||||
color: theme.palette.common.white,
|
||||
color: theme.palette.common.white
|
||||
},
|
||||
body: {
|
||||
fontSize: 14,
|
||||
},
|
||||
fontSize: 14
|
||||
}
|
||||
})
|
||||
)(TableCell);
|
||||
|
||||
@@ -42,8 +66,8 @@ const CustomTooltip = withStyles((theme: Theme) => ({
|
||||
color: 'white',
|
||||
boxShadow: theme.shadows[1],
|
||||
fontSize: 11,
|
||||
border: '1px solid #dadde9',
|
||||
},
|
||||
border: '1px solid #dadde9'
|
||||
}
|
||||
}))(Tooltip);
|
||||
|
||||
function compareDevices(a: Device, b: Device) {
|
||||
@@ -64,63 +88,81 @@ interface EMSESPDevicesFormState {
|
||||
devicevalue?: DeviceValue;
|
||||
}
|
||||
|
||||
type EMSESPDevicesFormProps = RestFormProps<EMSESPDevices> & AuthenticatedContextProps & WithWidthProps;
|
||||
type EMSESPDevicesFormProps = RestFormProps<EMSESPDevices> &
|
||||
AuthenticatedContextProps &
|
||||
WithWidthProps;
|
||||
|
||||
function formatTemp(t: string) {
|
||||
if (t == null) {
|
||||
return "n/a";
|
||||
return 'n/a';
|
||||
}
|
||||
return t + " °C";
|
||||
return t + ' °C';
|
||||
}
|
||||
|
||||
function formatUnit(u: string) {
|
||||
if (u == null) {
|
||||
return u;
|
||||
}
|
||||
return " " + u;
|
||||
return ' ' + u;
|
||||
}
|
||||
|
||||
class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesFormState> {
|
||||
class EMSESPDevicesForm extends Component<
|
||||
EMSESPDevicesFormProps,
|
||||
EMSESPDevicesFormState
|
||||
> {
|
||||
state: EMSESPDevicesFormState = {
|
||||
confirmScanDevices: false,
|
||||
processing: false
|
||||
};
|
||||
|
||||
handleValueChange = (name: keyof DeviceValue) => (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ devicevalue: { ...this.state.devicevalue!, [name]: extractEventValue(event) } });
|
||||
handleValueChange = (name: keyof DeviceValue) => (
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
this.setState({
|
||||
devicevalue: {
|
||||
...this.state.devicevalue!,
|
||||
[name]: extractEventValue(event)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
cancelEditingValue = () => {
|
||||
this.setState({
|
||||
devicevalue: undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
doneEditingValue = () => {
|
||||
const { devicevalue } = this.state;
|
||||
|
||||
redirectingAuthorizedFetch(WRITE_VALUE_ENDPOINT, {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ devicevalue: devicevalue }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
this.props.enqueueSnackbar("Write command sent to device", { variant: "success" });
|
||||
this.props.enqueueSnackbar('Write command sent to device', {
|
||||
variant: 'success'
|
||||
});
|
||||
} else if (response.status === 204) {
|
||||
this.props.enqueueSnackbar("Write command failed", { variant: "error" });
|
||||
this.props.enqueueSnackbar('Write command failed', {
|
||||
variant: 'error'
|
||||
});
|
||||
} else if (response.status === 403) {
|
||||
this.props.enqueueSnackbar("Write access denied", { variant: "error" });
|
||||
this.props.enqueueSnackbar('Write access denied', {
|
||||
variant: 'error'
|
||||
});
|
||||
} else {
|
||||
throw Error("Unexpected response code: " + response.status);
|
||||
throw Error('Unexpected response code: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.props.enqueueSnackbar(
|
||||
error.message || "Problem writing value", { variant: "error" }
|
||||
);
|
||||
this.props.enqueueSnackbar(error.message || 'Problem writing value', {
|
||||
variant: 'error'
|
||||
});
|
||||
});
|
||||
|
||||
if (devicevalue) {
|
||||
@@ -128,20 +170,19 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
devicevalue: undefined
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
sendCommand = (i: any) => {
|
||||
sendCommand = (i: number) => {
|
||||
this.setState({
|
||||
devicevalue: {
|
||||
id: this.state.selectedDevice!,
|
||||
data: this.state.deviceData?.data[i]!,
|
||||
uom: this.state.deviceData?.data[i + 1]!,
|
||||
name: this.state.deviceData?.data[i + 2]!,
|
||||
cmd: this.state.deviceData?.data[i + 3]!,
|
||||
cmd: this.state.deviceData?.data[i + 3]!
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
noDevices = () => {
|
||||
return this.props.data.devices.length === 0;
|
||||
@@ -166,22 +207,41 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
{!this.noDevices() && (
|
||||
<Table
|
||||
size="small"
|
||||
padding={isWidthDown("xs", width!) ? "none" : "default"}
|
||||
padding={isWidthDown('xs', width!) ? 'none' : 'default'}
|
||||
>
|
||||
<TableBody>
|
||||
{data.devices.sort(compareDevices).map((device) => (
|
||||
<TableRow hover key={device.id} onClick={() => this.handleRowClick(device)}>
|
||||
<TableRow
|
||||
hover
|
||||
key={device.id}
|
||||
onClick={() => this.handleRowClick(device)}
|
||||
>
|
||||
<TableCell>
|
||||
<CustomTooltip
|
||||
title={"DeviceID:0x" + ("00" + device.deviceid.toString(16).toUpperCase()).slice(-2) + " ProductID:" + device.productid + " Version:" + device.version}
|
||||
title={
|
||||
'DeviceID:0x' +
|
||||
(
|
||||
'00' + device.deviceid.toString(16).toUpperCase()
|
||||
).slice(-2) +
|
||||
' ProductID:' +
|
||||
device.productid +
|
||||
' Version:' +
|
||||
device.version
|
||||
}
|
||||
placement="right-end"
|
||||
>
|
||||
<Button startIcon={<ListIcon />} size="small" variant="outlined">
|
||||
<Button
|
||||
startIcon={<ListIcon />}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
>
|
||||
{device.type}
|
||||
</Button>
|
||||
</CustomTooltip>
|
||||
</TableCell>
|
||||
<TableCell align="right">{device.brand + " " + device.name} </TableCell>
|
||||
<TableCell align="right">
|
||||
{device.brand + ' ' + device.name}{' '}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
@@ -191,10 +251,13 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
<Box
|
||||
bgcolor="error.main"
|
||||
color="error.contrastText"
|
||||
p={2} mt={2} mb={2}
|
||||
p={2}
|
||||
mt={2}
|
||||
mb={2}
|
||||
>
|
||||
<Typography variant="body1">
|
||||
No EMS devices found. Check the connections and for possible Tx errors.
|
||||
No EMS devices found. Check the connections and for possible Tx
|
||||
errors.
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
@@ -255,14 +318,25 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
>
|
||||
<DialogTitle>Confirm Scan Devices</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
Are you sure you want to initiate a scan on the EMS bus for all new devices?
|
||||
Are you sure you want to initiate a scan on the EMS bus for all new
|
||||
devices?
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" onClick={this.onScanDevicesRejected} color="secondary">
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={this.onScanDevicesRejected}
|
||||
color="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<RefreshIcon />} variant="contained" onClick={this.onScanDevicesConfirmed} disabled={this.state.processing} color="primary" autoFocus>
|
||||
startIcon={<RefreshIcon />}
|
||||
variant="contained"
|
||||
onClick={this.onScanDevicesConfirmed}
|
||||
disabled={this.state.processing}
|
||||
color="primary"
|
||||
autoFocus
|
||||
>
|
||||
Start Scan
|
||||
</Button>
|
||||
</DialogActions>
|
||||
@@ -283,17 +357,17 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
redirectingAuthorizedFetch(SCANDEVICES_ENDPOINT)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
this.props.enqueueSnackbar("Device scan is starting...", {
|
||||
variant: "info",
|
||||
this.props.enqueueSnackbar('Device scan is starting...', {
|
||||
variant: 'info'
|
||||
});
|
||||
this.setState({ processing: false, confirmScanDevices: false });
|
||||
} else {
|
||||
throw Error("Invalid status code: " + response.status);
|
||||
throw Error('Invalid status code: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.props.enqueueSnackbar(error.message || "Problem with scan", {
|
||||
variant: "error",
|
||||
this.props.enqueueSnackbar(error.message || 'Problem with scan', {
|
||||
variant: 'error'
|
||||
});
|
||||
this.setState({ processing: false, confirmScanDevices: false });
|
||||
});
|
||||
@@ -302,25 +376,25 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
handleRowClick = (device: any) => {
|
||||
this.setState({ selectedDevice: device.id, deviceData: undefined });
|
||||
redirectingAuthorizedFetch(DEVICE_DATA_ENDPOINT, {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ id: device.id }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
}
|
||||
throw Error("Unexpected response code: " + response.status);
|
||||
throw Error('Unexpected response code: ' + response.status);
|
||||
})
|
||||
.then((json) => {
|
||||
this.setState({ deviceData: json });
|
||||
})
|
||||
.catch((error) => {
|
||||
this.props.enqueueSnackbar(
|
||||
error.message || "Problem getting device data",
|
||||
{ variant: "error" }
|
||||
error.message || 'Problem getting device data',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
this.setState({ deviceData: undefined });
|
||||
});
|
||||
@@ -351,10 +425,9 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
<TableContainer>
|
||||
<Table
|
||||
size="small"
|
||||
padding={isWidthDown("xs", width!) ? "none" : "default"}
|
||||
padding={isWidthDown('xs', width!) ? 'none' : 'default'}
|
||||
>
|
||||
<TableHead>
|
||||
</TableHead>
|
||||
<TableHead></TableHead>
|
||||
<TableBody>
|
||||
{deviceData.data.map((item, i) => {
|
||||
if (i % 4) {
|
||||
@@ -362,19 +435,30 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
} else {
|
||||
return (
|
||||
<TableRow hover key={i}>
|
||||
<TableCell padding="checkbox" style={{ width: 18 }} >
|
||||
<TableCell padding="checkbox" style={{ width: 18 }}>
|
||||
{deviceData.data[i + 3] && me.admin && (
|
||||
<CustomTooltip title="change value" placement="left-end"
|
||||
<CustomTooltip
|
||||
title="change value"
|
||||
placement="left-end"
|
||||
>
|
||||
<IconButton edge="start" size="small" aria-label="Edit"
|
||||
onClick={() => this.sendCommand(i)}>
|
||||
<IconButton
|
||||
edge="start"
|
||||
size="small"
|
||||
aria-label="Edit"
|
||||
onClick={() => this.sendCommand(i)}
|
||||
>
|
||||
<EditIcon color="primary" fontSize="small" />
|
||||
</IconButton>
|
||||
</CustomTooltip>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell padding="none" component="th" scope="row">{deviceData.data[i + 2]}</TableCell>
|
||||
<TableCell padding="none" align="right">{deviceData.data[i]}{formatUnit(deviceData.data[i + 1])}</TableCell>
|
||||
<TableCell padding="none" component="th" scope="row">
|
||||
{deviceData.data[i + 2]}
|
||||
</TableCell>
|
||||
<TableCell padding="none" align="right">
|
||||
{deviceData.data[i]}
|
||||
{formatUnit(deviceData.data[i + 1])}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
@@ -390,7 +474,7 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Fragment >
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -405,26 +489,34 @@ class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps, EMSESPDevicesF
|
||||
<br></br>
|
||||
<Box display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1} padding={1}>
|
||||
<FormButton startIcon={<RefreshIcon />} variant="contained" color="secondary" onClick={this.props.loadData} >
|
||||
<FormButton
|
||||
startIcon={<RefreshIcon />}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={this.props.loadData}
|
||||
>
|
||||
Refresh
|
||||
</FormButton>
|
||||
</Box>
|
||||
<Box flexWrap="none" padding={1} whiteSpace="nowrap">
|
||||
<FormButton startIcon={<RefreshIcon />} variant="contained" onClick={this.onScanDevices} >
|
||||
<FormButton
|
||||
startIcon={<RefreshIcon />}
|
||||
variant="contained"
|
||||
onClick={this.onScanDevices}
|
||||
>
|
||||
Scan Devices
|
||||
</FormButton>
|
||||
</Box>
|
||||
</Box>
|
||||
{this.renderScanDevicesDialog()}
|
||||
{
|
||||
devicevalue &&
|
||||
{devicevalue && (
|
||||
<ValueForm
|
||||
devicevalue={devicevalue}
|
||||
onDoneEditing={this.doneEditingValue}
|
||||
onCancelEditing={this.cancelEditingValue}
|
||||
handleValueChange={this.handleValueChange}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,85 +1,110 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Typography, Box, List, ListItem, ListItemText, Link, ListItemAvatar } from '@material-ui/core';
|
||||
import {
|
||||
Typography,
|
||||
Box,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Link,
|
||||
ListItemAvatar
|
||||
} from '@material-ui/core';
|
||||
import { SectionContent } from '../components';
|
||||
|
||||
import CommentIcon from "@material-ui/icons/CommentTwoTone";
|
||||
import MenuBookIcon from "@material-ui/icons/MenuBookTwoTone";
|
||||
import GitHubIcon from "@material-ui/icons/GitHub";
|
||||
import StarIcon from "@material-ui/icons/Star";
|
||||
import ImportExportIcon from "@material-ui/icons/ImportExport";
|
||||
import BugReportIcon from "@material-ui/icons/BugReportTwoTone";
|
||||
import CommentIcon from '@material-ui/icons/CommentTwoTone';
|
||||
import MenuBookIcon from '@material-ui/icons/MenuBookTwoTone';
|
||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
||||
import StarIcon from '@material-ui/icons/Star';
|
||||
import ImportExportIcon from '@material-ui/icons/ImportExport';
|
||||
import BugReportIcon from '@material-ui/icons/BugReportTwoTone';
|
||||
|
||||
export const WebAPISystemSettings = window.location.origin + "/api/system/settings";
|
||||
export const WebAPISystemInfo = window.location.origin + "/api/system/info";
|
||||
export const WebAPISystemSettings =
|
||||
window.location.origin + '/api/system/settings';
|
||||
export const WebAPISystemInfo = window.location.origin + '/api/system/info';
|
||||
|
||||
class EMSESPHelp extends Component {
|
||||
render() {
|
||||
return (
|
||||
<SectionContent title="EMS-ESP Help" titleGutter>
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<MenuBookIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
For the latest news and updates go to the{' '}
|
||||
<Link href="https://emsesp.github.io/docs" color="primary">
|
||||
{'official documentation'} website
|
||||
</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SectionContent title='EMS-ESP Help' titleGutter>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<CommentIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
For live community chat join our{' '}
|
||||
<Link href="https://discord.gg/3J3GgnzpyT" color="primary">
|
||||
{'Discord'} server
|
||||
</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<GitHubIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
To report an issue or feature request go to{' '}
|
||||
<Link
|
||||
href="https://github.com/emsesp/EMS-ESP32/issues/new/choose"
|
||||
color="primary"
|
||||
>
|
||||
{'click here'}
|
||||
</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<MenuBookIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
For the latest news and updates go to the <Link href="https://emsesp.github.io/docs" color="primary">{'official documentation'} website</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<ImportExportIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
To export your system settings{' '}
|
||||
<Link target="_blank" href={WebAPISystemSettings} color="primary">
|
||||
{'click here'}
|
||||
</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<CommentIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
For live community chat join our <Link href="https://discord.gg/3J3GgnzpyT" color="primary">{'Discord'} server</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<GitHubIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
To report an issue or feature request go to <Link href="https://github.com/emsesp/EMS-ESP32/issues/new/choose" color="primary">{'click here'}</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<ImportExportIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
To export your system settings <Link target="_blank" href={WebAPISystemSettings} color="primary">{'click here'}</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<BugReportIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
To export the current status of EMS-ESP <Link target="_blank" href={WebAPISystemInfo} color="primary">{'click here'}</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
</List>
|
||||
|
||||
<Box bgcolor="info.main" border={1} p={3} mt={1} mb={0}>
|
||||
<Typography variant="h6">
|
||||
EMS-ESP is free and open-source.
|
||||
<br></br>Please consider supporting this project by giving it a <StarIcon style={{ color: '#fdff3a' }} /> on our <Link href="https://github.com/emsesp/EMS-ESP32" color="primary">{'GitHub page'}</Link>.
|
||||
</Typography>
|
||||
</Box>
|
||||
<br></br>
|
||||
|
||||
</SectionContent>
|
||||
)
|
||||
}
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<BugReportIcon />
|
||||
</ListItemAvatar>
|
||||
<ListItemText>
|
||||
To export the current status of EMS-ESP{' '}
|
||||
<Link target="_blank" href={WebAPISystemInfo} color="primary">
|
||||
{'click here'}
|
||||
</Link>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
<Box bgcolor="info.main" border={1} p={3} mt={1} mb={0}>
|
||||
<Typography variant="h6">
|
||||
EMS-ESP is free and open-source.
|
||||
<br></br>Please consider supporting this project by giving it a{' '}
|
||||
<StarIcon style={{ color: '#fdff3a' }} /> on our{' '}
|
||||
<Link href="https://github.com/emsesp/EMS-ESP32" color="primary">
|
||||
{'GitHub page'}
|
||||
</Link>
|
||||
.
|
||||
</Typography>
|
||||
</Box>
|
||||
<br></br>
|
||||
</SectionContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EMSESPHelp;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom'
|
||||
import { Component } from 'react';
|
||||
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
import { Tabs, Tab } from '@material-ui/core';
|
||||
|
||||
@@ -10,26 +10,31 @@ import { AuthenticatedRoute } from '../authentication';
|
||||
import EMSESPSettingsController from './EMSESPSettingsController';
|
||||
|
||||
class EMSESP extends Component<RouteComponentProps> {
|
||||
|
||||
handleTabChange = (event: React.ChangeEvent<{}>, path: string) => {
|
||||
handleTabChange = (path: string) => {
|
||||
this.props.history.push(path);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MenuAppBar sectionTitle="Settings">
|
||||
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
|
||||
<Tabs
|
||||
value={this.props.match.url}
|
||||
onChange={(e, path) => this.handleTabChange(path)}
|
||||
variant="fullWidth"
|
||||
>
|
||||
<Tab value={`/${PROJECT_PATH}/settings`} label="EMS-ESP Settings" />
|
||||
</Tabs>
|
||||
<Switch>
|
||||
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/settings`} component={EMSESPSettingsController} />
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path={`/${PROJECT_PATH}/settings`}
|
||||
component={EMSESPSettingsController}
|
||||
/>
|
||||
<Redirect to={`/${PROJECT_PATH}/settings`} />
|
||||
</Switch>
|
||||
</MenuAppBar>
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default EMSESP;
|
||||
|
||||
@@ -1,38 +1,41 @@
|
||||
import React, { Component } from 'react';
|
||||
// import { Container } from '@material-ui/core';
|
||||
import { Component } from 'react';
|
||||
|
||||
import { ENDPOINT_ROOT } from '../api';
|
||||
import EMSESPSettingsForm from './EMSESPSettingsForm';
|
||||
|
||||
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
|
||||
import {
|
||||
restController,
|
||||
RestControllerProps,
|
||||
RestFormLoader,
|
||||
SectionContent
|
||||
} from '../components';
|
||||
|
||||
import { EMSESPSettings } from './EMSESPtypes';
|
||||
|
||||
export const EMSESP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "emsespSettings";
|
||||
export const EMSESP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'emsespSettings';
|
||||
|
||||
type EMSESPSettingsControllerProps = RestControllerProps<EMSESPSettings>;
|
||||
|
||||
class EMSESPSettingsController extends Component<EMSESPSettingsControllerProps> {
|
||||
componentDidMount() {
|
||||
this.props.loadData();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.loadData();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
// <Container maxWidth="md" disableGutters>
|
||||
<SectionContent title='' titleGutter>
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={formProps => (
|
||||
<EMSESPSettingsForm {...formProps} />
|
||||
)}
|
||||
/>
|
||||
</SectionContent>
|
||||
// </Container>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
// <Container maxWidth="md" disableGutters>
|
||||
<SectionContent title="" titleGutter>
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={(formProps) => <EMSESPSettingsForm {...formProps} />}
|
||||
/>
|
||||
</SectionContent>
|
||||
// </Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default restController(EMSESP_SETTINGS_ENDPOINT, EMSESPSettingsController);
|
||||
export default restController(
|
||||
EMSESP_SETTINGS_ENDPOINT,
|
||||
EMSESPSettingsController
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import React from 'react';
|
||||
import {
|
||||
ValidatorForm,
|
||||
TextValidator,
|
||||
SelectValidator,
|
||||
} from "react-material-ui-form-validator";
|
||||
SelectValidator
|
||||
} from 'react-material-ui-form-validator';
|
||||
|
||||
import {
|
||||
Checkbox,
|
||||
@@ -11,34 +11,34 @@ import {
|
||||
Box,
|
||||
Link,
|
||||
withWidth,
|
||||
WithWidthProps,
|
||||
} from "@material-ui/core";
|
||||
import SaveIcon from "@material-ui/icons/Save";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
WithWidthProps
|
||||
} from '@material-ui/core';
|
||||
import SaveIcon from '@material-ui/icons/Save';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
|
||||
import {
|
||||
redirectingAuthorizedFetch,
|
||||
withAuthenticatedContext,
|
||||
AuthenticatedContextProps,
|
||||
} from "../authentication";
|
||||
AuthenticatedContextProps
|
||||
} from '../authentication';
|
||||
|
||||
import {
|
||||
RestFormProps,
|
||||
FormActions,
|
||||
FormButton,
|
||||
BlockFormControlLabel,
|
||||
} from "../components";
|
||||
BlockFormControlLabel
|
||||
} from '../components';
|
||||
|
||||
import { isIP, optional } from "../validators";
|
||||
import { isIP, optional } from '../validators';
|
||||
|
||||
import { EMSESPSettings } from "./EMSESPtypes";
|
||||
import { EMSESPSettings } from './EMSESPtypes';
|
||||
|
||||
import { boardProfileSelectItems } from "./EMSESPBoardProfiles";
|
||||
import { boardProfileSelectItems } from './EMSESPBoardProfiles';
|
||||
|
||||
import { ENDPOINT_ROOT } from "../api";
|
||||
export const BOARD_PROFILE_ENDPOINT = ENDPOINT_ROOT + "boardProfile";
|
||||
import { ENDPOINT_ROOT } from '../api';
|
||||
export const BOARD_PROFILE_ENDPOINT = ENDPOINT_ROOT + 'boardProfile';
|
||||
|
||||
type EMSESPSettingsFormProps = RestFormProps<EMSESPSettings> &
|
||||
AuthenticatedContextProps &
|
||||
@@ -50,38 +50,38 @@ interface EMSESPSettingsFormState {
|
||||
|
||||
class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
state: EMSESPSettingsFormState = {
|
||||
processing: false,
|
||||
processing: false
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
ValidatorForm.addValidationRule("isOptionalIP", optional(isIP));
|
||||
ValidatorForm.addValidationRule('isOptionalIP', optional(isIP));
|
||||
}
|
||||
|
||||
changeBoardProfile = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const { data, setData } = this.props;
|
||||
setData({
|
||||
...data,
|
||||
board_profile: event.target.value,
|
||||
board_profile: event.target.value
|
||||
});
|
||||
|
||||
if (event.target.value === "CUSTOM") return;
|
||||
if (event.target.value === 'CUSTOM') return;
|
||||
|
||||
this.setState({ processing: true });
|
||||
redirectingAuthorizedFetch(BOARD_PROFILE_ENDPOINT, {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ code: event.target.value }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
}
|
||||
throw Error("Unexpected response code: " + response.status);
|
||||
throw Error('Unexpected response code: ' + response.status);
|
||||
})
|
||||
.then((json) => {
|
||||
this.props.enqueueSnackbar("Profile loaded", { variant: "success" });
|
||||
this.props.enqueueSnackbar('Profile loaded', { variant: 'success' });
|
||||
setData({
|
||||
...data,
|
||||
led_gpio: json.led_gpio,
|
||||
@@ -89,14 +89,14 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
rx_gpio: json.rx_gpio,
|
||||
tx_gpio: json.tx_gpio,
|
||||
pbutton_gpio: json.pbutton_gpio,
|
||||
board_profile: event.target.value,
|
||||
board_profile: event.target.value
|
||||
});
|
||||
this.setState({ processing: false });
|
||||
})
|
||||
.catch((error) => {
|
||||
this.props.enqueueSnackbar(
|
||||
error.message || "Problem fetching board profile",
|
||||
{ variant: "warning" }
|
||||
error.message || 'Problem fetching board profile',
|
||||
{ variant: 'warning' }
|
||||
);
|
||||
this.setState({ processing: false });
|
||||
});
|
||||
@@ -108,13 +108,13 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
<ValidatorForm onSubmit={saveData}>
|
||||
<Box bgcolor="info.main" p={2} mt={2} mb={2}>
|
||||
<Typography variant="body1">
|
||||
Adjust any of the EMS-ESP settings here. For help refer to the{" "}
|
||||
Adjust any of the EMS-ESP settings here. For help refer to the{' '}
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings"
|
||||
color="primary"
|
||||
>
|
||||
{"online documentation"}
|
||||
{'online documentation'}
|
||||
</Link>
|
||||
.
|
||||
</Typography>
|
||||
@@ -139,7 +139,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
value={data.tx_mode}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
onChange={handleValueChange("tx_mode")}
|
||||
onChange={handleValueChange('tx_mode')}
|
||||
margin="normal"
|
||||
>
|
||||
<MenuItem value={0}>Off</MenuItem>
|
||||
@@ -156,7 +156,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
value={data.ems_bus_id}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
onChange={handleValueChange("ems_bus_id")}
|
||||
onChange={handleValueChange('ems_bus_id')}
|
||||
margin="normal"
|
||||
>
|
||||
<MenuItem value={0x0b}>Service Key (0x0B)</MenuItem>
|
||||
@@ -169,16 +169,16 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
<Grid item xs={6}>
|
||||
<TextValidator
|
||||
validators={[
|
||||
"required",
|
||||
"isNumber",
|
||||
"minNumber:0",
|
||||
"maxNumber:120",
|
||||
'required',
|
||||
'isNumber',
|
||||
'minNumber:0',
|
||||
'maxNumber:120'
|
||||
]}
|
||||
errorMessages={[
|
||||
"Tx delay is required",
|
||||
"Must be a number",
|
||||
"Must be 0 or higher",
|
||||
"Max value is 120",
|
||||
'Tx delay is required',
|
||||
'Must be a number',
|
||||
'Must be 0 or higher',
|
||||
'Max value is 120'
|
||||
]}
|
||||
name="tx_delay"
|
||||
label="Tx start delay (seconds)"
|
||||
@@ -186,7 +186,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
variant="outlined"
|
||||
value={data.tx_delay}
|
||||
type="number"
|
||||
onChange={handleValueChange("tx_delay")}
|
||||
onChange={handleValueChange('tx_delay')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
@@ -216,12 +216,12 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
margin="normal"
|
||||
>
|
||||
{boardProfileSelectItems()}
|
||||
<MenuItem key={"CUSTOM"} value={"CUSTOM"}>
|
||||
<MenuItem key={'CUSTOM'} value={'CUSTOM'}>
|
||||
Custom...
|
||||
</MenuItem>
|
||||
</SelectValidator>
|
||||
|
||||
{data.board_profile === "CUSTOM" && (
|
||||
{data.board_profile === 'CUSTOM' && (
|
||||
<Grid
|
||||
container
|
||||
spacing={1}
|
||||
@@ -232,18 +232,18 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
<Grid item xs={4}>
|
||||
<TextValidator
|
||||
validators={[
|
||||
"required",
|
||||
"isNumber",
|
||||
"minNumber:0",
|
||||
"maxNumber:40",
|
||||
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
|
||||
'required',
|
||||
'isNumber',
|
||||
'minNumber:0',
|
||||
'maxNumber:40',
|
||||
'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$'
|
||||
]}
|
||||
errorMessages={[
|
||||
"GPIO is required",
|
||||
"Must be a number",
|
||||
"Must be 0 or higher",
|
||||
"Max value is 40",
|
||||
"Not a valid GPIO",
|
||||
'GPIO is required',
|
||||
'Must be a number',
|
||||
'Must be 0 or higher',
|
||||
'Max value is 40',
|
||||
'Not a valid GPIO'
|
||||
]}
|
||||
name="rx_gpio"
|
||||
label="Rx GPIO"
|
||||
@@ -251,25 +251,25 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
variant="outlined"
|
||||
value={data.rx_gpio}
|
||||
type="number"
|
||||
onChange={handleValueChange("rx_gpio")}
|
||||
onChange={handleValueChange('rx_gpio')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<TextValidator
|
||||
validators={[
|
||||
"required",
|
||||
"isNumber",
|
||||
"minNumber:0",
|
||||
"maxNumber:40",
|
||||
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
|
||||
'required',
|
||||
'isNumber',
|
||||
'minNumber:0',
|
||||
'maxNumber:40',
|
||||
'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$'
|
||||
]}
|
||||
errorMessages={[
|
||||
"GPIO is required",
|
||||
"Must be a number",
|
||||
"Must be 0 or higher",
|
||||
"Max value is 40",
|
||||
"Not a valid GPIO",
|
||||
'GPIO is required',
|
||||
'Must be a number',
|
||||
'Must be 0 or higher',
|
||||
'Max value is 40',
|
||||
'Not a valid GPIO'
|
||||
]}
|
||||
name="tx_gpio"
|
||||
label="Tx GPIO"
|
||||
@@ -277,25 +277,25 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
variant="outlined"
|
||||
value={data.tx_gpio}
|
||||
type="number"
|
||||
onChange={handleValueChange("tx_gpio")}
|
||||
onChange={handleValueChange('tx_gpio')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<TextValidator
|
||||
validators={[
|
||||
"required",
|
||||
"isNumber",
|
||||
"minNumber:0",
|
||||
"maxNumber:40",
|
||||
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
|
||||
'required',
|
||||
'isNumber',
|
||||
'minNumber:0',
|
||||
'maxNumber:40',
|
||||
'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$'
|
||||
]}
|
||||
errorMessages={[
|
||||
"GPIO is required",
|
||||
"Must be a number",
|
||||
"Must be 0 or higher",
|
||||
"Max value is 40",
|
||||
"Not a valid GPIO",
|
||||
'GPIO is required',
|
||||
'Must be a number',
|
||||
'Must be 0 or higher',
|
||||
'Max value is 40',
|
||||
'Not a valid GPIO'
|
||||
]}
|
||||
name="pbutton_gpio"
|
||||
label="Button GPIO"
|
||||
@@ -303,25 +303,25 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
variant="outlined"
|
||||
value={data.pbutton_gpio}
|
||||
type="number"
|
||||
onChange={handleValueChange("pbutton_gpio")}
|
||||
onChange={handleValueChange('pbutton_gpio')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<TextValidator
|
||||
validators={[
|
||||
"required",
|
||||
"isNumber",
|
||||
"minNumber:0",
|
||||
"maxNumber:40",
|
||||
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
|
||||
'required',
|
||||
'isNumber',
|
||||
'minNumber:0',
|
||||
'maxNumber:40',
|
||||
'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$'
|
||||
]}
|
||||
errorMessages={[
|
||||
"GPIO is required",
|
||||
"Must be a number",
|
||||
"Must be 0 or higher",
|
||||
"Max value is 40",
|
||||
"Not a valid GPIO",
|
||||
'GPIO is required',
|
||||
'Must be a number',
|
||||
'Must be 0 or higher',
|
||||
'Max value is 40',
|
||||
'Not a valid GPIO'
|
||||
]}
|
||||
name="dallas_gpio"
|
||||
label="Dallas GPIO (0=none)"
|
||||
@@ -329,25 +329,25 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
variant="outlined"
|
||||
value={data.dallas_gpio}
|
||||
type="number"
|
||||
onChange={handleValueChange("dallas_gpio")}
|
||||
onChange={handleValueChange('dallas_gpio')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<TextValidator
|
||||
validators={[
|
||||
"required",
|
||||
"isNumber",
|
||||
"minNumber:0",
|
||||
"maxNumber:40",
|
||||
"matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$",
|
||||
'required',
|
||||
'isNumber',
|
||||
'minNumber:0',
|
||||
'maxNumber:40',
|
||||
'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$'
|
||||
]}
|
||||
errorMessages={[
|
||||
"GPIO is required",
|
||||
"Must be a number",
|
||||
"Must be 0 or higher",
|
||||
"Max value is 40",
|
||||
"Not a valid GPIO",
|
||||
'GPIO is required',
|
||||
'Must be a number',
|
||||
'Must be 0 or higher',
|
||||
'Max value is 40',
|
||||
'Not a valid GPIO'
|
||||
]}
|
||||
name="led_gpio"
|
||||
label="LED GPIO (0=none)"
|
||||
@@ -355,7 +355,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
variant="outlined"
|
||||
value={data.led_gpio}
|
||||
type="number"
|
||||
onChange={handleValueChange("led_gpio")}
|
||||
onChange={handleValueChange('led_gpio')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
@@ -372,7 +372,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.hide_led}
|
||||
onChange={handleValueChange("hide_led")}
|
||||
onChange={handleValueChange('hide_led')}
|
||||
value="hide_led"
|
||||
/>
|
||||
}
|
||||
@@ -385,7 +385,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.dallas_parasite}
|
||||
onChange={handleValueChange("dallas_parasite")}
|
||||
onChange={handleValueChange('dallas_parasite')}
|
||||
value="dallas_parasite"
|
||||
/>
|
||||
}
|
||||
@@ -397,7 +397,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.notoken_api}
|
||||
onChange={handleValueChange("notoken_api")}
|
||||
onChange={handleValueChange('notoken_api')}
|
||||
value="notoken_api"
|
||||
/>
|
||||
}
|
||||
@@ -407,7 +407,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.analog_enabled}
|
||||
onChange={handleValueChange("analog_enabled")}
|
||||
onChange={handleValueChange('analog_enabled')}
|
||||
value="analog_enabled"
|
||||
/>
|
||||
}
|
||||
@@ -424,7 +424,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.shower_timer}
|
||||
onChange={handleValueChange("shower_timer")}
|
||||
onChange={handleValueChange('shower_timer')}
|
||||
value="shower_timer"
|
||||
/>
|
||||
}
|
||||
@@ -434,7 +434,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.shower_alert}
|
||||
onChange={handleValueChange("shower_alert")}
|
||||
onChange={handleValueChange('shower_alert')}
|
||||
value="shower_alert"
|
||||
/>
|
||||
}
|
||||
@@ -451,7 +451,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.syslog_enabled}
|
||||
onChange={handleValueChange("syslog_enabled")}
|
||||
onChange={handleValueChange('syslog_enabled')}
|
||||
value="syslog_enabled"
|
||||
/>
|
||||
}
|
||||
@@ -468,30 +468,30 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
>
|
||||
<Grid item xs={5}>
|
||||
<TextValidator
|
||||
validators={["isOptionalIP"]}
|
||||
errorMessages={["Not a valid IP address"]}
|
||||
validators={['isOptionalIP']}
|
||||
errorMessages={['Not a valid IP address']}
|
||||
name="syslog_host"
|
||||
label="IP"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={data.syslog_host}
|
||||
onChange={handleValueChange("syslog_host")}
|
||||
onChange={handleValueChange('syslog_host')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<TextValidator
|
||||
validators={[
|
||||
"required",
|
||||
"isNumber",
|
||||
"minNumber:0",
|
||||
"maxNumber:65535",
|
||||
'required',
|
||||
'isNumber',
|
||||
'minNumber:0',
|
||||
'maxNumber:65535'
|
||||
]}
|
||||
errorMessages={[
|
||||
"Port is required",
|
||||
"Must be a number",
|
||||
"Must be greater than 0 ",
|
||||
"Max value is 65535",
|
||||
'Port is required',
|
||||
'Must be a number',
|
||||
'Must be greater than 0 ',
|
||||
'Max value is 65535'
|
||||
]}
|
||||
name="syslog_port"
|
||||
label="Port"
|
||||
@@ -499,7 +499,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
variant="outlined"
|
||||
value={data.syslog_port}
|
||||
type="number"
|
||||
onChange={handleValueChange("syslog_port")}
|
||||
onChange={handleValueChange('syslog_port')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
@@ -510,7 +510,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
value={data.syslog_level}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
onChange={handleValueChange("syslog_level")}
|
||||
onChange={handleValueChange('syslog_level')}
|
||||
margin="normal"
|
||||
>
|
||||
<MenuItem value={-1}>OFF</MenuItem>
|
||||
@@ -524,16 +524,16 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
<Grid item xs={6}>
|
||||
<TextValidator
|
||||
validators={[
|
||||
"required",
|
||||
"isNumber",
|
||||
"minNumber:0",
|
||||
"maxNumber:65535",
|
||||
'required',
|
||||
'isNumber',
|
||||
'minNumber:0',
|
||||
'maxNumber:65535'
|
||||
]}
|
||||
errorMessages={[
|
||||
"Syslog Mark is required",
|
||||
"Must be a number",
|
||||
"Must be 0 or higher",
|
||||
"Max value is 10",
|
||||
'Syslog Mark is required',
|
||||
'Must be a number',
|
||||
'Must be 0 or higher',
|
||||
'Max value is 10'
|
||||
]}
|
||||
name="syslog_mark_interval"
|
||||
label="Mark Interval seconds (0=off)"
|
||||
@@ -541,7 +541,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
variant="outlined"
|
||||
value={data.syslog_mark_interval}
|
||||
type="number"
|
||||
onChange={handleValueChange("syslog_mark_interval")}
|
||||
onChange={handleValueChange('syslog_mark_interval')}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
@@ -549,7 +549,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.trace_raw}
|
||||
onChange={handleValueChange("trace_raw")}
|
||||
onChange={handleValueChange('trace_raw')}
|
||||
value="trace_raw"
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
import { Theme } from '@material-ui/core'
|
||||
import { EMSESPStatus, busConnectionStatus } from './EMSESPtypes'
|
||||
import { Theme } from '@material-ui/core';
|
||||
import { EMSESPStatus, busConnectionStatus } from './EMSESPtypes';
|
||||
|
||||
export const isConnected = ({ status }: EMSESPStatus) =>
|
||||
status !== busConnectionStatus.BUS_STATUS_OFFLINE
|
||||
status !== busConnectionStatus.BUS_STATUS_OFFLINE;
|
||||
|
||||
export const busStatusHighlight = ({ status }: EMSESPStatus, theme: Theme) => {
|
||||
switch (status) {
|
||||
case busConnectionStatus.BUS_STATUS_TX_ERRORS:
|
||||
return theme.palette.warning.main
|
||||
return theme.palette.warning.main;
|
||||
case busConnectionStatus.BUS_STATUS_CONNECTED:
|
||||
return theme.palette.success.main
|
||||
return theme.palette.success.main;
|
||||
case busConnectionStatus.BUS_STATUS_OFFLINE:
|
||||
return theme.palette.error.main
|
||||
return theme.palette.error.main;
|
||||
default:
|
||||
return theme.palette.warning.main
|
||||
return theme.palette.warning.main;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const busStatus = ({ status }: EMSESPStatus) => {
|
||||
switch (status) {
|
||||
case busConnectionStatus.BUS_STATUS_CONNECTED:
|
||||
return 'Connected'
|
||||
return 'Connected';
|
||||
case busConnectionStatus.BUS_STATUS_TX_ERRORS:
|
||||
return 'Tx Errors'
|
||||
return 'Tx Errors';
|
||||
case busConnectionStatus.BUS_STATUS_OFFLINE:
|
||||
return 'Disconnected'
|
||||
return 'Disconnected';
|
||||
default:
|
||||
return 'Unknown'
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const qualityHighlight = (value: number, theme: Theme) => {
|
||||
if (value >= 95) {
|
||||
return theme.palette.success.main
|
||||
return theme.palette.success.main;
|
||||
}
|
||||
|
||||
return theme.palette.error.main
|
||||
}
|
||||
return theme.palette.error.main;
|
||||
};
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
|
||||
import {
|
||||
restController,
|
||||
RestControllerProps,
|
||||
RestFormLoader,
|
||||
SectionContent
|
||||
} from '../components';
|
||||
import { ENDPOINT_ROOT } from '../api';
|
||||
import EMSESPStatusForm from './EMSESPStatusForm';
|
||||
import { EMSESPStatus } from './EMSESPtypes';
|
||||
|
||||
export const EMSESP_STATUS_ENDPOINT = ENDPOINT_ROOT + "emsespStatus";
|
||||
export const EMSESP_STATUS_ENDPOINT = ENDPOINT_ROOT + 'emsespStatus';
|
||||
|
||||
type EMSESPStatusControllerProps = RestControllerProps<EMSESPStatus>;
|
||||
|
||||
class EMSESPStatusController extends Component<EMSESPStatusControllerProps> {
|
||||
componentDidMount() {
|
||||
this.props.loadData();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.loadData();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SectionContent title="EMS Status">
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={formProps => <EMSESPStatusForm {...formProps} />}
|
||||
/>
|
||||
</SectionContent>
|
||||
)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<SectionContent title="EMS Status">
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={(formProps) => <EMSESPStatusForm {...formProps} />}
|
||||
/>
|
||||
</SectionContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default restController(EMSESP_STATUS_ENDPOINT, EMSESPStatusController);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { Component, Fragment } from "react";
|
||||
import React, { Component, Fragment } from 'react';
|
||||
|
||||
import { WithTheme, withTheme } from "@material-ui/core/styles";
|
||||
import { WithTheme, withTheme } from '@material-ui/core/styles';
|
||||
import {
|
||||
TableContainer,
|
||||
Table,
|
||||
@@ -13,35 +13,32 @@ import {
|
||||
ListItemText,
|
||||
withWidth,
|
||||
WithWidthProps,
|
||||
isWidthDown,
|
||||
} from "@material-ui/core";
|
||||
isWidthDown
|
||||
} from '@material-ui/core';
|
||||
|
||||
import RefreshIcon from "@material-ui/icons/Refresh";
|
||||
import DeviceHubIcon from "@material-ui/icons/DeviceHub";
|
||||
import RefreshIcon from '@material-ui/icons/Refresh';
|
||||
import DeviceHubIcon from '@material-ui/icons/DeviceHub';
|
||||
|
||||
import {
|
||||
RestFormProps,
|
||||
FormActions,
|
||||
FormButton,
|
||||
HighlightAvatar,
|
||||
} from "../components";
|
||||
HighlightAvatar
|
||||
} from '../components';
|
||||
|
||||
import {
|
||||
busStatus,
|
||||
busStatusHighlight,
|
||||
isConnected,
|
||||
} from "./EMSESPStatus";
|
||||
import { busStatus, busStatusHighlight, isConnected } from './EMSESPStatus';
|
||||
|
||||
import { EMSESPStatus } from "./EMSESPtypes";
|
||||
import { EMSESPStatus } from './EMSESPtypes';
|
||||
|
||||
function formatNumber(num: number) {
|
||||
return new Intl.NumberFormat().format(num);
|
||||
}
|
||||
|
||||
type EMSESPStatusFormProps = RestFormProps<EMSESPStatus> & WithTheme & WithWidthProps;
|
||||
type EMSESPStatusFormProps = RestFormProps<EMSESPStatus> &
|
||||
WithTheme &
|
||||
WithWidthProps;
|
||||
|
||||
class EMSESPStatusForm extends Component<EMSESPStatusFormProps> {
|
||||
|
||||
createListItems() {
|
||||
const { data, theme, width } = this.props;
|
||||
return (
|
||||
@@ -52,24 +49,30 @@ class EMSESPStatusForm extends Component<EMSESPStatusFormProps> {
|
||||
<DeviceHubIcon />
|
||||
</HighlightAvatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="Connection Status" secondary={busStatus(data)} />
|
||||
<ListItemText
|
||||
primary="Connection Status"
|
||||
secondary={busStatus(data)}
|
||||
/>
|
||||
</ListItem>
|
||||
{isConnected(data) && (
|
||||
<TableContainer>
|
||||
<Table size="small" padding={isWidthDown('xs', width!) ? "none" : "default"}>
|
||||
<Table
|
||||
size="small"
|
||||
padding={isWidthDown('xs', width!) ? 'none' : 'default'}
|
||||
>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
# Telegrams Received
|
||||
</TableCell>
|
||||
<TableCell align="right">{formatNumber(data.rx_received)} (quality {data.rx_quality}%)
|
||||
<TableCell># Telegrams Received</TableCell>
|
||||
<TableCell align="right">
|
||||
{formatNumber(data.rx_received)} (quality{' '}
|
||||
{data.rx_quality}%)
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell >
|
||||
# Telegrams Sent
|
||||
</TableCell >
|
||||
<TableCell align="right">{formatNumber(data.tx_sent)} (quality {data.tx_quality}%)
|
||||
<TableCell># Telegrams Sent</TableCell>
|
||||
<TableCell align="right">
|
||||
{formatNumber(data.tx_sent)} (quality {data.tx_quality}
|
||||
%)
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
@@ -86,7 +89,11 @@ class EMSESPStatusForm extends Component<EMSESPStatusFormProps> {
|
||||
<List>{this.createListItems()}</List>
|
||||
<FormActions>
|
||||
<FormButton
|
||||
startIcon={<RefreshIcon />} variant="contained" color="secondary" onClick={this.props.loadData}>
|
||||
startIcon={<RefreshIcon />}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={this.props.loadData}
|
||||
>
|
||||
Refresh
|
||||
</FormButton>
|
||||
</FormActions>
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
export interface EMSESPSettings {
|
||||
tx_mode: number
|
||||
tx_delay: number
|
||||
ems_bus_id: number
|
||||
syslog_enabled: boolean
|
||||
syslog_level: number
|
||||
syslog_mark_interval: number
|
||||
syslog_host: string
|
||||
syslog_port: number
|
||||
master_thermostat: number
|
||||
shower_timer: boolean
|
||||
shower_alert: boolean
|
||||
rx_gpio: number
|
||||
tx_gpio: number
|
||||
dallas_gpio: number
|
||||
dallas_parasite: boolean
|
||||
led_gpio: number
|
||||
hide_led: boolean
|
||||
notoken_api: boolean
|
||||
analog_enabled: boolean
|
||||
pbutton_gpio: number
|
||||
trace_raw: boolean
|
||||
board_profile: string
|
||||
tx_mode: number;
|
||||
tx_delay: number;
|
||||
ems_bus_id: number;
|
||||
syslog_enabled: boolean;
|
||||
syslog_level: number;
|
||||
syslog_mark_interval: number;
|
||||
syslog_host: string;
|
||||
syslog_port: number;
|
||||
master_thermostat: number;
|
||||
shower_timer: boolean;
|
||||
shower_alert: boolean;
|
||||
rx_gpio: number;
|
||||
tx_gpio: number;
|
||||
dallas_gpio: number;
|
||||
dallas_parasite: boolean;
|
||||
led_gpio: number;
|
||||
hide_led: boolean;
|
||||
notoken_api: boolean;
|
||||
analog_enabled: boolean;
|
||||
pbutton_gpio: number;
|
||||
trace_raw: boolean;
|
||||
board_profile: string;
|
||||
}
|
||||
|
||||
export enum busConnectionStatus {
|
||||
BUS_STATUS_CONNECTED = 0,
|
||||
BUS_STATUS_TX_ERRORS = 1,
|
||||
BUS_STATUS_OFFLINE = 2,
|
||||
BUS_STATUS_OFFLINE = 2
|
||||
}
|
||||
|
||||
export interface EMSESPStatus {
|
||||
status: busConnectionStatus
|
||||
rx_received: number
|
||||
tx_sent: number
|
||||
rx_quality: number
|
||||
tx_quality: number
|
||||
status: busConnectionStatus;
|
||||
rx_received: number;
|
||||
tx_sent: number;
|
||||
rx_quality: number;
|
||||
tx_quality: number;
|
||||
}
|
||||
|
||||
export interface Device {
|
||||
id: number
|
||||
type: string
|
||||
brand: string
|
||||
name: string
|
||||
deviceid: number
|
||||
productid: number
|
||||
version: string
|
||||
id: number;
|
||||
type: string;
|
||||
brand: string;
|
||||
name: string;
|
||||
deviceid: number;
|
||||
productid: number;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface Sensor {
|
||||
no: number
|
||||
id: string
|
||||
temp: string
|
||||
no: number;
|
||||
id: string;
|
||||
temp: string;
|
||||
}
|
||||
|
||||
export interface EMSESPDevices {
|
||||
devices: Device[]
|
||||
sensors: Sensor[]
|
||||
devices: Device[];
|
||||
sensors: Sensor[];
|
||||
}
|
||||
|
||||
export interface EMSESPDeviceData {
|
||||
name: string
|
||||
data: string[]
|
||||
name: string;
|
||||
data: string[];
|
||||
}
|
||||
|
||||
export interface DeviceValue {
|
||||
id: number
|
||||
data: string
|
||||
uom: string
|
||||
name: string
|
||||
cmd: string
|
||||
id: number;
|
||||
data: string;
|
||||
uom: string;
|
||||
name: string;
|
||||
cmd: string;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import React, { Component } from "react";
|
||||
import { Link, withRouter, RouteComponentProps } from "react-router-dom";
|
||||
import { Component } from 'react';
|
||||
import { Link, withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
import { List, ListItem, ListItemIcon, ListItemText } from "@material-ui/core";
|
||||
import { List, ListItem, ListItemIcon, ListItemText } from '@material-ui/core';
|
||||
|
||||
import TuneIcon from '@material-ui/icons/Tune';
|
||||
import DashboardIcon from "@material-ui/icons/Dashboard";
|
||||
import DashboardIcon from '@material-ui/icons/Dashboard';
|
||||
|
||||
import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication';
|
||||
import {
|
||||
withAuthenticatedContext,
|
||||
AuthenticatedContextProps
|
||||
} from '../authentication';
|
||||
|
||||
type ProjectProps = AuthenticatedContextProps & RouteComponentProps;
|
||||
|
||||
@@ -16,13 +19,28 @@ class ProjectMenu extends Component<ProjectProps> {
|
||||
const path = this.props.match.url;
|
||||
return (
|
||||
<List>
|
||||
<ListItem to='/ems-esp/' selected={path.startsWith('/ems-esp/status') || path.startsWith('/ems-esp/devices') || path.startsWith('/ems-esp/help')} button component={Link}>
|
||||
<ListItem
|
||||
to="/ems-esp/"
|
||||
selected={
|
||||
path.startsWith('/ems-esp/status') ||
|
||||
path.startsWith('/ems-esp/devices') ||
|
||||
path.startsWith('/ems-esp/help')
|
||||
}
|
||||
button
|
||||
component={Link}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DashboardIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Dashboard" />
|
||||
</ListItem>
|
||||
<ListItem to='/ems-esp/settings' selected={path.startsWith('/ems-esp/settings')} button component={Link} disabled={!authenticatedContext.me.admin}>
|
||||
<ListItem
|
||||
to="/ems-esp/settings"
|
||||
selected={path.startsWith('/ems-esp/settings')}
|
||||
button
|
||||
component={Link}
|
||||
disabled={!authenticatedContext.me.admin}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<TuneIcon />
|
||||
</ListItemIcon>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Component } from 'react';
|
||||
import { Redirect, Switch } from 'react-router';
|
||||
|
||||
import { AuthenticatedRoute } from '../authentication';
|
||||
@@ -7,24 +7,32 @@ import EMSESPDashboard from './EMSESPDashboard';
|
||||
import EMSESPSettings from './EMSESPSettings';
|
||||
|
||||
class ProjectRouting extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Switch>
|
||||
<AuthenticatedRoute exact path="/ems-esp/status/*" component={EMSESPDashboard} />
|
||||
<AuthenticatedRoute exact path="/ems-esp/settings" component={EMSESPSettings} />
|
||||
<AuthenticatedRoute exact path="/ems-esp/*" component={EMSESPDashboard} />
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
}
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path="/ems-esp/status/*"
|
||||
component={EMSESPDashboard}
|
||||
/>
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path="/ems-esp/settings"
|
||||
component={EMSESPSettings}
|
||||
/>
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path="/ems-esp/*"
|
||||
component={EMSESPDashboard}
|
||||
/>
|
||||
{/*
|
||||
* 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={`/ems-esp/status`} />
|
||||
</Switch>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ProjectRouting;
|
||||
|
||||
@@ -1,64 +1,100 @@
|
||||
import React, { RefObject } from 'react';
|
||||
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions, Box, Typography } from '@material-ui/core';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Box,
|
||||
Typography
|
||||
} from '@material-ui/core';
|
||||
import { FormButton } from '../components';
|
||||
import { DeviceValue } from './EMSESPtypes';
|
||||
|
||||
interface ValueFormProps {
|
||||
devicevalue: DeviceValue;
|
||||
onDoneEditing: () => void;
|
||||
onCancelEditing: () => void;
|
||||
handleValueChange: (data: keyof DeviceValue) => (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
devicevalue: DeviceValue;
|
||||
onDoneEditing: () => void;
|
||||
onCancelEditing: () => void;
|
||||
handleValueChange: (
|
||||
data: keyof DeviceValue
|
||||
) => (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
class ValueForm extends React.Component<ValueFormProps> {
|
||||
formRef: RefObject<any> = React.createRef();
|
||||
|
||||
formRef: RefObject<any> = React.createRef();
|
||||
submit = () => {
|
||||
this.formRef.current.submit();
|
||||
};
|
||||
|
||||
submit = () => {
|
||||
this.formRef.current.submit();
|
||||
buildLabel = (devicevalue: DeviceValue) => {
|
||||
if (devicevalue.uom === '' || !devicevalue.uom) {
|
||||
return 'New value';
|
||||
}
|
||||
return 'New value (' + devicevalue.uom + ')';
|
||||
};
|
||||
|
||||
buildLabel = (devicevalue: DeviceValue) => {
|
||||
if ((devicevalue.uom === "") || (!devicevalue.uom)) {
|
||||
return "New value";
|
||||
}
|
||||
return "New value (" + devicevalue.uom + ")";
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
devicevalue,
|
||||
handleValueChange,
|
||||
onDoneEditing,
|
||||
onCancelEditing
|
||||
} = this.props;
|
||||
return (
|
||||
<ValidatorForm onSubmit={onDoneEditing} ref={this.formRef}>
|
||||
<Dialog
|
||||
maxWidth="xs"
|
||||
onClose={onCancelEditing}
|
||||
aria-labelledby="user-form-dialog-title"
|
||||
open
|
||||
>
|
||||
<DialogTitle id="user-form-dialog-title">
|
||||
Change the {devicevalue.name}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<TextValidator
|
||||
validators={['required']}
|
||||
errorMessages={['is required']}
|
||||
name="data"
|
||||
label={this.buildLabel(devicevalue)}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={devicevalue.data}
|
||||
margin="normal"
|
||||
onChange={handleValueChange('data')}
|
||||
/>
|
||||
<Box color="warning.main" p={1} pl={0} pr={0} mt={0} mb={0}>
|
||||
<Typography variant="body2">
|
||||
<i>
|
||||
Note: it may take a few seconds before the change is visible.
|
||||
If nothing happens check the logs.
|
||||
</i>
|
||||
</Typography>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
render() {
|
||||
const { devicevalue, handleValueChange, onDoneEditing, onCancelEditing } = this.props;
|
||||
return (
|
||||
<ValidatorForm onSubmit={onDoneEditing} ref={this.formRef}>
|
||||
<Dialog maxWidth="xs" onClose={onCancelEditing} aria-labelledby="user-form-dialog-title" open>
|
||||
<DialogTitle id="user-form-dialog-title">Change the {devicevalue.name}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<TextValidator
|
||||
validators={['required']}
|
||||
errorMessages={['is required']}
|
||||
name="data"
|
||||
label={this.buildLabel(devicevalue)}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={devicevalue.data}
|
||||
margin="normal"
|
||||
onChange={handleValueChange('data')}
|
||||
/>
|
||||
<Box color="warning.main" p={1} pl={0} pr={0} mt={0} mb={0}>
|
||||
<Typography variant="body2">
|
||||
<i>Note: it may take a few seconds before the change is visible. If nothing happens check the logs.</i>
|
||||
</Typography>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<FormButton variant="contained" color="secondary" onClick={onCancelEditing}>Cancel</FormButton>
|
||||
<FormButton variant="contained" color="primary" type="submit" onClick={this.submit}>Done</FormButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</ValidatorForm>
|
||||
);
|
||||
}
|
||||
<DialogActions>
|
||||
<FormButton
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={onCancelEditing}
|
||||
>
|
||||
Cancel
|
||||
</FormButton>
|
||||
<FormButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
onClick={this.submit}
|
||||
>
|
||||
Done
|
||||
</FormButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</ValidatorForm>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ValueForm;
|
||||
|
||||
Reference in New Issue
Block a user