mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
auto formatting
This commit is contained in:
@@ -1,37 +1,51 @@
|
|||||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
const ManifestPlugin = require('webpack-manifest-plugin')
|
||||||
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
|
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||||
const CompressionPlugin = require('compression-webpack-plugin');
|
const CompressionPlugin = require('compression-webpack-plugin')
|
||||||
const ProgmemGenerator = require('./progmem-generator.js');
|
const ProgmemGenerator = require('./progmem-generator.js')
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
const fs = require('fs');
|
const fs = require('fs')
|
||||||
|
|
||||||
module.exports = function override(config, env) {
|
module.exports = function override(config, env) {
|
||||||
if (env === "production") {
|
if (env === 'production') {
|
||||||
// rename the output file, we need it's path to be short for LittleFS
|
// rename the output file, we need it's path to be short for LittleFS
|
||||||
config.output.filename = 'js/[id].[chunkhash:4].js';
|
config.output.filename = 'js/[id].[chunkhash:4].js'
|
||||||
config.output.chunkFilename = 'js/[id].[chunkhash:4].js';
|
config.output.chunkFilename = 'js/[id].[chunkhash:4].js'
|
||||||
|
|
||||||
// take out the manifest and service worker plugins
|
// take out the manifest and service worker plugins
|
||||||
config.plugins = config.plugins.filter(plugin => !(plugin instanceof ManifestPlugin));
|
config.plugins = config.plugins.filter(
|
||||||
config.plugins = config.plugins.filter(plugin => !(plugin instanceof WorkboxWebpackPlugin.GenerateSW));
|
(plugin) => !(plugin instanceof ManifestPlugin),
|
||||||
|
)
|
||||||
|
config.plugins = config.plugins.filter(
|
||||||
|
(plugin) => !(plugin instanceof WorkboxWebpackPlugin.GenerateSW),
|
||||||
|
)
|
||||||
|
|
||||||
// shorten css filenames
|
// shorten css filenames
|
||||||
const miniCssExtractPlugin = config.plugins.find((plugin) => plugin instanceof MiniCssExtractPlugin);
|
const miniCssExtractPlugin = config.plugins.find(
|
||||||
miniCssExtractPlugin.options.filename = "css/[id].[contenthash:4].css";
|
(plugin) => plugin instanceof MiniCssExtractPlugin,
|
||||||
miniCssExtractPlugin.options.chunkFilename = "css/[id].[contenthash:4].c.css";
|
)
|
||||||
|
miniCssExtractPlugin.options.filename = 'css/[id].[contenthash:4].css'
|
||||||
|
miniCssExtractPlugin.options.chunkFilename =
|
||||||
|
'css/[id].[contenthash:4].c.css'
|
||||||
|
|
||||||
// build progmem data files
|
// build progmem data files
|
||||||
config.plugins.push(new ProgmemGenerator({ outputPath: "../lib/framework/WWWData.h", bytesPerLine: 20 }));
|
config.plugins.push(
|
||||||
|
new ProgmemGenerator({
|
||||||
|
outputPath: '../lib/framework/WWWData.h',
|
||||||
|
bytesPerLine: 20,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
// add compression plugin, compress javascript
|
// add compression plugin, compress javascript
|
||||||
config.plugins.push(new CompressionPlugin({
|
config.plugins.push(
|
||||||
filename: "[path].gz[query]",
|
new CompressionPlugin({
|
||||||
algorithm: "gzip",
|
filename: '[path].gz[query]',
|
||||||
test: /\.(js)$/,
|
algorithm: 'gzip',
|
||||||
deleteOriginalAssets: true
|
test: /\.(js)$/,
|
||||||
}));
|
deleteOriginalAssets: true,
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return config;
|
return config
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,108 @@
|
|||||||
const { resolve, relative, sep } = require('path');
|
const { resolve, relative, sep } = require('path')
|
||||||
const { readdirSync, existsSync, unlinkSync, readFileSync, createWriteStream } = require('fs');
|
const {
|
||||||
var zlib = require('zlib');
|
readdirSync,
|
||||||
var mime = require('mime-types');
|
existsSync,
|
||||||
|
unlinkSync,
|
||||||
|
readFileSync,
|
||||||
|
createWriteStream,
|
||||||
|
} = require('fs')
|
||||||
|
var zlib = require('zlib')
|
||||||
|
var mime = require('mime-types')
|
||||||
|
|
||||||
const ARDUINO_INCLUDES = "#include <Arduino.h>\n\n";
|
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n'
|
||||||
|
|
||||||
function getFilesSync(dir, files = []) {
|
function getFilesSync(dir, files = []) {
|
||||||
readdirSync(dir, { withFileTypes: true }).forEach(entry => {
|
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
||||||
const entryPath = resolve(dir, entry.name);
|
const entryPath = resolve(dir, entry.name)
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
getFilesSync(entryPath, files);
|
getFilesSync(entryPath, files)
|
||||||
} else {
|
} else {
|
||||||
files.push(entryPath);
|
files.push(entryPath)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return files;
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
function coherseToBuffer(input) {
|
function coherseToBuffer(input) {
|
||||||
return Buffer.isBuffer(input) ? input : Buffer.from(input);
|
return Buffer.isBuffer(input) ? input : Buffer.from(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanAndOpen(path) {
|
function cleanAndOpen(path) {
|
||||||
if (existsSync(path)) {
|
if (existsSync(path)) {
|
||||||
unlinkSync(path);
|
unlinkSync(path)
|
||||||
}
|
}
|
||||||
return createWriteStream(path, { flags: "w+" });
|
return createWriteStream(path, { flags: 'w+' })
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProgmemGenerator {
|
class ProgmemGenerator {
|
||||||
|
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
const { outputPath, bytesPerLine = 20, indent = " ", includes = ARDUINO_INCLUDES } = options;
|
const {
|
||||||
this.options = { outputPath, bytesPerLine, indent, includes };
|
outputPath,
|
||||||
|
bytesPerLine = 20,
|
||||||
|
indent = ' ',
|
||||||
|
includes = ARDUINO_INCLUDES,
|
||||||
|
} = options
|
||||||
|
this.options = { outputPath, bytesPerLine, indent, includes }
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(compiler) {
|
apply(compiler) {
|
||||||
compiler.hooks.emit.tapAsync(
|
compiler.hooks.emit.tapAsync(
|
||||||
{ name: 'ProgmemGenerator' },
|
{ name: 'ProgmemGenerator' },
|
||||||
(compilation, callback) => {
|
(compilation, callback) => {
|
||||||
const { outputPath, bytesPerLine, indent, includes } = this.options;
|
const { outputPath, bytesPerLine, indent, includes } = this.options
|
||||||
const fileInfo = [];
|
const fileInfo = []
|
||||||
const writeStream = cleanAndOpen(resolve(compilation.options.context, outputPath));
|
const writeStream = cleanAndOpen(
|
||||||
|
resolve(compilation.options.context, outputPath),
|
||||||
|
)
|
||||||
try {
|
try {
|
||||||
const writeIncludes = () => {
|
const writeIncludes = () => {
|
||||||
writeStream.write(includes);
|
writeStream.write(includes)
|
||||||
}
|
}
|
||||||
|
|
||||||
const writeFile = (relativeFilePath, buffer) => {
|
const writeFile = (relativeFilePath, buffer) => {
|
||||||
const variable = "ESP_REACT_DATA_" + fileInfo.length;
|
const variable = 'ESP_REACT_DATA_' + fileInfo.length
|
||||||
const mimeType = mime.lookup(relativeFilePath);
|
const mimeType = mime.lookup(relativeFilePath)
|
||||||
var size = 0;
|
var size = 0
|
||||||
writeStream.write("const uint8_t " + variable + "[] PROGMEM = {");
|
writeStream.write('const uint8_t ' + variable + '[] PROGMEM = {')
|
||||||
const zipBuffer = zlib.gzipSync(buffer);
|
const zipBuffer = zlib.gzipSync(buffer)
|
||||||
zipBuffer.forEach((b) => {
|
zipBuffer.forEach((b) => {
|
||||||
if (!(size % bytesPerLine)) {
|
if (!(size % bytesPerLine)) {
|
||||||
writeStream.write("\n");
|
writeStream.write('\n')
|
||||||
writeStream.write(indent);
|
writeStream.write(indent)
|
||||||
}
|
}
|
||||||
writeStream.write("0x" + ("00" + b.toString(16).toUpperCase()).substr(-2) + ",");
|
writeStream.write(
|
||||||
size++;
|
'0x' + ('00' + b.toString(16).toUpperCase()).substr(-2) + ',',
|
||||||
});
|
)
|
||||||
|
size++
|
||||||
|
})
|
||||||
if (size % bytesPerLine) {
|
if (size % bytesPerLine) {
|
||||||
writeStream.write("\n");
|
writeStream.write('\n')
|
||||||
}
|
}
|
||||||
writeStream.write("};\n\n");
|
writeStream.write('};\n\n')
|
||||||
fileInfo.push({
|
fileInfo.push({
|
||||||
uri: '/' + relativeFilePath.replace(sep, '/'),
|
uri: '/' + relativeFilePath.replace(sep, '/'),
|
||||||
mimeType,
|
mimeType,
|
||||||
variable,
|
variable,
|
||||||
size
|
size,
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
const writeFiles = () => {
|
const writeFiles = () => {
|
||||||
// process static files
|
// process static files
|
||||||
const buildPath = compilation.options.output.path;
|
const buildPath = compilation.options.output.path
|
||||||
for (const filePath of getFilesSync(buildPath)) {
|
for (const filePath of getFilesSync(buildPath)) {
|
||||||
const readStream = readFileSync(filePath);
|
const readStream = readFileSync(filePath)
|
||||||
const relativeFilePath = relative(buildPath, filePath);
|
const relativeFilePath = relative(buildPath, filePath)
|
||||||
writeFile(relativeFilePath, readStream);
|
writeFile(relativeFilePath, readStream)
|
||||||
}
|
}
|
||||||
// process assets
|
// process assets
|
||||||
const { assets } = compilation;
|
const { assets } = compilation
|
||||||
Object.keys(assets).forEach((relativeFilePath) => {
|
Object.keys(assets).forEach((relativeFilePath) => {
|
||||||
writeFile(relativeFilePath, coherseToBuffer(assets[relativeFilePath].source()));
|
writeFile(
|
||||||
});
|
relativeFilePath,
|
||||||
|
coherseToBuffer(assets[relativeFilePath].source()),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const generateWWWClass = () => {
|
const generateWWWClass = () => {
|
||||||
@@ -93,30 +110,39 @@ class ProgmemGenerator {
|
|||||||
|
|
||||||
class WWWData {
|
class WWWData {
|
||||||
${indent}public:
|
${indent}public:
|
||||||
${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
|
${indent.repeat(
|
||||||
${fileInfo.map(file => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`).join('\n')}
|
2,
|
||||||
|
)}static void registerRoutes(RouteRegistrationHandler handler) {
|
||||||
|
${fileInfo
|
||||||
|
.map(
|
||||||
|
(file) =>
|
||||||
|
`${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${
|
||||||
|
file.variable
|
||||||
|
}, ${file.size});`,
|
||||||
|
)
|
||||||
|
.join('\n')}
|
||||||
${indent.repeat(2)}}
|
${indent.repeat(2)}}
|
||||||
};
|
};
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
const writeWWWClass = () => {
|
const writeWWWClass = () => {
|
||||||
writeStream.write(generateWWWClass());
|
writeStream.write(generateWWWClass())
|
||||||
}
|
}
|
||||||
|
|
||||||
writeIncludes();
|
writeIncludes()
|
||||||
writeFiles();
|
writeFiles()
|
||||||
writeWWWClass();
|
writeWWWClass()
|
||||||
|
|
||||||
writeStream.on('finish', () => {
|
writeStream.on('finish', () => {
|
||||||
callback();
|
callback()
|
||||||
});
|
})
|
||||||
} finally {
|
} finally {
|
||||||
writeStream.end();
|
writeStream.end()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ProgmemGenerator;
|
module.exports = ProgmemGenerator
|
||||||
|
|||||||
@@ -3,20 +3,26 @@
|
|||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/li.woff2) format('woff2');
|
src: local('Roboto Light'), local('Roboto-Light'),
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215;
|
url(../fonts/li.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||||
|
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/re.woff2) format('woff2');
|
src: local('Roboto'), local('Roboto-Regular'),
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215;
|
url(../fonts/re.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||||
|
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/me.woff2) format('woff2');
|
src: local('Roboto Medium'), local('Roboto-Medium'),
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215;
|
url(../fonts/me.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||||
|
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import { APSettings, APProvisionMode } from "./types";
|
import { APSettings, APProvisionMode } from './types'
|
||||||
|
|
||||||
export const isAPEnabled = ({ provision_mode }: APSettings) => {
|
export const isAPEnabled = ({ provision_mode }: APSettings) => {
|
||||||
return provision_mode === APProvisionMode.AP_MODE_ALWAYS || provision_mode === APProvisionMode.AP_MODE_DISCONNECTED;
|
return (
|
||||||
|
provision_mode === APProvisionMode.AP_MODE_ALWAYS ||
|
||||||
|
provision_mode === APProvisionMode.AP_MODE_DISCONNECTED
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
import { Theme } from "@material-ui/core";
|
import { Theme } from '@material-ui/core'
|
||||||
import { APStatus, APNetworkStatus } from "./types";
|
import { APStatus, APNetworkStatus } from './types'
|
||||||
|
|
||||||
export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => {
|
export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case APNetworkStatus.ACTIVE:
|
case APNetworkStatus.ACTIVE:
|
||||||
return theme.palette.success.main;
|
return theme.palette.success.main
|
||||||
case APNetworkStatus.INACTIVE:
|
case APNetworkStatus.INACTIVE:
|
||||||
return theme.palette.info.main;
|
return theme.palette.info.main
|
||||||
case APNetworkStatus.LINGERING:
|
case APNetworkStatus.LINGERING:
|
||||||
return theme.palette.warning.main;
|
return theme.palette.warning.main
|
||||||
default:
|
default:
|
||||||
return theme.palette.warning.main;
|
return theme.palette.warning.main
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const apStatus = ({ status }: APStatus) => {
|
export const apStatus = ({ status }: APStatus) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case APNetworkStatus.ACTIVE:
|
case APNetworkStatus.ACTIVE:
|
||||||
return "Active";
|
return 'Active'
|
||||||
case APNetworkStatus.INACTIVE:
|
case APNetworkStatus.INACTIVE:
|
||||||
return "Inactive";
|
return 'Inactive'
|
||||||
case APNetworkStatus.LINGERING:
|
case APNetworkStatus.LINGERING:
|
||||||
return "Lingering until idle";
|
return 'Lingering until idle'
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return 'Unknown'
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
export enum APProvisionMode {
|
export enum APProvisionMode {
|
||||||
AP_MODE_ALWAYS = 0,
|
AP_MODE_ALWAYS = 0,
|
||||||
AP_MODE_DISCONNECTED = 1,
|
AP_MODE_DISCONNECTED = 1,
|
||||||
AP_NEVER = 2
|
AP_NEVER = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum APNetworkStatus {
|
export enum APNetworkStatus {
|
||||||
ACTIVE = 0,
|
ACTIVE = 0,
|
||||||
INACTIVE = 1,
|
INACTIVE = 1,
|
||||||
LINGERING = 2
|
LINGERING = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface APStatus {
|
export interface APStatus {
|
||||||
status: APNetworkStatus;
|
status: APNetworkStatus
|
||||||
ip_address: string;
|
ip_address: string
|
||||||
mac_address: string;
|
mac_address: string
|
||||||
station_num: number;
|
station_num: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface APSettings {
|
export interface APSettings {
|
||||||
provision_mode: APProvisionMode;
|
provision_mode: APProvisionMode
|
||||||
ssid: string;
|
ssid: string
|
||||||
password: string;
|
password: string
|
||||||
local_ip: string;
|
local_ip: string
|
||||||
gateway_ip: string;
|
gateway_ip: string
|
||||||
subnet_mask: string;
|
subnet_mask: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
import { ENDPOINT_ROOT } from './Env';
|
import { ENDPOINT_ROOT } from './Env'
|
||||||
|
|
||||||
export const FEATURES_ENDPOINT = ENDPOINT_ROOT + "features";
|
export const FEATURES_ENDPOINT = ENDPOINT_ROOT + 'features'
|
||||||
export const NTP_STATUS_ENDPOINT = ENDPOINT_ROOT + "ntpStatus";
|
export const NTP_STATUS_ENDPOINT = ENDPOINT_ROOT + 'ntpStatus'
|
||||||
export const NTP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "ntpSettings";
|
export const NTP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'ntpSettings'
|
||||||
export const TIME_ENDPOINT = ENDPOINT_ROOT + "time";
|
export const TIME_ENDPOINT = ENDPOINT_ROOT + 'time'
|
||||||
export const AP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "apSettings";
|
export const AP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'apSettings'
|
||||||
export const AP_STATUS_ENDPOINT = ENDPOINT_ROOT + "apStatus";
|
export const AP_STATUS_ENDPOINT = ENDPOINT_ROOT + 'apStatus'
|
||||||
export const SCAN_NETWORKS_ENDPOINT = ENDPOINT_ROOT + "scanNetworks";
|
export const SCAN_NETWORKS_ENDPOINT = ENDPOINT_ROOT + 'scanNetworks'
|
||||||
export const LIST_NETWORKS_ENDPOINT = ENDPOINT_ROOT + "listNetworks";
|
export const LIST_NETWORKS_ENDPOINT = ENDPOINT_ROOT + 'listNetworks'
|
||||||
export const NETWORK_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "networkSettings";
|
export const NETWORK_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'networkSettings'
|
||||||
export const NETWORK_STATUS_ENDPOINT = ENDPOINT_ROOT + "networkStatus";
|
export const NETWORK_STATUS_ENDPOINT = ENDPOINT_ROOT + 'networkStatus'
|
||||||
export const OTA_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "otaSettings";
|
export const OTA_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'otaSettings'
|
||||||
export const UPLOAD_FIRMWARE_ENDPOINT = ENDPOINT_ROOT + "uploadFirmware";
|
export const UPLOAD_FIRMWARE_ENDPOINT = ENDPOINT_ROOT + 'uploadFirmware'
|
||||||
export const MQTT_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "mqttSettings";
|
export const MQTT_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'mqttSettings'
|
||||||
export const MQTT_STATUS_ENDPOINT = ENDPOINT_ROOT + "mqttStatus";
|
export const MQTT_STATUS_ENDPOINT = ENDPOINT_ROOT + 'mqttStatus'
|
||||||
export const SYSTEM_STATUS_ENDPOINT = ENDPOINT_ROOT + "systemStatus";
|
export const SYSTEM_STATUS_ENDPOINT = ENDPOINT_ROOT + 'systemStatus'
|
||||||
export const SIGN_IN_ENDPOINT = ENDPOINT_ROOT + "signIn";
|
export const SIGN_IN_ENDPOINT = ENDPOINT_ROOT + 'signIn'
|
||||||
export const VERIFY_AUTHORIZATION_ENDPOINT = ENDPOINT_ROOT + "verifyAuthorization";
|
export const VERIFY_AUTHORIZATION_ENDPOINT =
|
||||||
export const SECURITY_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "securitySettings";
|
ENDPOINT_ROOT + 'verifyAuthorization'
|
||||||
export const GENERATE_TOKEN_ENDPOINT = ENDPOINT_ROOT + "generateToken";
|
export const SECURITY_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'securitySettings'
|
||||||
export const RESTART_ENDPOINT = ENDPOINT_ROOT + "restart";
|
export const GENERATE_TOKEN_ENDPOINT = ENDPOINT_ROOT + 'generateToken'
|
||||||
export const FACTORY_RESET_ENDPOINT = ENDPOINT_ROOT + "factoryReset";
|
export const RESTART_ENDPOINT = ENDPOINT_ROOT + 'restart'
|
||||||
|
export const FACTORY_RESET_ENDPOINT = ENDPOINT_ROOT + 'factoryReset'
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
export const PROJECT_NAME = process.env.REACT_APP_PROJECT_NAME!;
|
export const PROJECT_NAME = process.env.REACT_APP_PROJECT_NAME!
|
||||||
export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH!;
|
export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH!
|
||||||
|
|
||||||
export const ENDPOINT_ROOT = calculateEndpointRoot("/rest/");
|
export const ENDPOINT_ROOT = calculateEndpointRoot('/rest/')
|
||||||
export const WEB_SOCKET_ROOT = calculateWebSocketRoot("/ws/");
|
export const WEB_SOCKET_ROOT = calculateWebSocketRoot('/ws/')
|
||||||
|
|
||||||
function calculateEndpointRoot(endpointPath: string) {
|
function calculateEndpointRoot(endpointPath: string) {
|
||||||
const httpRoot = process.env.REACT_APP_HTTP_ROOT;
|
const httpRoot = process.env.REACT_APP_HTTP_ROOT
|
||||||
if (httpRoot) {
|
if (httpRoot) {
|
||||||
return httpRoot + endpointPath;
|
return httpRoot + endpointPath
|
||||||
}
|
}
|
||||||
const location = window.location;
|
const location = window.location
|
||||||
return location.protocol + "//" + location.host + endpointPath;
|
return location.protocol + '//' + location.host + endpointPath
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateWebSocketRoot(webSocketPath: string) {
|
function calculateWebSocketRoot(webSocketPath: string) {
|
||||||
const webSocketRoot = process.env.REACT_APP_WEB_SOCKET_ROOT;
|
const webSocketRoot = process.env.REACT_APP_WEB_SOCKET_ROOT
|
||||||
if (webSocketRoot) {
|
if (webSocketRoot) {
|
||||||
return webSocketRoot + webSocketPath;
|
return webSocketRoot + webSocketPath
|
||||||
}
|
}
|
||||||
const location = window.location;
|
const location = window.location
|
||||||
const webProtocol = location.protocol === "https:" ? "wss:" : "ws:";
|
const webProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:'
|
||||||
return webProtocol + "//" + location.host + webSocketPath;
|
return webProtocol + '//' + location.host + webSocketPath
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,61 @@
|
|||||||
import * as H from 'history';
|
import * as H from 'history'
|
||||||
|
|
||||||
import history from '../history';
|
import history from '../history'
|
||||||
import { Features } from '../features/types';
|
import { Features } from '../features/types'
|
||||||
import { getDefaultRoute } from '../AppRouting';
|
import { getDefaultRoute } from '../AppRouting'
|
||||||
|
|
||||||
export const ACCESS_TOKEN = 'access_token';
|
export const ACCESS_TOKEN = 'access_token'
|
||||||
export const SIGN_IN_PATHNAME = 'signInPathname';
|
export const SIGN_IN_PATHNAME = 'signInPathname'
|
||||||
export const SIGN_IN_SEARCH = 'signInSearch';
|
export const SIGN_IN_SEARCH = 'signInSearch'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fallback to sessionStorage if localStorage is absent. WebView may not have local storage enabled.
|
* Fallback to sessionStorage if localStorage is absent. WebView may not have local storage enabled.
|
||||||
*/
|
*/
|
||||||
export function getStorage() {
|
export function getStorage() {
|
||||||
return localStorage || sessionStorage;
|
return localStorage || sessionStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
export function storeLoginRedirect(location?: H.Location) {
|
export function storeLoginRedirect(location?: H.Location) {
|
||||||
if (location) {
|
if (location) {
|
||||||
getStorage().setItem(SIGN_IN_PATHNAME, location.pathname);
|
getStorage().setItem(SIGN_IN_PATHNAME, location.pathname)
|
||||||
getStorage().setItem(SIGN_IN_SEARCH, location.search);
|
getStorage().setItem(SIGN_IN_SEARCH, location.search)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearLoginRedirect() {
|
export function clearLoginRedirect() {
|
||||||
getStorage().removeItem(SIGN_IN_PATHNAME);
|
getStorage().removeItem(SIGN_IN_PATHNAME)
|
||||||
getStorage().removeItem(SIGN_IN_SEARCH);
|
getStorage().removeItem(SIGN_IN_SEARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchLoginRedirect(features: Features): H.LocationDescriptorObject {
|
export function fetchLoginRedirect(
|
||||||
const signInPathname = getStorage().getItem(SIGN_IN_PATHNAME);
|
features: Features,
|
||||||
const signInSearch = getStorage().getItem(SIGN_IN_SEARCH);
|
): H.LocationDescriptorObject {
|
||||||
clearLoginRedirect();
|
const signInPathname = getStorage().getItem(SIGN_IN_PATHNAME)
|
||||||
|
const signInSearch = getStorage().getItem(SIGN_IN_SEARCH)
|
||||||
|
clearLoginRedirect()
|
||||||
return {
|
return {
|
||||||
pathname: signInPathname || getDefaultRoute(features),
|
pathname: signInPathname || getDefaultRoute(features),
|
||||||
search: (signInPathname && signInSearch) || undefined
|
search: (signInPathname && signInSearch) || undefined,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the normal fetch routine with one with provides the access token if present.
|
* Wraps the normal fetch routine with one with provides the access token if present.
|
||||||
*/
|
*/
|
||||||
export function authorizedFetch(url: RequestInfo, params?: RequestInit): Promise<Response> {
|
export function authorizedFetch(
|
||||||
const accessToken = getStorage().getItem(ACCESS_TOKEN);
|
url: RequestInfo,
|
||||||
|
params?: RequestInit,
|
||||||
|
): Promise<Response> {
|
||||||
|
const accessToken = getStorage().getItem(ACCESS_TOKEN)
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
params = params || {};
|
params = params || {}
|
||||||
params.credentials = 'include';
|
params.credentials = 'include'
|
||||||
params.headers = {
|
params.headers = {
|
||||||
...params.headers,
|
...params.headers,
|
||||||
"Authorization": 'Bearer ' + accessToken
|
Authorization: 'Bearer ' + accessToken,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
return fetch(url, params);
|
return fetch(url, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,57 +63,67 @@ export function authorizedFetch(url: RequestInfo, params?: RequestInit): Promise
|
|||||||
* for a single file upload and takes care of adding the Authorization header and redirecting on
|
* for a single file upload and takes care of adding the Authorization header and redirecting on
|
||||||
* authorization errors as we do for normal fetch operations.
|
* authorization errors as we do for normal fetch operations.
|
||||||
*/
|
*/
|
||||||
export function redirectingAuthorizedUpload(xhr: XMLHttpRequest, url: string, file: File, onProgress: (event: ProgressEvent<EventTarget>) => void): Promise<void> {
|
export function redirectingAuthorizedUpload(
|
||||||
|
xhr: XMLHttpRequest,
|
||||||
|
url: string,
|
||||||
|
file: File,
|
||||||
|
onProgress: (event: ProgressEvent<EventTarget>) => void,
|
||||||
|
): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
xhr.open("POST", url, true);
|
xhr.open('POST', url, true)
|
||||||
const accessToken = getStorage().getItem(ACCESS_TOKEN);
|
const accessToken = getStorage().getItem(ACCESS_TOKEN)
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
xhr.withCredentials = true;
|
xhr.withCredentials = true
|
||||||
xhr.setRequestHeader("Authorization", 'Bearer ' + accessToken);
|
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken)
|
||||||
}
|
}
|
||||||
xhr.upload.onprogress = onProgress;
|
xhr.upload.onprogress = onProgress
|
||||||
xhr.onload = function () {
|
xhr.onload = function () {
|
||||||
if (xhr.status === 401 || xhr.status === 403) {
|
if (xhr.status === 401 || xhr.status === 403) {
|
||||||
history.push("/unauthorized");
|
history.push('/unauthorized')
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
xhr.onerror = function (event: ProgressEvent<EventTarget>) {
|
xhr.onerror = function (event: ProgressEvent<EventTarget>) {
|
||||||
reject(new DOMException('Error', 'UploadError'));
|
reject(new DOMException('Error', 'UploadError'))
|
||||||
};
|
}
|
||||||
xhr.onabort = function () {
|
xhr.onabort = function () {
|
||||||
reject(new DOMException('Aborted', 'AbortError'));
|
reject(new DOMException('Aborted', 'AbortError'))
|
||||||
};
|
}
|
||||||
const formData = new FormData();
|
const formData = new FormData()
|
||||||
formData.append('file', file);
|
formData.append('file', file)
|
||||||
xhr.send(formData);
|
xhr.send(formData)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the normal fetch routene which redirects on 401 response.
|
* Wraps the normal fetch routene which redirects on 401 response.
|
||||||
*/
|
*/
|
||||||
export function redirectingAuthorizedFetch(url: RequestInfo, params?: RequestInit): Promise<Response> {
|
export function redirectingAuthorizedFetch(
|
||||||
|
url: RequestInfo,
|
||||||
|
params?: RequestInit,
|
||||||
|
): Promise<Response> {
|
||||||
return new Promise<Response>((resolve, reject) => {
|
return new Promise<Response>((resolve, reject) => {
|
||||||
authorizedFetch(url, params).then(response => {
|
authorizedFetch(url, params)
|
||||||
if (response.status === 401 || response.status === 403) {
|
.then((response) => {
|
||||||
history.push("/unauthorized");
|
if (response.status === 401 || response.status === 403) {
|
||||||
} else {
|
history.push('/unauthorized')
|
||||||
resolve(response);
|
} else {
|
||||||
}
|
resolve(response)
|
||||||
}).catch(error => {
|
}
|
||||||
reject(error);
|
})
|
||||||
});
|
.catch((error) => {
|
||||||
});
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addAccessTokenParameter(url: string) {
|
export function addAccessTokenParameter(url: string) {
|
||||||
const accessToken = getStorage().getItem(ACCESS_TOKEN);
|
const accessToken = getStorage().getItem(ACCESS_TOKEN)
|
||||||
if (!accessToken) {
|
if (!accessToken) {
|
||||||
return url;
|
return url
|
||||||
}
|
}
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url)
|
||||||
parsedUrl.searchParams.set(ACCESS_TOKEN, accessToken);
|
parsedUrl.searchParams.set(ACCESS_TOKEN, accessToken)
|
||||||
return parsedUrl.toString();
|
return parsedUrl.toString()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export { default as AuthenticatedRoute } from './AuthenticatedRoute';
|
export { default as AuthenticatedRoute } from './AuthenticatedRoute'
|
||||||
export { default as AuthenticationWrapper } from './AuthenticationWrapper';
|
export { default as AuthenticationWrapper } from './AuthenticationWrapper'
|
||||||
export { default as UnauthenticatedRoute } from './UnauthenticatedRoute';
|
export { default as UnauthenticatedRoute } from './UnauthenticatedRoute'
|
||||||
|
|
||||||
export * from './Authentication';
|
export * from './Authentication'
|
||||||
export * from './AuthenticationContext';
|
export * from './AuthenticationContext'
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
export { default as BlockFormControlLabel } from './BlockFormControlLabel';
|
export { default as BlockFormControlLabel } from './BlockFormControlLabel'
|
||||||
export { default as FormActions } from './FormActions';
|
export { default as FormActions } from './FormActions'
|
||||||
export { default as FormButton } from './FormButton';
|
export { default as FormButton } from './FormButton'
|
||||||
export { default as HighlightAvatar } from './HighlightAvatar';
|
export { default as HighlightAvatar } from './HighlightAvatar'
|
||||||
export { default as MenuAppBar } from './MenuAppBar';
|
export { default as MenuAppBar } from './MenuAppBar'
|
||||||
export { default as PasswordValidator } from './PasswordValidator';
|
export { default as PasswordValidator } from './PasswordValidator'
|
||||||
export { default as RestFormLoader } from './RestFormLoader';
|
export { default as RestFormLoader } from './RestFormLoader'
|
||||||
export { default as SectionContent } from './SectionContent';
|
export { default as SectionContent } from './SectionContent'
|
||||||
export { default as WebSocketFormLoader } from './WebSocketFormLoader';
|
export { default as WebSocketFormLoader } from './WebSocketFormLoader'
|
||||||
export { default as ErrorButton } from './ErrorButton';
|
export { default as ErrorButton } from './ErrorButton'
|
||||||
export { default as SingleUpload } from './SingleUpload';
|
export { default as SingleUpload } from './SingleUpload'
|
||||||
|
|
||||||
export * from './RestFormLoader';
|
export * from './RestFormLoader'
|
||||||
export * from './RestController';
|
export * from './RestController'
|
||||||
|
|
||||||
export * from './WebSocketFormLoader';
|
export * from './WebSocketFormLoader'
|
||||||
export * from './WebSocketController';
|
export * from './WebSocketController'
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
export interface Features {
|
export interface Features {
|
||||||
project: boolean;
|
project: boolean
|
||||||
security: boolean;
|
security: boolean
|
||||||
mqtt: boolean;
|
mqtt: boolean
|
||||||
ntp: boolean;
|
ntp: boolean
|
||||||
ota: boolean;
|
ota: boolean
|
||||||
upload_firmware: boolean;
|
upload_firmware: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createBrowserHistory } from 'history';
|
import { createBrowserHistory } from 'history'
|
||||||
|
|
||||||
export default createBrowserHistory({
|
export default createBrowserHistory({
|
||||||
/* pass a configuration object here if needed */
|
/* pass a configuration object here if needed */
|
||||||
|
|||||||
@@ -1,56 +1,59 @@
|
|||||||
import { Theme } from "@material-ui/core";
|
import { Theme } from '@material-ui/core'
|
||||||
import { MqttStatus, MqttDisconnectReason } from "./types";
|
import { MqttStatus, MqttDisconnectReason } from './types'
|
||||||
|
|
||||||
export const mqttStatusHighlight = ({ enabled, connected }: MqttStatus, theme: Theme) => {
|
export const mqttStatusHighlight = (
|
||||||
|
{ enabled, connected }: MqttStatus,
|
||||||
|
theme: Theme,
|
||||||
|
) => {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return theme.palette.info.main;
|
return theme.palette.info.main
|
||||||
}
|
}
|
||||||
if (connected) {
|
if (connected) {
|
||||||
return theme.palette.success.main;
|
return theme.palette.success.main
|
||||||
}
|
}
|
||||||
return theme.palette.error.main;
|
return theme.palette.error.main
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mqttStatus = ({ enabled, connected }: MqttStatus) => {
|
export const mqttStatus = ({ enabled, connected }: MqttStatus) => {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return "Not enabled";
|
return 'Not enabled'
|
||||||
}
|
}
|
||||||
if (connected) {
|
if (connected) {
|
||||||
return "Connected";
|
return 'Connected'
|
||||||
}
|
}
|
||||||
return "Disconnected";
|
return 'Disconnected'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const disconnectReason = ({ disconnect_reason }: MqttStatus) => {
|
export const disconnectReason = ({ disconnect_reason }: MqttStatus) => {
|
||||||
switch (disconnect_reason) {
|
switch (disconnect_reason) {
|
||||||
case MqttDisconnectReason.TCP_DISCONNECTED:
|
case MqttDisconnectReason.TCP_DISCONNECTED:
|
||||||
return "TCP disconnected";
|
return 'TCP disconnected'
|
||||||
case MqttDisconnectReason.MQTT_UNACCEPTABLE_PROTOCOL_VERSION:
|
case MqttDisconnectReason.MQTT_UNACCEPTABLE_PROTOCOL_VERSION:
|
||||||
return "Unacceptable protocol version";
|
return 'Unacceptable protocol version'
|
||||||
case MqttDisconnectReason.MQTT_IDENTIFIER_REJECTED:
|
case MqttDisconnectReason.MQTT_IDENTIFIER_REJECTED:
|
||||||
return "Client ID rejected";
|
return 'Client ID rejected'
|
||||||
case MqttDisconnectReason.MQTT_SERVER_UNAVAILABLE:
|
case MqttDisconnectReason.MQTT_SERVER_UNAVAILABLE:
|
||||||
return "Server unavailable";
|
return 'Server unavailable'
|
||||||
case MqttDisconnectReason.MQTT_MALFORMED_CREDENTIALS:
|
case MqttDisconnectReason.MQTT_MALFORMED_CREDENTIALS:
|
||||||
return "Malformed credentials";
|
return 'Malformed credentials'
|
||||||
case MqttDisconnectReason.MQTT_NOT_AUTHORIZED:
|
case MqttDisconnectReason.MQTT_NOT_AUTHORIZED:
|
||||||
return "Not authorized";
|
return 'Not authorized'
|
||||||
case MqttDisconnectReason.ESP8266_NOT_ENOUGH_SPACE:
|
case MqttDisconnectReason.ESP8266_NOT_ENOUGH_SPACE:
|
||||||
return "Device out of memory";
|
return 'Device out of memory'
|
||||||
case MqttDisconnectReason.TLS_BAD_FINGERPRINT:
|
case MqttDisconnectReason.TLS_BAD_FINGERPRINT:
|
||||||
return "Server fingerprint invalid";
|
return 'Server fingerprint invalid'
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return 'Unknown'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mqttPublishHighlight = ({ mqtt_fails }: MqttStatus, theme: Theme) => {
|
export const mqttPublishHighlight = (
|
||||||
|
{ mqtt_fails }: MqttStatus,
|
||||||
|
theme: Theme,
|
||||||
|
) => {
|
||||||
|
if (mqtt_fails === 0) return theme.palette.success.main
|
||||||
|
|
||||||
if (mqtt_fails === 0)
|
if (mqtt_fails < 10) return theme.palette.warning.main
|
||||||
return theme.palette.success.main;
|
|
||||||
|
|
||||||
if (mqtt_fails < 10)
|
return theme.palette.error.main
|
||||||
return theme.palette.warning.main;
|
|
||||||
|
|
||||||
return theme.palette.error.main;
|
|
||||||
}
|
}
|
||||||
@@ -6,40 +6,40 @@ export enum MqttDisconnectReason {
|
|||||||
MQTT_MALFORMED_CREDENTIALS = 4,
|
MQTT_MALFORMED_CREDENTIALS = 4,
|
||||||
MQTT_NOT_AUTHORIZED = 5,
|
MQTT_NOT_AUTHORIZED = 5,
|
||||||
ESP8266_NOT_ENOUGH_SPACE = 6,
|
ESP8266_NOT_ENOUGH_SPACE = 6,
|
||||||
TLS_BAD_FINGERPRINT = 7
|
TLS_BAD_FINGERPRINT = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MqttStatus {
|
export interface MqttStatus {
|
||||||
enabled: boolean;
|
enabled: boolean
|
||||||
connected: boolean;
|
connected: boolean
|
||||||
client_id: string;
|
client_id: string
|
||||||
disconnect_reason: MqttDisconnectReason;
|
disconnect_reason: MqttDisconnectReason
|
||||||
mqtt_fails: number;
|
mqtt_fails: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MqttSettings {
|
export interface MqttSettings {
|
||||||
enabled: boolean;
|
enabled: boolean
|
||||||
host: string;
|
host: string
|
||||||
port: number;
|
port: number
|
||||||
base: string;
|
base: string
|
||||||
username: string;
|
username: string
|
||||||
password: string;
|
password: string
|
||||||
client_id: string;
|
client_id: string
|
||||||
keep_alive: number;
|
keep_alive: number
|
||||||
clean_session: boolean;
|
clean_session: boolean
|
||||||
max_topic_length: number;
|
max_topic_length: number
|
||||||
publish_time_boiler: number;
|
publish_time_boiler: number
|
||||||
publish_time_thermostat: number;
|
publish_time_thermostat: number
|
||||||
publish_time_solar: number;
|
publish_time_solar: number
|
||||||
publish_time_mixer: number;
|
publish_time_mixer: number
|
||||||
publish_time_other: number;
|
publish_time_other: number
|
||||||
publish_time_sensor: number;
|
publish_time_sensor: number
|
||||||
dallas_format: number;
|
dallas_format: number
|
||||||
bool_format: number;
|
bool_format: number
|
||||||
mqtt_qos: number;
|
mqtt_qos: number
|
||||||
mqtt_retain: boolean;
|
mqtt_retain: boolean
|
||||||
ha_enabled: boolean;
|
ha_enabled: boolean
|
||||||
ha_climate_format: number;
|
ha_climate_format: number
|
||||||
nested_format: number;
|
nested_format: number
|
||||||
subscribe_format: number;
|
subscribe_format: number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
import { Theme } from "@material-ui/core";
|
import { Theme } from '@material-ui/core'
|
||||||
import { NetworkStatus, NetworkConnectionStatus } from "./types";
|
import { NetworkStatus, NetworkConnectionStatus } from './types'
|
||||||
|
|
||||||
export const isConnected = ({ status }: NetworkStatus) => {
|
export const isConnected = ({ status }: NetworkStatus) => {
|
||||||
return (
|
return (
|
||||||
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED ||
|
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED ||
|
||||||
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED
|
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export const isWiFi = ({ status }: NetworkStatus) =>
|
export const isWiFi = ({ status }: NetworkStatus) =>
|
||||||
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED;
|
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED
|
||||||
export const isEthernet = ({ status }: NetworkStatus) =>
|
export const isEthernet = ({ status }: NetworkStatus) =>
|
||||||
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
|
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED
|
||||||
|
|
||||||
export const networkStatusHighlight = (
|
export const networkStatusHighlight = (
|
||||||
{ status }: NetworkStatus,
|
{ status }: NetworkStatus,
|
||||||
theme: Theme
|
theme: Theme,
|
||||||
) => {
|
) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
||||||
return theme.palette.info.main;
|
return theme.palette.info.main
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
|
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
|
||||||
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
|
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
|
||||||
return theme.palette.success.main;
|
return theme.palette.success.main
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
|
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
|
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
|
||||||
return theme.palette.error.main;
|
return theme.palette.error.main
|
||||||
default:
|
default:
|
||||||
return theme.palette.warning.main;
|
return theme.palette.warning.main
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const networkStatus = ({ status }: NetworkStatus) => {
|
export const networkStatus = ({ status }: NetworkStatus) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
||||||
return "Inactive";
|
return 'Inactive'
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
||||||
return "Idle";
|
return 'Idle'
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL:
|
case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL:
|
||||||
return "No SSID Available";
|
return 'No SSID Available'
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
|
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
|
||||||
return "Connected (WiFi)";
|
return 'Connected (WiFi)'
|
||||||
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
|
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
|
||||||
return "Connected (Ethernet)";
|
return 'Connected (Ethernet)'
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
|
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
|
||||||
return "Connection Failed";
|
return 'Connection Failed'
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
|
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
|
||||||
return "Connection Lost";
|
return 'Connection Lost'
|
||||||
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
||||||
return "Disconnected";
|
return 'Disconnected'
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return 'Unknown'
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
import { WiFiNetwork, WiFiEncryptionType } from "./types";
|
import { WiFiNetwork, WiFiEncryptionType } from './types'
|
||||||
|
|
||||||
export const isNetworkOpen = ({ encryption_type }: WiFiNetwork) => encryption_type === WiFiEncryptionType.WIFI_AUTH_OPEN;
|
export const isNetworkOpen = ({ encryption_type }: WiFiNetwork) =>
|
||||||
|
encryption_type === WiFiEncryptionType.WIFI_AUTH_OPEN
|
||||||
|
|
||||||
export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => {
|
export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => {
|
||||||
switch (encryption_type) {
|
switch (encryption_type) {
|
||||||
case WiFiEncryptionType.WIFI_AUTH_WEP:
|
case WiFiEncryptionType.WIFI_AUTH_WEP:
|
||||||
return "WEP";
|
return 'WEP'
|
||||||
case WiFiEncryptionType.WIFI_AUTH_WPA_PSK:
|
case WiFiEncryptionType.WIFI_AUTH_WPA_PSK:
|
||||||
return "WPA";
|
return 'WPA'
|
||||||
case WiFiEncryptionType.WIFI_AUTH_WPA2_PSK:
|
case WiFiEncryptionType.WIFI_AUTH_WPA2_PSK:
|
||||||
return "WPA2";
|
return 'WPA2'
|
||||||
case WiFiEncryptionType.WIFI_AUTH_WPA_WPA2_PSK:
|
case WiFiEncryptionType.WIFI_AUTH_WPA_WPA2_PSK:
|
||||||
return "WPA/WPA2";
|
return 'WPA/WPA2'
|
||||||
case WiFiEncryptionType.WIFI_AUTH_WPA2_ENTERPRISE:
|
case WiFiEncryptionType.WIFI_AUTH_WPA2_ENTERPRISE:
|
||||||
return "WPA2 Enterprise";
|
return 'WPA2 Enterprise'
|
||||||
case WiFiEncryptionType.WIFI_AUTH_OPEN:
|
case WiFiEncryptionType.WIFI_AUTH_OPEN:
|
||||||
return "None";
|
return 'None'
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return 'Unknown'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export enum NetworkConnectionStatus {
|
|||||||
WIFI_STATUS_CONNECTION_LOST = 5,
|
WIFI_STATUS_CONNECTION_LOST = 5,
|
||||||
WIFI_STATUS_DISCONNECTED = 6,
|
WIFI_STATUS_DISCONNECTED = 6,
|
||||||
ETHERNET_STATUS_CONNECTED = 10,
|
ETHERNET_STATUS_CONNECTED = 10,
|
||||||
WIFI_STATUS_NO_SHIELD = 255
|
WIFI_STATUS_NO_SHIELD = 255,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum WiFiEncryptionType {
|
export enum WiFiEncryptionType {
|
||||||
@@ -15,43 +15,43 @@ export enum WiFiEncryptionType {
|
|||||||
WIFI_AUTH_WPA_PSK = 2,
|
WIFI_AUTH_WPA_PSK = 2,
|
||||||
WIFI_AUTH_WPA2_PSK = 3,
|
WIFI_AUTH_WPA2_PSK = 3,
|
||||||
WIFI_AUTH_WPA_WPA2_PSK = 4,
|
WIFI_AUTH_WPA_WPA2_PSK = 4,
|
||||||
WIFI_AUTH_WPA2_ENTERPRISE = 5
|
WIFI_AUTH_WPA2_ENTERPRISE = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NetworkStatus {
|
export interface NetworkStatus {
|
||||||
status: NetworkConnectionStatus;
|
status: NetworkConnectionStatus
|
||||||
local_ip: string;
|
local_ip: string
|
||||||
mac_address: string;
|
mac_address: string
|
||||||
rssi: number;
|
rssi: number
|
||||||
ssid: string;
|
ssid: string
|
||||||
bssid: string;
|
bssid: string
|
||||||
channel: number;
|
channel: number
|
||||||
subnet_mask: string;
|
subnet_mask: string
|
||||||
gateway_ip: string;
|
gateway_ip: string
|
||||||
dns_ip_1: string;
|
dns_ip_1: string
|
||||||
dns_ip_2: string;
|
dns_ip_2: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NetworkSettings {
|
export interface NetworkSettings {
|
||||||
ssid: string;
|
ssid: string
|
||||||
password: string;
|
password: string
|
||||||
hostname: string;
|
hostname: string
|
||||||
static_ip_config: boolean;
|
static_ip_config: boolean
|
||||||
local_ip?: string;
|
local_ip?: string
|
||||||
gateway_ip?: string;
|
gateway_ip?: string
|
||||||
subnet_mask?: string;
|
subnet_mask?: string
|
||||||
dns_ip_1?: string;
|
dns_ip_1?: string
|
||||||
dns_ip_2?: string;
|
dns_ip_2?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WiFiNetworkList {
|
export interface WiFiNetworkList {
|
||||||
networks: WiFiNetwork[];
|
networks: WiFiNetwork[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WiFiNetwork {
|
export interface WiFiNetwork {
|
||||||
rssi: number;
|
rssi: number
|
||||||
ssid: string;
|
ssid: string
|
||||||
bssid: string;
|
bssid: string
|
||||||
channel: number;
|
channel: number
|
||||||
encryption_type: WiFiEncryptionType;
|
encryption_type: WiFiEncryptionType
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
import { Theme } from "@material-ui/core";
|
import { Theme } from '@material-ui/core'
|
||||||
import { NTPStatus, NTPSyncStatus } from "./types";
|
import { NTPStatus, NTPSyncStatus } from './types'
|
||||||
|
|
||||||
export const isNtpActive = ({ status }: NTPStatus) => status === NTPSyncStatus.NTP_ACTIVE;
|
export const isNtpActive = ({ status }: NTPStatus) =>
|
||||||
|
status === NTPSyncStatus.NTP_ACTIVE
|
||||||
|
|
||||||
export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => {
|
export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case NTPSyncStatus.NTP_INACTIVE:
|
case NTPSyncStatus.NTP_INACTIVE:
|
||||||
return theme.palette.info.main;
|
return theme.palette.info.main
|
||||||
case NTPSyncStatus.NTP_ACTIVE:
|
case NTPSyncStatus.NTP_ACTIVE:
|
||||||
return theme.palette.success.main;
|
return theme.palette.success.main
|
||||||
default:
|
default:
|
||||||
return theme.palette.error.main;
|
return theme.palette.error.main
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ntpStatus = ({ status }: NTPStatus) => {
|
export const ntpStatus = ({ status }: NTPStatus) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case NTPSyncStatus.NTP_INACTIVE:
|
case NTPSyncStatus.NTP_INACTIVE:
|
||||||
return "Inactive";
|
return 'Inactive'
|
||||||
case NTPSyncStatus.NTP_ACTIVE:
|
case NTPSyncStatus.NTP_ACTIVE:
|
||||||
return "Active";
|
return 'Active'
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return 'Unknown'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,43 @@
|
|||||||
import parseMilliseconds from 'parse-ms';
|
import parseMilliseconds from 'parse-ms'
|
||||||
|
|
||||||
const LOCALE_FORMAT = new Intl.DateTimeFormat(
|
const LOCALE_FORMAT = new Intl.DateTimeFormat([...window.navigator.languages], {
|
||||||
[...window.navigator.languages],
|
day: 'numeric',
|
||||||
{
|
month: 'short',
|
||||||
day: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
hour: 'numeric',
|
||||||
year: 'numeric',
|
minute: 'numeric',
|
||||||
hour: 'numeric',
|
second: 'numeric',
|
||||||
minute: 'numeric',
|
hour12: false,
|
||||||
second: 'numeric',
|
})
|
||||||
hour12: false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const formatDateTime = (dateTime: string) => {
|
export const formatDateTime = (dateTime: string) => {
|
||||||
return LOCALE_FORMAT.format(new Date(dateTime.substr(0, 19)));
|
return LOCALE_FORMAT.format(new Date(dateTime.substr(0, 19)))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const formatLocalDateTime = (date: Date) => {
|
export const formatLocalDateTime = (date: Date) => {
|
||||||
return new Date(date.getTime() - date.getTimezoneOffset() * 60000)
|
return new Date(date.getTime() - date.getTimezoneOffset() * 60000)
|
||||||
.toISOString()
|
.toISOString()
|
||||||
.slice(0, -1)
|
.slice(0, -1)
|
||||||
.substr(0, 19);
|
.substr(0, 19)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const formatDuration = (duration: number) => {
|
export const formatDuration = (duration: number) => {
|
||||||
const { days, hours, minutes, seconds } = parseMilliseconds(duration * 1000);
|
const { days, hours, minutes, seconds } = parseMilliseconds(duration * 1000)
|
||||||
var formatted = '';
|
var formatted = ''
|
||||||
if (days) {
|
if (days) {
|
||||||
formatted += pluralize(days, 'day');
|
formatted += pluralize(days, 'day')
|
||||||
}
|
}
|
||||||
if (formatted || hours) {
|
if (formatted || hours) {
|
||||||
formatted += pluralize(hours, 'hour');
|
formatted += pluralize(hours, 'hour')
|
||||||
}
|
}
|
||||||
if (formatted || minutes) {
|
if (formatted || minutes) {
|
||||||
formatted += pluralize(minutes, 'minute');
|
formatted += pluralize(minutes, 'minute')
|
||||||
}
|
}
|
||||||
if (formatted || seconds) {
|
if (formatted || seconds) {
|
||||||
formatted += pluralize(seconds, 'second');
|
formatted += pluralize(seconds, 'second')
|
||||||
}
|
}
|
||||||
return formatted;
|
return formatted
|
||||||
}
|
}
|
||||||
|
|
||||||
const pluralize = (count: number, noun: string, suffix: string = 's') => ` ${count} ${noun}${count !== 1 ? suffix : ''} `;
|
const pluralize = (count: number, noun: string, suffix: string = 's') =>
|
||||||
|
` ${count} ${noun}${count !== 1 ? suffix : ''} `
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
export enum NTPSyncStatus {
|
export enum NTPSyncStatus {
|
||||||
NTP_INACTIVE = 0,
|
NTP_INACTIVE = 0,
|
||||||
NTP_ACTIVE = 1
|
NTP_ACTIVE = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NTPStatus {
|
export interface NTPStatus {
|
||||||
status: NTPSyncStatus;
|
status: NTPSyncStatus
|
||||||
utc_time: string;
|
utc_time: string
|
||||||
local_time: string;
|
local_time: string
|
||||||
server: string;
|
server: string
|
||||||
uptime: number;
|
uptime: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NTPSettings {
|
export interface NTPSettings {
|
||||||
enabled: boolean;
|
enabled: boolean
|
||||||
server: string;
|
server: string
|
||||||
tz_label: string;
|
tz_label: string
|
||||||
tz_format: string;
|
tz_format: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Time {
|
export interface Time {
|
||||||
local_time: string;
|
local_time: string
|
||||||
}
|
}
|
||||||
@@ -1,40 +1,39 @@
|
|||||||
import { Theme } from '@material-ui/core';
|
import { Theme } from '@material-ui/core'
|
||||||
import { EMSESPStatus, busConnectionStatus } from './EMSESPtypes';
|
import { EMSESPStatus, busConnectionStatus } from './EMSESPtypes'
|
||||||
|
|
||||||
export const isConnected = ({ status }: EMSESPStatus) => status !== busConnectionStatus.BUS_STATUS_OFFLINE;
|
export const isConnected = ({ status }: EMSESPStatus) =>
|
||||||
|
status !== busConnectionStatus.BUS_STATUS_OFFLINE
|
||||||
|
|
||||||
export const busStatusHighlight = ({ status }: EMSESPStatus, theme: Theme) => {
|
export const busStatusHighlight = ({ status }: EMSESPStatus, theme: Theme) => {
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case busConnectionStatus.BUS_STATUS_TX_ERRORS:
|
case busConnectionStatus.BUS_STATUS_TX_ERRORS:
|
||||||
return theme.palette.warning.main;
|
return theme.palette.warning.main
|
||||||
case busConnectionStatus.BUS_STATUS_CONNECTED:
|
case busConnectionStatus.BUS_STATUS_CONNECTED:
|
||||||
return theme.palette.success.main;
|
return theme.palette.success.main
|
||||||
case busConnectionStatus.BUS_STATUS_OFFLINE:
|
case busConnectionStatus.BUS_STATUS_OFFLINE:
|
||||||
return theme.palette.error.main;
|
return theme.palette.error.main
|
||||||
default:
|
default:
|
||||||
return theme.palette.warning.main;
|
return theme.palette.warning.main
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const busStatus = ({ status }: EMSESPStatus) => {
|
export const busStatus = ({ status }: EMSESPStatus) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case busConnectionStatus.BUS_STATUS_CONNECTED:
|
case busConnectionStatus.BUS_STATUS_CONNECTED:
|
||||||
return "Connected";
|
return 'Connected'
|
||||||
case busConnectionStatus.BUS_STATUS_TX_ERRORS:
|
case busConnectionStatus.BUS_STATUS_TX_ERRORS:
|
||||||
return "Tx Errors";
|
return 'Tx Errors'
|
||||||
case busConnectionStatus.BUS_STATUS_OFFLINE:
|
case busConnectionStatus.BUS_STATUS_OFFLINE:
|
||||||
return "Disconnected";
|
return 'Disconnected'
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return 'Unknown'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const qualityHighlight = (value: number, theme: Theme) => {
|
export const qualityHighlight = (value: number, theme: Theme) => {
|
||||||
if (value >= 95) {
|
if (value >= 95) {
|
||||||
return theme.palette.success.main;
|
return theme.palette.success.main
|
||||||
}
|
}
|
||||||
|
|
||||||
return theme.palette.error.main;
|
return theme.palette.error.main
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +1,72 @@
|
|||||||
export interface EMSESPSettings {
|
export interface EMSESPSettings {
|
||||||
tx_mode: number;
|
tx_mode: number
|
||||||
tx_delay: number;
|
tx_delay: number
|
||||||
ems_bus_id: number;
|
ems_bus_id: number
|
||||||
syslog_enabled: boolean;
|
syslog_enabled: boolean
|
||||||
syslog_level: number;
|
syslog_level: number
|
||||||
syslog_mark_interval: number;
|
syslog_mark_interval: number
|
||||||
syslog_host: string;
|
syslog_host: string
|
||||||
syslog_port: number;
|
syslog_port: number
|
||||||
master_thermostat: number;
|
master_thermostat: number
|
||||||
shower_timer: boolean;
|
shower_timer: boolean
|
||||||
shower_alert: boolean;
|
shower_alert: boolean
|
||||||
rx_gpio: number;
|
rx_gpio: number
|
||||||
tx_gpio: number;
|
tx_gpio: number
|
||||||
dallas_gpio: number;
|
dallas_gpio: number
|
||||||
dallas_parasite: boolean;
|
dallas_parasite: boolean
|
||||||
led_gpio: number;
|
led_gpio: number
|
||||||
hide_led: boolean;
|
hide_led: boolean
|
||||||
notoken_api: boolean;
|
notoken_api: boolean
|
||||||
analog_enabled: boolean;
|
analog_enabled: boolean
|
||||||
pbutton_gpio: number;
|
pbutton_gpio: number
|
||||||
trace_raw: boolean;
|
trace_raw: boolean
|
||||||
board_profile: string;
|
board_profile: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum busConnectionStatus {
|
export enum busConnectionStatus {
|
||||||
BUS_STATUS_CONNECTED = 0,
|
BUS_STATUS_CONNECTED = 0,
|
||||||
BUS_STATUS_TX_ERRORS = 1,
|
BUS_STATUS_TX_ERRORS = 1,
|
||||||
BUS_STATUS_OFFLINE = 2
|
BUS_STATUS_OFFLINE = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EMSESPStatus {
|
export interface EMSESPStatus {
|
||||||
status: busConnectionStatus;
|
status: busConnectionStatus
|
||||||
rx_received: number;
|
rx_received: number
|
||||||
tx_sent: number;
|
tx_sent: number
|
||||||
rx_quality: number;
|
rx_quality: number
|
||||||
tx_quality: number;
|
tx_quality: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Device {
|
export interface Device {
|
||||||
id: number;
|
id: number
|
||||||
type: string;
|
type: string
|
||||||
brand: string;
|
brand: string
|
||||||
name: string;
|
name: string
|
||||||
deviceid: number;
|
deviceid: number
|
||||||
productid: number;
|
productid: number
|
||||||
version: string;
|
version: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Sensor {
|
export interface Sensor {
|
||||||
no: number;
|
no: number
|
||||||
id: string;
|
id: string
|
||||||
temp: string;
|
temp: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EMSESPDevices {
|
export interface EMSESPDevices {
|
||||||
devices: Device[];
|
devices: Device[]
|
||||||
sensors: Sensor[];
|
sensors: Sensor[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EMSESPDeviceData {
|
export interface EMSESPDeviceData {
|
||||||
name: string;
|
name: string
|
||||||
data: string[];
|
data: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeviceValue {
|
export interface DeviceValue {
|
||||||
id: number;
|
id: number
|
||||||
data: string,
|
data: string
|
||||||
uom: string,
|
uom: string
|
||||||
name: string,
|
name: string
|
||||||
cmd: string
|
cmd: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
export interface User {
|
export interface User {
|
||||||
username: string;
|
username: string
|
||||||
password: string;
|
password: string
|
||||||
admin: boolean;
|
admin: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SecuritySettings {
|
export interface SecuritySettings {
|
||||||
users: User[];
|
users: User[]
|
||||||
jwt_secret: string;
|
jwt_secret: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GeneratedToken {
|
export interface GeneratedToken {
|
||||||
token: string;
|
token: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,64 +12,61 @@
|
|||||||
|
|
||||||
const isLocalhost = Boolean(
|
const isLocalhost = Boolean(
|
||||||
window.location.hostname === 'localhost' ||
|
window.location.hostname === 'localhost' ||
|
||||||
// [::1] is the IPv6 localhost address.
|
// [::1] is the IPv6 localhost address.
|
||||||
window.location.hostname === '[::1]' ||
|
window.location.hostname === '[::1]' ||
|
||||||
// 127.0.0.0/8 are considered localhost for IPv4.
|
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||||
window.location.hostname.match(
|
window.location.hostname.match(
|
||||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
|
||||||
)
|
),
|
||||||
);
|
)
|
||||||
|
|
||||||
type Config = {
|
type Config = {
|
||||||
onSuccess?: (registration: ServiceWorkerRegistration) => void;
|
onSuccess?: (registration: ServiceWorkerRegistration) => void
|
||||||
onUpdate?: (registration: ServiceWorkerRegistration) => void;
|
onUpdate?: (registration: ServiceWorkerRegistration) => void
|
||||||
};
|
}
|
||||||
|
|
||||||
export function register(config?: Config) {
|
export function register(config?: Config) {
|
||||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||||
// The URL constructor is available in all browsers that support SW.
|
// The URL constructor is available in all browsers that support SW.
|
||||||
const publicUrl = new URL(
|
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)
|
||||||
process.env.PUBLIC_URL,
|
|
||||||
window.location.href
|
|
||||||
);
|
|
||||||
if (publicUrl.origin !== window.location.origin) {
|
if (publicUrl.origin !== window.location.origin) {
|
||||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||||
// from what our page is served on. This might happen if a CDN is used to
|
// from what our page is served on. This might happen if a CDN is used to
|
||||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
|
||||||
|
|
||||||
if (isLocalhost) {
|
if (isLocalhost) {
|
||||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||||
checkValidServiceWorker(swUrl, config);
|
checkValidServiceWorker(swUrl, config)
|
||||||
|
|
||||||
// Add some additional logging to localhost, pointing developers to the
|
// Add some additional logging to localhost, pointing developers to the
|
||||||
// service worker/PWA documentation.
|
// service worker/PWA documentation.
|
||||||
navigator.serviceWorker.ready.then(() => {
|
navigator.serviceWorker.ready.then(() => {
|
||||||
console.log(
|
console.log(
|
||||||
'This web app is being served cache-first by a service ' +
|
'This web app is being served cache-first by a service ' +
|
||||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
'worker. To learn more, visit https://bit.ly/CRA-PWA',
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
// Is not localhost. Just register service worker
|
// Is not localhost. Just register service worker
|
||||||
registerValidSW(swUrl, config);
|
registerValidSW(swUrl, config)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerValidSW(swUrl: string, config?: Config) {
|
function registerValidSW(swUrl: string, config?: Config) {
|
||||||
navigator.serviceWorker
|
navigator.serviceWorker
|
||||||
.register(swUrl)
|
.register(swUrl)
|
||||||
.then(registration => {
|
.then((registration) => {
|
||||||
registration.onupdatefound = () => {
|
registration.onupdatefound = () => {
|
||||||
const installingWorker = registration.installing;
|
const installingWorker = registration.installing
|
||||||
if (installingWorker == null) {
|
if (installingWorker == null) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
installingWorker.onstatechange = () => {
|
installingWorker.onstatechange = () => {
|
||||||
if (installingWorker.state === 'installed') {
|
if (installingWorker.state === 'installed') {
|
||||||
@@ -79,67 +76,67 @@ function registerValidSW(swUrl: string, config?: Config) {
|
|||||||
// content until all client tabs are closed.
|
// content until all client tabs are closed.
|
||||||
console.log(
|
console.log(
|
||||||
'New content is available and will be used when all ' +
|
'New content is available and will be used when all ' +
|
||||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
|
||||||
);
|
)
|
||||||
|
|
||||||
// Execute callback
|
// Execute callback
|
||||||
if (config && config.onUpdate) {
|
if (config && config.onUpdate) {
|
||||||
config.onUpdate(registration);
|
config.onUpdate(registration)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// At this point, everything has been precached.
|
// At this point, everything has been precached.
|
||||||
// It's the perfect time to display a
|
// It's the perfect time to display a
|
||||||
// "Content is cached for offline use." message.
|
// "Content is cached for offline use." message.
|
||||||
console.log('Content is cached for offline use.');
|
console.log('Content is cached for offline use.')
|
||||||
|
|
||||||
// Execute callback
|
// Execute callback
|
||||||
if (config && config.onSuccess) {
|
if (config && config.onSuccess) {
|
||||||
config.onSuccess(registration);
|
config.onSuccess(registration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error during service worker registration:', error)
|
||||||
})
|
})
|
||||||
.catch(error => {
|
|
||||||
console.error('Error during service worker registration:', error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkValidServiceWorker(swUrl: string, config?: Config) {
|
function checkValidServiceWorker(swUrl: string, config?: Config) {
|
||||||
// Check if the service worker can be found. If it can't reload the page.
|
// Check if the service worker can be found. If it can't reload the page.
|
||||||
fetch(swUrl, {
|
fetch(swUrl, {
|
||||||
headers: { 'Service-Worker': 'script' }
|
headers: { 'Service-Worker': 'script' },
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
// Ensure service worker exists, and that we really are getting a JS file.
|
// Ensure service worker exists, and that we really are getting a JS file.
|
||||||
const contentType = response.headers.get('content-type');
|
const contentType = response.headers.get('content-type')
|
||||||
if (
|
if (
|
||||||
response.status === 404 ||
|
response.status === 404 ||
|
||||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||||
) {
|
) {
|
||||||
// No service worker found. Probably a different app. Reload the page.
|
// No service worker found. Probably a different app. Reload the page.
|
||||||
navigator.serviceWorker.ready.then(registration => {
|
navigator.serviceWorker.ready.then((registration) => {
|
||||||
registration.unregister().then(() => {
|
registration.unregister().then(() => {
|
||||||
window.location.reload();
|
window.location.reload()
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
// Service worker found. Proceed as normal.
|
// Service worker found. Proceed as normal.
|
||||||
registerValidSW(swUrl, config);
|
registerValidSW(swUrl, config)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
console.log(
|
console.log(
|
||||||
'No internet connection found. App is running in offline mode.'
|
'No internet connection found. App is running in offline mode.',
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unregister() {
|
export function unregister() {
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker.ready.then(registration => {
|
navigator.serviceWorker.ready.then((registration) => {
|
||||||
registration.unregister();
|
registration.unregister()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
const { createProxyMiddleware } = require('http-proxy-middleware');
|
const { createProxyMiddleware } = require('http-proxy-middleware')
|
||||||
|
|
||||||
module.exports = function (app) {
|
module.exports = function (app) {
|
||||||
app.use(
|
app.use(
|
||||||
'/rest/*',
|
'/rest/*',
|
||||||
createProxyMiddleware({
|
createProxyMiddleware({
|
||||||
target: 'http://localhost:3080',
|
target: 'http://localhost:3080',
|
||||||
secure: false,
|
secure: false,
|
||||||
changeOrigin: true
|
changeOrigin: true,
|
||||||
})
|
}),
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
export enum EspPlatform {
|
export enum EspPlatform {
|
||||||
ESP8266 = "esp8266",
|
ESP8266 = 'esp8266',
|
||||||
ESP32 = "esp32"
|
ESP32 = 'esp32',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ESPSystemStatus {
|
interface ESPSystemStatus {
|
||||||
esp_platform: EspPlatform;
|
esp_platform: EspPlatform
|
||||||
max_alloc_heap: number;
|
max_alloc_heap: number
|
||||||
cpu_freq_mhz: number;
|
cpu_freq_mhz: number
|
||||||
free_heap: number;
|
free_heap: number
|
||||||
sdk_version: string;
|
sdk_version: string
|
||||||
flash_chip_size: number;
|
flash_chip_size: number
|
||||||
flash_chip_speed: number;
|
flash_chip_speed: number
|
||||||
fs_used: number;
|
fs_used: number
|
||||||
fs_total: number;
|
fs_total: number
|
||||||
uptime: string;
|
uptime: string
|
||||||
free_mem: number;
|
free_mem: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ESP32SystemStatus extends ESPSystemStatus {
|
export interface ESP32SystemStatus extends ESPSystemStatus {
|
||||||
esp_platform: EspPlatform.ESP32;
|
esp_platform: EspPlatform.ESP32
|
||||||
psram_size: number;
|
psram_size: number
|
||||||
free_psram: number;
|
free_psram: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ESP8266SystemStatus extends ESPSystemStatus {
|
export interface ESP8266SystemStatus extends ESPSystemStatus {
|
||||||
esp_platform: EspPlatform.ESP8266;
|
esp_platform: EspPlatform.ESP8266
|
||||||
heap_fragmentation: number;
|
heap_fragmentation: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SystemStatus = ESP8266SystemStatus | ESP32SystemStatus;
|
export type SystemStatus = ESP8266SystemStatus | ESP32SystemStatus
|
||||||
|
|
||||||
export interface OTASettings {
|
export interface OTASettings {
|
||||||
enabled: boolean;
|
enabled: boolean
|
||||||
port: number;
|
port: number
|
||||||
password: string;
|
password: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export { default as isHostname } from './isHostname';
|
export { default as isHostname } from './isHostname'
|
||||||
export { default as isIP } from './isIP';
|
export { default as isIP } from './isIP'
|
||||||
export { default as optional } from './optional';
|
export { default as optional } from './optional'
|
||||||
export { default as or } from './or';
|
export { default as or } from './or'
|
||||||
export { default as isPath } from './isPath';
|
export { default as isPath } from './isPath'
|
||||||
|
|||||||
@@ -2,5 +2,7 @@ const hostnameLengthRegex = /^.{0,48}$/
|
|||||||
const hostnamePatternRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/
|
const hostnamePatternRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/
|
||||||
|
|
||||||
export default function isHostname(hostname: string) {
|
export default function isHostname(hostname: string) {
|
||||||
return hostnameLengthRegex.test(hostname) && hostnamePatternRegex.test(hostname);
|
return (
|
||||||
|
hostnameLengthRegex.test(hostname) && hostnamePatternRegex.test(hostname)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const ipAddressRegexp = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
const ipAddressRegexp = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
||||||
|
|
||||||
export default function isIp(ipAddress: string) {
|
export default function isIp(ipAddress: string) {
|
||||||
return ipAddressRegexp.test(ipAddress);
|
return ipAddressRegexp.test(ipAddress)
|
||||||
}
|
}
|
||||||
@@ -2,5 +2,5 @@ const pathLengthRegex = /^[^.]{0,108}$/
|
|||||||
const pathPatternRegex = /^([a-zA-Z0-9_][a-zA-Z0-9/_-]*[a-zA-Z0-9_])$/
|
const pathPatternRegex = /^([a-zA-Z0-9_][a-zA-Z0-9/_-]*[a-zA-Z0-9_])$/
|
||||||
|
|
||||||
export default function isPath(path: string) {
|
export default function isPath(path: string) {
|
||||||
return pathLengthRegex.test(path) && pathPatternRegex.test(path);
|
return pathLengthRegex.test(path) && pathPatternRegex.test(path)
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
const OPTIONAL = (validator: (value: any) => boolean) => (value: any) => !value || validator(value);
|
const OPTIONAL = (validator: (value: any) => boolean) => (value: any) =>
|
||||||
|
!value || validator(value)
|
||||||
|
|
||||||
export default OPTIONAL;
|
export default OPTIONAL
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
const OR = (validator1: (value: any) => boolean, validator2: (value: any) => boolean) => {
|
const OR = (
|
||||||
return (value: any) => validator1(value) || validator2(value);
|
validator1: (value: any) => boolean,
|
||||||
};
|
validator2: (value: any) => boolean,
|
||||||
|
) => {
|
||||||
export default OR;
|
return (value: any) => validator1(value) || validator2(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OR
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
@@ -20,7 +16,5 @@
|
|||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src"]
|
||||||
"src"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user