From 2876055a8c842f9b9e019936e07935538db6a680 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 10 Mar 2021 13:20:57 +0100 Subject: [PATCH] Add new embedded page --- embedded/.gitignore | 5 + embedded/build.bat | 14 - embedded/config/buildheader.js | 68 + embedded/config/server.js | 616 ++ embedded/config/webpack.dev.js | 52 + embedded/config/webpack.prod.js | 90 + embedded/embedded.h | 502 -- embedded/gulpfile.js | 125 - embedded/package-lock.json | 9240 +++++++++++++++----------- embedded/package.json | 67 +- embedded/server/public/favicon.ico | Bin 0 -> 1150 bytes embedded/server/public/fr.json | 28 + embedded/server/public/index.html.gz | Bin 0 -> 6089 bytes embedded/{ => src}/footer.txt | 0 embedded/{ => src}/header.txt | 0 embedded/src/index.html | 116 + embedded/src/index.js | 774 +++ embedded/src/menu.js | 15 + embedded/src/style.css | 334 + embedded/tool.html.gz | Bin 7528 -> 0 bytes embedded/www/css/style.css | 105 - embedded/www/js/script.js | 596 -- embedded/www/tool.html | 166 - esp3d/src/include/version.h | 2 +- esp3d/src/modules/http/embedded.h | 858 ++- 25 files changed, 7965 insertions(+), 5808 deletions(-) create mode 100644 embedded/.gitignore delete mode 100644 embedded/build.bat create mode 100644 embedded/config/buildheader.js create mode 100644 embedded/config/server.js create mode 100644 embedded/config/webpack.dev.js create mode 100644 embedded/config/webpack.prod.js delete mode 100644 embedded/embedded.h delete mode 100644 embedded/gulpfile.js create mode 100644 embedded/server/public/favicon.ico create mode 100644 embedded/server/public/fr.json create mode 100644 embedded/server/public/index.html.gz rename embedded/{ => src}/footer.txt (100%) rename embedded/{ => src}/header.txt (100%) create mode 100644 embedded/src/index.html create mode 100644 embedded/src/index.js create mode 100644 embedded/src/menu.js create mode 100644 embedded/src/style.css delete mode 100644 embedded/tool.html.gz delete mode 100644 embedded/www/css/style.css delete mode 100644 embedded/www/js/script.js delete mode 100644 embedded/www/tool.html diff --git a/embedded/.gitignore b/embedded/.gitignore new file mode 100644 index 00000000..0602c470 --- /dev/null +++ b/embedded/.gitignore @@ -0,0 +1,5 @@ + +node_modules +.vscode +dist/*.map +dist/*.tmp diff --git a/embedded/build.bat b/embedded/build.bat deleted file mode 100644 index b1afc23f..00000000 --- a/embedded/build.bat +++ /dev/null @@ -1,14 +0,0 @@ -cd %~dp0 -cmd.exe /c npm install -cmd.exe /c npm audit fix -cmd.exe /c npm audit -cmd.exe /c gulp package -cmd.exe /c bin2c -o embedded.h -m tool.html.gz -cat header.txt > out.h -cat embedded.h >> out.h -cat footer.txt >> out.h -sed -i "s/] =/] PROGMEM =/g" out.h -cat out.h > embedded.h -cat out.h > ../esp3d/src/modules/http/embedded.h -rm -f out.h -pause diff --git a/embedded/config/buildheader.js b/embedded/config/buildheader.js new file mode 100644 index 00000000..6b770fe0 --- /dev/null +++ b/embedded/config/buildheader.js @@ -0,0 +1,68 @@ +let path = require("path"); +const fs = require("fs"); +const child_process = require("child_process"); +const chalk = require("chalk"); + +let distPath = path.normalize(__dirname + "/../dist/"); +let srcPath = path.normalize(__dirname + "/../src/"); +let headerPath = path.normalize( + __dirname + "/../../esp3d/src/modules/http/embedded.h" +); + +console.log(chalk.yellow("Converting bin to text file")); +//Cleaning files +if (fs.existsSync(distPath + "out.tmp")) fs.rmSync(distPath + "out.tmp"); +if (fs.existsSync(distPath + "embedded.h")) fs.rmSync(distPath + "embedded.h"); + +//Convert bin2C +child_process.execSync( + "bin2c -o " + distPath + "out.tmp" + " -m " + distPath + "index.html.gz" +); + +//Check conversion +if (fs.existsSync(distPath + "out.tmp")) { + console.log(chalk.green("[ok]")); +} else { + console.log(chalk.red("[error]Conversion failed")); + console.log( + chalk.red( + "Be sure bin2c executable is in your path (https://github.com/AraHaan/bin2c)" + ) + ); + return; +} + +//Format header file +console.log(chalk.yellow("Building header")); +fs.writeFileSync( + distPath + "embedded.h", + fs.readFileSync(srcPath + "header.txt") +); +let bin2cfile = fs.readFileSync(distPath + "out.tmp").toString(); +let newfile = bin2cfile + .replace("] ", "] PROGMEM ") + .replace(/define.*dist_index_html_gz/, "define tool_html_gz") + .replace(/char.*dist_index_html_gz/, "char tool_html_gz"); +fs.appendFileSync(distPath + "embedded.h", newfile); +fs.appendFileSync( + distPath + "embedded.h", + fs.readFileSync(srcPath + "footer.txt") +); + +//Check format result +if (fs.existsSync(distPath + "embedded.h")) { + console.log(chalk.green("[ok]")); +} else { + console.log(chalk.red("[error]Conversion failed")); + return; +} + +//Move file to src +console.log(chalk.yellow("Overwriting header in sources")); +fs.writeFileSync(headerPath, fs.readFileSync(distPath + "embedded.h")); +if (fs.existsSync(headerPath)) { + console.log(chalk.green("[ok]")); +} else { + console.log(chalk.red("[error]Overwriting failed")); + return; +} diff --git a/embedded/config/server.js b/embedded/config/server.js new file mode 100644 index 00000000..ea6d903c --- /dev/null +++ b/embedded/config/server.js @@ -0,0 +1,616 @@ +const express = require("express"); +const chalk = require("chalk"); +let path = require("path"); +const fs = require("fs"); +const port = 8080; +/* + * Web Server for development + * Web Socket server for development + */ +const wscolor = chalk.cyan; +const expresscolor = chalk.green; +const commandcolor = chalk.white; +const WebSocket = require("ws"); +let currentID = 0; +const app = express(); +const fileUpload = require("express-fileupload"); +let serverpath = path.normalize(__dirname + "/../server/public/"); + +let WebSocketServer = require("ws").Server, + wss = new WebSocketServer({ port: 81 }); +app.use(fileUpload({ preserveExtension: true, debug: false })); +app.listen(port, () => + console.log(expresscolor(`[express] Listening on port ${port}!`)) +); + +//app.use(express.urlencoded({ extended: false })); + +function SendBinary(text) { + const array = new Uint8Array(text.length); + for (let i = 0; i < array.length; ++i) { + array[i] = text.charCodeAt(i); + } + wss.clients.forEach(function each(client) { + if (client.readyState === WebSocket.OPEN) { + client.send(array); + } + }); +} + +app.post("/login", function (req, res) { + res.send(""); + return; +}); + +app.get("/config", function (req, res) { + res.send( + "chip id: 56398\nCPU Freq: 240 Mhz
" + + "CPU Temp: 58.3 C
" + + "free mem: 212.36 KB
" + + "SDK: v3.2.3-14-gd3e562907
" + + "flash size: 4.00 MB
" + + "size for update: 1.87 MB
" + + "FS type: LittleFS
" + + "FS usage: 104.00 KB/192.00 KB
" + + "baud: 115200
" + + "sleep mode: none
" + + "wifi: ON
" + + "hostname: esp3d
" + + "HTTP port: 80
" + + "Telnet port: 23
" + + "WebDav port: 8383
" + + "sta: ON
" + + "mac: 80:7D:3A:C4:4E:DC
" + + "SSID: WIFI_OFFICE_A2G
" + + "signal: 100 %
" + + "phy mode: 11n
" + + "channel: 11
" + + "ip mode: dhcp
" + + "ip: 192.168.1.61
" + + "gw: 192.168.1.1
" + + "msk: 255.255.255.0
" + + "DNS: 192.168.1.1
" + + "ap: OFF
" + + "mac: 80:7D:3A:C4:4E:DD
" + + "serial: ON
" + + "notification: OFF
" + + "Target Fw: repetier
" + + "FW ver: 3.0.0.a91
" + + "FW arch: ESP32 " + ); + return; +}); + +app.get("/command", function (req, res) { + console.log(commandcolor(`[server]/command params: ${req.query.cmd}`)); + let url = req.query.cmd; + if (url.startsWith("[ESP800]")) { + res.json({ + FWVersion: "3.0.0.a28", + FWTarget: 40, + SDConnection: "none", + Authentication: "Disabled", + WebCommunication: "Synchronous", + WebSocketIP: "localhost", + WebSocketport: "81", + Hostname: "esp3d", + WiFiMode: "STA", + WebUpdate: "Enabled", + Filesystem: "SPIFFS", + Time: "none", + Cam_ID: "4", + Cam_name: "ESP32 Cam", + }); + return; + } + if (url.indexOf("ESP111") != -1) { + res.send("192.168.1.111"); + return; + } + if (url.indexOf("ESP420") != -1) { + res.json({ + Status: [ + { id: "chip id", value: "38078" }, + { id: "CPU Freq", value: "240 Mhz" }, + { id: "CPU Temp", value: "50.6 C" }, + { id: "free mem", value: "217.50 KB" }, + { id: "SDK", value: "v3.3.1-61-g367c3c09c" }, + { id: "flash size", value: "4.00 MB" }, + { id: "size for update", value: "1.87 MB" }, + { id: "FS type", value: "SPIFFS" }, + { id: "FS usage", value: "39.95 KB/169.38 KB" }, + { id: "baud", value: "115200" }, + { id: "sleep mode", value: "none" }, + { id: "wifi", value: "ON" }, + { id: "hostname", value: "esp3d" }, + { id: "HTTP port", value: "80" }, + { id: "Telnet port", value: "23" }, + { id: "Ftp ports", value: "21, 20, 55600" }, + { id: "sta", value: "ON" }, + { id: "mac", value: "30:AE:A4:21:BE:94" }, + { id: "SSID", value: "WIFI_OFFICE_B2G" }, + { id: "signal", value: "100 %" }, + { id: "phy mode", value: "11n" }, + { id: "channel", value: "2" }, + { id: "ip mode", value: "dhcp" }, + { id: "ip", value: "192.168.1.43" }, + { id: "gw", value: "192.168.1.1" }, + { id: "msk", value: "255.255.255.0" }, + { id: "DNS", value: "192.168.1.1" }, + { id: "ap", value: "OFF" }, + { id: "mac", value: "30:AE:A4:21:BE:95" }, + { id: "serial", value: "ON" }, + { id: "notification", value: "OFF" }, + { id: "FW ver", value: "3.0.0.a28" }, + { id: "FW arch", value: "ESP32" }, + ], + }); + return; + } + + if (url.indexOf("ESP410") != -1) { + res.json({ + AP_LIST: [ + { + SSID: "HP-Setup>71-M277 LaserJet", + SIGNAL: "92", + IS_PROTECTED: "0", + }, + { SSID: "WIFI_OFFICE_B2G", SIGNAL: "88", IS_PROTECTED: "1" }, + { SSID: "NETGEAR70", SIGNAL: "66", IS_PROTECTED: "1" }, + { SSID: "ZenFone6'luc", SIGNAL: "48", IS_PROTECTED: "1" }, + { SSID: "Livebox-EF01", SIGNAL: "20", IS_PROTECTED: "1" }, + { SSID: "orange", SIGNAL: "20", IS_PROTECTED: "0" }, + ], + }); + return; + } + + if (url.indexOf("ESP400") != -1) { + res.json({ + Settings: [ + { + F: "network/network", + P: "130", + T: "S", + V: "esp3d", + H: "hostname", + S: "32", + M: "1", + }, + { + F: "network/network", + P: "0", + T: "B", + V: "1", + H: "radio mode", + O: [{ none: "0" }, { sta: "1" }, { ap: "2" }], + }, + { + F: "network/sta", + P: "1", + T: "S", + V: "WIFI_OFFICE_B2G", + S: "32", + H: "SSID", + M: "1", + }, + { + F: "network/sta", + P: "34", + T: "S", + N: "1", + V: "********", + S: "64", + H: "pwd", + M: "8", + }, + { + F: "network/sta", + P: "99", + T: "B", + V: "1", + H: "ip mode", + O: [{ dhcp: "1" }, { static: "0" }], + }, + { + F: "network/sta", + P: "100", + T: "A", + V: "192.168.0.1", + H: "ip", + }, + { + F: "network/sta", + P: "108", + T: "A", + V: "192.168.0.1", + H: "gw", + }, + { + F: "network/sta", + P: "104", + T: "A", + V: "255.255.255.0", + H: "msk", + }, + { + F: "network/ap", + P: "218", + T: "S", + V: "ESP3D", + S: "32", + H: "SSID", + M: "1", + }, + { + F: "network/ap", + P: "251", + T: "S", + N: "1", + V: "********", + S: "64", + H: "pwd", + M: "8", + }, + { + F: "network/ap", + P: "316", + T: "A", + V: "192.168.0.1", + H: "ip", + }, + { + F: "network/ap", + P: "118", + T: "B", + V: "11", + H: "channel", + O: [ + { 1: "1" }, + { 2: "2" }, + { 3: "3" }, + { 4: "4" }, + { 5: "5" }, + { 6: "6" }, + { 7: "7" }, + { 8: "8" }, + { 9: "9" }, + { 10: "10" }, + { 11: "11" }, + { 12: "12" }, + { 13: "13" }, + { 14: "14" }, + ], + }, + { + F: "service/http", + P: "328", + T: "B", + V: "1", + H: "enable", + O: [{ no: "0" }, { yes: "1" }], + }, + { + F: "service/http", + P: "121", + T: "I", + V: "80", + H: "port", + S: "65001", + M: "1", + }, + { + F: "service/telnetp", + P: "329", + T: "B", + V: "1", + H: "enable", + O: [{ no: "0" }, { yes: "1" }], + }, + { + F: "service/telnetp", + P: "125", + T: "I", + V: "23", + H: "port", + S: "65001", + M: "1", + }, + { + F: "service/ftp", + P: "1021", + T: "B", + V: "1", + H: "enable", + O: [{ no: "0" }, { yes: "1" }], + }, + { + F: "service/ftp", + P: "1009", + T: "I", + V: "21", + H: "control port", + S: "65001", + M: "1", + }, + { + F: "service/ftp", + P: "1013", + T: "I", + V: "20", + H: "active port", + S: "65001", + M: "1", + }, + { + F: "service/ftp", + P: "1017", + T: "I", + V: "55600", + H: "passive port", + S: "65001", + M: "1", + }, + { + F: "service/notification", + P: "1004", + T: "B", + V: "1", + H: "auto notif", + O: [{ no: "0" }, { yes: "1" }], + }, + { + F: "service/notification", + P: "116", + T: "B", + V: "0", + H: "notification", + O: [{ none: "0" }, { pushover: "1" }, { email: "2" }, { line: "3" }], + }, + { + F: "service/notification", + P: "332", + T: "S", + V: "********", + S: "63", + H: "t1", + M: "0", + }, + { + F: "service/notification", + P: "396", + T: "S", + V: "********", + S: "63", + H: "t2", + M: "0", + }, + { + F: "service/notification", + P: "855", + T: "S", + V: " ", + S: "127", + H: "ts", + M: "0", + }, + { + F: "system/system", + P: "461", + T: "B", + V: "40", + H: "targetfw", + O: [ + { repetier: "50" }, + { marlin: "20" }, + { marlinkimbra: "35" }, + { smoothieware: "40" }, + { grbl: "10" }, + { unknown: "0" }, + ], + }, + { + F: "system/system", + P: "112", + T: "I", + V: "115200", + H: "baud", + O: [ + { 9600: "9600" }, + { 19200: "19200" }, + { 38400: "38400" }, + { 57600: "57600" }, + { 74880: "74880" }, + { 115200: "115200" }, + { 230400: "230400" }, + { 250000: "250000" }, + { 500000: "500000" }, + { 921600: "921600" }, + ], + }, + { + F: "system/system", + P: "320", + T: "I", + V: "10000", + H: "bootdelay", + S: "40000", + M: "0", + }, + { + F: "system/system", + P: "129", + T: "F", + V: "255", + H: "outputmsg", + O: [{ M117: "16" }, { serial: "1" }, { telnet: "2" }], + }, + ], + }); + return; + } + SendBinary("ok\n"); + res.send(""); +}); + +function fileSizeString(size) { + let s; + if (size < 1024) return size + " B"; + if (size < 1024 * 1024) return (size / 1024).toFixed(2) + " KB"; + if (size < 1024 * 1024 * 1024) + return (size / (1024 * 1024)).toFixed(2) + " MB"; + if (size < 1024 * 1024 * 1024 * 1024) + return (size / (1024 * 1024 * 1024)).toFixed(2) + " GB"; + return "X B"; +} + +function filesList(mypath) { + let res = '{"files":['; + let nb = 0; + let total = 1.31 * 1024 * 1024; + let totalused = getTotalSize(serverpath); + let currentpath = path.normalize(serverpath + mypath); + console.log("[path]" + currentpath); + fs.readdirSync(currentpath).forEach((fileelement) => { + let fullpath = path.normalize(currentpath + "/" + fileelement); + let fst = fs.statSync(fullpath); + let fsize = -1; + + if (fst.isFile()) { + fsize = fileSizeString(fst.size); + } + if (nb > 0) res += ","; + res += '{"name":"' + fileelement + '","size":"' + fsize + '"}'; + nb++; + }); + res += + '],"path":"' + + mypath + + '","occupation":"' + + ((100 * totalused) / total).toFixed(0) + + '","status":"ok","total":"' + + fileSizeString(total) + + '","used":"' + + fileSizeString(totalused) + + '"}'; + return res; +} + +const getAllFiles = function (dirPath, arrayOfFiles) { + let files = fs.readdirSync(dirPath); + + arrayOfFiles = arrayOfFiles || []; + + files.forEach(function (file) { + if (fs.statSync(dirPath + "/" + file).isDirectory()) { + arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles); + } else { + arrayOfFiles.push(dirPath + "/" + file); + } + }); + + return arrayOfFiles; +}; + +const getTotalSize = function (directoryPath) { + const arrayOfFiles = getAllFiles(directoryPath); + + let totalSize = 0; + + arrayOfFiles.forEach(function (filePath) { + totalSize += fs.statSync(filePath).size; + }); + + return totalSize; +}; + +function deleteFolderRecursive(path) { + if (fs.existsSync(path) && fs.lstatSync(path).isDirectory()) { + fs.readdirSync(path).forEach(function (file, index) { + let curPath = path + "/" + file; + + if (fs.lstatSync(curPath).isDirectory()) { + // recurse + deleteFolderRecursive(curPath); + } else { + // delete file + fs.unlinkSync(curPath); + } + }); + + console.log(`[server]Deleting directory "${path}"...`); + if (fs.existsSync(path)) fs.rmdirSync(path); + } else console.log(`[server]No directory "${path}"...`); +} + +app.all("/updatefw", function (req, res) { + res.send("ok"); +}); + +app.all("/files", function (req, res) { + let mypath = req.query.path; + let url = req.originalUrl; + let filepath = path.normalize(serverpath + mypath + "/" + req.query.filename); + if (url.indexOf("action=deletedir") != -1) { + console.log("[server]delete directory " + filepath); + deleteFolderRecursive(filepath); + fs.readdirSync(mypath); + } else if (url.indexOf("action=delete") != -1) { + fs.unlinkSync(filepath); + console.log("[server]delete file " + filepath); + } + if (url.indexOf("action=createdir") != -1) { + fs.mkdirSync(filepath); + console.log("[server]new directory " + filepath); + } + if (typeof mypath == "undefined") { + if (typeof req.body.path == "undefined") { + console.log("[server]path is not defined"); + mypath = "/"; + } else { + mypath = (req.body.path == "/" ? "" : req.body.path) + "/"; + } + } + console.log("[server]path is " + mypath); + if (!req.files || Object.keys(req.files).length === 0) { + return res.send(filesList(mypath)); + } + let myFile = req.files.myfiles; + if (typeof myFile.length == "undefined") { + let fullpath = path.normalize(serverpath + mypath + myFile.name); + console.log("[server]one file:" + fullpath); + myFile.mv(fullpath, function (err) { + if (err) return res.status(500).send(err); + res.send(filesList(mypath)); + }); + return; + } else { + console.log(myFile.length + " files"); + for (let i = 0; i < myFile.length; i++) { + let fullpath = path.normalize(serverpath + mypath + myFile[i].name); + console.log(fullpath); + myFile[i].mv(fullpath).then(() => { + if (i == myFile.length - 1) res.send(filesList(mypath)); + }); + } + } +}); + +wss.on("connection", (socket, request) => { + console.log(wscolor("[ws] New connection")); + console.log(wscolor(`[ws] currentID:${currentID}`)); + socket.send(`currentID:${currentID}`); + wss.clients.forEach(function each(client) { + if (client.readyState === WebSocket.OPEN) { + client.send(`activeID:${currentID}`); + } + }); + currentID++; + socket.on("message", (message) => { + console.log(wscolor("[ws] received: %s", message)); + }); +}); +wss.on("error", (error) => { + console.log(wscolor("[ws] Error: %s", error)); +}); diff --git a/embedded/config/webpack.dev.js b/embedded/config/webpack.dev.js new file mode 100644 index 00000000..88ff7bc3 --- /dev/null +++ b/embedded/config/webpack.dev.js @@ -0,0 +1,52 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); + +module.exports = { + mode: "development", // this will trigger some webpack default stuffs for dev + entry: path.resolve(__dirname, "../src/index.js"), // if not set, default path to './src/index.js'. Accepts an object with multiple key-value pairs, with key as your custom bundle filename(substituting the [name]), and value as the corresponding file path + output: { + filename: "[name].bundle.js", // [name] will take whatever the input filename is. defaults to 'main' if only a single entry value + path: path.resolve(__dirname, "../dist"), // the folder containing you final dist/build files. Default to './dist' + }, + devServer: { + historyApiFallback: true, // to make our SPA works after a full reload, so that it serves 'index.html' when 404 response + open: true, + contentBase: path.resolve(__dirname, "./dist"), + inline: true, + port: 8088, + proxy: { + context: () => true, + target: "http://localhost:8080", + }, + }, + stats: "minimal", // default behaviour spit out way too much info. adjust to your need. + devtool: "source-map", // a sourcemap type. map to original source with line number + plugins: [ + new HtmlWebpackPlugin({ + template: path.join(__dirname, "../src/index.html"), + inlineSource: ".(js|css)$", + inject: true, + }), + ], // automatically creates a 'index.html' for us with our ,