diff options
author | Evgeny Zinoviev <me@ch1p.io> | 2023-05-11 04:18:08 +0300 |
---|---|---|
committer | Evgeny Zinoviev <me@ch1p.io> | 2023-05-11 04:18:12 +0300 |
commit | 0aba139aeff8ff80757c5d36502413299a0b449e (patch) | |
tree | 2b8e760ff14d4691783eb7c7d341f093199aab82 /platformio/common | |
parent | 586d84b0c0a8b4dc1b5057733892b754397234ec (diff) |
mqtt, esp: add new esp8266-based device
Diffstat (limited to 'platformio/common')
-rwxr-xr-x | platformio/common/make_static.sh | 89 | ||||
-rw-r--r-- | platformio/common/static/app.js | 246 | ||||
-rw-r--r-- | platformio/common/static/favicon.ico | bin | 0 -> 7886 bytes | |||
-rw-r--r-- | platformio/common/static/index.html | 63 | ||||
-rw-r--r-- | platformio/common/static/md5.js | 615 | ||||
-rw-r--r-- | platformio/common/static/style.css | 85 |
6 files changed, 1098 insertions, 0 deletions
diff --git a/platformio/common/make_static.sh b/platformio/common/make_static.sh new file mode 100755 index 0000000..d207e57 --- /dev/null +++ b/platformio/common/make_static.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +#set -x +#set -e + +COMMON_DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" +PROJECT_DIR="$(pwd)" + +fw_version="$(cat "$PROJECT_DIR/src/config.def.h" | grep "^#define FW_VERSION" | awk '{print $3}')" +header="$PROJECT_DIR/src/static.h" +source="$PROJECT_DIR/src/static.cpp" + +[ -f "$header" ] && rm "$header" +[ -f "$source" ] && rm "$source" + +is_minifyable() { + local ext="$1" + [ "$ext" = "html" ] || [ "$ext" = "css" ] || [ "$ext" = "js" ] +} + +minify() { + local ext="$1" + local bin="$(realpath "$COMMON_DIR"/../../tools/minify.js)" + "$bin" --type "$ext" +} + +# .h header +cat <<EOF >> "$header" +/** + * This file is autogenerated with make_static.sh script + */ + +#pragma once + +#include <stdlib.h> + +namespace homekit::files { + +typedef struct { + size_t size; + const uint8_t* content; +} StaticFile; + +EOF + +cat <<EOF >> "$source" +/** + * This file is autogenerated with make_static.sh script + */ + +#include "static.h" + +namespace homekit::files { + +EOF + +# loop over files +for ext in html js css ico; do + for f in "$COMMON_DIR"/static/*.$ext; do + filename="$(basename "$f")" + echo "processing ${filename}..." + filename="${filename/./_}" + + # write .h + echo "extern const StaticFile $filename;" >> "$header" + + # write .c + { + echo "static const uint8_t ${filename}_content[] PROGMEM = {" + + cat "$f" | + ( [ "$ext" = "html" ] && sed "s/{version}/$fw_version/" || cat ) | + ( is_minifyable "$ext" && minify "$ext" || cat ) | + gzip | + xxd -ps -c 16 | + sed 's/.\{2\}/0x&, /g' | + sed 's/^/ /' | + sed 's/[ \t]*$//' + + echo "};" + echo "const StaticFile $filename PROGMEM = {(sizeof(${filename}_content)/sizeof(${filename}_content[0])), ${filename}_content};" + echo "" + } >> "$source" + done +done + +# end of homekit::files +( echo ""; echo "}" ) >> "$header" +echo "}" >> "$source" diff --git a/platformio/common/static/app.js b/platformio/common/static/app.js new file mode 100644 index 0000000..299230c --- /dev/null +++ b/platformio/common/static/app.js @@ -0,0 +1,246 @@ +function isObject(o) { + return Object.prototype.toString.call(o) === '[object Object]'; +} + +function ge(id) { + return document.getElementById(id) +} + +function hide(el) { + el.style.display = 'none' +} + +function cancelEvent(evt) { + if (evt.preventDefault) evt.preventDefault(); + if (evt.stopPropagation) evt.stopPropagation(); + + evt.cancelBubble = true; + evt.returnValue = false; + + return false; +} + +function errorText(e) { + return e instanceof Error ? e.message : e+'' +} + +(function() { + function request(method, url, data, callback) { + data = data || null; + + if (typeof callback != 'function') { + throw new Error('callback must be a function'); + } + + if (!url) + throw new Error('no url specified'); + + switch (method) { + case 'GET': + if (isObject(data)) { + for (var k in data) { + if (data.hasOwnProperty(k)) + url += (url.indexOf('?') === -1 ? '?' : '&')+encodeURIComponent(k)+'='+encodeURIComponent(data[k]) + } + } + break; + + case 'POST': + if (isObject(data)) { + var sdata = []; + for (var k in data) { + if (data.hasOwnProperty(k)) + sdata.push(encodeURIComponent(k)+'='+encodeURIComponent(data[k])); + } + data = sdata.join('&'); + } + break; + } + + var xhr = new XMLHttpRequest(); + xhr.open(method, url); + + if (method === 'POST') + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + if ('status' in xhr && !/^2|1223/.test(xhr.status)) + throw new Error('http code '+xhr.status) + callback(null, JSON.parse(xhr.responseText)); + } + }; + xhr.onerror = function(e) { + callback(e, null); + }; + + xhr.send(method === 'GET' ? null : data); + return xhr; + } + + window.ajax = { + get: request.bind(request, 'GET'), + post: request.bind(request, 'POST') + } +})(); + + +function lock(el) { + el.setAttribute('disabled', 'disabled'); +} + +function unlock(el) { + el.removeAttribute('disabled'); +} + +function initNetworkSettings() { + function setupField(el, value) { + if (value !== null) + el.value = value; + unlock(el); + } + + var doneRequestsCount = 0; + function onRequestDone() { + doneRequestsCount++; + if (doneRequestsCount === 2) { + hide(ge('loading_label')) + } + } + + var form = document.forms.network_settings; + form.addEventListener('submit', function(e) { + if (!form.hid.value.trim()) { + alert('Введите home id'); + return cancelEvent(e); + } + + if (form.psk.value.length < 8) { + alert('Неверный пароль (минимальная длина - 8 символов)'); + return cancelEvent(e); + } + + if (form.ssid.selectedIndex === -1) { + alert('Не выбрана точка доступа'); + return cancelEvent(e); + } + + lock(form.submit) + }) + form.show_psk.addEventListener('change', function(e) { + form.psk.setAttribute('type', e.target.checked ? 'text' : 'password'); + }); + form.ssid.addEventListener('change', function(e) { + var i = e.target.selectedIndex; + if (i !== -1) { + var opt = e.target.options[i]; + if (opt) + form.psk.value = ''; + } + }); + + ajax.get('/status', {}, function(error, response) { + try { + if (error) + throw error; + + setupField(form.hid, response.node_id || null); + setupField(form.psk, null); + setupField(form.submit, null); + + onRequestDone(); + } catch (error) { + alert(errorText(error)); + } + }); + + ajax.get('/scan', {}, function(error, response) { + try { + if (error) + throw error; + + form.ssid.innerHTML = ''; + for (var i = 0; i < response.list.length; i++) { + var ssid = response.list[i][0]; + var rssi = response.list[i][1]; + form.ssid.append(new Option(ssid + ' (' + rssi + ' dBm)', ssid)); + } + unlock(form.ssid); + + onRequestDone(); + } catch (error) { + alert(errorText(error)); + } + }); +} + +function initUpdateForm() { + var form = document.forms.update_settings; + form.addEventListener('submit', function(e) { + cancelEvent(e); + if (!form.file.files.length) { + alert('Файл обновления не выбран'); + return false; + } + + lock(form.submit); + + var xhr = new XMLHttpRequest(); + var fd = new FormData(); + fd.append('file', form.file.files[0]); + + xhr.upload.addEventListener('progress', function (e) { + var total = form.file.files[0].size; + var progress; + if (e.loaded < total) { + progress = Math.round(e.loaded / total * 100).toFixed(2); + } else { + progress = 100; + } + form.submit.innerHTML = progress + '%'; + }); + xhr.onreadystatechange = function() { + var errorMessage = 'Ошибка обновления'; + var successMessage = 'Обновление завершено, устройство перезагружается'; + if (xhr.readyState === 4) { + try { + var response = JSON.parse(xhr.responseText); + if (response.result === 1) { + alert(successMessage); + } else { + alert(errorMessage); + } + } catch (e) { + alert(successMessage); + } + } + }; + xhr.onerror = function(e) { + alert(errorText(e)); + }; + + xhr.open('POST', e.target.action); + xhr.send(fd); + + return false; + }); + form.file.addEventListener('change', function(e) { + if (e.target.files.length) { + var reader = new FileReader(); + reader.onload = function() { + var hash = window.md5(reader.result); + form.setAttribute('action', '/update?md5='+hash); + unlock(form.submit); + }; + reader.onerror = function() { + alert('Ошибка чтения файла'); + }; + reader.readAsBinaryString(e.target.files[0]); + } + }); +} + +window.initApp = function() { + initNetworkSettings(); + initUpdateForm(); +}
\ No newline at end of file diff --git a/platformio/common/static/favicon.ico b/platformio/common/static/favicon.ico Binary files differnew file mode 100644 index 0000000..6940e4f --- /dev/null +++ b/platformio/common/static/favicon.ico diff --git a/platformio/common/static/index.html b/platformio/common/static/index.html new file mode 100644 index 0000000..d4a8040 --- /dev/null +++ b/platformio/common/static/index.html @@ -0,0 +1,63 @@ +<!doctype html> +<html lang="en"> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <title>Configuration</title> + <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <script src="/md5.js"></script> + <script src="/app.js"></script> +</head> +<body onload="initApp()"> +<div class="title">Settings <span id="loading_label">(loading...)</span></div> +<div class="block"> + <form method="post" action="/status" name="network_settings"> + <div class="form_label">WiFi SSID</div> + <div class="form_input"> + <select id="ssid_select" name="ssid" class="full-width"> + <option value="">Loading...</option> + </select> + </div> + + <div class="form_label">WiFi Password</div> + <div class="form_input"> + <input type="password" value="" name="psk" class="full-width" id="fld_psk" maxlength="63" disabled> + <div class="form_sublabel"> + <label for="show_psk"><input type="checkbox" name="show_psk" id="show_psk"> show password</label> + </div> + </div> + + <div class="form_label">Home ID</div> + <div class="form_input"> + <input type="text" value="" maxlength="16" name="hid" id="fld_hid" class="full-width" disabled> + </div> + + <button type="submit" disabled="disabled" name="submit">Save and Reboot</button> + </form> +</div> + +<div class="title">Update firmware (.bin)</div> +<div class="block"> + <form method="post" action="/update" enctype="multipart/form-data" name="update_settings"> + <div class="form_input"> + <input type="file" accept=".bin,.bin.gz" name="file"> + </div> + <button type="submit" name="submit" disabled="disabled">Upload</button> + </form> +</div> + +<div class="title">Reset settings</div> +<div class="block"> + <form method="post" action="/reset"> + <button type="submit" name="submit" class="is_reset">Reset</button> + </form> +</div> + +<div class="title">Info</div> +<div class="block"> + ESP8266-based <b>relayctl</b>, firmware v{version}<br> + Part of <a href="https://git.ch1p.io/homekit.git/">homekit</a> by <a href="https://ch1p.io">Evgeny Zinoviev</a> © 2022 +</div> +</body> +</html>
\ No newline at end of file diff --git a/platformio/common/static/md5.js b/platformio/common/static/md5.js new file mode 100644 index 0000000..b707a4e --- /dev/null +++ b/platformio/common/static/md5.js @@ -0,0 +1,615 @@ +/** + * [js-md5]{@link https://github.com/emn178/js-md5} + * + * @namespace md5 + * @version 0.7.3 + * @author Chen, Yi-Cyuan [emn178@gmail.com] + * @copyright Chen, Yi-Cyuan 2014-2017 + * @license MIT + */ +(function () { + 'use strict'; + + var ERROR = 'input is invalid type'; + var ARRAY_BUFFER = typeof window.ArrayBuffer !== 'undefined'; + var HEX_CHARS = '0123456789abcdef'.split(''); + var EXTRA = [128, 32768, 8388608, -2147483648]; + var SHIFT = [0, 8, 16, 24]; + var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64']; + var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); + + var blocks = [], buffer8; + if (ARRAY_BUFFER) { + var buffer = new ArrayBuffer(68); + buffer8 = new Uint8Array(buffer); + blocks = new Uint32Array(buffer); + } + + if (!Array.isArray) { + Array.isArray = function (obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; + } + + if (ARRAY_BUFFER && !ArrayBuffer.isView) { + ArrayBuffer.isView = function (obj) { + return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; + }; + } + + /** + * @method hex + * @memberof md5 + * @description Output hash as hex string + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {String} Hex string + * @example + * md5.hex('The quick brown fox jumps over the lazy dog'); + * // equal to + * md5('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method digest + * @memberof md5 + * @description Output hash as bytes array + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Array} Bytes array + * @example + * md5.digest('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method array + * @memberof md5 + * @description Output hash as bytes array + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Array} Bytes array + * @example + * md5.array('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method arrayBuffer + * @memberof md5 + * @description Output hash as ArrayBuffer + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {ArrayBuffer} ArrayBuffer + * @example + * md5.arrayBuffer('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method buffer + * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. + * @memberof md5 + * @description Output hash as ArrayBuffer + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {ArrayBuffer} ArrayBuffer + * @example + * md5.buffer('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method base64 + * @memberof md5 + * @description Output hash as base64 string + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {String} base64 string + * @example + * md5.base64('The quick brown fox jumps over the lazy dog'); + */ + var createOutputMethod = function (outputType) { + return function (message) { + return new Md5(true).update(message)[outputType](); + }; + }; + + /** + * @method create + * @memberof md5 + * @description Create Md5 object + * @returns {Md5} Md5 object. + * @example + * var hash = md5.create(); + */ + /** + * @method update + * @memberof md5 + * @description Create and update Md5 object + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Md5} Md5 object. + * @example + * var hash = md5.update('The quick brown fox jumps over the lazy dog'); + * // equal to + * var hash = md5.create(); + * hash.update('The quick brown fox jumps over the lazy dog'); + */ + var createMethod = function () { + var method = createOutputMethod('hex'); + method.create = function () { + return new Md5(); + }; + method.update = function (message) { + return method.create().update(message); + }; + for (var i = 0; i < OUTPUT_TYPES.length; ++i) { + var type = OUTPUT_TYPES[i]; + method[type] = createOutputMethod(type); + } + return method; + }; + + /** + * Md5 class + * @class Md5 + * @description This is internal class. + * @see {@link md5.create} + */ + function Md5(sharedMemory) { + if (sharedMemory) { + blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + this.blocks = blocks; + this.buffer8 = buffer8; + } else { + if (ARRAY_BUFFER) { + var buffer = new ArrayBuffer(68); + this.buffer8 = new Uint8Array(buffer); + this.blocks = new Uint32Array(buffer); + } else { + this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + } + this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0; + this.finalized = this.hashed = false; + this.first = true; + } + + /** + * @method update + * @memberof Md5 + * @instance + * @description Update hash + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Md5} Md5 object. + * @see {@link md5.update} + */ + Md5.prototype.update = function (message) { + if (this.finalized) { + return; + } + + var notString, type = typeof message; + if (type !== 'string') { + if (type === 'object') { + if (message === null) { + throw ERROR; + } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) { + message = new Uint8Array(message); + } else if (!Array.isArray(message)) { + if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { + throw ERROR; + } + } + } else { + throw ERROR; + } + notString = true; + } + var code, index = 0, i, length = message.length, blocks = this.blocks; + var buffer8 = this.buffer8; + + while (index < length) { + if (this.hashed) { + this.hashed = false; + blocks[0] = blocks[16]; + blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + } + + if (notString) { + if (ARRAY_BUFFER) { + for (i = this.start; index < length && i < 64; ++index) { + buffer8[i++] = message[index]; + } + } else { + for (i = this.start; index < length && i < 64; ++index) { + blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; + } + } + } else { + if (ARRAY_BUFFER) { + for (i = this.start; index < length && i < 64; ++index) { + code = message.charCodeAt(index); + if (code < 0x80) { + buffer8[i++] = code; + } else if (code < 0x800) { + buffer8[i++] = 0xc0 | (code >> 6); + buffer8[i++] = 0x80 | (code & 0x3f); + } else if (code < 0xd800 || code >= 0xe000) { + buffer8[i++] = 0xe0 | (code >> 12); + buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); + buffer8[i++] = 0x80 | (code & 0x3f); + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + buffer8[i++] = 0xf0 | (code >> 18); + buffer8[i++] = 0x80 | ((code >> 12) & 0x3f); + buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); + buffer8[i++] = 0x80 | (code & 0x3f); + } + } + } else { + for (i = this.start; index < length && i < 64; ++index) { + code = message.charCodeAt(index); + if (code < 0x80) { + blocks[i >> 2] |= code << SHIFT[i++ & 3]; + } else if (code < 0x800) { + blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } else if (code < 0xd800 || code >= 0xe000) { + blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + } + } + } + this.lastByteIndex = i; + this.bytes += i - this.start; + if (i >= 64) { + this.start = i - 64; + this.hash(); + this.hashed = true; + } else { + this.start = i; + } + } + if (this.bytes > 4294967295) { + this.hBytes += this.bytes / 4294967296 << 0; + this.bytes = this.bytes % 4294967296; + } + return this; + }; + + Md5.prototype.finalize = function () { + if (this.finalized) { + return; + } + this.finalized = true; + var blocks = this.blocks, i = this.lastByteIndex; + blocks[i >> 2] |= EXTRA[i & 3]; + if (i >= 56) { + if (!this.hashed) { + this.hash(); + } + blocks[0] = blocks[16]; + blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + } + blocks[14] = this.bytes << 3; + blocks[15] = this.hBytes << 3 | this.bytes >>> 29; + this.hash(); + }; + + Md5.prototype.hash = function () { + var a, b, c, d, bc, da, blocks = this.blocks; + + if (this.first) { + a = blocks[0] - 680876937; + a = (a << 7 | a >>> 25) - 271733879 << 0; + d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708; + d = (d << 12 | d >>> 20) + a << 0; + c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375; + c = (c << 17 | c >>> 15) + d << 0; + b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209; + b = (b << 22 | b >>> 10) + c << 0; + } else { + a = this.h0; + b = this.h1; + c = this.h2; + d = this.h3; + a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330; + b = (b << 22 | b >>> 10) + c << 0; + } + + a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983; + b = (b << 22 | b >>> 10) + c << 0; + a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[10] - 42063; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162; + b = (b << 22 | b >>> 10) + c << 0; + a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329; + b = (b << 22 | b >>> 10) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734; + b = (b << 20 | b >>> 12) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[5] - 378558; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[8] - 2022574463; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[11] + 1839030562; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[14] - 35309556; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[1] - 1530992060; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[4] + 1272893353; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[7] - 155497632; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[10] - 1094730640; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[13] + 681279174; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[0] - 358537222; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[3] - 722521979; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[6] + 76029189; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[9] - 640364487; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[12] - 421815835; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[15] + 530742520; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[2] - 995338651; + b = (b << 23 | b >>> 9) + c << 0; + a += (c ^ (b | ~d)) + blocks[0] - 198630844; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[7] + 1126891415; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[14] - 1416354905; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[5] - 57434055; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[12] + 1700485571; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[3] - 1894986606; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[10] - 1051523; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[1] - 2054922799; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[8] + 1873313359; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[15] - 30611744; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[6] - 1560198380; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[13] + 1309151649; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[4] - 145523070; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[11] - 1120210379; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[2] + 718787259; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[9] - 343485551; + b = (b << 21 | b >>> 11) + c << 0; + + if (this.first) { + this.h0 = a + 1732584193 << 0; + this.h1 = b - 271733879 << 0; + this.h2 = c - 1732584194 << 0; + this.h3 = d + 271733878 << 0; + this.first = false; + } else { + this.h0 = this.h0 + a << 0; + this.h1 = this.h1 + b << 0; + this.h2 = this.h2 + c << 0; + this.h3 = this.h3 + d << 0; + } + }; + + /** + * @method hex + * @memberof Md5 + * @instance + * @description Output hash as hex string + * @returns {String} Hex string + * @see {@link md5.hex} + * @example + * hash.hex(); + */ + Md5.prototype.hex = function () { + this.finalize(); + + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; + + return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + + HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + + HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + + HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + + HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + + HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + + HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + + HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + + HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + + HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + + HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + + HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + + HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + + HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + + HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + + HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F]; + }; + + /** + * @method toString + * @memberof Md5 + * @instance + * @description Output hash as hex string + * @returns {String} Hex string + * @see {@link md5.hex} + * @example + * hash.toString(); + */ + Md5.prototype.toString = Md5.prototype.hex; + + /** + * @method digest + * @memberof Md5 + * @instance + * @description Output hash as bytes array + * @returns {Array} Bytes array + * @see {@link md5.digest} + * @example + * hash.digest(); + */ + Md5.prototype.digest = function () { + this.finalize(); + + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; + return [ + h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF, + h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF, + h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF, + h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF + ]; + }; + + /** + * @method array + * @memberof Md5 + * @instance + * @description Output hash as bytes array + * @returns {Array} Bytes array + * @see {@link md5.array} + * @example + * hash.array(); + */ + Md5.prototype.array = Md5.prototype.digest; + + /** + * @method arrayBuffer + * @memberof Md5 + * @instance + * @description Output hash as ArrayBuffer + * @returns {ArrayBuffer} ArrayBuffer + * @see {@link md5.arrayBuffer} + * @example + * hash.arrayBuffer(); + */ + Md5.prototype.arrayBuffer = function () { + this.finalize(); + + var buffer = new ArrayBuffer(16); + var blocks = new Uint32Array(buffer); + blocks[0] = this.h0; + blocks[1] = this.h1; + blocks[2] = this.h2; + blocks[3] = this.h3; + return buffer; + }; + + /** + * @method buffer + * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. + * @memberof Md5 + * @instance + * @description Output hash as ArrayBuffer + * @returns {ArrayBuffer} ArrayBuffer + * @see {@link md5.buffer} + * @example + * hash.buffer(); + */ + Md5.prototype.buffer = Md5.prototype.arrayBuffer; + + /** + * @method base64 + * @memberof Md5 + * @instance + * @description Output hash as base64 string + * @returns {String} base64 string + * @see {@link md5.base64} + * @example + * hash.base64(); + */ + Md5.prototype.base64 = function () { + var v1, v2, v3, base64Str = '', bytes = this.array(); + for (var i = 0; i < 15;) { + v1 = bytes[i++]; + v2 = bytes[i++]; + v3 = bytes[i++]; + base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + + BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] + + BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] + + BASE64_ENCODE_CHAR[v3 & 63]; + } + v1 = bytes[i]; + base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + + BASE64_ENCODE_CHAR[(v1 << 4) & 63] + + '=='; + return base64Str; + }; + + window.md5 = createMethod(); +})(); diff --git a/platformio/common/static/style.css b/platformio/common/static/style.css new file mode 100644 index 0000000..32bd02c --- /dev/null +++ b/platformio/common/static/style.css @@ -0,0 +1,85 @@ +body, html { + padding: 0; + margin: 0; +} +body, button, input[type="text"], input[type="password"] { + font-size: 16px; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; +} + +.title { + padding: 10px 10px 6px; + font-weight: 600; + background-color: #eff2f5; + border-bottom: 1px #d9e0e7 solid; + color: #276eb4; + font-size: 15px; +} +.block { + padding: 10px; +} +.full-width { + width: 100%; + box-sizing: border-box; +} + +.form_label { + padding: 0 0 3px; + font-weight: 600; +} +.form_input { + margin-bottom: 15px; +} +.form_sublabel { + padding-top: 3px; +} + +input[type="text"], +input[type="password"], +select { + border-radius: 4px; + border: 1px #c9cccf solid; + padding: 7px 9px; + outline: none; +} +input[type="text"]:focus, +input[type="password"]:focus, +select:focus { + box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); +} +input[type="text"]:disabled, +input[type="password"]:disabled, +select:disabled { + background-color: #f1f2f3; + border-color: #f1f2f3; +} + +button { + border-radius: 4px; + border: 1px #c9cccf solid; + padding: 7px 15px; + outline: none; + background: #fff; + color: #000; /* fix for iOS */ + position: relative; + line-height: 18px; + font-weight: 600; +} +button:disabled { + background-color: #f1f2f3; + border-color: #f1f2f3; +} +button:not(:disabled):hover { + box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); + cursor: pointer; + border-color: #b5cce3; + color: #276eb4; +} +button:not(:disabled):active { + top: 1px; +} + +button.is_reset, +button.is_reset:not(:disabled):hover { + color: #e63917; +}
\ No newline at end of file |