Fixed firmware uploading

GZipped HTML, JS and CSS
Added gulp task for copying firmware binary to bin folder
This commit is contained in:
Mark van Renswoude 2018-01-03 21:44:34 +01:00
parent d9ae78ba07
commit 0aca40c71e
17 changed files with 2559 additions and 1497 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.pioenvs .pioenvs
.piolibdeps .piolibdeps
bin
*.sublime-workspace *.sublime-workspace
node_modules node_modules

View File

@ -17,12 +17,17 @@ const watch = require('gulp-debounced-watch');
const uglify = require('gulp-uglify'); const uglify = require('gulp-uglify');
const concat = require('gulp-concat'); const concat = require('gulp-concat');
const print = require('gulp-print'); const print = require('gulp-print');
const path = require('path');
const gzip = require('gulp-gzip');
const config = { const config = {
assetsPath: 'web/', assetsPath: 'web/',
distPath: 'web/dist/', distPath: 'web/dist/',
outputPath: 'src/assets/' outputPath: 'src/assets/',
firmwareArtifact: '.pioenvs/esp12e/firmware.bin',
firmwareOutputPath: 'bin/'
}; };
@ -89,9 +94,11 @@ gulp.task('embedHTML', function()
minifyCSS: true, minifyCSS: true,
minifyJS: true minifyJS: true
})) }))
.pipe(gzip({ append: false }))
.pipe(cppstringify('html.h', { .pipe(cppstringify('html.h', {
headerDefineName: '__assets_html', headerDefineName: '__assets_html',
map: HTMLMap map: HTMLMap,
byteArray: true
})) }))
.pipe(gulp.dest(config.outputPath)); .pipe(gulp.dest(config.outputPath));
}); });
@ -135,9 +142,11 @@ gulp.task('compileJS', function()
gulp.task('embedJS', ['compileJS'], function() gulp.task('embedJS', ['compileJS'], function()
{ {
return gulp.src([config.distPath + 'bundle.js']) return gulp.src([config.distPath + 'bundle.js'])
.pipe(gzip({ append: false }))
.pipe(cppstringify('js.h', { .pipe(cppstringify('js.h', {
headerDefineName: '__assets_js', headerDefineName: '__assets_js',
map: JSMap map: JSMap,
byteArray: true
})) }))
.pipe(gulp.dest(config.outputPath)); .pipe(gulp.dest(config.outputPath));
}); });
@ -146,16 +155,26 @@ gulp.task('embedJS', ['compileJS'], function()
gulp.task('embedCSS', ['compileScss'], function() gulp.task('embedCSS', ['compileScss'], function()
{ {
return gulp.src([config.distPath + 'bundle.css']) return gulp.src([config.distPath + 'bundle.css'])
.pipe(gzip({ append: false }))
.pipe(cppstringify('css.h', { .pipe(cppstringify('css.h', {
headerDefineName: '__embed_css', headerDefineName: '__embed_css',
map: CSSMap map: CSSMap,
byteArray: true
})) }))
.pipe(gulp.dest(config.outputPath)); .pipe(gulp.dest(config.outputPath));
}); });
gulp.task('embedVersion', function()
var version = false;
function getVersion(callback)
{ {
if (version !== false)
{
callback(version);
return;
}
var versionData = ''; var versionData = '';
const cmd = spawn('gitversion'); const cmd = spawn('gitversion');
@ -174,6 +193,15 @@ gulp.task('embedVersion', function()
if (code != 0) return; if (code != 0) return;
var version = JSON.parse(versionData); var version = JSON.parse(versionData);
callback(version);
});
}
gulp.task('embedVersion', function(cb)
{
getVersion(function(version)
{
var headerFile = "#ifndef __assets_version\r\n"; var headerFile = "#ifndef __assets_version\r\n";
headerFile += "#define __assets_version\r\n\r\n"; headerFile += "#define __assets_version\r\n\r\n";
headerFile += "const uint8_t VersionMajor = " + version.Major + ";\r\n"; headerFile += "const uint8_t VersionMajor = " + version.Major + ";\r\n";
@ -194,11 +222,29 @@ gulp.task('embedVersion', function()
fs.writeFile(config.outputPath + 'version.h', headerFile, function(err) fs.writeFile(config.outputPath + 'version.h', headerFile, function(err)
{ {
if (err) throw err; if (err) throw err;
cb();
}); });
}); });
}); });
gulp.task('copyBinary', function(cb)
{
if (!fs.existsSync(config.firmwareOutputPath))
fs.mkdirSync(config.firmwareOutputPath, '0777', true);
getVersion(function(version)
{
var target = path.join(config.firmwareOutputPath, version.FullSemVer + '.bin');
console.log('Target: ' + target);
var reader = fs.createReadStream(config.firmwareArtifact);
reader.pipe(fs.createWriteStream(target));
reader.on('end', cb);
});
});
gulp.task('embedAssets', ['embedHTML', 'embedJS', 'embedCSS', 'embedVersion'], function() { }) gulp.task('embedAssets', ['embedHTML', 'embedJS', 'embedCSS', 'embedVersion'], function() { })
@ -238,6 +284,12 @@ var platformio = function(target)
{ {
console.log(data.toString().trim()); console.log(data.toString().trim());
}); });
cmd.on('exit', function(code)
{
if (code != 0) return;
gulp.start('copyBinary');
});
} }
gulp.task('upload', ['embedHTML', 'embedAssets'], function() { platformio('upload'); }); gulp.task('upload', ['embedHTML', 'embedAssets'], function() { platformio('upload'); });

View File

@ -21,6 +21,7 @@
"gulp-clean-css": "^3.9.0", "gulp-clean-css": "^3.9.0",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-debounced-watch": "^1.0.4", "gulp-debounced-watch": "^1.0.4",
"gulp-gzip": "^1.4.1",
"gulp-htmlmin": "^3.0.0", "gulp-htmlmin": "^3.0.0",
"gulp-plumber": "^1.1.0", "gulp-plumber": "^1.1.0",
"gulp-print": "^2.0.1", "gulp-print": "^2.0.1",

View File

@ -3,109 +3,137 @@
#include <pgmspace.h> #include <pgmspace.h>
const char EmbeddedBundleCSS[] PROGMEM = const uint8_t EmbeddedBundleCSS[] PROGMEM = {
"*,:after,:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#606c76;fo" 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0xc5,0x1a,0x4d,0x93,0xa3,0xba,0xf1,0xaf,0x90,0x99,
"nt-family:Roboto,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.6em;font-weight:300;letter-" 0xda,0x9a,0xb7,0x79,0xc0,0x62,0x6c,0x33,0x63,0xbc,0xb3,0x95,0xe4,0x94,0x43,0x92,0x43,0x0e,0xb9,0x6c,
"spacing:.01em;line-height:1.6}blockquote{border-left:.3rem solid #404040;margin-left:0;margin-right:" 0xed,0x41,0x06,0x61,0x54,0x8b,0x91,0x03,0x62,0x3c,0xf3,0x28,0xfe,0x7b,0x5a,0x1f,0x18,0x09,0x04,0x9e,
"0;padding:1rem 1.5rem}blockquote :last-child{margin-bottom:0}.button,button,input[type=button],input" 0xc9,0x4b,0x55,0xd6,0xb5,0x63,0xd3,0xea,0x6e,0xb5,0xba,0x5b,0xad,0xee,0x16,0x7f,0x74,0x63,0x94,0x31,
"[type=reset],input[type=submit]{background-color:#06f;border:.1rem solid #06f;border-radius:.4rem;co" 0x5c,0xb9,0xf1,0x01,0x67,0xb4,0xc2,0xed,0x81,0xbe,0x7a,0x35,0xf9,0x8d,0x94,0xc7,0x98,0x94,0x39,0xae,
"lor:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-s" 0x08,0xeb,0x72,0x76,0x2a,0x74,0xf8,0x81,0x56,0x29,0xae,0x3c,0x80,0xec,0x33,0x5a,0x32,0x0e,0xc6,0x71,
"pacing:.1rem;line-height:3.8rem;padding:0 3rem;text-align:center;text-decoration:none;text-transform" 0x14,0xfa,0xdb,0x4f,0xdd,0x81,0xa6,0x6f,0x6d,0x42,0x0b,0x5a,0xc5,0xf7,0x51,0x10,0x25,0x8f,0x91,0x44,
":uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type=butto" 0xc9,0xd0,0x89,0x14,0x6f,0xf1,0x3f,0xe9,0x81,0x32,0xea,0x3e,0xfc,0x15,0x17,0x2f,0x98,0x91,0x04,0x39,
"n]:focus,input[type=button]:hover,input[type=reset]:focus,input[type=reset]:hover,input[type=submit]" 0xff,0xc0,0x0d,0x7e,0x70,0xaf,0xcf,0xee,0x9f,0x2b,0x82,0x0a,0xb7,0x46,0x65,0xed,0xd5,0x30,0x79,0xa6,
":focus,input[type=submit]:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}." 0xcd,0xb0,0xf2,0x23,0x7c,0x92,0xcf,0x17,0x4c,0x8e,0x39,0x8b,0xd7,0x41,0xb0,0x2f,0x30,0x03,0xf1,0xbd,
"button[disabled],button[disabled],input[type=button][disabled],input[type=reset][disabled],input[typ" 0xfa,0x8c,0x12,0x2e,0x9b,0x1f,0xac,0x00,0xa9,0x20,0x25,0xf6,0x72,0x89,0x04,0x64,0xdd,0xa1,0xa0,0xc9,
"e=submit][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button" 0xcf,0x7f,0x37,0x94,0xf1,0xf5,0x09,0xe1,0x0b,0x9c,0xb1,0xd8,0x5f,0x57,0xf8,0xe4,0xd4,0xb4,0x20,0xa9,
"[disabled]:focus,button[disabled]:hover,input[type=button][disabled]:focus,input[type=button][disabl" 0x73,0xbf,0x09,0xf8,0x67,0x7f,0x42,0xd5,0x91,0x94,0x72,0xfc,0xfa,0x54,0x09,0x4e,0xc1,0xfe,0x8c,0xd2,
"ed]:hover,input[type=reset][disabled]:focus,input[type=reset][disabled]:hover,input[type=submit][dis" 0x94,0xcf,0xb2,0xe2,0x74,0x2b,0x7f,0x0b,0x5f,0x1a,0x6f,0x27,0x2e,0x50,0xcd,0xbc,0x24,0x27,0x45,0xda,
"abled]:focus,input[type=submit][disabled]:hover{background-color:#06f;border-color:#06f}.button.butt" 0x2a,0x4a,0x58,0x2f,0xa3,0xa7,0x38,0xe8,0xfc,0x43,0x03,0xbf,0x4a,0x57,0x7d,0x91,0xf2,0xdc,0xb0,0xef,
"on-outline,button.button-outline,input[type=button].button-outline,input[type=reset].button-outline," 0xec,0xed,0x8c,0x9f,0x25,0xe4,0x87,0x0e,0xaa,0x70,0x8d,0x99,0x01,0xa9,0x9b,0xc3,0x89,0xb0,0x1f,0xed,
"input[type=submit].button-outline{background-color:transparent;color:#06f}.button.button-outline:foc" 0x01,0x25,0x3f,0x8f,0x15,0x6d,0xca,0xd4,0x53,0x6a,0x0e,0xa2,0x6c,0x2f,0x17,0x15,0xfb,0x2b,0x6d,0x3d,
"us,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type=b" 0x03,0xdc,0xab,0x50,0x4a,0x9a,0x3a,0xf6,0x37,0x30,0xbc,0x57,0x64,0x59,0x96,0xed,0x93,0xa6,0xaa,0xe1,
"utton].button-outline:focus,input[type=button].button-outline:hover,input[type=reset].button-outline" 0xf7,0x99,0x92,0x12,0x74,0xb8,0x4f,0x49,0x7d,0x2e,0xd0,0x1b,0xd8,0x5d,0xe8,0x4f,0x2c,0xcc,0xd0,0x3f,
":focus,input[type=reset].button-outline:hover,input[type=submit].button-outline:focus,input[type=sub" 0x67,0x6f,0x18,0xe0,0x11,0x0c,0xa0,0xd4,0xbc,0xf6,0x9f,0xf8,0xe8,0xd8,0x1c,0x82,0x44,0x37,0x87,0xc2,
"mit].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.bu" 0xeb,0x35,0x19,0x38,0xdc,0x06,0x7b,0x86,0x5f,0x99,0x87,0x0a,0x72,0x2c,0xe3,0x04,0x0b,0x61,0x04,0x24,
"tton-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:" 0xc5,0x09,0xad,0x10,0x23,0xb4,0x8c,0x4b,0x5a,0x62,0x09,0x64,0x15,0x78,0x07,0xf8,0xea,0x29,0x6e,0xce,
"focus,button.button-outline[disabled]:hover,input[type=button].button-outline[disabled]:focus,input[" 0x67,0x5c,0x25,0xa8,0xc6,0xfb,0x4b,0x4e,0x18,0x16,0xb3,0x62,0xc0,0xbc,0x54,0xe8,0xdc,0x2b,0x3c,0xce,
"type=button].button-outline[disabled]:hover,input[type=reset].button-outline[disabled]:focus,input[t" 0x68,0xd2,0xd4,0x6e,0xff,0x94,0xd3,0x17,0x70,0x76,0x63,0xc8,0x18,0x99,0xda,0x45,0x61,0x59,0x06,0x26,
"ype=reset].button-outline[disabled]:hover,input[type=submit].button-outline[disabled]:focus,input[ty" 0x14,0xd2,0x6c,0x53,0x02,0x05,0x9f,0xe0,0x2b,0xa3,0x4e,0x09,0xfa,0x01,0x41,0x61,0xb1,0xb9,0xda,0x5a,
"pe=submit].button-outline[disabled]:hover{border-color:inherit;color:#06f}.button.button-clear,butto" 0xca,0xbc,0x26,0x50,0xb3,0x2f,0x6d,0x18,0x57,0xfd,0xe0,0x7d,0xdf,0xc1,0xc4,0xe8,0x50,0xe0,0xf4,0x87,
"n.button-clear,input[type=button].button-clear,input[type=reset].button-clear,input[type=submit].but" 0x3b,0x01,0x4c,0x17,0x68,0x1f,0x94,0x8b,0xb1,0x8f,0x29,0xb9,0x87,0xc1,0x56,0xb9,0x58,0x8a,0x33,0xd4,
"ton-clear{background-color:transparent;border-color:transparent;color:#06f}.button.button-clear:focu" 0x14,0x6c,0x4f,0xb9,0x5f,0xb0,0xb7,0xd8,0xdf,0x4e,0x45,0x32,0x2d,0xa5,0xc1,0x75,0x9b,0x4d,0xd0,0x67,
"s,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type=button]." 0xb0,0x97,0x56,0x33,0x6b,0xd1,0x25,0x2e,0xe3,0x65,0xcf,0x59,0x79,0x89,0xc7,0x44,0x3d,0xb3,0x96,0x1f,
"button-clear:focus,input[type=button].button-clear:hover,input[type=reset].button-clear:focus,input[" 0x73,0x59,0xdc,0xf7,0x1a,0xa4,0xd7,0xaa,0xfa,0xf2,0x94,0x07,0xb8,0x76,0xe8,0x54,0x03,0x0b,0x18,0x72,
"type=reset].button-clear:hover,input[type=submit].button-clear:focus,input[type=submit].button-clear" 0x79,0x0b,0x08,0x4a,0xf4,0x11,0xc6,0x54,0x72,0xb1,0x7f,0xcf,0xa8,0x82,0x7d,0xbe,0xbf,0x29,0xb9,0xe9,
":hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disa" 0x14,0xe3,0x41,0xdd,0x33,0xec,0x84,0x4b,0x74,0x37,0x97,0x3f,0xeb,0x28,0x37,0xf9,0x59,0x95,0x35,0xe7,
"bled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-c" 0x32,0x37,0xb9,0xd9,0x35,0x3b,0xeb,0x3c,0x56,0x7e,0xcb,0x76,0x58,0x8a,0x24,0xf2,0x69,0xc6,0x3e,0x73,
"lear[disabled]:hover,input[type=button].button-clear[disabled]:focus,input[type=button].button-clear" 0xdb,0x77,0x1e,0x6d,0xc1,0x66,0x33,0x9b,0xfb,0x16,0xaf,0x9b,0xf6,0x79,0xc7,0xd6,0xff,0xc0,0x1c,0x56,
"[disabled]:hover,input[type=reset].button-clear[disabled]:focus,input[type=reset].button-clear[disab" 0xa3,0xdd,0x0e,0x0c,0x1f,0x98,0xc1,0x6e,0xc7,0x77,0x84,0x8d,0x1b,0x73,0xb4,0x86,0x99,0x55,0x7a,0xb7,
"led]:hover,input[type=submit].button-clear[disabled]:focus,input[type=submit].button-clear[disabled]" 0xb0,0x07,0x93,0x02,0xa3,0xb1,0xa9,0x24,0x6c,0x5e,0x81,0x93,0x71,0x73,0xf5,0x93,0xe1,0x91,0xe4,0x62,
":hover{color:#06f}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:." 0xfc,0x03,0xbe,0xfa,0xbe,0x60,0x22,0xb8,0xda,0x1d,0x54,0x0e,0xd9,0x9c,0x52,0x27,0x9a,0xa7,0xb9,0xa1,
"2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:.3rem solid #06f;overflow-y:hidden}" 0x89,0x9b,0x0e,0x37,0xc3,0xcb,0xa2,0xb5,0x5b,0x8e,0x35,0xc3,0xc9,0xa6,0xe0,0x9b,0x0e,0xa4,0xf1,0xfa,
"pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:.1" 0x7d,0xc6,0xb0,0x07,0x0f,0xc1,0xfe,0x56,0xe8,0x18,0x23,0xcd,0xda,0xe8,0x46,0xd8,0xb0,0xf3,0xb9,0x61,
"rem solid #f4f5f6;margin:3rem 0}input[type=email],input[type=number],input[type=password],input[type" 0x91,0x0f,0x84,0x8c,0x9b,0xfc,0x2d,0x66,0x7a,0x7f,0xb8,0xb8,0xc9,0xdd,0x66,0xb9,0x0f,0x84,0x0a,0x2b,
"=search],input[type=tel],input[type=text],input[type=url],select,textarea{appearance:none;background" 0xff,0x56,0xdb,0x4a,0x09,0x4d,0xf5,0x43,0x1c,0x32,0xcb,0x4d,0xb6,0xcd,0x22,0x6b,0x6d,0x31,0x14,0x0b,
"-color:transparent;border:.1rem solid #404040;border-radius:.4rem;box-shadow:none;box-sizing:inherit" 0x4f,0xd1,0x27,0x55,0x3c,0x41,0x8a,0xef,0x87,0x7a,0xca,0x2f,0x9e,0x1c,0x51,0x3c,0xd9,0xf2,0xf6,0x73,
";height:3.8rem;padding:.6rem 1rem;width:100%}input[type=email]:focus,input[type=number]:focus,input[" 0xb5,0x34,0xdd,0xb4,0x6e,0xe3,0x79,0x10,0x97,0x39,0x2b,0xe8,0xc5,0x7b,0x8b,0x73,0x92,0xa6,0xb8,0xe4,
"type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[typ" 0x5c,0xbe,0x49,0xc9,0x0d,0x31,0x83,0x6b,0x91,0x23,0xab,0x1b,0x4b,0x41,0x67,0xc8,0x04,0x6c,0xba,0xbc,
"e=url]:focus,select:focus,textarea:focus{border-color:#06f;outline:0}select{background:url('data:ima" 0x8f,0x9b,0x40,0xad,0xb8,0x31,0x7a,0x36,0x8b,0x2d,0x25,0xa4,0x5a,0xb1,0x10,0x2f,0xe8,0x34,0xa5,0xe3,
"ge/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"14\" viewBox=\"0 0 29 14\" width=" 0x13,0x22,0x85,0x91,0x2a,0x97,0xcd,0xe9,0x80,0x2b,0x03,0x74,0x46,0x75,0x7d,0x81,0x09,0xcc,0x94,0x1a,
"\"29\"><path fill=\"#d1d1d1\" d=\"M9.37727 3.625l5.08154 6.93523L19.54036 3.625\"/></svg>') center r" 0xcc,0x93,0xe4,0x06,0x88,0xe1,0x62,0xf4,0xfc,0x6a,0x16,0x8b,0x4d,0x05,0x08,0x35,0x2e,0x70,0xc2,0x5c,
"ight no-repeat;padding-right:3rem}select:focus{background-image:url('data:image/svg+xml;utf8,<svg xm" 0x3e,0x08,0x3b,0x12,0xb5,0x08,0x8a,0x25,0x04,0x1b,0x54,0x68,0x1a,0x6a,0xa9,0x77,0x6c,0x6b,0x73,0x8d,
"lns=\"http://www.w3.org/2000/svg\" height=\"14\" viewBox=\"0 0 29 14\" width=\"29\"><path fill=\"#9b" 0xaa,0x40,0xb6,0xd9,0x5d,0x34,0x07,0x72,0x94,0xd2,0x8b,0xe2,0x3d,0x69,0x22,0xec,0xed,0xe5,0x9f,0x1f,
"4dca\" d=\"M9.37727 3.625l5.08154 6.93523L19.54036 3.625\"/></svg>')}textarea{min-height:6.5rem}labe" 0x09,0xc5,0x0b,0xb5,0x93,0x94,0xe5,0xf1,0x2a,0x08,0x3e,0x4d,0x15,0x37,0xf5,0x62,0xa5,0xbe,0xe9,0xc0,
"l,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;" 0x55,0x89,0x16,0xcf,0x97,0xaa,0x9c,0x0e,0x70,0x85,0xda,0xa0,0xaf,0xb6,0xda,0x8c,0x2b,0x57,0x41,0xa5,
"padding:0}input[type=checkbox],input[type=radio]{display:inline}.label-inline{display:inline-block;f" 0x8a,0xd5,0x43,0xaf,0x68,0xf9,0xd8,0x4e,0x52,0x73,0xad,0x1a,0x93,0x74,0xba,0x97,0x03,0xd3,0x5f,0x1e,
"ont-weight:400;margin-left:.5rem}.container{margin:0 auto;max-width:112rem;padding:0 2rem;position:r" 0x52,0xc4,0x50,0x4c,0x4e,0xe8,0x88,0xbf,0xd4,0x2f,0xc7,0x5f,0x5f,0x4f,0xc5,0xbe,0x61,0xd9,0x93,0xfb,
"elative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{" 0x15,0x9e,0x1c,0x78,0x2a,0xeb,0xe7,0xbb,0x9c,0xb1,0x73,0xfc,0xe5,0xcb,0xe5,0x72,0xf1,0x2f,0x6b,0x9f,
"padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-item" 0x56,0xc7,0x2f,0x61,0x10,0x04,0x1c,0xff,0xce,0x91,0x2a,0x7e,0xbe,0x5b,0x6d,0xee,0x9c,0x17,0x82,0x2f,
"s:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretc" 0x7f,0xa1,0xaf,0xcf,0x77,0x81,0x13,0x38,0xe1,0xce,0xe1,0x30,0xa1,0xe1,0xe7,0xbb,0x70,0x77,0xf7,0xed,
"h{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 aut" 0xeb,0x19,0xb1,0xdc,0xc9,0x48,0x51,0x3c,0xdf,0xdd,0xa7,0x2b,0xfe,0xb9,0x73,0xd2,0xe7,0xbb,0xbf,0xef,
"o;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column" 0xfc,0xf5,0xe3,0x63,0xf8,0xe8,0xac,0xfd,0x28,0xdc,0x16,0x5b,0x3f,0x78,0x5a,0x6d,0x37,0x4e,0xe4,0xef,
".column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-" 0xd6,0xdb,0x70,0xfd,0xb7,0xd5,0xce,0xdf,0x6e,0x82,0x75,0x24,0x87,0xef,0xbe,0x7c,0xfb,0xca,0x67,0xfe,
"offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-50{margin-le" 0xf6,0xf0,0xd9,0x91,0x55,0xbb,0x23,0x1a,0x25,0x4e,0x49,0xbd,0x0a,0x83,0xb7,0xb1,0xde,0xce,0xaa,0x81,
"ft:50%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column" 0xc2,0xf7,0x45,0xa7,0x2b,0x4d,0x3f,0x5b,0xc4,0xc2,0xff,0xbf,0x8a,0xd8,0x1d,0x36,0x69,0x82,0x7e,0x97,
".column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-" 0x22,0xba,0xeb,0x7e,0x3b,0x91,0xb2,0xef,0x79,0x44,0xb2,0x53,0x54,0xa0,0x03,0x2e,0xdc,0x02,0x1f,0x71,
"offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{f" 0x99,0xb6,0x66,0x1c,0x32,0xba,0x5c,0xb6,0x2e,0x8b,0xd9,0x4e,0x92,0xfc,0x32,0x82,0x8b,0x14,0xce,0x8a,
"lex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,." 0xde,0xd7,0xe4,0x0e,0x1a,0xba,0x54,0x46,0x04,0x4a,0x72,0x9c,0xfc,0x84,0x7d,0x69,0xd6,0xf2,0xb0,0x89,
"row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-w" 0xe9,0x8f,0xab,0x2c,0xb2,0xf1,0xd3,0xf9,0x42,0x50,0x4f,0x3e,0x8d,0x06,0xf5,0xae,0x90,0x12,0x6f,0x13,
"idth:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-w" 0x98,0x5d,0x33,0x29,0x9c,0x9f,0x00,0x0a,0x02,0x8a,0xaa,0xbd,0x9e,0x03,0xa8,0x61,0x14,0x50,0x5f,0x95,
"idth:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .co" 0xa4,0xab,0x55,0x68,0xb6,0x82,0xe4,0x23,0xad,0x89,0xe8,0xf8,0x54,0xb8,0x40,0x8c,0xbc,0x60,0x3d,0x32,
"lumn.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .co" 0xf8,0x15,0xbd,0x5c,0x25,0xca,0x0a,0xfc,0xba,0xe7,0x7f,0xbc,0x94,0x54,0xe0,0x53,0x9c,0x08,0xf6,0x5b,
"lumn.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .colum" 0x73,0x2a,0x07,0x9e,0x63,0x62,0xfe,0xdf,0x03,0xff,0x54,0x08,0xed,0xa0,0x2b,0xcb,0xe8,0x37,0x5f,0xb2,
"n .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width" 0xb3,0x61,0xf1,0xb3,0xaa,0x15,0x93,0xf3,0x5f,0xb1,0x6c,0x39,0xf5,0x83,0x70,0x3e,0xb4,0xa2,0x9b,0xe5,
":40rem){.row{flex-direction:row;margin-left:-1rem;width:calc(100% + 2rem)}.row .column{margin-bottom" 0xc1,0x51,0x72,0xaa,0x85,0xa4,0x5e,0x0d,0x7e,0xc1,0x06,0x1c,0x69,0xca,0x29,0x1a,0x38,0xc7,0x80,0x24,
":inherit;padding:0 1rem}}a{color:#06f;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{li" 0xb7,0x95,0x81,0x24,0x41,0x03,0x4a,0xcd,0x2a,0xcc,0x92,0xdc,0xc0,0x51,0x30,0x6d,0x32,0x04,0xdb,0x8e,
"st-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font" 0x5b,0x53,0xc7,0xea,0x81,0x02,0xcd,0xe9,0xd7,0x3a,0x72,0x4c,0x10,0x29,0x5e,0x39,0xab,0xde,0x76,0x66,
"-size:90%;margin:1.5rem 0 1.5rem 3rem}ol{list-style:decimal inside}ul{list-style:circle inside}.butt" 0x73,0xf4,0x6a,0x49,0x50,0xef,0x58,0xd3,0x3d,0x43,0xf5,0xe5,0xd1,0x2c,0x03,0x5f,0xf5,0x56,0x41,0xab,
"on,button,dd,dt,li{margin-bottom:1rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote" 0x73,0x59,0x2d,0x63,0x87,0x26,0x76,0x78,0x03,0x7b,0x6b,0x62,0x6f,0x17,0xb1,0xd7,0x6b,0x77,0x69,0x74,
",dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;width:100%}td,th{borde" 0x63,0xf0,0x5a,0xaf,0xfd,0x35,0xfc,0x5b,0x64,0xb8,0x35,0x85,0xdd,0x2e,0x0b,0x1b,0x45,0x4b,0xd3,0x47,
"r-bottom:.1rem solid #e1e1e1;padding:1.2rem 1.5rem;text-align:left}td:first-child,th:first-child{pad" 0x8f,0x06,0xaf,0x28,0xf2,0x23,0xf8,0xb7,0xc8,0xf0,0xd1,0x5c,0xfd,0xe3,0xf2,0xea,0x9f,0x4c,0x61,0x9f,
"ding-left:0}td:last-child,th:last-child{padding-right:0}b,strong{font-weight:700}p{margin-top:0}h1,h" 0x96,0x85,0xdd,0x99,0xd8,0xbb,0x19,0x6c,0x30,0xae,0x70,0x18,0x1e,0x6b,0xc1,0xb2,0x86,0x87,0xd8,0x29,
"2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2rem;margin-top:0}h1{font-size:4.6" 0x42,0x8d,0x22,0x34,0x28,0xe6,0x6c,0x0d,0x46,0x1e,0x28,0xb6,0x06,0xc5,0xcc,0x8a,0x67,0x0c,0x0d,0x16,
"rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font" 0xbe,0x32,0xea,0xcd,0xab,0x71,0x5b,0xb4,0xf8,0x46,0x13,0x7b,0x63,0x88,0xbd,0x99,0x11,0x7b,0xab,0x51,
"-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line" 0x6c,0x0d,0x8a,0x39,0x3f,0x89,0x34,0x8a,0xc8,0xa0,0x88,0xe6,0x28,0xec,0x2e,0x05,0xbe,0x34,0x30,0x52,
"-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{" 0x8e,0xa4,0x73,0x5b,0xf2,0xad,0x47,0x4d,0xdb,0x8f,0x86,0xb6,0xe7,0xfc,0xeb,0x49,0x13,0xfb,0xc9,0x10,
"clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right}[v-cloak]{displ" 0x7b,0xce,0xc7,0x76,0x1a,0xc5,0xce,0xa0,0x18,0xfb,0x59,0xff,0xad,0x05,0x58,0x08,0x61,0xd9,0x38,0xbe,
"ay:none}body{background-color:#000;color:#fff;font-family:Verdana,Arial,sans-serif;font-size:10pt;pa" 0x4e,0xd0,0x8d,0x58,0x3b,0x50,0xf4,0xa1,0x76,0x82,0x6f,0x84,0x5d,0x81,0xaf,0xa2,0xee,0x9f,0x4e,0x38,
"dding-bottom:3rem}@media screen and (min-width:768px){body{padding-top:3rem}}input,textarea{color:#f" 0x25,0xc8,0xf9,0x85,0x1f,0xee,0xbd,0xbd,0xe1,0xd0,0xfa,0xdc,0x8a,0x83,0x69,0x74,0x16,0x01,0xc8,0x88,
"ff}#container{background-color:#202020;margin-top:2rem;padding:1rem;box-shadow:0 0 50px #fcf6cf;bord" 0x98,0x9e,0x96,0xe7,0x26,0xa8,0x48,0x7e,0xe1,0xb1,0xd2,0xf9,0x55,0x1c,0x7b,0x9f,0xcd,0x20,0x6c,0x1e,
"er:solid 1px #000}@media screen and (min-width:768px){#container{width:768px;margin-left:auto;margin" 0xf7,0x7d,0x0e,0x3d,0x9c,0x94,0x9c,0x53,0xd7,0x21,0xad,0x4e,0xb3,0x5e,0x98,0x74,0x2a,0x1b,0x75,0x91,
"-right:auto}}.header{position:relative}.header img{float:left;margin-right:1rem}.header .wifistatus{" 0x59,0xd7,0xa9,0xaa,0x3c,0x2d,0x5c,0x5a,0xb8,0x4d,0xd1,0x16,0xa4,0x86,0xf4,0x83,0xbd,0x15,0xaa,0x36,
"position:absolute;right:0;top:0}.header .wifistatus .indicator{display:inline-block;width:1rem;heigh" 0x50,0xd3,0xf3,0x32,0xe7,0x9a,0x4e,0xa8,0xa8,0x0f,0x44,0x0e,0xd0,0xc1,0x5f,0x2a,0xfe,0x36,0x9c,0x87,
"t:1rem;border-radius:50%;margin-right:.5rem}.header .wifistatus .indicator[data-status=connected]{ba" 0x23,0x38,0x71,0x08,0x15,0x90,0x46,0x40,0x1a,0x01,0x69,0x38,0xa4,0x1d,0x12,0x1c,0x69,0x61,0x91,0x11,
"ckground-color:#396}.header .wifistatus .indicator[data-status=disconnected]{border:solid 1px grey}." 0xc8,0x82,0x8b,0xc7,0x0a,0xf9,0x43,0xe4,0x87,0xd4,0x10,0x07,0x16,0x04,0x89,0x60,0xe1,0x90,0xb2,0x26,
"header .wifistatus .indicator[data-status=connecting]{background-color:#f93}.header .wifistatus .ind" 0x29,0xee,0x4c,0x59,0x13,0x52,0x41,0xf9,0xda,0x8f,0x8d,0x6e,0xd8,0xd2,0xd4,0x4d,0x99,0x5b,0x90,0x91,
"icator[data-status=error]{background-color:#c00}h1{font-size:16pt;margin:0}h2{color:silver;font-size" 0x2e,0x57,0x7a,0xe6,0x24,0x73,0xa1,0x49,0xa9,0x34,0xa2,0x18,0xdf,0xf3,0xc1,0xb2,0xdd,0x8c,0x1c,0x9b,
":10pt;margin:0}h3{color:grey;background-color:#282828;font-size:14pt;border-bottom:solid 1px grey}.v" 0x0a,0xbb,0xfc,0x1a,0x8a,0xeb,0xf0,0xec,0x42,0xa5,0xe8,0x32,0x5e,0x43,0x73,0x7d,0x9a,0x0c,0x42,0xc9,
"ersion{color:grey;font-size:8pt;text-align:center;margin-top:2rem}.tabs{clear:both;margin-top:3rem}." 0x40,0x8c,0xf6,0xb9,0x5a,0x7f,0x41,0x66,0x24,0x28,0x2c,0x75,0x59,0xde,0x5e,0xaf,0x57,0x65,0xaa,0xa7,
"tabs .button{background-color:#404040;color:#fff!important;border-color:grey}.tabs .button.button-ou" 0x97,0x60,0x78,0xc5,0x3f,0x43,0xd5,0x2a,0x4b,0x69,0x55,0xb7,0x6a,0x77,0x68,0xdc,0x54,0xc0,0x2d,0xce,
"tline{background-color:transparent}input[disabled]{cursor:not-allowed;color:grey;background-color:#2" 0x48,0xd5,0x5f,0x48,0x02,0x67,0xfd,0xb1,0x1d,0x59,0x15,0x90,0x87,0xcb,0x4b,0x8e,0xab,0x5d,0x65,0x9a,
"62626}.label-inline{margin-right:2rem}.hint{display:block;font-size:8pt;color:grey;margin-bottom:1.5" 0x49,0x7c,0xd0,0x1d,0x5c,0xc8,0x2f,0x28,0x24,0x4f,0xa3,0x24,0xb5,0x3b,0xb7,0xba,0xe3,0x74,0xf9,0xca,
"rem}.loading{margin-top:3rem;text-align:center}.suboptions{margin-left:5rem}.buttons{text-align:cent" 0xcd,0x43,0x37,0x5f,0xbb,0xf9,0xc6,0xcd,0xb7,0x6e,0x1e,0xb5,0x37,0x2e,0x6f,0x3d,0x79,0x5d,0x38,0xd2,
"er}.slider{-webkit-appearance:none;width:100%;height:.5rem;border-radius:.25rem;background:#404040;o" 0x9e,0x06,0xea,0xf9,0x6a,0xee,0xb4,0x91,0xf9,0xb2,0x79,0xe3,0x1b,0x76,0x79,0xa8,0xe1,0xac,0xad,0x38,
"utline:0}.slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:2rem;height:2re" 0xdb,0x2e,0x5f,0x6b,0x48,0xa1,0xba,0xc0,0x34,0x90,0xd6,0x5d,0xbe,0x31,0x70,0x42,0xcb,0x25,0xa7,0x07,
"m;border-radius:50%;background:#fcf6cf;cursor:pointer}.slider::-moz-range-thumb{width:2rem;height:2r" 0xc5,0x81,0x85,0x14,0xf8,0x6f,0x5b,0x3d,0xb1,0xb7,0x5d,0x90,0x02,0xed,0x76,0x4a,0x0b,0xa4,0x51,0x3b,
"em;border-radius:50%;background:#fcf6cf;cursor:pointer}"; 0xa9,0x09,0x46,0xa4,0xc1,0x88,0x68,0xd3,0x91,0xd3,0xb1,0x35,0x93,0x32,0x48,0xc3,0x79,0x7f,0x27,0x23,
0xaf,0xf2,0x9a,0xbf,0x95,0x8d,0x3d,0x50,0x6d,0xbe,0xe7,0x09,0x3a,0x44,0xb5,0xf8,0xc1,0x79,0xb8,0x76,
0x45,0x84,0x8f,0x76,0x7e,0x56,0x50,0xc4,0x84,0x6b,0xb4,0xe2,0xa7,0x74,0x28,0x05,0x16,0x6e,0xa0,0xe0,
0xe2,0x77,0xf7,0xfd,0xc5,0x4b,0xe0,0xf1,0xe7,0x50,0x49,0x88,0xe0,0x23,0x5e,0x06,0xb0,0x5c,0x5c,0x81,
0xe1,0xb5,0x4b,0x4a,0xfd,0xfd,0x80,0x7f,0xe1,0x2a,0x45,0xe5,0xf2,0x5b,0x00,0xc1,0x79,0x28,0x2b,0x95,
0x8b,0x88,0xb8,0xa1,0x42,0x73,0x9d,0x54,0x18,0x97,0x0e,0x2a,0x53,0x3d,0x4a,0x3f,0x46,0x4f,0xe7,0xd7,
0xcf,0xad,0x90,0xa8,0x27,0xe6,0xce,0x24,0x28,0x65,0x99,0x34,0x6c,0xff,0x41,0xb8,0xee,0x7e,0xa8,0x62,
0xa6,0x0b,0x09,0x03,0xfe,0xd1,0x7d,0xd3,0xa8,0x67,0x56,0xa3,0xce,0x88,0x3c,0xf9,0xcf,0xaf,0xce,0x7d,
0x96,0x64,0x51,0x72,0xbd,0xb5,0x97,0x7b,0x7b,0xc5,0x07,0x40,0x35,0xef,0x5a,0x87,0x26,0x96,0x06,0x37,
0x0e,0x1b,0x3d,0x5f,0x97,0x1b,0x97,0x43,0xba,0xce,0xcf,0x31,0x82,0x59,0xdb,0x49,0x99,0xd5,0x8f,0x38,
0xdc,0x8b,0x06,0xab,0x9b,0x3c,0x44,0xf4,0xec,0x11,0xfd,0x0b,0xc9,0x20,0x18,0x23,0x06,0x85,0xfc,0x95,
0x1d,0x3a,0xc0,0x7a,0x1a,0x86,0xf7,0xfd,0x3b,0x13,0x72,0xcf,0x5a,0x68,0x1c,0x9f,0x94,0x29,0x49,0x10,
0xa3,0x95,0xbd,0xc8,0x54,0x6e,0xcc,0xd5,0xd8,0x3b,0xb9,0x54,0xa9,0xde,0x80,0xda,0x5e,0x8f,0x13,0x25,
0xa2,0x2a,0x3f,0x17,0xe7,0xfb,0xce,0x3b,0x0c,0x9e,0x04,0x3f,0x83,0x2e,0x4b,0x08,0xff,0xfc,0xb6,0x7a,
0x6a,0xe3,0xf5,0x2e,0xfa,0x08,0x2f,0x58,0x87,0xce,0x6e,0x6c,0xe0,0x63,0x85,0xdf,0xfe,0x0b,0xd1,0xc0,
0x9b,0x6c,0xb2,0x65,0xbb,0xf5,0x47,0x98,0xe1,0xaa,0xa2,0x95,0x8d,0x4f,0x12,0x8c,0x62,0xea,0x2a,0x3a,
0xf7,0x76,0xe7,0xe1,0x36,0x54,0x3b,0xa2,0x26,0x05,0xe4,0x10,0xe3,0xbd,0x38,0xe0,0xad,0x15,0x1e,0x5f,
0xe5,0xb4,0xbd,0x78,0x1f,0x3e,0xf1,0x8f,0x4e,0xbe,0x39,0x5f,0x2f,0x10,0xd4,0x4e,0x1e,0xab,0x0a,0xe6,
0xab,0xc1,0xab,0x74,0xc6,0x5a,0x8f,0x19,0xc8,0xa7,0x2f,0x8e,0x8c,0xb6,0x63,0xe7,0x43,0x4c,0xab,0xf5,
0xb8,0xa7,0x21,0xac,0xaf,0x08,0x8e,0xca,0x1e,0x2c,0xea,0x51,0x7d,0xcf,0x21,0x2a,0xfc,0x81,0x9c,0xce,
0xb4,0x62,0x68,0x7c,0xfd,0x21,0x45,0xd6,0xb9,0x7d,0xe4,0x2e,0x5c,0x35,0x6b,0x26,0xaf,0x4e,0x94,0x94,
0x2f,0xb0,0xa0,0x17,0x9c,0xee,0x97,0xf5,0x1b,0xf1,0xcf,0xa8,0x7b,0x63,0x6c,0x0d,0xa9,0x8f,0x9c,0x94,
0x6c,0xb6,0xfd,0xc4,0x75,0xaa,0xcd,0x62,0xcd,0x84,0x7c,0x08,0x0e,0xa2,0x79,0x32,0xd2,0xe4,0xd4,0x18,
0x9d,0x5f,0x37,0x07,0x7a,0xe6,0x81,0xa1,0x36,0x6b,0x63,0xc1,0x47,0x6a,0xa7,0x6e,0x6d,0x74,0xe0,0x07,
0x10,0xa5,0x20,0x59,0x38,0xfc,0x24,0x30,0x38,0x6a,0x5e,0x6b,0x6d,0x07,0x15,0x1a,0x64,0x0e,0x34,0x6a,
0x4e,0x87,0x12,0xa8,0xdd,0x26,0x28,0x63,0x6a,0x6f,0xc6,0xc8,0x99,0xe2,0xb8,0x9f,0x4a,0x3e,0x7b,0x2c,
0x6f,0x4e,0x87,0xd9,0xf9,0xed,0xf2,0x84,0x5a,0xa8,0x0a,0xed,0xa1,0xca,0xb8,0xd9,0x90,0xc7,0x80,0xf9,
0x16,0x96,0x26,0xd0,0x89,0xfe,0x06,0xa4,0xe5,0x11,0x2b,0x61,0xfe,0x87,0x93,0xfc,0x07,0xdc,0x88,0xab,
0x59,0xf7,0x27,0x00,0x00};
#endif #endif

View File

@ -3,57 +3,98 @@
#include <pgmspace.h> #include <pgmspace.h>
const char EmbeddedIndex[] PROGMEM = const uint8_t EmbeddedIndex[] PROGMEM = {
"<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><title></title><meta name=\"theme-color\" content" 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0xcd,0x58,0xe9,0x77,0xda,0x38,0x10,0xff,0x57,0x5c,
"=\"#000000\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><link rel=\"styl" 0xef,0xee,0x23,0x79,0x29,0x67,0x68,0x5a,0xb2,0xc0,0xd6,0xdc,0xf7,0x0d,0x01,0xbe,0xc9,0xb6,0xb0,0x05,
"esheet\" href=\"bundle.css\"><script src=\"bundle.js\"></script></head><body><div id=\"app\"><div v-" 0xf2,0x11,0x4b,0xe6,0xe8,0xf1,0xbf,0xaf,0x7c,0x60,0x1b,0x02,0x49,0xbb,0x7d,0x7d,0x6f,0xf9,0x80,0xd1,
"cloak><div id=\"container\"><div class=\"header\"><img src=\"data:image/png;base64,iVBORw0KGgoAAAANS" 0x9c,0xbf,0x19,0x66,0xa4,0xb1,0xf2,0xef,0x2a,0xfd,0xf2,0x64,0x31,0xa8,0x72,0x2a,0xd5,0x70,0x31,0xef,
"UhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXBJREFUeNrsWdENgjAQL" 0x7f,0x43,0x20,0x17,0xf3,0x1a,0xa4,0x80,0x93,0x54,0x60,0x11,0x48,0x0b,0xfc,0x74,0x52,0x8b,0x7f,0xe2,
"cYBcAPcACdQN4AN2MC4gRsYJ9ENdAPYADaADepdUhM1qFjurgp9ScMHgd713V3ftUp5eHgMF1rrGEau6VHD2HMbH5qJOLHra+fkz" 0x8b,0x79,0x8a,0x28,0x86,0xc5,0x7c,0xd2,0x7f,0xba,0x42,0x3a,0xd0,0x60,0x81,0xa7,0x2a,0xd4,0x60,0x5c,
"bsYRshM8pLTgUIgSgvuMMoYw+iMYTr6QhNYMrNiNywILlyVKdcyyPsmcRsyU50kgHtQQu2AdNJFpDkAK4I/LIWMb2AsIBcq0iRGe" 0x32,0xb0,0x61,0xf1,0x9c,0x64,0xe8,0x14,0xea,0x4c,0xef,0x8f,0x94,0xfb,0xe1,0x4f,0x44,0xb7,0x08,0xee,
"QGPTZfV6QE0+gDGF2rosGEgMQxIAhnZAiPN84upRf0/OlpsLCBp3yq0chgtCUUZrRw6QDO3EWHSqF9tarZaSKJXeJDdbQlsE0KD6" 0x4c,0xc3,0xa2,0x11,0xb9,0x1d,0x92,0xa9,0x5a,0x90,0xe1,0x16,0x49,0x30,0xee,0x2e,0xde,0x23,0x1d,0x51,
"JN/KoRsGhxXKClCKHJIfkThwMWhA6dBSolRijkJOd1ZUv9yQ9OpqbHpiaUVaEbZE7tIIjoBKXysos1c4V8ebLEdbv2bcMsE7gjuB" 0x04,0x70,0x9c,0x48,0x00,0xc3,0x42,0x9a,0x99,0xc0,0x48,0xdf,0x70,0x16,0xc4,0x05,0x9e,0xd0,0x03,0x86,
"dvXRSJ4F+/wqIXXrIGwmX3zwacLDheNO91OjLQKd14VMDCnYgCxVjI3NTe1mSoPD49x4SrAAG9qPn4eovCMAAAAAElFTkSuQmCC" 0x44,0x85,0x90,0xd9,0x50,0x2d,0xb8,0x2a,0xf0,0xa2,0xad,0xcb,0x18,0x26,0x24,0x42,0x98,0x20,0x91,0x2c,
"\"><h1>{{ $t('title') }}</h1><h2>{{ version.systemID !== null ? $t('systemID') + ': ' + version.syst" 0x64,0x52,0x8e,0x58,0x52,0xc0,0x58,0x3b,0xf4,0xa4,0xc7,0x60,0x3f,0xbc,0x18,0x45,0x43,0x3e,0x14,0xf3,
"emID : '' }}</h2><div class=\"wifistatus\"><div class=\"connection\"><div class=\"indicator\" :data-" 0x32,0xda,0x72,0x48,0x2e,0xf0,0xc0,0x34,0x79,0x6f,0xb5,0x8d,0x4b,0xd8,0x00,0x9b,0x90,0xe5,0xe0,0x04,
"status=\"wifiStatus.ap.enabled ? 'connected' : 'disconnected'\"></div>{{ $t('wifiStatus.accesspoint." 0x48,0x87,0x96,0x2f,0x20,0x61,0x40,0x48,0x81,0x77,0xac,0xb8,0x34,0xa4,0x29,0x9e,0x37,0x19,0x50,0xf0,
"title') }} {{ wifiStatus.ap.enabled ? wifiStatus.ap.ip : $t('wifiStatus.accesspoint.disabled') }}</d" 0x88,0x34,0xa0,0xc0,0xa4,0xa9,0x2b,0x7f,0x8b,0x80,0xc0,0x87,0xec,0x7b,0x34,0x2b,0xf5,0x47,0xbb,0x54,
"iv><div class=\"connection\"><div class=\"indicator\" :data-status=\"getWiFiStationStatus()\"></div>" 0xbb,0xae,0x18,0x02,0xfb,0xf4,0xc6,0x53,0xb5,0x3a,0x55,0xd8,0xaf,0x8a,0xb3,0x14,0x76,0x65,0x61,0xc1,
"{{ $t('wifiStatus.stationmode.title') }} {{ getWiFiStationStatusText() }}</div></div></div><div v-if" 0x1e,0xa5,0xb9,0xb0,0xd5,0x1a,0x0e,0xa1,0x3e,0x1f,0xd5,0x9e,0x1a,0xa3,0x89,0x98,0x59,0xa6,0xe4,0x4c,
"=\"loading\" class=\"loading\">{{ $t('loading') }} {{ loadingIndicator }}</div><div v-if=\"!loading" 0xed,0xb0,0x1c,0x96,0x4a,0xcb,0x7a,0x0e,0x2d,0xc7,0xa5,0x96,0xf8,0x54,0xd3,0x97,0xb3,0x16,0x5e,0x3c,
"\"><div class=\"tabs\"><button class=\"button\" :class=\"{ 'button-outline': activeTab != 'status' }" 0x8d,0x3e,0x48,0x12,0xc6,0x03,0x47,0x61,0x5e,0x6a,0x8d,0xaa,0xb5,0x29,0xec,0x59,0xe4,0x49,0xae,0xf6,
"\" @click=\"activeTab = 'status'\">{{ $t('status.tabTitle') }}</button> <button class=\"button\" :cl" 0x94,0xb5,0x30,0xec,0x48,0x8b,0x92,0x24,0x0c,0x24,0xa1,0x2c,0x0f,0x7b,0x59,0xa1,0x97,0xe9,0x96,0xb3,
"ass=\"{ 'button-outline': activeTab != 'triggers' }\" @click=\"activeTab = 'triggers'\">{{ $t('trigg" 0xca,0x88,0x2c,0x5a,0xb9,0x6a,0x4f,0x16,0x06,0x0b,0xa1,0x02,0x84,0x0a,0x34,0xe5,0xa9,0xda,0x4d,0x3f,
"ers.tabTitle') }}</button> <button class=\"button\" :class=\"{ 'button-outline': activeTab != 'conne" 0xd7,0xd6,0xb6,0xa5,0x98,0xb9,0xb1,0xd4,0x6d,0x28,0xf2,0xc7,0xf4,0xfd,0xec,0x7e,0x45,0xa7,0xe6,0x07,
"ction' }\" @click=\"activeTab = 'connection'\">{{ $t('connection.tabTitle') }}</button></div><div v-" 0xd8,0x50,0xba,0xb5,0xb4,0x65,0xd5,0xab,0xc0,0x7e,0x98,0x35,0x2a,0x99,0x46,0x57,0x6c,0x7c,0x78,0x6e,
"if=\"activeTab == 'status'\"><h3>{{ $t('status.title') }}</h3><div class=\"slidecontainer\" v-for=\"" 0xf5,0x3b,0x0d,0x0b,0xdc,0xad,0x36,0x5f,0x44,0xb2,0x18,0x11,0xb5,0xfb,0xc9,0xec,0x4c,0x94,0x69,0x53,
"(step, index) in steps\">{{ index + 1 }} <input type=\"range\" min=\"0\" max=\"100\" class=\"slider" 0x19,0x2b,0x5b,0xbb,0xdb,0x35,0x16,0xbb,0x3b,0xd4,0x5d,0x4c,0xac,0x87,0xa1,0xda,0x5b,0x74,0xad,0x1e,
"\" v-model=\"step.value\"> {{ step.value }}</div></div><div v-if=\"activeTab == 'triggers'\"><form @" 0xea,0x1d,0x76,0xcd,0x0e,0x3e,0xcc,0xda,0xb2,0x74,0x38,0x0c,0x88,0x26,0x8d,0xc8,0x61,0xfa,0x21,0xb5,
"submit.prevent=\"applyTriggers\"><fieldset><h3>{{ $t('triggers.timeTitle') }}</h3></fieldset><fields" 0x51,0x1a,0x74,0x38,0xb4,0x33,0x82,0xdc,0x6b,0xd5,0xcc,0xca,0x46,0x68,0x67,0x9b,0xc9,0x4e,0xf3,0xa9,
"et><h3>{{ $t('triggers.motionTitle') }}</h3></fieldset></form></div><div v-if=\"activeTab == 'connec" 0x2b,0x66,0x04,0xd2,0x2c,0x49,0xcf,0x29,0x34,0xaa,0xc3,0x61,0x7d,0x30,0x59,0xae,0x66,0x0f,0xc3,0x6a,
"tion'\"><form @submit.prevent=\"applyConnection\"><fieldset><h3>{{ $t('connection.title') }}</h3><in" 0xea,0x4e,0xa9,0xd4,0x6b,0x19,0xcb,0x20,0xf5,0xaa,0xd2,0x1d,0xee,0x9b,0x82,0xaa,0x2f,0x05,0x34,0xe8,
"put type=\"checkbox\" id=\"accesspoint\" v-model=\"connection.accesspoint\"><label class=\"label-inl" 0x7d,0xca,0xda,0xe6,0x68,0x95,0x4a,0xf6,0xb1,0x49,0x3a,0xe5,0x92,0x79,0x7f,0x78,0x4e,0x49,0xaa,0x42,
"ine\" for=\"accesspoint\">{{ $t('connection.accesspoint') }}</label><span class=\"hint\">{{ $t('conn" 0xcb,0xd3,0xe9,0xd2,0x1a,0xed,0x1e,0x86,0x95,0xfe,0x7d,0xf5,0xa9,0x31,0x7e,0xae,0xe5,0x28,0xb0,0x96,
"ection.accesspointHint') }}</span> <input type=\"checkbox\" id=\"station\" v-model=\"connection.stat" 0x60,0xdc,0x6e,0xcd,0x61,0xab,0x22,0x8b,0x43,0x4c,0xaa,0xa9,0x76,0xe5,0xa1,0xd5,0x4b,0xb6,0x8d,0x11,
"ion\"><label class=\"label-inline\" for=\"station\">{{ $t('connection.stationmode') }}</label><span " 0xa9,0xab,0xfb,0x79,0xbb,0x8c,0xcb,0xed,0x46,0xab,0xb9,0xda,0x4c,0xd4,0x5d,0xf7,0x49,0x15,0x1e,0xe4,
"class=\"hint\">{{ $t('connection.stationmodeHint') }}</span><label for=\"ssid\">{{ $t('connection.ss" 0xd2,0xd8,0xc0,0x23,0xb4,0xde,0xb4,0xfa,0x72,0x7a,0x39,0xdd,0xe6,0x0e,0xc3,0x5c,0xdf,0x7c,0x16,0x1b,
"id') }}</label><input type=\"text\" id=\"ssid\" v-model=\"connection.ssid\" :disabled=\"!connection." 0x26,0x02,0xd3,0x19,0xa8,0x8a,0xcb,0xea,0x47,0xda,0x6c,0xae,0x8d,0x52,0x7b,0x7e,0x20,0x06,0x49,0x4b,
"station\"><label for=\"password\">{{ $t('connection.password') }}</label><input type=\"password\" id" 0xd9,0xd9,0x27,0x28,0x76,0xaa,0xb2,0xb8,0xcd,0x88,0x52,0x97,0x54,0x3f,0x2a,0x6b,0xbb,0x24,0x6f,0xe7,
"=\"password\" v-model=\"connection.password\" :disabled=\"!connection.station\"> <input type=\"check" 0xa3,0x71,0x2b,0x5b,0xbb,0x4b,0xee,0x9e,0x9b,0xf3,0xb9,0xd5,0xac,0xef,0xb4,0xf9,0xfd,0x97,0x1d,0x90,
"box\" id=\"dhcp\" v-model=\"connection.dhcp\" :disabled=\"!connection.station\"><label class=\"label" 0x3a,0x15,0x15,0xf6,0xfa,0xb9,0x74,0x7f,0xdd,0x19,0xb6,0xe5,0x74,0x76,0xd6,0xad,0x94,0xf5,0x85,0x52,
"-inline\" for=\"dhcp\">{{ $t('connection.dhcp') }}</label><span class=\"hint\">{{ $t('connection.dhc" 0xde,0xcf,0xd6,0xcd,0xfb,0xde,0x04,0xa6,0xb5,0xb1,0x31,0xa8,0x64,0x73,0xfb,0xec,0xd8,0x62,0xc5,0x91,
"pHint') }}</span><div class=\"suboptions\"><label for=\"ip\">{{ $t('connection.ipaddress') }}</label" 0x7b,0x1e,0xe8,0x59,0x68,0x6c,0xcb,0x5d,0xb7,0x7a,0xaa,0xb8,0x36,0xd9,0x8c,0xed,0xa1,0x56,0x2e,0xb3,
"><input type=\"text\" id=\"ip\" v-model=\"connection.ip\" :disabled=\"!connection.station || connect" 0x4a,0x54,0xd3,0xc5,0xaf,0x5f,0xb9,0x3f,0xe9,0x4d,0xcc,0x6d,0xd1,0xd8,0x2d,0xf7,0xfd,0x3b,0x2b,0xf7,
"ion.dhcp\"><label for=\"subnetmask\">{{ $t('connection.subnetmask') }}</label><input type=\"text\" i" 0x34,0xe3,0x64,0x1c,0xce,0x16,0x5a,0x04,0x19,0x7a,0x82,0x1c,0x08,0x85,0x5a,0xb3,0xc2,0xbd,0x2b,0x14,
"d=\"subnetmask\" v-model=\"connection.subnetmask\" :disabled=\"!connection.station || connection.dhc" 0x38,0xdd,0xc6,0x98,0xfb,0xc7,0xd5,0x3a,0xd2,0x99,0xe2,0x1d,0x17,0x7b,0xe4,0x62,0xec,0xf1,0x42,0x87,
"p\"><label for=\"gateway\">{{ $t('connection.gateway') }}</label><input type=\"text\" id=\"gateway\"" 0x91,0x63,0x9e,0xdd,0xcc,0x49,0x3f,0xec,0xd0,0x0a,0x11,0x0a,0xa8,0x4d,0x4e,0xfb,0x84,0xb5,0x8f,0x0e,
" v-model=\"connection.gateway\" :disabled=\"!connection.station || connection.dhcp\"></div><label fo" 0x25,0xca,0x6c,0x9c,0xd2,0x91,0x2e,0x23,0x09,0x50,0x67,0xc7,0x78,0x74,0x3a,0x27,0xee,0x29,0x7b,0x86,
"r=\"hostname\">{{ $t('connection.hostname') }}</label><input type=\"text\" :placeholder=\"$t('connec" 0xc6,0xee,0xef,0x04,0x30,0x13,0x50,0x07,0x22,0x86,0x32,0x43,0x18,0xf3,0x2d,0x41,0x39,0xe6,0x80,0x90,
"tion.hostnamePlaceholder')\" id=\"hostname\" v-model=\"connection.hostname\" :disabled=\"!connection" 0x11,0x09,0x09,0x4e,0x7f,0x33,0xdb,0xc7,0xf0,0xa3,0x26,0x24,0x09,0x12,0x62,0x1a,0x48,0xa7,0x89,0x30,
".station\"><div class=\"buttons\"><input class=\"button-primary\" type=\"submit\" :disabled=\"saving" 0x2b,0x1c,0x13,0xbc,0xe6,0xe7,0x94,0x8e,0x4c,0xe6,0xec,0x15,0x9b,0x0c,0x86,0xab,0xe8,0x27,0xdb,0x01,
"\" :value=\"saving ? $t('applyButtonSaving') : $t('applyButton')\"></div></fieldset></form></div></d" 0xf1,0x4b,0xd1,0x2b,0x90,0x3e,0xa1,0x9a,0xeb,0x89,0x29,0x79,0x0e,0x6f,0x6e,0xaf,0xc7,0x47,0x3c,0x41,
"iv><div class=\"clearfix\"></div></div><div class=\"version\">{{ $t('copyright') }}<br>{{ version.ve" 0xcd,0x90,0xe1,0x59,0x7c,0x97,0x2c,0x4d,0xe0,0x9e,0xde,0x44,0x90,0x46,0xbf,0xbd,0xcd,0x0f,0xb1,0xfd,
"rsion !== null ? $t('firmwareVersion') + version.version : '' }}</div></div></div><script language=" 0x94,0xed,0x7f,0x32,0xd2,0x15,0xfe,0x08,0xf6,0xb8,0x3e,0xba,0xf7,0xd7,0x81,0x27,0x7f,0xdd,0x3c,0xc6,
"\"javascript\">console.log(\"Initializing...\"),startApp()</script></body></html>"; 0x74,0x9a,0x09,0xcf,0xe6,0xbb,0xc0,0x48,0x34,0x0d,0x14,0x88,0x4e,0xb9,0x88,0x36,0xa5,0x86,0x7e,0x24,
0x7a,0x2b,0x96,0x18,0x7f,0xfd,0x95,0x8b,0x79,0xa4,0xb8,0x61,0x53,0x76,0x0e,0x40,0x56,0x9a,0x80,0xe5,
0x74,0x0b,0x27,0x40,0x64,0x35,0xcc,0xc5,0xbc,0xe4,0xb1,0xb2,0xe4,0xb9,0xcf,0x12,0x46,0xd2,0x86,0x6d,
0xe8,0x81,0x40,0xc8,0x0f,0x02,0xf0,0xd6,0x09,0xe6,0x7d,0x12,0x69,0x14,0xcf,0x49,0x91,0xfb,0x65,0x38,
0xd4,0x42,0x8a,0xc2,0xfa,0xe6,0x3a,0xa0,0x40,0x22,0x80,0x74,0xa4,0xfc,0x36,0x50,0x61,0x25,0x5e,0x87,
0x15,0x91,0x09,0x80,0x85,0xb4,0xdf,0x06,0x6d,0x85,0x2c,0x6d,0x07,0x2c,0x78,0x1d,0x58,0x20,0x11,0xc0,
0x3a,0x52,0xae,0x80,0x7a,0x51,0x7f,0x11,0x73,0xd1,0x82,0xc8,0xab,0xf7,0xe7,0x45,0x11,0xdd,0x3a,0xef,
0x4f,0xaa,0x95,0x60,0x24,0xc3,0x70,0x1c,0x60,0x96,0x57,0x86,0x55,0xe0,0x6f,0xd8,0xce,0x68,0xbe,0xe7,
0x58,0x4b,0xc3,0xfd,0x2d,0x7b,0x70,0xce,0x9a,0xb8,0x48,0x5d,0x1a,0xdb,0x45,0xd3,0x4e,0xa7,0xe4,0x91,
0x6e,0xda,0x94,0xa3,0x07,0x93,0xcd,0x41,0x16,0xd0,0x15,0xc8,0x73,0x1a,0xd2,0x0b,0x7c,0x8a,0x3d,0xc1,
0xbe,0xc0,0xa7,0xd9,0xb0,0x74,0xe2,0xcb,0xf5,0xe1,0xb4,0xb6,0x3b,0xf6,0x40,0x33,0xb1,0x05,0xd8,0x86,
0x7c,0xd1,0x69,0xba,0x70,0x7d,0xde,0xce,0xd7,0x82,0x8e,0x14,0x5d,0x9e,0x01,0xd7,0xb8,0xcf,0xc4,0x16,
0x35,0x44,0x13,0xa6,0x05,0xb7,0xee,0x24,0xc6,0xa6,0x20,0x7c,0x98,0xf8,0x62,0x8e,0x14,0x82,0x58,0x66,
0x33,0x60,0x34,0x4d,0x61,0xa1,0x22,0x0d,0x4e,0xce,0x92,0x95,0x0c,0x35,0x5e,0xd5,0xd5,0x0c,0xa7,0xa0,
0x5e,0xd1,0x4e,0x3a,0x00,0xdf,0x0a,0xe8,0xa4,0x5c,0x5f,0x0b,0xa9,0x1c,0xdd,0x85,0x2f,0x01,0x8b,0x16,
0xf9,0x19,0xa8,0xe8,0x9f,0x26,0xa9,0x50,0xda,0x88,0xc6,0x9e,0xf7,0x66,0xc6,0xf0,0x18,0x88,0xfc,0x4f,
0x11,0x53,0x51,0x01,0x36,0xc1,0x02,0x11,0xe2,0x60,0x4b,0x75,0x16,0x71,0xa4,0x3b,0xfd,0xc0,0x73,0x6e,
0x19,0x9d,0x48,0xbf,0xc4,0x15,0x61,0xfb,0xe8,0x5c,0x1b,0x6c,0xe0,0x35,0x41,0xd0,0x7b,0xea,0xdb,0xca,
0x8d,0xd0,0x80,0xa3,0x59,0xe4,0x5e,0x89,0xd0,0x3f,0x5c,0x2e,0x47,0x77,0x64,0xbe,0x1d,0x59,0x20,0xf9,
0x12,0x58,0xe4,0xf8,0xfa,0xf9,0xa8,0x22,0xca,0xe7,0x51,0xf9,0x98,0x3c,0xf7,0x04,0xc9,0x17,0xd5,0x19,
0xfd,0xd4,0x69,0x34,0x13,0x94,0x1d,0x95,0x7e,0x16,0x1c,0xfd,0xcb,0x29,0x70,0x39,0x8f,0xc7,0x19,0x80,
0x9d,0x72,0xaf,0xe4,0xc7,0xc5,0x62,0xb2,0x80,0x76,0x86,0x75,0x11,0xcf,0x91,0x77,0x1d,0x53,0xa0,0xed,
0xe2,0x0a,0x57,0x97,0xb0,0x85,0xdc,0xb7,0xf0,0xbd,0x56,0x01,0xb2,0x2a,0x99,0x97,0xed,0x7b,0x9c,0x1f,
0x8c,0xfd,0x7a,0x6d,0xb8,0x66,0x2e,0x24,0xc3,0xa1,0xff,0x7c,0x45,0x38,0x5a,0x2f,0x4a,0x21,0xba,0x83,
0xdb,0xa2,0x61,0x3a,0x92,0xe4,0xf4,0x6f,0x41,0x17,0x31,0x20,0x13,0xc8,0xb2,0xc5,0x1a,0xe7,0x47,0xaa,
0x04,0x5d,0xc9,0x13,0x7a,0x33,0x4b,0xdc,0xb7,0x6f,0xdc,0x79,0x62,0x4f,0x0b,0xd8,0x16,0x75,0x48,0x35,
0x40,0x36,0x17,0xcb,0x38,0xe0,0xfe,0x50,0x31,0x87,0xb6,0x2e,0x97,0x74,0x84,0xff,0x8b,0xb0,0x15,0x40,
0xe1,0x0e,0x1c,0x2e,0x61,0xf6,0x59,0x3f,0x02,0xf8,0x68,0xe5,0x22,0xda,0x80,0xf9,0x5f,0xa0,0x7a,0x87,
0x4b,0x04,0xb0,0x6a,0x10,0xea,0xdc,0x52,0x5c,0x42,0x7c,0xe4,0xbd,0x05,0xf9,0xd1,0xc4,0x40,0x82,0xaa,
0x81,0xd9,0xe9,0x5d,0xe0,0xaf,0x18,0x19,0x84,0x32,0xb1,0x5b,0x2f,0xcc,0xc0,0xf7,0xc5,0x38,0x43,0xee,
0x9b,0x0d,0x17,0xa9,0x76,0x6f,0x16,0x72,0x4a,0xdd,0xc3,0x79,0x42,0x8e,0x9b,0x16,0xd2,0x80,0xc5,0x72,
0xe7,0xc1,0xf7,0x0e,0xce,0x13,0x07,0x04,0x6c,0xdd,0xd7,0x80,0x47,0x77,0xcc,0x38,0xae,0xfd,0x97,0x45,
0xf7,0x60,0x2d,0xb9,0xa6,0xc6,0x2e,0x9d,0x65,0xe6,0xf1,0x9c,0x13,0x0b,0xde,0x5c,0x7e,0xfa,0x70,0x8f,
0x8c,0x7c,0x57,0x8e,0x76,0xdb,0x74,0xde,0x29,0x6a,0xbe,0x9c,0x97,0xc6,0xa3,0xd6,0x95,0x73,0x3e,0x9c,
0x1a,0x5f,0x39,0xe5,0x57,0x08,0x9f,0x59,0xab,0x39,0x94,0xff,0x6f,0x6a,0xc3,0x14,0x7a,0x29,0x19,0x58,
0x86,0xe2,0x6c,0x5b,0xee,0xfb,0xfd,0x0a,0x60,0xe2,0x55,0xf4,0x19,0xf3,0xfb,0xf7,0xbf,0xde,0xf8,0x6b,
0x5e,0xbe,0xcd,0x62,0x08,0xac,0x15,0xda,0xf3,0x57,0x25,0xfc,0xeb,0x82,0x48,0x07,0x99,0x07,0x36,0xf4,
0xa9,0xfe,0x8e,0x2c,0x5a,0xd1,0x7b,0x08,0xff,0x79,0x7e,0x0d,0x71,0xcc,0xfa,0xcc,0x63,0xbb,0xb7,0x11,
0xe7,0x2a,0xc1,0x2d,0xc4,0x8b,0xd7,0x58,0xff,0xfe,0x0f,0xb3,0xf9,0xda,0x06,0x0a,0x4b,0xed,0x1a,0x6c,
0x81,0x47,0xe4,0x8b,0xac,0x63,0x88,0x81,0x61,0x02,0x1b,0xca,0x0d,0xdf,0xf4,0x2e,0x19,0xd1,0x17,0x96,
0xe1,0x44,0x22,0xc1,0xdf,0xbe,0x67,0x5d,0x64,0x51,0xc1,0x34,0x6f,0x6e,0x23,0xd7,0x85,0xde,0x45,0x61,
0xd2,0xbd,0x1f,0xfd,0x17,0x25,0x0b,0x23,0x59,0x35,0x15,0x00,0x00};
#endif #endif

View File

@ -1,32 +0,0 @@
#ifndef __assets_images
#define __assets_images
#include <pgmspace.h>
const uint8_t EmbeddedLogo[] PROGMEM = {
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x30,
0x00,0x00,0x00,0x30,0x08,0x06,0x00,0x00,0x00,0x57,0x02,0xf9,0x87,0x00,0x00,0x00,0x19,0x74,0x45,0x58,
0x74,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x00,0x41,0x64,0x6f,0x62,0x65,0x20,0x49,0x6d,0x61,0x67,
0x65,0x52,0x65,0x61,0x64,0x79,0x71,0xc9,0x65,0x3c,0x00,0x00,0x01,0x70,0x49,0x44,0x41,0x54,0x78,0xda,
0xec,0x59,0xd1,0x0d,0x82,0x30,0x10,0x2d,0xc6,0x01,0x70,0x03,0xdc,0x00,0x27,0x50,0x37,0x80,0x0d,0xd8,
0xc0,0xb8,0x81,0x1b,0x18,0x27,0xd1,0x0d,0x74,0x03,0xd8,0x00,0x36,0x80,0x0d,0xea,0x5d,0x52,0x13,0x35,
0xa8,0x58,0xee,0xae,0x0a,0x7d,0x49,0xc3,0x07,0x81,0xde,0xf5,0xdd,0x5d,0xdf,0xb5,0x4a,0x79,0x78,0x78,
0x0c,0x17,0x5a,0xeb,0x18,0x46,0xae,0xe9,0x51,0xc3,0xd8,0x73,0x1b,0x1f,0x9a,0x89,0x38,0xb1,0xeb,0x6b,
0xe7,0xe4,0xcd,0xbb,0x18,0x46,0xc8,0x4c,0xf2,0x92,0xd3,0x81,0x42,0x20,0x4a,0x0b,0xee,0x30,0xca,0x18,
0xc3,0xe8,0x8c,0x61,0x3a,0xfa,0x42,0x13,0x58,0x32,0xb3,0x62,0x37,0x2c,0x08,0x2e,0x5c,0x95,0x29,0xd7,
0x32,0xc8,0xfb,0x26,0x71,0x1b,0x32,0x53,0x9d,0x24,0x80,0x7b,0x50,0x42,0xed,0x80,0x74,0xd2,0x45,0xa4,
0x39,0x00,0x2b,0x82,0x3f,0x2c,0x85,0x8c,0x6f,0x60,0x2c,0x20,0x17,0x2a,0xd2,0x24,0x46,0x79,0x01,0x8f,
0x4d,0x97,0xd5,0xe9,0x01,0x34,0xfa,0x00,0xc6,0x17,0x6a,0xe8,0xb0,0x61,0x20,0x31,0x0c,0x48,0x02,0x19,
0xd9,0x02,0x23,0xcd,0xf3,0x8b,0xa9,0x45,0xfd,0x3f,0x3a,0x5a,0x6c,0x2c,0x20,0x69,0xdf,0x2a,0xb4,0x72,
0x18,0x2d,0x09,0x45,0x19,0xad,0x1c,0x3a,0x40,0x33,0xb7,0x11,0x61,0xd2,0xa8,0x5f,0x6d,0x6a,0xb6,0x5a,
0x48,0xa2,0x57,0x78,0x90,0xdd,0x6d,0x09,0x6c,0x13,0x42,0x83,0xe8,0x93,0x7f,0x2a,0x84,0x6c,0x1a,0x1c,
0x57,0x28,0x29,0x42,0x28,0x72,0x48,0x7e,0x44,0xe1,0xc0,0xc5,0xa1,0x03,0xa7,0x41,0x4a,0x89,0x51,0x8a,
0x39,0x09,0x39,0xdd,0x59,0x52,0xff,0x72,0x43,0xd3,0xa9,0xa9,0xb1,0xe9,0x89,0xa5,0x15,0x68,0x46,0xd9,
0x13,0xbb,0x48,0x22,0x3a,0x01,0x29,0x7c,0xac,0xa2,0xcd,0x5c,0xe1,0x5f,0x1e,0x6c,0xb1,0x1d,0x6e,0xfd,
0x9b,0x70,0xcb,0x04,0xee,0x08,0xee,0x05,0xdb,0xd7,0x45,0x22,0x78,0x17,0xef,0xf0,0xa8,0x85,0xd7,0xac,
0x81,0xb0,0x99,0x7d,0xf3,0xc1,0xa7,0x0b,0x0e,0x17,0x8d,0x3b,0xdd,0x4e,0x8c,0xb4,0x0a,0x77,0x5e,0x15,
0x30,0x30,0xa7,0x62,0x00,0xb1,0x56,0x32,0x37,0x35,0x37,0xb5,0x99,0x2a,0x0f,0x0f,0x8f,0x71,0xe1,0x2a,
0xc0,0x00,0x6f,0x6a,0x3e,0x7e,0x1e,0xa2,0xf0,0x8c,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,
0x60,0x82};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,11 @@
const uint8_t VersionMajor = 2; const uint8_t VersionMajor = 2;
const uint8_t VersionMinor = 0; const uint8_t VersionMinor = 0;
const uint8_t VersionPatch = 0; const uint8_t VersionPatch = 0;
const uint8_t VersionMetadata = 0; const uint8_t VersionMetadata = 3;
const char VersionBranch[] = "release/2.0"; const char VersionBranch[] = "release/2.0";
const char VersionSha[] = "3099dd8a0e2e5fa771e6a864a1daa83de5998df0"; const char VersionSha[] = "61d544f6f347c875e64b1e79985eeabd52ee1c9f";
const char VersionSemVer[] = "2.0.0-beta.1"; const char VersionSemVer[] = "2.0.0-beta.1";
const char VersionFullSemVer[] = "2.0.0-beta.1+0"; const char VersionFullSemVer[] = "2.0.0-beta.1+3";
const char VersionCommitDate[] = "2017-10-05"; const char VersionCommitDate[] = "2018-01-03";
#endif #endif

View File

@ -11,7 +11,8 @@ void _dinit()
{ {
#ifdef SerialDebug #ifdef SerialDebug
Serial.begin(SerialDebugBaudrate); Serial.begin(SerialDebugBaudrate);
Serial.setDebugOutput(true); // Enable if you want detailed WiFi state logging
//Serial.setDebugOutput(true);
delay(SerialDebugStartupDelay); delay(SerialDebugStartupDelay);
#endif #endif
} }

View File

@ -9,6 +9,8 @@
ConnectionSettings* connectionSettings = new ConnectionSettings(); ConnectionSettings* connectionSettings = new ConnectionSettings();
bool connectionSettingsChanged = false; bool connectionSettingsChanged = false;
bool shouldReboot = false;
uint32_t currentTime; uint32_t currentTime;

View File

@ -14,6 +14,9 @@
extern ConnectionSettings* connectionSettings; extern ConnectionSettings* connectionSettings;
extern bool connectionSettingsChanged; extern bool connectionSettingsChanged;
extern bool shouldReboot;
extern uint32_t currentTime; extern uint32_t currentTime;
extern IPAddress emptyIP; extern IPAddress emptyIP;

View File

@ -19,6 +19,7 @@ extern "C" {
#include "global.h" #include "global.h"
#include "server/static.h" #include "server/static.h"
#include "server/api.h" #include "server/api.h"
#include "server/firmware.h"
ADC_MODE(ADC_VCC); ADC_MODE(ADC_VCC);
@ -42,10 +43,15 @@ bool forceAccessPoint = false;
uint32_t stationModeStart = 0; uint32_t stationModeStart = 0;
#ifdef SerialDebug
uint32_t memoryStatusTime = 0;
#endif
void setup() void setup()
{ {
_dinit(); _dinit();
currentTime = millis(); currentTime = millis();
if (!SPIFFS.begin()) if (!SPIFFS.begin())
@ -70,6 +76,7 @@ void setup()
_dln("Setup :: registering routes"); _dln("Setup :: registering routes");
registerStaticRoutes(&server); registerStaticRoutes(&server);
registerAPIRoutes(&server); registerAPIRoutes(&server);
registerFirmwareRoutes(&server);
_dln("Setup :: starting HTTP server"); _dln("Setup :: starting HTTP server");
server.onNotFound(handleNotFound); server.onNotFound(handleNotFound);
@ -79,8 +86,26 @@ void setup()
void loop() void loop()
{ {
if (shouldReboot)
{
_dln("Reboot requested, bye bye!");
delay(100);
ESP.restart();
}
currentTime = millis(); currentTime = millis();
#ifdef SerialDebug
if (currentTime - memoryStatusTime >= 5000)
{
_d("Memory :: available: ");
_dln(ESP.getFreeHeap());
memoryStatusTime = currentTime;
}
#endif
if (connectionSettingsChanged) if (connectionSettingsChanged)
{ {
_dln("Loop :: connection settings changed"); _dln("Loop :: connection settings changed");

View File

@ -5,51 +5,70 @@
* https://git.x2software.net/pub/Stairs * https://git.x2software.net/pub/Stairs
*/ */
#include "firmware.h" #include "firmware.h"
#include "../config.h"
#include "../debug.h" #include "../debug.h"
#include "../global.h" #include "../global.h"
void handleFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final)
void handleFirmware(AsyncWebServerRequest *request)
{ {
_d("Firmware :: handleFileUpload: index = "); _d(index); shouldReboot = !Update.hasError();
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot ? "OK" : "FAIL");
response->addHeader("Connection", "close");
request->send(response);
}
void handleFirmwareFile(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final)
{
_d("Firmware :: file upload: index = "); _d(index);
_d(", len = "); _d(len); _d(", len = "); _d(len);
_d(", final = "); _dln(final); _d(", final = "); _dln(final);
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; if (!index)
if (index == 0)
{ {
if (Update.begin(maxSketchSpace)) uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
Update.runAsync(true); _d("Firmware :: update start, max sketch space: ");
else _dln(maxSketchSpace);
_dln("Firmware :: failed to start");
}
if (Update.write(data, len) == len) Update.runAsync(true);
{ if (!Update.begin(maxSketchSpace))
if(final)
{ {
#ifdef SerialDebug #ifdef SerialDebug
Update.printError(Serial);
if (Update.end(true)) #endif
Serial.println("Update succesful!"); }
else }
Update.printError(Serial);
if (!Update.hasError())
#else {
if (Update.write(data, len) != len)
Update.end(true); {
#ifdef SerialDebug
Update.printError(Serial);
#endif
}
}
if (final)
{
if (Update.end(true))
{
_dln("Firmware :: success");
}
else
{
_dln("Firmware :: failed");
#ifdef SerialDebug
Update.printError(Serial);
#endif #endif
} }
} }
#ifdef SerialDebug
else
Update.printError(Serial);
#endif
} }
void registerFirmwareRoutes(AsyncWebServer* server) void registerFirmwareRoutes(AsyncWebServer* server)
{ {
server.onFileUpload(handleFileUpload); server->on("/firmware", HTTP_POST, handleFirmware, handleFirmwareFile);
} }

View File

@ -9,27 +9,21 @@
#include "../assets/html.h" #include "../assets/html.h"
#include "../assets/js.h" #include "../assets/js.h"
#include "../assets/css.h" #include "../assets/css.h"
#include "../assets/images.h"
void handleStatic(AsyncWebServerRequest *request, const String& contentType, PGM_P content) void handleGzipped(AsyncWebServerRequest *request, const String& contentType, const uint8_t * content, size_t len)
{ {
_d("HTTP :: static: "); _dln(request->url()); _d("HTTP :: static: "); _dln(request->url());
request->send_P(200, contentType, content); AsyncWebServerResponse *response = request->beginResponse_P(200, contentType, content, len);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
} }
void registerStaticRoutes(AsyncWebServer* server) void registerStaticRoutes(AsyncWebServer* server)
{ {
server->on("/", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/html", EmbeddedIndex); }); server->on("/", HTTP_GET, [](AsyncWebServerRequest *request) { handleGzipped(request, "text/html", EmbeddedIndex, sizeof(EmbeddedIndex)); });
server->on("/bundle.js", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/javascript", EmbeddedBundleJS); }); server->on("/bundle.js", HTTP_GET, [](AsyncWebServerRequest *request) { handleGzipped(request, "text/javascript", EmbeddedBundleJS, sizeof(EmbeddedBundleJS)); });
server->on("/bundle.css", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/css", EmbeddedBundleCSS); }); server->on("/bundle.css", HTTP_GET, [](AsyncWebServerRequest *request) { handleGzipped(request, "text/css", EmbeddedBundleCSS, sizeof(EmbeddedBundleCSS)); });
server->on("/logo.png", HTTP_GET, [](AsyncWebServerRequest *request)
{
_d("HTTP :: static: "); _dln(request->url());
AsyncWebServerResponse *response = request->beginResponse_P(200, "image/png", EmbeddedLogo, sizeof(EmbeddedLogo));
request->send(response);
});
} }

View File

@ -15,6 +15,7 @@ function startApp()
loading: true, loading: true,
saving: false, saving: false,
loadingIndicator: '|', loadingIndicator: '|',
uploadProgress: false,
activeTab: 'status', activeTab: 'status',
@ -73,7 +74,6 @@ function startApp()
self.startLoadingIndicator(); self.startLoadingIndicator();
self.updateWiFiStatus(); self.updateWiFiStatus();
setInterval(self.updateWiFiStatus, 5000);
axios.get('/api/version') axios.get('/api/version')
.then(function(response) .then(function(response)
@ -155,7 +155,6 @@ function startApp()
self.loadingTimer = setInterval(function() self.loadingTimer = setInterval(function()
{ {
self.loadingStage++; self.loadingStage++;
console.log(self.loadingStage);
switch (self.loadingStage) switch (self.loadingStage)
{ {
case 1: self.loadingIndicator = '/'; break; case 1: self.loadingIndicator = '/'; break;
@ -230,23 +229,68 @@ function startApp()
updateWiFiStatus: function() updateWiFiStatus: function()
{ {
var self = this; var self = this;
if (self.saving) return; if (!self.saving)
{
axios.get('/api/connection/status') axios.get('/api/connection/status')
.then(function(response) .then(function(response)
{ {
if (typeof response.data == 'object') if (typeof response.data == 'object')
self.wifiStatus = response.data; self.wifiStatus = response.data;
}) })
.catch(function(error) .catch(function(error)
{ {
console.log(error); console.log(error);
}); })
.then(function()
{
setTimeout(self.updateWiFiStatus, 5000);
});
}
else
setTimeout(self.updateWiFiStatus, 5000);
}, },
uploadFirmware: function() uploadFirmware: function()
{ {
// var self = this;
if (self.saving) return;
self.saving = true;
self.uploadProgress = 0;
var data = new FormData();
data.append('file', document.getElementById('firmwareFile').files[0]);
var config = {
timeout: 360000,
onUploadProgress: function(progressEvent)
{
self.uploadProgress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
}
};
axios.post('/firmware', data, config)
.then(function(response)
{
// TODO show "now updating, please wait"
console.log("Update sent");
})
.catch(function(error)
{
console.log(error);
//output.innerHTML = err.message;
// TODO show error
})
.then(function()
{
self.uploadProgress = false;
self.saving = false;
document.getElementById('firmware').reset();
});
} }
} }
}); });

2
web/dist/bundle.js vendored

File diff suppressed because one or more lines are too long

View File

@ -108,15 +108,19 @@
</div> </div>
<div v-if="activeTab == 'firmware'"> <div v-if="activeTab == 'firmware'">
<form @submit.prevent="uploadFirmware"> <form @submit.prevent="uploadFirmware" id="firmware">
<fieldset> <fieldset>
<h3>{{ $t('firmware.title') }}</h3> <h3>{{ $t('firmware.title') }}</h3>
<input type="file"> <input type="file" id="firmwareFile">
<div class="buttons"> <div class="buttons">
<input class="button-primary" type="submit" :disabled="saving" :value="saving ? $t('applyButtonSaving') : $t('applyButton')"> <input class="button-primary" type="submit" :disabled="saving" :value="saving ? $t('applyButtonSaving') : $t('applyButton')">
</div> </div>
<div v-if="uploadProgress !== false">
{{ uploadProgress }}%
</div>
</fieldset> </fieldset>
</form> </form>
</div> </div>