3.0 code base

This commit is contained in:
Luc
2023-10-02 18:43:02 +08:00
parent 9161f40734
commit 66435e7261
582 changed files with 77871 additions and 45962 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1,276 +0,0 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"commitConvention": "angular",
"contributors": [
{
"login": "alxblog",
"name": " Alexandre ",
"avatar_url": "https://avatars.githubusercontent.com/u/3979539?v=4",
"profile": "https://github.com/alxblog",
"contributions": [
"code"
]
},
{
"login": "MonoAnji",
"name": "René Pasold",
"avatar_url": "https://avatars.githubusercontent.com/u/16881074?v=4",
"profile": "https://github.com/MonoAnji",
"contributions": [
"code"
]
},
{
"login": "aaronse",
"name": "aaron GitHub",
"avatar_url": "https://avatars.githubusercontent.com/u/16479976?v=4",
"profile": "https://github.com/aaronse",
"contributions": [
"code"
]
},
{
"login": "Pavulon87",
"name": "Pavulon87",
"avatar_url": "https://avatars.githubusercontent.com/u/23641103?v=4",
"profile": "https://github.com/Pavulon87",
"contributions": [
"bug",
"code"
]
},
{
"login": "MitchBradley",
"name": "Mitch Bradley",
"avatar_url": "https://avatars.githubusercontent.com/u/4861133?v=4",
"profile": "https://honuputters.com",
"contributions": [
"ideas",
"code"
]
},
{
"login": "cotepat",
"name": "Patrice Côté",
"avatar_url": "https://avatars.githubusercontent.com/u/29361809?v=4",
"profile": "https://www.facebook.com/Patricecotemusique/",
"contributions": [
"code"
]
},
{
"login": "Engineer2Designer",
"name": "E2D",
"avatar_url": "https://avatars.githubusercontent.com/u/25747949?v=4",
"profile": "http://engineer2designer.blogspot.com",
"contributions": [
"translation"
]
},
{
"login": "duramson",
"name": "Cedrik Theesen",
"avatar_url": "https://avatars.githubusercontent.com/u/24916321?v=4",
"profile": "http://cedrik-theesen.de",
"contributions": [
"translation"
]
},
{
"login": "royfocker19",
"name": "royfocker19",
"avatar_url": "https://avatars.githubusercontent.com/u/39307144?v=4",
"profile": "https://github.com/royfocker19",
"contributions": [
"doc"
]
},
{
"login": "BToersche",
"name": "Bart Toersche",
"avatar_url": "https://avatars.githubusercontent.com/u/16536432?v=4",
"profile": "https://github.com/BToersche",
"contributions": [
"code"
]
},
{
"login": "vivian-ng",
"name": "vivian-ng",
"avatar_url": "https://avatars.githubusercontent.com/u/24537694?v=4",
"profile": "https://github.com/vivian-ng",
"contributions": [
"code"
]
},
{
"login": "drzejkopf",
"name": "drzejkopf",
"avatar_url": "https://avatars.githubusercontent.com/u/41212609?v=4",
"profile": "https://github.com/drzejkopf",
"contributions": [
"translation"
]
},
{
"login": "lucmoda",
"name": "Luciano Charles Moda",
"avatar_url": "https://avatars.githubusercontent.com/u/6072702?v=4",
"profile": "http://www.gtmax.com.br",
"contributions": [
"translation"
]
},
{
"login": "leseaw",
"name": "AxelB",
"avatar_url": "https://avatars.githubusercontent.com/u/8026764?v=4",
"profile": "https://youprintin3d.de",
"contributions": [
"translation"
]
},
{
"login": "Zefram88",
"name": "Zefram88",
"avatar_url": "https://avatars.githubusercontent.com/u/40454706?v=4",
"profile": "https://github.com/Zefram88",
"contributions": [
"translation"
]
},
{
"login": "3d-gussner",
"name": "3d-gussner",
"avatar_url": "https://avatars.githubusercontent.com/u/25530011?v=4",
"profile": "https://github.com/3d-gussner",
"contributions": [
"translation"
]
},
{
"login": "aganov",
"name": "Alex Ganov",
"avatar_url": "https://avatars.githubusercontent.com/u/176610?v=4",
"profile": "http://aganov.github.io",
"contributions": [
"ideas",
"code",
"mentoring"
]
},
{
"login": "bdring",
"name": "bdring",
"avatar_url": "https://avatars.githubusercontent.com/u/189677?v=4",
"profile": "https://github.com/bdring",
"contributions": [
"financial",
"bug",
"platform"
]
},
{
"login": "ArturNadolski",
"name": "n4d01",
"avatar_url": "https://avatars.githubusercontent.com/u/20038314?v=4",
"profile": "https://github.com/ArturNadolski",
"contributions": [
"translation"
]
},
{
"login": "ewidance",
"name": "Jean-Philippe CIVADE",
"avatar_url": "https://avatars.githubusercontent.com/u/2135006?v=4",
"profile": "https://www.civade.com",
"contributions": [
"translation"
]
},
{
"login": "kondorzs",
"name": "kondorzs",
"avatar_url": "https://avatars.githubusercontent.com/u/15940476?v=4",
"profile": "https://github.com/kondorzs",
"contributions": [
"translation"
]
},
{
"login": "onekk",
"name": "Carlo",
"avatar_url": "https://avatars.githubusercontent.com/u/7129964?v=4",
"profile": "https://github.com/onekk",
"contributions": [
"translation"
]
},
{
"login": "zrwd01",
"name": "zrwd01",
"avatar_url": "https://avatars.githubusercontent.com/u/33946060?v=4",
"profile": "https://github.com/zrwd01",
"contributions": [
"translation"
]
},
{
"login": "Wesie",
"name": "Wesie",
"avatar_url": "https://avatars.githubusercontent.com/u/9315139?v=4",
"profile": "https://github.com/Wesie",
"contributions": [
"translation"
]
},
{
"login": "DusDus",
"name": "DusDus",
"avatar_url": "https://avatars.githubusercontent.com/u/69902032?v=4",
"profile": "https://github.com/DusDus",
"contributions": [
"translation"
]
},
{
"login": "nyarurato",
"name": "nyarurato",
"avatar_url": "https://avatars.githubusercontent.com/u/8384007?v=4",
"profile": "https://github.com/nyarurato",
"contributions": [
"translation"
]
},
{
"login": "terjeio",
"name": "Terje Io",
"avatar_url": "https://avatars.githubusercontent.com/u/20260062?v=4",
"profile": "https://github.com/terjeio",
"contributions": [
"ideas",
"code",
"translation"
]
},
{
"login": "V1EngineeringInc",
"name": "Ryan V1",
"avatar_url": "https://avatars.githubusercontent.com/u/55478432?v=4",
"profile": "https://www.v1engineering.com/",
"contributions": [
"financial"
]
}
],
"contributorsPerLine": 7,
"skipCi": true,
"repoType": "github",
"repoHost": "https://github.com",
"projectName": "ESP3D-WEBUI",
"projectOwner": "luc-github"
}

8
.github/FUNDING.yml vendored
View File

@@ -1,12 +1,12 @@
# These are supported funding model platforms
#github: luc-github
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
ko_fi: esp3d # Replace with a single Ko-fi username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: ESP3D
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
custom: https://www.paypal.com/donate/?hosted_button_id=FQL59C749A78L
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WWLSJZ97FV834

View File

@@ -1,8 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Wiki
url: https://github.com/luc-github/ESP3D-WEBUI/wiki
about: The Wiki has lot of informations.
- name: Discord chat
url: https://discord.gg/Z4ujTwE
about: Join the discord for support and discussion.

View File

@@ -1,10 +0,0 @@
---
name: Question
about: Ask your question, if not bug neither feature request.
title: "[Question]<Enter comprehensive title>"
labels: Question
assignees: ''
---
What is your question ?

View File

@@ -1,13 +0,0 @@
name: Greetings
on: [pull_request, issues]
jobs:
greeting:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: 'Thank your for submiting, please be sure you followed template or your issue may be dismissed.'
pr-message: 'Thank you for your contribution, be patient, review can take a time.'

View File

@@ -1,26 +0,0 @@
name: 'Lock threads'
on:
schedule:
- cron: '0 0 * * *'
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '10'
issue-exclude-created-before: ''
issue-exclude-labels: 'planned'
issue-lock-labels: 'outdated'
issue-lock-comment: 'This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.'
issue-lock-reason: 'resolved'
pr-lock-inactive-days: '365'
pr-exclude-created-before: ''
pr-exclude-labels: ''
pr-lock-labels: ''
pr-lock-comment: ''
pr-lock-reason: 'resolved'
process-only: 'issues'

5
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/.idea
node_modules
dist
src
.vscode
build

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
14.16.1

28
.prettierrc Normal file
View File

@@ -0,0 +1,28 @@
{
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"semi": false,
"singleQuote": true,
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "always",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"overrides": [
{
"files": "*.js",
"options": {
"parser": "babel"
}
},
{"files": "*.scss",
"options": {
"parser": "css"
}
}
]
}

View File

@@ -1,19 +0,0 @@
language: node_js
node_js:
- "lts/*"
cache:
directories:
- "node_modules"
sudo: false
install:
- npm install --global gulp-cli
- npm install --global gulp@4.0.0
- npm install
script:
- echo "build index.html"
- gulp package
notifications:
email:
on_success: change
on_failure: change

View File

@@ -1,39 +0,0 @@
## What's Changed
# Fixes
* Fix wrong source show in file panel
* Fix SSID with ' not properly transfered from dialog box to control
* Fix macro panel overload UI on some resolutions
* Fix moving buttons in grbl
* Fix SD icon and create dir displayed on GRBL thanks @Wesie
* Fix Abort button for marlin-embedded and marlinkimbra thanks @GerogeFu
* Fix always need to save preferences even no change
* Fix display glitch
* Fix Repetier ok 0 still visible with verbose mode off
* Fix Setup not working anymore due to breaking changes in GRBL_ESP32
* Fix T is not T0 when heating T1 and so display wrong value thanks @Drzet
* Fix typo thanks @terjeio
* Fix bug with pure GRBL no receiving commands feedback thanks @jjhamb
* Fix pur GRBL not managing positions properly
* Fix some typo - thanks @kondorzs
* Fix smoothieware cannot list sub directory - thanks @sns5400
* Fix missing translation for SD
# Additions
* Add ; Linear Units: as legend for G21 in Marlin
* Add more filter to files list if unwished output pop up thanks @badbod
* Add Surfacing Wizard (GRBL panel) thanks @cotepat
* Add BTT USB DISK and onBoard SD support
* Add firmware checks for temperature controls
* Add support for Marlin T0 redundant, probe and chamber temperatures - thanks @BToersche
* Add bin.gz as accepted extension for FW update
# New languages / update
* Add Turkish language thanks @DusDus
* Add Hungarian thanks @kondorzs
* Add Traditional Chinese. thanks @Engineer2Designer
* Add Japanese language thanks @nyarurato
* Update German language thanks @Wesie
* Update German language thanks @duramson
**Full Changelog**: https://github.com/luc-github/ESP3D-WEBUI/compare/v2.1...V2.1.1

BIN
ESP3D-WebUI-features.xls Normal file

Binary file not shown.

76
Features.md Normal file
View File

@@ -0,0 +1,76 @@
# V3 Features
## Global Features
- Firmware update
- WebUI update
- List of enabled features /capabilities
- Wifi configuration
- Features configuration
- WebUI features configuration
- Haptic feedback
- Audio feedback
- Terminal commands
- Emmergency stop
- Pluggins support
- Themes support (CSS)
- Language packs support
- Macro commands
- Local FS listing / content management
- External pages/panel support
- PC / Tablet / phone UI
- IP Camera & ESP32 Camera display support
- Import / Export settings
- Restart board support
- Monolitic small footprint
- Single user management support (auto close if not latest connected)
- Authentication support (admin / user)
- Configuration wizard (TBD)
- Firmware supported (3DPrinter / CNC / SandTable):
- ESP3D V3.x:
- Marlin (1.x / 2.x)
- Smoothieware (1.x / 2.x)
- Repetier (1.x / 2.x)
- GRBL (1.1h)
- ESP3D-TFT (ESP3D)
- ESP3DLib
- Marlin (2.x) - currently need custom version of Marlin : https://github.com/luc-github/Marlin/tree/ESP3DLibV3.0
- grblHAL (ongoing)
- Makerbase TFT (ESP3D)
- Bigtreetech TFT (ESP3D)
- Firmware NOT yet supported:
- Reprap
## 3D Printer Features
- Target firmware configuration
- Jog control / monitoring
- Temperatures control / monitoring
- Additionnal sensors support
- Chart support for temperatures / sensors
- Multiple extruder support
- Target Firmware SD listing / content management (if supported)
- TFT SD/USB listing / content management (if supported)
- Fan control / monitoring (if supported)
- Flow rate control / monitoring (if supported)
- Feed rate control / monitoring (if supported)
- Print control / monitoring
- More to come...
## CNC Features
- Target firmware configuration
- Jog control / monitoring
- Laser control
- Spindle control
- Status monitoring
- Probing control / monitoring
- Code streaming using ESP3D V3
- More to come...
## Sand Table Features
- Target firmware configuration
- Jog control / monitoring
- Status monitoring
- More to come...

310
Memo/Commands.md Normal file
View File

@@ -0,0 +1,310 @@
# Direct ESP3D commands (V3.x)
## Conventions
1 - add space to separate parameters
2 - if parameter has space add \\ in front of space to not be seen as separator
3 - json json=YES json=TRUE json=1 are paremeters to switch output to json
By default output is plain text, to get json formated output
add json or json=yes after main parameters
The json format is {
cmd:"<command id>", //the id of requested command
status:"<ok/error>" //give if it is success or an failure
data:"<response>" // response corresponding to answer in json format too
}
## Commands
- Show commands help
`[ESP]<command id> json=<no>`
- Set/Get STA SSID
`[ESP100]<SSID> json=<no> pwd=<admin password for set/get & user password to get>`
- Set STA Password
`[ESP101]<Password> json=<no> pwd=<admin password>`
- Set/Get STA IP mode (DHCP/STATIC)
`[ESP102]<mode> json=<no> pwd=<admin password>`
- Set/Get STA IP/Mask/GW/DNS
`[ESP103]IP=<IP> MSK=<IP> GW=<IP> DNS=<IP> json=<no> pwd=<admin password>`
- Set/Get sta fallback mode which can be WIFI-AP, BT, OFF
`[ESP104]<state> json=<no> pwd=<admin password>`
- Set/Get AP SSID
`[ESP105]<SSID> json=<no> pwd=<admin password>`
- Change AP Password
`[ESP106]<Password> json=<no> pwd=<admin password>`
- Set/Get AP IP
`[ESP107]<IP> json=<no> pwd=<admin password>`
- Set/Get AP channel
`[ESP108]<channel> json=<no> pwd=<admin password>`
- Set/Get radio state which can be WIFI-STA, WIFI-AP, BT, ETH-STA, ETH-AP, OFF
`[ESP110]<state> json=<no> pwd=<admin password>`
- Get current IP
`[ESP111]json=<no>`
- Get/Set hostname
`[ESP112]<Hostname> json=<no> pwd=<admin password>`
- Get /Set Boot radio state which can be ON, OFF
`[ESP114]<state> json=<no> pwd=<user/admin password>`
- Get/Set immediate network(WiFi/BT/Ethernet) state which can be ON, OFF
`[ESP115]<state> json=<no> pwd=<admin password>`
- Get/Set HTTP state which can be ON, OFF
`[ESP120]<state> json=<no> pwd=<admin password>`
- Get/Set HTTP port
`[ESP121]<port> json=<no> pwd=<admin password>`
- Get/Set Telnet state which can be ON, OFF, CLOSE
`[ESP130]<state> json=<no> pwd=<admin password>`
- Get/Set Telnet port
`[ESP131]<port> json=<no> pwd=<admin password>`
- Sync / Set / Get current time
`[ESP140]<SYNC> <srv1=XXXXX> <srv2=XXXXX> <srv3=XXXXX> <zone=xxx> <dst=YES/NO> <time=YYYY-MM-DDTHH:mm:ss> <NOW> json=<no> pwd=<admin password>`
- Get/Set display/set boot delay in ms / Verbose boot
`[ESP150]<delay=time in milliseconds><verbose=ON/OFF>pwd=<admin password>`
- Get/Set WebSocket state which can be ON, OFF
`[ESP160]<state> json=<no> pwd=<admin password>`
- Get/Set WebSocket port
`[ESP161]<port> json=<no> pwd=<admin password>`
- Get/Set Camera command value / list all values in JSON/plain
label can be: light/framesize/quality/contrast/brightness/saturation/gainceiling/colorbar/awb/agc/aec/hmirror/vflip/awb_gain/agc_gain/aec_value/aec2/cw/bpc/wpc/raw_gma/lenc/special_effect/wb_mode/ae_level
`[ESP170]<label=value> json=<no> pwd=<admin password>`
- Save frame to target path and filename (default target = today date, default name=timestamp.jpg)
`[ESP171] <path=target path> <filename=target filename>`
- Get/Set Ftp state which can be ON, OFF, CLOSE
`[ESP180]<state> json=<no> pwd=<admin password>`
- Get/Set Ftp ports
`[ESP181]ctrl=<port> active=<port> passive=<port> json=<no> pwd=<admin password>`
- Get/Set WebDav state which can be ON, OFF, CLOSE
`[ESP190]<state> json=<no> pwd=<admin password>`
- Get/Set WebDav port
`[ESP191]<port> json=<no> pwd=<admin password>`
- Get/Set SD Card Status
`[ESP200]<RELEASE> <REFRESH> json=<no> pwd=<user/admin password>`
`RELEASE` will force the release of SD from ESP3D if SD is shared
`REFRESH` will refresh the SD info is available`
- Get/Set pin value
`[ESP201]P=<pin> V=<value> [PULLUP=YES RAW=YES ANALOG=NO ANALOG_RANGE=255]pwd=<admin password>`
- if no V=<value> get P=<pin> value
- if V=<value> 0/1 set INPUT_PULLUP value, but for GPIO16(ESP8266) INPUT_PULLDOWN_16
- if PULLUP=YES set input pull up (for GPIO16(ESP8266) INPUT_PULLDOWN_16), if not set input
- if RAW=YES do not set pinmode just read value
Note: Flash pins according chip cannot be used
- Get/Set SD card Speed factor 1 2 4 6 8 16 32
`[ESP202]SPEED=<value> json=<no> pwd=<user/admin password>`
- Get Sensor Value / type/Set Sensor type
`[ESP210]<type=NONE/xxx> <interval=XXX in millisec> json=<no> pwd=<user/admin password>`
- Output to esp screen status
`[ESP214]<Text> json=<no> pwd=<user/admin password>`
- Touch Calibration
`[ESP215]<CALIBRATE> json=<no> pwd=<user password>`
- Show defined pins
`[ESP220]<SNAP> json=<no> pwd=<user password>`
- Play sound
`[ESP250]F=<frequency> D=<duration> json=<no> pwd=<user password>`
Note: No parameter just play beep
- Delay command
`[ESP290]<delay in ms> json=<no>pwd=<user password>`
- Get full EEPROM settings content
`[ESP400] pwd=<admin password>`
Note: do not give any passwords
\*Set EEPROM setting
position in EEPROM, type: B(byte), I(integer/long), S(string), A(IP address / mask)
`[ESP401]P=<position> T=<type> V=<value> json=<no> pwd=<user/admin password>`
```
Description: Positions:
ESP_RADIO_MODE 0 //1 byte = flag
ESP_STA_SSID 1 //33 bytes 32+1 = string ; warning does not support multibyte char like chinese
ESP_STA_PASSWORD 34 //65 bytes 64 +1 = string ;warning does not support multibyte char like chinese
ESP_STA_IP_MODE 99 //1 byte = flag
ESP_STA_IP_VALUE 100 //4 bytes xxx.xxx.xxx.xxx
ESP_STA_MASK_VALUE 104 //4 bytes xxx.xxx.xxx.xxx
ESP_STA_GATEWAY_VALUE 108 //4 bytes xxx.xxx.xxx.xxx
ESP_BAUD_RATE 112 //4 bytes = int
ESP_NOTIFICATION_TYPE 116 //1 byte = flag
ESP_CALIBRATION 117 //1 byte = flag
ESP_AP_CHANNEL 118 //1 byte = flag
ESP_BUZZER 119 //1 byte = flag
ESP_INTERNET_TIME 120 //1 byte = flag
ESP_HTTP_PORT 121 //4 bytes = int
ESP_TELNET_PORT 125 //4 bytes = int
ESP_SERIAL_FLAG 129 //1 bytes = flag
ESP_HOSTNAME 130 //33 bytes 32+1 = string ; warning does not support multibyte char like chinese
ESP_SENSOR_INTERVAL 164 //4 bytes = int
ESP_SETTINGS_VERSION 168 //8 bytes = 7+1 = string ESP3D + 2 digits
ESP_ADMIN_PWD 176 //21 bytes 20+1 = string ; warning does not support multibyte char like chinese
ESP_USER_PWD 197 //21 bytes 20+1 = string ; warning does not support multibyte char like chinese
ESP_AP_SSID 218 //33 bytes 32+1 = string ; warning does not support multibyte char like chinese
ESP_AP_PASSWORD 251 //65 bytes 64 +1 = string ;warning does not support multibyte char like chinese
ESP_AP_IP_VALUE 316 //4 bytes xxx.xxx.xxx.xxx
ESP_BOOT_DELAY 320 //4 bytes = int
ESP_WEBSOCKET_PORT 324 //4 bytes= int
ESP_HTTP_ON 328 //1 byte = flag
ESP_TELNET_ON 329 //1 byte = flag
ESP_WEBSOCKET_ON 330 //1 byte = flag
ESP_SD_SPEED_DIV 331 //1 byte = flag
ESP_NOTIFICATION_TOKEN1 332 //64 bytes 63+1 = string ; warning does not support multibyte char like chinese
ESP_NOTIFICATION_TOKEN2 396 //64 bytes 63+1 = string ; warning does not support multibyte char like chinese
ESP_SENSOR_TYPE 460 //1 bytes = flag
ESP_TARGET_FW 461 //1 bytes = flag
ESP_TIMEZONE 462 //1 bytes = flag
ESP_TIME_IS_DST 463 //1 bytes = flag
ESP_TIME_SERVER1 464 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese
ESP_TIME_SERVER2 593 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese
ESP_TIME_SERVER3 722 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese
ESP_REMOTE_SCREEN 851 //1 bytes = flag
ESP_SD_MOUNT 852 //1 bytes = flag
ESP_SESSION_TIMEOUT 853 //1 bytes = flag
ESP_WEBSOCKET_FLAG 854 //1 bytes = flag
ESP_SD_CHECK_UPDATE_AT_BOOT 855//1 bytes = flag
ESP_NOTIFICATION_SETTINGS 856 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese
ESP_CALIBRATION_1 985 //4 bytes = int
ESP_CALIBRATION_2 989 //4 bytes = int
ESP_CALIBRATION_3 993 //4 bytes = int
ESP_CALIBRATION_4 997 //4 bytes = int
ESP_CALIBRATION_5 1001 //4 bytes = int
ESP_SETUP 1005 //1 byte = flag
ESP_TELNET_FLAG 1006 //1 byte = flag
ESP_BT_FLAG 1007 //1 byte = flag
ESP_SCREEEN_FLAG 1008 //1 byte = flag
ESP_FTP_CTRL_PORT 1009 //4 bytes = int
ESP_FTP_DATA_ACTIVE_PORT 1013 //4 bytes = int
ESP_FTP_DATA_PASSIVE_PORT 1017 //4 bytes = int
ESP_FTP_ON 1021 //1 byte = flag
ESP_AUTO_NOTIFICATION 1022 //1 byte = flag
ESP_VERBOSE_BOOT 1023 //1 byte = flag
ESP_WEBDAV_ON 1024 //1 byte = flag
ESP_WEBDAV_PORT 1025 //4 bytes = int
ESP_STA_DNS_VALUE 1029 //4 bytes= int
ESP_SECURE_SERIAL 1033 //1 byte = flag
ESP_SERIAL_BRIDGE_ON 1036 //1 byte = flag
ESP_SERIAL_BRIDGE_FLAG 1037 //1 byte = flag
ESP_SERIAL_BRIDGE_BAUD 1038 //4 bytes= int
```
- Get/Set Check update at boot state which can be ON, OFF
`[ESP402]<state> json=<no> pwd=<admin password>`
- Get available AP list (limited to 30)
output is JSON or plain text according parameter
`[ESP410]json=<no> <pwd=admin/user>`
- Get current settings of ESP3D
Output is JSON or plain text according parameter
`[ESP420]json=<no> <pwd=admin/user>`
- Set ESP State
`cmd` can be `RESTART` to restart board or `RESET` to reset all setting to defaults values
`[ESP444]<cmd> json=<no> <pwd=admin>`
- Get available ESP3D list
output is JSON or plain text according parameter
`[ESP450]json=<no> <pwd=admin/user>`
- Change admin password
`[ESP550]<password> json=<no> pwd=<admin password>`
- Change user password
`[ESP555]<password> json=<no> pwd=<admin/user password>`
- Send Notification
`[ESP600]msg json=<no> pwd=<admin/user password>`
- Set/Get Notification settings
`[ESP610]type=<NONE/PUSHOVER/EMAIL/LINE/IFTTT> T1=<token1> T2=<token2> TS=<Settings> json=<no> [pwd=<admin password>]`
Get will give type and settings only, not the protected T1/T2
- Send Notification using URL
`[ESP620]URL=<encoded url> json=<no> pwd=<admin/user password>`
- Read / Stream / Process FS file
`[ESP700]<filename> json=<no> pwd=<admin/user password>`
- Query and Control ESP700 stream
`[ESP701]action=<PAUSE/RESUME/ABORT> json=<no> pwd=<admin/user password>`
- Format ESP Filesystem
`[ESP710]FORMATFS json=<no> pwd=<admin password>`
- Format SD Filesystem
`[ESP715]FORMATSD json=<no> pwd=<admin password>`
- List ESP Filesystem
`[ESP720]<Root> json=<no> pwd=<admin password>`
- Action on ESP Filesystem
Action can be `rmdir` to remove empty directory / `remove` to delete file / `mkdir` to create directory / `exists` to check if file or directory exists / `create` create an empty file
`[ESP730]<Action>=<path> json=<no> pwd=<admin password>`
- List SD Filesystem
`[ESP740]<Root> json=<no> pwd=<admin password>`
- Action on SD Filesystem
Action can be `rmdir` to remove empty directory / `remove` to delete file / `mkdir` to create directory / `exists` to check if file or directory exists / `create` create an empty file
`[ESP750]<Action>=<path> json=<no> pwd=<admin password>`
- List Global Filesystem
`[ESP780]<Root> json=<no> pwd=<admin password>`
- Action on Global Filesystem
Action can be `rmdir` to remove empty directory / `remove` to delete file / `mkdir` to create directory / `exists` to check if file or directory exists / `create` create an empty file
`[ESP790]<Action>=<path> json=<no> pwd=<admin password>`
- FW Informations
`[ESP800]json=<no> pwd=<admin password> <time=YYYY-MM-DDTHH:mm:ss> <version=3.0.0-a11> <setup=0/1>`
- Get state / Set Enable / Disable Serial Communication
`[ESP900]<ENABLE/DISABLE> json=<no> pwd=<admin/user password>`
- Get / Set Serial Baud Rate
`[ESP901]<BAUD RATE> json=<no> pwd=<admin/user password>`
- Get state / Set Enable / Disable buzzer
`[ESP910]<ENABLE/DISABLE> json=<no> pwd=<admin/user password>`
- Get state / Set state of output message clients
`[ESP920]<SERIAL / SCREEN / REMOTE_SCREEN/ WEBSOCKET / TELNET /BT / ALL>=<ON/OFF> json=<no> pwd=<admin/user password>`
- Get state / Set Enable / Disable Serial Bridge Communication
`[ESP930]<ENABLE/DISABLE> json=<no> pwd=<admin/user password>`
- Get / Set Serial Bridge Baud Rate
`[ESP931]<BAUD RATE> json=<no> pwd=<admin/user password>`
- Set quiet boot if strapping pin is High
`[ESP999]QUIETBOOT pwd=<admin/user password>`

View File

@@ -0,0 +1,102 @@
# ESP3D [ESP400] format
Only sent in JSON format
```
{"cmd":"400","status":"ok","data":[
{"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"},
{"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"},
]}
```
1 - key : `Settings`
2 - value: array of data formated like this
{"F":"network/network","P":"130","T":"S","V":"esp3d","H":"hostname","S":"32","M":"1"}
or
{"F":"service/notification","P":"1004","T":"B","V":"1","H":"auto notif","O":[{"no":"0"},{"yes":"1"}]}
- F: is filter formated as section/sub-section, if section is same as sub-section, it means no sub-section
- P: is id (also position reference so it is unique)
- T: is type of data which can be:
- S: for string
- I: for integer
- B: for Byte
- A: for IP address / Mask
- F: for float (only grblHAL)
- M: for bits mask (only grblHAL)
- X: for exclusive bitsfield (only grblHAL)
- V: is current value, if type is string and value is `********`, (8 stars) then it is a password
- E: is integer for exactess / precision of float/double value (only grblHAL)
- U: is text unit of value (only grblHAL)
- H: is text label of value
- S: is max size if type is string, and max possible value if value is number (byte, integer)
- M: is min size if type is string, and min possible value if value is number (byte, integer)
- MS: is additionnal min size if type is string (e.g for password can be 0 or 8, so need additional min size), M should be the more minimal value
so MS value must be between M and S
- O: is an array of {label:value} used for possible values in selection or bits labels list
- R: need restart to be applied
Note: if Type `M` and `X` use `O` entry to define the label / position, if `O` is `[]` then axis label are used according need `X`, `Y`, `Z`, `A`, `B`, `C`
Note2 : the 2.1 Flag type is no more used, several entries are used instead grouped by sub-section

View File

@@ -0,0 +1,22 @@
# ESP3D [ESP401] format
WebUI need use json format to get propelry formated answer
As described in Commands.md:
## Conventions
1 - add space to separate parameters
2 - if parameter has space add \\ in front of space to not be seen as separator
3 - json json=YES json=TRUE json=1 are paremeters to switch output to json
By default output is plain text, to get json formated output
add json or json=yes after main parameters
The json format is {
cmd:"<401>", //the id of requested command
status:"<ok/error>" //give if it is success or an failure
data:"the position of setting"
}
Example
`[ESP401]P=1 T=S V=My\ SSID json`
you will get the following if ok
`{"cmd":"401","status":"ok","data":"1"}`

View File

@@ -0,0 +1,34 @@
# ESP3D [ESP410] format
This command list all AP available, limited to 30 by API, if signal is too low, AP is not listed to avoid connection problems.
WebUI need use json format to get propelry formated answer
As described in Commands.md:
Example
`[ESP410]json`
you will get the following if ok
```
{
"cmd": "410",
"status": "ok",
"data": [
{
"SSID": "GRBL",
"SIGNAL": "100",
"IS_PROTECTED": "1"
},
{
"SSID": "luc-ext1",
"SIGNAL": "64",
"IS_PROTECTED": "1"
},
{
"SSID": "TP-Link_Luc",
"SIGNAL": "62",
"IS_PROTECTED": "1"
}
]
}
```

View File

@@ -0,0 +1,119 @@
# ESP3D [ESP800] format
can be in JSON or plain text
## Input
`[ESP800]<time=YYYY-MM-DDTHH:mm:ss> <version=3.0.0-a11> <setup=0/1> json=<no> pwd=<admin password>`
* json=yes
the output format
* time=
to set ESP3D time using ISO 8601 format : `YYYY`-`MM`-`DD`T`HH`-`minutes`-`seconds`
* version
version of webUI
* setup flag
Enable / Disable the setup flag
## Output
- In json format
```
{
"cmd":"800",
"status":"ok",
"data":{
"FWVersion":"bugfix-2.0.x-3.0.0.a200",
"FWTarget":"marlin",
"FWTargetID":"30",
"Setup":"Enabled",
"SDConnection":"shared",
"SerialProtocol":"Socket",
"Authentication":"Disabled",
"WebCommunication":"Synchronous",
"WebSocketIP":"192.168.2.117",
"WebSocketPort":"81",
"Hostname":"esp3d",
"WiFiMode":"STA",
"WebUpdate":"Enabled",
"FlashFileSystem":"LittleFS",
"HostPath":"www",
"Time":"none"
}
}
```
* `cmd`
Id of requested command, should be `800`
* `status`
status of command, should be `ok`
* `data`
content of response:
* `FWVersion`
Version of ESP3D firmware or targeted FW (Marlin with ESP3DLib / grblHal)
* `FWTarget`
name of targeted Firmware
* `FWTargetID`
numerical ID of targeted FW as same name can have several Ids
* `Setup`
Should be `Enabled` or `Disabled` according flag in EEPROM/Preferences, this allows to WedUI to start wizard automaticaly (or not)
* `SDConnection`
This is SD capability, SD can be
* `shared`
ESP does share access to SD card reader with main board or Firmware (Marlin with ESP3Dlib, ESP3D with hardware SD share solution)
* `direct`
ESP does have direct access to SD card reader (e.g: ESP3D, grblHal)
* `none`
ESP does not have direct access to SD card reader, (e.g: ESP3D with only serial connection)
* `SerialProtocol`
It define how ESP3D FW communicate with main FW
* `Socket`
ESP and main FW use same FW (e.g: Marlin with ESP3DLib, grblHal)
* `Raw`
Classic serial connection
* `MKS`
Serial connection using MKS protocol
* `Authentication`
Can be `Enabled` or `Disabled`
* `WebCommunication`
currently only `Synchronous`, because `Asychronous` has been put in hold
* `WebSocketIP`
Ip address for the websocket terminal `192.168.2.117`
* `WebSocketPort`
Port for the web socket terminal `81`
* `Hostname`
Hostname of ESP3D or main Baord `esp3d`
* `WiFiMode`
Current wiFi mode in use can be `AP` or `STA`
* `WebUpdate`
Inform webUI the feature is available or not, can be `Enabled` or `Disabled`
* `FlashFileSystem` (currently `FileSystem`, to be updated soon )
The file system used by ESP board can be `LittleFS`, `SPIFFS`, `Fat`, `none`
* `HostPath`
Path where the preferences.json and index.html.gz are stored and can be updated (e.g: `www`)
* `Time`
Type of time support
* `none`
Time is not supported
* `Auto`
Board use internet to sync time and it is successful
* `Failed to set`
Board use internet to sync time and it is failed
* `Manual`
Board use time of ESP800 to set the time and it is successful
* `Not set`
Board use time of ESP800 to set the time and command did not sent it (time may have been set by previous command)
* `CameraID`
if ESP has camera it contain the camera ID
* `CameraName`
if ESP has camera it contain the camera name
* `Axisletters`
Currently only used for grbHAL
can be :
- XYZABC
- XYZUVZ (supported soon)
- XYZABCUVZ (supported soon)

175
Memo/Handlers.md Normal file
View File

@@ -0,0 +1,175 @@
# Web Handlers
### /
root is the default handler where all files will be served, if no file is defined, it looks for index.html or index.html.gz (compressed)
if you call specific file, it will look for the filename and filename.gz (compressed)
if no file is defined and there is not index.html(.gz) it will display embedded page
another way to show the embedded page is /?forcefallback=yes
### /sd/
it will serve any file from SD card if there is one, it is only a wrapper to read SD card, no upload
### /files
this handler handle all commands for FS, including upload on FS.
possible options/arguments are:
- `quiet=yes` can be used when you don't want list files but just upload them
- `path=...` define the path to the file
- `action=...` define the action to execute which can be:
- delete
delete the file defined by `filename=...` it will also use `path=...` to do full path
- deletedir
delete the directory defined by `filename=...` it will also use `path=...` to do full path
- createdir
create the directory defined by `filename=...` it will also use `path=...` to do full path
- `createPath=yes` when doing upload and the path do not exists, it will create it, POST only
- `<filename>S=...` give the size of uploaded file with <filename> name, need to be set before file is set in upload, POST only
the output is a json file:
```
{
"files":[ //the files list
{
"name":"index.html.gz", //the name of the file
"size":"83.46 KB", //the formated size of the file
"time":"2022-09-04 11:56:05" //the time when the file was modified last time, this one is optional and depend on (FILESYSTEM_TIMESTAMP_FEATURE)
},
{
"name":"subdir", //the name of the file / directory
"size":"-1", //the size is -1 because it is a directory
"time":"" //no time for directories optional as depend on (FILESYSTEM_TIMESTAMP_FEATURE)
}
],
"path":"/", //current path
"occupation":"52", //% of occupation
"status":"subdir created", //status
"total":"192.00 KB", //Formated total space of Filesystem
"used":"100.00 KB" //Formated used space of Filesystem
}
```
### /sdfiles
this handler handle all commands for SD, including upload on SD (only shared and direct SD)
this handler handle all commands for FS, including upload on FS.
possible options/arguments are:
- `quiet=yes` can be used when you don't want list files but just upload them
- `path=...` define the path to the file
- `action=...` define the action to execute which can be:
- list
Will refresh the stats of the files - delete
delete the file defined by `filename=...` it will also use `path=...` to do full path
- deletedir
delete the directory defined by `filename=...` it will also use `path=...` to do full path
- createdir
create the directory defined by `filename=...` it will also use `path=...` to do full path
- `createPath=yes` when doing upload and the path do not exists, it will create it, POST only
- `<filename>S=...` give the size of uploaded file with <filename> name, need to be set before file is set in upload, POST only
the output is a json file:
```
{
"files":[ //the files list
{
"name":"3Oc-pika2.gco",//the name of the file
"shortname":"3Oc-pika2.gco", //the 8.3 shortname if available, if not the name of the file
"size":"83.46 KB", //the formated size of the file
"time":"2022-09-04 11:56:05" //the time when the file was modified last time, this one is optional and depend on (SD_TIMESTAMP_FEATURE)
},
{
"name":"subdir", //the name of the file / directory
"size":"-1", //the size is -1 because it is a directory
"time":"" //no time for directories optional as depend on (SD_TIMESTAMP_FEATURE)
}
],
"path":"/", //current path
"occupation":"52", //% of occupation
"status":"subdir created", //status
"total":"192.00 KB", //Formated total space of Filesystem
"used":"100.00 KB" //Formated used space of Filesystem
}
```
### /upload
this handler is for MKS boards using MKS communication protocol if enabled, it handle only upload on SD
### /command
this handler is for all commands the parameter is `cmd=...`
if it is an `[ESPXXX]` command the answer is the `[ESPXXX]` response
if it is not an `[ESPXXX]` command the answer is `ESP3D says: command forwarded` and can be ignored
### /login
this handler is for authentication function if enabled
possible options/arguments are:
- `DISCONNECT=YES`
it will clear current session, remove authentication cookie, set status to `disconnected` and response code to 401 - `SUBMIT=YES`
to login it will need also `PASSWORD=...` and `USER=...`, the answer will be 200 if success and 401 if failed
if user is already authenticated it can use `NEWPASSWORD=...` instead of `PASSWORD=...` to change his password, if successful answer will be returned with code 200, otherwise code will be 500 if change failed or if password format is invalid
Output:
- if authentified and no submission:
`{"status":"Identified","authentication_lvl":"admin"}` and code 200
- if not authenticated and no submission:
`{"status":"Wrong authentication!","authentication_lvl":"guest"}` and code 401
### /config
this handler is a shortcut to [ESP420] command in text mode, to get output in json add `json=yes`
### /updatefw
this handler is for FW upload and update
Answer output is :
`{"status":"..."}` if upload is successful the ESP will restart
### /snap
this handler is on esp32cam with camera enabled to capture a Frame
it answer by sending a jpg image
### /description.xml
this handler is for SSDP if enabled to present device informations
```
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://192.168.2.178:80/</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:upnp:rootdevice:1</deviceType>
<friendlyName>esp3d</friendlyName>
<presentationURL>/</presentationURL>
<serialNumber>52332</serialNumber>
<modelName>ESP Board</modelName>
<modelDescription/>
<modelNumber>ESP3D 3.0</modelNumber>
<modelURL>https://www.espressif.com/en/products/devkits</modelURL>
<manufacturer>Espressif Systems</manufacturer>
<manufacturerURL>https://www.espressif.com</manufacturerURL>
<UDN>uuid:38323636-4558-4dda-9188-cda0e600cc6c</UDN>
<serviceList/>
<iconList/>
</device>
</root>
```
### Captive portal bypass handlers
to avoid a redirect to index.html and so a refresh of the page, some classic handler have been added so they all go to / handler actually
- /generate_204
- /gconnectivitycheck.gstatic.com
- /fwlink/

20
Memo/TargetFW.md Normal file
View File

@@ -0,0 +1,20 @@
# Firmware names, ids, usages
- grblhal
grblhal -80 - grblHAL Fw
- reprap
reprap -70 - NA
- fluidnc
fluidnc -60 - NA
- repetier
repetier - 50 - ESP3D Fw
- smoothieware
smoothieware- 40 - ESP3D Fw
- marlin_embedded
marlin - 30 - ESP3DLib/Marlin
- marlin
marlin - 20 - ESP3D Fw
- grbl
grbl - 10 - ESP3D Fw
- unknown
unknown - 0 - ESP3D Fw

BIN
Memo/data structure.odt Normal file

Binary file not shown.

62
Memo/languagepack.md Normal file
View File

@@ -0,0 +1,62 @@
# Language packs
## Generate template files
Use the script `npm run template` to geenrate up todate template files for all packs
Currently:
- CNC GRBL in `languages/cncgrblpack`
- CNC grblHAL `languages/cncgrblhalpack`
- 3D Printers (all) `languages/printerpack`
- Sand Table (all) `languages/sandtablepack`
## Generate language pack files
- Rename the template file according the language code http://www.lingoes.net/en/translator/langcode.htm using `_` instead of `-` and add `lang-` in from of name.
so for example :
- for french language pack, `en.json` file would be renamed to `lang-fr.json`
- for simplified chinese language pack, `en.json` file would be renamed to `lang-zh_cn.json`
- for simplified chinese language pack, `en.json` file would be renamed to `lang-zh_cn.json`
- for german language pack, `en.json` file would be renamed to `lang-de.json`
- Modify the language pack file according to the language and test it against the WebUI
- Compress the final pack
use the following command to compress the final pack targeting the file :
`npm run package target=languages/<target pack>/lang-<target language>.json`
so for French language pack for example:
`npm run package target=languages/printerpack/lang-fr.json`
## Compare template pack with language pack file
This script is used to compare current language pack content against the template language pack to see if the language pack need to be updated.
`npm run check reference=<template path file> target=<not compressed language pack>`
```
npm run check target=languages/printerpack/lang-fr.json reference=languages/printerpack/en.json
> ESP3D-WEBUI@3.0.0 check
> node ./config/checkpack.js "target=languages/printerpack/lang-fr.json" "reference=languages/printerpack/en.json"
Comparing files
Checking extra entries...
S724 : Fermer l'application
...done, found 1 extra entries
Checking missing entries...
S14 : Settings
S24 : Close
...done, found 2 missing entries
Comparaison done
```
## Propose / update language pack files
Please do a PR to webUI 3.0 github branch or submit ticket with compressed and clear version of the language pack file
if submitting PR please keep the clear version in `languages/<target pack>` and compressed version in `dist/<target pack>`

133
Memo/realtimecmd.md Normal file
View File

@@ -0,0 +1,133 @@
# Real time commands variables
## grbl
- 0x18 (ctrl-x) : Soft-Reset : #SOFTRESET#
- 0x84 : Safety Door #SAFETYDOOR#
- 0x85 : Jog Cancel #JOGCANCEL#
Feed Overrides
- 0x90 : Set 100% of programmed rate. #FO100#
- 0x91 : Increase 10% #FO+10#
- 0x92 : Decrease 10% #FO-10#
- 0x93 : Increase 1% #FO+1#
- 0x94 : Decrease 1% #FO-1#
Rapid Overrides
- 0x95 : Set to 100% full rapid rate. #RO100#
- 0x96 : Set to 50% of rapid rate. #RO50#
- 0x97 : Set to 25% of rapid rate. #RO25#
Spindle Speed Overrides 10%->200%
- 0x99 : Set 100% of programmed spindle speed #SSO100#
- 0x9A : Increase 10% #SSO+10#
- 0x9B : Decrease 10% #SSO-10#
- 0x9C : Increase 1% #SSO+1#
- 0x9D : Decrease 1% #SSO-1#
Toggle commands
- 0x9E : Toggle Spindle Stop #T-SPINDLESTOP#
- 0xA0 : Toggle Flood Coolant #T-FLOODCOOLANT#
- 0xA1 : Toggle Mist Coolant #T-MISTCOOLANT#
```
[{name:"#SOFTRESET#", value:"\x18"},
{name:"#SAFETYDOOR#", value:"\x84"},
{name:"#JOGCANCEL#", value:"\x85"},
{name:"#FO100#", value:"\x90"},
{name:"#FO+10#", value:"\x91"},
{name:"#FO-10#", value:"\x92"},
{name:"#FO+1#", value:"\x93"},
{name:"#FO-1#", value:"\x94"},
{name:"#RO100#", value:"\x95"},
{name:"#RO50#", value:"\x96"},
{name:"#RO25#", value:"\x97"},
{name:"#SSO100#", value:"\x99"},
{name:"#SSO+10#", value:"\x9A"},
{name:"#SSO-10#", value:"\x9B"},
{name:"#SSO+1#", value:"\x9C"},
{name:"#SSO-1#", value:"\x9D"},
{name:"#T-SPINDLESTOP#", value:"\x9E"},
{name:"#T-FLOODCOOLANT#", value:"\xA0"},
{name:"#T-MISTCOOLANT#", value:"\xA1"}
]
```
## grblHAL
- 0x18 (ctrl-x) : Soft-Reset : #SOFTRESET#
- 0x80 : Instead of ? for requesting a real-time report #STATUSREPORT#
- 0x81 : Instead of ~ for requesting cycle start #CYCLESTART#
- 0x82 : Instead of ! for requesting feed hold "#FEEDHOLD#
- 0x83 : Request parser state report #PARSERREPORT#
- 0x84 : Safety Door #SAFETYDOOR#
- 0x85 : Jog Cancel #JOGCANCEL#
- 0x87 : Request a complete real-time report #COMPLETEREPORT#
- 0x88 : Toggle the virtual optional stop switch #T-STOPSWITCH#
Feed Overrides
- 0x90 : Set 100% of programmed rate. #FO100#
- 0x91 : Increase 10% #FO+10#
- 0x92 : Decrease 10% #FO-10#
- 0x93 : Increase 1% #FO+1#
- 0x94 : Decrease 1% #FO-1#
Rapid Overrides
- 0x95 : Set to 100% full rapid rate. #RO100#
- 0x96 : Set to 50% of rapid rate. #RO50#
- 0x97 : Set to 25% of rapid rate. #RO25#
Spindle Speed Overrides 10%->200%
- 0x99 : Set 100% of programmed spindle speed #SSO100#
- 0x9A : Increase 10% #SSO+10#
- 0x9B : Decrease 10% #SSO-10#
- 0x9C : Increase 1% #SSO+1#
- 0x9D : Decrease 1% #SSO-1#
Toggles and extras
- 0x9E : Toggle Spindle Stop #T-SPINDLESTOP#
- 0xA0 : Toggle Flood Coolant #T-FLOODCOOLANT#
- 0xA1 : Toggle Mist Coolant #T-MISTCOOLANT#
- 0xA2 : Request a PID report #PIDREPORT#
- 0xA3 : Acknowledge a tool change request #TOOLCHANGE#
- 0xA4 : Toggle the virtual optional probe connected switch #T-PROBE#
```
{ name: "#SOFTRESET#", value: "\x18" },
{ name: "#STATUSREPORT#", value: "\x80"},
{ name: "#CYCLESTART#", value: "\x81" },
{ name: "#FEEDHOLD#", value: "\x82" },
{ name: "#PARSERREPORT#", value: "\x83" },
{ name: "#SAFETYDOOR#", value: "\x84" },
{ name: "#JOGCANCEL#", value: "\x85" },
{ name: "#COMPLETEREPORT#", value: "\x87" },
{ name: "#T-STOPSWITCH#", value: "\x88" },
{ name: "#FO100#", value: "\x90" },
{ name: "#FO+10#", value: "\x91" },
{ name: "#FO-10#", value: "\x92" },
{ name: "#FO+1#", value: "\x93" },
{ name: "#FO-1#", value: "\x94" },
{ name: "#RO100#", value: "\x95" },
{ name: "#RO50#", value: "\x96" },
{ name: "#RO25#", value: "\x97" },
{ name: "#SSO100#", value: "\x99" },
{ name: "#SSO+10#", value: "\x9A" },
{ name: "#SSO-10#", value: "\x9B" },
{ name: "#SSO+1#", value: "\x9C" },
{ name: "#SSO-1#", value: "\x9D" },
{ name: "#T-SPINDLESTOP#", value: "\x9E" },
{ name: "#T-FLOODCOOLANT#", value: "\xA0" },
{ name: "#T-MISTCOOLANT#", value: "\xA1" },
{ name: "#PIDREPORT#", value: "\xA2" },
{ name: "#TOOLCHANGE#", value: "\xA3" },
{ name: "#T-PROBE#", value: "\xA4" },
];
```

23
Memo/variablesList.md Normal file
View File

@@ -0,0 +1,23 @@
# Variables list
- From output:
- [PRB:0.000,0.000,0.000:0]
#prb_x#, #prb_y#,#prb_z#
optional according axis definition #prb_a#,#prb_b#,#prb_c#
- from ? report MPos:0.000,0.000,0.000,0.000,0.000,0.000
#pos_x#, #pos_y#, #pos_z#, #pos_a#, #pos_b#, #pos_c#,
#pos_wx#, #pos_wy#, #pos_wz#, #pos_wa#, #pos_wb#, #pos_wc#,
optional according axis definition #pos_u#,#pos_v#,#pos_w#, #pos_wu#,#pos_wv#,#pos_ww#
Note: if variable is unknown, then it is set to `0`
- From UI
- Probe Panel
Probe thickness : #probe_thickness#
Selected axis : #selected_axis#
- Laser CNC Panel
Maximum value of laser: #laser_max#

68
Memo/websocket.md Normal file
View File

@@ -0,0 +1,68 @@
# Websocket
there are 2
- terminal websocket
used to stream data to webUIand exchange internal data
- data websocket
used to exchange data
## Terminal websocket
subprotocol: `webui-v3`
port: webport number + 1
### <u>text mode</u>
Reserved
messages between webui / ESP
Format: `<label>:<message>`
- from ESP to WebUI
- `currentID:<id>`
Sent when client is connecting, it is the last ID used and become the active ID
- `activeID:<id>`
Broadcast current active ID, when new client is connecting, client without this is <id> should close, ESP WS Server close all open WS connections but this one also
- `PING:<time left>:<time out>`
It is a response to PING from client to inform the time left if no activity (see below)
- `ERROR:<code>:<message>`
If an error raise when doing upload, it informs client it must stop uploading because sometimes the http answer is not possible,
or cannot cancel the upload, this is a workaround as there is no API in current webserver to cancel active upload
- `NOTIFICATION:<message>`
Forward the message sent by [ESP600] to webUI toast system
- `SENSOR: <value>[<unit>] <value2>[<unit2>] ...`
The sensor connected to ESP like DHT22
- from WebUI to ESP
- `PING:<current cookiesessionID / none >` if any, or "none" if none
### <u>binary mode</u>
Reserved
- from ESP to WebUI
stream data from ESP to WebUI
- from WEBUI to ESP
[-> File transfert from WebUI to ESP : not implemented yet]
## Data websocket
protocol: `arduino`
port: configurable in settings
### <u>text mode</u>
Free to use
### <u>binary mode</u>
Free to use

16
Notes.txt Normal file
View File

@@ -0,0 +1,16 @@
* Fix dev websocket server cannot work under Linux
> sudo apt-get install libcap2-bin
> sudo setcap cap_net_bind_service=+ep `readlink -f \`which node\``
* Fix and “ need space to be displayed under Linux
> setxkbmap -layout us
* Fix for sass div warning
>npm install -g sass-migrator
>sass-migrator division **/*.scss
Note:
on windows need change script policy first:
> Get-ExecutionPolicy -List
>Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
then when done, put back default (the one got by initial Get-ExecutionPolicy -List)
>Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope CurrentUser

183
README.md
View File

@@ -1,161 +1,70 @@
# ESP3D-WEBUI [<img src="https://img.shields.io/liberapay/patrons/ESP3D.svg?logo=liberapay">](https://liberapay.com/ESP3D)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-28-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
# ESP3D-WEBUI 3.0
[Latest stable release ![Release Version](https://img.shields.io/github/v/release/luc-github/ESP3D-WEBUI?color=green&include_prereleases&style=plastic) ![Release Date](https://img.shields.io/github/release-date/luc-github/ESP3D-WEBUI.svg?style=plastic)](https://github.com/luc-github/ESP3D-WEBUI/releases/latest/) [![Travis (.org) branch](https://img.shields.io/travis/luc-github/ESP3D-WEBUI/2.1?style=plastic)](https://travis-ci.org/github/luc-github/ESP3D-WEBUI)
using Preact per @aganov suggestion
Rewrite per @alxblog suggestion to use proper Preactjs API and lighter code: use spectre.css instead of bootstrap 4.x
[Latest development version ![Development Version](https://img.shields.io/badge/Devt-v3.0-yellow?style=plastic) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/luc-github/ESP3D-WEBUI/3.0?style=plastic)](https://github.com/luc-github/ESP3D-WEBUI/tree/3.0) [![Travis (.org) branch](https://img.shields.io/travis/luc-github/ESP3D-WEBUI/3.0?style=plastic)](https://travis-ci.org/github/luc-github/ESP3D-WEBUI) [![Project Page ESP3D 3.0](https://img.shields.io/badge/Project%20page-ESP3D%203.0-blue?style=plastic)](https://github.com/users/luc-github/projects/1/views/1)
[Project board](https://github.com/users/luc-github/projects/1/views/1)
## In development / alpha stage / Ready to test
## What is that ?
A web configuration tool for ESP3D 2.1
Originaly based on great UI from Jarek Szczepanski (imrahil): [smoothieware-webui](http://imrahil.github.io/smoothieware-webui/) to get a multi firmware support for [Repetier](https://github.com/repetier/Repetier-Firmware), [Repetier for Davinci printer](https://github.com/luc-github/Repetier-Firmware-0.92), (Marlin)[https://github.com/MarlinFirmware], [Marlin Kimbra](https://github.com/MagoKimbra/MarlinKimbra) and of course [Smoothieware](https://github.com/Smoothieware/Smoothieware)
Only compatible with [ESP3DLib 3.0](https://github.com/luc-github/ESP3DLib/tree/3.0) , [ESP3D 3.0](https://github.com/luc-github/ESP3D/tree/3.0), [grblHAL](https://github.com/grblHAL)
## Why doing it ?
Original I ported [smoothieware-webui](http://imrahil.github.io/smoothieware-webui/) to support [ESP3D firmware](https://github.com/luc-github/ESP3D) and it was working pretty well and gave :[smoothieware-webui-for-ESP3D](https://github.com/luc-github/smoothieware-webui-for-ESP3D)
But this UI has a 2 big limitations:
1 - you need internet access to get all libraries available to download, which may not happen when ESP is in AP mode for configuration if you do not have all js/css in your browser cache, or if you want to use in local environement, in that case not only ESP AP mode is not displaying UI properly but also STA mode - so it make the ESP useless
[Latest development version ![Development Version](https://img.shields.io/badge/Devt-v3.0-yellow?style=plastic)](https://github.com/luc-github/ESP3D-WEBUI/tree/3.0) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/luc-github/ESP3D-WEBUI/3.0?style=plastic) [![Travis (.org) branch](https://img.shields.io/travis/luc-github/ESP3D-WEBUI/3.0?style=plastic)](https://travis-ci.org/github/luc-github/ESP3D-WEBUI) [![Project Page ESP3D 3.0](https://img.shields.io/badge/Project%20page-ESP3D%203.0-blue?style=plastic)](https://github.com/users/luc-github/projects/1/views/1)
2 - it rely on server availability and certificat check, I got several certificat failure for unknown reason that made the UI not working
### Setup development tools
So the solution was to make all resources available - easy no ?
1 - Install current nodejs LTS (currently using v16.14.2)
Yes but! ESP webserver is a convenient but it is also a very light webserver, allowing no more than 5 active connections at once and with a pretty limited filesystem space, so even concatenated all resources like bootstrap icon, angular and others libraries do not work as expected and do not fit the available space.
```
node -v
v16.14.2
So I came with a full rewrite using pure javascript and resized resources:
1 - a compressed css based on [bootstrap](http://getbootstrap.com/css/)
2 - a local limited version of svg based of [Glyphicons Halflings](http://glyphicons.com/) to get a small footprint.
3 - a customized version of [smoothiecharts](http://smoothiecharts.org/) is used to display temperatures charts, it is simple and perfectly sized for the current purpose
npm -v
8.5.0
```
The result is a monolitic file with a minimal size allowing almost full control of ESP3D board and your 3D printer
2 - Download all necessary packages in ESP3D-WEBUI directory (repository root)
## Sponsors
[<img width="200px" src="https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/2.1/images/sponsors-supporters/MKS/mksmakerbase.jpg" title="MKS Makerbase">](https://github.com/makerbase-mks)&nbsp;&nbsp;
```
npm install
```
## Supporters
### Start dev server
in ESP3D-WEBUI directory (repository root)
## Become a sponsor or a supporter
* A sponsor is a recurent donator
If your tier is `10 US$/month` or more, to thank you for your support, your logo / avatar will be added to the readme page with eventually with a link to your site.
* A supporter is per time donator
If your donation is over `120 US$` per year, to thank you for your support, your logo / avatar will be added to the readme page with eventually with a link to your site.
```
npm run dev-<system>-<firmware>
```
Every support is welcome, indeed helping users / developing new features need time and devices, donations contribute a lot to make things happen, thank you.
- where `<system>` is `cnc` (CNC system, laser, spindle..) , `printer` (3D printer), `sand` (Sand Table)
- where `<firmware>` is :
- `grbl`, `grblhal` for `cnc`
- `marlin`, `marlin-embedded` (esp3dlib), `repetier`, `smoothieware` for `printer`
- `grbl` for `sand`
* liberapay <a href="https://liberapay.com/ESP3D/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
* Paypal [<img src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG_global.gif" border="0" alt="PayPal The safer, easier way to pay online.">](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FQL59C749A78L)
* ko-fi [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G0C0QT7)
will open http://localhost:8088 which display the webUI using a local test server
## Features
- It supports several firmwares based on Repetier, Marlin, Smoothieware and GRBL.
- It allows to fully configure ESP wifi
- It has a macro support to add custom commands in UI by adding buttons launching some GCODE files from SD or ESP
- It supports several languages, check list [here](https://github.com/luc-github/ESP3D-WEBUI/wiki/Translation-support)
- It allows to display a web camera in UI or detached
- It allows to edit the Repetier EEPROM, Smoothieware config file, Marlin and GRBL settings
- It allows to update the ESP3D by uploading the FW
- it allows to control and monitor your 3D printer in every aspect (position, temperature, print, SD card content, custom command
### Build index.html.gz to /dist folder
Please look at screenshots:
Main tab and menu:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/Full1.PNG'/>
Control panel:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/controls.PNG'/>
Macro dialog:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/Macro.PNG'/>
Temperatures panel:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/temperatures.PNG'/>
Extruder panel:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/esxtruders.PNG'/>
SD card panel:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/SD1.PNG'/>
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/SD1.5.PNG'/>
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/SD2.PNG'/>
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/SD-Dir.PNG'/>
Camera Tab:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/Camera.PNG'/>
Repetier EEPROM Editor tab:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/Repetier.PNG'/>
Smoothieware config Editor tab:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/smoothieware.PNG'/>
Marlin config Editor tab:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/Marlin.PNG'/>
GRBL config Editor tab:
<img src='https://user-images.githubusercontent.com/8822552/37540735-60bada08-2958-11e8-92ee-69aee4b83e7a.png'/>
ESP3D settings Editor:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/ESP3D1.PNG'/>
ESP3D Status:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/status.PNG'/>
ESP3D SPIFFS:
<img src='https://raw.githubusercontent.com/luc-github/ESP3D-WEBUI/master/images/SPIFFS.PNG'/>
in ESP3D-WEBUI directory (repository root)
```
npm run buildall
```
## Installation
Please use the latest [ESP3D firmware](https://github.com/luc-github/ESP3D/tree/2.1.x) and copy the index.html.gz file on root of SPIFFS, in theory ESP3D have a version of web-ui but it may not be the latest one
Will generate production version for each target and firmware in dist directory
## Contribution / development
Check wiki section [Contribution/Development](https://github.com/luc-github/ESP3D-WEBUI/wiki/Compilation---Development)
to build specific index.html.gz
## Issues / Questions
You can submit ticket [here](https://github.com/luc-github/ESP3D-WEBUI/issues) or open discussion if it is not an issue [here](https://github.com/luc-github/ESP3D-WEBUI/discussions) or Join the chat at [![Discord server](https://img.shields.io/discord/752822148795596940?color=blue&label=discord&logo=discord)](https://discord.gg/Z4ujTwE)
```
npm run <system>-<firmware>
```
- where `<system>` is `cnc` (CNC system, laser, spindle..) , `printer` (3D printer), `sand` (Sand Table)
- where `<firmware>` is :
- `grbl`, `grblhal` for `cnc`
- `marlin`, `marlin-embedded` (esp3dlib), `repetier`, `smoothieware` for `printer`
- `grbl` for `sand`
# Chat
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alxblog"><img src="https://avatars.githubusercontent.com/u/3979539?v=4?s=100" width="100px;" alt=" Alexandre "/><br /><sub><b> Alexandre </b></sub></a><br /><a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=alxblog" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MonoAnji"><img src="https://avatars.githubusercontent.com/u/16881074?v=4?s=100" width="100px;" alt="René Pasold"/><br /><sub><b>René Pasold</b></sub></a><br /><a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=MonoAnji" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronse"><img src="https://avatars.githubusercontent.com/u/16479976?v=4?s=100" width="100px;" alt="aaron GitHub"/><br /><sub><b>aaron GitHub</b></sub></a><br /><a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=aaronse" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Pavulon87"><img src="https://avatars.githubusercontent.com/u/23641103?v=4?s=100" width="100px;" alt="Pavulon87"/><br /><sub><b>Pavulon87</b></sub></a><br /><a href="https://github.com/luc-github/ESP3D-WEBUI/issues?q=author%3APavulon87" title="Bug reports">🐛</a> <a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=Pavulon87" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://honuputters.com"><img src="https://avatars.githubusercontent.com/u/4861133?v=4?s=100" width="100px;" alt="Mitch Bradley"/><br /><sub><b>Mitch Bradley</b></sub></a><br /><a href="#ideas-MitchBradley" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=MitchBradley" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.facebook.com/Patricecotemusique/"><img src="https://avatars.githubusercontent.com/u/29361809?v=4?s=100" width="100px;" alt="Patrice Côté"/><br /><sub><b>Patrice Côté</b></sub></a><br /><a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=cotepat" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://engineer2designer.blogspot.com"><img src="https://avatars.githubusercontent.com/u/25747949?v=4?s=100" width="100px;" alt="E2D"/><br /><sub><b>E2D</b></sub></a><br /><a href="#translation-Engineer2Designer" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="http://cedrik-theesen.de"><img src="https://avatars.githubusercontent.com/u/24916321?v=4?s=100" width="100px;" alt="Cedrik Theesen"/><br /><sub><b>Cedrik Theesen</b></sub></a><br /><a href="#translation-duramson" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/royfocker19"><img src="https://avatars.githubusercontent.com/u/39307144?v=4?s=100" width="100px;" alt="royfocker19"/><br /><sub><b>royfocker19</b></sub></a><br /><a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=royfocker19" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BToersche"><img src="https://avatars.githubusercontent.com/u/16536432?v=4?s=100" width="100px;" alt="Bart Toersche"/><br /><sub><b>Bart Toersche</b></sub></a><br /><a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=BToersche" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vivian-ng"><img src="https://avatars.githubusercontent.com/u/24537694?v=4?s=100" width="100px;" alt="vivian-ng"/><br /><sub><b>vivian-ng</b></sub></a><br /><a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=vivian-ng" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/drzejkopf"><img src="https://avatars.githubusercontent.com/u/41212609?v=4?s=100" width="100px;" alt="drzejkopf"/><br /><sub><b>drzejkopf</b></sub></a><br /><a href="#translation-drzejkopf" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.gtmax.com.br"><img src="https://avatars.githubusercontent.com/u/6072702?v=4?s=100" width="100px;" alt="Luciano Charles Moda"/><br /><sub><b>Luciano Charles Moda</b></sub></a><br /><a href="#translation-lucmoda" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://youprintin3d.de"><img src="https://avatars.githubusercontent.com/u/8026764?v=4?s=100" width="100px;" alt="AxelB"/><br /><sub><b>AxelB</b></sub></a><br /><a href="#translation-leseaw" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Zefram88"><img src="https://avatars.githubusercontent.com/u/40454706?v=4?s=100" width="100px;" alt="Zefram88"/><br /><sub><b>Zefram88</b></sub></a><br /><a href="#translation-Zefram88" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/3d-gussner"><img src="https://avatars.githubusercontent.com/u/25530011?v=4?s=100" width="100px;" alt="3d-gussner"/><br /><sub><b>3d-gussner</b></sub></a><br /><a href="#translation-3d-gussner" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://aganov.github.io"><img src="https://avatars.githubusercontent.com/u/176610?v=4?s=100" width="100px;" alt="Alex Ganov"/><br /><sub><b>Alex Ganov</b></sub></a><br /><a href="#ideas-aganov" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=aganov" title="Code">💻</a> <a href="#mentoring-aganov" title="Mentoring">🧑‍🏫</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bdring"><img src="https://avatars.githubusercontent.com/u/189677?v=4?s=100" width="100px;" alt="bdring"/><br /><sub><b>bdring</b></sub></a><br /><a href="#financial-bdring" title="Financial">💵</a> <a href="https://github.com/luc-github/ESP3D-WEBUI/issues?q=author%3Abdring" title="Bug reports">🐛</a> <a href="#platform-bdring" title="Packaging/porting to new platform">📦</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ArturNadolski"><img src="https://avatars.githubusercontent.com/u/20038314?v=4?s=100" width="100px;" alt="n4d01"/><br /><sub><b>n4d01</b></sub></a><br /><a href="#translation-ArturNadolski" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.civade.com"><img src="https://avatars.githubusercontent.com/u/2135006?v=4?s=100" width="100px;" alt="Jean-Philippe CIVADE"/><br /><sub><b>Jean-Philippe CIVADE</b></sub></a><br /><a href="#translation-ewidance" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kondorzs"><img src="https://avatars.githubusercontent.com/u/15940476?v=4?s=100" width="100px;" alt="kondorzs"/><br /><sub><b>kondorzs</b></sub></a><br /><a href="#translation-kondorzs" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/onekk"><img src="https://avatars.githubusercontent.com/u/7129964?v=4?s=100" width="100px;" alt="Carlo"/><br /><sub><b>Carlo</b></sub></a><br /><a href="#translation-onekk" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zrwd01"><img src="https://avatars.githubusercontent.com/u/33946060?v=4?s=100" width="100px;" alt="zrwd01"/><br /><sub><b>zrwd01</b></sub></a><br /><a href="#translation-zrwd01" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Wesie"><img src="https://avatars.githubusercontent.com/u/9315139?v=4?s=100" width="100px;" alt="Wesie"/><br /><sub><b>Wesie</b></sub></a><br /><a href="#translation-Wesie" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DusDus"><img src="https://avatars.githubusercontent.com/u/69902032?v=4?s=100" width="100px;" alt="DusDus"/><br /><sub><b>DusDus</b></sub></a><br /><a href="#translation-DusDus" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nyarurato"><img src="https://avatars.githubusercontent.com/u/8384007?v=4?s=100" width="100px;" alt="nyarurato"/><br /><sub><b>nyarurato</b></sub></a><br /><a href="#translation-nyarurato" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/terjeio"><img src="https://avatars.githubusercontent.com/u/20260062?v=4?s=100" width="100px;" alt="Terje Io"/><br /><sub><b>Terje Io</b></sub></a><br /><a href="#ideas-terjeio" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/luc-github/ESP3D-WEBUI/commits?author=terjeio" title="Code">💻</a> <a href="#translation-terjeio" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.v1engineering.com/"><img src="https://avatars.githubusercontent.com/u/55478432?v=4?s=100" width="100px;" alt="Ryan V1"/><br /><sub><b>Ryan V1</b></sub></a><br /><a href="#financial-V1EngineeringInc" title="Financial">💵</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
ESP3D is now on discord https://discord.gg/Z4ujTwE

View File

@@ -1,4 +0,0 @@
cd %~dp0
cmd.exe /c npm install
cmd.exe /c gulp package
pause

View File

@@ -1,52 +0,0 @@
cd %~dp0
cmd.exe /c npm install
rmdir /Q /S languages
mkdir languages\en
cmd.exe /c gulp package --lang en
copy index.html.gz languages\en
mkdir languages\fr
cmd.exe /c gulp package --lang fr
copy index.html.gz languages\fr
mkdir languages\es
cmd.exe /c gulp package --lang es
copy index.html.gz languages\es
mkdir languages\it
cmd.exe /c gulp package --lang it
copy index.html.gz languages\it
mkdir languages\ja
cmd.exe /c gulp package --lang ja
copy index.html.gz languages\ja
mkdir languages\hu
cmd.exe /c gulp package --lang hu
copy index.html.gz languages\hu
mkdir languages\de
cmd.exe /c gulp package --lang de
copy index.html.gz languages\de
mkdir languages\pl
cmd.exe /c gulp package --lang pl
copy index.html.gz languages\pl
mkdir languages\ptbr
cmd.exe /c gulp package --lang ptbr
copy index.html.gz languages\ptbr
mkdir languages\ru
cmd.exe /c gulp package --lang ru
copy index.html.gz languages\ru
mkdir languages\tr
cmd.exe /c gulp package --lang tr
copy index.html.gz languages\tr
mkdir languages\zh_CN
cmd.exe /c gulp package --lang zh_CN
copy index.html.gz languages\zh_CN
mkdir languages\zh_TW
cmd.exe /c gulp package --lang zh_TW
copy index.html.gz languages\zh_TW
mkdir languages\uk
cmd.exe /c gulp package --lang uk
copy index.html.gz languages\uk
mkdir languages\grbl
cmd.exe /c gulp package --lang uk
copy index.html.gz languages\grbl
cmd.exe /c gulp package
mkdir languages\multi
copy index.html.gz languages\multi
pause

View File

@@ -1,52 +0,0 @@
cd "$(dirname "$0")"
npm install
rm -fr languages
mkdir -p languages/en
gulp package --lang en
cp index.html.gz languages/en
mkdir -p languages/fr
gulp package --lang fr
cp index.html.gz languages/fr
mkdir -p languages/es
gulp package --lang es
cp index.html.gz languages/es
mkdir -p languages/it
gulp package --lang it
cp index.html.gz languages/it
mkdir -p languages/ja
gulp package --lang ja
cp index.html.gz languages/ja
mkdir -p languages/hu
gulp package --lang hu
cp index.html.gz languages/hu
mkdir -p languages/de
gulp package --lang de
cp index.html.gz languages/de
mkdir -p languages/pl
gulp package --lang pl
cp index.html.gz languages/pl
mkdir -p languages/ptbr
gulp package --lang ptbr
cp index.html.gz languages/ptbr
mkdir -p languages/ru
gulp package --lang ru
cp index.html.gz languages/ru
mkdir -p languages/tr
gulp package --lang tr
cp index.html.gz languages/tr
mkdir -p languages/zh_CN
gulp package --lang zh_CN
cp index.html.gz languages/zh_CN
mkdir -p languages/zh_TW
gulp package --lang zh_TW
cp index.html.gz languages/zh_TW
mkdir -p languages/uk
gulp package --lang uk
cp index.html.gz languages/uk
mkdir -p languages/grbl
gulp package --lang uk
cp index.html.gz languages/grbl
gulp package
mkdir -p languages/multi
cp index.html.gz languages/multi
read -p "Press any key to close ..."

135
config/buildtemplate.js Normal file
View File

@@ -0,0 +1,135 @@
/*
buildtemplate.js - ESP3D WebUI package file
Copyright (c) 2021 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require("chalk")
const path = require("path")
const fs = require("fs")
const { Console } = require("console")
const targetPath = path.normalize(__dirname + "/../languages/")
const readable = true // process.argv.length == 3 && process.argv[2] == "readable" ? true : false
const cncgrblpack = [
{ id: "globals", path: "src/targets/translations/en.json" },
{
id: "CNC",
path: "src/targets/CNC/translations/en.json",
},
{
id: "GRBL",
path: "src/targets/CNC/GRBL/translations/en.json",
},
]
const cncgrblhalpack = [
{ id: "globals", path: "src/targets/translations/en.json" },
{
id: "CNC",
path: "src/targets/CNC/translations/en.json",
},
{
id: "grblHAL",
path: "src/targets/CNC/grblHAL/translations/en.json",
},
]
const printerpack = [
{ id: "globals", path: "src/targets/translations/en.json" },
{
id: "printers3D",
path: "src/targets/Printer3D/translations/en.json",
},
{
id: "Marlin",
path: "src/targets/Printer3D/Marlin/translations/en.json",
},
{
id: "Marlin-embedded",
path: "src/targets/Printer3D/Marlin-embedded/translations/en.json",
},
{
id: "Repetier",
path: "src/targets/Printer3D/Repetier/translations/en.json",
},
{
id: "Smoothieware",
path: "src/targets/Printer3D/Smoothieware/translations/en.json",
},
]
const sandtablepack = [
{ id: "globals", path: "src/targets/translations/en.json" },
{
id: "SandTable",
path: "src/targets/SandTable/translations/en.json",
},
{
id: "GRBL",
path: "src/targets/SandTable/GRBL/translations/en.json",
},
]
const processList = [
{ targetPath: "cncgrblpack", files: cncgrblpack },
{ targetPath: "cncgrblhalpack", files: cncgrblhalpack },
{ targetPath: "printerpack", files: printerpack },
{ targetPath: "sandtablepack", files: sandtablepack },
]
if (readable) console.log(chalk.green("Processing in readable mode"))
else console.log(chalk.green("Processing in production mode"))
processList.map((element) => {
let resultfile = {}
const finalFilePath = path.join(targetPath, element.targetPath)
console.log(chalk.green("Starting to merge:", element.targetPath))
element.files.forEach((item) => {
console.log(chalk.green("Processing:", item.id))
const sourcepath = path.normalize(__dirname + "/../" + item.path)
const file = fs.readFileSync(sourcepath, "UTF-8")
const currentFile = JSON.parse(file.toString())
Object.keys(currentFile).map((key) => {
if (!resultfile[key] && typeof currentFile[key] != "undefined") {
resultfile[key] = currentFile[key]
} else {
if (resultfile[key] != currentFile[key]) {
console.log(chalk.red("In " + sourcepath))
console.log(
chalk.red(
key,
":" + currentFile[key] + " vs " + resultfile[key]
)
)
} else {
console.log(
chalk.yellow(
"Ignoring duplicate: " + key,
"=" + currentFile[key]
)
)
}
}
})
})
fs.mkdirSync(finalFilePath, { recursive: true })
console.log(
chalk.green("Saving result to :" + path.join(finalFilePath, "en.json"))
)
fs.writeFileSync(
path.join(finalFilePath, "en.json"),
JSON.stringify(resultfile, "", readable ? " " : ""),
"UTF-8"
)
})
console.log(chalk.green("Processing done"))

108
config/checkpack.js Normal file
View File

@@ -0,0 +1,108 @@
/*
chekpack.js - ESP3D WebUI package file
Copyright (c) 2021 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require("chalk")
const path = require("path")
const fs = require("fs")
const { exit } = require("process")
//const targetPath = path.normalize(__dirname + "/../languages/")
let referencePath = ""
let targetPath = ""
function raiseError() {
console.log(chalk.red("Invalid parameters, please use:"))
console.log(
chalk.yellow(
"npm run check reference=<template path file> target=<not compressed language pack>"
)
)
exit(0)
}
if (process.argv.length == 4) {
if (process.argv[2].startsWith("reference=")) {
referencePath = process.argv[2].replace("reference=", "")
}
if (process.argv[2].startsWith("target=")) {
targetPath = process.argv[2].replace("target=", "")
}
if (process.argv[3].startsWith("reference=")) {
referencePath = process.argv[3].replace("reference=", "")
}
if (process.argv[3].startsWith("target=")) {
targetPath = process.argv[3].replace("target=", "")
}
if (referencePath.length == 0 || targetPath == 0) {
raiseError()
}
} else {
raiseError()
}
let count = 0
const referenceFile = path.join(
path.normalize(__dirname + "/../"),
referencePath
)
const targetFile = path.join(path.normalize(__dirname + "/../"), targetPath)
if (!fs.existsSync(referenceFile)) {
console.log(chalk.red("Cannot open:"))
console.log(chalk.yellow(referenceFile))
exit(0)
}
if (!fs.existsSync(targetFile)) {
console.log(chalk.red("Cannot open:"))
console.log(chalk.yellow(targetFile))
exit(0)
}
console.log(chalk.cyan("Comparing files"))
const fileTarget = JSON.parse(fs.readFileSync(targetFile, "UTF-8").toString())
const fileReference = JSON.parse(
fs.readFileSync(referenceFile, "UTF-8").toString()
)
console.log("")
console.log(chalk.green("Checking extra entries..."))
Object.keys(fileTarget).map((key) => {
if (typeof fileReference[key] == "undefined") {
console.log(chalk.yellow(key + " : " + fileTarget[key]))
count++
}
})
console.log(
chalk.green(
"...done, found ",
count ? chalk.yellow(count + " extra entries") : ""
)
)
count = 0
console.log("")
console.log(chalk.green("Checking missing entries..."))
Object.keys(fileReference).map((key) => {
if (typeof fileTarget[key] == "undefined") {
count++
console.log(chalk.red(key + " : " + fileReference[key]))
}
})
console.log(
chalk.green(
"...done, found ",
count ? chalk.red(count + " missing entries") : ""
)
)
console.log("")
console.log(chalk.cyan("Comparaison done"))

89
config/pack.js Normal file
View File

@@ -0,0 +1,89 @@
/*
package.js - ESP3D WebUI package file
Copyright (c) 2021 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require("chalk")
const path = require("path")
const fs = require("fs")
const { Compress } = require("gzipper")
const minify = require("html-minifier").minify
const { exit } = require("process")
console.log(chalk.cyan("Running Package 1.0"))
//Sanity check for command line
const arg = process.argv[process.argv.length > 1 ? 2 : 0]
if (process.argv.length < 3 || !arg.startsWith("target=")) {
console.log(
chalk.red(
"Error!\nSyntax: npm run package target=<relative path to file>"
)
)
exit(0)
}
//Sanity check for file creation
const sourcepath = path.normalize(
__dirname + "/../" + arg.replace("target=", "")
)
console.log("Checking ", sourcepath)
const sourcedir = path.dirname(sourcepath)
if (!fs.existsSync(sourcepath)) {
console.log(chalk.red("Error!\nCannot find file"))
exit(0)
}
//Start minify
console.log(chalk.green("Processing"))
const source = fs.readFileSync(sourcepath, "UTF-8")
const result = minify(source, {
removeComments: true,
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true,
})
const minifiedFile = sourcepath + ".minified.html"
fs.writeFileSync(minifiedFile, result)
//Compress minified file
const compressedDir = sourcepath
console.log(
chalk.blue(
"Minify: " + source.length + " Bytes => ",
result.length,
"Bytes"
)
)
//it seems it is ok for css but json is not really minimified
//space are still present => Need to fix that
let gzipper = new Compress(minifiedFile, sourcedir, { verbose: true })
gzipper
.run()
.then((files) => {
//remove temp minified file
fs.unlinkSync(minifiedFile)
//rename compressed file to match original filename
fs.renameSync(minifiedFile + ".gz", sourcepath + ".gz")
const finalSize = fs.lstatSync(sourcepath + ".gz").size
//Show report
console.log(
chalk.green(
"\n\nMinify + Compression: ",
source.length,
"Bytes =>",
finalSize,
"Bytes = compression ",
(100 - 100 * (finalSize / source.length)).toFixed(2),
"%\n"
)
)
})
.catch((err) => console.error(err))

324
config/server.js Normal file
View File

@@ -0,0 +1,324 @@
const express = require("express")
const expressStaticGzip = require("express-static-gzip")
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 sensorInterval = -1
//const serverpath = path.normalize(__dirname + "/../server/public/");
const subtarget = process.env.SUBTARGET_ENV
? process.env.SUBTARGET_ENV
: "Marlin"
const target = process.env.TARGET_ENV ? process.env.TARGET_ENV : "Printer3D"
const serverpath =
path.normalize(__dirname + "/../server/" + target + "/" + subtarget) + "/"
if (!fs.existsSync(serverpath + "Flash")) {
fs.mkdirSync(serverpath + "Flash", { recursive: true })
}
if (!fs.existsSync(serverpath + "SD")) {
fs.mkdirSync(serverpath + "SD", { recursive: true })
}
const {
commandsQuery,
configURI,
getLastconnection,
hasEnabledAuthentication,
} = require(path.normalize(
__dirname + "/targets/" + target + "/" + subtarget + "/index.js"
))
const WebSocketServer = require("ws").Server,
wss = new WebSocketServer({ port: 8089 })
app.use("/", express.static(serverpath + "Flash"))
app.use("/sd", express.static(serverpath + "sd"))
app.use("/", expressStaticGzip(serverpath + "Flash"))
app.use(fileUpload({ preserveExtension: true, debug: false }))
app.listen(port, () => console.log("Env:", subtarget, ":", target))
app.timeout = 2000
//app.use(express.urlencoded({ extended: false }));
function SendWS(text, isbinary = true, isNotification = true) {
if (typeof isbinary === "undefined") isbinary = true
if (isbinary) {
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)
}
})
} else {
const notif = (isNotification ? "NOTIFICATION:" : "") + text
console.log(wscolor("[ws] send:", notif))
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(notif)
}
})
}
}
app.post("/login", function (req, res) {
loginURI(req, res)
})
app.get("/config", function (req, res) {
configURI(req, res)
})
app.get("/command", function (req, res) {
commandsQuery(req, res, SendWS)
})
/*app.get("/sdfiles", function (req, res) {
res.status(200);
res.send(
'{"files":[{"name":"LOST.DIR","shortname":"LOST.DIR","size":"-1"},{"name":".android_secure","shortname":"ANDROI~1","size":"-1"},{"name":"app","shortname":"APP","size":"-1"},{"name":"framework","shortname":"FRAMEW~1","size":"-1"},{"name":"lib","shortname":"LIB","size":"-1"},{"name":"permissions","shortname":"PERMIS~1","size":"-1"},{"name":".Trash-1000","shortname":"TRASH-~1","size":"-1"},{"name":".FileExpert","shortname":"FILEEX~1","size":"-1"},{"name":"download","shortname":"DOWNLOAD","size":"-1"},{"name":"Android","shortname":"ANDROID","size":"-1"},{"name":".mmsyscache","shortname":"MMSYSC~1","size":"-1"},{"name":"clockworkmod","shortname":"CLOCKW~1","size":"-1"},{"name":"Evernote","shortname":"EVERNOTE","size":"-1"},{"name":"data","shortname":"DATA","size":"-1"},{"name":".estrongs","shortname":"ESTRON~1","size":"-1"},{"name":"DCIM","shortname":"DCIM","size":"-1"},{"name":"backups","shortname":"BACKUPS","size":"-1"},{"name":".zdworks","shortname":"ZDWORK~1","size":"-1"},{"name":"toolbox-stericson","shortname":"TOOLBO~1","size":"75.54 KB"},{"name":"SystemROMToolbox","shortname":"SYSTEM~1","size":"-1"},{"name":"busybox-stericson","shortname":"BUSYBO~1","size":"843.20 KB"},{"name":"recovery.img","shortname":"RECOVERY.IMG","size":"6.00 MB"},{"name":"preloader.img","shortname":"PRELOA~1.IMG","size":"128.00 KB"},{"name":"nvram.img","shortname":"NVRAM.IMG","size":"3.00 MB"},{"name":"seccnfg.img","shortname":"SECCNFG.IMG","size":"128.00 KB"},{"name":"uboot.img","shortname":"UBOOT.IMG","size":"384.00 KB"},{"name":"boot.img","shortname":"BOOT.IMG","size":"6.00 MB"},{"name":"secstatic.img","shortname":"SECSTA~1.IMG","size":"1.12 MB"},{"name":"system.img","shortname":"SYSTEM.IMG","size":"170.00 MB"},{"name":"misc.img","shortname":"MISC.IMG","size":"384.00 KB"},{"name":"cache.img","shortname":"CACHE.IMG","size":"60.00 MB"},{"name":"logo.img","shortname":"LOGO.IMG","size":"3.00 MB"},{"name":"expdb.img","shortname":"EXPDB.IMG","size":"640.00 KB"},{"name":"userdata.img","shortname":"USERDATA.IMG","size":"261.25 MB"},{"name":"recovery2.img","shortname":"RECOVE~1.IMG","size":"6.00 MB"},{"name":"touchrec.img","shortname":"TOUCHREC.IMG","size":"4.00 MB"},{"name":"restart.gcode","shortname":"RESTAR~1.GCO","size":"1 B"},{"name":"M3.G","shortname":"M3.G","size":"75 B"},{"name":"WeChat Image_20210108102318.jpg","shortname":"WECHAT~1.JPG","size":"876.47 KB"},{"name":"test.txt","shortname":"test.txt","size":"0 B"},{"name":"foo.txt","shortname":"foo.txt","size":"13 B"},{"name":"myfile.txt","shortname":"myfile.txt","size":"0 B"},{"name":"update.zip","shortname":"update.zip","size":"1.29 MB"},{"name":"luc","shortname":"luc","size":"-1"}],"path":"/","occupation":"22","status":"ok","total":"3.67 GB","used":"833.38 MB"}'
);
console.log(commandcolor(`[server]/sdfiles)`));
return;
});*/
function fileSizeString(size) {
if (size === -1) return ""
const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
let i = 0
while (size >= 1024) {
size /= 1024
++i
}
return `${size.toFixed(2)} ${units[i]}`
}
function filesList(mypath, destination) {
const currentPath = path.normalize(serverpath + destination + mypath)
console.log("[path]" + currentPath)
const totalUsed = getTotalSize(serverpath + destination)
const total = (destination == "SD" ? 4096 : 1.31) * 1024 * 1024
const occupation = ((100 * totalUsed) / total).toFixed(0)
const files = fs.readdirSync(currentPath).map((file) => {
const fullpath = path.normalize(currentPath + "/" + file)
const fst = fs.statSync(fullpath)
const fsize = fst.isFile() ? fileSizeString(fst.size) : "-1"
return { name: file, size: fsize }
})
const response = {
files,
path: mypath,
occupation,
status: "ok",
total: fileSizeString(total),
used: fileSizeString(totalUsed),
}
return JSON.stringify(response)
}
const getAllFiles = function (dirPath, arrayOfFiles = []) {
let files = fs.readdirSync(dirPath) || []
const newFiles = files.reduce((acc, file) => {
const fullpath = dirPath + "/" + file
return fs.statSync(fullpath).isDirectory()
? getAllFiles(fullpath, acc)
: [...acc, fullpath]
}, [])
return [...arrayOfFiles, ...newFiles]
}
const getTotalSize = function (directoryPath) {
const allFiles = getAllFiles(directoryPath)
console.log("allFiles", allFiles)
return allFiles.reduce(
(acc, currFile) => acc + fs.statSync(currFile).size,
0
)
}
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 + "Flash" + 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) {
console.log("[server]delete file " + filepath)
fs.unlinkSync(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, "Flash"))
}
let myFile = req.files.myfiles
if (typeof myFile.length == "undefined") {
let fullpath = path.normalize(
serverpath + "Flash" + 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, "Flash"))
})
return
} else {
console.log(myFile.length + " files")
for (let i = 0; i < myFile.length; i++) {
let fullpath = path.normalize(
serverpath + "Flash" + mypath + myFile[i].name
)
console.log(fullpath)
myFile[i].mv(fullpath).then(() => {
if (i == myFile.length - 1) res.send(filesList(mypath, "Flash"))
})
}
}
})
app.all("/sdfiles", function (req, res) {
let mypath = req.query.path
let url = req.originalUrl
let filepath = path.normalize(
serverpath + "SD" + 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, "SD"))
}
let myFile = req.files.myfiles
if (typeof myFile.length == "undefined") {
let fullpath = path.normalize(serverpath + "SD" + 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, "SD"))
})
return
} else {
console.log(myFile.length + " files")
for (let i = 0; i < myFile.length; i++) {
let fullpath = path.normalize(
serverpath + "SD" + mypath + myFile[i].name
)
console.log(fullpath)
myFile[i].mv(fullpath).then(() => {
if (i == myFile.length - 1) res.send(filesList(mypath, "SD"))
})
}
}
})
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}`)
}
})
if (sensorInterval != -1) {
clearInterval(sensorInterval)
sensorInterval = setInterval(() => {
const sensorTxt = "SENSOR:10[C] 15[%]"
SendWS(sensorTxt, false, false)
}, 3000)
}
currentID++
socket.on("message", (message) => {
console.log(wscolor("[ws] received:", message))
if (hasEnabledAuthentication() && message.startsWith("PING:")) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
let t = hasEnableAuthentication()
? sessiontTime - (Date.now() - getLastconnection())
: 60000
let remainingtime = t < 0 ? 0 : t
console.log("remain:", remainingtime, "millisec")
client.send(`PING:${remainingtime}:60000`)
}
})
}
})
})
wss.on("error", (error) => {
console.log(wscolor("[ws] Error:", error))
})

View File

@@ -0,0 +1,662 @@
/*
index.js - ESP3D WebUI Target file
Copyright (c) 2020 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require("chalk")
const wscolor = chalk.cyan
const expresscolor = chalk.green
const commandcolor = chalk.white
const enableAuthentication = false
let lastconnection = Date.now()
let logindone = false
const sessiontTime = 60000
let countStatus = 0
function getLastconnection() {
return lastconnection
}
function hasEnabledAuthentication() {
return enableAuthentication
}
const commandsQuery = (req, res, SendWS) => {
let url = req.query.cmd ? req.query.cmd : req.originalUrl
if (req.query.cmd)
console.log(commandcolor(`[server]/command params: ${req.query.cmd}`))
else console.log(commandcolor(`[server]/command : ${url}`))
if (url.indexOf("PING") != -1) {
lastconnection = Date.now()
res.status(200)
res.send("ok\n")
console.log(commandcolor(`[server]/command :PING`))
return
}
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
if (req.query.cmd && req.query.cmd == "?") {
countStatus++
if (countStatus == 1)
SendWS(
"<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0|WCO:0.000,0.000,0.000,1.000,1.000>\n"
)
if (countStatus == 2)
SendWS(
"<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0|Ov:100,100,100|Pn:XYZ>\n"
)
if (countStatus > 2)
SendWS(
"<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0|A:S|Pn:P>\n"
)
if (countStatus == 10) countStatus = 0
res.send("")
return
}
if (url.indexOf("SIM:") != -1) {
const response = url.substring(url.indexOf("SIM:") + 4)
SendWS(response + "\n" + "ok\n")
res.send("")
return
}
if (url.indexOf("ESP800") != -1) {
res.json({
cmd: "800",
status: "ok",
data: {
FWVersion: "3.0.0.a111",
FWTarget: "grbl",
FWTargetID: "10",
Setup: "Enabled",
SDConnection: "direct",
SerialProtocol: "Socket",
Authentication: "Disabled",
WebCommunication: "Synchronous",
WebSocketIP: "localhost",
WebSocketPort: "81",
Hostname: "esp3d",
WiFiMode: "STA",
WebUpdate: "Enabled",
FlashFileSystem: "LittleFS",
HostPath: "/",
Time: "none",
CameraID: "4",
CameraName: "ESP32 Cam",
},
})
return
}
if (url.indexOf("ESP111") != -1) {
res.send("192.168.1.111")
return
}
if (url.indexOf("ESP401") != -1) {
const reg_search1 = /P=(?<pos>[^\s]*)/i
let posres = null
if ((posres = reg_search1.exec(url)) == null) {
console.log("Cannot find P= in url")
}
res.json({
cmd: "401",
status: "ok",
data: posres.groups.pos ? posres.groups.pos : "Unknown position",
})
return
}
if (url.indexOf("ESP420") != -1) {
res.json({
cmd: "420",
status: "ok",
data: [
{ id: "chip id", value: "18569" },
{ id: "CPU Freq", value: "240Mhz" },
{ id: "CPU Temp", value: "54.4C" },
{ id: "free mem", value: "201.86 KB" },
{ id: "SDK", value: "v4.4-beta1-308-gf3e0c8bc41" },
{ id: "flash size", value: "4.00 MB" },
{ id: "size for update", value: "1.25 MB" },
{ id: "FS type", value: "LittleFS" },
{ id: "FS usage", value: "64.00 KB/1.44 MB" },
{ id: "sleep mode", value: "none" },
{ id: "wifi", value: "ON" },
{ id: "hostname", value: "esp3d" },
{ id: "HTTP port", value: "80" },
{ id: "Telnet port", value: "23" },
{ id: "sta", value: "ON" },
{ id: "mac", value: "24:6F:28:4C:89:48" },
{ id: "SSID", value: "luc-ext1" },
{ id: "signal", value: "60%" },
{ id: "phy mode", value: "11n" },
{ id: "channel", value: "3" },
{ id: "ip mode", value: "dhcp" },
{ id: "ip", value: "192.168.2.215" },
{ id: "gw", value: "192.168.2.1" },
{ id: "msk", value: "255.255.255.0" },
{ id: "DNS", value: "192.168.2.1" },
{ id: "ap", value: "OFF" },
{ id: "mac", value: "24:6F:28:4C:89:49" },
{ id: "notification", value: "ON(line)" },
{ id: "targetfw", value: "grbl" },
{ id: "FW ver", value: "3.0.0.a111" },
{ id: "FW arch", value: "ESP32" },
],
})
return
}
if (url.indexOf("701") != -1) {
if (url.indexOf("json") != -1) {
res.json({
cmd: "701",
status: "ok",
data: {
status: "processing",
total: "1000",
processed: "100",
type: "SD",
name: "test.gcode",
code: 3,
},
})
/*res.json({
cmd: "701",
status: "ok",
data: "no stream",
})*/
} else {
res.send("no stream\n")
}
return
}
if (url.indexOf("ESP410") != -1) {
res.json({
cmd: "410",
status: "ok",
data: [{ SSID: "luc-ext1", SIGNAL: "52", IS_PROTECTED: "1" }],
})
return
}
if (url.indexOf("$G") != -1) {
SendWS("[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F0.0 S0]\n")
res.send("")
return
}
if (url.indexOf("$I") != -1) {
SendWS("[VER:1.1f.20170801:]\n" + "[OPT:VZHTL,15,128]\n")
res.send("")
return
}
if (url.indexOf("\x18") != -1) {
SendWS("Grbl 1.1f ['$' for help]\n")
res.send("")
return
}
if (url.indexOf("$#") != -1) {
SendWS(
"[G54:4.000,0.000,0.000]\n" +
"[G55:4.000,6.000,7.000]\n" +
"[G56:0.000,0.000,0.000]\n" +
"[G57:0.000,0.000,0.000]\n" +
"[G58:0.000,0.000,0.000]\n" +
"[G59:0.000,0.000,0.000]\n" +
"[G28:1.000,2.000,0.000]\n" +
"[G30:4.000,6.000,0.000]\n" +
"[G92:0.000,0.000,0.000]\n" +
"[TLO:0.000]\n" +
"[PRB:0.000,0.000,0.000:1]\n"
)
res.send("")
return
}
if (url.indexOf("$$") != -1) {
SendWS(
"$0=3\n" +
"$1=250\n" +
"$2=0\n" +
"$3=0\n" +
"$4=0\n" +
"$5=1\n" +
"$6=0\n" +
"$10=1\n" +
"$11=0.010\n" +
"$12=0.002\n" +
"$13=0\n" +
"$20=0\n" +
"$21=0\n" +
"$22=0\n" +
"$23=3\n" +
"$24=200.000\n" +
"$25=2000.000\n" +
"$26=250\n" +
"$27=1.000\n" +
"$30=1000.000\n" +
"$31=0.000\n" +
"$32=0\n" +
"$100=100.000\n" +
"$101=100.000\n" +
"$102=100.000\n" +
"$103=100.000\n" +
"$104=100.000\n" +
"$105=100.000\n" +
"$110=1000.000\n" +
"$111=1000.000\n" +
"$112=1000.000\n" +
"$113=1000.000\n" +
"$114=1000.000\n" +
"$115=1000.000\n" +
"$120=200.000\n" +
"$121=200.000\n" +
"$122=200.000\n" +
"$123=200.000\n" +
"$124=200.000\n" +
"$125=200.000\n" +
"$130=300.000\n" +
"$131=300.000\n" +
"$132=300.000\n" +
"$133=300.000\n" +
"$134=300.000\n" +
"$135=300.000\n" +
"ok\n"
)
res.send("")
return
}
if (url.indexOf("ESP600") != -1) {
const text = url.substring(8)
SendWS(text, false)
res.send("")
return
}
if (url.indexOf("ESP400") != -1) {
res.json({
cmd: "400",
status: "ok",
data: [
{
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" }],
R: "1",
},
{
F: "network/sta",
P: "1",
T: "S",
V: "WIFI_OFFICE_B2G",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/sta",
P: "34",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/sta",
P: "99",
T: "B",
V: "1",
H: "ip mode",
O: [{ dhcp: "1" }, { static: "0" }],
R: "1",
},
{
F: "network/sta",
P: "100",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
F: "network/sta",
P: "108",
T: "A",
V: "192.168.0.1",
H: "gw",
R: "1",
},
{
F: "network/sta",
P: "104",
T: "A",
V: "255.255.255.0",
H: "msk",
R: "1",
},
{
F: "network/ap",
P: "218",
T: "S",
V: "ESP3D",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/ap",
P: "251",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/ap",
P: "316",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
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" },
],
R: "1",
},
{
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: "10",
H: "targetfw",
O: [
{ repetier: "50" },
{ marlin: "20" },
{ 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",
},
],
})
return
}
SendWS("ok\n")
res.send("")
}
const loginURI = (req, res) => {
if (req.body.DISCONNECT == "YES") {
res.status(401)
logindone = false
} else if (req.body.USER == "admin" && req.body.PASSWORD == "admin") {
logindone = true
lastconnection = Date.now()
} else {
res.status(401)
logindone = false
}
res.send("")
}
const configURI = (req, res) => {
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
res.send(
"chip id: 56398\nCPU Freq: 240 Mhz<br/>" +
"CPU Temp: 58.3 C<br/>" +
"free mem: 212.36 KB<br/>" +
"SDK: v3.2.3-14-gd3e562907<br/>" +
"flash size: 4.00 MB<br/>" +
"size for update: 1.87 MB<br/>" +
"FS type: LittleFS<br/>" +
"FS usage: 104.00 KB/192.00 KB<br/>" +
"baud: 115200<br/>" +
"sleep mode: none<br/>" +
"wifi: ON<br/>" +
"hostname: esp3d<br/>" +
"HTTP port: 80<br/>" +
"Telnet port: 23<br/>" +
"WebDav port: 8383<br/>" +
"sta: ON<br/>" +
"mac: 80:7D:3A:C4:4E:DC<br/>" +
"SSID: WIFI_OFFICE_A2G<br/>" +
"signal: 100 %<br/>" +
"phy mode: 11n<br/>" +
"channel: 11<br/>" +
"ip mode: dhcp<br/>" +
"ip: 192.168.1.61<br/>" +
"gw: 192.168.1.1<br/>" +
"msk: 255.255.255.0<br/>" +
"DNS: 192.168.1.1<br/>" +
"ap: OFF<br/>" +
"mac: 80:7D:3A:C4:4E:DD<br/>" +
"serial: ON<br/>" +
"notification: OFF<br/>" +
"Target Fw: grbl<br/>" +
"FW ver: 3.0.0.a91<br/>" +
"FW arch: ESP32 "
)
}
module.exports = {
commandsQuery,
configURI,
loginURI,
getLastconnection,
hasEnabledAuthentication,
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,592 @@
/*
index.js - ESP3D WebUI Target file
Copyright (c) 2020 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require("chalk")
const wscolor = chalk.cyan
const expresscolor = chalk.green
const commandcolor = chalk.white
const enableAuthentication = false
let lastconnection = Date.now()
let logindone = false
const sessiontTime = 60000
let countStatus = 0
function getLastconnection() {
return lastconnection
}
function hasEnabledAuthentication() {
return enableAuthentication
}
let posx = 0
let posy = 0
let pendown = 0
const commandsQuery = (req, res, SendWS) => {
let url = req.query.cmd ? req.query.cmd : req.originalUrl
if (req.query.cmd)
console.log(commandcolor(`[server]/command params: ${req.query.cmd}`))
else console.log(commandcolor(`[server]/command : ${url}`))
if (url.indexOf("PING") != -1) {
lastconnection = Date.now()
res.status(200)
res.send("ok\n")
console.log(commandcolor(`[server]/command :PING`))
return
}
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
if (url.indexOf("SIM:") != -1) {
const response = url.substring(url.indexOf("SIM:") + 4)
SendWS(response + "\n" + "ok\n")
res.send("")
return
}
if (url.indexOf("ESP800") != -1) {
res.json({
cmd: "800",
status: "ok",
data: {
FWVersion: "3.0.0.a111",
FWTarget: "hp_gl",
FWTargetID: "90",
Setup: "Enabled",
SDConnection: "direct",
SerialProtocol: "Socket",
Authentication: "Disabled",
WebCommunication: "Synchronous",
WebSocketIP: "localhost",
WebSocketPort: "81",
Hostname: "esp3d",
WiFiMode: "STA",
WebUpdate: "Enabled",
FlashFileSystem: "LittleFS",
HostPath: "/",
Time: "none",
},
})
return
}
if (url.indexOf("ESP111") != -1) {
res.send("192.168.1.111")
return
}
if (url.indexOf("ESP401") != -1) {
const reg_search1 = /P=(?<pos>[^\s]*)/i
let posres = null
if ((posres = reg_search1.exec(url)) == null) {
console.log("Cannot find P= in url")
}
res.json({
cmd: "401",
status: "ok",
data: posres.groups.pos ? posres.groups.pos : "Unknown position",
})
return
}
if (url.indexOf("ESP420") != -1) {
res.json({
cmd: "420",
status: "ok",
data: [
{ id: "chip id", value: "18569" },
{ id: "CPU Freq", value: "240Mhz" },
{ id: "CPU Temp", value: "54.4C" },
{ id: "free mem", value: "201.86 KB" },
{ id: "SDK", value: "v4.4-beta1-308-gf3e0c8bc41" },
{ id: "flash size", value: "4.00 MB" },
{ id: "size for update", value: "1.25 MB" },
{ id: "FS type", value: "LittleFS" },
{ id: "FS usage", value: "64.00 KB/1.44 MB" },
{ id: "sleep mode", value: "none" },
{ id: "wifi", value: "ON" },
{ id: "hostname", value: "esp3d" },
{ id: "HTTP port", value: "80" },
{ id: "Telnet port", value: "23" },
{ id: "sta", value: "ON" },
{ id: "mac", value: "24:6F:28:4C:89:48" },
{ id: "SSID", value: "luc-ext1" },
{ id: "signal", value: "60%" },
{ id: "phy mode", value: "11n" },
{ id: "channel", value: "3" },
{ id: "ip mode", value: "dhcp" },
{ id: "ip", value: "192.168.2.215" },
{ id: "gw", value: "192.168.2.1" },
{ id: "msk", value: "255.255.255.0" },
{ id: "DNS", value: "192.168.2.1" },
{ id: "ap", value: "OFF" },
{ id: "mac", value: "24:6F:28:4C:89:49" },
{ id: "notification", value: "ON(line)" },
{ id: "targetfw", value: "hp_gl" },
{ id: "FW ver", value: "3.0.0.a111" },
{ id: "FW arch", value: "ESP32" },
],
})
return
}
if (url.indexOf("701") != -1) {
if (url.indexOf("json") != -1) {
res.json({
cmd: "701",
status: "ok",
data: {
status: "processing",
total: "1000",
processed: "100",
type: "SD",
name: "test.gcode",
code: 3,
},
})
/*res.json({
cmd: "701",
status: "ok",
data: "no stream",
})*/
} else {
res.send("no stream\n")
}
return
}
if (url.indexOf("ESP410") != -1) {
res.json({
cmd: "410",
status: "ok",
data: [{ SSID: "luc-ext1", SIGNAL: "52", IS_PROTECTED: "1" }],
})
return
}
if (url.indexOf("OA") != -1) {
SendWS(`${posx},${posy},${pendown}\n`)
res.send("")
return
}
if (url.indexOf("PR") != -1) {
const pos_pattern = /PR(?<xrel>[+|-]?\d+),(?<yrel>[+|-]?\d+)/i
let posres = pos_pattern.exec(url)
posx = posx + parseInt(posres.groups.xrel)
posy = posy + parseInt(posres.groups.yrel)
//SendWS(`${posx},${posy},${pendown}\n`)
res.send("")
return
}
if (url.indexOf("PD") != -1) {
pendown = 1
//SendWS(`${posx},${posy},${pendown}\n`)
res.send("")
return
}
if (url.indexOf("PU") != -1) {
pendown = 0
//SendWS(`${posx},${posy},${pendown}\n`)
res.send("")
return
}
if (url.indexOf(String.fromCharCode(27) + ".") != -1) {
//it is esc command ESC.
//SendWS("EScape command\n")
res.send("")
return
}
if (url.indexOf("ESP600") != -1) {
const text = url.substring(8)
SendWS(text, false)
res.send("")
return
}
if (url.indexOf("ESP400") != -1) {
res.json({
cmd: "400",
status: "ok",
data: [
{
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" }],
R: "1",
},
{
F: "network/sta",
P: "1",
T: "S",
V: "WIFI_OFFICE_B2G",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/sta",
P: "34",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/sta",
P: "99",
T: "B",
V: "1",
H: "ip mode",
O: [{ dhcp: "1" }, { static: "0" }],
R: "1",
},
{
F: "network/sta",
P: "100",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
F: "network/sta",
P: "108",
T: "A",
V: "192.168.0.1",
H: "gw",
R: "1",
},
{
F: "network/sta",
P: "104",
T: "A",
V: "255.255.255.0",
H: "msk",
R: "1",
},
{
F: "network/ap",
P: "218",
T: "S",
V: "ESP3D",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/ap",
P: "251",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/ap",
P: "316",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
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" },
],
R: "1",
},
{
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: "90",
H: "targetfw",
O: [
{ hp_gl: "90" },
{ repetier: "50" },
{ marlin: "20" },
{ 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",
},
],
})
return
}
SendWS("ok\n")
res.send("")
}
const loginURI = (req, res) => {
if (req.body.DISCONNECT == "YES") {
res.status(401)
logindone = false
} else if (req.body.USER == "admin" && req.body.PASSWORD == "admin") {
logindone = true
lastconnection = Date.now()
} else {
res.status(401)
logindone = false
}
res.send("")
}
const configURI = (req, res) => {
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
res.send(
"chip id: 56398\nCPU Freq: 240 Mhz<br/>" +
"CPU Temp: 58.3 C<br/>" +
"free mem: 212.36 KB<br/>" +
"SDK: v3.2.3-14-gd3e562907<br/>" +
"flash size: 4.00 MB<br/>" +
"size for update: 1.87 MB<br/>" +
"FS type: LittleFS<br/>" +
"FS usage: 104.00 KB/192.00 KB<br/>" +
"baud: 115200<br/>" +
"sleep mode: none<br/>" +
"wifi: ON<br/>" +
"hostname: esp3d<br/>" +
"HTTP port: 80<br/>" +
"Telnet port: 23<br/>" +
"WebDav port: 8383<br/>" +
"sta: ON<br/>" +
"mac: 80:7D:3A:C4:4E:DC<br/>" +
"SSID: WIFI_OFFICE_A2G<br/>" +
"signal: 100 %<br/>" +
"phy mode: 11n<br/>" +
"channel: 11<br/>" +
"ip mode: dhcp<br/>" +
"ip: 192.168.1.61<br/>" +
"gw: 192.168.1.1<br/>" +
"msk: 255.255.255.0<br/>" +
"DNS: 192.168.1.1<br/>" +
"ap: OFF<br/>" +
"mac: 80:7D:3A:C4:4E:DD<br/>" +
"serial: ON<br/>" +
"notification: OFF<br/>" +
"Target Fw: grbl<br/>" +
"FW ver: 3.0.0.a91<br/>" +
"FW arch: ESP32 "
)
}
module.exports = {
commandsQuery,
configURI,
loginURI,
getLastconnection,
hasEnabledAuthentication,
}

View File

@@ -0,0 +1,861 @@
/*
index.js - ESP3D WebUI Target file
Copyright (c) 2020 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require("chalk")
const wscolor = chalk.cyan
const expresscolor = chalk.green
const commandcolor = chalk.white
const enableAuthentication = false
const SERIAL_PROTOCOL = "RAW"
let lastconnection = Date.now()
let logindone = false
const sessiontTime = 60000
const roomTemperature = 20
const temperatures = {
T: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
{
value: 20,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
],
B: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.2,
coolspeed: 0.8,
variation: 0.5,
},
],
C: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
],
P: [{ value: roomTemperature, sameas: "T", lastTime: -1, variation: 0.5 }], //let say probe is 50% of extruder temperature
R: [{ value: roomTemperature, sameas: "T", lastTime: -1, variation: 1 }], //the redondant is same as extruder 0
M: [{ value: roomTemperature, lastTime: -1, variation: 1 }], //the motherboard is same as room temperature +5/10 degres
}
const updateTemperature = (entry, time) => {
if (entry.lastTime == -1) {
entry.lastTime = time
}
const v = Math.random() * 5
//heater
if (typeof entry.target != "undefined") {
const target = entry.target == 0 ? roomTemperature : entry.target
if (entry.value + 5 < target) {
entry.value =
entry.value + (entry.heatspeed * (time - entry.lastTime)) / 1000
} else if (entry.value - 5 > target) {
entry.value =
entry.value - (entry.coolspeed * (time - entry.lastTime)) / 1000
} else if (target - 2 < entry.value && entry.value < target + 2) {
entry.value = target + entry.variation * (Math.random() - 0.5)
} else if (entry.value < target) {
entry.value =
entry.value +
((entry.heatspeed / 3) * (time - entry.lastTime)) / 1000
} else {
entry.value =
entry.value -
((entry.coolspeed / 3) * (time - entry.lastTime)) / 1000
}
}
//sensor
else if (typeof entry.sameas != "undefined") {
if (
entry.sameas == "T" &&
entry.variation == 0.5 &&
entry.value < 2 * roomTemperature
) {
//probe is same as room temperature if under 40 degres
entry.value =
v > 2.5 ? roomTemperature + v / 2 : roomTemperature - v / 2
} else {
entry.value =
v > 2.5
? temperatures[entry.sameas][0].value * entry.variation +
v / 4
: temperatures[entry.sameas][0].value * entry.variation -
v / 4
}
} else {
entry.value =
v > 2.5 ? roomTemperature + v / 2 : roomTemperature - v / 2
}
entry.lastTime = time
}
function getLastconnection() {
return lastconnection
}
function hasEnabledAuthentication() {
return enableAuthentication
}
function Temperatures() {
Object.keys(temperatures).map((tool) => {
temperatures[tool].map((entry) => {
updateTemperature(entry, new Date())
})
})
const result =
"ok T:" +
Number(temperatures["T"][0].value).toFixed(2) +
" /" +
Number(temperatures["T"][0].target).toFixed(2) +
" C:" +
Number(temperatures["C"][0].value).toFixed(2) +
" /" +
Number(temperatures["C"][0].target).toFixed(2) +
" B:" +
Number(temperatures["B"][0].value).toFixed(2) +
" /" +
Number(temperatures["B"][0].target).toFixed(2) +
" P:" +
Number(temperatures["P"][0].value).toFixed(2) +
" /0 R:" +
Number(temperatures["R"][0].value).toFixed(2) +
" /0 T0:" +
Number(temperatures["T"][0].value).toFixed(2) +
" /" +
Number(temperatures["T"][0].target).toFixed(2) +
" T1:" +
Number(temperatures["T"][1].value).toFixed(2) +
" /" +
Number(temperatures["T"][1].target).toFixed(2) +
" @:0\n"
console.log(result)
return result
}
const commandsQuery = (req, res, SendWS) => {
let url = req.query.cmd ? req.query.cmd : req.originalUrl
if (req.query.cmd)
console.log(commandcolor(`[server]/command params: ${req.query.cmd}`))
else console.log(commandcolor(`[server]/command : ${url}`))
if (url.indexOf("PING") != -1) {
lastconnection = Date.now()
res.status(200)
res.send("ok\n")
console.log(commandcolor(`[server]/command :PING`))
return
}
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
if (url.indexOf("M114") != -1) {
let X = Number(Math.random() * 200.12).toFixed(2)
let Y = Number(Math.random() * 200.12).toFixed(2)
let Z = Number(Math.random() * 200.12).toFixed(2)
SendWS(`X:${X} Y:${Y} Z:${Z} E:0.00 Count X: 0 Y:10160 Z:116000\nok\n`)
res.send("")
return
}
if (url.indexOf("SIM:") != -1) {
const response = url.substring(url.indexOf("SIM:") + 4)
SendWS(response + "\n" + "ok\n")
res.send("")
return
}
if (url.indexOf("M20 1:") != -1) {
SendWS(
"Begin file list\n" +
"System Volume Information.DIR\n" +
"mycode3.gco\n" +
"CUBE.GCO\n" +
"bak_pic.DIR\n" +
"bak_font.DIR\n" +
"macro1.g\n" +
"BAK.DIR\n" +
"End file list\n" +
"ok\n"
)
res.send("")
return
}
if (url.indexOf("M20 L") != -1) {
SendWS(
"echo:SD card ok\n" +
"ok\n" +
"Begin file listt\n" +
"V2T-TEST.GCO 569266 V2T-TEST.GCO\n" +
"DFQ-PI~1.GCO 1490254 DFq-pika2.gco\n" +
"VJ1-TEST.GCO 569266 VJ1-TEST.GCO\n" +
"XRP-SU~1.GCO 569266 xRP-SupportChain-Body.gcod\n" +
"RGW-PI~1.GCO 1490254 rgw-pika2.gco\n" +
"PIKA2~1.GCO 1635116 pika2.gcode\n" +
"UJP-PI~1.GCO 1573255 ujp-pika2.gcode\n" +
"CTEST/INDEXH~1.GZ 69111 /index.html.gz\n" +
"PIKA2.GCO 1635116 PIKA2.GCO\n" +
"MACRO1.GCO 19 MACRO1.GCO\n" +
"INDEX_~1.GZ 78055 index.html.gz\n" +
"GCODE/TESTLO~1.GCO 25 /testlongname.gcode\n" +
"GCODE/TESTCUBE.GCO 353194 /TESTCUBE.GCO\n" +
"RESOUR~1/GCODE/APPLE~1.GCO 8140 resources//Apple.gcode\n" +
"RESOUR~1/GCODE/BANANA~1.GCO 7554 resources//Banana.gcode\n" +
"RESOUR~1/GCODE/CHERRY~1.GCO 6465 resources//Cherry.gcode\n" +
"RESOUR~1/GCODE/PEACH~1.GCO 8467 resources//Peach.gcode\n" +
"RESOUR~1/GCODE/PEAR~1.GCO 6010 resources//Pear.gcode\n" +
"TESTCUBE.GCO 353194 TESTCUBE.GCO\n" +
"TEST1.GCO 1143935 TEST1.GCO\n" +
"End file list\n" +
"ok"
)
res.send("")
return
}
if (url.indexOf("M20") != -1) {
SendWS(
"echo:SD card ok\n" +
"ok\n" +
"Begin file list\n" +
"V2T-TEST.GCO 569266\n" +
"DFQ-PI~1.GCO 1490254\n" +
"VJ1-TEST.GCO 569266\n" +
"XRP-SU~1.GCO 569266\n" +
"RGW-PI~1.GCO 1490254\n" +
"PIKA2~1.GCO 1635116\n" +
"UJP-PI~1.GCO 1573255\n" +
"CTEST/INDEXH~1.GZ 69111\n" +
"PIKA2.GCO 1635116\n" +
"MACRO1.GCO 19\n" +
"INDEX_~1.GZ 78055\n" +
"GCODE/TESTLO~1.GCO 25\n" +
"GCODE/TESTCUBE.GCO 353194\n" +
"RESOUR~1/GCODE/APPLE~1.GCO 8140\n" +
"RESOUR~1/GCODE/BANANA~1.GCO 7554\n" +
"RESOUR~1/GCODE/CHERRY~1.GCO 6465\n" +
"RESOUR~1/GCODE/PEACH~1.GCO 8467\n" +
"RESOUR~1/GCODE/PEAR~1.GCO 6010\n" +
"TESTCUBE.GCO 353194\n" +
"118.GCO 41\n" +
"TEST1.GCO 1143935\n" +
"End file list\n" +
"ok\n"
)
res.send("")
return
}
if (url.indexOf("M104") != -1) {
const reg_ex_temp = /S([0-9]*\.?[0-9]*)/
const reg_ex_index = /T([0-9])/
const result_target = reg_ex_temp.exec(url)
const result_index = reg_ex_index.exec(url)
console.log(result_target[1], result_index[1])
temperatures["T"][result_index[1]].target = parseFloat(result_target[1])
res.send("")
return
}
if (url.indexOf("M140") != -1) {
const reg_ex_temp = /S([0-9]*\.?[0-9]*)/
const result_target = reg_ex_temp.exec(url)
temperatures["B"][0].target = parseFloat(result_target[1])
res.send("")
return
}
if (url.indexOf("M141") != -1) {
const reg_ex_temp = /S([0-9]*\.?[0-9]*)/
const result_target = reg_ex_temp.exec(url)
temperatures["C"][0].target = parseFloat(result_target[1])
res.send("")
return
}
if (url.indexOf("M30") != -1) {
const name = url.split(" ")
SendWS(
//"Deletion failed, File:" + name[1].substring(1) + ".\n" + "ok\n"
"File deleted:" + name[1].substring(1) + "\n" + "ok\n"
)
res.send("")
return
}
if (url.indexOf("M115") != -1) {
SendWS(
"FIRMWARE_NAME:Marlin 2.0.9.1 (Sep 8 2021 17:07:06) SOURCE_CODE_URL:github.com/MarlinFirmware/Marlin PROTOCOL_VERSION:1.0 MACHINE_TYPE:MRR ESPA EXTRUDER_COUNT:1 UUID:cede2a2f-41a2-4748-9b12-c55c62f367ff\n" +
"Cap:SERIAL_XON_XOFF:0\n" +
"Cap:BINARY_FILE_TRANSFER:0\n" +
"Cap:EEPROM:0\n" +
"Cap:VOLUMETRIC:1\n" +
"Cap:AUTOREPORT_POS:0\n" +
"Cap:AUTOREPORT_TEMP:1\n" +
"Cap:PROGRESS:0\n" +
"Cap:PRINT_JOB:1\n" +
"Cap:AUTOLEVEL:0\n" +
"Cap:RUNOUT:0\n" +
"Cap:Z_PROBE:0\n" +
"Cap:LEVELING_DATA:0\n" +
"Cap:BUILD_PERCENT:0\n" +
"Cap:SOFTWARE_POWER:0\n" +
"Cap:TOGGLE_LIGHTS:0\n" +
"Cap:CASE_LIGHT_BRIGHTNESS:0\n" +
"Cap:EMERGENCY_PARSER:0\n" +
"Cap:HOST_ACTION_COMMANDS:0\n" +
"Cap:PROMPT_SUPPORT:0\n" +
"Cap:SDCARD:1\n" +
"Cap:REPEAT:0\n" +
"Cap:SD_WRITE:1\n" +
"Cap:AUTOREPORT_SD_STATUS:0\n" +
"Cap:LONG_FILENAME:1\n" +
"Cap:THERMAL_PROTECTION:1\n" +
"Cap:MOTION_MODES:0\n" +
"Cap:ARCS:1\n" +
"Cap:BABYSTEPPING:0\n" +
"Cap:CHAMBER_TEMPERATURE:0\n" +
"Cap:COOLER_TEMPERATURE:0\n" +
"Cap:MEATPACK:0\n" +
"ok\n"
)
res.send("")
return
}
if (url.indexOf("M503") != -1) {
SendWS(
"echo:; Linear Units:\n" +
"echo: G21 ; (mm)\n" +
"echo:; Temperature Units:\n" +
"echo: M149 C ; Units in Celsius\n" +
"echo:; Filament settings (Disabled):\n" +
"echo: M200 S0 D1.75\n" +
"echo:; Steps per unit:\n" +
"echo: M92 X80.00 Y80.00 Z400.00 E500.00\n" +
"echo:; Max feedrates (units/s):\n" +
"echo: M203 X300.00 Y300.00 Z5.00 E25.00\n" +
"echo:; Max Acceleration (units/s2):\n" +
"echo: M201 X3000.00 Y3000.00 Z100.00 E10000.00\n" +
"echo:; Acceleration (units/s2) (P<print-accel> R<retract-accel> T<travel-accel>):\n" +
"echo: M204 P3000.00 R3000.00 T3000.00\n" +
"echo:; Advanced (B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate> J<junc_dev>):\n" +
"echo: M205 B20000.00 S0.00 T0.00 J0.01\n" +
"echo:; Home offset:\n" +
"echo: M206 X0.00 Y0.00 Z0.00\n" +
"echo:; Hotend PID:\n" +
"echo: M301 P22.20 I1.08 D114.00\n" +
"ok\n"
)
res.send("")
return
}
if (url.indexOf("M105") != -1) {
SendWS(Temperatures())
res.send("")
return
}
if (url.indexOf("ESP800") != -1) {
res.json({
cmd: "800",
status: "ok",
data: {
FWVersion: "2.0.9.3+-3.0.0.a111",
FWTarget: "marlin",
FWTargetID: "30",
Setup: "Enabled",
SDConnection: "shared",
SerialProtocol: "Socket",
Authentication: "Disabled",
WebCommunication: "Synchronous",
WebSocketIP: "localhost",
WebSocketPort: "81",
Hostname: "esp3d",
WiFiMode: "STA",
WebUpdate: "Enabled",
FlashFileSystem: "LittleFS",
HostPath: "/",
Time: "none",
},
})
return
}
if (url.indexOf("ESP111") != -1) {
res.send("192.168.1.111")
return
}
if (url.indexOf("ESP401") != -1) {
const reg_search1 = /P=(?<pos>[^\s]*)/i
let posres = null
if ((posres = reg_search1.exec(url)) == null) {
console.log("Cannot find P= in url")
}
res.json({
cmd: "401",
status: "ok",
data: posres.groups.pos ? posres.groups.pos : "Unknown position",
})
return
}
if (url.indexOf("ESP420") != -1) {
res.json({
cmd: "420",
status: "ok",
data: [
{ id: "chip id", value: "18569" },
{ id: "CPU Freq", value: "240Mhz" },
{ id: "CPU Temp", value: "54.4C" },
{ id: "free mem", value: "201.86 KB" },
{ id: "SDK", value: "v4.4-beta1-308-gf3e0c8bc41" },
{ id: "flash size", value: "4.00 MB" },
{ id: "size for update", value: "1.25 MB" },
{ id: "FS type", value: "LittleFS" },
{ id: "FS usage", value: "64.00 KB/1.44 MB" },
{ id: "sleep mode", value: "none" },
{ id: "wifi", value: "ON" },
{ id: "hostname", value: "esp3d" },
{ id: "HTTP port", value: "80" },
{ id: "Telnet port", value: "23" },
{ id: "sta", value: "ON" },
{ id: "mac", value: "24:6F:28:4C:89:48" },
{ id: "SSID", value: "luc-ext1" },
{ id: "signal", value: "60%" },
{ id: "phy mode", value: "11n" },
{ id: "channel", value: "3" },
{ id: "ip mode", value: "dhcp" },
{ id: "ip", value: "192.168.2.215" },
{ id: "gw", value: "192.168.2.1" },
{ id: "msk", value: "255.255.255.0" },
{ id: "DNS", value: "192.168.2.1" },
{ id: "ap", value: "OFF" },
{ id: "mac", value: "24:6F:28:4C:89:49" },
{ id: "notification", value: "ON(line)" },
{ id: "sd", value: "shared(SDFat - 2.1.2)" },
{ id: "targetfw", value: "marlin" },
{ id: "FW ver", value: "3.0.0.a111" },
{ id: "FW arch", value: "ESP32" },
],
})
return
}
if (url.indexOf("ESP410") != -1) {
res.json({
cmd: "410",
status: "ok",
data: [{ SSID: "luc-ext1", SIGNAL: "52", IS_PROTECTED: "1" }],
})
return
}
if (url.indexOf("ESP600") != -1) {
const text = url.substring(8)
SendWS(text, false)
res.send("")
return
}
if (url.indexOf("ESP400") != -1) {
res.json({
cmd: "400",
status: "ok",
data: [
{
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" }],
R: "1",
},
{
F: "network/sta",
P: "1",
T: "S",
V: "WIFI_OFFICE_B2G",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/sta",
P: "34",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/sta",
P: "99",
T: "B",
V: "1",
H: "ip mode",
O: [{ dhcp: "1" }, { static: "0" }],
R: "1",
},
{
F: "network/sta",
P: "100",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
F: "network/sta",
P: "108",
T: "A",
V: "192.168.0.1",
H: "gw",
R: "1",
},
{
F: "network/sta",
P: "104",
T: "A",
V: "255.255.255.0",
H: "msk",
R: "1",
},
{
F: "network/ap",
P: "218",
T: "S",
V: "ESP3D",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/ap",
P: "251",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/ap",
P: "316",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
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" },
],
R: "1",
},
{
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" },
{ 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",
},
],
})
return
}
SendWS("ok\n")
res.send("")
}
const loginURI = (req, res) => {
if (req.body.DISCONNECT == "YES") {
res.status(401)
logindone = false
} else if (req.body.USER == "admin" && req.body.PASSWORD == "admin") {
logindone = true
lastconnection = Date.now()
} else {
res.status(401)
logindone = false
}
res.send("")
}
const configURI = (req, res) => {
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
res.send(
"chip id: 56398\nCPU Freq: 240 Mhz<br/>" +
"CPU Temp: 58.3 C<br/>" +
"free mem: 212.36 KB<br/>" +
"SDK: v3.2.3-14-gd3e562907<br/>" +
"flash size: 4.00 MB<br/>" +
"size for update: 1.87 MB<br/>" +
"FS type: LittleFS<br/>" +
"FS usage: 104.00 KB/192.00 KB<br/>" +
"baud: 115200<br/>" +
"sleep mode: none<br/>" +
"wifi: ON<br/>" +
"hostname: esp3d<br/>" +
"HTTP port: 80<br/>" +
"Telnet port: 23<br/>" +
"WebDav port: 8383<br/>" +
"sta: ON<br/>" +
"mac: 80:7D:3A:C4:4E:DC<br/>" +
"SSID: WIFI_OFFICE_A2G<br/>" +
"signal: 100 %<br/>" +
"phy mode: 11n<br/>" +
"channel: 11<br/>" +
"ip mode: dhcp<br/>" +
"ip: 192.168.1.61<br/>" +
"gw: 192.168.1.1<br/>" +
"msk: 255.255.255.0<br/>" +
"DNS: 192.168.1.1<br/>" +
"ap: OFF<br/>" +
"mac: 80:7D:3A:C4:4E:DD<br/>" +
"serial: ON<br/>" +
"notification: OFF<br/>" +
"Target Fw: marlin<br/>" +
"FW ver: 3.0.0.a91<br/>" +
"FW arch: ESP32 "
)
}
module.exports = {
commandsQuery,
configURI,
loginURI,
getLastconnection,
hasEnabledAuthentication,
}

View File

@@ -0,0 +1,969 @@
/*
index.js - ESP3D WebUI Target file
Copyright (c) 2020 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require('chalk')
const wscolor = chalk.cyan
const expresscolor = chalk.green
const commandcolor = chalk.white
const enableAuthentication = false
const SERIAL_PROTOCOL = 'RAW'
let lastconnection = Date.now()
let logindone = false
const sessiontTime = 60000
const roomTemperature = 20
const temperatures = {
T: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
{
value: 20,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
],
B: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.2,
coolspeed: 0.8,
variation: 0.5,
},
],
C: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
],
P: [{ value: roomTemperature, sameas: 'T', lastTime: -1, variation: 0.5 }], //let say probe is 50% of extruder temperature
R: [{ value: roomTemperature, sameas: 'T', lastTime: -1, variation: 1 }], //the redondant is same as extruder 0
M: [{ value: roomTemperature, lastTime: -1, variation: 1 }], //the motherboard is same as room temperature +5/10 degres
}
const updateTemperature = (entry, time) => {
if (entry.lastTime == -1) {
entry.lastTime = time
}
const v = Math.random() * 5
//heater
if (typeof entry.target != 'undefined') {
const target = entry.target == 0 ? roomTemperature : entry.target
if (entry.value + 5 < target) {
entry.value =
entry.value + (entry.heatspeed * (time - entry.lastTime)) / 1000
} else if (entry.value - 5 > target) {
entry.value =
entry.value - (entry.coolspeed * (time - entry.lastTime)) / 1000
} else if (target - 2 < entry.value && entry.value < target + 2) {
entry.value = target + entry.variation * (Math.random() - 0.5)
} else if (entry.value < target) {
entry.value =
entry.value +
((entry.heatspeed / 3) * (time - entry.lastTime)) / 1000
} else {
entry.value =
entry.value -
((entry.coolspeed / 3) * (time - entry.lastTime)) / 1000
}
}
//sensor
else if (typeof entry.sameas != 'undefined') {
if (
entry.sameas == 'T' &&
entry.variation == 0.5 &&
entry.value < 2 * roomTemperature
) {
//probe is same as room temperature if under 40 degres
entry.value =
v > 2.5 ? roomTemperature + v / 2 : roomTemperature - v / 2
} else {
entry.value =
v > 2.5
? temperatures[entry.sameas][0].value * entry.variation +
v / 4
: temperatures[entry.sameas][0].value * entry.variation -
v / 4
}
} else {
entry.value =
v > 2.5 ? roomTemperature + v / 2 : roomTemperature - v / 2
}
entry.lastTime = time
}
function getLastconnection() {
return lastconnection
}
function hasEnabledAuthentication() {
return enableAuthentication
}
function Temperatures() {
Object.keys(temperatures).map((tool) => {
temperatures[tool].map((entry) => {
updateTemperature(entry, new Date())
})
})
const result =
'ok T:' +
Number(temperatures['T'][0].value).toFixed(2) +
' /' +
Number(temperatures['T'][0].target).toFixed(2) +
' C:' +
Number(temperatures['C'][0].value).toFixed(2) +
' /' +
Number(temperatures['C'][0].target).toFixed(2) +
' B:' +
Number(temperatures['B'][0].value).toFixed(2) +
' /' +
Number(temperatures['B'][0].target).toFixed(2) +
' P:' +
Number(temperatures['P'][0].value).toFixed(2) +
' /0 R:' +
Number(temperatures['R'][0].value).toFixed(2) +
' /0 T0:' +
Number(temperatures['T'][0].value).toFixed(2) +
' /' +
Number(temperatures['T'][0].target).toFixed(2) +
' T1:' +
Number(temperatures['T'][1].value).toFixed(2) +
' /' +
Number(temperatures['T'][1].target).toFixed(2) +
' @:0\n'
console.log(result)
return result
}
const commandsQuery = (req, res, SendWS) => {
let url = req.query.cmd ? req.query.cmd : req.originalUrl
if (req.query.cmd)
console.log(commandcolor(`[server]/command params: ${req.query.cmd}`))
else console.log(commandcolor(`[server]/command : ${url}`))
if (url.indexOf('PING') != -1) {
lastconnection = Date.now()
res.status(200)
res.send('ok\n')
console.log(commandcolor(`[server]/command :PING`))
return
}
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
if (url.indexOf('M114') != -1) {
let X = Number(Math.random() * 200.12).toFixed(2)
let Y = Number(Math.random() * 200.12).toFixed(2)
let Z = Number(Math.random() * 200.12).toFixed(2)
SendWS(`X:${X} Y:${Y} Z:${Z} E:0.00 Count X: 0 Y:10160 Z:116000\nok\n`)
res.send('')
return
}
if (url.indexOf('SIM:') != -1) {
const response = url.substring(url.indexOf('SIM:') + 4)
SendWS(response + '\n' + 'ok\n')
res.send('')
return
}
if (url.indexOf('M20 1:') != -1) {
SendWS(
'Begin file list\n' +
'System Volume Information.DIR\n' +
'mycode3.gco\n' +
'CUBE.GCO\n' +
'bak_pic.DIR\n' +
'bak_font.DIR\n' +
'macro1.g\n' +
'BAK.DIR\n' +
'End file list\n' +
'ok\n'
)
res.send('')
return
}
if (url.indexOf('M20 L') != -1) {
SendWS(
'echo:SD card ok\n' +
'ok\n' +
'Begin file listt\n' +
'V2T-TEST.GCO 569266 V2T-TEST.GCO\n' +
'DFQ-PI~1.GCO 1490254 DFq-pika2.gco\n' +
'VJ1-TEST.GCO 569266 VJ1-TEST.GCO\n' +
'XRP-SU~1.GCO 569266 xRP-SupportChain-Body.gcod\n' +
'RGW-PI~1.GCO 1490254 rgw-pika2.gco\n' +
'PIKA2~1.GCO 1635116 pika2.gcode\n' +
'UJP-PI~1.GCO 1573255 ujp-pika2.gcode\n' +
'CTEST/INDEXH~1.GZ 69111 /index.html.gz\n' +
'PIKA2.GCO 1635116 PIKA2.GCO\n' +
'MACRO1.GCO 19 MACRO1.GCO\n' +
'INDEX_~1.GZ 78055 index.html.gz\n' +
'GCODE/TESTLO~1.GCO 25 /testlongname.gcode\n' +
'GCODE/TESTCUBE.GCO 353194 /TESTCUBE.GCO\n' +
'RESOUR~1/GCODE/APPLE~1.GCO 8140 resources//Apple.gcode\n' +
'RESOUR~1/GCODE/BANANA~1.GCO 7554 resources//Banana.gcode\n' +
'RESOUR~1/GCODE/CHERRY~1.GCO 6465 resources//Cherry.gcode\n' +
'RESOUR~1/GCODE/PEACH~1.GCO 8467 resources//Peach.gcode\n' +
'RESOUR~1/GCODE/PEAR~1.GCO 6010 resources//Pear.gcode\n' +
'TESTCUBE.GCO 353194 TESTCUBE.GCO\n' +
'TEST1.GCO 1143935 TEST1.GCO\n' +
'End file list\n' +
'ok'
)
res.send('')
return
}
if (url.indexOf('M20') != -1) {
SendWS(
'echo:SD card ok\n' +
'ok\n' +
'Begin file list\n' +
'V2T-TEST.GCO 569266\n' +
'DFQ-PI~1.GCO 1490254\n' +
'VJ1-TEST.GCO 569266\n' +
'XRP-SU~1.GCO 569266\n' +
'RGW-PI~1.GCO 1490254\n' +
'PIKA2~1.GCO 1635116\n' +
'UJP-PI~1.GCO 1573255\n' +
'CTEST/INDEXH~1.GZ 69111\n' +
'PIKA2.GCO 1635116\n' +
'MACRO1.GCO 19\n' +
'INDEX_~1.GZ 78055\n' +
'GCODE/TESTLO~1.GCO 25\n' +
'GCODE/TESTCUBE.GCO 353194\n' +
'RESOUR~1/GCODE/APPLE~1.GCO 8140\n' +
'RESOUR~1/GCODE/BANANA~1.GCO 7554\n' +
'RESOUR~1/GCODE/CHERRY~1.GCO 6465\n' +
'RESOUR~1/GCODE/PEACH~1.GCO 8467\n' +
'RESOUR~1/GCODE/PEAR~1.GCO 6010\n' +
'TESTCUBE.GCO 353194\n' +
'118.GCO 41\n' +
'TEST1.GCO 1143935\n' +
'End file list\n' +
'ok\n'
)
res.send('')
return
}
if (url.indexOf('M104') != -1) {
const reg_ex_temp = /S([0-9]*\.?[0-9]*)/
const reg_ex_index = /T([0-9])/
const result_target = reg_ex_temp.exec(url)
const result_index = reg_ex_index.exec(url)
console.log(result_target[1], result_index[1])
temperatures['T'][result_index[1]].target = parseFloat(result_target[1])
res.send('')
return
}
if (url.indexOf('M140') != -1) {
const reg_ex_temp = /S([0-9]*\.?[0-9]*)/
const result_target = reg_ex_temp.exec(url)
temperatures['B'][0].target = parseFloat(result_target[1])
res.send('')
return
}
if (url.indexOf('M141') != -1) {
const reg_ex_temp = /S([0-9]*\.?[0-9]*)/
const result_target = reg_ex_temp.exec(url)
temperatures['C'][0].target = parseFloat(result_target[1])
res.send('')
return
}
if (url.indexOf('M30') != -1) {
const name = url.split(' ')
SendWS(
//"Deletion failed, File:" + name[1].substring(1) + ".\n" + "ok\n"
'File deleted:' + name[1].substring(1) + '\n' + 'ok\n'
)
res.send('')
return
}
if (url.indexOf('M27') != -1) {
SendWS('SD printing byte 990/1000\n')
res.send('')
return
}
if (url.indexOf('M31') != -1) {
SendWS('echo:Print time: 12h 15m 13s\n')
res.send('')
return
}
if (url.indexOf('M115') != -1) {
SendWS(
'FIRMWARE_NAME:Marlin 2.0.9.1 (Sep 8 2021 17:07:06) SOURCE_CODE_URL:github.com/MarlinFirmware/Marlin PROTOCOL_VERSION:1.0 MACHINE_TYPE:MRR ESPA EXTRUDER_COUNT:1 UUID:cede2a2f-41a2-4748-9b12-c55c62f367ff\n' +
'Cap:SERIAL_XON_XOFF:0\n' +
'Cap:BINARY_FILE_TRANSFER:0\n' +
'Cap:EEPROM:0\n' +
'Cap:VOLUMETRIC:1\n' +
'Cap:AUTOREPORT_POS:0\n' +
'Cap:AUTOREPORT_TEMP:1\n' +
'Cap:PROGRESS:0\n' +
'Cap:PRINT_JOB:1\n' +
'Cap:AUTOLEVEL:0\n' +
'Cap:RUNOUT:0\n' +
'Cap:Z_PROBE:0\n' +
'Cap:LEVELING_DATA:0\n' +
'Cap:BUILD_PERCENT:0\n' +
'Cap:SOFTWARE_POWER:0\n' +
'Cap:TOGGLE_LIGHTS:0\n' +
'Cap:CASE_LIGHT_BRIGHTNESS:0\n' +
'Cap:EMERGENCY_PARSER:0\n' +
'Cap:HOST_ACTION_COMMANDS:0\n' +
'Cap:PROMPT_SUPPORT:0\n' +
'Cap:SDCARD:1\n' +
'Cap:REPEAT:0\n' +
'Cap:SD_WRITE:1\n' +
'Cap:AUTOREPORT_SD_STATUS:0\n' +
'Cap:LONG_FILENAME:1\n' +
'Cap:THERMAL_PROTECTION:1\n' +
'Cap:MOTION_MODES:0\n' +
'Cap:ARCS:1\n' +
'Cap:BABYSTEPPING:0\n' +
'Cap:CHAMBER_TEMPERATURE:0\n' +
'Cap:COOLER_TEMPERATURE:0\n' +
'Cap:MEATPACK:0\n' +
'ok\n'
)
res.send('')
return
}
if (url.indexOf('M503') != -1) {
let Marlin = 2
if (Marlin == 1)
SendWS(
'echo: G21 ; Units in mm (mm)\n' +
'echo:Filament settings: Disabled\n' +
'echo: M200 D1.75\n' +
'echo: M200 D0\n' +
'echo:Steps per unit:\n' +
'echo: M92 X80.00 Y80.00 Z400.00 E93.00\n' +
'echo:Maximum feedrates (units/s):\n' +
'echo: M203 X500.00 Y500.00 Z5.00 E25.00\n' +
'echo:Maximum Acceleration (units/s2):\n' +
'echo: M201 X500.00 Y500.00 Z100.00 E1000.00\n' +
'echo:Acceleration (units/s2): P<print_accel> R<retract_accel> T<travel_accel>\n' +
'echo: M204 P500.00 R1000.00 T1000.00\n' +
'echo:Advanced: B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate> X<max_x_jerk> Y<max_y_jerk> Z<max_z_jerk> E<max_e_jerk>\n' +
'echo: M205 B20000.00 S0.00 T0.00 X10.00 Y10.00 Z0.30 E5.00\n' +
'echo:Home offset:\n' +
'echo: M206 X0.00 Y0.00 Z0.00\n' +
'echo:Auto Bed Leveling:\n' +
'echo: M420 S0 Z0.00\n' +
'echo: G29 W I0 J0 Z0.35250\n' +
'echo: G29 W I1 J0 Z0.15350\n' +
'echo: G29 W I2 J0 Z0.10850\n' +
'echo: G29 W I0 J1 Z0.08750\n' +
'echo: G29 W I1 J1 Z-0.00100\n' +
'echo: G29 W I2 J1 Z0.02350\n' +
'echo: G29 W I0 J2 Z-0.09000\n' +
'echo: G29 W I1 J2 Z-0.19850\n' +
'echo: G29 W I2 J2 Z-0.16250\n' +
'echo:PID settings:\n' +
'echo: M301 P28.72 I2.62 D78.81\n' +
'echo: M304 P462.10 I85.47 D624.59\n' +
'echo:Power-Loss Recovery:\n' +
'echo: M413 S1\n' +
'echo:Z-Probe Offset (mm):\n' +
'echo: M851 X-45.00 Y-20.00 Z-2.98\n' +
'ok\n'
)
if (Marlin == 2)
SendWS(
'echo:; Linear Units:\n' +
'echo: G21 ; (mm)\n' +
'echo:; Temperature Units:\n' +
'echo: M149 C ; Units in Celsius\n' +
'echo:; Filament settings (Disabled):\n' +
'echo: M200 S0 D1.75\n' +
'echo:; Steps per unit:\n' +
'echo: M92 X80.00 Y80.00 Z400.00 E500.00\n' +
'echo:; Max feedrates (units/s):\n' +
'echo: M203 X300.00 Y300.00 Z5.00 E25.00\n' +
'echo:; Max Acceleration (units/s2):\n' +
'echo: M201 X3000.00 Y3000.00 Z100.00 E10000.00\n' +
'echo:; Acceleration (units/s2) (P<print-accel> R<retract-accel> T<travel-accel>):\n' +
'echo: M204 P3000.00 R3000.00 T3000.00\n' +
'echo:; Advanced (B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate> J<junc_dev>):\n' +
'echo: M205 B20000.00 S0.00 T0.00 J0.01\n' +
'echo:; Home offset:\n' +
'echo: M206 X0.00 Y0.00 Z0.00\n' +
'echo:; Hotend PID:\n' +
'echo: M301 P22.20 I1.08 D114.00\n' +
'echo:; Mesh Insets and leveling settings:\n' +
'echo: C29 L25.00 R205.00 F25.00 B205.00 N9 T60 ; 9x9 T=60°C\n' +
'echo:; Physical minimums:\n' +
'echo: C100 X0 Y0\n' +
'echo:; Physical maximums:\n' +
'echo: C101 X248 Y231 Z250\n' +
'echo:; Bed size:\n' +
'echo: C102 X230 Y230\n' +
'echo:; Max Extruder temperature:\n' +
'echo: C104 T275\n' +
'echo:; Park Head:\n' +
'echo: C125 X240 Y221 Z20\n' +
'echo:; Filament runout sensor:\n' +
'echo: C412 M0 ; Active mode: LOW\n' +
'echo:; Invert Extruder:\n' +
'echo: C562 E0 ; No inverted\n' +
'echo:; Probe Z Speed and Multiple Probing:\n' +
'echo: C851 S480 M2\n' +
'ok\n'
)
res.send('')
return
}
if (url.indexOf('M105') != -1) {
SendWS(Temperatures())
res.send('')
return
}
if (url.indexOf('ESP701') != -1) {
res.json({
cmd: '701',
status: 'ok',
data: {
status: 'processing',
total: '159694',
processed: '6719',
type: '2',
name: '/ESP3DPrintFile.gcode',
},
})
return
}
if (url.indexOf('ESP800') != -1) {
res.json({
cmd: '800',
status: 'ok',
data: {
FWVersion: '3.0.0.a111',
FWTarget: 'marlin',
FWTargetID: '40',
Setup: 'Enabled',
Screen: 'Any screen',
SDConnection: 'direct',
SerialProtocol: SERIAL_PROTOCOL,
Authentication: 'Disabled',
WebCommunication: 'Synchronous',
WebSocketIP: 'localhost',
WebSocketPort: '81',
Hostname: 'esp3d',
WiFiMode: 'STA',
WebUpdate: 'Enabled',
FlashFileSystem: 'LittleFS',
HostPath: '/',
Time: 'none',
CameraID: '4',
CameraName: 'ESP32 Cam',
},
})
return
}
if (url.indexOf('ESP111') != -1) {
res.send('192.168.1.111')
return
}
if (url.indexOf('ESP401') != -1) {
const reg_search1 = /P=(?<pos>[^\s]*)/i
let posres = null
if ((posres = reg_search1.exec(url)) == null) {
console.log('Cannot find P= in url')
}
res.json({
cmd: '401',
status: 'ok',
data: posres.groups.pos ? posres.groups.pos : 'Unknown position',
})
return
}
if (url.indexOf('ESP420') != -1) {
res.json({
cmd: '420',
status: 'ok',
data: [
{ id: 'chip id', value: '18569' },
{ id: 'CPU Freq', value: '240Mhz' },
{ id: 'CPU Temp', value: '54.4C' },
{ id: 'free mem', value: '201.86 KB' },
{ id: 'SDK', value: 'v4.4-beta1-308-gf3e0c8bc41' },
{ id: 'flash size', value: '4.00 MB' },
{ id: 'size for update', value: '1.25 MB' },
{ id: 'FS type', value: 'LittleFS' },
{ id: 'FS usage', value: '64.00 KB/1.44 MB' },
{ id: 'sleep mode', value: 'none' },
{ id: 'wifi', value: 'ON' },
{ id: 'hostname', value: 'esp3d' },
{ id: 'HTTP port', value: '80' },
{ id: 'Telnet port', value: '23' },
{ id: 'sta', value: 'ON' },
{ id: 'mac', value: '24:6F:28:4C:89:48' },
{ id: 'SSID', value: 'luc-ext1' },
{ id: 'signal', value: '60%' },
{ id: 'phy mode', value: '11n' },
{ id: 'channel', value: '3' },
{ id: 'ip mode', value: 'dhcp' },
{ id: 'ip', value: '192.168.2.215' },
{ id: 'gw', value: '192.168.2.1' },
{ id: 'msk', value: '255.255.255.0' },
{ id: 'DNS', value: '192.168.2.1' },
{ id: 'ap', value: 'OFF' },
{ id: 'mac', value: '24:6F:28:4C:89:49' },
{ id: 'notification', value: 'ON (line)' },
{ id: 'sd', value: 'shared (SDFat - 2.1.2)' },
{ id: 'targetfw', value: 'marlin' },
{ id: 'FW ver', value: '3.0.0.a111' },
{ id: 'FW arch', value: 'ESP32' },
{
id: 'language',
value: 'English (default)',
},
],
})
return
}
if (url.indexOf('ESP410') != -1) {
res.json({
cmd: '410',
status: 'ok',
data: [{ SSID: 'luc-ext1', SIGNAL: '52', IS_PROTECTED: '1' }],
})
return
}
if (url.indexOf('ESP600') != -1) {
const text = url.substring(8)
SendWS(text, false)
res.send('')
return
}
if (url.indexOf('ESP400') != -1) {
res.json({
cmd: '400',
status: 'ok',
data: [
{
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' }],
R: '1',
},
{
F: 'network/sta',
P: '1',
T: 'S',
V: 'WIFI_OFFICE_B2G',
S: '32',
H: 'SSID',
M: '1',
R: '1',
},
{
F: 'network/sta',
P: '34',
T: 'S',
N: '1',
V: '********',
S: '64',
H: 'pwd',
M: '0',
MS: '8',
R: '1',
},
{
F: 'network/sta',
P: '99',
T: 'B',
V: '1',
H: 'ip mode',
O: [{ dhcp: '1' }, { static: '0' }],
R: '1',
},
{
F: 'network/sta',
P: '100',
T: 'A',
V: '192.168.0.1',
H: 'ip',
R: '1',
},
{
F: 'network/sta',
P: '108',
T: 'A',
V: '192.168.0.1',
H: 'gw',
R: '1',
},
{
F: 'network/sta',
P: '104',
T: 'A',
V: '255.255.255.0',
H: 'msk',
R: '1',
},
{
F: 'network/ap',
P: '218',
T: 'S',
V: 'ESP3D',
S: '32',
H: 'SSID',
M: '1',
R: '1',
},
{
F: 'network/ap',
P: '251',
T: 'S',
N: '1',
V: '********',
S: '64',
H: 'pwd',
M: '0',
MS: '8',
R: '1',
},
{
F: 'network/ap',
P: '316',
T: 'A',
V: '192.168.0.1',
H: 'ip',
R: '1',
},
{
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' },
],
R: '1',
},
{
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' },
{ 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: '36',
T: 'S',
V: 'default',
H: 'language',
O: [
{
English: 'default',
},
{
Français: 'fr',
},
],
},
],
})
return
}
SendWS('ok\n')
res.send('')
}
const loginURI = (req, res) => {
if (req.body.DISCONNECT == 'YES') {
res.status(401)
logindone = false
} else if (req.body.USER == 'admin' && req.body.PASSWORD == 'admin') {
logindone = true
lastconnection = Date.now()
} else {
res.status(401)
logindone = false
}
res.send('')
}
const configURI = (req, res) => {
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
res.send(
'chip id: 56398\nCPU Freq: 240 Mhz<br/>' +
'CPU Temp: 58.3 C<br/>' +
'free mem: 212.36 KB<br/>' +
'SDK: v3.2.3-14-gd3e562907<br/>' +
'flash size: 4.00 MB<br/>' +
'size for update: 1.87 MB<br/>' +
'FS type: LittleFS<br/>' +
'FS usage: 104.00 KB/192.00 KB<br/>' +
'baud: 115200<br/>' +
'sleep mode: none<br/>' +
'wifi: ON<br/>' +
'hostname: esp3d<br/>' +
'HTTP port: 80<br/>' +
'Telnet port: 23<br/>' +
'WebDav port: 8383<br/>' +
'sta: ON<br/>' +
'mac: 80:7D:3A:C4:4E:DC<br/>' +
'SSID: WIFI_OFFICE_A2G<br/>' +
'signal: 100 %<br/>' +
'phy mode: 11n<br/>' +
'channel: 11<br/>' +
'ip mode: dhcp<br/>' +
'ip: 192.168.1.61<br/>' +
'gw: 192.168.1.1<br/>' +
'msk: 255.255.255.0<br/>' +
'DNS: 192.168.1.1<br/>' +
'ap: OFF<br/>' +
'mac: 80:7D:3A:C4:4E:DD<br/>' +
'serial: ON<br/>' +
'notification: OFF<br/>' +
'Target Fw: marlin<br/>' +
'FW ver: 3.0.0.a91<br/>' +
'FW arch: ESP32 '
)
}
module.exports = {
commandsQuery,
configURI,
loginURI,
getLastconnection,
hasEnabledAuthentication,
}

View File

@@ -0,0 +1,894 @@
/*
index.js - ESP3D WebUI Target file
Copyright (c) 2020 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require("chalk")
const wscolor = chalk.cyan
const expresscolor = chalk.green
const commandcolor = chalk.white
const enableAuthentication = false
let lastconnection = Date.now()
let logindone = false
const sessiontTime = 60000
const roomTemperature = 20
const temperatures = {
T: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
{
value: 20,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
],
B: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.2,
coolspeed: 0.8,
variation: 0.5,
},
],
C: [
{
value: roomTemperature,
target: 0,
lastTime: -1,
heatspeed: 0.6,
coolspeed: 0.8,
variation: 0.5,
},
],
P: [{ value: roomTemperature, sameas: "T", lastTime: -1, variation: 0.5 }], //let say probe is 50% of extruder temperature
R: [{ value: roomTemperature, sameas: "T", lastTime: -1, variation: 1 }], //the redondant is same as extruder 0
M: [{ value: roomTemperature, lastTime: -1, variation: 1 }], //the motherboard is same as room temperature +5/10 degres
}
const updateTemperature = (entry, time) => {
if (entry.lastTime == -1) {
entry.lastTime = time
}
const v = Math.random() * 5
//heater
if (typeof entry.target != "undefined") {
const target = entry.target == 0 ? roomTemperature : entry.target
if (entry.value + 5 < target) {
entry.value =
entry.value + (entry.heatspeed * (time - entry.lastTime)) / 1000
} else if (entry.value - 5 > target) {
entry.value =
entry.value - (entry.coolspeed * (time - entry.lastTime)) / 1000
} else if (target - 2 < entry.value && entry.value < target + 2) {
entry.value = target + entry.variation * (Math.random() - 0.5)
} else if (entry.value < target) {
entry.value =
entry.value +
((entry.heatspeed / 3) * (time - entry.lastTime)) / 1000
} else {
entry.value =
entry.value -
((entry.coolspeed / 3) * (time - entry.lastTime)) / 1000
}
}
//sensor
else if (typeof entry.sameas != "undefined") {
if (
entry.sameas == "T" &&
entry.variation == 0.5 &&
entry.value < 2 * roomTemperature
) {
//probe is same as room temperature if under 40 degres
entry.value =
v > 2.5 ? roomTemperature + v / 2 : roomTemperature - v / 2
} else {
entry.value =
v > 2.5
? temperatures[entry.sameas][0].value * entry.variation +
v / 4
: temperatures[entry.sameas][0].value * entry.variation -
v / 4
}
} else {
entry.value =
v > 2.5 ? roomTemperature + v / 2 : roomTemperature - v / 2
}
entry.lastTime = time
}
function getLastconnection() {
return lastconnection
}
function hasEnabledAuthentication() {
return enableAuthentication
}
function Temperatures() {
Object.keys(temperatures).map((tool) => {
temperatures[tool].map((entry) => {
updateTemperature(entry, new Date())
})
})
const result =
"T:" +
Number(temperatures["T"][0].value).toFixed(2) +
" /" +
Number(temperatures["T"][0].target).toFixed(2) +
" B:" +
Number(temperatures["B"][0].value).toFixed(2) +
" /" +
Number(temperatures["B"][0].target).toFixed(2) +
" T0:" +
Number(temperatures["T"][0].value).toFixed(2) +
" /" +
Number(temperatures["T"][0].target).toFixed(2) +
" T1:" +
Number(temperatures["T"][1].value).toFixed(2) +
" /" +
Number(temperatures["T"][1].target).toFixed(2) +
" @:0 B@:0 @:0\nok\n"
console.log(result)
return result
}
const commandsQuery = (req, res, SendWS) => {
let url = req.query.cmd ? req.query.cmd : req.originalUrl
if (req.query.cmd)
console.log(commandcolor(`[server]/command params: ${req.query.cmd}`))
else console.log(commandcolor(`[server]/command : ${url}`))
if (url.indexOf("PING") != -1) {
lastconnection = Date.now()
res.status(200)
res.send("ok\n")
console.log(commandcolor(`[server]/command :PING`))
return
}
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
if (url.indexOf("M114") != -1) {
let X = Number(Math.random() * 200.12).toFixed(2)
let Y = Number(Math.random() * 200.12).toFixed(2)
let Z = Number(Math.random() * 200.12).toFixed(2)
SendWS(`X:${X} Y:${Y} Z:${Z} E:0.0000\nok\n`)
res.send("")
return
}
if (url.indexOf("SIM:") != -1) {
const response = url.substring(url.indexOf("SIM:") + 4)
SendWS(response + "\n" + "ok\n")
res.send("")
return
}
if (url.indexOf("M205") != -1) {
SendWS(
"EPR:0 1028 0 Language\n" +
"EPR:2 75 230400 Baudrate\n" +
"EPR:0 1125 1 Display Mode:\n" +
"EPR:0 1119 1 Light On:\n" +
"EPR:0 1127 1 Keep Light On:\n" +
"EPR:0 1126 0 Filament Sensor On:\n" +
"EPR:0 1176 0 Top Sensor On:\n" +
"EPR:0 1120 1 Sound On:\n" +
"EPR:0 1177 1 Wifi On:\n" +
"EPR:3 129 16.065 Filament printed [m]\n" +
"EPR:2 125 21576 Printer active [s]\n" +
"EPR:2 79 0 Max. inactive time [ms,0=off]\n" +
"EPR:2 83 360000 Stop stepper after inactivity [ms,0=off]\n" +
"EPR:2 1121 0 Powersave after [ms,0=off]:\n" +
"EPR:3 1160 180.000 Temp Ext PLA:\n" +
"EPR:3 1164 230.000 Temp Ext ABS:\n" +
"EPR:3 1168 60.000 Temp Bed PLA:\n" +
"EPR:3 1172 90.000 Temp Bed ABS:\n" +
"EPR:3 1179 2.000 Load Feed Rate:\n" +
"EPR:3 1183 4.000 Unload Feed Rate:\n" +
"EPR:3 1187 60.000 Unload/Load Distance:\n" +
"EPR:3 3 80.0000 X-axis steps per mm\n" +
"EPR:3 7 80.0000 Y-axis steps per mm\n" +
"EPR:3 11 2560.0000 Z-axis steps per mm\n" +
"EPR:3 15 200.000 X-axis max. feedrate [mm/s]\n" +
"EPR:3 19 200.000 Y-axis max. feedrate [mm/s]\n" +
"EPR:3 23 5.000 Z-axis max. feedrate [mm/s]\n" +
"EPR:3 27 40.000 X-axis homing feedrate [mm/s]\n" +
"EPR:3 31 40.000 Y-axis homing feedrate [mm/s]\n" +
"EPR:3 35 4.000 Z-axis homing feedrate [mm/s]\n" +
"EPR:3 39 20.000 Max. jerk [mm/s]\n" +
"EPR:3 47 0.342 Max. Z-jerk [mm/s]\n" +
"EPR:3 133 0.000 X min pos [mm]\n" +
"EPR:3 137 0.000 Y min pos [mm]\n" +
"EPR:3 141 0.000 Z min pos [mm]\n" +
"EPR:3 145 199.000 X max length [mm]\n" +
"EPR:3 149 204.000 Y max length [mm]\n" +
"EPR:3 153 200.000 Z max length [mm]\n" +
"EPR:3 51 1000.000 X-axis acceleration [mm/s^2]\n" +
"EPR:3 55 1000.000 Y-axis acceleration [mm/s^2]\n" +
"EPR:3 59 100.000 Z-axis acceleration [mm/s^2]\n" +
"EPR:3 63 1000.000 X-axis travel acceleration [mm/s^2]\n" +
"EPR:3 67 1000.000 Y-axis travel acceleration [mm/s^2]\n" +
"EPR:3 71 150.000 Z-axis travel acceleration [mm/s^2]\n" +
"EPR:3 1024 0.000 Coating thickness [mm]\n" +
"EPR:3 1128 100.000 Manual-probe X1 [mm]\n" +
"EPR:3 1132 180.000 Manual-probe Y1 [mm]\n" +
"EPR:3 1136 100.000 Manual-probe X2 [mm]\n" +
"EPR:3 1140 10.000 Manual-probe Y2 [mm]\n" +
"EPR:3 1144 50.000 Manual-probe X3 [mm]\n" +
"EPR:3 1148 95.000 Manual-probe Y3 [mm]\n" +
"EPR:3 1152 150.000 Manual-probe X4 [mm]\n" +
"EPR:3 1156 95.000 Manual-probe Y4 [mm]\n" +
"EPR:3 808 0.280 Z-probe height [mm]\n" +
"EPR:3 929 5.000 Max. z-probe - bed dist. [mm]\n" +
"EPR:3 812 1.000 Z-probe speed [mm/s]\n" +
"EPR:3 840 30.000 Z-probe x-y-speed [mm/s]\n" +
"EPR:3 800 0.000 Z-probe offset x [mm]\n" +
"EPR:3 804 0.000 Z-probe offset y [mm]\n" +
"EPR:3 816 36.000 Z-probe X1 [mm]\n" +
"EPR:3 820 -7.000 Z-probe Y1 [mm]\n" +
"EPR:3 824 36.000 Z-probe X2 [mm]\n" +
"EPR:3 828 203.000 Z-probe Y2 [mm]\n" +
"EPR:3 832 171.000 Z-probe X3 [mm]\n" +
"EPR:3 836 203.000 Z-probe Y3 [mm]\n" +
"EPR:3 1036 0.000 Z-probe bending correction A [mm]\n" +
"EPR:3 1040 0.000 Z-probe bending correction B [mm]\n" +
"EPR:3 1044 0.000 Z-probe bending correction C [mm]\n" +
"EPR:0 880 0 Autolevel active (1/0)\n" +
"EPR:0 106 2 Bed Heat Manager [0-3]\n" +
"EPR:0 107 255 Bed PID drive max\n" +
"EPR:0 124 80 Bed PID drive min\n" +
"EPR:3 108 196.000 Bed PID P-gain\n" +
"EPR:3 112 33.000 Bed PID I-gain\n" +
"EPR:3 116 290.000 Bed PID D-gain\n" +
"EPR:0 120 255 Bed PID max value [0-255]\n" +
"EPR:0 1020 0 Enable retraction conversion [0/1]\n" +
"EPR:3 992 3.000 Retraction length [mm]\n" +
"EPR:3 996 13.000 Retraction length extruder switch [mm]\n" +
"EPR:3 1000 40.000 Retraction speed [mm/s]\n" +
"EPR:3 1004 0.000 Retraction z-lift [mm]\n" +
"EPR:3 1008 0.000 Extra extrusion on undo retract [mm]\n" +
"EPR:3 1012 0.000 Extra extrusion on undo switch retract [mm]\n" +
"EPR:3 1016 20.000 Retraction undo speed\n" +
"EPR:3 200 99.000 Extr.1 steps per mm\n" +
"EPR:3 204 50.000 Extr.1 max. feedrate [mm/s]\n" +
"EPR:3 208 20.000 Extr.1 start feedrate [mm/s]\n" +
"EPR:3 212 5000.000 Extr.1 acceleration [mm/s^2]\n" +
"EPR:0 216 1 Extr.1 heat manager [0-3]\n" +
"EPR:0 217 230 Extr.1 PID drive max\n" +
"EPR:0 245 40 Extr.1 PID drive min\n" +
"EPR:3 218 3.0000 Extr.1 PID P-gain/dead-time\n" +
"EPR:3 222 2.0000 Extr.1 PID I-gain\n" +
"EPR:3 226 40.0000 Extr.1 PID D-gain\n" +
"EPR:0 230 255 Extr.1 PID max value [0-255]\n" +
"EPR:2 231 0 Extr.1 X-offset [steps]\n" +
"EPR:2 235 0 Extr.1 Y-offset [steps]\n" +
"EPR:2 290 0 Extr.1 Z-offset [steps]\n" +
"EPR:1 239 1 Extr.1 temp. stabilize time [s]\n" +
"EPR:1 250 150 Extr.1 temp. for retraction when heating [C]\n" +
"EPR:1 252 0 Extr.1 distance to retract when heating [mm]\n" +
"EPR:0 254 255 Extr.1 extruder cooler speed [0-255]\n" +
"EPR:3 246 0.000 Extr.1 advance L [0=off]\n" +
"EPR:3 300 99.000 Extr.2 steps per mm\n" +
"EPR:3 304 50.000 Extr.2 max. feedrate [mm/s]\n" +
"EPR:3 308 20.000 Extr.2 start feedrate [mm/s]\n" +
"EPR:3 312 5000.000 Extr.2 acceleration [mm/s^2]\n" +
"EPR:0 316 3 Extr.2 heat manager [0-3]\n" +
"EPR:0 317 230 Extr.2 PID drive max\n" +
"EPR:0 345 40 Extr.2 PID drive min\n" +
"EPR:3 318 3.0000 Extr.2 PID P-gain/dead-time\n" +
"EPR:3 322 2.0000 Extr.2 PID I-gain\n" +
"EPR:3 326 40.0000 Extr.2 PID D-gain\n" +
"EPR:0 330 255 Extr.2 PID max value [0-255]\n" +
"EPR:2 331 -2852 Extr.2 X-offset [steps]\n" +
"EPR:2 335 12 Extr.2 Y-offset [steps]\n" +
"EPR:2 390 0 Extr.2 Z-offset [steps]\n" +
"EPR:1 339 1 Extr.2 temp. stabilize time [s]\n" +
"EPR:1 350 150 Extr.2 temp. for retraction when heating [C]\n" +
"EPR:1 352 0 Extr.2 distance to retract when heating [mm]\n" +
"EPR:0 354 255 Extr.2 extruder cooler speed [0-255]\n" +
"EPR:3 346 0.000 Extr.2 advance L [0=off]\n" +
"wait\n"
)
res.send("")
return
}
if (url.indexOf("M206") != -1) {
SendWS("wait\n")
res.send("")
return
}
if (url.indexOf("M104") != -1) {
const reg_ex_temp = /S([0-9]*\.?[0-9]*)/
const reg_ex_index = /T([0-9])/
const result_target = reg_ex_temp.exec(url)
const result_index = reg_ex_index.exec(url)
console.log(result_target[1], result_index[1])
temperatures["T"][result_index[1]].target = parseFloat(result_target[1])
res.send("")
return
}
if (url.indexOf("M140") != -1) {
const reg_ex_temp = /S([0-9]*\.?[0-9]*)/
const result_target = reg_ex_temp.exec(url)
temperatures["B"][0].target = parseFloat(result_target[1])
res.send("")
return
}
if (url.indexOf("M20") != -1) {
SendWS(
"ok 0\n" +
"Begin file list\n" +
"TEST.ZIP 66622272\n" +
"ad_check_0001 2400\n" +
"Machine_Life.dat 0\n" +
"SOUND8.G 992\n" +
"eeprom.bin 4096\n" +
"FW_upgrade.dat 0\n" +
"MYFOLDER/\n" +
"MYFOLDER/sound.g 1040\n" +
"MYFOLDER/Lucdir/\n" +
"M33.G 90\n" +
"M3.G 90\n" +
"SUPPOR~1.GCO 1226740\n" +
"TEST1~1.GCO 113\n" +
"T1.G 21\n" +
"smal.gco 81\n" +
"testgcode.gco 14\n" +
"fr.json 0\n" +
"End file list\n" +
"wait\n"
)
res.send("")
return
}
if (url.indexOf("M32") != -1) {
const name = url.split(" ")
SendWS(
//"Creation failed\n"
"Directory created\n"
)
res.send("")
return
}
if (url.indexOf("M30") != -1) {
const name = url.split(" ")
SendWS(
//"Deletion failed, File:" + name[1].substring(1) + ".\n" + "ok\n"
"File deleted:" + name[1].substring(1) + "\n" + "ok\n"
)
res.send("")
return
}
if (url.indexOf("M115") != -1) {
SendWS(
"FIRMWARE_NAME:Repetier_1.0.4 COMPILED:Apr 30 2022 FIRMWARE_URL:https://github.com/repetier/Repetier-Firmware/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1 REPETIER_PROTOCOL:3\n" +
"Cap:PROGRESS:1\n" +
"Cap:AUTOREPORT_TEMP:1\n" +
"Cap:HOST_RESCUE:1\n" +
"Cap:EEPROM:1\n" +
"Cap:AUTOLEVEL:0\n" +
"Cap:Z_PROBE:0\n" +
"Cap:SOFTWARE_POWER:0\n" +
"Cap:TOGGLE_LIGHTS:0\n" +
"Cap:PAUSESTOP:1\n" +
"Cap:PREHEAT:1\n" +
"Cap:EMERGENCY_PARSER:1\n" +
"Printed filament:0.00m Printing time:0 days 0 hours 0 min\n" +
"PrinterMode:FFF\n" +
"ok\n"
)
res.send("")
return
}
if (url.indexOf("M105") != -1) {
SendWS(Temperatures())
res.send("")
return
}
if (url.indexOf("ESP800") != -1) {
res.json({
cmd: "800",
status: "ok",
data: {
FWVersion: "3.0.0.a111",
FWTarget: "repetier",
FWTargetID: "50",
Setup: "Enabled",
SDConnection: "shared",
SerialProtocol: "Socket",
Authentication: enableAuthentication ? "Enabled" : "Disabled",
WebCommunication: "Synchronous",
WebSocketIP: "localhost",
WebSocketPort: "81",
Hostname: "esp3d",
WiFiMode: "STA",
WebUpdate: "Enabled",
FlashFileSystem: "LittleFS",
HostPath: "/",
Time: "none",
CameraID: "4",
CameraName: "ESP32 Cam",
},
})
return
}
if (url.indexOf("ESP111") != -1) {
res.send("192.168.1.111")
return
}
if (url.indexOf("ESP401") != -1) {
const reg_search1 = /P=(?<pos>[^\s]*)/i
let posres = null
if ((posres = reg_search1.exec(url)) == null) {
console.log("Cannot find P= in url")
}
res.json({
cmd: "401",
status: "ok",
data: posres.groups.pos ? posres.groups.pos : "Unknown position",
})
return
}
if (url.indexOf("ESP420") != -1) {
res.json({
cmd: "420",
status: "ok",
data: [
{ id: "chip id", value: "18569" },
{ id: "CPU Freq", value: "240Mhz" },
{ id: "CPU Temp", value: "54.4C" },
{ id: "free mem", value: "201.86 KB" },
{ id: "SDK", value: "v4.4-beta1-308-gf3e0c8bc41" },
{ id: "flash size", value: "4.00 MB" },
{ id: "size for update", value: "1.25 MB" },
{ id: "FS type", value: "LittleFS" },
{ id: "FS usage", value: "64.00 KB/1.44 MB" },
{ id: "sleep mode", value: "none" },
{ id: "wifi", value: "ON" },
{ id: "hostname", value: "esp3d" },
{ id: "HTTP port", value: "80" },
{ id: "Telnet port", value: "23" },
{ id: "sta", value: "ON" },
{ id: "mac", value: "24:6F:28:4C:89:48" },
{ id: "SSID", value: "luc-ext1" },
{ id: "signal", value: "60%" },
{ id: "phy mode", value: "11n" },
{ id: "channel", value: "3" },
{ id: "ip mode", value: "dhcp" },
{ id: "ip", value: "192.168.2.215" },
{ id: "gw", value: "192.168.2.1" },
{ id: "msk", value: "255.255.255.0" },
{ id: "DNS", value: "192.168.2.1" },
{ id: "ap", value: "OFF" },
{ id: "mac", value: "24:6F:28:4C:89:49" },
{ id: "notification", value: "ON(line)" },
{ id: "sd", value: "shared(SDFat - 2.1.2)" },
{ id: "targetfw", value: "repetier" },
{ id: "FW ver", value: "3.0.0.a111" },
{ id: "FW arch", value: "ESP32" },
],
})
return
}
if (url.indexOf("ESP410") != -1) {
res.json({
cmd: "410",
status: "ok",
data: [{ SSID: "luc-ext1", SIGNAL: "52", IS_PROTECTED: "1" }],
})
return
}
if (url.indexOf("ESP600") != -1) {
const text = url.substring(8)
SendWS(text, false)
res.send("")
return
}
if (url.indexOf("ESP400") != -1) {
res.json({
cmd: "400",
status: "ok",
data: [
{
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" }],
R: "1",
},
{
F: "network/sta",
P: "1",
T: "S",
V: "WIFI_OFFICE_B2G",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/sta",
P: "34",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/sta",
P: "99",
T: "B",
V: "1",
H: "ip mode",
O: [{ dhcp: "1" }, { static: "0" }],
R: "1",
},
{
F: "network/sta",
P: "100",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
F: "network/sta",
P: "108",
T: "A",
V: "192.168.0.1",
H: "gw",
R: "1",
},
{
F: "network/sta",
P: "104",
T: "A",
V: "255.255.255.0",
H: "msk",
R: "1",
},
{
F: "network/ap",
P: "218",
T: "S",
V: "ESP3D",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/ap",
P: "251",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/ap",
P: "316",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
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" },
],
R: "1",
},
{
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: "50",
H: "targetfw",
O: [
{ repetier: "50" },
{ marlin: "20" },
{ 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",
},
],
})
return
}
SendWS("ok\n")
res.send("")
}
const loginURI = (req, res) => {
if (req.body.DISCONNECT == "YES") {
res.status(401)
logindone = false
} else if (req.body.USER == "admin" && req.body.PASSWORD == "admin") {
logindone = true
lastconnection = Date.now()
} else {
res.status(401)
logindone = false
}
res.send("")
}
const configURI = (req, res) => {
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
res.send(
"chip id: 56398\nCPU Freq: 240 Mhz<br/>" +
"CPU Temp: 58.3 C<br/>" +
"free mem: 212.36 KB<br/>" +
"SDK: v3.2.3-14-gd3e562907<br/>" +
"flash size: 4.00 MB<br/>" +
"size for update: 1.87 MB<br/>" +
"FS type: LittleFS<br/>" +
"FS usage: 104.00 KB/192.00 KB<br/>" +
"baud: 115200<br/>" +
"sleep mode: none<br/>" +
"wifi: ON<br/>" +
"hostname: esp3d<br/>" +
"HTTP port: 80<br/>" +
"Telnet port: 23<br/>" +
"WebDav port: 8383<br/>" +
"sta: ON<br/>" +
"mac: 80:7D:3A:C4:4E:DC<br/>" +
"SSID: WIFI_OFFICE_A2G<br/>" +
"signal: 100 %<br/>" +
"phy mode: 11n<br/>" +
"channel: 11<br/>" +
"ip mode: dhcp<br/>" +
"ip: 192.168.1.61<br/>" +
"gw: 192.168.1.1<br/>" +
"msk: 255.255.255.0<br/>" +
"DNS: 192.168.1.1<br/>" +
"ap: OFF<br/>" +
"mac: 80:7D:3A:C4:4E:DD<br/>" +
"serial: ON<br/>" +
"notification: OFF<br/>" +
"Target Fw: repetier<br/>" +
"FW ver: 3.0.0.a91<br/>" +
"FW arch: ESP32 "
)
}
module.exports = {
commandsQuery,
configURI,
loginURI,
getLastconnection,
hasEnabledAuthentication,
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,594 @@
/*
index.js - ESP3D WebUI Target file
Copyright (c) 2020 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
const chalk = require("chalk")
const wscolor = chalk.cyan
const expresscolor = chalk.green
const commandcolor = chalk.white
const enableAuthentication = false
let lastconnection = Date.now()
let logindone = false
const sessiontTime = 60000
let countStatus = 0
function getLastconnection() {
return lastconnection
}
function hasEnabledAuthentication() {
return enableAuthentication
}
const commandsQuery = (req, res, SendWS) => {
let url = req.query.cmd ? req.query.cmd : req.originalUrl
if (req.query.cmd)
console.log(commandcolor(`[server]/command params: ${req.query.cmd}`))
else console.log(commandcolor(`[server]/command : ${url}`))
if (url.indexOf("PING") != -1) {
lastconnection = Date.now()
res.status(200)
res.send("ok\n")
console.log(commandcolor(`[server]/command :PING`))
return
}
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
if (req.query.cmd && req.query.cmd == "?") {
countStatus++
if (countStatus == 1)
SendWS(
"<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0|WCO:0.000,0.000,0.000,1.000,1.000>\n"
)
if (countStatus == 2)
SendWS(
"<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0|Ov:100,100,100>\n"
)
if (countStatus > 2)
SendWS("<Idle|MPos:0.000,0.000,0.000,1.000,1.000|FS:0,0>\n")
if (countStatus == 10) countStatus = 0
res.send("")
return
}
if (url.indexOf("ESP800") != -1) {
res.json({
cmd: "800",
status: "ok",
data: {
FWVersion: "3.0.0.a111",
FWTarget: "grbl",
FWTargetID: "10",
Setup: "Enabled",
SDConnection: "shared",
SerialProtocol: "Socket",
Authentication: "Disabled",
WebCommunication: "Synchronous",
WebSocketIP: "localhost",
WebSocketPort: "81",
Hostname: "esp3d",
WiFiMode: "STA",
WebUpdate: "Enabled",
FlashFileSystem: "LittleFS",
HostPath: "/",
Time: "none",
CameraID: "4",
CameraName: "ESP32 Cam",
},
})
return
}
if (url.indexOf("ESP111") != -1) {
res.send("192.168.1.111")
return
}
if (url.indexOf("ESP401") != -1) {
const reg_search1 = /P=(?<pos>[^\s]*)/i
let posres = null
if ((posres = reg_search1.exec(url)) == null) {
console.log("Cannot find P= in url")
}
res.json({
cmd: "401",
status: "ok",
data: posres.groups.pos ? posres.groups.pos : "Unknown position",
})
return
}
if (url.indexOf("ESP420") != -1) {
res.json({
cmd: "420",
status: "ok",
data: [
{ id: "chip id", value: "18569" },
{ id: "CPU Freq", value: "240Mhz" },
{ id: "CPU Temp", value: "54.4C" },
{ id: "free mem", value: "201.86 KB" },
{ id: "SDK", value: "v4.4-beta1-308-gf3e0c8bc41" },
{ id: "flash size", value: "4.00 MB" },
{ id: "size for update", value: "1.25 MB" },
{ id: "FS type", value: "LittleFS" },
{ id: "FS usage", value: "64.00 KB/1.44 MB" },
{ id: "sleep mode", value: "none" },
{ id: "wifi", value: "ON" },
{ id: "hostname", value: "esp3d" },
{ id: "HTTP port", value: "80" },
{ id: "Telnet port", value: "23" },
{ id: "sta", value: "ON" },
{ id: "mac", value: "24:6F:28:4C:89:48" },
{ id: "SSID", value: "luc-ext1" },
{ id: "signal", value: "60%" },
{ id: "phy mode", value: "11n" },
{ id: "channel", value: "3" },
{ id: "ip mode", value: "dhcp" },
{ id: "ip", value: "192.168.2.215" },
{ id: "gw", value: "192.168.2.1" },
{ id: "msk", value: "255.255.255.0" },
{ id: "DNS", value: "192.168.2.1" },
{ id: "ap", value: "OFF" },
{ id: "mac", value: "24:6F:28:4C:89:49" },
{ id: "notification", value: "ON(line)" },
{ id: "targetfw", value: "grbl" },
{ id: "FW ver", value: "3.0.0.a111" },
{ id: "FW arch", value: "ESP32" },
],
})
return
}
if (url.indexOf("ESP410") != -1) {
res.json({
cmd: "410",
status: "ok",
data: [{ SSID: "luc-ext1", SIGNAL: "52", IS_PROTECTED: "1" }],
})
return
}
if (url.indexOf("$$") != -1) {
SendWS(
"$0=3\n" +
"$1=250\n" +
"$2=0\n" +
"$3=0\n" +
"$4=0\n" +
"$5=1\n" +
"$6=0\n" +
"$10=1\n" +
"$11=0.010\n" +
"$12=0.002\n" +
"$13=0\n" +
"$20=0\n" +
"$21=0\n" +
"$22=0\n" +
"$23=3\n" +
"$24=200.000\n" +
"$25=2000.000\n" +
"$26=250\n" +
"$27=1.000\n" +
"$30=1000.000\n" +
"$31=0.000\n" +
"$32=0\n" +
"$100=100.000\n" +
"$101=100.000\n" +
"$102=100.000\n" +
"$103=100.000\n" +
"$104=100.000\n" +
"$105=100.000\n" +
"$110=1000.000\n" +
"$111=1000.000\n" +
"$112=1000.000\n" +
"$113=1000.000\n" +
"$114=1000.000\n" +
"$115=1000.000\n" +
"$120=200.000\n" +
"$121=200.000\n" +
"$122=200.000\n" +
"$123=200.000\n" +
"$124=200.000\n" +
"$125=200.000\n" +
"$130=300.000\n" +
"$131=300.000\n" +
"$132=300.000\n" +
"$133=300.000\n" +
"$134=300.000\n" +
"$135=300.000\n" +
"ok\n"
)
res.send("")
return
}
if (url.indexOf("ESP600") != -1) {
const text = url.substring(8)
SendWS(text, false)
return
}
if (url.indexOf("ESP400") != -1) {
res.json({
cmd: "400",
status: "ok",
data: [
{
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" }],
R: "1",
},
{
F: "network/sta",
P: "1",
T: "S",
V: "WIFI_OFFICE_B2G",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/sta",
P: "34",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/sta",
P: "99",
T: "B",
V: "1",
H: "ip mode",
O: [{ dhcp: "1" }, { static: "0" }],
R: "1",
},
{
F: "network/sta",
P: "100",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
F: "network/sta",
P: "108",
T: "A",
V: "192.168.0.1",
H: "gw",
R: "1",
},
{
F: "network/sta",
P: "104",
T: "A",
V: "255.255.255.0",
H: "msk",
R: "1",
},
{
F: "network/ap",
P: "218",
T: "S",
V: "ESP3D",
S: "32",
H: "SSID",
M: "1",
R: "1",
},
{
F: "network/ap",
P: "251",
T: "S",
N: "1",
V: "********",
S: "64",
H: "pwd",
M: "0",
MS: "8",
R: "1",
},
{
F: "network/ap",
P: "316",
T: "A",
V: "192.168.0.1",
H: "ip",
R: "1",
},
{
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" },
],
R: "1",
},
{
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: "10",
H: "targetfw",
O: [
{ repetier: "50" },
{ marlin: "20" },
{ 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",
},
],
})
return
}
SendWS("ok\n")
res.send("")
}
const loginURI = (req, res) => {
if (req.body.DISCONNECT == "YES") {
res.status(401)
logindone = false
} else if (req.body.USER == "admin" && req.body.PASSWORD == "admin") {
logindone = true
lastconnection = Date.now()
} else {
res.status(401)
logindone = false
}
res.send("")
}
const configURI = (req, res) => {
if (!logindone && enableAuthentication) {
res.status(401)
return
}
lastconnection = Date.now()
res.send(
"chip id: 56398\nCPU Freq: 240 Mhz<br/>" +
"CPU Temp: 58.3 C<br/>" +
"free mem: 212.36 KB<br/>" +
"SDK: v3.2.3-14-gd3e562907<br/>" +
"flash size: 4.00 MB<br/>" +
"size for update: 1.87 MB<br/>" +
"FS type: LittleFS<br/>" +
"FS usage: 104.00 KB/192.00 KB<br/>" +
"baud: 115200<br/>" +
"sleep mode: none<br/>" +
"wifi: ON<br/>" +
"hostname: esp3d<br/>" +
"HTTP port: 80<br/>" +
"Telnet port: 23<br/>" +
"WebDav port: 8383<br/>" +
"sta: ON<br/>" +
"mac: 80:7D:3A:C4:4E:DC<br/>" +
"SSID: WIFI_OFFICE_A2G<br/>" +
"signal: 100 %<br/>" +
"phy mode: 11n<br/>" +
"channel: 11<br/>" +
"ip mode: dhcp<br/>" +
"ip: 192.168.1.61<br/>" +
"gw: 192.168.1.1<br/>" +
"msk: 255.255.255.0<br/>" +
"DNS: 192.168.1.1<br/>" +
"ap: OFF<br/>" +
"mac: 80:7D:3A:C4:4E:DD<br/>" +
"serial: ON<br/>" +
"notification: OFF<br/>" +
"Target Fw: grbl<br/>" +
"FW ver: 3.0.0.a91<br/>" +
"FW arch: ESP32 "
)
}
module.exports = {
commandsQuery,
configURI,
loginURI,
getLastconnection,
hasEnabledAuthentication,
}

87
config/webpack.dev.js Normal file
View File

@@ -0,0 +1,87 @@
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
let target = process.env.TARGET_ENV ? process.env.TARGET_ENV : "Printer3D";
let subtarget = process.env.SUBTARGET_ENV
? process.env.SUBTARGET_ENV
: "Marlin";
console.log("Target:", target, " Subtarget:", subtarget);
module.exports = {
resolve: {
alias: {
TargetDir: path.resolve(__dirname, "../src/targets", target),
SubTargetDir: path.resolve(
__dirname,
"../src/targets",
target,
subtarget
),
},
},
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,
static: {
directory: path.resolve(__dirname, "server", "public"),
},
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 MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// all options are optional
filename: "[name].css",
chunkFilename: "[id].css",
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, "../src/index.html"),
inlineSource: ".(js|css)$",
inject: true,
}),
], // automatically creates a 'index.html' for us with our <link>, <style>, <script> tags inserted! Visit https://github.com/jantimon/html-webpack-plugin for more options
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: {
presets: ["preact"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{ loader: "style-loader" },
{
loader: "css-loader",
options: {
sourceMap: true,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
},
],
},
};

110
config/webpack.prod.js Normal file
View File

@@ -0,0 +1,110 @@
const path = require("path")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const HtmlMinimizerPlugin = require("html-minimizer-webpack-plugin")
const HtmlInlineScriptPlugin = require("html-inline-script-webpack-plugin")
const HTMLInlineCSSWebpackPlugin =
require("html-inline-css-webpack-plugin").default
const Compression = require("compression-webpack-plugin")
let target = process.env.TARGET_ENV ? process.env.TARGET_ENV : "Printer3D"
let subtarget = process.env.SUBTARGET_ENV ? process.env.SUBTARGET_ENV : "Marlin"
module.exports = {
resolve: {
alias: {
TargetDir: path.resolve(__dirname, "../src/targets", target),
SubTargetDir: path.resolve(
__dirname,
"../src/targets",
target,
subtarget
),
},
},
mode: "production", // this trigger webpack out-of-box prod optimizations
entry: path.resolve(__dirname, "../src/index.js"),
output: {
filename: `[name].[hash].js`, // [hash] is useful for cache busting!
path: path.resolve(__dirname, "../build"),
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: "css-loader",
options: {
sourceMap: false,
},
},
{
loader: "sass-loader",
options: {
sourceMap: false,
},
},
],
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: ["preact"],
},
},
],
},
],
},
plugins: [
// always deletes the dist folder first in each build run.
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css",
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, "../src/index.html"),
inlineSource: ".(js|css)$",
inject: "body",
}),
new HtmlInlineScriptPlugin({
scriptMatchPattern: [/.+[.]js$/],
htmlMatchPattern: [/index.html$/],
}),
new HTMLInlineCSSWebpackPlugin(),
new Compression({
test: /\.(html)$/,
filename:
"[path]../dist/" + target + "/" + subtarget + "/[base].gz",
algorithm: "gzip",
exclude: /.map$/,
deleteOriginalAssets: "keep-source-map",
}),
],
optimization: {
minimize: true,
minimizer: [
new HtmlMinimizerPlugin({
minimizerOptions: {
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true,
},
minify: (data, minimizerOptions) => {
const htmlMinifier = require("html-minifier-terser")
const [[filename, input]] = Object.entries(data)
return htmlMinifier.minify(input, minimizerOptions)
},
}),
],
},
devtool: "source-map", // supposedly the ideal type without bloating bundle size
}

BIN
dist/CNC/GRBL/index.html.gz vendored Normal file

Binary file not shown.

BIN
dist/CNC/GRBLHal/index.html.gz vendored Normal file

Binary file not shown.

BIN
dist/Plotter/HP-GL/index.html.gz vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
dist/Printer3D/Marlin/index.html.gz vendored Normal file

Binary file not shown.

BIN
dist/Printer3D/Repetier/index.html.gz vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
dist/SandTable/GRBL/index.html.gz vendored Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

3
esp3d.todo Normal file
View File

@@ -0,0 +1,3 @@
TODO:ESP3D
- Add MS in [ESP400] @done
- Add R in [ESP400] @done

646
extensions_samples/API.md Normal file
View File

@@ -0,0 +1,646 @@
# Extension API
## Basic code
```
<script type="text/javascript">
//Send message to web ui
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
//Process Message coming from webUI
function processMessage(eventMsg){
//now process eventMsg.data
}
//Setup message listener from webUI
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
};
</script>
<div class="container">
Display your HTML here
</div>
```
As you can see code is minimal - it will fit a Frame, webui css / theme will be added by webUI after loaded, so you do not need to add any, you can use any of existing class available in webUI.
Communication between frame and main window is done by messages using objects (string / array based), do not use any object that could ne be cloned or loading will fail.
---
### Send message
message structure used by `window.parent.postMessage(msg, '*');` has a defined format, some parameters are madatories, some are optionals and some depend on message type:
`{type:'<message type>', target:'webui', id:'[origin]', noDispatch:[true], XXX:YYY}`
`<message type>` is mandatory, it define the purpose of the message
`target:'webui'` is mandatory, it help to screen the message
`id:'[origin]'` is optionnal, it define which id must read the response if any, if present it can be used by extension to filter message, no id means the message is for everyone
`noDispatch:[true]` is optionnal, if true it will prevent to send answer if any, if not or set to false, it will send answer message if any
`XXX:YYY` are optionals/mandatories according message type
---
### Send GCODE command or ESP command
Example: `{type:'cmd', target:'webui',id:'terminal', content:'[ESP111]'}`
**type** is `cmd` (mandatory)
**target** is `webui` (mandatory)
**id** is `terminal` (optional)
**content** is the command that need to be sent, in our case `[ESP111]` (mandatory)
Note: there is no `noDispatch:true` so answer, if any from ESP firmware, will be sent
Note 2: there is no way to prevent the answer to be spread if it come from external board from serial, even if `id` and `noDispatch` are set
* Answer format: check the `eventMsg.data`
- if success
```
{
"type": "cmd",
"content": {
"status": "success"
"response": "192.168.1.111",
"initiator": {
"content":"[ESP111]",
"id":"terminal",
"target":"webui",
"type":"cmd",
}
},
"id": "terminal"
}
```
**type** is `cmd`
**id** is the id set in command message to help to screen
**content** has the response's **status** which is `success`, the response it self **response**, in our case `192.168.1.111` and also the **initiator** is the initial command for reference
- if error
```
{
"type": "cmd",
"content": {
"status": "error",
"error":"Cannot connect",
"initiator": {
"content":"[ESP111]",
"id":"terminal",
"target":"webui",
"type":"cmd",
}
},
"id":"terminal"
}
```
**type** is `error` for any error command
**id** is the id set in command message to help to screen
**content** has the response's **status** which is `error`, and the error it self **error**, in our case `Cannot connect` and also the **initiator** is the initial command for reference
---
### Send web query
Example: `{type:'query', target:'webui', id:'filemanager', url:'files', args:{action:'list', path:'/'}}`
**type** is `query` (mandatory)
**target** is `webui` (mandatory)
**id** is `terminal` (optional)
**url** is the base url in our case `files` for `/files` (mandatory)
**args** is the set of arguments url in our case `{action:'list', path:'/'}` for `/files?action=list&path=/` (optional for query)
Note: `noDispatch:true` and `id:'term'` are applicable in this case if needed
* Answer format: check the `eventMsg.data`
- if success
```
{
"type": "query",
"response": {
"status": "success",
"response": "{\"files\":[{\"name\":\"config.yaml\",\"size\":\"1.55 KB\"}],\"path\":\"/\",\"occupation\":\"35\",\"status\":\"ok\",\"total\":\"1.31 MB\",\"used\":\"470.08 KB\"}",
"initiator": {
"type": "query",
"target": "webui",
"id": "filemanager",
"url": "files",
"args": {
"action": "list",
"path": "/"
}
}
},
"id": "filemanager"
}
```
**type** is `query`
**id** is the id set in output message to help to screen
**content** has the response's **status** which is `success`, the response it self **response**, in our case a JSON, and also the **initiator** is the initial command for reference
- if error
```
{
"type": "query",
"response": {
"status": "error",
"error": "Cannot connect",
"initiator": {
"type": "query",
"target": "webui",
"id": "filemanager",
"url": "files",
"args": {
"action": "list",
"path": "/"
}
}
},
"id": "filemanager"
}
```
**type** is `query`
**id** is the id set in output message to help to screen
**content** has the response's **status** which is `error`, and the error it self **error**, in our case `Cannot connect` and also the **initiator** is the initial command for reference
---
### Send web upload
Example: `{type:'upload', target:'webui', id:'filemanager', url:'files', content:[...],size:500, path:"/", filename:'file.txt'}`
**type** is `upload` (mandatory)
**target** is `webui` (mandatory)
**id** is `filemanager` (optional)
**url** is the base url in our case `files` for `/files` (mandatory for upload)
**content** is the file in an array object (mandatory)
**size** is the file size (mandatory)
**path** is the file target path (not including name) (mandatory)
**size** is the filename (not including path) (mandatory)
**args** is an object with optional arguments like for query, they are no used in post but in url itself
Note: `noDispatch:true` and `id:'filemanager'` are applicable in this case if needed
* Answer format: check the `eventMsg.data`
for upload the initiator does not contain the file content
- if success
```
{
"type": "upload",
"response": {
"status": "success",
"response": "{\"files\":[{\"name\":\"config.yaml\",\"size\":\"1.55 KB\"},{\"name\":\"file.txt\",\"size\":\"500B\"}],\"path\":\"/\",\"occupation\":\"35\",\"status\":\"ok\",\"total\":\"1.31 MB\",\"used\":\"470.08 KB\"}",
"initiator": {
"type":"upload",
"target":"webui",
"id":"filemanager",
"url":"files",
"size":500,
"path":"/",
"filename":"file.txt"
}
},
"id": "filemanager"
}
```
**type** is `upload`
**id** is the id set in output message to help to screen
**content** has the response's **status** which is `success`, the response it self **response**, in our case a JSON, and also the **initiator** is the initial command for reference but without the file content
- progression message
```
{
"type": "upload",
"response": {
"status": "progress",
"progress": "100",
"initiator": {
"type":"upload",
"target":"webui",
"id":"filemanager",
"url":"files",
"size":500,
"path":"/",
"filename":"file.txt"
}
},
"id": "filemanager"
}
```
**type** is `upload`
**id** is the id set in output message to help to screen
**content** has the response's **status** which is `progress`, and the progression it self **progress**, in our case `100` = 100% and also the **initiator** is the initial command for reference but without the file content
- if error
```
{
"type": "upload",
"response": {
"status": "error",
"error": "Cannot connect",
"initiator": {
"type":"upload",
"target":"webui",
"id":"filemanager",
"url":"files",
"size":500,
"path":"/",
"filename":"file.txt"
}
},
"id": "filemanager"
}
```
**type** is `upload`
**id** is the id set in output message to help to screen
**content** has the response's **status** which is `error`, and the error it self **error**, in our case `Cannot connect` and also the **initiator** is the initial command for reference but without the file content
---
### Send webdownload request
Example: `{type:'download', target:'webui', id:'filemanager', url:'preferences.json'}`
**type** is `download` (mandatory)
**target** is `webui` (mandatory)
**id** is `filemanager` (optional)
**url** is the url of the file in our case `preferences.json` for `/preferences.json` (mandatory)
**args** is an object with optional arguments like for query
Note: `id:'filemanager'` is applicable in this case if needed, but not `noDispatch:true` as the purpose is to get response
* Answer format: check the `eventMsg.data`
- if success
```
{
"type": "download",
"response": {
"status": "success",
"response": [...],
"initiator": {
"type":"download",
"target":"webui",
"id":"filemanager",
"url":"preferences.json",
}
},
"id": "filemanager"
}
```
**type** is `upload`
**id** is the id set in output message to help to screen
**content** has the response's **status** which is `success`, the response it self **response**, in our case a blob which is the file that need to be read properly, and also the **initiator** is the initial command for reference
- progression message
```
{
"type": "upload",
"response": {
"status": "progress",
"progress": "100",
"initiator": {
"type":"upload",
"target":"webui",
"id":"filemanager",
"url":"preferences.json",
}
},
"id": "filemanager"
}
```
**type** is `download`
**id** is the id set in output message to help to screen
**content** has the response's **status** which is `progress`, and the progression it self **progress**, in our case `100` = 100% and also the **initiator** is the initial command for reference
- if error
```
{
"type": "download",
"response": {
"status": "error",
"error": "404",
"initiator": {
"type":"upload",
"target":"webui",
"id":"filemanager",
"url":"preferences.json",
}
},
"id": "filemanager"
}
```
**type** is `download`
**id** is the id set in output message to help to screen
**content** has the response's **status** which is `error`, and the error it self **error**, in our case `404` (file not found) and also the **initiator** is the initial command for reference
---
### Send sound notification
There is no answer for this message, so `id` is not necessary
- Generate a beep notification
Example: `{type:'sound', target:'webui', content:'beep'}`
**type** is `` (mandatory)
**target** is `webui` (mandatory)
**sound** is the sound type, in our case `beep` (mandatory)
- Generate a beep error notification
Example: `{type:'sound', target:'webui', content:'error'}`
**type** is `` (mandatory)
**target** is `webui` (mandatory)
**sound** is the sound type, in our case `error` (mandatory)
- Generate a beep sequence notification
Example: `{type:'sound', target:'webui', content:'beep', seq:[{ f: 1046, d: 200 },{ f: 1318, d: 100 }]}`
**type** is `` (mandatory)
**target** is `webui` (mandatory)
**sound** is the sound type, in our case `seq` (mandatory)
**seq** is an array of sequence of beep, in our case `[{ f: 1046, d: 200 },{ f: 1318, d: 100 }]` (mandatory), `f` is frequency and `d` is duration of the beep
---
### Send toast notification
There is no answer for this message, so `id` is not necessary
- Generate a success toast notification
Example: `{type:'toast', target:'webui', content:{text:'This is a success', type:'success'}}`
**type** is `` (mandatory)
**target** is `webui` (mandatory)
**content** has the toast **type**, in our case `success`, and the **text** to display, in ou case `This is a success` (mandatory)
- Generate an error toast notification
Example: `{type:'toast', target:'webui', content:{text:'This is an error', type:'error'}}`
**type** is `` (mandatory)
**target** is `webui` (mandatory)
**content** has the toast **type**, in our case `error`, and the **text** to display, in ou case `This is an error` (mandatory)
- Generate a normal toast notification
Example: `{type:'toast', target:'webui', content:{text:'This is a toast', type:'default'}}`
**type** is `` (mandatory)
**target** is `webui` (mandatory)
**content** has the toast **type**, in our case `default`, and the **text** to display, in ou case `This is a toast` (mandatory)
---
### Send translation request
- simple translation
Example: `{type:'translate', target:'webui', id:'transpanel', content:'S153'}`
**type** is `translate` (mandatory)
**target** is `webui` (mandatory)
**id** is `transpanel` (optional)
**content** is the text that need to be translated, in our case `S153` (mandatory)
* Answer format: check the `eventMsg.data`
```
{
"type": "translate",
"content": {
"response": "Your session will end soon, do you want to stay connected ?",
"initiator": {
"type":"translate",
"target":"webui",
"id":"transpanel",
"content":"S153"
}
},
"id": "transpanel"
}
```
**type** is `translate`
**id** is the id set in command message to help to screen
**content** has the response it self **response**, in our case `Your session will end soon, do you want to stay connected ?` and also the **initiator** is the initial command for reference
- full dump of translations
Example: `{type:'translate', target:'webui', id:'transpanel', all:'true'}`
**type** is `translate` (mandatory)
**target** is `webui` (mandatory)
**id** is `transpanel` (optional)
**all** to take all translations (mandatory)
* Answer format: check the `eventMsg.data`
```
{
"type": "translate",
"content": {
"response": "Your session will end soon, do you want to stay connected ?",
"initiator": {
"type":"translate",
"target":"webui",
"id":"transpanel",
"content":[....]
}
},
"id": "transpanel"
}
```
**type** is `translate`
**id** is the id set in command message to help to screen
**content** has the response it self **response**, in our case an array of all translations and also the **initiator** is the initial command for reference
---
### Send capabilities request
Example: `{type:'capabilities', target:'webui', id:'transpanel'}`
**type** is `capabilities` (mandatory)
**target** is `webui` (mandatory)
**id** is `infopanel` (optional)
* Answer format: check the `eventMsg.data`
```
{
"type": "capabilities",
"content": {
"response": "Your session will end soon, do you want to stay connected ?",
"initiator": {
"type":"capabilities",
"target":"webui",
"id":"infopanel"
}
},
"id": "infopanel"
}
```
**type** is `capabilities`
**id** is the id set in command message to help to screen
**content** has the response it self **response**, in our case a JSON and also the **initiator** is the initial command for reference
---
### Dispatch message to other extensions
Example: `{type:'dispatch', target:'webui', id:'senderpanel', content:'any message' , targetid:'receiverpanel'}`
**type** is `dispatch` (mandatory)
**target** is `webui` (mandatory)
**id** is `senderpanel` (optional)
**content** the message to dispatch using
Note: there no answer as the purpose of this is to send answer
---
### Send Modal dialog display request
- Simple modal
Example: `{type:'modal', target:'webui', id:'modalpanel', content:{title:'This is tile', id:'simple_modal', style:'default', bt1Txt:'S126', response1:'ok', text:'some text', overlay:true}}`
**type** is `modal` (mandatory)
**target** is `webui` (mandatory)
**id** is `modalpanel` (optional)
**content** is modal deescription:
- **title** of the modal (mandatory), `This is tile` is used as example but you better use predefined text that could be translated
- **id** is modal id (mandatory), here `simple_modal`
- **style** is modal style (mandatory), for simple modal it is `default`,
- **bt1Txt** is the text to show on button 1 (optional), `S126` will be translated as `Ok`, if not defined button won't be displayed
- **response1** is the message sent if button 1 is clicked (optional), here `ok`, the click close the modal
- **bt2Txt** is the text to show on button 2 (optional), if not defined button won't be displayed
- **response2** is the message sent if button 2 is clicked (optional), the click close the modal
- **hideclose** if set and true it will hide the cross button to close the modal (optional)
- **overlay** if set and true it will automatically close modal if modal loose focus (optional)
- **text** display the text in modal, if it is predefined's one it will be translated (optional)
Note: close button and overlay feature won't send any notification when modal is closed, be aware of it
* Answer format: check the `eventMsg.data`
```
{
"type": "modal",
"content": {
"response": "ok",
"initiator": {
type:'modal',
target:'webui',
id:'modalpanel',
content : {
"title":"This is tile",
"id":"simple_modal",
"style":"default",
"bt1Txt":"S126",
"response1":"ok",
"text":"some text",
"overlay":true
}
}
},
"id": "modalpanel"
}
```
**type** is `modal`
**id** is the id set in command message to help to screen
**content** has the response it self **response**, in our case `ok` because only one button, and also the **initiator** is the initial command for reference
- Confirmation modal
Example: `{type:'modal', target:'webui', id:'modalpanel', content:{title:'S26', id:'confirm_modal',style:'question',bt1Txt:'S27', response1:'yes',bt2Txt:'S28', response2:'cancel', text:'S30',hideclose:true}}`
**type** is `modal` (mandatory)
**target** is `webui` (mandatory)
**id** is `modalpanel` (optional)
**content** is modal deescription:
- **title** of the modal (mandatory), `S26` will be translated as `Please Confirm`
- **id** is modal id (mandatory), here `confirmation_modal`
- **style** is modal style (mandatory), for confirmation modal it is `question`,
- **bt1Txt** is the text to show on button 1 (optional), here `S27` will be translated as `Yes`, if not defined button won't be displayed
- **response1** is the message sent if button 1 is clicked (optional), here `yes`, the click close the modal
- **bt2Txt** is the text to show on button 2 (optional), here `S28` will be translated as `Cancel`, if not defined button won't be displayed
- **response2** is the message sent if button 2 is clicked (optional), here `cancel`, the click close the modal
- **hideclose** if set and true it will hide the cross button to close the modal (optional)
- **overlay** if set and true it will automatically close modal if modal loose focus (optional)
- **text** display the text in moda (optional), here `S30` will be translated as`Do you want to update?`
Note: close button and overlay feature won't send any notification when modal is closed, be aware of it
* Answer format: check the `eventMsg.data`
```
{
"type": "modal",
"content": {
"response": "yes",
"initiator": {
type:'modal',
target:'webui',
id:'modalpanel',
content : {
"title":"S26",
"id":"confirmation_modal",
"style":"question",
"bt1Txt":"S27",
"response1":"yes",
"bt2Txt":"S28",
"response2":"cancel",
"text":"S30",
"hideclose":true
}
}
},
"id": "modalpanel"
}
```
**type** is `modal`
**id** is the id set in command message to help to screen
**content** has the response it self **response**, in our case `yes` because user clicked on button 1, and also the **initiator** is the initial command for reference
- Input modal
Example: `{type:'modal', target:'webui', id:'modalpanel', content:{title:'S90', id:'input_modal',style:'input',bt1Txt:'S106', response1:'create',bt2Txt:'S28', response2:'cancel', text:'S104',hideclose:true}}`
**type** is `modal` (mandatory)
**target** is `webui` (mandatory)
**id** is `modalpanel` (optional)
**content** is modal deescription:
- **title** of the modal (mandatory), `S90` will be translated as `Create Directory`
- **id** is modal id (mandatory), here `inputmodal`
- **style** is modal style (mandatory), for input modal it is `input`,
- **bt1Txt** is the text to show on button 1 (optional), here `S106` will be translated as `Create`, if not defined button won't be displayed
- **response1** is the message sent if button 1 is clicked (optional), here `create`, the click close the modal
- **bt2Txt** is the text to show on button 2 (optional), here `S28` will be translated as `Cancel`, if not defined button won't be displayed
- **response2** is the message sent if button 2 is clicked (optional), here `cancel`, the click close the modal
- **hideclose** if set and true it will hide the cross button to close the modal (optional)
- **overlay** if set and true it will automatically close modal if modal loose focus (optional)
- **text** display the text in moda (optional), here `S104` will be translated as`Please type directory name`
Note: close button and overlay feature won't send any notification when modal is closed, be aware of it
* Answer format: check the `eventMsg.data`
```
{
"type": "modal",
"content": {
"response": "create",
"inputData": "mydir"
"initiator": {
type:'modal',
target:'webui',
id:'modalpanel',
content : {
"title":"S90",
"id":"input_modal",
"style":"input",
"bt1Txt":"S106",
"response1":"create",
"bt2Txt":"S28",
"response2":"cancel",
"text":"S104",
"hideclose":true
}
}
},
"id": "modalpanel"
}
```
**type** is `modal`
**id** is the id set in command message to help to screen
**content** has the response it self **response**, in our case `create` because user clicked on button 1, and the text entered is in **inputData**, here `mydir`, and also the **initiator** is the initial command for reference
Note: **inputData** is present for both buttons clicked, so screening must be done according response

View File

@@ -0,0 +1,30 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
function processMessage(eventMsg){
if (eventMsg.data.type && (!eventMsg.data.id||eventMsg.data.id=="infopanel")){
if (eventMsg.data.type=="capabilities"){
const line = eventMsg.data.content
const resultPanel = document.getElementById("output");
resultPanel.innerHTML = resultPanel.innerHTML + "<br>"+ JSON.stringify(line.response, " ", "<br>")+"</span><br><hr />";
}
}
}
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
}
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'capabilities', target:'webui', id:'infopanel',});">Capabilities</button>
<div class="container m-2" id="output">
</div>
</div>

View File

@@ -0,0 +1,28 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
function processMessage(eventMsg){
if (eventMsg.data.type && (!eventMsg.data.id||eventMsg.data.id=="panel")){
if (eventMsg.data.type=="dispatch"){
const line = eventMsg.data.content
const resultPanel = document.getElementById("output");
resultPanel.innerHTML = resultPanel.innerHTML + "<br> this messsage is from "+ line.initiator.id+ " <span class='text-primary'>"+ line.response+"</span><br><hr />";
}
}
}
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
}
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'dispatch', target:'webui', id:'panel', targetid:'panel',content:'this is a broadcasted message'});">Dispatch</button>
<div class="container m-2" id="output">
</div>
</div>

View File

@@ -0,0 +1,60 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
function processMessage(eventMsg){
if (eventMsg.data.type && (!eventMsg.data.id||eventMsg.data.id=="downloadpanel")){
if (eventMsg.data.type=="download"){
const line = eventMsg.data.content
if (line.status=="success"){
//it is text so we can read it
var reader = new FileReader();
reader.onload = function() {
//it is text display it
const resultPanel = document.getElementById("output");
resultPanel.innerHTML += "<br>" + reader.result + "<hr>"
}
reader.readAsText(eventMsg.data.content.response);
//we ca also save it localy
if (window.navigator.msSaveOrOpenBlob)
// IE10+
window.navigator.msSaveOrOpenBlob(eventMsg.data.content.response, eventMsg.data.content.initiato.url);
else {
// Others
const a = document.createElement("a");
const url = URL.createObjectURL(eventMsg.data.content.response);
a.href = url;
a.download = eventMsg.data.content.initiator.url;
a.onload = () => {
URL.revokeObjectURL(a.href);
};
document.body.appendChild(a);
a.click();
setTimeout(function () {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
}
if (line.status=="error"){
//TBD
}
}
}
}
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
};
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'download', target:'webui',id:'downloadpanel',url:'preferences.json'});">Download preferences.json</button>
<div class="container m-2" id="output">
</div>
</div>

View File

@@ -0,0 +1,32 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
function processMessage(eventMsg){
if (eventMsg.data.type && (!eventMsg.data.id||eventMsg.data.id=="modalpanel")){
if (eventMsg.data.type=="modal"){
const line = eventMsg.data.content;
const resultPanel = document.getElementById("output");
resultPanel.innerHTML += "<br><span class='text-bold'>"+line.initiator.content.id+"</span> modal sent <span class='text-primary'>"+ line.response+"</span><br>";
if (line.response == "create" && line.inputData) resultPanel.innerHTML += "Text entered is <span class='text-primary'>"+ line.inputData+"</span><br>";
resultPanel.innerHTML += "<hr>";
}
}
}
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
}
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'modal', target:'webui', id:'modalpanel', content:{title:'This is tile', id:'simple_modal',style:'default',bt1Txt:'S126', response1:'ok', text:'some text', overlay:true}});">Simple Modal</button>
<button class="btn m-1" onclick="sendMessage({type:'modal', target:'webui', id:'modalpanel', content:{title:'S26', id:'confirm_modal',style:'question',bt1Txt:'S27', response1:'yes',bt2Txt:'S28', response2:'cancel', text:'S30',hideclose:true}});">Confirmation Modal</button>
<button class="btn m-1" onclick="sendMessage({type:'modal', target:'webui', id:'modalpanel', content:{title:'S90', id:'input_modal',style:'input',bt1Txt:'S106', response1:'create',bt2Txt:'S28', response2:'cancel', text:'S104',hideclose:true}});">Input Modal</button>
<div class="container m-2" id="output">
</div>
</div>

View File

@@ -0,0 +1,33 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
function processMessage(eventMsg){
if (eventMsg.data.type && (!eventMsg.data.id||eventMsg.data.id=="querypanel")){
if (eventMsg.data.type=="query"){
const line = eventMsg.data.content
if (line.status=="success"){
const resultPanel = document.getElementById("output");
resultPanel.innerHTML = resultPanel.innerHTML + "<br>" + line.response.replace("\n", "<br/>") + "<hr />";
}
if (line.status=="error"){
//TBD
}
}
}
}
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
};
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'query', target:'webui', id:'querypanel', url:'files', args:{action:'list', path:'/'}});">List Files</button>
<div class="container m-2" id="output">
</div>
</div>

View File

@@ -0,0 +1,14 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'sound', target:'webui', content:'beep'});">Beep</button>
<button class="btn m-1" onclick="sendMessage({type:'sound', target:'webui', content:'error'});">Beep Error</button>
<button class="btn m-1" onclick="sendMessage({type:'sound', target:'webui', content:'seq', seq:[{ f: 1046, d: 200 },{ f: 1318, d: 100 }]});">Beep Sequence</button>
</div>

View File

@@ -0,0 +1,49 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
if (msg.type=="cmd"){
const resultPanel = document.getElementById("terminal");
resultPanel.innerHTML = resultPanel.innerHTML + "<br>" + msg.content.replace("\n", "<br/>").replace("\r", "") ;
resultPanel.scrollTop = resultPanel.scrollHeight
}
}
function processMessage(eventMsg){
if (eventMsg.data.type && (!eventMsg.data.id||eventMsg.data.id=="terminal")){
if (eventMsg.data.type=="cmd"){
const line = eventMsg.data.content
if (line.status=="success"){
const resultPanel = document.getElementById("terminal");
resultPanel.innerHTML = resultPanel.innerHTML + "<br>" + line.response.replace("\n", "<br/>") ;
resultPanel.scrollTop = resultPanel.scrollHeight
}
if (line.status=="error"){
//TBD
}
}
}
}
function sendCommand(){
sendMessage({type: "cmd", target: "webui", id: "terminal",content: document.getElementById("command").value});
document.getElementById('command').value='';
}
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
};
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'cmd', target:'webui', id:'terminal',content:'[ESP111]'});">[ESP111]</button>
<div class="input-group">
<input type="text" class="form-input" id="command" />
<button class="btn btn-black input-group-btn" onclick="sendCommand()">Send</button>
</div>
<div class="container m-2">
<pre id="terminal" class="bg-primary p-2" style="min-height: 200px;"></pre>
</div>
</div>

View File

@@ -0,0 +1,14 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'toast', target:'webui', content:{text:'This is an error', type:'error'}});">Error Toast</button>
<button class="btn m-1" onclick="sendMessage({type:'toast', target:'webui', content:{text:'This is a success', type:'success'}});">Success Toast</button>
<button class="btn m-1" onclick="sendMessage({type:'toast', target:'webui', content:{text:'This is a toast', type:'default'}});">Classic Toast</button>
</div>

View File

@@ -0,0 +1,34 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
function processMessage(eventMsg){
if (eventMsg.data.type && (!eventMsg.data.id||eventMsg.data.id=="translatepanel")){
if (eventMsg.data.type=="translate"){
const line = eventMsg.data.content
const resultPanel = document.getElementById("output");
if (line.initiator.all){
resultPanel.innerHTML = resultPanel.innerHTML + "<br>All translations:<br>" + JSON.stringify(line.response," ", "<br>")+"<br><hr />";
} else {
resultPanel.innerHTML = resultPanel.innerHTML + "<br>" + line.initiator.content + " is translated <span class='text-primary'>"+ line.response+"</span><br><hr />";
}
}
}
}
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
}
</script>
<div class="container">
<button class="btn m-1" onclick="sendMessage({type:'translate', target:'webui', id:'translatepanel', content:'S153'});">Translate `S153`</button>
<button class="btn m-1" onclick="sendMessage({type:'translate', target:'webui', id:'translatepanel', all:'true'});">Dump all translation array</button>
<div class="container m-2" id="output">
</div>
</div>

View File

@@ -0,0 +1,45 @@
<script type="text/javascript">
function sendMessage(msg){
window.parent.postMessage(msg, '*');
}
function processMessage(eventMsg){
if (eventMsg.data.type && (!eventMsg.data.id||eventMsg.data.id=="uploadpanel")){
if (eventMsg.data.type=="upload"){
const line = eventMsg.data.content
if (line.status=="success"){
const resultPanel = document.getElementById("output");
resultPanel.innerHTML = resultPanel.innerHTML + "<br>" + line.initiator.filename + " is uploaded<br><hr />";
}
if (line.status=="error"){
//TBD
}
}
}
}
function uploadFile(){
const files = document.getElementById("uploadBtn").files
if (files.length>0){
const reader = new FileReader();
reader.onload = function (e) {
sendMessage({type:'upload', target:"webui", id:'uploadpanel', url:"files", content:e.target.result,size:e.target.result.byteLength, path:"/", filename:files[0].name});
document.getElementById("uploadBtn").value="";
}
reader.readAsArrayBuffer(files[0]);
}
};
window.onload = (event) => {
window.addEventListener("message", processMessage, false);
};
</script>
<div class="container">
<button class="btn m-1" onclick="document.getElementById('uploadBtn').click();">Upload</button>
<input type="file" class="d-none" id="uploadBtn" onChange="uploadFile()" />
<div class="container m-2" id="output">
</div>
</div>

View File

@@ -1,334 +0,0 @@
var gulp = require('gulp'),
jshint = require('gulp-jshint'),
gulpif = require('gulp-if'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
cleanCSS = require('gulp-clean-css'),
removeCode = require('gulp-remove-code'),
merge = require('merge-stream'),
del = require('del'),
zip = require('gulp-zip'),
gzip = require('gulp-gzip'),
htmlmin = require('gulp-htmlmin'),
replace = require('gulp-replace'),
fs = require('fs'),
smoosher = require('gulp-smoosher');
size = require('gulp-filesize');
var en_lang = true;
var fr_lang = false;
var es_lang = false;
var de_lang = false;
var it_lang = false;
var ja_lang = false;
var pl_lang = false;
var ptbr_lang = false;
var ru_lang = false;
var uk_lang = false;
var zh_cn_lang = false;
var hu_lang = false;
var tr_lang = false;
var zh_tw_lang = false;
function clean() {
return del(['dist']);
}
function clean2() {
return del(['dist/js', 'dist/css']);
}
function lint() {
return gulp.src('www/js/**/app.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
}
function Copytest() {
return merge(
gulp.src(['www/index.html'])
.pipe(removeCode({production: false}))
.pipe(removeCode({cleanheader: true}))
.pipe(gulp.dest('dist')),
gulp.src(['www/images/**/*.*'])
.pipe(gulp.dest('dist/images'))
)
}
function Copy() {
return merge(
gulp.src(['www/index.html'])
.pipe(removeCode({production: true}))
.pipe(removeCode({cleanheader: true}))
.pipe(gulp.dest('dist')),
gulp.src(['www/images/**/*.*'])
.pipe(gulp.dest('dist/images'))
)
}
function concatApptest() {
return merge(
gulp.src([ 'www/js/**/*.js'])
.pipe(concat('app.js'))
.pipe(removeCode({production: false}))
.pipe(removeCode({cleanheader: true}))
.pipe(gulp.dest('./dist/js')),
gulp.src([ 'www/css/**/*.css'])
.pipe(concat('style.css'))
.pipe(gulp.dest('./dist/css/'))
)
}
function concatApp() {
return merge(
gulp.src([ 'www/js/**/*.js'])
.pipe(concat('app.js'))
.pipe(removeCode({production: true}))
.pipe(removeCode({cleanheader: true}))
.pipe(gulp.dest('./dist/js')),
gulp.src([ 'www/css/**/*.css'])
.pipe(concat('style.css'))
.pipe(gulp.dest('./dist/css/'))
)
}
function replaceSVG() {
return gulp.src('dist/index.html')
.pipe(replace(/<!-- replaceSVG -->(.*?)<!-- \/replaceSVG -->/g, function (match, p1) {
return fs.readFileSync('dist/images/jogdial.svg', 'utf8');
}))
.pipe(gulp.dest('dist'))
}
function clearlang() {
// fetch command line arguments
console.log("Enable Language:");
const arg = (argList => {
let arg = {}, a, opt, thisOpt, curOpt;
for (a = 0; a < argList.length; a++) {
thisOpt = argList[a].trim();
opt = thisOpt.replace(/^\-+/, '');
if (opt === thisOpt) {
// argument value
if (curOpt) arg[curOpt] = opt;
curOpt = null;
}
else {
// argument name
curOpt = opt;
arg[curOpt] = true;
}
}
return arg;
})(process.argv);
if ((arg.lang == 'grbl') ) {
en_lang = true;
fr_lang = true;
es_lang = true;
de_lang = true;
it_lang = true;
ja_lang = false;
hu_lang = false;
pl_lang = true;
ptbr_lang = true;
ru_lang = true;
tr_lang = false;
uk_lang = true;
zh_cn_lang = false;
}
if ((typeof arg.lang == 'undefined') || (arg.lang == 'all')) {
en_lang = true;
fr_lang = true;
es_lang = true;
de_lang = true;
it_lang = true;
ja_lang = true;
hu_lang = true;
pl_lang = true;
ptbr_lang = true;
ru_lang = true;
tr_lang = true;
uk_lang = true;
zh_cn_lang = true;
zh_tw_lang = true;
}
if (arg.lang == 'en'){
en_lang = true;
}
if(en_lang){
console.log("en");
}
if (arg.lang == 'fr'){
fr_lang = true;
}
if(fr_lang){
console.log("fr");
}
if (arg.lang == 'es'){
es_lang = true;
}
if(es_lang){
console.log("es");
}
if (arg.lang == 'de'){
de_lang = true;
}
if(de_lang){
console.log("de");
}
if (arg.lang == 'it'){
it_lang = true;
}
if (arg.lang == 'ja'){
ja_lang = true;
}
if(hu_lang){
console.log("hu");
}
if (arg.lang == 'hu'){
hu_lang = true;
}
if(it_lang){
console.log("it");
}
if(ja_lang){
console.log("ja");
}
if (arg.lang == 'pl'){
pl_lang = true;
}
if(pl_lang){
console.log("pl");
}
if (arg.lang == 'ptbr'){
ptbr_lang = true;
}
if(ptbr_lang){
console.log("ptbr");
}
if (arg.lang == 'ru'){
ru_lang = true;
}
if(ru_lang){
console.log("ru");
}
if (arg.lang == 'tr'){
tr_lang = true;
}
if(tr_lang){
console.log("tr");
}
if (arg.lang == 'uk'){
uk_lang = true;
}
if(uk_lang){
console.log("uk");
}
if (arg.lang == 'zh_CN'){
zh_cn_lang = true;
}
if(zh_cn_lang){
console.log("zh_CN");
}
if (arg.lang == 'zh_TW'){
zh_tw_lang = true;
}
if(zh_tw_lang){
console.log("zh_TW");
}
return gulp.src('dist/js/app.js')
.pipe(removeCode({de_lang_disabled: !de_lang}))
.pipe(removeCode({en_lang_disabled: !en_lang}))
.pipe(removeCode({es_lang_disabled: !es_lang}))
.pipe(removeCode({fr_lang_disabled: !fr_lang}))
.pipe(removeCode({it_lang_disabled: !it_lang}))
.pipe(removeCode({ja_lang_disabled: !ja_lang}))
.pipe(removeCode({hu_lang_disabled: !hu_lang}))
.pipe(removeCode({pl_lang_disabled: !pl_lang}))
.pipe(removeCode({ptbr_lang_disabled: !ptbr_lang}))
.pipe(removeCode({ru_lang_disabled: !ru_lang}))
.pipe(removeCode({tr_lang_disabled: !tr_lang}))
.pipe(removeCode({uk_lang_disabled: !uk_lang}))
.pipe(removeCode({zh_cn_lang_disabled: !zh_cn_lang}))
.pipe(removeCode({zh_tw_lang_disabled: !zh_tw_lang}))
.pipe(gulp.dest('./dist/js/'))
}
function minifyApp() {
return merge(
gulp.src(['dist/js/app.js'])
.pipe(uglify({mangle: true}))
.pipe(gulp.dest('./dist/js/')),
gulp.src('dist/css/style.css')
.pipe(cleanCSS({debug: true}, function(details) {
console.log(details.name + ': ' + details.stats.originalSize);
console.log(details.name + ': ' + details.stats.minifiedSize);
}))
.pipe(gulp.dest('./dist/css/')),
gulp.src('dist/index.html')
.pipe(htmlmin({collapseWhitespace: true, minifyCSS: true}))
.pipe(gulp.dest('dist'))
)
}
function includehtml() {
return merge(
gulp.src('dist/index.html')
.pipe(replace(/<file-include w3-include-html="'sub\/(.*?)'"><\/file-include>/g, function (match, p1) {
return fs.readFileSync('www/sub/' + p1, 'utf8');
}))
.pipe(gulp.dest('dist/'))
)
}
function smoosh() {
return gulp.src('dist/index.html')
.pipe(smoosher())
.pipe(gulp.dest('dist'))
}
function compress() {
return gulp.src('dist/index.html')
.pipe(gzip({ gzipOptions: { level: 9} }))
.pipe(gulp.dest('.'))
.pipe(size());
}
gulp.task(clean);
gulp.task(lint);
gulp.task(Copy);
gulp.task(Copytest);
gulp.task(replaceSVG);
gulp.task(concatApp);
gulp.task(concatApptest);
gulp.task(minifyApp);
gulp.task(smoosh);
gulp.task(clean2);
gulp.task(clearlang)
var defaultSeries = gulp.series(clean, lint, Copy, concatApp, minifyApp, includehtml, includehtml, smoosh);
//var packageSeries = gulp.series(clean, lint, Copy, concatApp, minifyApp, smoosh, compress);
var packageSeries = gulp.series(clean, lint, Copy, concatApp, includehtml, includehtml, replaceSVG, clearlang, minifyApp, smoosh, compress, clean2);
var package2Series = gulp.series(clean, lint, Copy, concatApp, includehtml, includehtml, replaceSVG, smoosh);
var package2testSeries = gulp.series(clean, lint, Copytest, concatApptest, includehtml, includehtml, replaceSVG, smoosh);
gulp.task('default', defaultSeries);
gulp.task('package', packageSeries);
gulp.task('package2', package2Series);
gulp.task('package2test', package2testSeries);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

11
images/esp3d.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 283.5 283.5">
<path fill="white" d="m 227,91.9 -97,-0.3 0,100.4 83,0 c 20,0 46,-6 47,-36 l 0,-24 c 1,-20 -13,-40 -33,-40.1 z" />
<path d="M79.7,200.2h124c-15.5,16.5-37.6,26.7-62,26.7S95.3,216.7,79.7,200.2z"/>
<path d="M203.7,83.2h-124c15.5-16.5,37.6-26.7,62-26.7S188.2,66.8,203.7,83.2z"/>
<path d="M200.3,152.7c0,2.7-0.5,5-1.5,7.1s-2.4,3.8-4.2,5.2c-1.8,1.4-4,2.5-6.5,3.2c-2.5,0.7-5.3,1.1-8.3,1.1c-1.8,0-3.5-0.1-5.1-0.4c-1.6-0.3-3-0.6-4.2-1c-1.2-0.4-2.2-0.8-3-1.2c-0.8-0.4-1.3-0.7-1.6-0.9c-0.2-0.2-0.4-0.5-0.6-0.7c-0.1-0.3-0.2-0.6-0.3-1c-0.1-0.4-0.2-0.8-0.2-1.4c0-0.6-0.1-1.2-0.1-2c0-1.3,0.1-2.2,0.3-2.7c0.2-0.5,0.5-0.8,1-0.8c0.3,0,0.7,0.2,1.4,0.6c0.7,0.4,1.5,0.8,2.6,1.2c1,0.4,2.3,0.8,3.7,1.2c1.4,0.4,3,0.6,4.8,0.6c1.5,0,2.8-0.2,4-0.5c1.2-0.4,2.1-0.9,2.9-1.5c0.8-0.6,1.4-1.4,1.8-2.3c0.4-0.9,0.6-1.9,0.6-3.1c0-1.2-0.2-2.3-0.7-3.3c-0.5-1-1.2-1.8-2.1-2.5c-0.9-0.7-2.1-1.2-3.6-1.6c-1.4-0.4-3.1-0.6-5.1-0.6h-4.6c-0.4,0-0.7,0-0.9-0.1c-0.2-0.1-0.5-0.3-0.6-0.6c-0.2-0.3-0.3-0.7-0.3-1.3c-0.1-0.5-0.1-1.2-0.1-2.1c0-0.8,0-1.4,0.1-2c0.1-0.5,0.2-0.9,0.3-1.2c0.2-0.3,0.3-0.5,0.6-0.6c0.2-0.1,0.5-0.2,0.8-0.2h4.6c1.6,0,3-0.2,4.2-0.6c1.2-0.4,2.3-0.9,3.1-1.6c0.8-0.7,1.5-1.5,1.9-2.5c0.4-1,0.7-2,0.7-3.2c0-0.9-0.2-1.8-0.5-2.6c-0.3-0.8-0.7-1.5-1.3-2.1c-0.6-0.6-1.3-1.1-2.3-1.4c-0.9-0.3-2-0.5-3.3-0.5c-1.4,0-2.8,0.2-4,0.6c-1.3,0.4-2.4,0.9-3.4,1.4c-1,0.5-1.8,1-2.5,1.4c-0.7,0.4-1.2,0.7-1.5,0.7c-0.2,0-0.4,0-0.6-0.1c-0.2-0.1-0.3-0.3-0.4-0.6c-0.1-0.3-0.2-0.7-0.2-1.2c-0.1-0.5-0.1-1.2-0.1-2c0-0.7,0-1.3,0-1.7c0-0.5,0.1-0.8,0.2-1.1c0.1-0.3,0.2-0.6,0.3-0.8c0.1-0.2,0.3-0.5,0.6-0.7c0.3-0.3,0.8-0.7,1.7-1.2c0.8-0.5,1.9-1,3.2-1.5c1.3-0.5,2.8-0.9,4.5-1.3c1.7-0.3,3.5-0.5,5.5-0.5c2.6,0,4.9,0.3,6.8,0.9c2,0.6,3.7,1.5,5,2.6c1.4,1.1,2.4,2.5,3.1,4.2c0.7,1.7,1,3.5,1,5.6c0,1.6-0.2,3.1-0.6,4.5c-0.4,1.4-1,2.6-1.8,3.7c-0.8,1.1-1.8,2-3,2.8c-1.2,0.8-2.6,1.3-4.1,1.7v0.1c1.9,0.2,3.5,0.7,5,1.4c1.5,0.7,2.7,1.6,3.8,2.7c1,1.1,1.8,2.3,2.4,3.7C200,149.7,200.3,151.2,200.3,152.7z"/>
<path d="M249.6,141c0,4.9-0.6,9-1.9,12.5c-1.3,3.5-3.1,6.3-5.5,8.5c-2.4,2.2-5.3,3.8-8.7,4.8c-3.4,1-7.5,1.5-12.2,1.5h-12.7c-0.9,0-1.7-0.3-2.3-0.8c-0.6-0.5-0.9-1.4-0.9-2.6v-46.4c0-1.2,0.3-2.1,0.9-2.6c0.6-0.5,1.4-0.8,2.3-0.8h13.6c4.7,0,8.8,0.6,12.1,1.7c3.3,1.1,6.1,2.8,8.3,4.9c2.3,2.2,4,4.9,5.2,8.1C249,133,249.6,136.7,249.6,141z M238.5,141.3c0-2.5-0.3-4.9-0.9-7c-0.6-2.2-1.5-4-2.8-5.6c-1.3-1.6-3-2.8-5-3.7c-2-0.9-4.7-1.3-8-1.3h-5.5v36.2h5.6c3,0,5.5-0.4,7.5-1.2c2-0.8,3.7-1.9,5.1-3.5c1.4-1.5,2.4-3.5,3-5.8C238.1,147.1,238.5,144.4,238.5,141.3z"/>
<path d="M222.1,90.3h-34.9H61.4c-21.5,0-39,17.5-39,39v24.9c0,21.5,17.5,39,39,39h68.4h92.3c21.5,0,39-17.5,39-39v-24.9C261.1,107.8,243.6,90.3,222.1,90.3z M155.1,179.4c5-7,4.9-16.5,4.9-16.5v-42.5c0-15,12.2-27.2,27.2-27.2h34.9c19.8,0,36,16.1,36,36v24.9c0,19.8-16.1,36-36,36h-79.2C142.9,190.2,149.6,187.2,155.1,179.4z"/>
<path fill="white" d="M69.7,164.1c0,0.8,0,1.5-0.1,2c-0.1,0.5-0.2,1-0.3,1.3c-0.1,0.3-0.3,0.6-0.5,0.7c-0.2,0.2-0.4,0.2-0.7,0.2H41.4c-0.9,0-1.7-0.3-2.3-0.8c-0.6-0.5-0.9-1.4-0.9-2.6v-46.4c0-1.2,0.3-2.1,0.9-2.6c0.6-0.5,1.4-0.8,2.3-0.8H68c0.2,0,0.5,0.1,0.7,0.2c0.2,0.1,0.4,0.4,0.5,0.7c0.1,0.3,0.2,0.8,0.3,1.3c0.1,0.5,0.1,1.2,0.1,2c0,0.8,0,1.4-0.1,2c-0.1,0.5-0.2,1-0.3,1.3c-0.1,0.3-0.3,0.6-0.5,0.7c-0.2,0.2-0.4,0.2-0.7,0.2H49v13H65c0.2,0,0.5,0.1,0.7,0.2c0.2,0.2,0.4,0.4,0.5,0.7c0.1,0.3,0.2,0.7,0.3,1.3c0.1,0.5,0.1,1.2,0.1,2c0,0.8,0,1.5-0.1,2c-0.1,0.5-0.2,0.9-0.3,1.3c-0.1,0.3-0.3,0.5-0.5,0.7c-0.2,0.1-0.4,0.2-0.7,0.2H49v15h19.2c0.2,0,0.5,0.1,0.7,0.2c0.2,0.2,0.4,0.4,0.5,0.7c0.1,0.3,0.2,0.8,0.3,1.3C69.7,162.6,69.7,163.3,69.7,164.1z"/>
<path fill="white" d="M109.4,152.4c0,2.8-0.5,5.2-1.6,7.4c-1,2.1-2.5,3.9-4.2,5.3c-1.8,1.4-3.9,2.5-6.2,3.2c-2.4,0.7-4.9,1.1-7.6,1.1c-1.8,0-3.5-0.2-5.1-0.5c-1.6-0.3-3-0.7-4.2-1.1c-1.2-0.4-2.2-0.9-3-1.3c-0.8-0.5-1.4-0.9-1.7-1.2c-0.4-0.4-0.6-0.9-0.8-1.5c-0.2-0.7-0.2-1.6-0.2-2.9c0-0.8,0-1.6,0.1-2.1c0.1-0.6,0.1-1,0.3-1.4c0.1-0.4,0.3-0.6,0.5-0.8c0.2-0.2,0.4-0.2,0.7-0.2c0.4,0,0.9,0.2,1.6,0.7c0.7,0.5,1.6,1,2.7,1.5c1.1,0.5,2.4,1,3.9,1.5c1.5,0.5,3.3,0.7,5.3,0.7c1.3,0,2.5-0.2,3.5-0.5c1-0.3,1.9-0.8,2.7-1.3c0.7-0.6,1.3-1.3,1.7-2.1c0.4-0.8,0.6-1.8,0.6-2.8c0-1.2-0.3-2.2-1-3.1c-0.7-0.9-1.5-1.6-2.6-2.3c-1.1-0.7-2.3-1.3-3.6-1.9c-1.3-0.6-2.7-1.2-4.2-1.9c-1.4-0.7-2.8-1.4-4.2-2.2c-1.3-0.8-2.5-1.8-3.6-3c-1.1-1.2-1.9-2.5-2.6-4.1c-0.7-1.6-1-3.5-1-5.7c0-2.5,0.5-4.8,1.4-6.7c0.9-1.9,2.2-3.5,3.8-4.8c1.6-1.3,3.5-2.2,5.7-2.9c2.2-0.6,4.5-0.9,6.9-0.9c1.3,0,2.5,0.1,3.8,0.3c1.3,0.2,2.4,0.5,3.5,0.8c1.1,0.3,2.1,0.7,2.9,1.1c0.8,0.4,1.4,0.8,1.7,1c0.3,0.3,0.5,0.5,0.6,0.7c0.1,0.2,0.2,0.4,0.2,0.8c0.1,0.3,0.1,0.7,0.1,1.2c0,0.5,0,1.1,0,1.8c0,0.8,0,1.5-0.1,2c0,0.5-0.1,1-0.2,1.4c-0.1,0.4-0.2,0.6-0.4,0.8c-0.2,0.2-0.4,0.2-0.7,0.2c-0.3,0-0.8-0.2-1.4-0.6c-0.7-0.4-1.5-0.8-2.4-1.3c-1-0.5-2.1-0.9-3.3-1.2c-1.3-0.4-2.6-0.6-4.2-0.6c-1.2,0-2.2,0.1-3.1,0.4c-0.9,0.3-1.6,0.7-2.2,1.2c-0.6,0.5-1,1.1-1.3,1.8c-0.3,0.7-0.4,1.5-0.4,2.3c0,1.2,0.3,2.2,1,3.1c0.6,0.9,1.5,1.6,2.6,2.3c1.1,0.7,2.3,1.3,3.7,1.9c1.4,0.6,2.8,1.2,4.2,1.9c1.4,0.7,2.8,1.4,4.2,2.2c1.4,0.8,2.6,1.8,3.7,3c1.1,1.2,1.9,2.5,2.6,4.1C109.1,148.4,109.4,150.2,109.4,152.4z"/>
<path fill="white" d="M151.4,131.2c0,3-0.5,5.6-1.4,7.9c-0.9,2.3-2.3,4.2-4.1,5.8c-1.8,1.6-4,2.8-6.6,3.6c-2.6,0.8-5.6,1.2-9.1,1.2h-4.4v17c0,0.3-0.1,0.5-0.3,0.7c-0.2,0.2-0.5,0.4-0.9,0.5c-0.4,0.1-1,0.2-1.6,0.3c-0.7,0.1-1.6,0.1-2.6,0.1c-1,0-1.9,0-2.6-0.1c-0.7-0.1-1.3-0.2-1.7-0.3c-0.4-0.1-0.7-0.3-0.9-0.5c-0.2-0.2-0.2-0.5-0.2-0.7v-47.8c0-1.3,0.3-2.3,1-2.9c0.7-0.6,1.6-1,2.7-1h12.5c1.3,0,2.5,0,3.6,0.1c1.1,0.1,2.5,0.3,4.1,0.6c1.6,0.3,3.2,0.9,4.8,1.7c1.6,0.8,3,1.9,4.2,3.2c1.2,1.3,2,2.8,2.6,4.6C151.1,127.1,151.4,129,151.4,131.2z M140.1,132c0-1.9-0.3-3.4-1-4.6c-0.7-1.2-1.5-2.1-2.4-2.7c-1-0.6-2-0.9-3-1.1c-1.1-0.2-2.1-0.2-3.3-0.2h-4.6v18h4.8c1.7,0,3.2-0.2,4.3-0.7c1.2-0.5,2.1-1.1,2.9-2c0.7-0.8,1.3-1.8,1.7-3C139.9,134.6,140.1,133.3,140.1,132z"/>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

1
images/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 158 KiB

1
images/logob&W.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1,69 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1669.71px" height="495.161px" viewBox="0 0 1669.71 495.161" enable-background="new 0 0 1669.71 495.161"
xml:space="preserve">
<path fill="#E71F19" d="M327.458,329.786c1.844,0.75,3.516,2.328,5,4.734s2.234,5.094,2.234,8.063v47.266
c0,2.234-0.75,4.094-2.234,5.578s-3.156,2.219-5,2.219c-0.75,0-1.391-0.094-1.953-0.281s-1.203-0.453-1.938-0.828L107.224,271.958
c-0.75-0.375-1.391-0.656-1.953-0.844s-1.016-0.281-1.391-0.281c-2.219,0-4.078,0.75-5.563,2.234s-2.219,3.156-2.219,5v30.031
c0,9.281,2.313,17.531,6.953,24.75c4.625,7.234,9.734,11.969,15.297,14.188l216.344,124.578
c-26.328,11.5-56.172,17.234-89.547,17.234c-44.125,0-84.453-10.844-120.969-32.531c-36.531-21.688-65.625-50.688-87.313-87.031
s-32.531-76.75-32.531-121.25c0-33.359,7.219-65.516,21.688-96.484c14.453-30.969,37.813-61.828,70.078-92.609v111.797
c0,9.266,2.313,17.422,6.953,24.469c4.625,7.047,9.734,11.688,15.297,13.906L327.458,329.786z"/>
<path fill="#E71F19" d="M155.615,24.458c26.688-11.484,56.531-17.234,89.531-17.234c44.484,0,84.984,10.844,121.516,32.531
c36.516,21.688,65.625,50.703,87.313,87.047s32.547,76.75,32.547,121.234c0,33.375-7.328,65.547-21.969,96.5
c-14.656,30.969-38.109,62.016-70.359,93.156V325.349c0-9.266-2.234-17.422-6.672-24.469c-4.453-7.047-9.641-11.688-15.578-13.906
L163.396,166.286c-1.859-0.734-3.625-2.313-5.281-4.719c-1.672-2.406-2.5-5.109-2.5-8.078v-47.266c0-2.219,0.734-4.078,2.219-5.563
c1.469-1.484,3.328-2.234,5.563-2.234c0.359,0,0.813,0.094,1.375,0.281s1.391,0.469,2.516,0.844l215.781,125.125
c0.75,0.375,1.484,0.563,2.234,0.563c0.734,0,1.297,0,1.672,0c1.844,0,3.5-0.734,4.984-2.219s2.234-3.156,2.234-5.016v-30.031
c0-9.266-2.234-17.516-6.672-24.75c-4.453-7.219-9.641-11.953-15.578-14.188L155.615,24.458z"/>
<polygon points="576.052,101.771 722.333,101.771 722.333,154.052 638.896,154.052 638.896,202.989 716.208,202.989
716.208,256.942 638.896,256.942 638.896,476.614 576.052,370.396 "/>
<polygon points="734.568,101.771 801.849,101.771 827.989,186.864 854.13,101.771 921.989,101.771 860.802,256.38 860.802,370.396
796.302,370.396 796.302,256.38 "/>
<polygon points="933.661,279.177 990.942,279.177 990.942,286.974 992.067,303.646 994.833,315.333 996.505,318.661
1005.958,326.458 1013.755,327.567 1026.536,323.677 1029.317,320.333 1034.88,309.208 1035.442,301.989 1033.208,291.411
1027.099,280.849 1016.536,270.833 1007.083,264.161 1000.396,259.724 997.614,257.489 981.489,246.927 969.255,237.474
959.239,229.13 952.567,221.896 950.349,219.114 943.677,207.442 940.333,197.427 937.552,184.63 937.005,170.739 937.552,155.724
940.896,142.364 945.896,130.692 952.567,120.13 957.021,115.677 967.036,107.88 978.161,101.771 990.396,97.88 1004.849,95.646
1013.192,95.646 1028.771,96.208 1042.677,98.989 1054.911,103.442 1065.474,109.552 1072.708,115.114 1080.489,124.567
1086.599,135.146 1090.505,147.927 1092.724,162.396 1093.286,171.849 1092.724,176.286 1092.724,180.739 1036.552,180.739
1036.552,177.411 1034.88,162.396 1030.989,151.271 1030.989,150.708 1020.974,142.927 1014.864,141.817 1002.63,146.255
1000.958,147.927 995.958,160.161 995.396,165.177 997.614,174.067 1004.302,184.083 1015.411,194.083 1025.989,201.317
1034.333,206.88 1041.005,211.333 1056.021,221.349 1068.255,230.239 1077.146,238.583 1083.271,246.364 1089.38,258.599
1092.161,267.505 1094.396,280.302 1094.942,293.083 1094.396,308.099 1092.161,322.005 1087.724,334.802 1081.599,345.364
1074.364,354.817 1064.911,363.161 1054.349,369.286 1042.114,373.724 1028.208,375.958 1014.864,376.505 998.739,375.958
984.833,373.177 972.599,369.286 962.021,363.161 953.692,355.927 945.896,346.474 940.333,335.911 936.442,323.677
933.661,309.208 933.114,294.192 933.114,288.63 "/>
<polygon points="1128.88,101.771 1275.146,101.771 1275.146,154.052 1191.161,154.052 1191.161,203.552 1268.474,203.552
1268.474,256.942 1191.161,256.942 1191.161,315.896 1275.146,315.896 1275.146,370.396 1128.88,370.396 "/>
<polygon points="1296.271,101.771 1462.005,101.771 1462.005,154.052 1409.177,154.052 1409.177,502.755 1346.333,370.396
1346.333,154.052 1296.271,154.052 "/>
<polygon points="1597.708,266.396 1659.442,266.396 1659.442,271.396 1659.442,279.739 1658.88,296.427 1657.224,310.88
1653.88,324.224 1649.427,335.911 1643.317,345.927 1638.302,352.599 1629.411,360.942 1619.396,367.052 1607.161,372.052
1593.817,374.833 1578.802,376.505 1572.13,376.505 1557.114,375.958 1543.771,373.724 1531.521,369.833 1527.63,368.161
1515.958,360.942 1505.396,352.599 1497.599,341.474 1492.036,330.911 1488.146,317.552 1485.927,306.989 1484.817,296.974
1483.692,285.849 1483.146,271.958 1482.583,256.38 1482.036,238.583 1482.036,236.364 1482.583,218.005 1483.146,202.427
1483.692,188.536 1484.255,176.849 1485.364,166.833 1485.927,165.177 1489.255,150.161 1493.146,137.927 1497.599,130.692
1505.942,119.567 1515.958,110.661 1527.083,104.552 1538.755,99.552 1552.099,96.771 1566.567,95.646 1571.021,95.646
1586.583,96.208 1600.489,98.989 1613.286,102.88 1624.411,108.442 1633.864,116.224 1637.192,120.13 1644.427,129.021
1649.989,139.583 1653.88,151.817 1657.224,165.177 1658.88,180.192 1659.442,193.536 1659.442,195.755 1598.271,195.755
1597.161,178.521 1594.927,165.724 1592.146,157.38 1583.255,148.489 1572.13,146.255 1559.896,149.599 1551.552,159.052
1551.552,159.614 1549.88,166.286 1548.208,176.286 1547.099,189.646 1545.989,206.333 1545.989,225.786 1545.989,231.349
1545.989,236.364 1545.989,256.942 1546.536,274.739 1547.661,289.192 1548.771,300.317 1550.442,308.661 1551.552,312.552
1558.786,322.567 1571.021,326.458 1572.13,326.458 1585.474,323.114 1592.146,315.896 1595.489,306.989 1597.161,293.083
1597.708,278.067 "/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

View File

@@ -0,0 +1,573 @@
{
"lang": "English",
"S1": "Connection error",
"S2": "Connecting",
"S3": "Looks like you are connected from another place, so this page is now disconnected",
"S4": "Parsing response error, format is incorrect",
"S5": "Cannot connect with board",
"S6": "WebSocket connection error",
"S7": "Parsing preferences error, file is incorrect",
"S8": "Retry",
"S9": "Disconnected",
"S10": "Connection with board is lost",
"S11": "Connect again",
"S12": "About %s",
"S13": "Dashboard",
"S14": "Settings",
"S15": "Donation for ESP3D",
"S16": "Firmware",
"S17": "Interface",
"S18": "Browser version",
"S19": "Unknown",
"S20": "Go to github",
"S21": "Parsing data error, data are incorrect",
"S22": "Error",
"S23": "Refresh information",
"S24": "Close",
"S25": "Update",
"S26": "Please Confirm",
"S27": "Yes",
"S28": "Cancel",
"S29": "No",
"S30": "Do you want to update ?",
"S31": "Do you want to upload ?",
"S32": "Uploading...",
"S33": "File transfert failed",
"S34": "Update done",
"S35": "Restarting...",
"S36": "Features",
"S37": "Delete",
"polling": "Polling",
"S38": "Move Up",
"S39": "Move Down",
"S40": "Scan available networks",
"S41": "enter value",
"S42": "Incorrect value",
"S43": "Set",
"S44": "Save data failed!",
"S45": "List of available networks",
"S47": "Select network",
"S48": "Join",
"S49": "Protected",
"S50": "Refresh",
"S51": "Select this network",
"S52": "Export",
"S53": "Export to file",
"S54": "Import",
"S55": "Import from file",
"S56": "Problem with import file",
"S57": "Importing...",
"S58": "Restart Board",
"S59": "This will restart the board",
"S60": "Please wait...",
"S61": "Save",
"S62": "Save and apply changes",
"S63": "Show",
"S64": "Auto load data",
"S65": "Files",
"S66": "Jog",
"S67": "Language pack",
"S68": "Language",
"S69": "not used",
"S70": "Label",
"S71": "Value",
"S72": "Help",
"S73": "General",
"S74": "Play file",
"S75": "Terminal",
"terminal": "Terminal Panel",
"S76": "Verbose mode",
"S77": "Autoscroll",
"S78": "Clear",
"S79": "Clear terminal",
"S80": "Enter command",
"S81": "Send",
"S82": "Send command",
"S83": "There is an error, fix problem first",
"S84": "Creation failed %s",
"S85": "Deletion failed %s",
"S86": "Close panel",
"S87": "Download file?",
"S88": "Upload",
"S89": "Upload file",
"S90": "Create directory",
"S91": "Saving...",
"S92": "Terminal panel",
"S93": "Visible when starting",
"S94": "Edit",
"S95": "Minimize",
"jog": "Jog panel",
"files": "Files panel",
"S96": "Extensions",
"S97": "use ; to separate",
"S98": "Total",
"S99": "Used",
"S100": "Delete file",
"S101": "Delete directory",
"S102": "Processing...",
"S103": "Request failed",
"S104": "Please type directory name",
"S105": "Type directory name",
"S106": "Create",
"S107": "Destination",
"S108": "Downloading...",
"S109": "Command error...",
"S110": "No SD card",
"S111": "Could not open directory",
"S112": "Enable polling commands",
"S113": "Refresh time",
"S114": "ms",
"S115": "Commands",
"S116": "Positions",
"S117": "Close all panels",
"S118": "Distance of movement",
"S119": "sec",
"S120": "Expand buttons on start",
"S121": "Extension",
"macros": "Macros",
"S122": "Force mobile view",
"S123": "Informations",
"S124": "It seems you are in limited environment, please open a browser using http://%s address to get all features working.",
"S125": "Macro editor",
"S126": "Ok",
"S127": "Macro",
"S128": "Add macro",
"S129": "Name",
"S130": "Color",
"S131": "Text color",
"S132": "Icon",
"S133": "Select",
"S134": "Select icon",
"S135": "Type",
"S136": "Output",
"S137": "Flash",
"S138": "SD Card",
"S139": "URL address",
"S140": "GCODE command",
"S141": "File name",
"S142": "Command",
"S143": "SD",
"S144": "SD",
"S145": "Authentication Required",
"S146": "User Name",
"S147": "Password",
"S148": "Log In",
"S149": "You are now disconnected",
"S150": "WebUI version",
"S151": "Disconnect",
"S152": "Do you want to disconnect?",
"S153": "Your session will end soon, do you want to stay connected ?",
"S154": "Stay connected",
"S155": "Extra pages",
"extracontents": "Extra content",
"S156": "Add content",
"S157": "Panel",
"S158": "Page",
"S159": "Action",
"S160": "Image",
"S161": "Content",
"S162": "Camera",
"S163": "Next",
"S164": "Previous",
"S165": "Setup",
"S166": "Display setup next time?",
"S167": "Show it",
"S168": "Hide it",
"S169": "free to use",
"S170": "Sound notifications",
"S171": "Update WebUI",
"S172": "Update Firmware",
"S173": "Session timeout",
"S174": "Changes applied, now need to restart the board.",
"S175": "Operation canceled by user",
"S176": "Haptic feedback",
"S177": "List of language packs",
"S178": "Select",
"S179": "Select this language pack",
"S180": "Select this theme pack",
"S181": "Theme",
"S182": "List of available themes",
"S183": "Theme pack",
"S184": "Hold Stream",
"S185": "Show Stream",
"S186": "Save image",
"S187": "Panels list",
"S188": "TFT SD",
"S189": "TFT USB",
"S190": "SD",
"S191": "Extra SD",
"S192": "Directories are not allowed",
"S193": "Multiple files are not allowed",
"S194": "WebUI and Firmware version are not compatible",
"S195": "Error saving data",
"S196": "Show informations page",
"S197": "Show machine settings tab",
"S198": "Select from list",
"S199": "Not yet supported",
"S200": "Audio feedback",
"S201": "Invalid user name or password",
"S202": "Panels order",
"S203": "Fixed panels order",
"S204": "Stream commands",
"S205": "Abort",
"S206": "Clear stream error",
"S207": "Add command(s)",
"S208": "Precision: $",
"panels": "Panels",
"processing": "Processing",
"no stream": "No stream",
"pause": "Stream on hold",
"resume stream": "Resume stream",
"sta fallback mode": "Client fallback mode",
"radio_boot": "Radio at boot",
"general": "General",
"chip id": "Chip ID",
"CPU Freq": "CPU Frequency",
"CPU Temp": "CPU Temperature",
"free mem": "Free memory",
"SDK": "SDK",
"flash size": "Flash Size",
"size for update": "Available Size for update",
"FS type": "Filesystem type",
"FS usage": "Filesystem usage",
"sleep mode": "Sleep mode",
"wifi": "WiFi",
"HTTP port": "HTTP port",
"Telnet port": "Telnet port",
"Ftp ports": "Ftp ports",
"Telnet Client": "Telnet Client",
"Ftp Client": "Ftp Client",
"Websocket port": "Websocket port",
"WebDav port": "WebDav port",
"WebDav Client": "WebDav Client",
"camera name": "Camera name",
"camera ports": "Camera ports",
"BT Status": "Status",
"connected": "Connected",
"disconnected": "Disconnected",
"cable": "Cable",
"ON": "Enabled",
"OFF": "Disabled",
"DNS": "DNS",
"mac": "Mac address",
"signal": "Signal",
"phy mode": "Phy Mode",
"visible": "Visible",
"authentication": "Authentication",
"DHCP Server": "DHCP Server",
"clients": "Clients",
"direct": "Direct",
"shared": "Shared",
"debug": "Debug",
"FW arch": "FW architecture",
"FW ver": "FW version",
"system": "System",
"sta": "Client mode",
"ap": "Access point mode",
"mixed": "Mixed mode",
"service": "Services",
"http": "HTTP protocol",
"telnetp": "Telnet protocol",
"websocketp": "WebSocket protocol",
"webdavp": "WebDav protocol",
"telnet": "Telnet",
"ftp": "FTP protocol",
"notification": "Notifications",
"network": "Network",
"yes": "Yes",
"no": "No",
"hostname": "Hostname",
"radio mode": "Radio mode",
"bt": "Bluetooth",
"ethernet": "Ethernet",
"eth-sta": "Ethernet",
"SSID": "SSID",
"ip mode": "IP Mode",
"none": "None",
"dhcp": "DHCP",
"static": "Static",
"ip": "IP",
"gw": "Gateway",
"msk": "Mask",
"pwd": "Password",
"channel": "Channel",
"security": "Security",
"adm pwd": "Admin password",
"user pwd": "User Password",
"enable": "Enable",
"port": "Port",
"control port": "Control port",
"active port": "Active port",
"passive port": "Passive port",
"time": "Time",
"i-time": "Internet time",
"tzone": "Time zone",
"dst": "DST",
"t-server": "Time server",
"auto notif": "Auto notification",
"pushover": "Pushover",
"email": "Email",
"line": "Line",
"telegram": "Telegram",
"t1": "Token 1",
"t2": "Token 2",
"ts": "Setting",
"device": "Connected device",
"camera": "Camera",
"buzzer": "Buzzer",
"sensor": "Sensor",
"type": "Type",
"sd": "SD card",
"speedx": "Speed factor",
"targetfw": "Target firmware",
"repetier": "Repetier",
"marlin": "Marlin",
"smoothieware": "Smoothieware",
"unknown": "Unknown",
"baud": "Baud rate",
"verbose": "Verbose",
"bootdelay": "Delay (ms)",
"boot": "Boot sequence",
"session timeout": "Inactivity timeout (min)",
"outputmsg": "Output message",
"M117": "Machine screen",
"screen": "Screen",
"ws": "Websocket",
"serial": "Serial",
"intervalms": "Interval (millisec)",
"modem": "Modem",
"light": "Light",
"grbl": "Grbl",
"SD updater": "SD updater",
"setup": "Setup mode",
"serial_bridge": "Serial Bridge",
"timeout": "Timeout, did not get response in time",
"CN1": "mm/min",
"CN2": "XY feed rate",
"CN3": "Z feed rate",
"CN4": "A feed rate",
"CN5": "B feed rate",
"CN6": "C feed rate",
"CN7": "Use keyboard",
"CN8": "Show axis",
"CN9": "Feedrate",
"CN10": "Home axis",
"CN11": "(#) is axis",
"CN12": "Jog up",
"CN13": "Jog Down",
"CN14": "Keyboard keys",
"CN15": "",
"CN16": "Home single axis",
"CN17": "Home",
"CN18": "Jogging distance",
"CN19": "Zero axis",
"CN20": "Zero all axis",
"CN21": "Home all axis",
"CN22": "Disable",
"CN23": "Stop",
"CN24": "[Arrow Right] X+, [Arrow Left] X-, [X] Zero X,",
"CN25": "[Arrow Up] Y+, [Arrow Down] Y-, [Y] Zero Y,",
"CN26": "[PageUp] Z+, [PageDown] Z-,[Z] Zero Z,",
"CN27": "[1] Home X,",
"CN28": "[2] Home Y,",
"CN29": "[3] Home Z,",
"CN30": "[/] Selected axis+, [*] Selected axis-, [A] Zero selected axis,",
"CN31": "[4] Home selected axis,",
"CN32": "[( )] Axis selector,",
"CN33": "[+ -] Distance selector, [Home] Home all axis, [O] Zero all axis, [End] Disable, [Delete] Stop,",
"CN34": "Status",
"CN35": "Laser",
"CN36": "Spindle",
"CN37": "Probe",
"CN38": "Coolant",
"CN39": "Tool",
"CN40": "Controls commands",
"CN41": "Soft Reset",
"CN42": "Unlock",
"CN43": "Sleep",
"CN44": "Modes",
"CN45": "Motion mode",
"CN46": "Coordinate system",
"CN47": "Plane selection",
"CN48": "Distance mode",
"CN49": "Arc IJK distance mode",
"CN50": "Feed rate mode",
"CN51": "Units mode",
"CN52": "Cutter radius compensation",
"CN53": "Tool length offset",
"CN54": "Program mode",
"CN55": "Spindle mode",
"CN56": "Coolant mode",
"CN57": "Override Control",
"CN58": "Active tool",
"CN59": "Spindle speed",
"CN60": "Feed rate",
"CN61": "Resume",
"CN62": "RPM",
"CN63": "Rapid",
"CN64": "Speed",
"CN65": "Overrides",
"CN66": "Reset",
"CN67": "Spindle speed override",
"CN68": "Feed override",
"CN69": "Rapid override",
"CN70": "Show M4 controls",
"CN71": "Show M7 controls",
"CN72": "Show coolant controls",
"CN73": "Show mist controls",
"CN74": "Enable spindle\nclockwise",
"CN75": "Enable spindle\ncounterclockwise",
"CN76": "Stop spindle",
"CN77": "Enable mist coolant",
"CN78": "Enable flood coolant",
"CN79": "Disable coolant",
"CN80": "Toogle controls",
"CN81": "Toogle spindle state",
"CN82": "Toogle flood state",
"CN83": "Toogle mist state",
"CN84": "Maximum power",
"CN85": "Test duration",
"CN86": "Test",
"CN87": "Disable laser",
"CN88": "Enable laser for test",
"CN89": "% of max power",
"CN90": "Laser Test",
"CN91": "Mode",
"CN92": "Input pins",
"CN93": "Distance max",
"CN94": "Probe thickness",
"CN95": "Finalize probing commands",
"CN96": "mm",
"CN97": "inch",
"CN98": "Probe type",
"CN99": "Probe axis",
"CN100": "Start probing process",
"CN101": "Sucessfully probed",
"CN102": "No successful probing",
"CN103": "Probe status",
"CN104": "Status",
"CN105": "Retract mode",
"CN106": "Scaling",
"CN107": "Global offset",
"CN108": "Diameter mode",
"CN109": "Tool change",
"CN110": "OVC feedrate disable",
"CN111": "OVC rpm enable",
"CN112": "OVC hold disable",
"CN113": "OVC parking disable",
"status": "Status panel",
"laser": "Laser panel",
"spindle": "Spindle panel",
"overrides": "Overrides panel",
"probe": "Probe panel",
"Idle": "Idle",
"Run": "Run",
"Hold": "Hold",
"Jog": "Jog",
"Home": "Home",
"Alarm": "Alarm",
"Sleep": "Sleep",
"Check": "Check",
"Door": "Door",
"Hold:0": "Hold complete. Ready to resume.",
"Hold:1": "Hold in-progress. Reset will throw an alarm.",
"Door:0": "Door closed. Ready to resume.",
"Door:1": "Machine stopped. Door still ajar. Can't resume until closed.",
"Door:2": "Door opened. Hold (or parking retract) in-progress. Reset will throw an alarm.",
"Door:3": "Door closed and resuming. Restoring from park, if applicable. Reset will throw an alarm.",
"ALARM:1": "Hard limit has been triggered. Position lost. Re-homing is highly recommended.",
"ALARM:2": "Soft limit alarm. Machine position retained. Alarm may be safely unlocked.",
"ALARM:3": "Reset while in motion. Machine position is likely lost. Re-homing is highly recommended.",
"ALARM:4": "Probe fail. Probe is not in the expected initial state before starting probe cycle.",
"ALARM:5": "Probe fail. Probe did not contact the workpiece.",
"ALARM:6": "Homing fail. The active homing cycle was reset.",
"ALARM:7": "Homing fail. Safety door was opened during homing cycle.",
"ALARM:8": "Homing fail. Pull off travel failed to clear limit switch.",
"ALARM:9": "Homing fail. Could not find limit switch within search distances.",
"error:1": "GCode command letter was not found.",
"error:2": "GCode command value invalid or missing.",
"error:3": "Grbl '$' system command was not recognized or supported.",
"error:4": "Negative value received for an expected positive value.",
"error:5": "Homing failed. Homing is not enabled in settings.",
"error:6": "Minimum step pulse time must be greater than 3usec.",
"error:7": "EEPROM read failed. Default values used.",
"error:8": "Grbl '$' command only valid when Idle.",
"error:9": "G-code commands are locked out during alarm or jog state.",
"error:10": "Soft limits require homing to be enabled.",
"error:11": "Max characters per line exceeded. Command ignored.",
"error:12": "Grbl '$' setting exceeds the maximum step rate.",
"error:13": "Safety door detected as opened and door state initiated.",
"error:14": "Build info or startup line exceeded EEPROM line length limit.",
"error:15": "Jog target exceeds machine travel. Command ignored.",
"error:16": "Jog command has no '=' or contains prohibited GCode.",
"error:17": "Laser mode requires PWM output.",
"error:20": "Unsupported or invalid GCode command.",
"error:21": "More than one GCode command from same modal group found in block.",
"error:22": "Feed rate has not yet been set or is undefined.",
"error:23": "GCode command requires an integer value.",
"error:24": "More than one GCode command using axis word found.",
"error:25": "Repeated GCode word found in block.",
"error:26": "No axis words found in command block.",
"error:27": "Line number value is invalid.",
"error:28": "GCode command is missing a required value word.",
"error:29": "G59.x work coordinate systems are not supported.",
"error:30": "G53 only allowed with G0 and G1 motion modes.",
"error:31": "Unneeded axis words found in block.",
"error:32": "G2 and G3 arcs require at least one in-plane axis word.",
"error:33": "Motion command target is invalid.",
"error:34": "Arc radius value is invalid.",
"error:35": "G2 and G3 arcs require at least one in-plane offset word.",
"error:36": "Unused value words found in block.",
"error:37": "G43.1 offset is not assigned to tool length axis.",
"error:38": "Tool number greater than max supported value.",
"$0": "Step pulse, microseconds",
"$1": "Step idle delay, milliseconds",
"$2": "Step port invert, mask",
"$3": "Direction port invert, mask",
"$4": "Step enable invert, boolean",
"$5": "Limit pins invert, boolean",
"$6": "Probe pin invert, boolean",
"$10": "Status report, mask",
"$11": "Junction deviation, mm",
"$12": "Arc tolerance, mm",
"$13": "Report inches, boolean",
"$20": "Soft limits, boolean",
"$21": "Hard limits, boolean",
"$22": "Homing cycle, boolean",
"$23": "Homing dir invert, mask",
"$24": "Homing feed, mm/min",
"$25": "Homing seek, mm/min",
"$26": "Homing debounce, milliseconds",
"$27": "Homing pull-off, mm",
"$30": "Max spindle speed, RPM",
"$31": "Min spindle speed, RPM",
"$32": "Laser mode, boolean",
"$100": "X steps/mm",
"$101": "Y steps/mm",
"$102": "Z steps/mm",
"$103": "A steps/mm",
"$104": "B steps/mm",
"$105": "C steps/mm",
"$110": "X Max rate, mm/min",
"$111": "Y Max rate, mm/min",
"$112": "Z Max rate, mm/min",
"$113": "A Max rate, mm/min",
"$114": "B Max rate, mm/min",
"$115": "C Max rate, mm/min",
"$120": "X Acceleration, mm/sec^2",
"$121": "Y Acceleration, mm/sec^2",
"$122": "Z Acceleration, mm/sec^2",
"$123": "A Acceleration, mm/sec^2",
"$124": "B Acceleration, mm/sec^2",
"$125": "C Acceleration, mm/sec^2",
"$130": "X Max travel, mm",
"$131": "Y Max travel, mm",
"$132": "Z Max travel, mm",
"$133": "A Max travel, mm",
"$134": "B Max travel, mm",
"$135": "C Max travel, mm",
"P15": "Emergency Stop",
"P65": "Move X to",
"P66": "Move Y to",
"P75": "Move Z to"
}

View File

@@ -0,0 +1,573 @@
{
"lang": "English",
"S1": "Connection error",
"S2": "Connecting",
"S3": "Looks like you are connected from another place, so this page is now disconnected",
"S4": "Parsing response error, format is incorrect",
"S5": "Cannot connect with board",
"S6": "WebSocket connection error",
"S7": "Parsing preferences error, file is incorrect",
"S8": "Retry",
"S9": "Disconnected",
"S10": "Connection with board is lost",
"S11": "Connect again",
"S12": "About %s",
"S13": "Dashboard",
"S14": "Settings",
"S15": "Donation for ESP3D",
"S16": "Firmware",
"S17": "Interface",
"S18": "Browser version",
"S19": "Unknown",
"S20": "Go to github",
"S21": "Parsing data error, data are incorrect",
"S22": "Error",
"S23": "Refresh information",
"S24": "Close",
"S25": "Update",
"S26": "Please Confirm",
"S27": "Yes",
"S28": "Cancel",
"S29": "No",
"S30": "Do you want to update ?",
"S31": "Do you want to upload ?",
"S32": "Uploading...",
"S33": "File transfert failed",
"S34": "Update done",
"S35": "Restarting...",
"S36": "Features",
"S37": "Delete",
"polling": "Polling",
"S38": "Move Up",
"S39": "Move Down",
"S40": "Scan available networks",
"S41": "enter value",
"S42": "Incorrect value",
"S43": "Set",
"S44": "Save data failed!",
"S45": "List of available networks",
"S47": "Select network",
"S48": "Join",
"S49": "Protected",
"S50": "Refresh",
"S51": "Select this network",
"S52": "Export",
"S53": "Export to file",
"S54": "Import",
"S55": "Import from file",
"S56": "Problem with import file",
"S57": "Importing...",
"S58": "Restart Board",
"S59": "This will restart the board",
"S60": "Please wait...",
"S61": "Save",
"S62": "Save and apply changes",
"S63": "Show",
"S64": "Auto load data",
"S65": "Files",
"S66": "Jog",
"S67": "Language pack",
"S68": "Language",
"S69": "not used",
"S70": "Label",
"S71": "Value",
"S72": "Help",
"S73": "General",
"S74": "Play file",
"S75": "Terminal",
"terminal": "Terminal Panel",
"S76": "Verbose mode",
"S77": "Autoscroll",
"S78": "Clear",
"S79": "Clear terminal",
"S80": "Enter command",
"S81": "Send",
"S82": "Send command",
"S83": "There is an error, fix problem first",
"S84": "Creation failed %s",
"S85": "Deletion failed %s",
"S86": "Close panel",
"S87": "Download file?",
"S88": "Upload",
"S89": "Upload file",
"S90": "Create directory",
"S91": "Saving...",
"S92": "Terminal panel",
"S93": "Visible when starting",
"S94": "Edit",
"S95": "Minimize",
"jog": "Jog panel",
"files": "Files panel",
"S96": "Extensions",
"S97": "use ; to separate",
"S98": "Total",
"S99": "Used",
"S100": "Delete file",
"S101": "Delete directory",
"S102": "Processing...",
"S103": "Request failed",
"S104": "Please type directory name",
"S105": "Type directory name",
"S106": "Create",
"S107": "Destination",
"S108": "Downloading...",
"S109": "Command error...",
"S110": "No SD card",
"S111": "Could not open directory",
"S112": "Enable polling commands",
"S113": "Refresh time",
"S114": "ms",
"S115": "Commands",
"S116": "Positions",
"S117": "Close all panels",
"S118": "Distance of movement",
"S119": "sec",
"S120": "Expand buttons on start",
"S121": "Extension",
"macros": "Macros",
"S122": "Force mobile view",
"S123": "Informations",
"S124": "It seems you are in limited environment, please open a browser using http://%s address to get all features working.",
"S125": "Macro editor",
"S126": "Ok",
"S127": "Macro",
"S128": "Add macro",
"S129": "Name",
"S130": "Color",
"S131": "Text color",
"S132": "Icon",
"S133": "Select",
"S134": "Select icon",
"S135": "Type",
"S136": "Output",
"S137": "Flash",
"S138": "SD Card",
"S139": "URL address",
"S140": "GCODE command",
"S141": "File name",
"S142": "Command",
"S143": "SD",
"S144": "SD",
"S145": "Authentication Required",
"S146": "User Name",
"S147": "Password",
"S148": "Log In",
"S149": "You are now disconnected",
"S150": "WebUI version",
"S151": "Disconnect",
"S152": "Do you want to disconnect?",
"S153": "Your session will end soon, do you want to stay connected ?",
"S154": "Stay connected",
"S155": "Extra pages",
"extracontents": "Extra content",
"S156": "Add content",
"S157": "Panel",
"S158": "Page",
"S159": "Action",
"S160": "Image",
"S161": "Content",
"S162": "Camera",
"S163": "Next",
"S164": "Previous",
"S165": "Setup",
"S166": "Display setup next time?",
"S167": "Show it",
"S168": "Hide it",
"S169": "free to use",
"S170": "Sound notifications",
"S171": "Update WebUI",
"S172": "Update Firmware",
"S173": "Session timeout",
"S174": "Changes applied, now need to restart the board.",
"S175": "Operation canceled by user",
"S176": "Haptic feedback",
"S177": "List of language packs",
"S178": "Select",
"S179": "Select this language pack",
"S180": "Select this theme pack",
"S181": "Theme",
"S182": "List of available themes",
"S183": "Theme pack",
"S184": "Hold Stream",
"S185": "Show Stream",
"S186": "Save image",
"S187": "Panels list",
"S188": "TFT SD",
"S189": "TFT USB",
"S190": "SD",
"S191": "Extra SD",
"S192": "Directories are not allowed",
"S193": "Multiple files are not allowed",
"S194": "WebUI and Firmware version are not compatible",
"S195": "Error saving data",
"S196": "Show informations page",
"S197": "Show machine settings tab",
"S198": "Select from list",
"S199": "Not yet supported",
"S200": "Audio feedback",
"S201": "Invalid user name or password",
"S202": "Panels order",
"S203": "Fixed panels order",
"S204": "Stream commands",
"S205": "Abort",
"S206": "Clear stream error",
"S207": "Add command(s)",
"S208": "Precision: $",
"panels": "Panels",
"processing": "Processing",
"no stream": "No stream",
"pause": "Stream on hold",
"resume stream": "Resume stream",
"sta fallback mode": "Client fallback mode",
"radio_boot": "Radio at boot",
"general": "General",
"chip id": "Chip ID",
"CPU Freq": "CPU Frequency",
"CPU Temp": "CPU Temperature",
"free mem": "Free memory",
"SDK": "SDK",
"flash size": "Flash Size",
"size for update": "Available Size for update",
"FS type": "Filesystem type",
"FS usage": "Filesystem usage",
"sleep mode": "Sleep mode",
"wifi": "WiFi",
"HTTP port": "HTTP port",
"Telnet port": "Telnet port",
"Ftp ports": "Ftp ports",
"Telnet Client": "Telnet Client",
"Ftp Client": "Ftp Client",
"Websocket port": "Websocket port",
"WebDav port": "WebDav port",
"WebDav Client": "WebDav Client",
"camera name": "Camera name",
"camera ports": "Camera ports",
"BT Status": "Status",
"connected": "Connected",
"disconnected": "Disconnected",
"cable": "Cable",
"ON": "Enabled",
"OFF": "Disabled",
"DNS": "DNS",
"mac": "Mac address",
"signal": "Signal",
"phy mode": "Phy Mode",
"visible": "Visible",
"authentication": "Authentication",
"DHCP Server": "DHCP Server",
"clients": "Clients",
"direct": "Direct",
"shared": "Shared",
"debug": "Debug",
"FW arch": "FW architecture",
"FW ver": "FW version",
"system": "System",
"sta": "Client mode",
"ap": "Access point mode",
"mixed": "Mixed mode",
"service": "Services",
"http": "HTTP protocol",
"telnetp": "Telnet protocol",
"websocketp": "WebSocket protocol",
"webdavp": "WebDav protocol",
"telnet": "Telnet",
"ftp": "FTP protocol",
"notification": "Notifications",
"network": "Network",
"yes": "Yes",
"no": "No",
"hostname": "Hostname",
"radio mode": "Radio mode",
"bt": "Bluetooth",
"ethernet": "Ethernet",
"eth-sta": "Ethernet",
"SSID": "SSID",
"ip mode": "IP Mode",
"none": "None",
"dhcp": "DHCP",
"static": "Static",
"ip": "IP",
"gw": "Gateway",
"msk": "Mask",
"pwd": "Password",
"channel": "Channel",
"security": "Security",
"adm pwd": "Admin password",
"user pwd": "User Password",
"enable": "Enable",
"port": "Port",
"control port": "Control port",
"active port": "Active port",
"passive port": "Passive port",
"time": "Time",
"i-time": "Internet time",
"tzone": "Time zone",
"dst": "DST",
"t-server": "Time server",
"auto notif": "Auto notification",
"pushover": "Pushover",
"email": "Email",
"line": "Line",
"telegram": "Telegram",
"t1": "Token 1",
"t2": "Token 2",
"ts": "Setting",
"device": "Connected device",
"camera": "Camera",
"buzzer": "Buzzer",
"sensor": "Sensor",
"type": "Type",
"sd": "SD card",
"speedx": "Speed factor",
"targetfw": "Target firmware",
"repetier": "Repetier",
"marlin": "Marlin",
"smoothieware": "Smoothieware",
"unknown": "Unknown",
"baud": "Baud rate",
"verbose": "Verbose",
"bootdelay": "Delay (ms)",
"boot": "Boot sequence",
"session timeout": "Inactivity timeout (min)",
"outputmsg": "Output message",
"M117": "Machine screen",
"screen": "Screen",
"ws": "Websocket",
"serial": "Serial",
"intervalms": "Interval (millisec)",
"modem": "Modem",
"light": "Light",
"grbl": "Grbl",
"SD updater": "SD updater",
"setup": "Setup mode",
"serial_bridge": "Serial Bridge",
"timeout": "Timeout, did not get response in time",
"CN1": "mm/min",
"CN2": "XY feed rate",
"CN3": "Z feed rate",
"CN4": "A feed rate",
"CN5": "B feed rate",
"CN6": "C feed rate",
"CN7": "Use keyboard",
"CN8": "Show axis",
"CN9": "Feedrate",
"CN10": "Home axis",
"CN11": "(#) is axis",
"CN12": "Jog up",
"CN13": "Jog Down",
"CN14": "Keyboard keys",
"CN15": "",
"CN16": "Home single axis",
"CN17": "Home",
"CN18": "Jogging distance",
"CN19": "Zero axis",
"CN20": "Zero all axis",
"CN21": "Home all axis",
"CN22": "Disable",
"CN23": "Stop",
"CN24": "[Arrow Right] X+, [Arrow Left] X-, [X] Zero X,",
"CN25": "[Arrow Up] Y+, [Arrow Down] Y-, [Y] Zero Y,",
"CN26": "[PageUp] Z+, [PageDown] Z-,[Z] Zero Z,",
"CN27": "[1] Home X,",
"CN28": "[2] Home Y,",
"CN29": "[3] Home Z,",
"CN30": "[/] Selected axis+, [*] Selected axis-, [A] Zero selected axis,",
"CN31": "[4] Home selected axis,",
"CN32": "[( )] Axis selector,",
"CN33": "[+ -] Distance selector, [Home] Home all axis, [O] Zero all axis, [End] Disable, [Delete] Stop,",
"CN34": "Status",
"CN35": "Laser",
"CN36": "Spindle",
"CN37": "Probe",
"CN38": "Coolant",
"CN39": "Tool",
"CN40": "Controls commands",
"CN41": "Soft Reset",
"CN42": "Unlock",
"CN43": "Sleep",
"CN44": "Modes",
"CN45": "Motion mode",
"CN46": "Coordinate system",
"CN47": "Plane selection",
"CN48": "Distance mode",
"CN49": "Arc IJK distance mode",
"CN50": "Feed rate mode",
"CN51": "Units mode",
"CN52": "Cutter radius compensation",
"CN53": "Tool length offset",
"CN54": "Program mode",
"CN55": "Spindle mode",
"CN56": "Coolant mode",
"CN57": "Override Control",
"CN58": "Active tool",
"CN59": "Spindle speed",
"CN60": "Feed rate",
"CN61": "Resume",
"CN62": "RPM",
"CN63": "Rapid",
"CN64": "Speed",
"CN65": "Overrides",
"CN66": "Reset",
"CN67": "Spindle speed override",
"CN68": "Feed override",
"CN69": "Rapid override",
"CN70": "Show M4 controls",
"CN71": "Show M7 controls",
"CN72": "Show coolant controls",
"CN73": "Show mist controls",
"CN74": "Enable spindle\nclockwise",
"CN75": "Enable spindle\ncounterclockwise",
"CN76": "Stop spindle",
"CN77": "Enable mist coolant",
"CN78": "Enable flood coolant",
"CN79": "Disable coolant",
"CN80": "Toogle controls",
"CN81": "Toogle spindle state",
"CN82": "Toogle flood state",
"CN83": "Toogle mist state",
"CN84": "Maximum power",
"CN85": "Test duration",
"CN86": "Test",
"CN87": "Disable laser",
"CN88": "Enable laser for test",
"CN89": "% of max power",
"CN90": "Laser Test",
"CN91": "Mode",
"CN92": "Input pins",
"CN93": "Distance max",
"CN94": "Probe thickness",
"CN95": "Finalize probing commands",
"CN96": "mm",
"CN97": "inch",
"CN98": "Probe type",
"CN99": "Probe axis",
"CN100": "Start probing process",
"CN101": "Sucessfully probed",
"CN102": "No successful probing",
"CN103": "Probe status",
"CN104": "Status",
"CN105": "Retract mode",
"CN106": "Scaling",
"CN107": "Global offset",
"CN108": "Diameter mode",
"CN109": "Tool change",
"CN110": "OVC feedrate disable",
"CN111": "OVC rpm enable",
"CN112": "OVC hold disable",
"CN113": "OVC parking disable",
"status": "Status panel",
"laser": "Laser panel",
"spindle": "Spindle panel",
"overrides": "Overrides panel",
"probe": "Probe panel",
"Idle": "Idle",
"Run": "Run",
"Hold": "Hold",
"Jog": "Jog",
"Home": "Home",
"Alarm": "Alarm",
"Sleep": "Sleep",
"Check": "Check",
"Door": "Door",
"Hold:0": "Hold complete. Ready to resume.",
"Hold:1": "Hold in-progress. Reset will throw an alarm.",
"Door:0": "Door closed. Ready to resume.",
"Door:1": "Machine stopped. Door still ajar. Can't resume until closed.",
"Door:2": "Door opened. Hold (or parking retract) in-progress. Reset will throw an alarm.",
"Door:3": "Door closed and resuming. Restoring from park, if applicable. Reset will throw an alarm.",
"ALARM:1": "Hard limit has been triggered. Position lost. Re-homing is highly recommended.",
"ALARM:2": "Soft limit alarm. Machine position retained. Alarm may be safely unlocked.",
"ALARM:3": "Reset while in motion. Machine position is likely lost. Re-homing is highly recommended.",
"ALARM:4": "Probe fail. Probe is not in the expected initial state before starting probe cycle.",
"ALARM:5": "Probe fail. Probe did not contact the workpiece.",
"ALARM:6": "Homing fail. The active homing cycle was reset.",
"ALARM:7": "Homing fail. Safety door was opened during homing cycle.",
"ALARM:8": "Homing fail. Pull off travel failed to clear limit switch.",
"ALARM:9": "Homing fail. Could not find limit switch within search distances.",
"error:1": "GCode command letter was not found.",
"error:2": "GCode command value invalid or missing.",
"error:3": "Grbl '$' system command was not recognized or supported.",
"error:4": "Negative value received for an expected positive value.",
"error:5": "Homing failed. Homing is not enabled in settings.",
"error:6": "Minimum step pulse time must be greater than 3usec.",
"error:7": "EEPROM read failed. Default values used.",
"error:8": "Grbl '$' command only valid when Idle.",
"error:9": "G-code commands are locked out during alarm or jog state.",
"error:10": "Soft limits require homing to be enabled.",
"error:11": "Max characters per line exceeded. Command ignored.",
"error:12": "Grbl '$' setting exceeds the maximum step rate.",
"error:13": "Safety door detected as opened and door state initiated.",
"error:14": "Build info or startup line exceeded EEPROM line length limit.",
"error:15": "Jog target exceeds machine travel. Command ignored.",
"error:16": "Jog command has no '=' or contains prohibited GCode.",
"error:17": "Laser mode requires PWM output.",
"error:20": "Unsupported or invalid GCode command.",
"error:21": "More than one GCode command from same modal group found in block.",
"error:22": "Feed rate has not yet been set or is undefined.",
"error:23": "GCode command requires an integer value.",
"error:24": "More than one GCode command using axis word found.",
"error:25": "Repeated GCode word found in block.",
"error:26": "No axis words found in command block.",
"error:27": "Line number value is invalid.",
"error:28": "GCode command is missing a required value word.",
"error:29": "G59.x work coordinate systems are not supported.",
"error:30": "G53 only allowed with G0 and G1 motion modes.",
"error:31": "Unneeded axis words found in block.",
"error:32": "G2 and G3 arcs require at least one in-plane axis word.",
"error:33": "Motion command target is invalid.",
"error:34": "Arc radius value is invalid.",
"error:35": "G2 and G3 arcs require at least one in-plane offset word.",
"error:36": "Unused value words found in block.",
"error:37": "G43.1 offset is not assigned to tool length axis.",
"error:38": "Tool number greater than max supported value.",
"$0": "Step pulse, microseconds",
"$1": "Step idle delay, milliseconds",
"$2": "Step port invert, mask",
"$3": "Direction port invert, mask",
"$4": "Step enable invert, boolean",
"$5": "Limit pins invert, boolean",
"$6": "Probe pin invert, boolean",
"$10": "Status report, mask",
"$11": "Junction deviation, mm",
"$12": "Arc tolerance, mm",
"$13": "Report inches, boolean",
"$20": "Soft limits, boolean",
"$21": "Hard limits, boolean",
"$22": "Homing cycle, boolean",
"$23": "Homing dir invert, mask",
"$24": "Homing feed, mm/min",
"$25": "Homing seek, mm/min",
"$26": "Homing debounce, milliseconds",
"$27": "Homing pull-off, mm",
"$30": "Max spindle speed, RPM",
"$31": "Min spindle speed, RPM",
"$32": "Laser mode, boolean",
"$100": "X steps/mm",
"$101": "Y steps/mm",
"$102": "Z steps/mm",
"$103": "A steps/mm",
"$104": "B steps/mm",
"$105": "C steps/mm",
"$110": "X Max rate, mm/min",
"$111": "Y Max rate, mm/min",
"$112": "Z Max rate, mm/min",
"$113": "A Max rate, mm/min",
"$114": "B Max rate, mm/min",
"$115": "C Max rate, mm/min",
"$120": "X Acceleration, mm/sec^2",
"$121": "Y Acceleration, mm/sec^2",
"$122": "Z Acceleration, mm/sec^2",
"$123": "A Acceleration, mm/sec^2",
"$124": "B Acceleration, mm/sec^2",
"$125": "C Acceleration, mm/sec^2",
"$130": "X Max travel, mm",
"$131": "Y Max travel, mm",
"$132": "Z Max travel, mm",
"$133": "A Max travel, mm",
"$134": "B Max travel, mm",
"$135": "C Max travel, mm",
"P15": "Emergency Stop",
"P65": "Move X to",
"P66": "Move Y to",
"P75": "Move Z to"
}

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More