1135 lines
51 KiB
C++
1135 lines
51 KiB
C++
/*
|
|
xsns_62_esp32_mi.h - MI-BLE-sensors via ESP32 support for Tasmota
|
|
|
|
Copyright (C) 2021 Christian Baars and Theo Arends
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
#ifdef USE_MI_ESP32
|
|
|
|
#pragma once
|
|
|
|
#include <NimBLEDevice.h>
|
|
|
|
/*********************************************************************************************\
|
|
* structs and types
|
|
\*********************************************************************************************/
|
|
#pragma pack(1) // byte-aligned structures to read the sensor data
|
|
|
|
struct frame_crtl_t{
|
|
uint16_t reserved1:1;
|
|
uint16_t reserved2:1;
|
|
uint16_t reserved3:1;
|
|
uint16_t isEncrypted:1;
|
|
uint16_t includesMAC:1;
|
|
uint16_t includesCapability:1;
|
|
uint16_t includesObj:1;
|
|
uint16_t MESH:1;
|
|
uint16_t registered:1;
|
|
uint16_t solicited:1;
|
|
uint16_t AuthMode:2;
|
|
uint16_t version:4;
|
|
};
|
|
|
|
struct mi_payload_t{
|
|
uint16_t type;
|
|
uint8_t size;
|
|
union {
|
|
struct{ //0d
|
|
int16_t temp;
|
|
uint16_t hum;
|
|
}HT;
|
|
uint8_t bat; //0a
|
|
int16_t temp; //04
|
|
uint16_t hum; //06
|
|
uint32_t lux; //07
|
|
uint8_t moist; //08
|
|
uint16_t fert; //09
|
|
uint8_t leak; //14
|
|
uint32_t NMT; //17
|
|
uint8_t door; //19
|
|
uint16_t objID; //0x0002
|
|
struct{ //01
|
|
uint8_t num;
|
|
uint8_t value;
|
|
uint8_t type;
|
|
}Btn;
|
|
};
|
|
uint8_t padding[12]; //for decryption
|
|
};
|
|
|
|
struct mi_beacon_t{
|
|
frame_crtl_t frame;
|
|
uint16_t productID;
|
|
uint8_t counter;
|
|
uint8_t MAC[6];
|
|
uint8_t capability;
|
|
mi_payload_t payload;
|
|
};
|
|
|
|
|
|
struct cg_packet_t {
|
|
uint16_t frameID;
|
|
uint8_t MAC[6];
|
|
uint16_t mode;
|
|
union {
|
|
struct {
|
|
int16_t temp; // -9 - 59 °C
|
|
uint16_t hum;
|
|
};
|
|
uint8_t bat;
|
|
};
|
|
};
|
|
|
|
struct encPacket_t{
|
|
// the packet is longer, but this part is enough to decrypt
|
|
uint16_t PID;
|
|
uint8_t frameCnt;
|
|
uint8_t MAC[6];
|
|
uint8_t payload[16]; // only a pointer to the address, size is variable
|
|
};
|
|
|
|
struct berryAdvPacket_t{
|
|
uint8_t MAC[6];
|
|
uint8_t addressType;
|
|
uint8_t RSSI;
|
|
uint8_t length; // length of payload
|
|
uint8_t payload[32]; // only a pointer to the address, size is 0-31 bytes
|
|
};
|
|
|
|
|
|
union mi_bindKey_t{
|
|
struct{
|
|
uint8_t key[16];
|
|
uint8_t MAC[6];
|
|
};
|
|
uint8_t buf[22];
|
|
};
|
|
|
|
struct ATCPacket_t{ //and PVVX
|
|
uint8_t MAC[6];
|
|
union {
|
|
struct{
|
|
uint16_t temp; //sadly this is in wrong endianess
|
|
uint8_t hum;
|
|
uint8_t batPer;
|
|
uint16_t batMV;
|
|
uint8_t frameCnt;
|
|
} A; //ATC
|
|
struct{
|
|
int16_t temp;
|
|
uint16_t hum; // x 0.01 %
|
|
uint16_t batMV;
|
|
uint8_t batPer;
|
|
uint8_t frameCnt;
|
|
struct {
|
|
uint8_t reed:1;
|
|
uint8_t TRGval:1;
|
|
uint8_t TRGcrtl:1;
|
|
uint8_t tempTrig:1;
|
|
uint8_t humTrig:1;
|
|
uint8_t spare:3;
|
|
};
|
|
}P; //PVVX
|
|
};
|
|
};
|
|
|
|
union BTHome_info_t{
|
|
struct{
|
|
uint8_t encrypted:1;
|
|
uint8_t reserved:1;
|
|
uint8_t triggered:1;
|
|
uint8_t reserved2:2;
|
|
uint8_t version:2;
|
|
};
|
|
char byte_value;
|
|
};
|
|
|
|
struct BLERingBufferItem_t{
|
|
uint16_t returnCharUUID;
|
|
uint16_t handle;
|
|
uint32_t type;
|
|
uint8_t length;
|
|
};
|
|
|
|
#pragma pack(0)
|
|
|
|
|
|
struct MI32connectionContextBerry_t{
|
|
NimBLEUUID serviceUUID;
|
|
NimBLEUUID charUUID;
|
|
uint16_t returnCharUUID;
|
|
uint16_t handle;
|
|
uint8_t * buffer;
|
|
uint8_t MAC[6];
|
|
uint8_t operation;
|
|
uint8_t addrType;
|
|
int error;
|
|
int32_t arg1;
|
|
uint32_t pin;
|
|
bool hasArg1;
|
|
bool oneOp;
|
|
bool response;
|
|
};
|
|
|
|
struct {
|
|
// uint32_t period; // set manually in addition to TELE-period, is set to TELE-period after start
|
|
TaskHandle_t ScanTask = nullptr;
|
|
TaskHandle_t ConnTask = nullptr;
|
|
TaskHandle_t ServerTask = nullptr;
|
|
MI32connectionContextBerry_t *conCtx = nullptr;
|
|
uint16_t connID;
|
|
union {
|
|
struct {
|
|
uint32_t init:1;
|
|
uint32_t connected:1;
|
|
uint32_t autoScan:1;
|
|
// uint32_t canScan:1;
|
|
uint32_t runningScan:1;
|
|
uint32_t updateScan:1;
|
|
uint32_t deleteScanTask:1;
|
|
uint32_t IRKinCfg:1;
|
|
|
|
|
|
uint32_t canConnect:1;
|
|
uint32_t willConnect:1;
|
|
uint32_t readingDone:1;
|
|
|
|
uint32_t shallTriggerTele:1;
|
|
uint32_t triggeredTele:1;
|
|
uint32_t shallShowStatusInfo:1; // react to amount of found sensors via RULES
|
|
uint32_t didGetConfig:1;
|
|
|
|
uint32_t triggerBerryAdvCB:1;
|
|
uint32_t triggerBerryConnCB:1;
|
|
uint32_t triggerNextConnJob:1;
|
|
uint32_t readyForNextConnJob:1;
|
|
uint32_t discoverAttributes:1;
|
|
|
|
uint32_t triggerNextServerJob:1;
|
|
uint32_t readyForNextServerJob:1;
|
|
uint32_t triggerBerryServerCB:1;
|
|
uint32_t deleteServerTask:1;
|
|
};
|
|
uint32_t all = 0;
|
|
} mode;
|
|
struct {
|
|
uint8_t sensor; // points to to the number 0...255
|
|
} state;
|
|
struct {
|
|
uint32_t allwaysAggregate:1; // always show all known values of one sensor in brdigemode
|
|
uint32_t noSummary:1; // no sensor values at TELE-period
|
|
uint32_t directBridgeMode:1; // send every received BLE-packet as a MQTT-message in real-time
|
|
uint32_t activeScan:1;
|
|
uint32_t ignoreBogusBattery:1;
|
|
uint32_t handleEveryDevice:1;
|
|
} option;
|
|
#ifdef USE_MI_EXT_GUI
|
|
uint32_t widgetSlot = 0;
|
|
#ifdef USE_ENERGY_SENSOR
|
|
uint8_t energy_history[24];
|
|
#endif //USE_ENERGY_SENSOR
|
|
#endif //USE_MI_EXT_GUI
|
|
|
|
void *beConnCB;
|
|
void *beAdvCB;
|
|
void *beServerCB;
|
|
uint8_t *beAdvBuf;
|
|
uint8_t infoMsg = 0;
|
|
uint8_t role = 0;
|
|
} MI32;
|
|
|
|
struct mi_sensor_t{
|
|
uint8_t type; //Flora = 1; MI-HT_V1=2; LYWSD02=3; LYWSD03=4; CGG1=5; CGD1=6
|
|
uint8_t lastCnt; //device generated counter of the packet
|
|
uint8_t shallSendMQTT;
|
|
uint8_t MAC[6];
|
|
uint16_t PID;
|
|
uint8_t *key = nullptr;
|
|
char *name = nullptr;
|
|
union {
|
|
struct {
|
|
uint32_t needsKey:1;
|
|
uint32_t temp:1;
|
|
uint32_t hum:1;
|
|
uint32_t tempHum:1; //every hum sensor has temp too, easier to use Tasmota dew point functions
|
|
uint32_t lux:1;
|
|
uint32_t moist:1;
|
|
uint32_t fert:1;
|
|
uint32_t bat:1;
|
|
uint32_t NMT:1;
|
|
uint32_t motion:1;
|
|
uint32_t Btn:1;
|
|
uint32_t knob:1;
|
|
uint32_t door:1;
|
|
uint32_t leak:1;
|
|
uint32_t payload:1;
|
|
};
|
|
uint32_t raw = 0;
|
|
} feature;
|
|
union {
|
|
struct {
|
|
uint32_t temp:1;
|
|
uint32_t hum:1;
|
|
uint32_t tempHum:1; //can be combined from the sensor
|
|
uint32_t lux:1;
|
|
uint32_t moist:1;
|
|
uint32_t fert:1;
|
|
uint32_t bat:1;
|
|
uint32_t NMT:1;
|
|
uint32_t motion:1;
|
|
uint32_t noMotion:1;
|
|
uint32_t Btn:1;
|
|
uint32_t knob:1;
|
|
uint32_t longpress:1; //needs no extra feature bit, because knob is sufficient
|
|
uint32_t door:1;
|
|
uint32_t leak:1;
|
|
uint32_t payload:1;
|
|
};
|
|
uint32_t raw = 0;
|
|
} eventType;
|
|
union{
|
|
struct{
|
|
uint8_t hasWrongKey:1;
|
|
uint8_t isUnbounded:1;
|
|
};
|
|
uint8_t raw = 0;
|
|
} status;
|
|
|
|
int RSSI = 0;
|
|
uint32_t lastTime = 0;
|
|
uint32_t lux;
|
|
uint8_t lux_history[24];
|
|
float temp; //Flora, MJ_HT_V1, LYWSD0x, CGx
|
|
uint8_t temp_history[24];
|
|
union {
|
|
struct {
|
|
uint8_t moisture;
|
|
uint16_t fertility;
|
|
char firmware[6]; // actually only for FLORA but hopefully we can add for more devices
|
|
}; // Flora
|
|
struct {
|
|
float hum;
|
|
uint8_t hum_history[24];
|
|
};
|
|
struct {
|
|
uint16_t events; //"alarms" since boot
|
|
uint32_t NMT; // no motion time in seconds for the MJYD2S and NLIGHT
|
|
};
|
|
struct {
|
|
uint8_t Btn; // number starting with 0
|
|
uint8_t BtnType; // 0 -single, 1 - double, 2 - hold
|
|
uint8_t leak; // the leak sensor is the only non-RC device so far with a button fuctionality, so we handle it here
|
|
int8_t dimmer;
|
|
uint8_t pressed; // dimmer knob pressed while rotating
|
|
uint8_t longpress; // dimmer knob pressed without rotating
|
|
};
|
|
uint8_t door;
|
|
|
|
};
|
|
union {
|
|
uint8_t bat; // many values seem to be hard-coded garbage (LYWSD0x, GCD1)
|
|
};
|
|
struct {
|
|
uint8_t * payload = nullptr;
|
|
uint8_t payload_len;
|
|
};
|
|
};
|
|
|
|
/*********************************************************************************************\
|
|
* constants
|
|
\*********************************************************************************************/
|
|
|
|
#define D_CMND_MI32 "MI32"
|
|
|
|
const char kMI32_Commands[] PROGMEM = D_CMND_MI32 "|Key|Name|Cfg|Option";
|
|
|
|
void (*const MI32_Commands[])(void) PROGMEM = {&CmndMi32Key, &CmndMi32Name,&CmndMi32Cfg, &CmndMi32Option };
|
|
|
|
#define UNKNOWN_MI 0
|
|
#define FLORA 1
|
|
#define MJ_HT_V1 2
|
|
#define LYWSD02 3
|
|
#define LYWSD03MMC 4
|
|
#define CGG1 5
|
|
#define CGD1 6
|
|
#define NLIGHT 7
|
|
#define MJYD2S 8
|
|
#define YLYK01 9
|
|
#define MHOC401 10
|
|
#define MHOC303 11
|
|
#define ATC 12
|
|
#define MCCGQ02 13
|
|
#define SJWS01L 14
|
|
#define PVVX 15
|
|
#define YLKG08 16
|
|
#define YLAI003 17
|
|
#define BTHOME 18
|
|
|
|
#define MI32_TYPES 18 //count this manually
|
|
|
|
const uint16_t kMI32DeviceID[MI32_TYPES]={ 0x0098, // Flora
|
|
0x01aa, // MJ_HT_V1
|
|
0x045b, // LYWSD02
|
|
0x055b, // LYWSD03
|
|
0x0347, // CGG1
|
|
0x0576, // CGD1
|
|
0x03dd, // NLIGHT
|
|
0x07f6, // MJYD2S
|
|
0x0153, // YLYK01, old name yee-rc
|
|
0x0387, // MHO-C401
|
|
0x06d3, // MHO-C303
|
|
0x0a1c, // ATC -> this is a fake ID
|
|
0x098b, // MCCGQ02
|
|
0x0863, // SJWS01L
|
|
0x944a, // PVVX -> this is a fake ID
|
|
0x03b6, // YLKG08 and YLKG07 - version w/wo mains
|
|
0x07bf, // YLAI003
|
|
0xb770, // BTHome -> fake ID
|
|
};
|
|
|
|
const char kMI32DeviceType[] PROGMEM = {"Flora|MJ_HT_V1|LYWSD02|LYWSD03|CGG1|CGD1|NLIGHT|MJYD2S|YLYK01|MHOC401|MHOC303|ATC|MCCGQ02|SJWS01L|PVVX|YLKG08|YLAI003|BTHOME"};
|
|
|
|
const char kMI32_ConnErrorMsg[] PROGMEM = "no Error|could not connect|did disconnect|got no service|got no characteristic|can not read|can not notify|can not write|did not write|notify time out";
|
|
|
|
const char kMI32_BLEInfoMsg[] PROGMEM = "Scan ended|Got Notification|Did connect|Did disconnect|Still connected|Start passive scanning|Start active scanning|Server characteristic set|Server advertisement set|Server scan response set|Server client did connect|Server client did disconnect| Server client did authenticate";
|
|
|
|
const char kMI32_ButtonMsg[] PROGMEM = "Single|Double|Hold"; //mapping: in Tasmota: 1,2,3 ; for HomeKit and Xiaomi 0,1,2
|
|
/*********************************************************************************************\
|
|
* enumerations
|
|
\*********************************************************************************************/
|
|
|
|
enum MI32_Commands { // commands useable in console or rules
|
|
CMND_MI32_KEY, // add bind key to a mac for packet decryption
|
|
CMND_MI32_CFG, // save config file as JSON with all sensors w/o keys to mi32cfg
|
|
CMND_MI32_OPTION // change driver options at runtime
|
|
};
|
|
|
|
enum MI32_TASK {
|
|
MI32_TASK_SCAN = 0,
|
|
MI32_TASK_CONN = 1,
|
|
MI32_TASK_SERV = 2,
|
|
};
|
|
|
|
enum BLE_CLIENT_OP {
|
|
BLE_OP_READ = 1,
|
|
BLE_OP_WRITE,
|
|
BLE_OP_SUBSCRIBE,
|
|
BLE_OP_UNSUBSCRIBE, //maybe used later
|
|
BLE_OP_DISCONNECT,
|
|
BLE_OP_GET_NOTIFICATION = 103,
|
|
};
|
|
|
|
enum BLE_SERVER_OP {
|
|
//commands
|
|
BLE_OP_SET_ADV = 201,
|
|
BLE_OP_SET_SCAN_RESP,
|
|
BLE_OP_SET_CHARACTERISTIC = 211,
|
|
//response
|
|
BLE_OP_ON_READ = 221,
|
|
BLE_OP_ON_WRITE,
|
|
BLE_OP_ON_UNSUBSCRIBE,
|
|
BLE_OP_ON_SUBSCRIBE_TO_NOTIFICATIONS,
|
|
BLE_OP_ON_SUBSCRIBE_TO_INDICATIONS,
|
|
BLE_OP_ON_SUBSCRIBE_TO_NOTIFICATIONS_AND_INDICATIONS,
|
|
BLE_OP_ON_CONNECT,
|
|
BLE_OP_ON_DISCONNECT,
|
|
BLE_OP_ON_STATUS,
|
|
BLE_OP_ON_AUTHENTICATED
|
|
};
|
|
|
|
enum MI32_ConnErrorMsg {
|
|
MI32_CONN_NO_ERROR = 0,
|
|
MI32_CONN_NO_CONNECT,
|
|
MI32_CONN_DID_DISCCONNECT,
|
|
MI32_CONN_NO_SERVICE,
|
|
MI32_CONN_NO_CHARACTERISTIC,
|
|
MI32_CONN_CAN_NOT_READ,
|
|
MI32_CONN_CAN_NOT_NOTIFY,
|
|
MI32_CONN_CAN_NOT_WRITE,
|
|
MI32_CONN_DID_NOT_WRITE,
|
|
MI32_CONN_NOTIFY_TIMEOUT
|
|
};
|
|
|
|
enum MI32_BLEInfoMsg {
|
|
MI32_SCAN_ENDED = 1,
|
|
MI32_GOT_NOTIFICATION,
|
|
MI32_DID_CONNECT,
|
|
MI32_DID_DISCONNECT,
|
|
MI32_STILL_CONNECTED,
|
|
MI32_START_SCANNING_PASSIVE,
|
|
MI32_START_SCANNING_ACTIVE,
|
|
MI32_SERV_CHARACTERISTIC_ADDED,
|
|
MI32_SERV_ADVERTISEMENT_ADDED,
|
|
MI32_SERV_SCANRESPONSE_ADDED,
|
|
MI32_SERV_CLIENT_CONNECTED,
|
|
MI32_SERV_CLIENT_DISCONNECTED,
|
|
MI32_SERV_CLIENT_AUTHENTICATED
|
|
};
|
|
|
|
/*********************************************************************************************\
|
|
* extended web gui
|
|
\*********************************************************************************************/
|
|
|
|
#ifdef USE_WEBSERVER
|
|
#ifdef USE_MI_EXT_GUI
|
|
const char HTTP_BTN_MENU_MI32[] PROGMEM = "<p></p><form action='m32' method='get'><button>Dashboard</button></form>";
|
|
|
|
const char HTTP_MI32_BOOTSTRAP[] PROGMEM =
|
|
"wl(_=>fetch('/m32?wi=0').then(r=>r.text()).then(t=>{"
|
|
"d=document;" // this is global now
|
|
"x=d.createElement('div');"
|
|
"x.innerHTML=t;" // was global already
|
|
"x.querySelectorAll('style').forEach(n=>d.head.appendChild(n.cloneNode(1)));"
|
|
"x.querySelectorAll('script').forEach(n=>{s=d.createElement('script');s.textContent=n.textContent;d.body.appendChild(s)});"
|
|
"eb('m').innerHTML=(x.querySelector('body')||x).innerHTML;"
|
|
"}));";
|
|
|
|
const char HTTP_MI32_PARENT_BLE_ROLE[] PROGMEM = "None|Observer|Peripheral|Central";
|
|
|
|
const char HTTP_MI32_WIDGET[] PROGMEM =
|
|
"<div class='box' id='box%u' style='opacity:%u.5;'>MAC:%s RSSI:%d %s<br>"
|
|
"<small>‌%s</small>"
|
|
"<h2 style='margin-top:0em;'>%s"
|
|
"{ci}" // circle animation
|
|
"</h2>";
|
|
|
|
#ifdef USE_MI_ESP32_ENERGY
|
|
const char HTTP_MI32_POWER_WIDGET[] PROGMEM =
|
|
"<div class='box' id='box%u'>"
|
|
"<h2 style='margin-top:0em;'>Energy"
|
|
"</h2>"
|
|
"<p>" D_VOLTAGE ": %.1f " D_UNIT_VOLT "</p>"
|
|
"<p>" D_CURRENT ": %.3f " D_UNIT_AMPERE "</p>";
|
|
#endif //USE_MI_ESP32_ENERGY
|
|
|
|
/*
|
|
STATIC_PAGE MI32_STATIC_PAGE
|
|
<style>
|
|
body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
code {
|
|
word-break: break-all;
|
|
}
|
|
.parent {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill,350px);
|
|
grid-template-rows: repeat(auto-fill,220px);
|
|
grid-auto-rows: 220px;
|
|
grid-auto-columns: 350px;
|
|
gap: 1rem;
|
|
justify-content: center;
|
|
}
|
|
svg {
|
|
float: inline-end;
|
|
}
|
|
svg text {
|
|
font-size: 0.95em;
|
|
fill: currentColor;
|
|
}
|
|
.box {
|
|
padding: 10px;
|
|
border-radius: 0.8rem;
|
|
background-color: rgba(221,221,221,0.2);
|
|
overflow-y: auto;
|
|
}
|
|
.box svg {
|
|
max-width: 100%;
|
|
}
|
|
.box.w1 { grid-column: span 1; }
|
|
.box.w2 { grid-column: span 2; }
|
|
.box.w3 { grid-column: span 3; }
|
|
.box.h1 { grid-row: span 1; }
|
|
.box.h2 { grid-row: span 2; }
|
|
.box.h3 { grid-row: span 3; }
|
|
@media (width < 720px) {
|
|
.box.w2, .box.w3 { grid-column: span 1; }
|
|
.box.h3 { grid-row: span 2; }
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
let sz=[], u=0; // sizes, uptime
|
|
//global vars from tasmota header script for local reuse:
|
|
// x,lt,to,tp,pc
|
|
// d = document from the bootstrap script
|
|
// we also have:
|
|
// eb=s=>document.getElementById(s);
|
|
// qs=s=>document.querySelector(s);
|
|
// wl=f=>window.addEventListener('load',f);
|
|
|
|
function pulse(s) { // size
|
|
sz.push(s);
|
|
if (sz.length > 60) sz.shift();
|
|
lt = "(0,200,0):" + sz.join(",");
|
|
pc = `{l,250,20,${lt}}`;
|
|
eb('pulse').innerHTML = "AJAX: " + render(pc);
|
|
}
|
|
|
|
function setUp() {
|
|
setInterval(cU, 1000); // countUp
|
|
setInterval(update, 200);
|
|
}
|
|
|
|
function cU() {
|
|
x = eb('clock');
|
|
if (x) x.innerHTML = Date().slice(4,24);
|
|
}
|
|
|
|
function updateMetrics(m) {
|
|
let fk = +(m[3] / 1024).toFixed(1); // freeKB
|
|
let tk = +(m[4] / 1024).toFixed(1); // totalKB
|
|
let fp = +(m[7] / 1024).toFixed(0); // freePSRAM
|
|
let tp = +(m[6] / 1024).toFixed(0); // totalPSRAM
|
|
let fh = +(m[5]); // fragHeap
|
|
|
|
eb('r').innerHTML = 'RSSI: ' + m[0] + ' dBm';
|
|
eb('mo').innerHTML = 'Mode: ' + ['Low Rate','802.11b','802.11g','HT20 (11n)','HT40 (11n)','HE20 (11ax)'][m[2]] + ' / Channel: ' + m[1];
|
|
eb('heap_gauge').innerHTML = render(`{g,50,50,${fk},0,${tk},255,102,102,0,255,255,153,40,0,200,0,80,kB}`);
|
|
eb('psram_gauge').innerHTML = render(`{g,50,50,${fp},0,${tp},255,102,102,0,255,255,153,100,0,200,0,250,kB}`);
|
|
eb('heap').innerHTML = 'Heap free: ' + fk + '/' + tk + ' kB<br>(frag. ' + fh + '%)';
|
|
eb('psram').innerHTML = 'PSRAM free: ' + fp + '/' + tp + ' kB';
|
|
eb('ut').innerHTML = 'Uptime: ' + m[8] + ' sec';
|
|
eb('ro').innerHTML = 'BLE role: ' + ['none','observer','peripheral','central'][m[9]];
|
|
eb('sd').innerHTML = 'MI32 sensors: ' + m[10];
|
|
}
|
|
|
|
function update() {
|
|
try {
|
|
fetch('/m32?wi=1').then(r => r.text()).then(html => {
|
|
x = html.length; // number of characters ≈ bytes
|
|
pulse(x); // pass size instead of true/false
|
|
if (!html) {
|
|
return;
|
|
}
|
|
let parts = html.trim().split(/[\n\r,]+/);
|
|
if (parts.length === 11 && parts.every(p => /^-?\d+$/.test(p))) {
|
|
updateMetrics(parts.map(Number));
|
|
return;
|
|
}
|
|
|
|
let ciSVG =
|
|
"<svg height='24' width='24' >" // style='float:right;'
|
|
+ "<circle cx='11' cy='11' r='0' fill='#90ee90' opacity='0'>"
|
|
+ "<animate attributeName='r' from='11' to='0' dur='9s' repeatCount='1'/>"
|
|
+ "<animate attributeName='opacity' from='1' to='0' dur='9s' repeatCount='1'/>"
|
|
+ "</circle></svg>";
|
|
|
|
let replaced = html
|
|
.replace(/{ci}/g, ciSVG)
|
|
.replace(/\{[lLhHgG],[^}]+\}/g, match => {
|
|
try { return render(match); }
|
|
catch (e) {
|
|
console.warn("DSL render error:", e);
|
|
return "<small>graph unavailable</small>";
|
|
}
|
|
});
|
|
|
|
x = d.createElement('div');
|
|
x.innerHTML = replaced.trim();
|
|
|
|
lt = Array.from(x.getElementsByTagName('script'));
|
|
lt.forEach(el => el.remove());
|
|
|
|
tp = x.firstChild; //new element
|
|
to = eb(tp.id); // old element
|
|
if (to) to.parentNode.replaceChild(tp, to);
|
|
else eb('pr').appendChild(tp);
|
|
|
|
lt.forEach(el => {
|
|
let sc = d.createElement('script');
|
|
sc.textContent = el.textContent;
|
|
d.body.appendChild(sc);
|
|
});
|
|
});
|
|
} catch (e) {
|
|
// console.warn("update error:", e);
|
|
}
|
|
}
|
|
|
|
setTimeout(setUp, 500);
|
|
|
|
// Dispatcher for compact DSL only: {type,w,h,(r,g,b):v1,v2…[|…]}
|
|
// Uppercase ⇒ WITH grid; lowercase ⇒ WITHOUT grid
|
|
function render(payload) {
|
|
let s = String(payload).trim();
|
|
if (!s.startsWith("{") || !s.endsWith("}")) return "";
|
|
let inner = s.slice(1, -1);
|
|
|
|
// First char = type
|
|
let typeChar = inner[0];
|
|
let showGrid = typeChar === typeChar.toUpperCase();
|
|
let type = typeChar.toLowerCase();
|
|
|
|
// Handle line/histogram with series syntax
|
|
if ("lh".includes(type)) {
|
|
let m = inner.match(/^([lLhH]),(\d+),(\d+),(.+)$/);
|
|
if (!m) return "";
|
|
|
|
let [, , wStr, hStr, sStr] = m;
|
|
let w = +wStr; // width
|
|
let h = +hStr; // height
|
|
|
|
// Extract xl: parameter if present
|
|
let xl = null; // xLabels - custom X-axis labels
|
|
let seg = sStr.split("|");
|
|
for (let i = 0; i < seg.length; i++) {
|
|
if (seg[i].startsWith("xl:")) {
|
|
xl = seg[i].substring(3).split(",");
|
|
seg.splice(i, 1); // remove xl: segment from array
|
|
break;
|
|
}
|
|
}
|
|
|
|
let sl = seg.map(seg => { // sl = seriesList
|
|
let mm = seg.match(/^\((\d+),(\d+),(\d+)\):(.*)$/);
|
|
if (!mm) return null;
|
|
return {
|
|
rgb: [+mm[1], +mm[2], +mm[3]],
|
|
values: mm[4].split(",").map(v => Number(v.trim()))
|
|
};
|
|
}).filter(Boolean);
|
|
|
|
switch (type) {
|
|
case "l":
|
|
return renderLG(sl, w, h, showGrid, xl);
|
|
break;
|
|
case "h":
|
|
if (sl.length === 1)
|
|
return renderH(sl[0].values, sl[0].rgb, w, h, showGrid, xl);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Handle gauge DSL separately
|
|
// Gauge DSL: {g,w,h,val,min,max,r1,g1,b1,threshold1,r2,g2,b2,threshold2,...,unit}
|
|
// Example: {g,200,140,75,0,100,0,200,0,0,200,160,0,40,200,0,0,75,%}
|
|
// Stops: RGB triplet + threshold value, repeating. Unit string at end.
|
|
if (type === "g") {
|
|
let p = inner.split(',');
|
|
let w = +p[1], h = +p[2], val = +p[3], min = +p[4], max = +p[5];
|
|
let stops = [];
|
|
for (let i = 6; i < p.length - 1; i += 4) {
|
|
stops.push({
|
|
value: +p[i+3],
|
|
color: `rgb(${p[i]},${p[i+1]},${p[i+2]})`
|
|
});
|
|
}
|
|
let unit = p[p.length - 1];
|
|
let showValue = (typeChar === "G");
|
|
return renderG(val, min, max, w, h, stops, unit, showValue);
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
function buildGrid(w, h, mv, dL, yt = 4, cX = null) { // maxVal, dataLength, yTicks, customXLabels
|
|
let ln = [], lb = [], xl = []; // lines, labels, xLabels
|
|
let nm = Math.ceil(mv / 10) * 10; // niceMax
|
|
let ti = nm / yt; // tickInterval
|
|
if (ti <= 5) ti = 5;
|
|
else if (ti <= 10) ti = 10;
|
|
else if (ti <= 25) ti = 25;
|
|
else ti = Math.ceil(ti / 50) * 50;
|
|
nm = Math.ceil(mv / ti) * ti;
|
|
let at = Math.ceil(nm / ti); // actualTicks
|
|
for (let i = 0; i <= at; i++) {
|
|
let v = i * ti;
|
|
let y = h - (v * h / nm);
|
|
ln.push(`<line x1="0" y1="${y}" x2="${w}" y2="${y}" stroke="#ddd" stroke-width="1"/>`);
|
|
if (i < at) lb.push(`<text x="-5" y="${y+4}" text-anchor="end">${v}</text>`);
|
|
}
|
|
if (cX && cX.length > 0) { // X-axis labels - use custom if provided, otherwise default numeric
|
|
let xs = cX.length - 1; // xSteps
|
|
for (let i = 0; i < cX.length; i++) {
|
|
let x = xs > 0 ? i * (w / xs) : w / 2;
|
|
xl.push(`<text x="${x}" y="${h+20}" text-anchor="middle">${cX[i]}</text>`);
|
|
}
|
|
} else {
|
|
let xs = 4; // xSteps
|
|
for (let i = 0; i <= xs; i++) {
|
|
let x = i * (w / xs);
|
|
let xi = Math.round(i * (dL - 1) / xs);
|
|
xl.push(`<text x="${x}" y="${h+20}" text-anchor="middle">${xi}</text>`);
|
|
}
|
|
}
|
|
return { lines: ln.join(""), labels: lb.join(""), xl: xl.join("") };
|
|
}
|
|
|
|
function renderG(v, mn, mx, w, h, st, u = "", sv = true) { // value, min, max, stops, unit, showValue
|
|
let cl = x => Math.max(mn, Math.min(mx, x)); // clamp
|
|
let vl = cl(v); // val
|
|
let sp = mx - mn || 1; // span
|
|
let t = (vl - mn) / sp;
|
|
let cx = w / 2, cy = h / 2;
|
|
let ro = Math.min(w, h) * 0.45; // rOuter
|
|
let ri = ro * 0.75; // rInner
|
|
let so = ro * 0.06, si = ro * 0.35; // swOuter, swInner
|
|
let gd = 2; // gapDeg
|
|
let sd = -135 + gd, ed = 135 - gd, swd = ed - sd; // startDeg, endDeg, sweepDeg
|
|
|
|
function polar(cx, cy, r, d) { // deg
|
|
let rd = (d - 90) * Math.PI / 180; // rad
|
|
return { x: cx + r * Math.cos(rd), y: cy + r * Math.sin(rd) };
|
|
}
|
|
function arcPath(cx, cy, r, a0, a1) {
|
|
let la = Math.abs(a1 - a0) > 180 ? 1 : 0; // largeArc
|
|
let sw = a1 > a0 ? 1 : 0; // sweep
|
|
let p0 = polar(cx, cy, r, a0);
|
|
let p1 = polar(cx, cy, r, a1);
|
|
return `M ${p0.x},${p0.y} A ${r},${r} 0 ${la} ${sw} ${p1.x},${p1.y}`;
|
|
}
|
|
function colorFor(v) {
|
|
if (!st.length) return "rgb(120,120,120)";
|
|
let c = st[0].color;
|
|
for (let i = 0; i < st.length; i++) {
|
|
if (v >= st[i].value) c = st[i].color;
|
|
else break;
|
|
}
|
|
return c;
|
|
}
|
|
let os = ""; // outerSegs
|
|
for (let i = 0; i < st.length; i++) {
|
|
let fr = (st[i].value - mn) / sp; // from
|
|
let to = (i + 1 < st.length) ? (st[i+1].value - mn) / sp : 1;
|
|
let a0 = sd + swd * fr, a1 = sd + swd * to;
|
|
if (a1 <= a0) continue;
|
|
os += `<path d="${arcPath(cx, cy, ro, a0, a1)}" stroke="${st[i].color}" stroke-width="${so}" fill="none"/>`;
|
|
}
|
|
let bt = `<path d="${arcPath(cx, cy, ri, sd, ed)}" stroke="rgba(120,120,120,0.25)" stroke-width="${si}" fill="none"/>`; // bgTrack
|
|
let pc = colorFor(vl); // progColor
|
|
let pe = sd + swd * t; // progEnd
|
|
let ia = t > 0 ? `<path d="${arcPath(cx, cy, ri, sd, pe)}" stroke="${pc}" stroke-width="${si}" fill="none"/>` : ""; // innerArc
|
|
let tx = ""; // text
|
|
if (sv) {
|
|
let fs = Math.round(Math.min(w, h) * 0.18); // fontSize
|
|
tx = `<text x="${cx}" y="${cy}" text-anchor="middle" dominant-baseline="middle" font-size="${fs}" fill="${pc}" font-weight="600">${vl}${u}</text>`;
|
|
}
|
|
return `<svg width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">${os}${bt}${ia}${tx}</svg>`.trim();
|
|
}
|
|
|
|
function renderLG(sl, w, h, sg = true, customXL = null) { // showGrid, customXLabels
|
|
let mv = Math.max(...sl.flatMap(s => s.values), 1); // maxVal
|
|
let gd = sg ? buildGrid(w, h, mv, sl[0].values.length, 4, customXL) : { lines: "", labels: "", xl: "" }; // grid
|
|
let clipId = `clip_${Math.random().toString(36).slice(2)}`; // Clip path to hide vertical edges at x=0 and x=w
|
|
let clip = `<clipPath id="${clipId}"><rect x="0" y="0" width="${w}" height="${h}"/></clipPath>`;
|
|
let df = [], ly = []; // defs, layers
|
|
sl.forEach((s, i) => {
|
|
let gi = `g${i}_${Math.random().toString(36).slice(2)}`; // gradId
|
|
df.push(`<linearGradient id="${gi}" x1="0" y1="0" x2="0" y2="${h}" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="rgba(${s.rgb[0]},${s.rgb[1]},${s.rgb[2]},0.35)"/><stop offset="100%" stop-color="rgba(${s.rgb[0]},${s.rgb[1]},${s.rgb[2]},0)"/></linearGradient>`);
|
|
let pt = s.values.map((v, j) => { // points
|
|
let x = s.values.length > 1 ? (j * w) / (s.values.length - 1) : 0;
|
|
let y = v <= 0 ? h : h - (v / mv) * h;
|
|
return `${x},${y}`;
|
|
}).join(" ");
|
|
ly.push(`<polyline points="-20,${h} ${pt} ${w+20},${h}" fill="url(#${gi})" stroke="rgb(${s.rgb[0]},${s.rgb[1]},${s.rgb[2]})" stroke-width="2" clip-path="url(#${clipId})"/>`);
|
|
});
|
|
return `<svg width="${w}" height="${h+30}" viewBox="-50 0 ${w+100} ${h+40}">${gd.lines}${gd.labels}${gd.xl}<defs>${clip}${df.join("")}</defs>${ly.join("")}</svg>`.trim();
|
|
}
|
|
|
|
function renderH(vs, rgb, w, h, sg = true, cX = null) { // values, showGrid, customXLabels
|
|
let mv = Math.max(...vs); // maxVal
|
|
let sc = mv > h ? h / mv : 1; // scale
|
|
let gp = 2; // gap
|
|
let tg = (vs.length - 1) * gp; // totalGaps
|
|
let bw = (w - tg) / vs.length; // barW
|
|
let gi = "hg_" + (Math.random()*1e9|0); // gradId
|
|
let df = `<linearGradient id="${gi}" x1="0%" y1="0%" x2="0%" y2="${h}" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="rgba(${rgb[0]},${rgb[1]},${rgb[2]},1)"/><stop offset="100%" stop-color="rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.1)"/></linearGradient>`; // defs
|
|
let rs = ''; // rects
|
|
vs.forEach((v, i) => {
|
|
let bh = Math.min(v * sc, h); // barH
|
|
let y = h - bh;
|
|
let x = i * (bw + gp);
|
|
rs += `<rect x="${x}" y="${y}" width="${bw}" height="${bh}" fill="url(#${gi})"/>`;
|
|
});
|
|
if (!sg) return `<svg width="${w}" height="${h}"><defs>${df}</defs>${rs}</svg>`;
|
|
let gd = buildGrid(w, h, mv, vs.length, 4, cX); // grid
|
|
return `<svg width="${w}" height="${h+30}" viewBox="-50 0 ${w+100} ${h+40}">${gd.lines}${gd.labels}${gd.xl}<defs>${df}</defs>${rs}</svg>`.trim();
|
|
}
|
|
</script>
|
|
|
|
<div>
|
|
<div class="parent" id="pr">
|
|
<div class="box h2" id="info">
|
|
<h2 id="clock"></h2>
|
|
<p id="ut"></p>
|
|
<p id="ro"></p>
|
|
<p id="sd"></p><br>
|
|
|
|
<p id="r"></p>
|
|
<p id="mo"></p>
|
|
<p id="pulse"></p><br>
|
|
|
|
<div id="heap_gauge"></div>
|
|
<p id="heap"></p>
|
|
<div id="psram_gauge"></div>
|
|
<p id="psram"></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
END_STATIC_PAGE
|
|
*/
|
|
|
|
|
|
const char MI32_STATIC_PAGE[] PROGMEM = {
|
|
/* AUTO-GENERATED (BEGIN) */
|
|
0x1f, 0x8b, 0x08, 0x00, 0x1a, 0x5c, 0xe1, 0x68, 0x02, 0xff, 0xc5, 0x39, 0xfd, 0x73, 0xdb, 0x36,
|
|
0xb2, 0xbf, 0xf7, 0xaf, 0x60, 0x59, 0xa7, 0x22, 0x2c, 0x4a, 0x22, 0x65, 0x2b, 0x4d, 0x24, 0x41,
|
|
0xbe, 0x24, 0xd7, 0x4b, 0x72, 0xe3, 0xf4, 0x3a, 0x4d, 0x73, 0x2f, 0x33, 0x8e, 0x5a, 0x53, 0x24,
|
|
0x44, 0xb2, 0xe6, 0xd7, 0x10, 0x90, 0x44, 0x55, 0xe1, 0xff, 0x7e, 0xbb, 0x00, 0x48, 0x51, 0x76,
|
|
0x92, 0xcb, 0x7b, 0xef, 0x66, 0x6e, 0xc6, 0x26, 0x81, 0xdd, 0xc5, 0x62, 0xb1, 0xdf, 0xa0, 0xe6,
|
|
0x5c, 0xec, 0x13, 0xb6, 0x58, 0xe5, 0xc1, 0xfe, 0x10, 0xc4, 0xbc, 0x48, 0xbc, 0xfd, 0x74, 0x9d,
|
|
0xb0, 0x6a, 0x86, 0x8f, 0x41, 0x10, 0x97, 0xcc, 0x17, 0x71, 0x9e, 0x4d, 0xfd, 0x3c, 0xd9, 0xa4,
|
|
0x59, 0xed, 0xe7, 0x01, 0x3b, 0xec, 0xf2, 0x32, 0x18, 0xac, 0x4a, 0xe6, 0xdd, 0x4d, 0xe5, 0x73,
|
|
0xe0, 0x25, 0x49, 0x3d, 0x2c, 0xbc, 0x92, 0x65, 0xa2, 0x65, 0x12, 0x96, 0x71, 0x30, 0xc3, 0xc7,
|
|
0x40, 0xb0, 0x14, 0x20, 0x82, 0x0d, 0x14, 0x0f, 0x3e, 0x2d, 0x59, 0xc1, 0x3c, 0x61, 0x79, 0x1b,
|
|
0x91, 0x0f, 0xd6, 0x71, 0x92, 0xd8, 0x17, 0x13, 0xa7, 0xa8, 0xc8, 0x3d, 0xea, 0x32, 0xdf, 0x7d,
|
|
0x82, 0x74, 0x3c, 0x3e, 0x92, 0x4a, 0xa8, 0x24, 0x93, 0xd0, 0x0e, 0xb0, 0xd9, 0x49, 0x32, 0x9e,
|
|
0x85, 0x5e, 0x31, 0x75, 0x4b, 0x96, 0xce, 0xfe, 0xd8, 0x70, 0x11, 0xaf, 0xf7, 0x80, 0xce, 0x04,
|
|
0xc8, 0x3a, 0xf5, 0xe1, 0xc1, 0xca, 0x9a, 0x6f, 0xc3, 0xc3, 0x3a, 0xc9, 0x3d, 0x31, 0x8d, 0xb3,
|
|
0x24, 0xce, 0xd8, 0x80, 0x65, 0x01, 0x02, 0x0d, 0xc1, 0x2a, 0x71, 0x58, 0x03, 0xf1, 0x80, 0xc7,
|
|
0x7f, 0xb2, 0xa9, 0x33, 0x7c, 0x3a, 0x01, 0x2e, 0x28, 0xc7, 0xd4, 0xdf, 0x94, 0x78, 0xdc, 0x17,
|
|
0x79, 0x92, 0x97, 0xf5, 0x70, 0x95, 0x57, 0x87, 0xc2, 0x0b, 0x82, 0x38, 0x0b, 0xa7, 0x2e, 0x6e,
|
|
0xb9, 0x02, 0x15, 0xb1, 0x72, 0x50, 0x7a, 0x41, 0xbc, 0xe1, 0xb0, 0xf0, 0x09, 0x6e, 0xbf, 0xf2,
|
|
0xfc, 0xbb, 0xb0, 0xcc, 0x37, 0x59, 0x80, 0x02, 0xe6, 0xe5, 0xb4, 0x0c, 0x57, 0x9e, 0x35, 0x1e,
|
|
0xbb, 0x76, 0xf3, 0xef, 0x0c, 0xc7, 0x64, 0x96, 0x6f, 0x59, 0x09, 0xe2, 0xec, 0x06, 0xfb, 0x29,
|
|
0x1e, 0x46, 0x72, 0x37, 0x50, 0xc6, 0xd4, 0xab, 0x06, 0xbb, 0x38, 0x10, 0x11, 0xec, 0xe1, 0x3c,
|
|
0x92, 0xf0, 0xe1, 0xce, 0x3d, 0xc8, 0x63, 0xab, 0x13, 0x4f, 0x79, 0xe1, 0x65, 0x86, 0xab, 0x51,
|
|
0xe3, 0x87, 0xa8, 0xb1, 0x46, 0x5d, 0x3c, 0x44, 0x5d, 0x28, 0x54, 0xa4, 0x19, 0x82, 0x5e, 0x4f,
|
|
0xb8, 0x45, 0xe3, 0x7b, 0x70, 0xcd, 0x2a, 0xba, 0xb8, 0x07, 0xbf, 0xa8, 0xff, 0x92, 0xb2, 0x20,
|
|
0xf6, 0x0c, 0x4b, 0xca, 0x6a, 0xcc, 0x8d, 0x1f, 0xa4, 0xcd, 0x0e, 0x5a, 0x28, 0xfb, 0xb3, 0x12,
|
|
0xb8, 0x9f, 0xe1, 0x38, 0xae, 0xeb, 0xf9, 0x48, 0xf9, 0xe9, 0x9c, 0xfb, 0x65, 0x5c, 0x88, 0x45,
|
|
0xc2, 0x84, 0xc1, 0xff, 0xa4, 0x37, 0x4b, 0x7b, 0x43, 0x9d, 0xd9, 0x7a, 0x93, 0x49, 0x2f, 0x35,
|
|
0x8a, 0x4d, 0xc2, 0x99, 0xc5, 0xc9, 0x81, 0xff, 0x39, 0x2c, 0x36, 0x3c, 0x82, 0xe1, 0x2c, 0x5e,
|
|
0x5b, 0x30, 0x4b, 0x58, 0x16, 0x8a, 0x68, 0xf1, 0xd8, 0x21, 0x30, 0xe1, 0x51, 0xbc, 0x16, 0x16,
|
|
0x99, 0x25, 0x82, 0x9a, 0x96, 0x63, 0x8f, 0x1d, 0xc7, 0x76, 0xc8, 0xd4, 0xec, 0x03, 0xea, 0x8f,
|
|
0x3c, 0xce, 0x2c, 0xd3, 0x36, 0xc9, 0xac, 0xf0, 0xe9, 0xed, 0x01, 0x1c, 0x6e, 0x82, 0x04, 0xf6,
|
|
0xd9, 0x21, 0x11, 0x75, 0x7d, 0x3b, 0x63, 0x2b, 0xab, 0x27, 0x77, 0xe9, 0x91, 0x61, 0x9c, 0x65,
|
|
0xac, 0x7c, 0xf5, 0xeb, 0x9b, 0x6b, 0x6a, 0x3e, 0xfb, 0xfb, 0xb3, 0xf7, 0x53, 0xc3, 0xec, 0x83,
|
|
0x4f, 0x80, 0xdd, 0xad, 0xc2, 0x27, 0xb3, 0xfa, 0x9b, 0x56, 0x2c, 0xce, 0xc4, 0xbb, 0xc2, 0x02,
|
|
0xa9, 0x98, 0x78, 0x8d, 0x1e, 0xb7, 0xf5, 0x12, 0xcb, 0x7f, 0x67, 0x83, 0x15, 0x1d, 0x32, 0xeb,
|
|
0x02, 0x37, 0x45, 0x00, 0xae, 0x8f, 0x02, 0x9d, 0xac, 0xf7, 0xdf, 0xc1, 0xe2, 0x8a, 0xe2, 0xde,
|
|
0x7e, 0x92, 0xfb, 0x77, 0x3d, 0x79, 0xaa, 0x8a, 0x54, 0x1d, 0x11, 0xfe, 0x0a, 0x0b, 0x2d, 0x32,
|
|
0xe4, 0x49, 0xec, 0x33, 0xeb, 0xd2, 0x1e, 0x5f, 0x9e, 0x70, 0x50, 0x8c, 0xdf, 0x30, 0x51, 0xc6,
|
|
0x3e, 0xb7, 0x52, 0x72, 0x40, 0x05, 0xae, 0xef, 0x68, 0xdf, 0x4a, 0x6f, 0x2e, 0x96, 0x23, 0xd7,
|
|
0x01, 0xfa, 0xa1, 0xc8, 0xff, 0x16, 0x57, 0x2c, 0xb0, 0x5c, 0xd0, 0x0c, 0xa0, 0x85, 0x42, 0x5f,
|
|
0x7e, 0x06, 0xbd, 0x2e, 0x24, 0xfa, 0x87, 0xfb, 0x68, 0x47, 0xaf, 0x56, 0xe8, 0xc7, 0x9f, 0x41,
|
|
0xaf, 0x23, 0x89, 0x9e, 0x2c, 0x89, 0x54, 0x69, 0x79, 0xa2, 0xce, 0xde, 0x2f, 0x6f, 0xdf, 0xbe,
|
|
0x9e, 0x1a, 0xbd, 0x7e, 0x7a, 0xe3, 0x2c, 0xfb, 0x3d, 0x23, 0x78, 0x9e, 0xf6, 0x24, 0x59, 0x9a,
|
|
0x9f, 0xd2, 0xbd, 0x81, 0x74, 0x84, 0x74, 0x37, 0xbd, 0xeb, 0x7c, 0x67, 0xfc, 0x02, 0x47, 0xec,
|
|
0xd9, 0xbd, 0x27, 0xce, 0x78, 0xe8, 0xba, 0xab, 0x76, 0x14, 0xc2, 0xe8, 0xd5, 0xaf, 0x63, 0xc7,
|
|
0xb0, 0x5c, 0x37, 0x23, 0x72, 0x72, 0xd9, 0x99, 0xfc, 0xa8, 0x30, 0x5e, 0x45, 0x7a, 0xcb, 0x9b,
|
|
0xf4, 0x66, 0xbc, 0xc4, 0x1d, 0x47, 0xc6, 0x8b, 0xc8, 0x83, 0x7d, 0x12, 0x25, 0x85, 0xbb, 0x94,
|
|
0xdb, 0x47, 0xcc, 0x2b, 0x7e, 0x0f, 0xbd, 0x4d, 0x78, 0x6a, 0x7d, 0x6d, 0xf4, 0xdb, 0x43, 0x68,
|
|
0x83, 0xb3, 0x4c, 0xd0, 0x59, 0xd6, 0x77, 0xb5, 0x8d, 0x6f, 0x01, 0xef, 0xf1, 0x64, 0x02, 0xa6,
|
|
0x1e, 0xcb, 0x7f, 0x47, 0xce, 0x24, 0x64, 0x72, 0x61, 0x5f, 0x3a, 0xb6, 0xf6, 0x3e, 0xfb, 0x89,
|
|
0x63, 0xdf, 0x3d, 0xaf, 0x6f, 0x95, 0x36, 0x0a, 0x5e, 0x7a, 0xe9, 0x57, 0x6e, 0x54, 0xe8, 0x8d,
|
|
0x8a, 0x2f, 0x6d, 0xe4, 0x3a, 0xc7, 0x9d, 0xd0, 0xa1, 0x8f, 0x5b, 0xe1, 0x91, 0x4e, 0x75, 0xfa,
|
|
0x0a, 0x20, 0xc6, 0xba, 0x64, 0x52, 0xb1, 0xeb, 0xbb, 0x7e, 0x6f, 0xd4, 0xeb, 0x0b, 0x78, 0x19,
|
|
0x77, 0xcf, 0xe7, 0xab, 0x72, 0x61, 0xad, 0x4b, 0x2f, 0x1c, 0x22, 0x2a, 0xea, 0xf7, 0x1e, 0x91,
|
|
0xde, 0x51, 0xe0, 0x53, 0x36, 0x3f, 0xbf, 0xfd, 0xe5, 0xd9, 0x9b, 0x23, 0x9f, 0x42, 0xf1, 0x29,
|
|
0x24, 0x1f, 0xb5, 0x68, 0x23, 0x4e, 0x57, 0xbc, 0x2b, 0x44, 0x9c, 0x32, 0xa5, 0xf0, 0x27, 0x68,
|
|
0x04, 0xce, 0x7c, 0x45, 0x59, 0xde, 0x33, 0xfb, 0xf3, 0xeb, 0x1f, 0x8d, 0x32, 0x4f, 0xb4, 0xe9,
|
|
0xb3, 0x3c, 0x43, 0xb3, 0xe7, 0x2b, 0x0e, 0x41, 0xc4, 0x4a, 0x18, 0x16, 0x0c, 0x92, 0x44, 0xc4,
|
|
0x4a, 0x2f, 0x81, 0x09, 0x26, 0x79, 0x1c, 0xa1, 0x71, 0x9f, 0x2e, 0x95, 0x21, 0x79, 0x70, 0xcf,
|
|
0x8f, 0x5e, 0x5f, 0x8c, 0x61, 0xbb, 0x8c, 0xe7, 0x25, 0xd7, 0x16, 0x77, 0x96, 0x0f, 0xe3, 0x07,
|
|
0xa2, 0x50, 0x94, 0xfb, 0xc3, 0x9a, 0x09, 0x3f, 0xb2, 0x7a, 0xa3, 0xf4, 0x62, 0x7c, 0xb5, 0x8b,
|
|
0xa9, 0x0b, 0xbc, 0x44, 0xc4, 0x32, 0xab, 0xa4, 0x8b, 0x72, 0x88, 0x35, 0xc3, 0x22, 0x1a, 0x12,
|
|
0x89, 0x34, 0xa1, 0x0b, 0x08, 0x5d, 0x1c, 0xe8, 0x1c, 0x34, 0x53, 0x49, 0xaa, 0x92, 0x31, 0xfc,
|
|
0x2d, 0x22, 0xc8, 0xa1, 0x64, 0x62, 0x53, 0x66, 0xb0, 0x21, 0x86, 0x06, 0x14, 0x52, 0xc1, 0xd5,
|
|
0x0a, 0x08, 0xd7, 0x14, 0x83, 0xba, 0x48, 0x62, 0x61, 0x8d, 0x6e, 0x3e, 0x64, 0x1f, 0x4a, 0x7b,
|
|
0xd9, 0x1f, 0xc9, 0xa5, 0x92, 0x4c, 0xf3, 0xa4, 0x94, 0xba, 0xee, 0xf7, 0xdf, 0x2b, 0x10, 0x03,
|
|
0x25, 0xec, 0xad, 0x82, 0x2e, 0x46, 0xbf, 0x0d, 0xae, 0x3e, 0x04, 0xfd, 0xb3, 0x11, 0x08, 0xc5,
|
|
0x85, 0x55, 0x10, 0x42, 0x0e, 0xa7, 0x89, 0x40, 0x2d, 0x48, 0xbd, 0xc2, 0xfa, 0x69, 0x93, 0xae,
|
|
0x58, 0x49, 0xc8, 0xec, 0x44, 0x14, 0x3f, 0x7e, 0xfb, 0xcf, 0x97, 0xd4, 0x9c, 0x63, 0x31, 0x8c,
|
|
0x58, 0x1c, 0x46, 0x82, 0xf6, 0xc6, 0x97, 0x3d, 0x43, 0x66, 0x76, 0x35, 0x5c, 0x98, 0xdf, 0xf4,
|
|
0xcd, 0xb9, 0x1f, 0x97, 0x7e, 0xc2, 0x0c, 0xbf, 0xa2, 0x3d, 0xd7, 0xed, 0x19, 0xfe, 0x5e, 0xbd,
|
|
0x4b, 0xda, 0x73, 0x7a, 0x06, 0x16, 0x4c, 0xda, 0xfb, 0xee, 0xa9, 0xc3, 0xd8, 0x53, 0x98, 0xe6,
|
|
0x85, 0xe7, 0xc7, 0x62, 0x8f, 0x28, 0xb5, 0xd8, 0xcb, 0xe2, 0x14, 0x84, 0x32, 0x3c, 0x01, 0x52,
|
|
0xad, 0x36, 0x82, 0xfd, 0xe4, 0xa5, 0x8c, 0x42, 0x4e, 0x00, 0xf7, 0xc9, 0x53, 0xc5, 0x49, 0xe4,
|
|
0x92, 0x55, 0xb0, 0x01, 0x96, 0x4f, 0x39, 0x70, 0x96, 0x8d, 0xc1, 0x0b, 0x28, 0xa6, 0x20, 0x92,
|
|
0xdb, 0x1b, 0x7d, 0x91, 0x93, 0xde, 0xb1, 0xe5, 0xf7, 0xb5, 0xec, 0x46, 0xea, 0x58, 0x0b, 0xa8,
|
|
0x3e, 0xdb, 0x70, 0x61, 0xca, 0xc4, 0x05, 0x94, 0x89, 0xe7, 0xb3, 0x40, 0x19, 0x48, 0xcf, 0xac,
|
|
0xd1, 0xc1, 0x8f, 0xeb, 0x51, 0x68, 0x4b, 0x85, 0x91, 0x23, 0xf8, 0xc3, 0xe1, 0x26, 0xb9, 0x8e,
|
|
0x5e, 0x85, 0x2f, 0x97, 0xf6, 0xcd, 0x6f, 0xf5, 0xb2, 0xff, 0x01, 0x89, 0x40, 0x44, 0x3f, 0x02,
|
|
0xb7, 0x40, 0x5f, 0x52, 0xea, 0x36, 0x74, 0x64, 0x4b, 0x0c, 0x26, 0x6e, 0x1f, 0x07, 0x16, 0x23,
|
|
0x07, 0x68, 0x55, 0x38, 0x78, 0xfa, 0x70, 0xe7, 0x95, 0x50, 0x97, 0xfe, 0xfa, 0xf6, 0x5a, 0x93,
|
|
0x1a, 0xac, 0x2c, 0xa1, 0x83, 0x30, 0x6d, 0xd6, 0x98, 0x0c, 0xac, 0x94, 0x42, 0x23, 0xb6, 0x08,
|
|
0x4b, 0xaf, 0x88, 0x8c, 0x4d, 0xe6, 0x6d, 0xbd, 0x38, 0xf1, 0x56, 0x09, 0x03, 0xe9, 0x25, 0xc2,
|
|
0x9c, 0xd5, 0x35, 0x99, 0x55, 0x34, 0x18, 0xfa, 0xd0, 0xb5, 0x09, 0xf6, 0x63, 0xc2, 0x52, 0x88,
|
|
0x0d, 0xab, 0x17, 0xc4, 0x5b, 0xa8, 0x28, 0xd5, 0x49, 0xa2, 0x51, 0x87, 0xd4, 0x0e, 0x88, 0x85,
|
|
0xf2, 0x59, 0x59, 0x7a, 0xfb, 0x21, 0x2a, 0xd0, 0xaa, 0x86, 0x21, 0x13, 0x7a, 0x35, 0x7f, 0xbe,
|
|
0xff, 0xd5, 0x0b, 0x51, 0xcd, 0x10, 0x55, 0xb2, 0x36, 0xf7, 0x08, 0xd2, 0x0f, 0xd7, 0x79, 0xf9,
|
|
0xa3, 0x87, 0x67, 0x80, 0x00, 0x60, 0xa8, 0xa8, 0x14, 0xfa, 0x1a, 0x08, 0x8c, 0x19, 0x14, 0x86,
|
|
0x6a, 0xb8, 0x8e, 0x4b, 0x2e, 0x5e, 0x44, 0x71, 0x12, 0xcc, 0xc0, 0x14, 0x10, 0x92, 0xa2, 0x18,
|
|
0xc6, 0x81, 0xf4, 0x6b, 0x91, 0x13, 0x91, 0xeb, 0x6e, 0xf2, 0x27, 0xc8, 0xef, 0x8d, 0x32, 0x25,
|
|
0x35, 0xd0, 0xd9, 0x40, 0x30, 0x63, 0x10, 0x42, 0x86, 0xcc, 0x3c, 0x58, 0x39, 0xbc, 0xa2, 0x00,
|
|
0xa5, 0x34, 0x04, 0x0f, 0xb6, 0x97, 0xc5, 0x8e, 0xfb, 0x0f, 0x0f, 0xde, 0x08, 0x3c, 0xe3, 0xbe,
|
|
0x8c, 0xdb, 0x17, 0xaa, 0x2f, 0xa4, 0x20, 0x6f, 0x67, 0x3a, 0x0b, 0x86, 0xd8, 0x1e, 0x9f, 0xec,
|
|
0xc2, 0xb1, 0xc0, 0xab, 0xbf, 0xd6, 0x54, 0x75, 0xfd, 0x0d, 0xd4, 0xf2, 0x5f, 0x21, 0x87, 0xe5,
|
|
0x1b, 0x61, 0xc9, 0x9a, 0x0f, 0x39, 0x1a, 0xea, 0x5d, 0x9b, 0x45, 0x9a, 0xee, 0xc0, 0xdb, 0x43,
|
|
0xb7, 0x19, 0xa8, 0x22, 0xcc, 0xe9, 0x5b, 0x50, 0x72, 0x16, 0xb6, 0xd0, 0x46, 0xe7, 0x98, 0x1d,
|
|
0xf8, 0x90, 0x0b, 0x0c, 0xd1, 0xff, 0x89, 0x45, 0x64, 0x99, 0x07, 0x93, 0x7c, 0xfc, 0x08, 0x30,
|
|
0xe0, 0xa2, 0x21, 0xb5, 0x49, 0x88, 0xb6, 0xbe, 0xf2, 0x4e, 0x69, 0x42, 0xca, 0x75, 0x1b, 0xe0,
|
|
0xda, 0x83, 0xa6, 0x96, 0xef, 0x0b, 0x50, 0xa0, 0x57, 0x52, 0x49, 0x00, 0x55, 0x55, 0x42, 0x79,
|
|
0x94, 0xef, 0x5e, 0x42, 0xab, 0x45, 0x5b, 0x34, 0x6d, 0x87, 0x50, 0xb0, 0xdf, 0xc1, 0x81, 0xcb,
|
|
0x17, 0x1e, 0x24, 0xab, 0x23, 0x93, 0x2e, 0x1e, 0x6a, 0x6e, 0x8b, 0x07, 0x69, 0xcd, 0x24, 0x32,
|
|
0xc1, 0x87, 0xfc, 0x64, 0x13, 0x30, 0x6e, 0x21, 0x1d, 0x51, 0x47, 0x4c, 0xd5, 0xae, 0x43, 0xe9,
|
|
0xdd, 0xd6, 0xe8, 0x37, 0x4b, 0xc6, 0xc4, 0x92, 0xd8, 0x16, 0x64, 0xa7, 0xf6, 0x39, 0xec, 0x93,
|
|
0x33, 0x95, 0xd9, 0xbe, 0x4d, 0x4f, 0x0e, 0x75, 0x63, 0xdb, 0x3b, 0xd0, 0x91, 0x1d, 0xe1, 0x83,
|
|
0xc3, 0x63, 0x49, 0x53, 0x29, 0xcf, 0x8e, 0xf6, 0x11, 0x21, 0xc7, 0xd0, 0x4e, 0x44, 0xcd, 0xb8,
|
|
0x4a, 0x68, 0xb6, 0x49, 0x12, 0x75, 0x44, 0x16, 0x52, 0x5c, 0xa3, 0x73, 0xa8, 0xf9, 0x11, 0x3a,
|
|
0x3b, 0xf0, 0x0d, 0x4b, 0x2a, 0x0b, 0x5a, 0xc7, 0x78, 0x0e, 0x14, 0x4d, 0x66, 0x8e, 0xfb, 0x7d,
|
|
0x72, 0xc0, 0x7e, 0x91, 0x85, 0x37, 0xf1, 0xf2, 0x44, 0xf7, 0x55, 0x32, 0x05, 0x5d, 0x1f, 0x80,
|
|
0x75, 0x83, 0xdc, 0xac, 0xb8, 0x32, 0xdc, 0x45, 0x93, 0xa0, 0x65, 0xdb, 0x88, 0xec, 0x70, 0x0a,
|
|
0xea, 0x8f, 0x6d, 0xd0, 0xbe, 0xbc, 0x21, 0x41, 0xe4, 0xc9, 0x7c, 0xca, 0xe5, 0x72, 0x99, 0x70,
|
|
0x51, 0x30, 0xe5, 0x99, 0x69, 0xaa, 0x81, 0x4a, 0x3b, 0x1f, 0xac, 0x13, 0xb5, 0xe0, 0xf3, 0x03,
|
|
0x99, 0x5a, 0xc3, 0xf3, 0xa3, 0x7a, 0x1a, 0xfd, 0x18, 0xf2, 0x98, 0x6a, 0x7c, 0x80, 0xcb, 0xc4,
|
|
0xf4, 0xa6, 0x9f, 0x62, 0xb3, 0x62, 0xe3, 0x6b, 0xac, 0x5e, 0x17, 0xcb, 0xa5, 0x0d, 0xad, 0xe5,
|
|
0x86, 0xf1, 0x69, 0x8a, 0xcd, 0x5c, 0x47, 0x56, 0x29, 0xc7, 0x96, 0x2e, 0x54, 0xee, 0xb7, 0xb6,
|
|
0xda, 0xf3, 0x08, 0xa9, 0xc1, 0xb1, 0x21, 0x44, 0x13, 0xe8, 0x4a, 0xad, 0xe7, 0x39, 0xa4, 0x1f,
|
|
0x2f, 0x83, 0x83, 0xed, 0x62, 0x14, 0x50, 0xda, 0xf5, 0xe0, 0x83, 0xd5, 0xcd, 0xc4, 0x9c, 0x9e,
|
|
0xa4, 0xaf, 0xeb, 0x97, 0x16, 0x4f, 0xec, 0x9d, 0x1d, 0xd9, 0x8d, 0x63, 0xd9, 0x55, 0xd2, 0x68,
|
|
0x40, 0xae, 0x88, 0xcc, 0x29, 0xaa, 0x37, 0xe9, 0x94, 0x2d, 0xf2, 0xcd, 0x09, 0x8f, 0x57, 0x80,
|
|
0x05, 0xf7, 0x1c, 0x2a, 0x91, 0x6d, 0x35, 0x81, 0xa3, 0x7d, 0x8e, 0x2d, 0x28, 0x16, 0x73, 0x06,
|
|
0x7a, 0x26, 0xa5, 0x66, 0x68, 0x2a, 0x8f, 0x2b, 0xb4, 0xc7, 0xa9, 0xb3, 0x42, 0x13, 0x40, 0x1a,
|
|
0x87, 0x29, 0x50, 0x3d, 0x11, 0xbe, 0xc7, 0x52, 0x2f, 0x38, 0xba, 0x58, 0xda, 0x69, 0x9c, 0xe1,
|
|
0xe8, 0x12, 0x46, 0x5e, 0x85, 0xa3, 0x89, 0x8e, 0x10, 0x91, 0x17, 0x1c, 0xae, 0x19, 0x1d, 0x9f,
|
|
0x79, 0x0c, 0x3e, 0x53, 0xe8, 0x03, 0x0c, 0x5c, 0xf0, 0x19, 0x7a, 0x09, 0x9d, 0x3d, 0xd2, 0xa9,
|
|
0x2b, 0xc7, 0x41, 0x8a, 0x3e, 0x05, 0x1e, 0x71, 0x1f, 0x38, 0xab, 0x9b, 0xde, 0x2d, 0x1c, 0xc1,
|
|
0x3a, 0x3b, 0x00, 0x6c, 0x59, 0xdb, 0xf2, 0xdd, 0x77, 0xdb, 0xd1, 0x78, 0x59, 0x93, 0x5b, 0x4c,
|
|
0x25, 0xd2, 0x47, 0x36, 0x59, 0x2c, 0x68, 0x71, 0x73, 0xdc, 0xe2, 0x18, 0xab, 0xff, 0x44, 0xce,
|
|
0xd4, 0xea, 0x44, 0xab, 0xf9, 0xd2, 0x6c, 0xf2, 0xbf, 0x56, 0xe0, 0x4b, 0x0b, 0xf6, 0xc7, 0xf3,
|
|
0xe0, 0x49, 0x94, 0xd6, 0x50, 0x36, 0x1b, 0xd9, 0xda, 0x2d, 0x13, 0xdc, 0xac, 0x8d, 0xb1, 0x4e,
|
|
0x9f, 0xb3, 0xda, 0x40, 0x76, 0x43, 0x15, 0x5b, 0xb8, 0x32, 0xdd, 0xda, 0xc1, 0xb5, 0xbd, 0x17,
|
|
0xf4, 0xd2, 0xf6, 0xdf, 0xcb, 0x98, 0x52, 0xea, 0x4d, 0x32, 0xbc, 0x79, 0x25, 0x2b, 0x7c, 0x42,
|
|
0x44, 0xdc, 0x28, 0x09, 0xb3, 0x94, 0xbe, 0xf1, 0x44, 0x34, 0xf4, 0x59, 0x9c, 0x58, 0xe9, 0x16,
|
|
0xfa, 0x7e, 0x72, 0xee, 0x3a, 0x2a, 0x73, 0xc4, 0x34, 0x4b, 0x47, 0x7b, 0x21, 0xf3, 0x7b, 0x3c,
|
|
0xa7, 0x13, 0x02, 0x90, 0x89, 0xca, 0xe2, 0x1a, 0x04, 0xd4, 0x00, 0x03, 0xfa, 0x2e, 0x70, 0x2c,
|
|
0x09, 0xc7, 0x9a, 0x12, 0x86, 0xc7, 0x0d, 0x44, 0x3c, 0x9a, 0xc0, 0x06, 0x13, 0x67, 0x76, 0x7f,
|
|
0x5f, 0x11, 0x93, 0x73, 0x11, 0xcb, 0x7d, 0x3d, 0xd1, 0x41, 0x81, 0x04, 0x80, 0xba, 0x17, 0xfd,
|
|
0xd4, 0x13, 0x2a, 0xec, 0x11, 0xb4, 0xa5, 0x71, 0xb3, 0x72, 0x4f, 0xa3, 0x81, 0xb5, 0x3d, 0x8f,
|
|
0x46, 0x59, 0x0a, 0xbe, 0x93, 0x29, 0xd3, 0xde, 0xce, 0xf1, 0xf3, 0x80, 0x51, 0xb9, 0xd4, 0x74,
|
|
0x4c, 0x63, 0x0f, 0xaf, 0xb3, 0xc3, 0xbe, 0x36, 0x8d, 0x6a, 0x8c, 0xa3, 0x1d, 0x8c, 0xf6, 0xe3,
|
|
0x06, 0x06, 0xc9, 0x21, 0xbf, 0x63, 0xd4, 0xfc, 0x2e, 0x08, 0x82, 0x66, 0xa6, 0x6e, 0xef, 0xd4,
|
|
0x74, 0xcd, 0xd1, 0xe2, 0x56, 0xc6, 0x72, 0x3c, 0xf7, 0x04, 0x49, 0x56, 0x0d, 0x7b, 0xac, 0x3a,
|
|
0x46, 0x45, 0xcd, 0xc1, 0x04, 0x58, 0x49, 0x4e, 0xfd, 0x4b, 0xe0, 0x85, 0xe0, 0x81, 0x97, 0xf9,
|
|
0x51, 0x5e, 0x52, 0x13, 0xac, 0x6c, 0x2e, 0xce, 0x0e, 0x5b, 0xb8, 0x13, 0x23, 0x1c, 0x19, 0xc9,
|
|
0x18, 0xf0, 0xdf, 0x7f, 0xff, 0xbd, 0xff, 0xbe, 0xb9, 0xe8, 0x3a, 0xea, 0x44, 0x15, 0xa7, 0x2d,
|
|
0x0c, 0x9c, 0xf5, 0xf4, 0xec, 0x2d, 0xe6, 0xa8, 0x81, 0x8a, 0x56, 0x7c, 0xe1, 0x5c, 0xc5, 0xe7,
|
|
0xd6, 0x6e, 0x54, 0x71, 0x32, 0xdd, 0x8d, 0xc6, 0xb3, 0x2a, 0xb9, 0x2f, 0xde, 0xd9, 0xa1, 0xaa,
|
|
0xb5, 0x80, 0x51, 0x7f, 0xec, 0xdc, 0x97, 0x30, 0x8d, 0x83, 0x20, 0x61, 0x28, 0xa4, 0xff, 0x1e,
|
|
0x1d, 0xbe, 0x23, 0x68, 0x8d, 0x86, 0x6c, 0x24, 0xbb, 0xbc, 0x6f, 0x8b, 0x8a, 0x77, 0x25, 0x69,
|
|
0x84, 0x50, 0x39, 0x5d, 0xdb, 0x5e, 0x7e, 0x3e, 0xb1, 0x00, 0x15, 0x5c, 0x43, 0x6d, 0x93, 0xe8,
|
|
0xff, 0x87, 0x7c, 0x55, 0x7c, 0x22, 0x9c, 0x0e, 0x89, 0x03, 0x5a, 0x99, 0x4f, 0xc1, 0xea, 0xea,
|
|
0x6b, 0x80, 0x49, 0x6c, 0x68, 0xa4, 0x40, 0xf2, 0x29, 0x58, 0xaa, 0x05, 0x41, 0x45, 0x80, 0x9d,
|
|
0x9b, 0x69, 0xdd, 0x8d, 0xa2, 0x36, 0x12, 0xed, 0x14, 0xc2, 0xb0, 0x89, 0x42, 0x7b, 0x43, 0x4d,
|
|
0xd3, 0xe6, 0x5b, 0x2a, 0x4a, 0x08, 0x40, 0x79, 0x48, 0x3f, 0xa1, 0x15, 0x5d, 0xc8, 0x83, 0x41,
|
|
0xb4, 0x5a, 0x40, 0xad, 0xc6, 0xc0, 0x13, 0x96, 0x55, 0x44, 0x9d, 0x7d, 0x9b, 0x50, 0x3f, 0xb1,
|
|
0xb6, 0x6a, 0xc2, 0x0b, 0x9a, 0x56, 0x83, 0x34, 0xfb, 0xf8, 0xd1, 0x55, 0xa1, 0x45, 0xad, 0x6d,
|
|
0x02, 0x73, 0x32, 0xe2, 0x85, 0x04, 0x40, 0x0f, 0x0e, 0x56, 0xb3, 0xa1, 0x05, 0x8f, 0xc0, 0x78,
|
|
0xb2, 0x65, 0xcd, 0x69, 0xcb, 0x16, 0x44, 0x21, 0xe7, 0xce, 0xf0, 0x72, 0xa2, 0x30, 0x31, 0x2d,
|
|
0x73, 0x98, 0xfe, 0xa0, 0xa6, 0x3c, 0x57, 0x53, 0xe7, 0xb1, 0xcd, 0x35, 0xe6, 0x42, 0x61, 0xc2,
|
|
0x80, 0x2a, 0x5e, 0x3c, 0xa0, 0x03, 0xf7, 0x62, 0xd2, 0x0f, 0x03, 0x1b, 0x7a, 0x60, 0x18, 0x0d,
|
|
0x60, 0xc4, 0x77, 0x01, 0x65, 0xc1, 0x80, 0x07, 0x9d, 0x2f, 0x31, 0x79, 0xe2, 0x95, 0x96, 0x5f,
|
|
0x81, 0x1c, 0x76, 0x69, 0xeb, 0x5e, 0xa7, 0x0c, 0xa8, 0x15, 0x0c, 0x9e, 0x42, 0xd8, 0x4a, 0x79,
|
|
0x7e, 0x7e, 0x3d, 0x72, 0x9f, 0x38, 0x4d, 0xfd, 0xaa, 0xa6, 0x7e, 0xd5, 0x2f, 0x15, 0xc6, 0xcf,
|
|
0xb9, 0x55, 0x06, 0xc4, 0xde, 0x4f, 0xfd, 0x7d, 0x03, 0xe3, 0x20, 0x3d, 0xc0, 0x4e, 0x14, 0xed,
|
|
0x95, 0xfe, 0xcf, 0x80, 0x6b, 0xf7, 0xf1, 0x1c, 0xdb, 0x73, 0x75, 0x8e, 0xf2, 0xd4, 0xa1, 0xbd,
|
|
0x15, 0xb7, 0x3c, 0x77, 0xe0, 0x39, 0x64, 0x01, 0x9b, 0x5d, 0xb9, 0x53, 0x95, 0x91, 0xf8, 0x8e,
|
|
0x7a, 0xee, 0xc2, 0x3b, 0x02, 0x0a, 0x87, 0x9e, 0xca, 0xec, 0xe9, 0x2f, 0x15, 0x85, 0x7b, 0x1f,
|
|
0xe1, 0x36, 0x29, 0xf7, 0xf6, 0x8d, 0x01, 0x19, 0xdc, 0x19, 0x56, 0x32, 0x93, 0x3b, 0xc3, 0x7d,
|
|
0x6d, 0x3c, 0x03, 0x48, 0x89, 0xd3, 0xb2, 0x36, 0x1c, 0x18, 0x27, 0x5e, 0x0d, 0x4f, 0xbe, 0xc3,
|
|
0x67, 0xe1, 0x6a, 0x4a, 0x17, 0x28, 0x6f, 0x4f, 0x3e, 0xf0, 0x60, 0x91, 0xf8, 0x1b, 0x04, 0xc3,
|
|
0x56, 0xf6, 0x1f, 0xdf, 0x72, 0xa1, 0x23, 0xb3, 0x69, 0x84, 0xb0, 0x7c, 0xb8, 0x63, 0xc7, 0xd6,
|
|
0xff, 0x44, 0x75, 0x7b, 0x3e, 0xe5, 0x02, 0xeb, 0xa3, 0x5c, 0x7e, 0xbf, 0xad, 0x11, 0xf7, 0xbb,
|
|
0x9a, 0xed, 0x02, 0xc9, 0x63, 0x5d, 0x5b, 0x89, 0xaf, 0x67, 0x6a, 0xb1, 0x4c, 0xb0, 0xba, 0xa4,
|
|
0x36, 0x15, 0xd9, 0xd7, 0x15, 0x29, 0xe7, 0xe0, 0xb8, 0x5f, 0x66, 0x2f, 0x3f, 0xe9, 0x94, 0xd4,
|
|
0xea, 0x6c, 0xd0, 0xf5, 0x49, 0xe8, 0xf1, 0x2d, 0xa8, 0x78, 0xc7, 0x55, 0xe4, 0x4a, 0x92, 0x42,
|
|
0x11, 0x3c, 0x21, 0x9e, 0x2a, 0x9f, 0xf6, 0x1c, 0xca, 0x83, 0x3e, 0x78, 0xd5, 0xf9, 0x1a, 0xd5,
|
|
0xdd, 0x4c, 0x44, 0x8e, 0x29, 0xd3, 0x73, 0x21, 0x69, 0x3b, 0x04, 0xbf, 0xe1, 0xc6, 0xd9, 0x86,
|
|
0xcd, 0x72, 0xde, 0xa7, 0xb7, 0xf3, 0x02, 0x6c, 0x6d, 0x04, 0x18, 0xf1, 0x1d, 0x9f, 0x80, 0x7b,
|
|
0xa8, 0x0d, 0xde, 0x6f, 0x03, 0x43, 0xf8, 0x77, 0x49, 0x27, 0x2d, 0x83, 0x4d, 0x8e, 0xa7, 0xaf,
|
|
0xef, 0x27, 0x68, 0xc0, 0xe6, 0x00, 0x94, 0x17, 0x57, 0x13, 0xbf, 0x2f, 0x60, 0xc2, 0xd6, 0xda,
|
|
0x58, 0x89, 0x2f, 0x6f, 0x17, 0xdb, 0x10, 0x24, 0xb6, 0xc1, 0x82, 0xee, 0x76, 0xf2, 0x4b, 0x6f,
|
|
0xc7, 0x80, 0xf8, 0xa5, 0x77, 0x42, 0x3e, 0xb1, 0x6d, 0xfc, 0x70, 0x5b, 0xe9, 0x84, 0x3e, 0x3d,
|
|
0xfa, 0x48, 0xa2, 0x1d, 0x93, 0xb5, 0x8a, 0x51, 0xbd, 0xbf, 0x47, 0x05, 0xe4, 0xee, 0xaf, 0x11,
|
|
0x0e, 0x5a, 0xb8, 0x13, 0x5d, 0x14, 0x7e, 0xfd, 0x55, 0xb2, 0x4c, 0xf5, 0x35, 0x43, 0x54, 0xe8,
|
|
0x11, 0xd8, 0xca, 0x6d, 0xb5, 0xed, 0x79, 0x37, 0x3d, 0xdf, 0xcf, 0x36, 0xee, 0x13, 0xb8, 0xf6,
|
|
0x55, 0xb4, 0x9b, 0xa0, 0xfd, 0x36, 0x43, 0xfb, 0xfb, 0xcf, 0xe4, 0x67, 0x23, 0xc8, 0x81, 0x87,
|
|
0x97, 0x89, 0xc1, 0x0a, 0x7a, 0x47, 0xcc, 0xc9, 0x47, 0x54, 0xfb, 0x51, 0x1e, 0x39, 0xac, 0x79,
|
|
0x2b, 0xa8, 0x3e, 0x8a, 0x44, 0xef, 0xd4, 0x07, 0x0b, 0xf3, 0xb1, 0xe3, 0xc8, 0x82, 0x99, 0xd4,
|
|
0x67, 0x87, 0x4d, 0x9b, 0xef, 0x5b, 0x37, 0xbf, 0x95, 0x5f, 0x37, 0xda, 0x53, 0x63, 0x15, 0xd7,
|
|
0x9f, 0x3a, 0xb0, 0x7c, 0xc0, 0x6c, 0x1b, 0xb3, 0xdd, 0xf3, 0x1c, 0xa4, 0x76, 0x64, 0x44, 0xcb,
|
|
0x50, 0x06, 0x38, 0xb0, 0xcc, 0x39, 0xb0, 0x5c, 0x09, 0x78, 0xc4, 0x1e, 0x3c, 0x44, 0x55, 0xab,
|
|
0x2f, 0x05, 0xb7, 0xcd, 0x1d, 0xee, 0x41, 0x4d, 0xe8, 0xb4, 0xc8, 0xa1, 0xac, 0x03, 0xb6, 0xbf,
|
|
0x81, 0xfe, 0x2c, 0x7d, 0x7f, 0xdd, 0x69, 0xaf, 0xd2, 0x2d, 0x6d, 0x4b, 0xc2, 0x70, 0x08, 0x77,
|
|
0xb9, 0xe1, 0x3a, 0xf1, 0xc4, 0x1b, 0xbc, 0x34, 0xd0, 0x05, 0xd7, 0xad, 0x31, 0xb1, 0xf5, 0xd5,
|
|
0x0e, 0x52, 0x33, 0x0f, 0xaf, 0x1e, 0x34, 0x6e, 0xdd, 0x36, 0x5a, 0x07, 0x9d, 0x7d, 0xd9, 0xee,
|
|
0x46, 0xa6, 0xba, 0xc8, 0x41, 0x45, 0xd2, 0xb5, 0x0d, 0x46, 0x78, 0xc9, 0x31, 0x6b, 0x95, 0x5a,
|
|
0x92, 0xb8, 0x78, 0x1d, 0xd0, 0x5b, 0x7c, 0xff, 0x7e, 0x76, 0x50, 0xc6, 0xf5, 0x32, 0x30, 0x89,
|
|
0x85, 0xdf, 0x72, 0xf5, 0x9d, 0xf5, 0xe2, 0x71, 0xf3, 0xc5, 0x79, 0x4c, 0xea, 0xdb, 0x76, 0x21,
|
|
0x58, 0x1a, 0x5f, 0xe8, 0x7a, 0x46, 0x2c, 0x1d, 0x51, 0xb1, 0x03, 0xa5, 0xcd, 0xf1, 0x07, 0x25,
|
|
0x74, 0x01, 0x47, 0x9a, 0x1f, 0x9e, 0x9f, 0xd7, 0xfc, 0x68, 0x31, 0x1f, 0x35, 0x7c, 0x74, 0x1c,
|
|
0x04, 0x6b, 0xd9, 0x79, 0xee, 0xb1, 0xe7, 0x44, 0xbd, 0xe8, 0x5b, 0xbe, 0xc5, 0xed, 0x98, 0xe8,
|
|
0xeb, 0x54, 0x18, 0xd3, 0xdb, 0x10, 0x2c, 0x52, 0x7f, 0xb5, 0xd8, 0xc1, 0xba, 0xdb, 0xde, 0x79,
|
|
0xe5, 0x4b, 0xfc, 0xd9, 0x06, 0x2e, 0xfe, 0x5a, 0xf6, 0x10, 0xe3, 0xa0, 0xd3, 0xf3, 0x39, 0xaa,
|
|
0xe1, 0x73, 0x9a, 0x6e, 0x0f, 0x7d, 0x24, 0xd4, 0x4b, 0xde, 0x41, 0x97, 0x0d, 0xd9, 0x72, 0xc3,
|
|
0x59, 0xf9, 0xb6, 0xf0, 0x7c, 0xf6, 0x8f, 0xec, 0x1d, 0x5c, 0x7b, 0x16, 0x73, 0xec, 0xc1, 0x8d,
|
|
0x7c, 0xbd, 0xe6, 0x0c, 0x0e, 0xe7, 0x3c, 0x32, 0xe5, 0xc5, 0x42, 0xfd, 0x0a, 0xa4, 0x93, 0x03,
|
|
0xc4, 0x1b, 0xde, 0x73, 0xc0, 0x68, 0x58, 0x22, 0xd4, 0xd8, 0xed, 0x8c, 0xe1, 0x92, 0x60, 0x63,
|
|
0x39, 0x26, 0xa8, 0x96, 0x13, 0x76, 0xf8, 0x63, 0xd0, 0xff, 0x95, 0xa1, 0xe4, 0x36, 0x3a, 0x3d,
|
|
0x36, 0xf6, 0x42, 0x32, 0xbf, 0x08, 0xda, 0x38, 0x9b, 0xbc, 0x29, 0x42, 0x3b, 0xf3, 0x47, 0xa3,
|
|
0xe4, 0xea, 0x88, 0xd2, 0x0d, 0xa7, 0x7b, 0x65, 0xfd, 0x71, 0xbe, 0x23, 0x23, 0xeb, 0x1e, 0x02,
|
|
0xba, 0x34, 0x5d, 0x61, 0xf7, 0x74, 0x3b, 0xa7, 0xce, 0x55, 0x34, 0xc5, 0xce, 0x7a, 0x94, 0x6e,
|
|
0xc9, 0x79, 0xd4, 0xd4, 0x51, 0x6c, 0xd8, 0x6c, 0xec, 0x9b, 0x6f, 0xf1, 0xe6, 0xa9, 0x7a, 0x2a,
|
|
0x03, 0x6e, 0x36, 0xc9, 0xbe, 0xb1, 0x0c, 0x94, 0xe0, 0xbd, 0x6c, 0xbe, 0x0b, 0x40, 0xa2, 0x8a,
|
|
0x07, 0xf2, 0x47, 0x99, 0x48, 0xd6, 0x55, 0x81, 0xcf, 0x1d, 0x76, 0x7a, 0xb6, 0x32, 0x87, 0x4a,
|
|
0x06, 0x9b, 0x32, 0xb1, 0xbe, 0x93, 0xf6, 0x23, 0x27, 0x99, 0xf8, 0x6b, 0x54, 0xf3, 0x20, 0x37,
|
|
0x8f, 0x4d, 0xe9, 0xda, 0x03, 0x4c, 0xae, 0x2d, 0x6b, 0xed, 0xd6, 0x44, 0xf5, 0xf3, 0x75, 0xdb,
|
|
0x17, 0x7c, 0x31, 0xa5, 0xf4, 0x2f, 0x9c, 0x6e, 0x56, 0x19, 0x4c, 0x74, 0x5e, 0xe9, 0x83, 0x21,
|
|
0x65, 0x6e, 0xe9, 0x5f, 0x3a, 0x32, 0xbd, 0x84, 0xc1, 0x50, 0x06, 0x69, 0xad, 0x86, 0x32, 0x4c,
|
|
0xd5, 0xb8, 0x4a, 0xea, 0x79, 0xc0, 0xd6, 0x7c, 0xa1, 0x44, 0x00, 0x20, 0xf8, 0x70, 0xdb, 0x8a,
|
|
0xce, 0x47, 0x1a, 0x07, 0xea, 0xeb, 0x00, 0xbf, 0x9c, 0x99, 0x5e, 0x59, 0x5b, 0x6e, 0xb7, 0x17,
|
|
0xed, 0x26, 0x39, 0xbd, 0xff, 0x7c, 0x5a, 0xda, 0xea, 0xce, 0x9c, 0xfb, 0x34, 0xdd, 0x2e, 0xa2,
|
|
0xab, 0x08, 0x4c, 0xaa, 0xeb, 0x77, 0x58, 0xe8, 0x6e, 0x51, 0x84, 0xd0, 0x9d, 0x76, 0x3c, 0xe1,
|
|
0x3c, 0x54, 0xfd, 0xc0, 0x6a, 0x47, 0xad, 0xdd, 0x40, 0x84, 0x64, 0xd4, 0x62, 0x67, 0x3a, 0x76,
|
|
0xcd, 0x28, 0xfc, 0xdd, 0xec, 0x5b, 0x27, 0x91, 0x7b, 0xee, 0xb2, 0xa7, 0x1f, 0x75, 0x3b, 0x06,
|
|
0x19, 0xe0, 0xdf, 0xc6, 0xe9, 0x23, 0x1d, 0xa8, 0x8f, 0x74, 0xa4, 0x3e, 0xfa, 0x4f, 0x87, 0xea,
|
|
0xd1, 0x79, 0x8e, 0xae, 0xd3, 0xc4, 0x94, 0xfb, 0xbf, 0x88, 0xd0, 0x2f, 0xf1, 0x81, 0xb2, 0xf9,
|
|
0xe9, 0xe8, 0x54, 0x9d, 0x3b, 0xa7, 0xbd, 0xde, 0x0c, 0xb4, 0xd7, 0xa6, 0xc0, 0xed, 0x31, 0x05,
|
|
0xae, 0xa2, 0x63, 0xc3, 0xbf, 0x3d, 0xe7, 0x3e, 0x54, 0xe1, 0xf6, 0x52, 0xbb, 0x52, 0x9a, 0x96,
|
|
0xd7, 0xab, 0xd5, 0xae, 0x1f, 0x16, 0xe0, 0xb4, 0xb2, 0x83, 0x6a, 0x12, 0x73, 0xe7, 0xf2, 0x84,
|
|
0x95, 0xb9, 0xf5, 0xe2, 0xd5, 0xa9, 0x1b, 0xaf, 0x3e, 0x1d, 0x67, 0xb2, 0x4f, 0xd2, 0x1f, 0x2f,
|
|
0x43, 0xf2, 0x75, 0x15, 0x76, 0xd1, 0xf8, 0x72, 0xb0, 0x3e, 0xfa, 0x6e, 0xc9, 0x1b, 0x97, 0x6d,
|
|
0xaa, 0xdc, 0x83, 0x12, 0xb7, 0xed, 0x16, 0xb6, 0xf7, 0xff, 0x8d, 0xe0, 0xfb, 0xb4, 0xc0, 0x6d,
|
|
0x8c, 0xc1, 0x5c, 0xfd, 0x5c, 0x3d, 0x0f, 0xe2, 0xad, 0x7c, 0x40, 0x0e, 0xf1, 0x38, 0xa7, 0xea,
|
|
0xeb, 0x36, 0xfa, 0x6d, 0x51, 0x76, 0xe1, 0x26, 0xfe, 0xd4, 0x1f, 0x41, 0xaa, 0x01, 0x4c, 0x9c,
|
|
0xad, 0xf3, 0xc5, 0x3c, 0x1a, 0xe3, 0x58, 0xfe, 0xea, 0x0b, 0xae, 0x10, 0x8d, 0x17, 0xf3, 0x02,
|
|
0x01, 0x1b, 0xe0, 0x39, 0x2a, 0xf4, 0xa4, 0xcc, 0x3b, 0x13, 0x1e, 0xa8, 0xc9, 0xaa, 0x6c, 0xb0,
|
|
0x1d, 0x64, 0xda, 0xa5, 0x94, 0xbf, 0x43, 0x1d, 0x89, 0x51, 0x0a, 0x80, 0x1e, 0x7f, 0xe3, 0x04,
|
|
0x94, 0x14, 0xbb, 0x68, 0xc0, 0x8a, 0x56, 0xd3, 0x75, 0x7e, 0xa3, 0x3c, 0x21, 0x94, 0x70, 0x45,
|
|
0xa9, 0xa0, 0x9d, 0xe7, 0xbf, 0x00, 0xe4, 0xe5, 0x5a, 0x82, 0x6d, 0x22, 0x00, 0x00
|
|
/* AUTO-GENERATED (END) */
|
|
};
|
|
constexpr unsigned int MI32_STATIC_PAGE_len = sizeof(MI32_STATIC_PAGE);
|
|
|
|
|
|
#endif //USE_MI_EXT_GUI
|
|
#endif // USE_WEBSERVER
|
|
|
|
#endif //USE_MI_ESP32
|