Added inital files
This commit is contained in:
parent
9b0b2ad9b2
commit
2dab9c20fa
21 changed files with 4791 additions and 130 deletions
130
.gitignore
vendored
130
.gitignore
vendored
|
|
@ -1,129 +1 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
*.DS_Store
|
||||
|
|
|
|||
|
|
@ -1,2 +1,7 @@
|
|||
# WipperSnapper_Firmware_Uploader
|
||||
# WipperSnapper Firmware Uploader
|
||||
|
||||
A JavaScript tool for generating a LittleFS Partition with Credentials for WipperSnapper.
|
||||
|
||||
## Live Tool
|
||||
|
||||
A live copy of the tool is hosted here: https://adafruit.github.io/WipperSnapper_Firmware_Uploader/
|
||||
|
|
|
|||
BIN
bin/Wippersnapper_demo.ino.bin
Normal file
BIN
bin/Wippersnapper_demo.ino.bin
Normal file
Binary file not shown.
BIN
bin/Wippersnapper_demo.ino.bootloader.bin
Normal file
BIN
bin/Wippersnapper_demo.ino.bootloader.bin
Normal file
Binary file not shown.
BIN
bin/Wippersnapper_demo.ino.partitions.bin
Normal file
BIN
bin/Wippersnapper_demo.ino.partitions.bin
Normal file
Binary file not shown.
BIN
bin/boot_app0.bin
Normal file
BIN
bin/boot_app0.bin
Normal file
Binary file not shown.
91
css/dark.css
Normal file
91
css/dark.css
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
.header {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
input, select, button {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.footer button {
|
||||
border-color: #fff;
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.footer button:hover {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.remix button {
|
||||
border-color: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.remix button:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
#commands button {
|
||||
border-color: #fff;
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#commands button:hover {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#notSupported {
|
||||
background-color: red;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.firmware {
|
||||
border-color: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.firmware:focus,
|
||||
.firmware:hover {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.firmware:disabled {
|
||||
color: #ccc;
|
||||
border-color: #ccc;
|
||||
}
|
||||
|
||||
.firmware:disabled:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#commands .buttons button:disabled,
|
||||
#commands .buttons button:disabled:hover{
|
||||
border-color: #999;
|
||||
background-color: #888;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
#commands .buttons button:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
border-color: #aaa;
|
||||
}
|
||||
79
css/light.css
Normal file
79
css/light.css
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
.header {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
input, select, button {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#notSupported {
|
||||
background-color: red;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.footer button {
|
||||
border-color: #63338f;
|
||||
background-color: #fff;
|
||||
color: #63338f;
|
||||
}
|
||||
|
||||
.footer button:hover {
|
||||
background-color: #63338f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.remix button {
|
||||
border-color: #333;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.remix button:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.firmware {
|
||||
border-color: #63338f;
|
||||
color: #63338f;
|
||||
}
|
||||
|
||||
.firmware:focus,
|
||||
.firmware:hover {
|
||||
background-color: #63338f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.firmware:disabled {
|
||||
background-color: #ddd;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.firmware:disabled:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
#commands .buttons button {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
#commands .buttons button:disabled,
|
||||
#commands .buttons button:disabled:hover {
|
||||
border-color: #ccc;
|
||||
background-color: #ddd;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
#commands .buttons button:hover {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
border-color: #333;
|
||||
}
|
||||
376
css/style.css
Normal file
376
css/style.css
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
/**
|
||||
* Header
|
||||
*/
|
||||
|
||||
.header {
|
||||
box-sizing: border-box;
|
||||
font-size: 16px;
|
||||
height: 85px;
|
||||
line-height: 40px;
|
||||
padding: 20px 70px 0px 70px; /* TRouBLe */
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
margin: 0;
|
||||
border-bottom: 5px solid #00a7e9;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
flex: 1;
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.header button {
|
||||
border: solid 2px #fff;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
margin-left: 20px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.header button:hover {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
button, .firmware {
|
||||
height: 25px;
|
||||
font-size: 16px;
|
||||
border-radius: 15px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: proxima-nova, sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input, select, button, label {
|
||||
font-weight: 600;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.left {
|
||||
float: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div.right {
|
||||
float: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.Adafruit-Logo {
|
||||
width: 115px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.main {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-top: 80px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.notSupported {
|
||||
padding: 1em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.subheader {
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
padding-left: 70px;
|
||||
padding-right: 70px;
|
||||
}
|
||||
|
||||
.subheader .title {
|
||||
font-size: 36px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#app.connected #commands {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
#app.connected #log {
|
||||
height: calc(100vh - 530px);
|
||||
}
|
||||
|
||||
#app #commands {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#app #log {
|
||||
height: calc(100vh - 330px);
|
||||
}
|
||||
|
||||
#commands, #log {
|
||||
transition: height 0.5s;
|
||||
}
|
||||
|
||||
#commands {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
overflow-y: auto;
|
||||
padding: 0 60px;
|
||||
}
|
||||
|
||||
#log {
|
||||
max-width: 100%;
|
||||
font-family: pt-mono, monospace;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
overflow-x: hidden;
|
||||
overflow-x: auto;
|
||||
transition : color 0.1s linear;
|
||||
padding: 0 50px;
|
||||
border: 20px solid #000;
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
background-color: #000;
|
||||
color: #cecece;
|
||||
}
|
||||
|
||||
#log::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.footer {
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
padding-left: 70px;
|
||||
padding-right: 70px;
|
||||
}
|
||||
|
||||
.footer button {
|
||||
font-size: 14px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.remix {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 60px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.remix button {
|
||||
position: absolute;
|
||||
bottom: 11px;
|
||||
}
|
||||
|
||||
#templates {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* On/Off Switch Widget */
|
||||
.onoffswitch {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 50px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.onoffswitch-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.onoffswitch-label {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border: 1px solid #900;
|
||||
border-radius: 15px;
|
||||
transition: border 0.3s ease-in 0s;
|
||||
}
|
||||
|
||||
.onoffswitch-inner {
|
||||
display: block;
|
||||
width: 200%;
|
||||
margin-left: -100%;
|
||||
transition: margin 0.3s ease-in 0s;
|
||||
}
|
||||
|
||||
.onoffswitch-inner:before,
|
||||
.onoffswitch-inner:after {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 50%;
|
||||
height: 25px;
|
||||
padding: 0;
|
||||
line-height: 25px;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
font-family: proxima-nova, sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.onoffswitch-inner:before {
|
||||
content: "on";
|
||||
padding-left: 6px;
|
||||
background-color: #8ec641;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.onoffswitch-inner:after {
|
||||
content: "off";
|
||||
padding-right: 6px;
|
||||
background-color: #c64141;
|
||||
color: #fff;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.onoffswitch-switch {
|
||||
display: block;
|
||||
width: 19px;
|
||||
margin: 3px;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 23px;
|
||||
border: 1px solid #900;
|
||||
border-radius: 15px;
|
||||
transition: all 0.3s ease-in 0s;
|
||||
}
|
||||
|
||||
.onoffswitch-checkbox:checked + .onoffswitch-label {
|
||||
border-color: #71ae1e;
|
||||
}
|
||||
|
||||
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
|
||||
right: 0px;
|
||||
border-color: #67ac38;
|
||||
}
|
||||
|
||||
.footer .onoffswitch {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#fpsCounter {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#butClear {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#commands {
|
||||
min-width: 600px;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#commands .field {
|
||||
width: 400px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 5px auto;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
#commands .field label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#commands .field span {
|
||||
width: 200px;
|
||||
display: inline-flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.firmware > input {
|
||||
width: 0.1px;
|
||||
height: 0.1px;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.firmware {
|
||||
border-style: solid;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.firmware > svg {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.debug-function {
|
||||
color: #8ec641;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #c64141;
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
color: #8ec641;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
border-radius: 10px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar > div {
|
||||
height: 24px;
|
||||
background-color: #71ae1e;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
#commands .buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 600px;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
#commands .buttons button {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
}
|
||||
8
files/secrets.json
Normal file
8
files/secrets.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"io_username": "YOUR_IO_USERNAME_HERE",
|
||||
"io_key": "YOUR_IO_KEY_HERE",
|
||||
"network_type_wifi_native": {
|
||||
"network_ssid": "YOUR_WIFI_SSID_HERE",
|
||||
"network_password": "YOUR_WIFI_PASS_HERE"
|
||||
}
|
||||
}
|
||||
114
index.html
Normal file
114
index.html
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Install Adafruit.io WipperSnapper for ESP32</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script>
|
||||
// Redirect to HTTPS if HTTP is requested.
|
||||
if (window.location.protocol === 'http:') {
|
||||
window.location.href = 'https:' + window.location.href.substring(5);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- import the web page's stylesheets along with the themes -->
|
||||
<link rel="stylesheet" href="https://use.typekit.net/qtk5kiq.css">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="css/light.css" id="light" class="alternate" disabled>
|
||||
<link rel="stylesheet" href="css/dark.css" id="dark" class="alternate" disabled>
|
||||
|
||||
<!-- import the webpage's javascript file -->
|
||||
<script src="https://adafruit.github.io/Adafruit_WebSerial_ESPTool/js/utilities.js" defer></script>
|
||||
<script src="https://adafruit.github.io/Adafruit_WebSerial_ESPTool/js/esptool.js" defer></script>
|
||||
<script src="js/littlefs.js" defer></script>
|
||||
<script src="js/script.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="header">
|
||||
<div class="left">
|
||||
<img src="https://adafruit.github.io/Adafruit_WebSerial_ESPTool/assets/adafruit-logo.svg" class="Adafruit-Logo">
|
||||
</div>
|
||||
<div class="right">
|
||||
<select id="baudRate"></select>
|
||||
<button id="butConnect" type="button">Connect</button>
|
||||
</div>
|
||||
</header>
|
||||
<main class="main">
|
||||
<div id="notSupported" class="notSupported">
|
||||
Sorry, <b>Web Serial</b> is not supported on this device, make sure you're
|
||||
running Chrome 78 or later and have enabled the
|
||||
<code>#enable-experimental-web-platform-features</code> flag in
|
||||
<code>chrome://flags</code>
|
||||
</div>
|
||||
<div class="subheader">
|
||||
<div class="title left">
|
||||
Install Adafruit.io WipperSnapper for ESP32
|
||||
</div>
|
||||
<div class="right">
|
||||
<label for="darkmode">
|
||||
Dark Mode
|
||||
</label>
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" name="darkmode" class="onoffswitch-checkbox" id="darkmode">
|
||||
<label class="onoffswitch-label" for="darkmode">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app" class="connected">
|
||||
<div id="commands">
|
||||
<div class="field">
|
||||
<label><span>SSID:</span>
|
||||
<input id="network_type_wifi_native.network_ssid" class="partition-data" type="text" placeholder="WiFi SSID" value="" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label><span>Password:</span>
|
||||
<input id="network_type_wifi_native.network_password" class="partition-data" type="text" placeholder="WiFi Password" value="" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label><span>Adafruit IO Username:</span>
|
||||
<input id="io_username" class="partition-data" type="text" placeholder="AIO Username" value="" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label><span>Adafruit IO Password:</span>
|
||||
<input id="io_key" class="partition-data" type="text" placeholder="AIO Password" value="" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<div id="stepname" class="hidden"></div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<div id="progressBar" class="progress-bar hidden"><div></div></div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button id="butProgram" type="button" disabled="disabled">Install WipperSnapper</button>
|
||||
<button id="butProgramNvm" type="button" disabled="disabled">Update Credentials ONLY</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="log"></div>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="left">
|
||||
<label for="autoscroll">Autoscroll</label>
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" name="autoscroll" class="onoffswitch-checkbox" id="autoscroll">
|
||||
<label class="onoffswitch-label" for="autoscroll">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span id="fpsCounter"></span>
|
||||
<button id="butClear" type="button">Clear Text</button>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
3465
js/littlefs.js
Normal file
3465
js/littlefs.js
Normal file
File diff suppressed because it is too large
Load diff
628
js/script.js
Normal file
628
js/script.js
Normal file
|
|
@ -0,0 +1,628 @@
|
|||
// Note: the code will still work without this line, but without it you
|
||||
// will see an error in the editor
|
||||
/* global EspLoader, ESP_ROM_BAUD, port, reader, inputBuffer, generate */
|
||||
'use strict';
|
||||
|
||||
const ESP8266_SETTINGS = {
|
||||
"offset": 0x200000,
|
||||
"imagesize": 65536,
|
||||
"blocksize": 8192
|
||||
}
|
||||
|
||||
const ESP32_SETTINGS = {
|
||||
"offset": 0x290000,
|
||||
"imagesize": 94208,
|
||||
"blocksize": 4096,
|
||||
}
|
||||
|
||||
// C3 is not tested (or currently used)
|
||||
const ESP32_C3_SETTINGS = {
|
||||
"offset": 0x290000,
|
||||
"imagesize": 94208,
|
||||
"blocksize": 4096,
|
||||
}
|
||||
|
||||
const DO_DOWNLOAD = false
|
||||
|
||||
let espTool;
|
||||
let isConnected = false;
|
||||
|
||||
const baudRates = [115200];
|
||||
const flashSizes = {
|
||||
"512KB": 0x00,
|
||||
"256KB": 0x10,
|
||||
"1MB": 0x20,
|
||||
"2MB": 0x30,
|
||||
"4MB": 0x40,
|
||||
"2MB-c1": 0x50,
|
||||
"4MB-c1": 0x60,
|
||||
"8MB": 0x80,
|
||||
"16MB": 0x90,
|
||||
};
|
||||
|
||||
const secretsFilename = "secrets.json";
|
||||
const binFolder = "bin/";
|
||||
|
||||
const structure = {
|
||||
0xe000: "boot_app0.bin",
|
||||
0x1000: "Wippersnapper_demo.ino.bootloader.bin",
|
||||
0x10000: "Wippersnapper_demo.ino.bin",
|
||||
0x8000: "Wippersnapper_demo.ino.partitions.bin",
|
||||
}
|
||||
|
||||
const stage_erase_all = 0x01;
|
||||
const stage_flash_structure = 0x02;
|
||||
const stage_flash_nvm = 0x03;
|
||||
|
||||
const full_program = [stage_erase_all, stage_flash_structure, stage_flash_nvm];
|
||||
const nvm_only_program = [stage_flash_nvm];
|
||||
|
||||
const bufferSize = 512;
|
||||
const colors = ['#00a7e9', '#f89521', '#be1e2d'];
|
||||
const measurementPeriodId = '0001';
|
||||
|
||||
const maxLogLength = 100;
|
||||
const log = document.getElementById('log');
|
||||
const butConnect = document.getElementById('butConnect');
|
||||
const baudRate = document.getElementById('baudRate');
|
||||
const butClear = document.getElementById('butClear');
|
||||
const butProgram = document.getElementById('butProgram');
|
||||
const butProgramNvm = document.getElementById('butProgramNvm');
|
||||
const autoscroll = document.getElementById('autoscroll');
|
||||
const lightSS = document.getElementById('light');
|
||||
const darkSS = document.getElementById('dark');
|
||||
const darkMode = document.getElementById('darkmode');
|
||||
const partitionData = document.querySelectorAll(".field input.partition-data");
|
||||
const progress = document.getElementById('progressBar');
|
||||
const stepname = document.getElementById('stepname');
|
||||
const appDiv = document.getElementById('app');
|
||||
const disableWhileBusy = [partitionData, butProgram, butProgramNvm, baudRate];
|
||||
|
||||
|
||||
let colorIndex = 0;
|
||||
let activePanels = [];
|
||||
let bytesReceived = 0;
|
||||
let currentBoard;
|
||||
let buttonState = 0;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
let debug = false;
|
||||
var getParams = {}
|
||||
location.search.substr(1).split("&").forEach(function(item) {getParams[item.split("=")[0]] = item.split("=")[1]})
|
||||
if (getParams["debug"] !== undefined) {
|
||||
debug = getParams["debug"] == "1" || getParams["debug"].toLowerCase() == "true";
|
||||
}
|
||||
|
||||
espTool = new EspLoader({
|
||||
updateProgress: updateProgress,
|
||||
logMsg: logMsg,
|
||||
debugMsg: debugMsg,
|
||||
debug: debug})
|
||||
butConnect.addEventListener('click', () => {
|
||||
clickConnect().catch(async (e) => {
|
||||
errorMsg(e.message);
|
||||
disconnect();
|
||||
});
|
||||
});
|
||||
butClear.addEventListener('click', clickClear);
|
||||
butProgram.addEventListener('click', clickProgram);
|
||||
butProgramNvm.addEventListener('click', clickProgramNvm);
|
||||
for (let i = 0; i < partitionData.length; i++) {
|
||||
partitionData[i].addEventListener('change', checkProgrammable);
|
||||
partitionData[i].addEventListener('keydown', checkProgrammable);
|
||||
partitionData[i].addEventListener('input', checkProgrammable);
|
||||
}
|
||||
autoscroll.addEventListener('click', clickAutoscroll);
|
||||
baudRate.addEventListener('change', changeBaudRate);
|
||||
darkMode.addEventListener('click', clickDarkMode);
|
||||
window.addEventListener('error', function(event) {
|
||||
console.log("Got an uncaught error: ", event.error)
|
||||
});
|
||||
if ('serial' in navigator) {
|
||||
const notSupported = document.getElementById('notSupported');
|
||||
notSupported.classList.add('hidden');
|
||||
}
|
||||
|
||||
initBaudRate();
|
||||
loadAllSettings();
|
||||
updateTheme();
|
||||
logMsg("Adafruit WebSerial ESPTool loaded.");
|
||||
checkProgrammable();
|
||||
});
|
||||
|
||||
/**
|
||||
* @name connect
|
||||
* Opens a Web Serial connection to a micro:bit and sets up the input and
|
||||
* output stream.
|
||||
*/
|
||||
async function connect() {
|
||||
logMsg("Connecting...")
|
||||
await espTool.connect()
|
||||
readLoop().catch((error) => {
|
||||
toggleUIConnected(false);
|
||||
});
|
||||
}
|
||||
|
||||
function initBaudRate() {
|
||||
for (let rate of baudRates) {
|
||||
var option = document.createElement("option");
|
||||
option.text = rate + " Baud";
|
||||
option.value = rate;
|
||||
baudRate.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
let lastPercent = 0;
|
||||
|
||||
function updateProgress(part, percentage) {
|
||||
if (percentage != lastPercent) {
|
||||
logMsg(percentage + "%...");
|
||||
lastPercent = percentage;
|
||||
}
|
||||
let progressBar = progress.querySelector("div");
|
||||
progressBar.style.width = percentage + "%";
|
||||
}
|
||||
|
||||
/**
|
||||
* @name disconnect
|
||||
* Closes the Web Serial connection.
|
||||
*/
|
||||
async function disconnect() {
|
||||
toggleUIToolbar(false);
|
||||
await espTool.disconnect()
|
||||
toggleUIConnected(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name readLoop
|
||||
* Reads data from the input stream and places it in the inputBuffer
|
||||
*/
|
||||
async function readLoop() {
|
||||
reader = port.readable.getReader();
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) {
|
||||
reader.releaseLock();
|
||||
break;
|
||||
}
|
||||
inputBuffer = inputBuffer.concat(Array.from(value));
|
||||
}
|
||||
}
|
||||
|
||||
function logMsg(text) {
|
||||
log.innerHTML += text+ "<br>";
|
||||
|
||||
// Remove old log content
|
||||
if (log.textContent.split("\n").length > maxLogLength + 1) {
|
||||
let logLines = log.innerHTML.replace(/(\n)/gm, "").split("<br>");
|
||||
log.innerHTML = logLines.splice(-maxLogLength).join("<br>\n");
|
||||
}
|
||||
|
||||
if (autoscroll.checked) {
|
||||
log.scrollTop = log.scrollHeight
|
||||
}
|
||||
}
|
||||
|
||||
function debugMsg(...args) {
|
||||
function getStackTrace() {
|
||||
let stack = new Error().stack;
|
||||
stack = stack.split("\n").map(v => v.trim());
|
||||
for (let i=0; i<3; i++) {
|
||||
stack.shift();
|
||||
}
|
||||
|
||||
let trace = [];
|
||||
for (let line of stack) {
|
||||
line = line.replace("at ", "");
|
||||
trace.push({
|
||||
"func": line.substr(0, line.indexOf("(") - 1),
|
||||
"pos": line.substring(line.indexOf(".js:") + 4, line.lastIndexOf(":"))
|
||||
});
|
||||
}
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
let stack = getStackTrace();
|
||||
stack.shift();
|
||||
let top = stack.shift();
|
||||
let prefix = '<span class="debug-function">[' + top.func + ":" + top.pos + ']</span> ';
|
||||
for (let arg of args) {
|
||||
if (typeof arg == "string") {
|
||||
logMsg(prefix + arg);
|
||||
} else if (typeof arg == "number") {
|
||||
logMsg(prefix + arg);
|
||||
} else if (typeof arg == "boolean") {
|
||||
logMsg(prefix + arg ? "true" : "false");
|
||||
} else if (Array.isArray(arg)) {
|
||||
logMsg(prefix + "[" + arg.map(value => espTool.toHex(value)).join(", ") + "]");
|
||||
} else if (typeof arg == "object" && (arg instanceof Uint8Array)) {
|
||||
logMsg(prefix + "[" + Array.from(arg).map(value => espTool.toHex(value)).join(", ") + "]");
|
||||
} else {
|
||||
logMsg(prefix + "Unhandled type of argument:" + typeof arg);
|
||||
console.log(arg);
|
||||
}
|
||||
prefix = ""; // Only show for first argument
|
||||
}
|
||||
}
|
||||
|
||||
function errorMsg(text) {
|
||||
logMsg('<span class="error-message">Error:</span> ' + text);
|
||||
console.log(text);
|
||||
}
|
||||
|
||||
function formatMacAddr(macAddr) {
|
||||
return macAddr.map(value => value.toString(16).toUpperCase().padStart(2, "0")).join(":");
|
||||
}
|
||||
|
||||
/**
|
||||
* @name updateTheme
|
||||
* Sets the theme to Adafruit (dark) mode. Can be refactored later for more themes
|
||||
*/
|
||||
function updateTheme() {
|
||||
// Disable all themes
|
||||
document
|
||||
.querySelectorAll('link[rel=stylesheet].alternate')
|
||||
.forEach((styleSheet) => {
|
||||
enableStyleSheet(styleSheet, false);
|
||||
});
|
||||
|
||||
if (darkMode.checked) {
|
||||
enableStyleSheet(darkSS, true);
|
||||
} else {
|
||||
enableStyleSheet(lightSS, true);
|
||||
}
|
||||
}
|
||||
|
||||
function enableStyleSheet(node, enabled) {
|
||||
node.disabled = !enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name reset
|
||||
* Reset the Panels, Log, and associated data
|
||||
*/
|
||||
async function reset() {
|
||||
bytesReceived = 0;
|
||||
|
||||
// Clear the log
|
||||
log.innerHTML = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickConnect
|
||||
* Click handler for the connect/disconnect button.
|
||||
*/
|
||||
async function clickConnect() {
|
||||
if (espTool.connected()) {
|
||||
await disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
await connect();
|
||||
|
||||
toggleUIConnected(true);
|
||||
try {
|
||||
if (await espTool.sync()) {
|
||||
toggleUIToolbar(true);
|
||||
appDiv.classList.add("connected");
|
||||
let baud = parseInt(baudRate.value);
|
||||
logMsg("Connected to " + await espTool.chipName());
|
||||
logMsg("MAC Address: " + formatMacAddr(espTool.macAddr()));
|
||||
espTool = await espTool.runStub();
|
||||
if (baud != ESP_ROM_BAUD) {
|
||||
if (await espTool.chipType() == ESP32) {
|
||||
logMsg("WARNING: ESP32 is having issues working at speeds faster than 115200. Continuing at 115200 for now...")
|
||||
} else {
|
||||
await changeBaudRate(baud);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
errorMsg(e);
|
||||
await disconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name changeBaudRate
|
||||
* Change handler for the Baud Rate selector.
|
||||
*/
|
||||
async function changeBaudRate() {
|
||||
saveSetting('baudrate', baudRate.value);
|
||||
if (isConnected) {
|
||||
let baud = parseInt(baudRate.value);
|
||||
if (baudRates.includes(baud)) {
|
||||
await espTool.setBaudrate(baud);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickAutoscroll
|
||||
* Change handler for the Autoscroll checkbox.
|
||||
*/
|
||||
async function clickAutoscroll() {
|
||||
saveSetting('autoscroll', autoscroll.checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickDarkMode
|
||||
* Change handler for the Dark Mode checkbox.
|
||||
*/
|
||||
async function clickDarkMode() {
|
||||
updateTheme();
|
||||
saveSetting('darkmode', darkMode.checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickProgram
|
||||
* Click handler for the program button.
|
||||
*/
|
||||
async function clickProgram() {
|
||||
await programScript(full_program);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickProgramNvm
|
||||
* Click handler for the program button.
|
||||
*/
|
||||
async function clickProgramNvm() {
|
||||
await programScript(nvm_only_program);
|
||||
}
|
||||
|
||||
async function populateSecretsFile(path) {
|
||||
let response = await fetch(path);
|
||||
let contents = await response.json();
|
||||
|
||||
// Get the secrets data
|
||||
for (let field of getValidFields()) {
|
||||
updateObject(contents, partitionData[field].id, partitionData[field].value);
|
||||
}
|
||||
// Convert the data to text and return
|
||||
return JSON.stringify(contents, null, 4);
|
||||
}
|
||||
|
||||
function updateObject(obj, path, value) {
|
||||
if(typeof obj === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var _index = path.indexOf('.')
|
||||
if(_index > -1) {
|
||||
return updateObject(obj[path.substring(0, _index)], path.substr(_index + 1), value);
|
||||
}
|
||||
|
||||
obj[path] = value;
|
||||
}
|
||||
|
||||
async function programScript(stages) {
|
||||
let params = {
|
||||
'files': [{
|
||||
'filename': secretsFilename,
|
||||
'callback': populateSecretsFile,
|
||||
}],
|
||||
'rootFolder': "files",
|
||||
'fileSystemSize': 0,
|
||||
'blockSize': 0,
|
||||
}
|
||||
|
||||
let steps = [];
|
||||
for (let i=0; i<stages.length; i++) {
|
||||
if (stages[i] == stage_erase_all) {
|
||||
steps.push({
|
||||
name: "Erasing Flash",
|
||||
func: async function() {
|
||||
await espTool.eraseFlash();
|
||||
},
|
||||
params: {},
|
||||
})
|
||||
} else if (stages[i] == stage_flash_structure) {
|
||||
for (const [offset, filename] of Object.entries(structure)) {
|
||||
steps.push({
|
||||
name: "Flashing " + filename,
|
||||
func: async function(params) {
|
||||
let firmware = await getFirmware(params["filename"]);
|
||||
await espTool.flashData(firmware, params["offset"], 0);
|
||||
},
|
||||
params: {
|
||||
filename: filename,
|
||||
offset: offset,
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if (stages[i] == stage_flash_nvm) {
|
||||
steps.push({
|
||||
name: "Generating and Flashing LittleFS Partition",
|
||||
func: async function(params) {
|
||||
let chipType = await espTool.chipType();
|
||||
let offset;
|
||||
if (chipType == ESP8266) {
|
||||
logMsg("Using ESP8266 Settings...");
|
||||
params.params.fileSystemSize = ESP8266_SETTINGS.imagesize;
|
||||
params.params.blockSize = ESP8266_SETTINGS.blocksize;
|
||||
offset = ESP8266_SETTINGS.offset;
|
||||
} else if (chipType == ESP32) {
|
||||
logMsg("Using ESP32 Settings...");
|
||||
params.params.fileSystemSize = ESP32_SETTINGS.imagesize;
|
||||
params.params.blockSize = ESP32_SETTINGS.blocksize;
|
||||
offset = ESP32_SETTINGS.offset;
|
||||
} else {
|
||||
errorMsg("Unsupported Chip!");
|
||||
return;
|
||||
}
|
||||
|
||||
let fileSystemImage = await generate(params.params);
|
||||
|
||||
if (DO_DOWNLOAD) {
|
||||
// Download the Partition
|
||||
var blob = new Blob([new Uint8Array(fileSystemImage)], {type: "application/octet-stream"});
|
||||
var link = document.createElement('a');
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = "littleFS.bin";
|
||||
link.click();
|
||||
link.remove();
|
||||
} else {
|
||||
await espTool.flashData(new Uint8Array(fileSystemImage).buffer, offset, 0);
|
||||
}
|
||||
},
|
||||
params: {
|
||||
params: params,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for (let i=0; i<disableWhileBusy.length; i++) {
|
||||
if (Array.isArray(disableWhileBusy[i])) {
|
||||
for (let j=0; j<disableWhileBusy[i].length; i++) {
|
||||
disableWhileBusy[i][j].disable = true;
|
||||
}
|
||||
} else {
|
||||
disableWhileBusy[i].disable = true;
|
||||
}
|
||||
}
|
||||
|
||||
progress.classList.remove("hidden");
|
||||
stepname.classList.remove("hidden");
|
||||
|
||||
for (let i=0; i<steps.length; i++) {
|
||||
stepname.innerText = steps[i].name + " ("+ (i + 1) +"/" + steps.length + ")...";
|
||||
await steps[i].func(steps[i].params);
|
||||
}
|
||||
|
||||
stepname.classList.add("hidden");
|
||||
stepname.innerText = "";
|
||||
progress.classList.add("hidden");
|
||||
progress.querySelector("div").style.width = "0";
|
||||
|
||||
for (let i=0; i<disableWhileBusy.length; i++) {
|
||||
if (Array.isArray(disableWhileBusy[i])) {
|
||||
for (let j=0; j<disableWhileBusy[i].length; i++) {
|
||||
disableWhileBusy[i][j].disable = false;
|
||||
}
|
||||
} else {
|
||||
disableWhileBusy[i].disable = false;
|
||||
}
|
||||
}
|
||||
|
||||
checkProgrammable();
|
||||
disconnect();
|
||||
logMsg("To run the new firmware, please reset your device.")
|
||||
}
|
||||
|
||||
function getValidFields() {
|
||||
// Get a list of file and offsets
|
||||
// This will be used to check if we have valid stuff
|
||||
// and will also return a list of files to program
|
||||
let validFields = [];
|
||||
for (let i=0; i<4; i++) {
|
||||
//let pd = parseInt(partitionData[i].value, 16);
|
||||
if (partitionData[i].value.length > 0) {
|
||||
validFields.push(i);
|
||||
}
|
||||
}
|
||||
return validFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name checkProgrammable
|
||||
* Check if the conditions to program the device are sufficient
|
||||
*/
|
||||
async function checkProgrammable() {
|
||||
butProgramNvm.disabled = getValidFields().length < 4;
|
||||
butProgram.disabled = getValidFields().length < 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name checkFirmware
|
||||
* Handler for firmware upload changes
|
||||
*/
|
||||
async function checkFirmware(event) {
|
||||
let filename = event.target.value.split("\\" ).pop();
|
||||
let label = event.target.parentNode.querySelector("span");
|
||||
let icon = event.target.parentNode.querySelector("svg");
|
||||
if (filename != "") {
|
||||
if (filename.length > 17) {
|
||||
label.innerHTML = filename.substring(0, 14) + "…";
|
||||
} else {
|
||||
label.innerHTML = filename;
|
||||
}
|
||||
icon.classList.add("hidden");
|
||||
} else {
|
||||
label.innerHTML = "Choose a file…";
|
||||
icon.classList.remove("hidden");
|
||||
}
|
||||
|
||||
await checkProgrammable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @name clickClear
|
||||
* Click handler for the clear button.
|
||||
*/
|
||||
async function clickClear() {
|
||||
reset();
|
||||
}
|
||||
|
||||
function convertJSON(chunk) {
|
||||
try {
|
||||
let jsonObj = JSON.parse(chunk);
|
||||
return jsonObj;
|
||||
} catch (e) {
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleUIToolbar(show) {
|
||||
isConnected = show;
|
||||
for (let i=0; i< 4; i++) {
|
||||
progress.classList.add("hidden");
|
||||
progress.querySelector("div").style.width = "0";
|
||||
}
|
||||
if (show) {
|
||||
appDiv.classList.add("connected");
|
||||
} else {
|
||||
appDiv.classList.remove("connected");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleUIConnected(connected) {
|
||||
let lbl = 'Connect';
|
||||
if (connected) {
|
||||
lbl = 'Disconnect';
|
||||
} else {
|
||||
toggleUIToolbar(false);
|
||||
}
|
||||
butConnect.textContent = lbl;
|
||||
}
|
||||
|
||||
function loadAllSettings() {
|
||||
// Load all saved settings or defaults
|
||||
autoscroll.checked = loadSetting('autoscroll', true);
|
||||
baudRate.value = loadSetting('baudrate', baudRates[0]);
|
||||
darkMode.checked = loadSetting('darkmode', false);
|
||||
}
|
||||
|
||||
function loadSetting(setting, defaultValue) {
|
||||
let value = JSON.parse(window.localStorage.getItem(setting));
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function saveSetting(setting, value) {
|
||||
window.localStorage.setItem(setting, JSON.stringify(value));
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function getFirmware(filename) {
|
||||
let response = await fetch(binFolder + filename);
|
||||
return await response.arrayBuffer();
|
||||
}
|
||||
10
license.md
Normal file
10
license.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Melissa LeBlanc-Williams for Adafruit Industries
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
1
stubs/esp32.json
Normal file
1
stubs/esp32.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"text": "CAD0PxwA9D8AAPQ/pOv9PxAA9D82QQAh+v/AIAA4AkH5/8AgACgEICB0nOIGBQAAAEH1/4H2/8AgAKgEiAigoHTgCAALImYC54b0/yHx/8AgADkCHfAAAPgg9D/4MPQ/NkEAkf3/wCAAiAmAgCRWSP+R+v/AIACICYCAJFZI/x3wAAAAECD0PwAg9D8AAAAINkEA5fz/Ifv/DAjAIACJApH7/4H5/8AgAJJoAMAgAJgIVnn/wCAAiAJ88oAiMCAgBB3wAAAAAEA2QQBl/P8Wmv+B7f+R/P/AIACZCMAgAJgIVnn/HfAAAAAAgAAAAAABmMD9P////wAEIPQ/NkEAIfz/OEIWIwal+P8WygWIQgz5DAOHqQyIIpCIEAwZgDmDMDB0Zfr/pfP/iCKR8v9AiBGHOR+R7f/ME5Hs/6Hv/8AgAIkKgdH/wCAAmQjAIACYCFZ5/xwJDBgwiZM9CIhCMIjAiUKIIjo4OSId8JDA/T8IQP0/gIAAAISAAABAQAAASID9P5TA/T82QQCx+P8goHSltwCW6gWB9v+R9v+goHSQmIDAIACyKQCR8/+QiIDAIACSGACQkPQbycDA9MAgAMJYAJqbwCAAokkAwCAAkhgAger/kJD0gID0h5lGgeT/keX/oej/mpjAIADICbHk/4ecGUYCAHzohxrhRgkAAADAIACJCsAgALkJRgIAwCAAuQrAIACJCZHY/5qIDAnAIACSWAAd8AAAUC0GQDZBAEGw/1g0UDNjFvMDWBRaU1BcQYYAAGXr/4hEphgEiCSHpfLl4/8Wmv+oFM0DvQKB8v/gCACgoHSMOiKgxClUKBQ6IikUKDQwMsA5NB3wCCD0PwAAQABw4vo/SCQGQPAiBkA2YQDl3P+tAYH8/+AIAD0KDBLs6ogBkqIAkIgQiQGl4f+R8v+h8//AIACICaCIIMAgAIJpALIhAKHv/4Hw/+AIAKAjgx3wAAD/DwAANkEAgYT/kqABkkgAMJxBkmgCkfr/MmgBKTgwMLSaIiozMDxBDAIpWDlIpfj/LQqMGiKgxR3wAAAskgBANkEAgqDArQKHkg6ioNuB+//gCACioNyGAwCCoNuHkgiB9//gCACioN2B9P/gCAAd8AAAADZBADoyBgIAAKICABsi5fv/N5L0HfAAAAAQAABYEAAAfNoFQNguBkCc2gVAHNsFQDYhIaLREIH6/+AIAIYKAAAAUfX/vQFQQ2PNBK0CgfX/4AgAoKB0/CrNBL0BotEQgfL/4AgASiJAM8BWM/2h6/+y0RAaqoHt/+AIAKHo/xwLGqrl9/8tAwYBAAAAIqBjHfAAAAA2QQCioMCBy//gCAAd8AAAbBAAAGgQAABwEAAAdBAAAHgQAAD8ZwBA0JIAQAhoAEA2QSFh+f+B+f8aZkkGGohi0RAMBCwKWQhCZhqB9v/gCABR8f+BzP8aVVgFV7gCBjgArQaByv/gCACB7f9x6f8aiHpRWQhGJgCB6P9Ac8AaiIgIvQFweGPNB60CgcH/4AgAoKB0jMpx3/8MBVJmFnpxBg0AAKX1/3C3IK0B5ev/JfX/zQcQsSBgpiCBtv/gCAB6InpEN7TOgdX/UHTAGoiICIc3o4bv/wAMCqJGbIHQ/xqIoigAgdD/4AgAVur+sab/ogZsGrtlgwD36gz2RQlat6JLABtVhvP/sq/+t5rIZkUIUiYaN7UCV7SooZv/YLYgEKqAgZ3/4AgAZe3/oZb/HAsaqmXj/6Xs/ywKgbz/4AgAHfAAwPw/T0hBSajr/T+I4QtAFOALQAwA9D84QPQ///8AAAAAAQCMgAAAEEAAAABAAAAAwPw/BMD8PxAnAAAUAPQ/8P//AKjr/T8IwPw/sMD9P3xoAEDsZwBAWIYAQGwqBkA4MgZAFCwGQMwsBkBMLAZANIUAQMyQAEB4LgZAMO8FQFiSAEBMggBANsEAId7/DAoiYQhCoACB7v/gCAAh2f8x2v8GAQBCYgBLIjcy9+Xg/wxLosEgJdf/JeD/MeT+IeT+QdL/KiPAIAA5ArHR/yGG/gwMDFpJAoHf/+AIAEHN/1KhAcAgACgELApQIiDAIAApBIF9/+AIAIHY/+AIACHG/8AgACgCzLocxEAiECLC+AwUIKSDDAuB0f/gCADxv//RSP/Bv/+xqP7ioQAMCoHM/+AIACG8/0Gl/iozYtQrDALAIABIAxZ0/8AgAFgDDBTAIAApA0JBEEIFAQwnQkERclEJKVEmlAccN3cUHgYIAEIFA3IFAoBEEXBEIGZEEUglwCAASARJUUYBAAAcJEJRCaXS/wyLosEQ5cj/QgUDcgUCgEQRcEQgcaD/cHD0R7cSoqDA5cP/oqDupcP/5c//Rt//AHIFAQzZl5cChq8AdzlWZmcCBugA9ncgZjcCxoEA9kcIZicCRmcABigAZkcCRpUAZlcCBsQARiQADJmXlwLGpwB3ORBmdwLGxQBmhwKGIADGHQAAAGaXAka3AAy5l5cCRpAABhkAHDmXlwIGUAB3OSpmtwLGXQAcCXc5DAz57QKXlwKGRADGEAAcGZeXAgZlABwkR5cCBnsAhgsAkqDSl5cCxkAAdzkQkqDQlxdbkqDRlxdpxgQAAACSoNOXlwKGVwGSoNSXlwKGVgDtAnKg/0bAACxJ7QJyoMCXFAIGvQApUUKgByCiIKW0/yCiICW0/2XA/2XA/7KgCKLBEAtEZbb/VvT9RiYAAAAMF1Y0LIFk/+AIAKB0g8atAAAAACaEBAwXBqsAQiUCciUDcJQgkJC0Vrn+Jaf/cESAnBoG+P8AoKxBgVj/4AgAVjr9ctfwcKTAzCcGgQAAoID0Vhj+RgQAoKD1gVH/4AgAVir7gTv/gHfAkTr/cKTAdznkxgMAAKCsQYFI/+AIAFY6+XLX8HCkwFan/sZwAHKgwCaEAoaMAO0CDAfGigAmtPXGYwByoAEmtAKGhgCyJQOiJQJlrf8GCQAAcqABJrQCBoEAkSb/QiUEIOIgcqDCR7kCBn0AuFWoJQwX5aD/oHKDxngADBlmtCxIRaEc/+0CcqDCR7oCBnQAeDW4VaglcHSCmeFlnv9B/f2Y4SlkQtQreSSgkoN9CQZrAJH4/e0CogkAcqDGFgoaeFmYJULE8ECZwKKgwJB6kwwKkqDvhgIAAKq1sgsYG6qwmTBHKvKiBQVCBQSAqhFAqiBCBQbtAgBEEaCkIEIFB4BEAaBEIECZwEKgwZB0k4ZTAEHg/e0CkgQAcqDGFgkUmDRyoMhWiROSRAB4VAZMAAAcie0CDBeXFALGSADoZfh12FXIRbg1qCWB+P7gCADtCqByg0ZCAAwXJkQCxj8AqCW9AoHw/uAIAAYfAABAoDTtAnKgwFaKDkC0QYuVTQp8/IYOAACoOZnhucHJ0YHr/uAIAJjhuMF4KagZ2AmgpxDCIQ0mBw7AIADiLQBwfDDgdxBwqiDAIACpDRtEkskQtzTCBpr/ZkQChpj/7QJyoMBGIwAMFya0AsYgAEHH/phVeCWZBEHG/nkEfQIGHACxwv4MF8gLQsTwnQJAl5PAcpNwmRDtAnKgxlZZBYG8/nKgydgIRz1KQKAUcqDAVhoEfQoMH0YCAHqVmGlLd5kKnQ9w7cB6rEc37RYp36kL6QjGev8MF2aEF0Gt/ngEjBdyoMgpBAwaQan+cKKDKQR9Cu0CcKB04mEMZYX/4iEM4KB05YT/JZH/Vge5QgUBcqAPdxRARzcUZkQCRnkAZmQCxn8AJjQChtz+hh8AHCd3lAKGcwBHNwscF3eUAgY6AEbW/gByoNJ3FE9yoNR3FHNG0v4AAACYNaGP/lglmeGBm/7gCABBjP6Bjf7AIABIBJjhQHQ1wEQRgEQQQEcgkESCrQJQtMKBkv7gCACio+iBj/7gCAAGwf4AANIlBcIlBLIlA6glJYr/Rrz+ALIFA0IFAoC7EUC7ILLL8KLFGGVq/wa2/kIFA3IFAoBEEXBEIHFW/ULE8Jg3kERjFuSrmBealJCcQQYCAJJhDqVU/5IhDqInBKYaBKgnp6nrpUz/Fpr/oicBQMQgssUYgXL+4AgAFkoAgqDEiVeIF0qIiReIN0BIwEk3xpz+ggUDcgUCgIgRcIggQsUYgsjwDBUGIAAAkVf+cVn9WAmJcVB3wHlheCYMGne4AQw6idGZ4anBZU3/qMFxUP6pAaFP/r0E7QXywRjdB8LBHIFY/uAIAF0KuCaocYjRmOGgu8C5JqCIwLgJqkSoYaq7C6WgpSC5CaCvBXC7wMya0tuADB7QroMW6gCtB4nRmeGlWv+Y4YjReQmRGf14OYyoUJ8xUJnA1ikAVsf21qUAURT9QqDHSVVGAACMNZwHxmz+FgebgQ/9QqDISVhGaf4AkQz9QqDJSVlGZv4ASCVWNJmtAoE0/uAIAKEg/oEu/uAIAIEx/uAIAEZe/gBINRY0l60CgSz+4AgAoqPogSb+4AgA4AQABlf+HfAAADZBAJ0CgqDAKAOHmQ/MMgwShgcADAIpA3zihg4AJhIHJiIWhgMAAACCoNuAKSOHmSYMIikDfPJGBwAioNwnmQgMEikDLQiGAwCCoN188oeZBgwSKQMioNsd8AAA", "text_start": 1074520064, "entry": 1074521516, "data": "CMD8Pw==", "data_start": 1073605544}
|
||||
1
stubs/esp32c3.json
Normal file
1
stubs/esp32c3.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"text": "QREixCbCBsa3NwRgEUfYyzc0BGC3RMg/XECRi5HnskAiRJJEQQGCgAhAg6cEABN19Q+Cl9W3ARG3BwBgSsgDqYcAJspOxlLEBs4izLcEAGD9WTdKyD/ATBN09A8N4PJAYkQjqCQBsknSREJJIkoFYYKAiECDJwoAE3X1D4KXfRTjGTT/yb83JwBgfEudi/X/NzcAYHxLnYv1/4KAQREGxt03tycAYCOmBwI3BwAImMOYQ33/yFeyQBNF9f8FiUEBgoBBEQbG2T993TcHAEC3JwBgmMM3JwBgHEP9/7JAQQGCgEERIsQ3RMk/kwfECZxLBsYmwqHPXTcxyRMExAkYSL1HgURj1ucABES9iJO0FABNP5U/HEQ3BwABE5bHAGN/5gC3BoAAmeC3BgABNycAYFDDFMO3JgBgmEJ9/0FHkeAFRxRIupccxJmOFMiyQCJEkkRBAYKAEwcADJxBYxvlAIHnhUecwSGoI6AFAPlXPoWCgAVHY4fnAIlGY43XAP1X/beTFwUBEwewDcGH4xHl/olHyb+TB8ANYxb1AJjBkwcADPG3kwbQDf1X4xLV/JjBkwewDW2/t0XJP0ERk4VFCQbGUT9jSQUGt0fJP5OHxwCDpgcIA9dHCBN19Q9CB0GDEwYXAEIGQYIjkscINpcjAKcAA9dHCJFnk4cHBEIHQYNjHvcCN8fIPxMHxwChZ7qXA6YHCLcGyT+3R8k/k4fHAJOGxgRjH+YAI6bHCCOg1wgjkgcIIaD5V+MG9fyyQEEBgoAjptcII6DnCN23QREGxpcAyP/ngADmA0WFAbJAdRUTNRUAQQGCgEERBsbFNxHBDUWyQEEBFwPI/2cAo+BBEQbGlwDI/+eAYN7JNwHFskBBAdm/skBBAYKAQREGxhMHAAxjGuUAEwWwDdE/EwXADbJAQQHptxMHsA3jG+X+wTcTBdAN9bdBESLEJsIGxiqEswS1AGMXlACyQCJEkkRBAYKAA0UEAAUETT/ttxMFAAx5twERIsw3RMk/kwfECSbKxEcGzkrITsYTBMQJY/OVAK6EucADKUQAqokmmRNZyQAcSGNV8AAcRGNf+QKFO33dSEAmhs6FlwDI/+eAYN8TdfUPAcWTB0AMXMhcQKaXXMBcRLOEl0BExPJAYkTSREJJskkFYYKAtTtlvwERBs4izBk7NwTOP2wAEwVE/5cAyP/ngADehUcV5bJHk/cHID7GDTs3JwBgHEe3BkAAEwVE/9WPHMeyRZcAyP/ngKDbszegAPJAYkQ+hQVhgoBBEbdHyT8FRwbGI47nCJOHxwkT18UAmMcFZ30XzMPIx/mNOpWqlbGBjMsjqgcAQTcZwRMFUAyyQEEBgoB1cUrBfXMFaSLFJsPO3tLc1toGx310GpGTBwkHipcTBIT6PpSqiSKFroSXAMj/54AgH5MHCQcFaoqXs4pHQbngBWeTBwcHfXSTBYT6ipcTBIT5PpSTBwcHipe+lSKFlwDI/+eAYBwihcFFlTUBRQVjGpG6QCpEmkQKSfZZZlrWWklhgoAmiWNzmgAFaUqG1oVOhZcAyP/ngGDKE3X1DwHtSobWhSKFlwDI/+eAoBfKmbOEJEFptxMFMAZVvzFxfXNW01rRXs9izQbfIt0m20rZTtdS1WbLasluxwVnGpE2jBMHBwcUCDaX/Xe6lz7GI6oH+KqKLouyi7E7kwcAAhnBtwcCAD6FlwDI/+eAoBCFZ2PjdxWFZBgIfXSThwQHupcTBIT6M4mHAEqFlwDI/+eAIA99ehgIk4cEB7qXkww6+b6ck4cEBxMNivm6l4FJPp2FZ5OHBwcYCLqXM4RHAYMtRPlj9m0LY/G5A1WgYTOmhSKFsTtBMyaGooVKhZcAyP/ngEAKppqmmWP2aQOzh7lBY/KHA7MHO0HehGPzdwG+hCaGooVWhZcAyP/ngCC5E3X1D03dhWeThwcHGAi6lzOERwEjLAT4gUSNTaMJBPhmhZcAyP/ngICqffkDRTT56oW9PmNABQLj4p3+hWcYCJOHBwe6lzOHlwBSlyMKp/iFBOm3+VfjE/X8EUfjg+T0BWcUCJMHBwd9dLaXkwWE+hMEhPk+lJMHBwe2l76VIoWXAMj/54Bg/305wUUihUk5XTkRObcHAgAZ4ZMHAAI+hZcAyP/ngGD8BWMakfpQalTaVEpZulkqWppaClv6S2pM2kxKTbpNKWGCgLdXQUlZcZOH94QBRT7Ohtai1KbSytDOztLM1srayN7G4sTmwurAbt6XAMj/54BAordHyD83d8k/k4cHABMHh7pj6+cSJTmRRWgIMTEFObfHyD+Th8cAIWc+lyMg9wi3BzhAN0rIP5OHZxsjIPoAt0rJP602k4rKABMKCgBjAQUQtycMYEVHuNeFRUVFlwDI/+eAQO63BThAAUaThQUARUWXAMj/54BA7zc3BGAcSzcFAgCT50cAHMuXAMj/54BA7pcAyP/ngMD+t0cAYJxfEeUT9ccBYRUTNRUAgUWXAMj/54CAocFnN0vJP/0XEwcAEIVmQWa3BQABAUWTCcsJjWs3TMg/lwDI/+eAAJzOm5MMzACDp8oI9d+DpMoIhUcjpgoIIwTxAoPHFAAJRyMV4QKjBPECAtYpR2OG5wZNR2OA5wgtPqFFKBA5NgPHNACDxyQAkWYiB12Pk4cGAWP15wYTBbANbTQTBcANVTQTBeAOeTwpNnm/I6AHAJEH0bW3BThAAUaThWUDFUWXAMj/54Cg4DcHAGBcRxMFAAKT5xcQXMcZv4PHNAADxyQAogfZjxFH45jn+JxEnEM+1lm3yUcjFfECvb+DxxQANUZjiscqY272DhlGY4vHNGNi9ggNRmOKxxZjbPYECUZjhcckAUkTBPAPE3X0Dw08E3X5DzU0tTzjGATwg8cUAD1HY4jnQmNq9zQRR2OC51IZR2OA51QNR+OY5+6DxTQAg8ckABOFhAGiBd2NwRWpNOG9kUZjgdcMlUbjldf6wUcFRWMZ9w6cRNhIIyT6ACMi6gCdqqVGY4vXImPs9gKdRmOI1yahRuOf1/aTB0ACYxr3BgLWHUQBRXEyAUVVMtU6zTqhRSgQfRTRMnX0AUkBRKm/qUZjjNcirUbjldf04UdjGPcc3EyYTNRIkEjMRIhElwDI/+eAoIAqiTM1oAAqhC23TUZji8cUY2T2BEFGY4nHFmNs9gC9RuOW1/ChR+MH9/oBSRMEAAwJt8VGY4/XBElH45nn7oNHywljgAceg6fJAGOUByQjDgsIA6RJASWgkwYgDWOB1xBj4fYCkwYADWOK1waTBhAN457X6qFHYwz3BgVFKoQBSU29kwYwDWOH10KTBkAN45/X6INHywljhgcYnERBFwOkSQFjhOcAEwQADIFHkwbwDmPN5w4Dx1QAg8dEAAFJIgddj4PHZADCB12Pg8d0AOIH2Y/jgPbmEwQQDKG9BURF85fwx//ngOBwMzSgAEm/A62EAMBEs2eNABOXRwE9/y06Lf1BaSKdfRn9fTMFjUAZ6AFFrbcxgZfwx//ngABuMf1ulOW3s3clAfX3QWkzBY1AY26JAH15MwWNQHnYMYGX8Mf/54CAaxX5SpT1t0GBl/DH/+eAQGoV8TMEJEHBv8FH2bXBRwVE4xz38MxEiEShOqW/wUcFROMU9/CcSGPn9hDMSIhEGTKNtwVE4xr37pxIY+32DsBEzEiIRDOEhwL1MCOsCQAjpIuwgbczhvQAA0aGAYUHsY7tvQFJBUWptZFHBUXjHffqiESBRZfwx//ngIBmPb+Td/cA45kH5BNdRwAThIQAAUn9XeN2qd9IRJfwx//ngABTHERYQBRAfY9jh7cBkEKTx/f/8Y9dj5jCBQlBBNm/kUcBvYMlSgBBF5HlCc8BSRMEYAwps4MnigBj5ucGk3c3AOOaB94DKIoAAUaBR7OG9QAzBfhAY+nnAOMDBtgjItoAIySqAK27M4b0ABBOkQeQwgVG6b+hRwVF4xf34AMkigAZwBMEgAwjJAoAIyIKADM1gADVuwFJEwQgDE2xAUkTBIAMabkBSRMEkAxJuUlHY4rnHGNi9wRFR+OR57qDxzQAA8ckABOEhAGiB9mPk40H/wVJg6fJAGOFDQCZw2NEIBFjWAkYEwdwDCOq6QDjlwe2kweQDGGiEwcgDWOL5wwTB0AN45zntAPENACDxyQAIgRdjJfwx//ngOBNA6nJAEEUY3MkASKJ4woJsgOkSQBKlDGAg6cJAWNW8ACDp4kAY1D0Cu/wL8N13QOlSQBKhpOFhAGX8Mf/54BgSQnFkwdADCOq+QCDp0kAypcjovkAg6fJADOJJ0EjpikBl/DH/+eAoEfhvAllEwUFcQOpxACARJfwx//ngIA5twcAYNhLtwYAAcEWk1dHARIHdY+9i9mPs4cnAwFFs9WHApfwx//ngGA6EwWAPpfwx//ngCA2cbTUSJBIzESIRO/wT/u9vO/wz72Bv7d2yT8Dp4a6t8fIP5OHxwCZjz7Sg6eLsDd9yT9u0BMNzQmThIa6BUhj8/0ADUhCxjrE7/BPuiJHMkg3Rck/ooVcEJMGzAAQEBMFRQuX8Mf/54DAOYJXAyeNsIxAs439QB2PPpSSVyMk7bAqib6VjMCTB8wAnY1jVaAAoWfjmfXmZoXv8E/WI6CUAZW14x4J5uODB56TB4AMI6r5AOm6nETjmwec7/CPywllEwUFcZfwx//ngGApl/DH/+eA4CxlusBE4woEmu/wb8kTBYA+l/DH/+eAYCcClHm6tlAmVJZUBln2SWZK1kpGS7ZLJkyWTAZN8l1lYYKA", "text_start": 1077411840, "entry": 1077413488, "data": "DEDIPw==", "data_start": 1070164904}
|
||||
1
stubs/esp32h2.json
Normal file
1
stubs/esp32h2.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"text": "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", "text_start": 1077411840, "entry": 1077413328, "data": "DEDIPw==", "data_start": 1070164904}
|
||||
1
stubs/esp32s2.json
Normal file
1
stubs/esp32s2.json
Normal file
File diff suppressed because one or more lines are too long
1
stubs/esp32s3.json
Normal file
1
stubs/esp32s3.json
Normal file
File diff suppressed because one or more lines are too long
1
stubs/esp8266.json
Normal file
1
stubs/esp8266.json
Normal file
File diff suppressed because one or more lines are too long
7
wsPartitions.csv
Normal file
7
wsPartitions.csv
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Wippersnapper ESP32 Non-Volatile Storage (NVM) Partition Template,,,
|
||||
key,type,encoding,value
|
||||
wsNamespace,namespace,,
|
||||
wsNetSSID,data,string,YOURSSID
|
||||
wsNetPass,data,string,YOURSSIDPASS
|
||||
wsAIOUser,data,string,YOURAIOUSER
|
||||
wsAIOKey,data,string,YOURAIOPASS
|
||||
|
Loading…
Reference in a new issue