show EMS Devices in Web UI - (v2) New Web UI #421

This commit is contained in:
proddy
2020-07-06 20:55:57 +02:00
parent e57bc0731f
commit d4dd75214c
10 changed files with 262 additions and 34 deletions

View File

@@ -9,6 +9,7 @@ import { AuthenticatedRoute } from '../authentication';
import EMSESPSettingsController from './EMSESPSettingsController';
import EMSESPStatusController from './EMSESPStatusController';
import EMSESPDevicesController from './EMSESPDevicesController';
class EMSESP extends Component<RouteComponentProps> {
@@ -21,10 +22,12 @@ class EMSESP extends Component<RouteComponentProps> {
<MenuAppBar sectionTitle="EMS-ESP">
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
<Tab value={`/${PROJECT_PATH}/status`} label="EMS-ESP Status" />
<Tab value={`/${PROJECT_PATH}/devices`} label="EMS Devices" />
<Tab value={`/${PROJECT_PATH}/settings`} label="EMS-ESP Settings" />
</Tabs>
<Switch>
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/status`} component={EMSESPStatusController} />
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/devices`} component={EMSESPDevicesController} />
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/settings`} component={EMSESPSettingsController} />
<Redirect to={`/${PROJECT_PATH}/status`} />
</Switch>

View File

@@ -0,0 +1,30 @@
import React, { Component } from 'react';
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
import { ENDPOINT_ROOT } from '../api';
import EMSESPDevicesForm from './EMSESPDevicesForm';
import { EMSESPDevices } from './types';
export const EMSESP_DEVICES_ENDPOINT = ENDPOINT_ROOT + "emsespDevices";
type EMSESPDevicesControllerProps = RestControllerProps<EMSESPDevices>;
class EMSESPDevicesController extends Component<EMSESPDevicesControllerProps> {
componentDidMount() {
this.props.loadData();
}
render() {
return (
<SectionContent title="EMS Devices">
<RestFormLoader
{...this.props}
render={formProps => <EMSESPDevicesForm {...formProps} />}
/>
</SectionContent>
)
}
}
export default restController(EMSESP_DEVICES_ENDPOINT, EMSESPDevicesController);

View File

@@ -0,0 +1,121 @@
import React, { Component, Fragment } from "react";
import {
Table,
TableBody,
TableCell,
TableHead,
TableRow,
List,
withWidth,
WithWidthProps,
isWidthDown
} from "@material-ui/core";
import { Box, Typography } from '@material-ui/core';
import RefreshIcon from "@material-ui/icons/Refresh";
import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication';
import {
RestFormProps,
FormActions,
FormButton,
} from "../components";
import { EMSESPDevices, Device } from "./types";
function compareDevices(a: Device, b: Device) {
if (a.type < b.type) {
return -1;
}
if (a.type > b.type) {
return 1;
}
return 0;
}
type EMSESPDevicesFormProps = RestFormProps<EMSESPDevices> & AuthenticatedContextProps & WithWidthProps;
class EMSESPDevicesForm extends Component<EMSESPDevicesFormProps> {
noData = () => {
return (this.props.data.devices.length === 0);
};
createListItems() {
const { width, data } = this.props;
return (
<Fragment>
<Table size="small" padding={isWidthDown('xs', width!) ? "none" : "default"}>
<TableHead>
<TableRow>
<TableCell>Type</TableCell>
<TableCell align="center">Brand</TableCell>
<TableCell align="center">Name</TableCell>
<TableCell align="center">Device ID</TableCell>
<TableCell align="center">Product ID</TableCell>
<TableCell align="center">Version</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.devices.sort(compareDevices).map(device => (
<TableRow key={device.type}>
<TableCell component="th" scope="row">
{device.type}
</TableCell>
<TableCell align="center">
{device.brand}
</TableCell>
<TableCell align="center">
{device.name}
</TableCell>
<TableCell align="center">
0x{('00' + device.deviceid.toString(16).toUpperCase()).slice(-2)}
</TableCell>
<TableCell align="center">
{device.productid}
</TableCell>
<TableCell align="center">
{device.version}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{this.noData() &&
(
<Box bgcolor="error.main" color="error.contrastText" p={2} mt={2} mb={2}>
<Typography variant="body1">
No EMS devices found.
</Typography>
</Box>
)
}
</Fragment >
);
}
render() {
return (
<Fragment>
<List>{this.createListItems()}</List>
<FormActions>
<FormButton
startIcon={<RefreshIcon />}
variant="contained"
color="secondary"
onClick={this.props.loadData}
>
Refresh
</FormButton>
</FormActions>
</Fragment>
);
}
}
export default withAuthenticatedContext(withWidth()(EMSESPDevicesForm));
// export default withTheme(EMSESPDevicesForm);

View File

@@ -55,7 +55,7 @@ function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps)
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:255']}
errorMessages={['TX mode is required', "Must be a number", "Must be 0 or higher", "Max value is 255"]}
name="tx_mode"
label="Tx mode (0=off)"
label="Tx Mode (0=off)"
fullWidth
variant="outlined"
value={data.tx_mode}
@@ -71,10 +71,10 @@ function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps)
value="system_heartbeat"
/>
}
label="MQTT heartbeat"
label="MQTT Heartbeat"
/>
<SelectValidator name="mqtt_format"
label="MQTT format"
label="MQTT Format"
value={data.mqtt_format}
fullWidth
variant="outlined"
@@ -100,7 +100,7 @@ function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps)
validators={['required', 'isNumber', 'minNumber:1', 'maxNumber:65535']}
errorMessages={['Keep alive is required', "Must be a number", "Must be greater than 0", "Max value is 65535"]}
name="publish_time"
label="MQTT Publish time (seconds)"
label="MQTT Publish Time (seconds)"
fullWidth
variant="outlined"
value={data.publish_time}
@@ -108,18 +108,6 @@ function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps)
onChange={handleValueChange('publish_time')}
margin="normal"
/>
<SelectValidator name="syslog_level"
label="Syslog log level"
value={data.syslog_level}
fullWidth
variant="outlined"
onChange={handleValueChange('syslog_level')}
margin="normal">
<MenuItem value={-1}>OFF</MenuItem>
<MenuItem value={3}>ERR</MenuItem>
<MenuItem value={6}>INFO</MenuItem>
<MenuItem value={7}>DEBUG</MenuItem>
</SelectValidator>
<BlockFormControlLabel
control={
<Checkbox
@@ -140,6 +128,18 @@ function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps)
}
label="Shower Alert"
/>
<SelectValidator name="syslog_level"
label="Syslog Log Level"
value={data.syslog_level}
fullWidth
variant="outlined"
onChange={handleValueChange('syslog_level')}
margin="normal">
<MenuItem value={-1}>OFF</MenuItem>
<MenuItem value={3}>ERR</MenuItem>
<MenuItem value={6}>INFO</MenuItem>
<MenuItem value={7}>DEBUG</MenuItem>
</SelectValidator>
{data.syslog_level !== -1 &&
<Fragment>
<TextValidator
@@ -154,13 +154,13 @@ function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps)
margin="normal"
/>
<TextValidator
validators={['required', 'isNumber', 'minNumber:1', 'maxNumber:65535']}
errorMessages={['Keep alive is required', "Must be a number", "Must be greater than 0", "Max value is 65535"]}
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Keep alive is required', "Must be a number", "Must be 0 or higher (0=off)", "Max value is 65535"]}
name="syslog_mark_interval"
label="Syslog mark interval (seconds)"
label="Syslog Mark Interval (seconds, 0=off)"
fullWidth
variant="outlined"
value={data.publish_time}
value={data.syslog_mark_interval}
type="number"
onChange={handleValueChange('syslog_mark_interval')}
margin="normal"

View File

@@ -12,7 +12,7 @@ import {
List,
ListItem,
ListItemAvatar,
ListItemText,
ListItemText
} from "@material-ui/core";
import BuildIcon from "@material-ui/icons/Build";
@@ -81,7 +81,7 @@ class EMSESPStatusForm extends Component<EMSESPStatusFormProps> {
</HighlightAvatar>
</ListItemAvatar>
<ListItemText
primary="MQTT Publish failures"
primary="MQTT Publish Errors"
secondary={data.mqtt_fails}
/>
</ListItem>
@@ -125,7 +125,7 @@ class EMSESPStatusForm extends Component<EMSESPStatusFormProps> {
</TableRow>
<TableRow>
<TableCell component="th" scope="row">
(Tx) Send failures
(Tx) Send Errors
</TableCell>
<TableCell align="center">{data.tx_errors}</TableCell>
</TableRow>

View File

@@ -30,3 +30,17 @@ export interface EMSESPStatus {
uptime: string;
free_mem: number;
}
export interface Device {
type: string;
brand: string;
name: string;
deviceid: number;
productid: number;
version: string;
}
export interface EMSESPDevices {
devices: Device[];
}

View File

@@ -0,0 +1,36 @@
#include "EMSESPDevicesService.h"
#include "emsesp.h"
#include "mqtt.h"
namespace emsesp {
EMSESPDevicesService::EMSESPDevicesService(AsyncWebServer * server, SecurityManager * securityManager) {
server->on(EMSESP_DEVICES_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&EMSESPDevicesService::emsespDevicesService, this, std::placeholders::_1),
AuthenticationPredicates::IS_AUTHENTICATED));
}
void EMSESPDevicesService::emsespDevicesService(AsyncWebServerRequest * request) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_EMSESP_STATUS_SIZE);
JsonObject root = response->getRoot();
JsonArray devices = root.createNestedArray("devices");
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
JsonObject deviceRoot = devices.createNestedObject();
deviceRoot["type"] = emsdevice->device_type_name();
deviceRoot["brand"] = emsdevice->brand_to_string();
deviceRoot["name"] = emsdevice->name();
deviceRoot["deviceid"] = emsdevice->device_id();
deviceRoot["productid"] = emsdevice->product_id();
deviceRoot["version"] = emsdevice->version();
}
response->setLength();
request->send(response);
}
}
} // namespace emsesp

View File

@@ -0,0 +1,31 @@
#ifndef EMSESPDevicesService_h
#define EMSESPDevicesService_h
#include <ArduinoJson.h>
#include <AsyncJson.h>
#include <ESPAsyncWebServer.h>
#include <SecurityManager.h>
#include <HttpEndpoint.h>
#include <MqttPubSub.h>
#include <WebSocketTxRx.h>
#include "EMSESPSettingsService.h"
#include "version.h"
#define MAX_EMSESP_STATUS_SIZE 1024
#define EMSESP_DEVICES_SERVICE_PATH "/rest/emsespDevices"
namespace emsesp {
class EMSESPDevicesService {
public:
EMSESPDevicesService(AsyncWebServer * server, SecurityManager * securityManager);
private:
void emsespDevicesService(AsyncWebServerRequest * request);
};
} // namespace emsesp
#endif

View File

@@ -1,6 +1,7 @@
#include "EMSESPStatusService.h"
#include "emsesp.h"
#include "mqtt.h"
#include "version.h"
namespace emsesp {

View File

@@ -5,14 +5,7 @@
#include <AsyncJson.h>
#include <ESPAsyncWebServer.h>
#include <SecurityManager.h>
#include <HttpEndpoint.h>
#include <MqttPubSub.h>
#include <WebSocketTxRx.h>
#include "EMSESPSettingsService.h"
#include "version.h"
#include <AsyncMqttClient.h>
#define MAX_EMSESP_STATUS_SIZE 1024
#define EMSESP_STATUS_SERVICE_PATH "/rest/emsespStatus"
@@ -24,7 +17,6 @@ class EMSESPStatusService {
EMSESPStatusService(AsyncWebServer * server, SecurityManager * securityManager, AsyncMqttClient * mqttClient);
private:
EMSESPSettingsService * _emsespSettingsService;
void emsespStatusService(AsyncWebServerRequest * request);
AsyncMqttClient * _mqttClient;