mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
log to webui - initial version
This commit is contained in:
563
interface/package-lock.json
generated
563
interface/package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "esp8266-react",
|
||||
"name": "emsesp-react",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "esp8266-react",
|
||||
"name": "emsesp-react",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^4.11.4",
|
||||
@@ -8860,18 +8860,6 @@
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
@@ -19797,284 +19785,6 @@
|
||||
"watchpack-chokidar2": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
|
||||
"integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^2.1.8"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/anymatch": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
|
||||
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"micromatch": "^3.1.4",
|
||||
"normalize-path": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/anymatch/node_modules/normalize-path": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
|
||||
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"remove-trailing-separator": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/binary-extensions": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
|
||||
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/braces": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
|
||||
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"arr-flatten": "^1.1.0",
|
||||
"array-unique": "^0.3.2",
|
||||
"extend-shallow": "^2.0.1",
|
||||
"fill-range": "^4.0.0",
|
||||
"isobject": "^3.0.1",
|
||||
"repeat-element": "^1.1.2",
|
||||
"snapdragon": "^0.8.1",
|
||||
"snapdragon-node": "^2.0.1",
|
||||
"split-string": "^3.0.2",
|
||||
"to-regex": "^3.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/braces/node_modules/extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-extendable": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/chokidar": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
|
||||
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"anymatch": "^2.0.0",
|
||||
"async-each": "^1.0.1",
|
||||
"braces": "^2.3.2",
|
||||
"fsevents": "^1.2.7",
|
||||
"glob-parent": "^3.1.0",
|
||||
"inherits": "^2.0.3",
|
||||
"is-binary-path": "^1.0.0",
|
||||
"is-glob": "^4.0.0",
|
||||
"normalize-path": "^3.0.0",
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"readdirp": "^2.2.1",
|
||||
"upath": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/fill-range": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||
"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-number": "^3.0.0",
|
||||
"repeat-string": "^1.6.1",
|
||||
"to-regex-range": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/fill-range/node_modules/extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-extendable": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/fsevents": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/glob-parent": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
||||
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^3.1.0",
|
||||
"path-dirname": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/glob-parent/node_modules/is-glob": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
|
||||
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/is-binary-path": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
|
||||
"integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"binary-extensions": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/is-number": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
||||
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"kind-of": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/is-number/node_modules/kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-buffer": "^1.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/micromatch": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
||||
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"arr-diff": "^4.0.0",
|
||||
"array-unique": "^0.3.2",
|
||||
"braces": "^2.3.1",
|
||||
"define-property": "^2.0.2",
|
||||
"extend-shallow": "^3.0.2",
|
||||
"extglob": "^2.0.4",
|
||||
"fragment-cache": "^0.2.1",
|
||||
"kind-of": "^6.0.2",
|
||||
"nanomatch": "^1.2.9",
|
||||
"object.pick": "^1.3.0",
|
||||
"regex-not": "^1.0.0",
|
||||
"snapdragon": "^0.8.1",
|
||||
"to-regex": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/readdirp": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
|
||||
"integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.11",
|
||||
"micromatch": "^3.1.10",
|
||||
"readable-stream": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack-chokidar2/node_modules/to-regex-range": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
|
||||
"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-number": "^3.0.0",
|
||||
"repeat-string": "^1.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wbuf": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
|
||||
@@ -20376,19 +20086,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/fsevents": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/glob-parent": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
||||
@@ -29146,12 +28843,6 @@
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
@@ -38130,250 +37821,6 @@
|
||||
"watchpack-chokidar2": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"watchpack-chokidar2": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
|
||||
"integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chokidar": "^2.1.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"anymatch": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
|
||||
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"micromatch": "^3.1.4",
|
||||
"normalize-path": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"normalize-path": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
|
||||
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"remove-trailing-separator": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
|
||||
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
|
||||
"optional": true
|
||||
},
|
||||
"braces": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
|
||||
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"arr-flatten": "^1.1.0",
|
||||
"array-unique": "^0.3.2",
|
||||
"extend-shallow": "^2.0.1",
|
||||
"fill-range": "^4.0.0",
|
||||
"isobject": "^3.0.1",
|
||||
"repeat-element": "^1.1.2",
|
||||
"snapdragon": "^0.8.1",
|
||||
"snapdragon-node": "^2.0.1",
|
||||
"split-string": "^3.0.2",
|
||||
"to-regex": "^3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
|
||||
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"anymatch": "^2.0.0",
|
||||
"async-each": "^1.0.1",
|
||||
"braces": "^2.3.2",
|
||||
"fsevents": "^1.2.7",
|
||||
"glob-parent": "^3.1.0",
|
||||
"inherits": "^2.0.3",
|
||||
"is-binary-path": "^1.0.0",
|
||||
"is-glob": "^4.0.0",
|
||||
"normalize-path": "^3.0.0",
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"readdirp": "^2.2.1",
|
||||
"upath": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||
"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^2.0.1",
|
||||
"is-number": "^3.0.0",
|
||||
"repeat-string": "^1.6.1",
|
||||
"to-regex-range": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||
"optional": true
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
||||
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-glob": "^3.1.0",
|
||||
"path-dirname": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-glob": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
|
||||
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
|
||||
"integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"binary-extensions": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-number": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
||||
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"kind-of": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"optional": true
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
||||
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"arr-diff": "^4.0.0",
|
||||
"array-unique": "^0.3.2",
|
||||
"braces": "^2.3.1",
|
||||
"define-property": "^2.0.2",
|
||||
"extend-shallow": "^3.0.2",
|
||||
"extglob": "^2.0.4",
|
||||
"fragment-cache": "^0.2.1",
|
||||
"kind-of": "^6.0.2",
|
||||
"nanomatch": "^1.2.9",
|
||||
"object.pick": "^1.3.0",
|
||||
"regex-not": "^1.0.0",
|
||||
"snapdragon": "^0.8.1",
|
||||
"to-regex": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
|
||||
"integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.11",
|
||||
"micromatch": "^3.1.10",
|
||||
"readable-stream": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"optional": true
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
|
||||
"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-number": "^3.0.0",
|
||||
"repeat-string": "^1.6.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"wbuf": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
|
||||
@@ -38852,12 +38299,6 @@
|
||||
"locate-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||
"optional": true
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "esp8266-react",
|
||||
"name": "emsesp-react",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -3,6 +3,7 @@ export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH!;
|
||||
|
||||
export const ENDPOINT_ROOT = calculateEndpointRoot('/rest/');
|
||||
export const WEB_SOCKET_ROOT = calculateWebSocketRoot('/ws/');
|
||||
export const EVENT_SOURCE_ROOT = calculateEndpointRoot('/es/');
|
||||
|
||||
function calculateEndpointRoot(endpointPath: string) {
|
||||
const httpRoot = process.env.REACT_APP_HTTP_ROOT;
|
||||
|
||||
14
interface/src/components/WindowSize.tsx
Normal file
14
interface/src/components/WindowSize.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { useLayoutEffect, useState } from 'react';
|
||||
|
||||
export function useWindowSize() {
|
||||
const [size, setSize] = useState([0, 0]);
|
||||
useLayoutEffect(() => {
|
||||
function updateSize() {
|
||||
setSize([window.innerWidth, window.innerHeight]);
|
||||
}
|
||||
window.addEventListener('resize', updateSize);
|
||||
updateSize();
|
||||
return () => window.removeEventListener('resize', updateSize);
|
||||
}, []);
|
||||
return size;
|
||||
}
|
||||
@@ -15,3 +15,5 @@ export * from './RestController';
|
||||
|
||||
export * from './WebSocketFormLoader';
|
||||
export * from './WebSocketController';
|
||||
|
||||
export * from './WindowSize';
|
||||
|
||||
@@ -23,14 +23,12 @@ class EMSESPSettingsController extends Component<EMSESPSettingsControllerProps>
|
||||
|
||||
render() {
|
||||
return (
|
||||
// <Container maxWidth="md" disableGutters>
|
||||
<SectionContent title="" titleGutter>
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={(formProps) => <EMSESPSettingsForm {...formProps} />}
|
||||
/>
|
||||
</SectionContent>
|
||||
// </Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class EMSESPStatusController extends Component<EMSESPStatusControllerProps> {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SectionContent title="EMS Status">
|
||||
<SectionContent title="EMS Status" titleGutter>
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={(formProps) => <EMSESPStatusForm {...formProps} />}
|
||||
|
||||
@@ -9,4 +9,13 @@ module.exports = function (app) {
|
||||
changeOrigin: true
|
||||
})
|
||||
);
|
||||
|
||||
app.use(
|
||||
'/es/*',
|
||||
createProxyMiddleware({
|
||||
target: 'http://localhost:3090',
|
||||
secure: false,
|
||||
changeOrigin: true
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
112
interface/src/system/LogEventConsole.tsx
Normal file
112
interface/src/system/LogEventConsole.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { FC } from 'react';
|
||||
|
||||
import { LogEvent, LogLevel } from './types';
|
||||
import { Theme, makeStyles, Box } from '@material-ui/core';
|
||||
import { useWindowSize } from '../components';
|
||||
|
||||
interface LogEventConsoleProps {
|
||||
events: LogEvent[];
|
||||
}
|
||||
|
||||
interface Offsets {
|
||||
topOffset: () => number;
|
||||
leftOffset: () => number;
|
||||
}
|
||||
|
||||
const topOffset = () =>
|
||||
document.getElementById('log-window')?.getBoundingClientRect().bottom || 0;
|
||||
|
||||
const leftOffset = () =>
|
||||
document.getElementById('log-window')?.getBoundingClientRect().left || 0;
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
console: {
|
||||
padding: theme.spacing(2),
|
||||
position: 'absolute',
|
||||
left: (offsets: Offsets) => offsets.leftOffset(),
|
||||
right: 24,
|
||||
top: (offsets: Offsets) => offsets.topOffset(),
|
||||
bottom: 24,
|
||||
backgroundColor: 'black',
|
||||
overflow: 'auto'
|
||||
},
|
||||
entry: {
|
||||
color: '#bbbbbb',
|
||||
fontFamily: 'Courier New, monospace',
|
||||
fontSize: '14px',
|
||||
letterSpacing: 'normal',
|
||||
whiteSpace: 'nowrap'
|
||||
},
|
||||
debug: {
|
||||
color: '#0000ff'
|
||||
},
|
||||
info: {
|
||||
color: '#00ff00'
|
||||
},
|
||||
notice: {
|
||||
color: '#ffff00'
|
||||
},
|
||||
err: {
|
||||
color: '#ff0000'
|
||||
},
|
||||
unknown: {
|
||||
color: '#ffffff'
|
||||
}
|
||||
}));
|
||||
|
||||
const LogEventConsole: FC<LogEventConsoleProps> = (props) => {
|
||||
useWindowSize();
|
||||
const classes = useStyles({ topOffset, leftOffset });
|
||||
const { events } = props;
|
||||
|
||||
const styleLevel = (level: LogLevel) => {
|
||||
switch (level) {
|
||||
case LogLevel.DEBUG:
|
||||
return classes.debug;
|
||||
case LogLevel.INFO:
|
||||
return classes.info;
|
||||
case LogLevel.NOTICE:
|
||||
return classes.notice;
|
||||
case LogLevel.ERR:
|
||||
return classes.err;
|
||||
default:
|
||||
return classes.unknown;
|
||||
}
|
||||
};
|
||||
|
||||
const levelLabel = (level: LogLevel) => {
|
||||
switch (level) {
|
||||
case LogLevel.DEBUG:
|
||||
return 'DEBUG';
|
||||
case LogLevel.INFO:
|
||||
return 'INFO';
|
||||
case LogLevel.ERR:
|
||||
return 'ERR';
|
||||
case LogLevel.NOTICE:
|
||||
return 'NOTICE';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
};
|
||||
|
||||
const paddedLevelLabel = (level: LogLevel) => {
|
||||
const label = levelLabel(level);
|
||||
return label.padStart(7, '\xa0');
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className={classes.console}>
|
||||
{events.map((e) => (
|
||||
<div className={classes.entry}>
|
||||
<span>{e.time} </span>
|
||||
<span className={styleLevel(e.level)}>
|
||||
{paddedLevelLabel(e.level)}{' '}
|
||||
</span>
|
||||
<span>{e.message}</span>
|
||||
</div>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogEventConsole;
|
||||
109
interface/src/system/LogEventController.tsx
Normal file
109
interface/src/system/LogEventController.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import { Component } from 'react';
|
||||
import { FormActions, FormButton } from '../components';
|
||||
|
||||
import {
|
||||
createStyles,
|
||||
WithStyles,
|
||||
withStyles,
|
||||
Typography,
|
||||
Theme,
|
||||
Paper
|
||||
} from '@material-ui/core';
|
||||
|
||||
import { LogEvent } from './types';
|
||||
import { EVENT_SOURCE_ROOT } from '../api/Env';
|
||||
import LogEventConsole from './LogEventConsole';
|
||||
import { addAccessTokenParameter } from '../authentication';
|
||||
|
||||
import SaveIcon from '@material-ui/icons/Save';
|
||||
|
||||
const LOG_EVENT_EVENT_SOURCE_URL = EVENT_SOURCE_ROOT + 'log';
|
||||
|
||||
interface LogEventControllerState {
|
||||
eventSource?: EventSource;
|
||||
events: LogEvent[];
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
content: {
|
||||
padding: theme.spacing(2),
|
||||
margin: theme.spacing(3)
|
||||
}
|
||||
});
|
||||
|
||||
type LogEventControllerProps = WithStyles<typeof styles>;
|
||||
|
||||
class LogEventController extends Component<
|
||||
LogEventControllerProps,
|
||||
LogEventControllerState
|
||||
> {
|
||||
eventSource?: EventSource;
|
||||
reconnectTimeout?: NodeJS.Timeout;
|
||||
|
||||
constructor(props: LogEventControllerProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
events: []
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.configureEventSource();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.eventSource) {
|
||||
this.eventSource.close();
|
||||
}
|
||||
if (this.reconnectTimeout) {
|
||||
clearTimeout(this.reconnectTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
configureEventSource = () => {
|
||||
this.eventSource = new EventSource(
|
||||
addAccessTokenParameter(LOG_EVENT_EVENT_SOURCE_URL)
|
||||
);
|
||||
this.eventSource.onmessage = this.onMessage;
|
||||
this.eventSource.onerror = this.onError;
|
||||
};
|
||||
|
||||
onError = () => {
|
||||
if (this.eventSource && this.reconnectTimeout) {
|
||||
this.eventSource.close();
|
||||
this.eventSource = undefined;
|
||||
this.reconnectTimeout = setTimeout(this.configureEventSource, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
onMessage = (event: MessageEvent) => {
|
||||
const rawData = event.data;
|
||||
if (typeof rawData === 'string' || rawData instanceof String) {
|
||||
const event = JSON.parse(rawData as string) as LogEvent;
|
||||
this.setState((state) => ({ events: [...state.events, event] }));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<Paper id="log-window" className={classes.content}>
|
||||
<Typography variant="h6">System Log</Typography>
|
||||
<FormActions>
|
||||
<FormButton
|
||||
startIcon={<SaveIcon />}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
// onClick={this.requestNetworkScan}
|
||||
>
|
||||
Save
|
||||
</FormButton>
|
||||
</FormActions>
|
||||
<LogEventConsole events={this.state.events} />
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(LogEventController);
|
||||
@@ -15,6 +15,7 @@ import { MenuAppBar } from '../components';
|
||||
import SystemStatusController from './SystemStatusController';
|
||||
import OTASettingsController from './OTASettingsController';
|
||||
import UploadFirmwareController from './UploadFirmwareController';
|
||||
import LogEventController from './LogEventController';
|
||||
|
||||
type SystemProps = AuthenticatedContextProps &
|
||||
RouteComponentProps &
|
||||
@@ -35,6 +36,7 @@ class System extends Component<SystemProps> {
|
||||
variant="fullWidth"
|
||||
>
|
||||
<Tab value="/system/status" label="System Status" />
|
||||
<Tab value="/system/log" label="System Log" />
|
||||
{features.ota && (
|
||||
<Tab
|
||||
value="/system/ota"
|
||||
@@ -56,6 +58,11 @@ class System extends Component<SystemProps> {
|
||||
path="/system/status"
|
||||
component={SystemStatusController}
|
||||
/>
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path="/system/log"
|
||||
component={LogEventController}
|
||||
/>
|
||||
{features.ota && (
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
|
||||
@@ -36,3 +36,16 @@ export interface OTASettings {
|
||||
port: number;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export enum LogLevel {
|
||||
ERR = 3,
|
||||
NOTICE = 5,
|
||||
INFO = 6,
|
||||
DEBUG = 7
|
||||
}
|
||||
|
||||
export interface LogEvent {
|
||||
time: string;
|
||||
level: LogLevel;
|
||||
message: string;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class AsyncWebServerResponse;
|
||||
class AsyncJsonResponse;
|
||||
class PrettyAsyncJsonResponse;
|
||||
class MsgpackAsyncJsonResponse;
|
||||
class AsyncEventSource;
|
||||
|
||||
class AsyncWebParameter {
|
||||
private:
|
||||
@@ -197,6 +198,10 @@ class AsyncWebHandler {
|
||||
virtual bool isRequestHandlerTrivial() {
|
||||
return true;
|
||||
}
|
||||
|
||||
AsyncWebHandler & setFilter(ArRequestFilterFunction fn) {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class AsyncWebServerResponse {
|
||||
@@ -230,4 +235,17 @@ class AsyncWebServer {
|
||||
};
|
||||
|
||||
|
||||
class AsyncEventSource : public AsyncWebHandler {
|
||||
public:
|
||||
AsyncEventSource(const String & url){};
|
||||
~AsyncEventSource(){};
|
||||
|
||||
size_t count() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void send(const char * message, const char * event = NULL, uint32_t id = 0, uint32_t reconnect = 0){};
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
4
makefile
4
makefile
@@ -17,8 +17,8 @@ MAKEFLAGS+="j "
|
||||
#TARGET := $(notdir $(CURDIR))
|
||||
TARGET := emsesp
|
||||
BUILD := build
|
||||
SOURCES := src lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src src/devices lib/ArduinoJson/src lib/PButton src/test
|
||||
INCLUDES := lib/ArduinoJson/src lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src lib/PButton src/devices lib src
|
||||
SOURCES := src src/* lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src src/devices lib/ArduinoJson/src lib/PButton
|
||||
INCLUDES := src lib_standalone lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src lib/* src/devices
|
||||
LIBRARIES :=
|
||||
|
||||
CPPCHECK = cppcheck
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
(<https://github.com/emsesp/EMS-ESP32/issues/41>)
|
||||
|
||||
When developing and testing the web interface, it's handy not to bother with re-flashing an ESP32 each time. The idea is to mimic the ESP using a mock/stub server that responds to the REST (HTTP POST & GET) and WebSocket calls.
|
||||
@@ -16,7 +15,7 @@ and to run it
|
||||
|
||||
```sh
|
||||
% cd interface
|
||||
% npm run dev
|
||||
% npm run standalone
|
||||
```
|
||||
|
||||
## Notes
|
||||
@@ -24,6 +23,18 @@ and to run it
|
||||
- new file `interface/src/setupProxy.js`
|
||||
- new files `mock-api/server.js` with the hardcoded data. Requires its own npm packages for express
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
% curl -i http://localhost:3080/rest/emsespSettings
|
||||
```
|
||||
|
||||
or from a browser use port 3000 since `setupProxy.js` is redirecting, like http://172.22.227.82:3000/rest/emsespSettings
|
||||
|
||||
http://172.22.227.82:3090/es/log?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInZlcnNpb24iOiIzLjAuMmIwIn0.MsHSgoJKI1lyYz77EiT5ZN3ECMrb4mPv9FNy3udq0TU
|
||||
|
||||
Testing the EventSource/SSE use http://172.22.227.82:3090/es/log
|
||||
|
||||
## To Do
|
||||
|
||||
- add filter rule to prevent from exposing yourself to malicious attacks when running the dev server(<https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a>)
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
const express = require('express')
|
||||
const path = require('path')
|
||||
|
||||
const msgpack = require('@msgpack/msgpack')
|
||||
// import { encode } from "@msgpack/msgpack";
|
||||
|
||||
// REST API
|
||||
const app = express()
|
||||
const port = process.env.PORT || 3080
|
||||
|
||||
const REST_ENDPOINT_ROOT = '/rest/'
|
||||
app.use(express.static(path.join(__dirname, '../interface/build')))
|
||||
app.use(express.json())
|
||||
|
||||
const ENDPOINT_ROOT = '/rest/'
|
||||
// ES API
|
||||
const server = express()
|
||||
const es_port = 3090
|
||||
const ES_ENDPOINT_ROOT = '/es/'
|
||||
|
||||
// NTP
|
||||
const NTP_STATUS_ENDPOINT = ENDPOINT_ROOT + 'ntpStatus'
|
||||
const NTP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'ntpSettings'
|
||||
const TIME_ENDPOINT = ENDPOINT_ROOT + 'time'
|
||||
const NTP_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'ntpStatus'
|
||||
const NTP_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'ntpSettings'
|
||||
const TIME_ENDPOINT = REST_ENDPOINT_ROOT + 'time'
|
||||
const ntp_settings = {
|
||||
enabled: true,
|
||||
server: 'time.google.com',
|
||||
@@ -31,8 +33,8 @@ const ntp_status = {
|
||||
}
|
||||
|
||||
// AP
|
||||
const AP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'apSettings'
|
||||
const AP_STATUS_ENDPOINT = ENDPOINT_ROOT + 'apStatus'
|
||||
const AP_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'apSettings'
|
||||
const AP_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'apStatus'
|
||||
const ap_settings = {
|
||||
provision_mode: 1,
|
||||
ssid: 'ems-esp',
|
||||
@@ -49,10 +51,10 @@ const ap_status = {
|
||||
}
|
||||
|
||||
// NETWORK
|
||||
const NETWORK_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'networkSettings'
|
||||
const NETWORK_STATUS_ENDPOINT = ENDPOINT_ROOT + 'networkStatus'
|
||||
const SCAN_NETWORKS_ENDPOINT = ENDPOINT_ROOT + 'scanNetworks'
|
||||
const LIST_NETWORKS_ENDPOINT = ENDPOINT_ROOT + 'listNetworks'
|
||||
const NETWORK_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'networkSettings'
|
||||
const NETWORK_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'networkStatus'
|
||||
const SCAN_NETWORKS_ENDPOINT = REST_ENDPOINT_ROOT + 'scanNetworks'
|
||||
const LIST_NETWORKS_ENDPOINT = REST_ENDPOINT_ROOT + 'listNetworks'
|
||||
const network_settings = {
|
||||
ssid: 'myWifi',
|
||||
password: 'myPassword',
|
||||
@@ -134,7 +136,7 @@ const list_networks = {
|
||||
}
|
||||
|
||||
// OTA
|
||||
const OTA_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'otaSettings'
|
||||
const OTA_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'otaSettings'
|
||||
const ota_settings = {
|
||||
enabled: true,
|
||||
port: 8266,
|
||||
@@ -142,8 +144,8 @@ const ota_settings = {
|
||||
}
|
||||
|
||||
// MQTT
|
||||
const MQTT_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'mqttSettings'
|
||||
const MQTT_STATUS_ENDPOINT = ENDPOINT_ROOT + 'mqttStatus'
|
||||
const MQTT_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'mqttSettings'
|
||||
const MQTT_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'mqttStatus'
|
||||
const mqtt_settings = {
|
||||
enabled: true,
|
||||
host: '192.168.1.4',
|
||||
@@ -179,15 +181,15 @@ const mqtt_status = {
|
||||
}
|
||||
|
||||
// SYSTEM
|
||||
const FEATURES_ENDPOINT = ENDPOINT_ROOT + 'features'
|
||||
const VERIFY_AUTHORIZATION_ENDPOINT = ENDPOINT_ROOT + 'verifyAuthorization'
|
||||
const SYSTEM_STATUS_ENDPOINT = ENDPOINT_ROOT + 'systemStatus'
|
||||
const SECURITY_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'securitySettings'
|
||||
const RESTART_ENDPOINT = ENDPOINT_ROOT + 'restart'
|
||||
const FACTORY_RESET_ENDPOINT = ENDPOINT_ROOT + 'factoryReset'
|
||||
const UPLOAD_FIRMWARE_ENDPOINT = ENDPOINT_ROOT + 'uploadFirmware'
|
||||
const SIGN_IN_ENDPOINT = ENDPOINT_ROOT + 'signIn'
|
||||
const GENERATE_TOKEN_ENDPOINT = ENDPOINT_ROOT + 'generateToken'
|
||||
const FEATURES_ENDPOINT = REST_ENDPOINT_ROOT + 'features'
|
||||
const VERIFY_AUTHORIZATION_ENDPOINT = REST_ENDPOINT_ROOT + 'verifyAuthorization'
|
||||
const SYSTEM_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'systemStatus'
|
||||
const SECURITY_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'securitySettings'
|
||||
const RESTART_ENDPOINT = REST_ENDPOINT_ROOT + 'restart'
|
||||
const FACTORY_RESET_ENDPOINT = REST_ENDPOINT_ROOT + 'factoryReset'
|
||||
const UPLOAD_FIRMWARE_ENDPOINT = REST_ENDPOINT_ROOT + 'uploadFirmware'
|
||||
const SIGN_IN_ENDPOINT = REST_ENDPOINT_ROOT + 'signIn'
|
||||
const GENERATE_TOKEN_ENDPOINT = REST_ENDPOINT_ROOT + 'generateToken'
|
||||
const system_status = {
|
||||
emsesp_version: '3.1 demo',
|
||||
esp_platform: 'ESP32',
|
||||
@@ -226,13 +228,13 @@ const signin = {
|
||||
const generate_token = { token: '1234' }
|
||||
|
||||
// EMS-ESP Project specific
|
||||
const EMSESP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'emsespSettings'
|
||||
const EMSESP_ALLDEVICES_ENDPOINT = ENDPOINT_ROOT + 'allDevices'
|
||||
const EMSESP_SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + 'scanDevices'
|
||||
const EMSESP_DEVICEDATA_ENDPOINT = ENDPOINT_ROOT + 'deviceData'
|
||||
const EMSESP_STATUS_ENDPOINT = ENDPOINT_ROOT + 'emsespStatus'
|
||||
const EMSESP_BOARDPROFILE_ENDPOINT = ENDPOINT_ROOT + 'boardProfile'
|
||||
const WRITE_VALUE_ENDPOINT = ENDPOINT_ROOT + 'writeValue'
|
||||
const EMSESP_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'emsespSettings'
|
||||
const EMSESP_ALLDEVICES_ENDPOINT = REST_ENDPOINT_ROOT + 'allDevices'
|
||||
const EMSESP_SCANDEVICES_ENDPOINT = REST_ENDPOINT_ROOT + 'scanDevices'
|
||||
const EMSESP_DEVICEDATA_ENDPOINT = REST_ENDPOINT_ROOT + 'deviceData'
|
||||
const EMSESP_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'emsespStatus'
|
||||
const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile'
|
||||
const WRITE_VALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeValue'
|
||||
const emsesp_settings = {
|
||||
tx_mode: 1,
|
||||
tx_delay: 0,
|
||||
@@ -912,5 +914,60 @@ app.post(EMSESP_BOARDPROFILE_ENDPOINT, (req, res) => {
|
||||
res.json(data)
|
||||
})
|
||||
|
||||
// create helper middleware so we can reuse server-sent events
|
||||
const useServerSentEventsMiddleware = (req, res, next) => {
|
||||
res.setHeader('Content-Type', 'text/event-stream')
|
||||
res.setHeader('Cache-Control', 'no-cache')
|
||||
|
||||
// only if you want anyone to access this endpoint
|
||||
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||
|
||||
res.flushHeaders()
|
||||
|
||||
const sendEventStreamData = (data) => {
|
||||
const sseFormattedResponse = `data: ${JSON.stringify(data)}\n\n`
|
||||
res.write(sseFormattedResponse)
|
||||
}
|
||||
|
||||
// we are attaching sendEventStreamData to res, so we can use it later
|
||||
Object.assign(res, {
|
||||
sendEventStreamData,
|
||||
})
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
const streamLog = (req, res) => {
|
||||
let interval = setInterval(function generateAndSendLog() {
|
||||
count = count + 1
|
||||
|
||||
const data = {
|
||||
time: '000+00:00:00.000',
|
||||
level: 4,
|
||||
message: 'this is message #' + count,
|
||||
}
|
||||
|
||||
res.sendEventStreamData(data)
|
||||
}, 1000)
|
||||
|
||||
res.on('close', () => {
|
||||
clearInterval(interval)
|
||||
res.end()
|
||||
})
|
||||
}
|
||||
|
||||
// event source, server-sent events SSE
|
||||
const ES_LOG_ENDPOINT = ES_ENDPOINT_ROOT + 'log'
|
||||
let count = 0
|
||||
server.get(ES_LOG_ENDPOINT, useServerSentEventsMiddleware, streamLog)
|
||||
server.listen(es_port, () =>
|
||||
console.log(
|
||||
`Mock EventSource server for EMS-ESP listening at http://localhost:${es_port}`,
|
||||
),
|
||||
)
|
||||
|
||||
// rest API
|
||||
app.listen(port)
|
||||
console.log(`Mock API Server is up and running at: http://localhost:${port}`)
|
||||
console.log(
|
||||
`Mock RESTful API server for EMS-ESP is up and running at http://localhost:${port}`,
|
||||
)
|
||||
|
||||
@@ -40,6 +40,7 @@ WebSettingsService EMSESP::webSettingsService = WebSettingsService(&webServer, &
|
||||
WebStatusService EMSESP::webStatusService = WebStatusService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
||||
WebDevicesService EMSESP::webDevicesService = WebDevicesService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
||||
WebAPIService EMSESP::webAPIService = WebAPIService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
||||
WebLogService EMSESP::webLogService = WebLogService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
||||
|
||||
using DeviceFlags = EMSdevice;
|
||||
using DeviceType = EMSdevice::DeviceType;
|
||||
@@ -1209,11 +1210,12 @@ void EMSESP::start() {
|
||||
|
||||
// main loop calling all services
|
||||
void EMSESP::loop() {
|
||||
esp8266React.loop(); // web
|
||||
esp8266React.loop(); // web services
|
||||
system_.loop(); // does LED and checks system health, and syslog service
|
||||
|
||||
// if we're doing an OTA upload, skip MQTT and EMS
|
||||
if (!system_.upload_status()) {
|
||||
webLogService.loop(); // log in Web UI
|
||||
rxservice_.loop(); // process any incoming Rx telegrams
|
||||
shower_.loop(); // check for shower on/off
|
||||
dallassensor_.loop(); // read dallas sensor temperatures
|
||||
|
||||
10
src/emsesp.h
10
src/emsesp.h
@@ -35,10 +35,11 @@
|
||||
|
||||
#include <ESP8266React.h>
|
||||
|
||||
#include "WebStatusService.h"
|
||||
#include "WebDevicesService.h"
|
||||
#include "WebSettingsService.h"
|
||||
#include "WebAPIService.h"
|
||||
#include "web/WebStatusService.h"
|
||||
#include "web/WebDevicesService.h"
|
||||
#include "web/WebSettingsService.h"
|
||||
#include "web/WebAPIService.h"
|
||||
#include "web/WebLogService.h"
|
||||
|
||||
#include "emsdevice.h"
|
||||
#include "emsfactory.h"
|
||||
@@ -205,6 +206,7 @@ class EMSESP {
|
||||
static WebStatusService webStatusService;
|
||||
static WebDevicesService webDevicesService;
|
||||
static WebAPIService webAPIService;
|
||||
static WebLogService webLogService;
|
||||
|
||||
static uuid::log::Logger logger();
|
||||
|
||||
|
||||
@@ -849,6 +849,7 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
|
||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||
node = json.createNestedObject("Settings");
|
||||
node["tx_mode"] = settings.tx_mode;
|
||||
node["tx_delay"] = settings.tx_delay;
|
||||
node["ems_bus_id"] = settings.ems_bus_id;
|
||||
node["syslog_enabled"] = settings.syslog_enabled;
|
||||
node["syslog_level"] = settings.syslog_level;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.1.1b6"
|
||||
#define EMSESP_APP_VERSION "3.1.1b7"
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#define DEVICE_DATA_SERVICE_PATH "/rest/deviceData"
|
||||
#define WRITE_VALUE_SERVICE_PATH "/rest/writeValue"
|
||||
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class WebDevicesService {
|
||||
126
src/web/WebLogService.cpp
Normal file
126
src/web/WebLogService.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "emsesp.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||
: _events(EVENT_SOURCE_LOG_PATH) {
|
||||
_events.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
|
||||
server->addHandler(&_events);
|
||||
server->on(EVENT_SOURCE_LOG_PATH, HTTP_GET, std::bind(&WebLogService::forbidden, this, _1));
|
||||
start();
|
||||
}
|
||||
|
||||
void WebLogService::forbidden(AsyncWebServerRequest * request) {
|
||||
request->send(403);
|
||||
}
|
||||
|
||||
void WebLogService::start() {
|
||||
uuid::log::Logger::register_handler(this, uuid::log::Level::INFO); // default is INFO
|
||||
}
|
||||
|
||||
uuid::log::Level WebLogService::log_level() const {
|
||||
return uuid::log::Logger::get_log_level(this);
|
||||
}
|
||||
|
||||
void WebLogService::remove_queued_messages(uuid::log::Level level) {
|
||||
unsigned long offset = 0;
|
||||
|
||||
for (auto it = log_messages_.begin(); it != log_messages_.end();) {
|
||||
if (it->content_->level > level) {
|
||||
offset++;
|
||||
it = log_messages_.erase(it);
|
||||
} else {
|
||||
it->id_ -= offset;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
log_message_id_ -= offset;
|
||||
}
|
||||
|
||||
void WebLogService::log_level(uuid::log::Level level) {
|
||||
uuid::log::Logger::register_handler(this, level);
|
||||
}
|
||||
|
||||
size_t WebLogService::maximum_log_messages() const {
|
||||
return maximum_log_messages_;
|
||||
}
|
||||
|
||||
void WebLogService::maximum_log_messages(size_t count) {
|
||||
maximum_log_messages_ = std::max((size_t)1, count);
|
||||
while (log_messages_.size() > maximum_log_messages_) {
|
||||
log_messages_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
WebLogService::QueuedLogMessage::QueuedLogMessage(unsigned long id, std::shared_ptr<uuid::log::Message> && content)
|
||||
: id_(id)
|
||||
, content_(std::move(content)) {
|
||||
}
|
||||
|
||||
void WebLogService::operator<<(std::shared_ptr<uuid::log::Message> message) {
|
||||
if (log_messages_.size() >= maximum_log_messages_) {
|
||||
log_messages_.pop_front();
|
||||
}
|
||||
log_messages_.emplace_back(log_message_id_++, std::move(message));
|
||||
}
|
||||
|
||||
void WebLogService::loop() {
|
||||
if (!_events.count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (!log_messages_.empty() && can_transmit()) {
|
||||
transmit(log_messages_.front());
|
||||
log_messages_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
bool WebLogService::can_transmit() {
|
||||
const uint64_t now = uuid::get_uptime_ms();
|
||||
if (now < last_transmit_ || now - last_transmit_ < 100) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// send to web eventsource
|
||||
void WebLogService::transmit(const QueuedLogMessage & message) {
|
||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_SMALL);
|
||||
JsonObject logEvent = jsonDocument.to<JsonObject>();
|
||||
logEvent["time"] = uuid::log::format_timestamp_ms(message.content_->uptime_ms, 3);
|
||||
logEvent["level"] = message.content_->level;
|
||||
logEvent["message"] = message.content_->text;
|
||||
|
||||
size_t len = measureJson(jsonDocument);
|
||||
char * buffer = new char[len + 1];
|
||||
if (buffer) {
|
||||
serializeJson(jsonDocument, buffer, len + 1);
|
||||
_events.send(buffer, "message", millis());
|
||||
}
|
||||
delete[] buffer;
|
||||
|
||||
last_transmit_ = uuid::get_uptime_ms();
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
74
src/web/WebLogService.h
Normal file
74
src/web/WebLogService.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WebLogService_h
|
||||
#define WebLogService_h
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <AsyncJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
#define EVENT_SOURCE_LOG_PATH "/es/log"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class WebLogService : public uuid::log::Handler {
|
||||
public:
|
||||
static constexpr size_t MAX_LOG_MESSAGES = 50;
|
||||
|
||||
WebLogService(AsyncWebServer * server, SecurityManager * securityManager);
|
||||
|
||||
void start();
|
||||
uuid::log::Level log_level() const;
|
||||
void log_level(uuid::log::Level level);
|
||||
size_t maximum_log_messages() const;
|
||||
void maximum_log_messages(size_t count);
|
||||
void loop();
|
||||
|
||||
virtual void operator<<(std::shared_ptr<uuid::log::Message> message);
|
||||
|
||||
private:
|
||||
AsyncEventSource _events;
|
||||
|
||||
class QueuedLogMessage {
|
||||
public:
|
||||
QueuedLogMessage(unsigned long id, std::shared_ptr<uuid::log::Message> && content);
|
||||
~QueuedLogMessage() = default;
|
||||
|
||||
unsigned long id_; // Sequential identifier for this log message
|
||||
struct timeval time_; // Time message was received
|
||||
const std::shared_ptr<const uuid::log::Message> content_; // Log message content
|
||||
};
|
||||
|
||||
void forbidden(AsyncWebServerRequest * request);
|
||||
void remove_queued_messages(uuid::log::Level level);
|
||||
bool can_transmit();
|
||||
void transmit(const QueuedLogMessage & message);
|
||||
|
||||
uint64_t last_transmit_ = 0; // Last transmit time
|
||||
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; // Maximum number of log messages to buffer before they are output
|
||||
unsigned long log_message_id_ = 0; // The next identifier to use for queued log messages
|
||||
std::list<QueuedLogMessage> log_messages_; // Queued log messages, in the order they were received
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <HttpEndpoint.h>
|
||||
#include <FSPersistence.h>
|
||||
|
||||
#include "default_settings.h"
|
||||
#include "../default_settings.h"
|
||||
|
||||
#define EMSESP_SETTINGS_FILE "/config/emsespSettings.json"
|
||||
#define EMSESP_SETTINGS_SERVICE_PATH "/rest/emsespSettings"
|
||||
Reference in New Issue
Block a user