ESP32 panic when calling a function from another function

I have a project which implement SQLite database on ESP32. It works as expected.

My sketch is at: BatteryNode/SQLite3_Proberequest.ino at master · happytm/BatteryNode · GitHub

My problem is following:

When I call processData() function from loop it works fine but when I call same function from another place (line 542) it panics and decoded message looks like following:

PC: 0x4008c01b
EXCVADDR: 0x00000000

Decoding stack results
0x4018a80f: esp_ipc_call_and_wait at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/ipc.c line 116
0x4018a8e6: esp_ipc_call at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/ipc.c line 123
0x400871ce: spi_flash_disable_interrupts_caches_and_other_cpu at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/spi_flash/cache_utils.c line 122
0x400876d1: spi_flash_read at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/spi_flash/flash_ops.c line 165
0x40191a17: esp_partition_read at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/spi_flash/partition.c line 242
0x4011d070: littlefs_api_read at C:\Users\WinCycle\Documents\Arduino\libraries\LittleFS_esp32\src\littlefs_api.c line 22
0x40119cf5: lfs_bd_read at C:\Users\WinCycle\Documents\Arduino\libraries\LittleFS_esp32\src\lfs.c line 104
0x4011a14f: lfs_dir_fetchmatch at C:\Users\WinCycle\Documents\Arduino\libraries\LittleFS_esp32\src\lfs.c line 861
0x4011a705: lfs_dir_find at C:\Users\WinCycle\Documents\Arduino\libraries\LittleFS_esp32\src\lfs.c line 1245
0x4011cbb1: lfs_stat at C:\Users\WinCycle\Documents\Arduino\libraries\LittleFS_esp32\src\lfs.c line 3189
0x40118f15: vfs_littlefs_fstat at C:\Users\WinCycle\Documents\Arduino\libraries\LittleFS_esp32\src\esp_littlefs.c line 1165
0x40187f71: esp_vfs_fstat at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/vfs/vfs.c line 479
0x40148be9: fstat at ../../../.././newlib/libc/syscalls/sysfstat.c line 12
0x40116f9f: ESP32FileSize(sqlite3_file*, sqlite_int64*) at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\esp32.cpp line 305
0x4019958f: sqlite3OsFileSize at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 22896
0x400d5add: pagerPagecount at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 54718
0x400f1ca1: sqlite3PagerSharedLock at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 56848
0x400f4723: sqlite3BtreeBeginTrans at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 67181
0x40108145: sqlite3InitOne at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 127174
0x4010e225: sqlite3Init at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 127359
0x4010e282: sqlite3ReadSchema at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 127385
0x4010f6f0: sqlite3LocateTable at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 109489
0x4010f87d: sqlite3LocateTableItem at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 109550
0x4011021a: sqlite3SrcListLookup at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 114722
0x40112c79: sqlite3Insert at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 119829
0x40105a75: sqlite3RunParser at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 156261
0x40107da5: sqlite3Prepare at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 127586
0x40107f32: sqlite3LockAndPrepare at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 127658
0x40107f75: sqlite3_prepare_v2 at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 127742
0x4010db3f: sqlite3_exec at C:\Users\WinCycle\Documents\Arduino\libraries\Sqlite3Esp32\src\sqlite3.c line 122065
0x400d20c4: db_exec(sqlite3*, char const*) at C:\Users\WinCycle\Documents\Arduino\sqlite3.ino/sqlite3.ino.ino line 167
0x400d2637: processData() at C:\Users\WinCycle\Documents\Arduino\sqlite3.ino/sqlite3.ino.ino line 371
0x400d2dc0: probeRequest(system_event_id_t, system_event_info_t) at C:\Users\WinCycle\Documents\Arduino\sqlite3.ino/sqlite3.ino.ino line 542
0x400d19c9: std::_Function_handler ::_M_invoke(std::_Any_data const&, system_event_id_t&&, system_event_info_t&&) at c:\users\wincycle\appdata\local\arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1871
0x400d461d: WiFiGenericClass::_eventCallback(void*, system_event_t*, wifi_prov_event_t*) at c:\users\wincycle\appdata\local\arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 2271
0x400d46f8: _network_event_task(void*) at C:\Users\WinCycle\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src\WiFiGeneric.cpp line 73
0x4008993e: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

I can not figure out what causes this panic.

Can you please help me resolve this issue?

Thanks.

it would be easier if you posted the code using </> rather than requiring downloading your git respository

Sorry for the linked code.

Here is the code:

// SQLite reference at https://www.w3schools.com/sql/exercise.asp
#define PROBEREQUESTS     true     // Receives data from remote ESP8266 devices on network
#define MQTT              true     // Communicate with MQTT clients
#define WEBSOCKETS        true     // Communicate with Websockets clients
#define ASYNCWEBSERVER    true     // Publishes web interface
#define SQLITE3           true     // Store data
#define FIRSTTIME         true    // Warning - This must be false.Make it true if creating new data and table files for first time.

#include <WiFi.h>
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h> // Thanks to https://github.com/siara-cc/esp32_arduino_sqlite3_lib
#include <SPI.h>
#include <FS.h>
#include <LITTLEFS.h>
#include "time.h"   // Arduino built in
String Timestamp, Date, Day, Time, Hour;
String dateReceived, dayReceived, timeReceived, hourReceived, rooms, V, S, T, H, P, L;
#define FORMAT_LITTLEFS_IF_FAILED true
int rc;
sqlite3 *db1;
sqlite3_stmt *res;
int rec_count = 0;
const char *tail;
   
const char* ssid = "";    // Your WiFi SSID
const char* password = ""; // Your WiFi Password
const char* apSSID = "ESP";        // SSID for access point. This must be same on all remote devices.
const char* apPassword = "";       // Password for Access point if required otherwise leave blank.
const int apChannel = 7;           // WiFi Channel number for access point. This must be same on all remote devices.
const int hidden = 0;              // If hidden is 1 probe request event handling does not work ?
int wsport = 8084;                 // Websocket server port
String deviceData;
String sensorData;
int device;

#if PROBEREQUESTS
// Channge following according to your remote sensor types for each device.
int Livingroom[4] = {16,26,36,46}; // temperature = 16, humidity= 26, pressure= 36, light= 46, OpenClose = 56, level = 66, presence = 76, motion = 86, rain = 96 etc.
int Kitchen[4] =    {46,36,26,16};
int Bedroom1[4] =   {46,36,26,16};
int Bedroom2[4] =   {16,26,36,36};
int Bedroom3[4] =   {16,26,36,36};
int Bedroom4[4] =   {16,26,36,36};
int Bathroom1[4] =  {16,26,36,36};
int Bathroom2[4] =  {16,26,36,36};
int Bathroom3[4] =  {16,26,36,36};
int Bathroom4[4] =  {16,26,36,36};
int Laundry[4] =    {16,26,36,36};
int Boiler[4] =     {16,26,36,36};
int Workshop[4] =   {16,26,36,36};
int Garage[4] =     {16,26,36,36};
int Office[4] =     {16,26,36,36};
int Tank[4] =       {16,26,36,36};
int Solar[4] =      {16,26,36,36};

//================= No user confiuration require below thi line =================================================


#include <esp_wifi.h>
char str [256];
char s [70];
float voltage;
int rssi;
uint8_t mac[6];
int sensorValues[4];
int sensorTypes[4];
int deviceStatus[4];
#endif

#if MQTT
#include <TinyMqtt.h>   // Thanks to https://github.com/hsaturn/TinyMqtt
#endif

#if WEBSOCKETS
#include <ArduinoWebsockets.h>  // Thanks to https://github.com/gilmaimon/ArduinoWebsockets
using namespace websockets;
WebsocketsServer WSserver;
String sql;
#endif

#if ASYNCWEBSERVER
#include <ESPAsyncWebServer.h>  // Install manually to arduino folder
int index_html_gz_len = 17960;
const uint8_t index_html_gz[] = {
0x1f,0x8b,0x08,0x08,0xa1,0xbf,0xb6,0x60,0x00,0xff,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x2e,0x67,0x7a,0x00,0xed,0x5b,0xeb,0x77,0xe2,0x36,0x94,0xff,0x4c,0xfe,0x0a,0xad,0xdb,0x5d,0xe0,0x0c,0xd8,0x3c,0x92,0x4c,0x86,0x40,0xce,0xce,0x73,0xdb,0xdd,0x4c,0x67,0xda,0xcc,0x6e,0x3f,0x4c,0xe7,0xf4,0x18,0x5b,0x80,0x27,0xc6,0xf2,0xda,0x72,0x12,0x76,0x9a,0xff,0xbd,0xbf,0x2b,0xc9,0xd8,0x80,0x4d,0x98,0xed,0xe3,0xf4,0x43,0x80,0xc3,0x43,0xd2,0xbd,0xba,0x6f,0x5d,0x49,0x97,0xf1,0x42,0x2e,0xc3,0x0b,0x76,0x34,0x5e,0x70,0xd7,0xa7,0xcf,0x25,0x97,0x2e,0xf3,0x16,0x6e,0x92,0x72,0x39,0xb1,0x32,0x39,0xeb,0x9e,0x59,0x17,0xa6,0x39,0x72,0x97,0x7c,0x62,0xdd,0x04,0xfc,0x36,0x16,0x89,0xb4,0x98,0x27,0x22,0xc9,0x23,0x0c,0xbb,0x0d,0x7c,0xb9,0x98,0xf8,0xfc,0x26,0xf0,0x78,0x57,0xfd,0xe8,0xb0,0x20,0x0a,0x64,0xe0,0x86,0xdd,0xd4,0x73,0x43,0x3e,0xe9,0x5b,0x84,0x5c,0x06,0x32,0xe4,0x17,0xef,0x13,0x31,0xe5,0x09,0xff,0xdf,0x8c,0xa7,0xb2,0xc3,0x2e,0x03,0x89,0xc6,0x57,0x2f,0x3a,0xec,0x43,0x10,0xad,0xde,0xfe,0xf8,0xe1,0x43,0x87,0xfd,0xcc,0xa7,0xa9,0xf0,0xae,0xb9,0x4c,0x3b,0xec,0x79,0xba,0x8a,0xbc,0x5b,0x34,0xf0,0xe4,0x86,0x27,0xec,0xdf,0x58,0xf6,0x3e,0x14,0x72,0xec,0x68,0x5c,0x40,0x9a,0x7a,0x49,0x10,0x4b,0x26,0x57,0x31,0x88,0x93,0xfc,0x4e,0x3a,0x9f,0xdd,0x1b,0x57,0xb7,0x5a,0x2c,0x4d,0xbc,0x89,0xb5,0x90,0x32,0x4e,0x47,0x8e,0xe3,0xf9,0xd1,0xe7,0xd4,0xf6,0x42,0x91,0xf9,0xb3,0xd0,0x4d,0xb8,0xed,0x89,0xa5,0xe3,0x7e,0x76,0xef,0x9c,0x30,0x98,0xa6,0xce,0x67,0x90,0x94,0xac,0x9c,0xbe,0xdd,0xef,0xdb,0x03,0xf3,0xcb,0x5e,0x06,0x91,0xfd,0x39,0xb5,0x2e,0xc6,0x8e,0x46,0x79,0x71,0x74,0x34,0x0e,0x83,0xe8,0x9a,0x25,0x3c,0x9c,0x58,0xa9,0x5c,0x85,0x3c,0x5d,0x70,0x8e,0xa9,0x16,0x09,0x9f,0x6d,0xcc,0x05,0x38,0x9f,0x87,0xc1,0x4d,0x62,0x47,0x5c,0x3a,0x51,0xbc,0x74,0xb2,0x18,0xb4,0xff,0x7b,0xdf,0x3e,0xb5,0x9f,0x3a,0x7e,0x90,0x4a,0x47,0x31,0xa3,0xe6,0xf0,0x52,0x4c,0x02,0xdc,0x0a,0x23,0xf8,0xfa,0x86,0xa4,0xeb,0x06,0x11,0x78,0xfe,0xc2,0x94,0x4c,0x47,0xac,0xdf,0xeb,0xfd,0xeb,0x39,0x5b,0xf0,0x60,0xbe,0x90,0x23,0x76,0xfc,0xec,0x66,0x71,0xce,0xa6,0xae,0x77,0x3d,0x4f,0x44,0x16,0xf9,0x5d,0x4f,0x84,0x22,0x19,0xb1,0x6f,0x86,0xc3,0xe1,0x39,0x03,0xfa,0x38,0x74,0x57,0x23,0x36,0x0b,0xf9,0xdd,0x39,0x73,0xc3,0x60,0x1e,0x75,0x03,0xc9,0x97,0xe9,0x88,0x79,0xd0,0x1a,0x4f,0xce,0xd9,0xe7,0x2c,0x95,0xc1,0x6c,0x05,0x40,0xa5,0xc8,0xa2,0x43,0x40,0xd4,0xb3,0x50,0xdc,0x8e,0xd8,0x22,0xf0,0x7d,0x1e,0x61,0x1a,0x91,0xf8,0x3c,0xe9,0x26,0xae,0x1f,0x64,0xc0,0xf0,0x34,0x06,0x4e,0x29,0x32,0x6f,0xd1,0x75,0x3d,0x19,0x88,0x68,0xc4,0x22,0x11,0xf1,0x73,0x76,0x0f,0xca,0x69,0x96,0x0d,0xa2,0x69,0x70,0x4e,0xb5,0xf9,0xb9,0x4b,0x76,0x32,0x9f,0xb6,0x06,0xc7,0x27,0x1d,0x36,0x18,0xf6,0x3a,0xec,0xd9,0xb3,0x76,0x3e,0x29,0xc1,0xc4,0x77,0x2c,0x15,0x61,0xe0,0xd3,0x28,0xb7,0xd5,0x1f,0x9e,0x76,0x58,0xf1,0x66,0x9f,0xac,0xc7,0xae,0x09,0x3c,0x21,0x49,0x55,0x11,0x98,0xc1,0x90,0xba,0x29,0x0f,0xb9,0x07,0x62,0x36,0x69,0x1e,0xd1,0xc8,0x1b,0x0e,0xd2,0x2b,0xa9,0xc3,0xbc,0xa7,0x67,0x20,0xaf,0x4f,0x6f,0x03,0xd0,0xd8,0xb7,0x7b,0x3d,0xcc,0xbc,0x06,0x5f,0x90,0xd8,0x00,0xed,0x65,0x49,0x4a,0x30,0xb1,0x08,0xb4,0x38,0x0d,0x6d,0x46,0x20,0x03,0x25,0x00,0x82,0x82,0x09,0xba,0x18,0x1f,0x8b,0x14,0xbe,0x42,0x24,0xce,0x82,0x3b,0xee,0x9f,0xb3,0x44,0x8b,0x6a,0x38,0xb4,0x87,0x43,0xc5,0x46,0x4c,0x0c,0x91,0xb6,0x09,0x2a,0x95,0x00,0x5b,0x2a,0xa5,0x29,0xfb,0xf8,0xb2,0x65,0x11,0xb1,0xeb,0xfb,0x41,0x34,0x1f,0xf5,0xce,0xd9,0xd2,0x4d,0xe6,0x41,0x54,0x7c,0xeb,0x4e,0x43,0xf8,0x55,0x37,0x95,0x6e,0x22,0x77,0x5a,0x79,0xe4,0x97,0xda,0x82,0x08,0x56,0xce,0x77,0x86,0x9a,0x66,0x35,0xb6,0x92,0x1a,0x16,0x2c,0xe7,0x5f,0xd6,0xd6,0xa7,0x30,0x13,0xf0,0x9d,0xe1,0x5e,0x9b,0x30,0x0c,0xbe,0x6b,0x88,0x36,0x56,0xbc,0xa1,0xbd,0x63,0x12,0x90,0x99,0x90,0x98,0x3f,0x83,0xfa,0x31,0x17,0x5c,0xd0,0x38,0x07,0xbe,0x9a,0x80,0x75,0x34,0x9e,0x0a,0x7f,0x85,0x08,0xf5,0x75,0x61,0xe0,0x60,0xd7,0x0c,0x82,0x19,0xaf,0x8c,0x01,0x8b,0xc1,0x9f,0x14,0xc8,0x80,0x08,0xe8,0x66,0x22,0x59,0x32,0x6d,0xa9,0x13,0x0b,0x81,0x80,0x81,0xdd,0xab,0xd7,0x97,0xaf,0x5f,0x7e,0x60,0x5e,0xe8,0xa6,0xe9,0xc4,0x42,0xac,0x9a,0x42,0xc0,0x16,0x83,0x17,0xa8,0x5f,0x4b,0x37,0xf2,0x2d,0x15,0x94,0xd9,0x84,0x59,0xae,0x02,0x62,0x6c,0x2c,0x62,0x42,0x02,0x5a,0xcd,0x97,0x8d,0x56,0x6d,0xf8,0x6c,0x96,0x88,0x25,0x93,0x20,0xfb,0x57,0x39,0x0d,0xd9,0xed,0x02,0x5c,0x54,0x8f,0x7f,0x15,0xcc,0x03,0xe9,0x86,0xec,0xe7,0x04,0x16,0x5e,0x3d,0xe4,0x79,0xe4,0x86,0x62,0xbe,0x6f,0x44,0x8e,0xe4,0x27,0xa8,0x6c,0x2f,0x8e,0xfa,0x01,0x3f,0x70,0x11,0xc3,0x37,0xc2,0xea,0xde,0x2b,0x2e,0xd9,0xf3,0xf7,0xec,0xe5,0xc2,0x8d,0xa2,0x7d,0x63,0xae,0x42,0xce,0x63,0xa8,0x67,0x59,0x43,0x28,0x8d,0x79,0x2b,0xfc,0x52,0xef,0xd8,0xd1,0x4a,0x20,0x15,0xed,0x53,0x87,0x5e,0xfb,0x0a,0x6d,0x4c,0x0f,0xd2,0xc6,0x65,0x70,0x03,0x47,0x4d,0x84,0x58,0x56,0xf7,0xff,0x57,0x20,0xbd,0x05,0x8f,0xaa,0x3b,0x5f,0x70,0x9f,0x20,0xfb,0x7b,0x7b,0x07,0x35,0xbd,0xae,0x5c,0xec,0x03,0x36,0xdd,0x35,0xd0,0x97,0x2e,0x02,0x63,0xb2,0xaa,0xee,0x7c,0x37,0x9b,0x41,0x12,0x9b,0x7d,0x07,0x8b,0xd1,0x58,0x75,0xbf,0x10,0xa4,0x67,0xb1,0x4d,0xfc,0xbd,0x5e,0xf5,0xbc,0xbd,0x1a,0x5e,0x7a,0x35,0x4c,0xf4,0x86,0x35,0xed,0xc7,0x35,0xed,0x27,0x35,0xed,0xa7,0xd5,0xed,0xfd,0x9a,0x79,0xfb,0x35,0xf3,0xf6,0x6b,0xe6,0xed,0xd7,0xcc,0xdb,0xaf,0x99,0x77,0x50,0xd3,0x3e,0xac,0x69,0x3f,0xae,0x69,0x3f,0xa9,0x69,0x3f,0xad,0x69,0x7f,0x5a,0xd3,0x7e,0x56,0xd3,0xfe,0xac,0x4e,0x6e,0xb5,0x02,0xad,0xe3,0xb8,0x5f,0xc7,0x32,0x92,0x83,0x3a,0x59,0xd7,0x75,0xd4,0x71,0xdd,0xaf,0x63,0xbb,0x5f,0xc7,0x77,0xbf,0x8e,0xf1,0x7e,0x1d,0xe7,0x83,0x3a,0xce,0x07,0xb5,0xba,0xae,0xe3,0x7c,0x50,0xc7,0xf9,0xa0,0x8e,0xf3,0xc1,0x36,0xe7,0x5f,0xeb,0xb3,0x83,0xc2,0x67,0xfd,0xad,0xe0,0xf7,0xe8,0xb2,0x8f,0x2e,0xfb,0xe8,0xb2,0x7f,0xad,0xcb,0x7e,0xa5,0xb7,0x0e,0x0b,0x6f,0xe5,0x8f,0xde,0xfa,0xe8,0xad,0x8f,0xde,0xfa,0x4f,0xf6,0xd6,0xe3,0xc2,0x5b,0x67,0x8f,0xf9,0xf0,0xa3,0xbb,0x3e,0xba,0xeb,0x3f,0xd5,0x5d,0xc3,0x6c,0x19,0x15,0xce,0x3a,0xdf,0x5a,0x5a,0x2f,0x85,0xe7,0xd2,0x97,0x9a,0x63,0x12,0xb7,0xf6,0x00,0xc5,0xad,0xd9,0x6c,0xd7,0x1f,0x65,0x7c,0x27,0xb2,0xe4,0xeb,0x19,0x10,0x31,0x4f,0x5c,0x29,0x92,0x82,0x85,0xc5,0x16,0x0b,0x93,0xea,0xe9,0x6a,0x0e,0x38,0xc6,0x35,0xcd,0x75,0x58,0x6a,0xda,0xc7,0x25,0xf4,0x05,0x2b,0xe3,0x69,0xa2,0x0e,0xcc,0xcd,0x91,0xdc,0x8d,0x9b,0x30,0x57,0x4a,0xd7,0x5b,0xbc,0xbe,0xc1,0x31,0x36,0x88,0x9f,0x65,0x91,0x3a,0x50,0x6b,0x45,0x38,0xd3,0xe9,0x30,0x4e,0xcd,0x1d,0x16,0xe2,0x70,0x8f,0xe3,0xa0,0xb2,0x43,0x47,0xc1,0x2f,0xdd,0x58,0x66,0x09,0x6f,0xb3,0x2f,0x98,0xd0,0x71,0xd8,0x5b,0x2e,0x17,0xc2,0x67,0x38,0x8d,0x63,0x6f,0xde,0x74,0xd8,0x3b,0x92,0x47,0x07,0x07,0x4b,0x38,0x2f,0x03,0x86,0x2b,0x77,0xe6,0x26,0x01,0x46,0x06,0x33,0xd6,0xc2,0xf9,0x76,0xe4,0x8b,0x5b,0x1b,0xa7,0xad,0x6a,0xc2,0x4b,0x83,0x97,0x69,0x64,0x0c,0x87,0xcb,0x3e,0xdf,0xe9,0x6d,0xed,0xa1,0x82,0xfd,0xf6,0x1b,0x9b,0xb9,0x61,0xca,0xdb,0xe7,0x40,0x70,0xaf,0x29,0xfa,0xfe,0x35,0x5b,0xb8,0x29,0x0b,0x64,0xca,0xc4,0x6d,0xc4,0x70,0x11,0x03,0x02,0xd1,0xc5,0x31,0x6e,0x63,0xa2,0x82,0xf5,0x56,0x53,0x44,0xcd,0x27,0x5b,0x13,0x19,0x9c,0xf7,0xe7,0x47,0x47,0xc0,0xfa,0x2e,0xf2,0x38,0x93,0x0b,0x6e,0x98,0x60,0xa1,0x70,0xfd,0x94,0x61,0xa9,0x51,0x8d,0xaf,0xde,0xbd,0x65,0x41,0x8a,0x1b,0x0e,0xd7,0x5f,0x75,0x8c,0x50,0x55,0x87,0xc2,0x89,0xf3,0x68,0xf5,0x63,0x89,0xf3,0x5e,0xe0,0x2c,0x4f,0xac,0xb1,0x75,0x98,0x45,0xf8,0xac,0x4e,0xa1,0x01,0x2d,0x13,0x52,0x91,0x3e,0x81,0xfc,0xd5,0xac,0x6c,0xd0,0x92,0x2f,0xbc,0x6c,0x09,0x60,0x7b,0xce,0xe5,0xeb,0x90,0xd3,0xd7,0x17,0xab,0xef,0xfd,0xd6,0xfa,0x88,0x13,0x94,0x6f,0xc0,0x7e,0x87,0xc6,0x10,0x72,0x2e,0x29,0x38,0x17,0x39,0x63,0xda,0x4c,0xfa,0xfb,0xf0,0x9a,0xb3,0xba,0x76,0xe7,0xa8,0x91,0x8f,0x1f,0x1c,0x40,0x47,0x9f,0x08,0x29,0x4f,0x32,0x3c,0x00,0x68,0xb0,0x0d,0x74,0x7c,0x00,0xd0,0x70,0x1b,0xe8,0xe4,0x00,0xa0,0xe3,0x6d,0xa0,0xd3,0xfd,0x40,0x2a,0x52,0x6d,0x81,0x3c,0xdd,0x07,0xb2,0x8e,0x0d,0xed,0xf3,0x06,0xd3,0x60,0x64,0x49,0x57,0x0b,0x98,0x0f,0x69,0x12,0x37,0x45,0xda,0xa4,0xdc,0x38,0x4e,0x44,0x9c,0x04,0x08,0x67,0x46,0x63,0xcd,0x54,0x8f,0x27,0xb7,0x91,0x8b,0x20,0xb5,0x6f,0xdc,0x30,0x43,0x78,0x41,0x7c,0xc9,0x0f,0x76,0x2d,0x32,0xfe,0xad,0xbe,0xf2,0xc9,0xb2,0xb5,0x56,0xb1,0xa1,0x38,0xd7,0xb4,0xad,0xee,0x04,0x6c,0x73,0xe1,0x40,0x21,0xcb,0xca,0x99,0xca,0x95,0xfb,0xf0,0x90,0xe1,0xc3,0x43,0x8e,0x1f,0x1e,0x72,0xf2,0xf0,0x90,0xd3,0xdd,0x21,0x74,0x07,0xb5,0x3d,0xec,0xe9,0x43,0xc3,0x8c,0x14,0xee,0x75,0x18,0xa8,0x90,0xeb,0xe6,0x91,0xb8,0x92,0xae,0x6a,0x2b,0x8e,0xc0,0x8b,0x36,0x3a,0xf2,0xd6,0xbf,0xca,0x27,0xf5,0xba,0xa5,0x74,0x32,0xbf,0x39,0x64,0x4b,0x2b,0x7f,0x9b,0x5e,0xaa,0xc4,0x55,0xa1,0x9b,0xaa,0x61,0x15,0xfa,0xa9,0x1a,0xf6,0xa7,0xe9,0x88,0x51,0x80,0xa9,0xb4,0xfa,0x5d,0x21,0xc2,0xa5,0xd4,0xe0,0x83,0xe4,0x77,0x98,0x08,0x0f,0xb3,0xee,0xc3,0x85,0x78,0xb8,0x1c,0x0f,0x17,0xe5,0x01,0xd2,0x6c,0x40,0x2e,0xf7,0xea,0x5d,0xbd,0x55,0x48,0xb3,0xfe,0x52,0xeb,0xcf,0x15,0x6d,0x0d,0xe9,0x0f,0x1a,0xe9,0xdf,0x2d,0xe2,0xc3,0xc4,0x4b,0xa2,0xa5,0x10,0x92,0x47,0x12,0x4a,0x0f,0xd4,0x4a,0x8b,0xa0,0xfe,0xdf,0x08,0x2a,0x14,0xca,0x45,0x84,0x52,0x90,0x68,0x8e,0x98,0x8e,0x00,0x2f,0xa2,0x6b,0xbe,0x8a,0x13,0x9e,0xa6,0x3a,0x0f,0x48,0x29,0x11,0xf0,0xb9,0x24,0xd9,0x43,0xda,0x91,0x82,0xd0,0xf0,0x5a,0x37,0x62,0xb6,0xbd,0xda,0x53,0x26,0xa3,0x31,0x52,0x0a,0x53,0xce,0x1c,0x36,0x07,0x22,0x83,0xd0,0xc3,0x90,0x43,0x6c,0x2c,0xfa,0x6a,0xc1,0xda,0x0b,0x97,0xd3,0x58,0x01,0x79,0x4f,0x99,0xc4,0xb7,0xad,0x7c,0x85,0x6b,0xdb,0x2a,0xc1,0x69,0x15,0x59,0x04,0xc5,0xb2,0x6f,0x5b,0x16,0xdd,0xc5,0x5a,0x6d,0x3b,0xcd,0xa6,0xcb,0x40,0x6e,0x75,0xe7,0x89,0x48,0x24,0x5f,0x3e,0x98,0xc1,0x34,0x41,0x47,0x16,0xca,0x66,0x5b,0xdb,0xaa,0xd6,0xca,0x6d,0x6a,0x03,0xda,0x07,0xe1,0x6b,0x14,0xa8,0x21,0x50,0xd1,0xd3,0x71,0x50,0x2a,0x93,0xc8,0x96,0x75,0xa5,0x66,0x96,0x5c,0xe5,0x3e,0xaa,0x03,0x31,0xb8,0xd5,0xbc,0x02,0x1c,0x5d,0xec,0xb3,0x26,0x7b,0x52,0x26,0x41,0xa7,0x76,0x87,0x31,0x68,0xd6,0xd0,0x6f,0x5b,0x4d,0x2a,0x7e,0xa1,0xd4,0x1f,0xe4,0xa1,0xab,0xa9,0xe5,0xdd,0x2c,0xe7,0x6c,0x18,0x7d,0x44,0xee,0x86,0xc1,0xa8,0x46,0x51,0x53,0x69,0x5e,0x90,0x6f,0xfd,0x55,0x6b,0x4c,0x1b,0x04,0x7e,0x21,0x69,0x90,0x98,0x63,0x77,0x45,0x89,0x24,0x44,0x5c,0x45,0xc2,0x13,0xd6,0x74,0x48,0x12,0xd4,0xa7,0x73,0xba,0xca,0xae,0x3c,0x7d,0xcb,0x3b,0xcf,0x95,0xa5,0x43,0x06,0x7b,0x79,0xdb,0x8a,0xd0,0x4a,0x6c,0x85,0xfe,0xff,0x12,0xc2,0xd0,0x6c,0x39,0xd6,0x66,0xe7,0x60,0x83,0x6a,0xf2,0xd6,0x7d,0x44,0xef,0x0b,0x84,0x5f,0xc9,0x81,0x85,0x67,0x4e,0x09,0xa5,0x8a,0xa5,0x2e,0x6a,0xcc,0x93,0xc1,0xad,0xe6,0x4d,0x6e,0xd7,0x34,0x37,0x8e,0x1a,0xd4,0x5b,0x76,0x87,0x96,0x21,0x60,0x3d,0x48,0x99,0x2f,0x95,0x78,0xac,0x2b,0x2c,0x68,0x7b,0x37,0x0e,0xa2,0x38,0x2b,0x57,0x75,0xd0,0x46,0x75,0x62,0x69,0x4c,0x28,0xeb,0x08,0xfe,0x4f,0xed,0x52,0x07,0x67,0x7a,0xc7,0x8a,0x82,0x2c,0xf8,0x88,0xa5,0xe3,0x0f,0xea,0x28,0x98,0xb3,0x85,0x42,0xfb,0xf4,0x7a,0x00,0x79,0x14,0x33,0x5e,0xa4,0xaa,0xaf,0x1c,0xf2,0x7d,0xfa,0x42,0x73,0xa9,0xf2,0x9c,0x44,0xdc,0x62,0x9b,0x8c,0x13,0x38,0xc8,0x01,0x5f,0x86,0x27,0x9a,0x02,0x13,0x48,0x4b,0x53,0xa5,0x31,0x0f,0x43,0x5c,0xd7,0x7b,0xd7,0x13,0x4b,0xed,0xe2,0x2c,0xa6,0x76,0x50,0x22,0x0a,0x57,0xa0,0x3d,0xc9,0xd0,0xa0,0x82,0x30,0xba,0x51,0x2c,0xd3,0x25,0xda,0x47,0xfd,0x53,0x94,0xba,0xa8,0x8a,0x9a,0x75,0x7d,0x14,0x5f,0x9e,0x53,0xc5,0x9d,0x93,0x53,0x40,0xd4,0xfc,0x4b,0xb7,0x3b,0x8e,0x2f,0x0c,0x27,0x34,0x3d,0x79,0xff,0x5b,0x44,0x39,0x17,0x21,0x72,0x43,0x3a,0x84,0x15,0xe4,0xf6,0xd6,0x84,0xf5,0x4e,0x1d,0xbc,0x08,0xe3,0x34,0x93,0x52,0x44,0x14,0xd3,0xc3,0x80,0x88,0x24,0x51,0x7d,0x00,0x50,0xab,0x6d,0xa1,0xf2,0xa1,0x10,0x04,0xc3,0xe6,0xf7,0xea,0xc7,0xcb,0xb1,0xa3,0x01,0xb0,0xf7,0x8e,0x01,0x9d,0x85,0x46,0xf2,0x1e,0x47,0x8d,0x94,0x9f,0x4f,0x7e,0x61,0x80,0x52,0x14,0xb4,0x98,0x36,0xda,0x38,0xea,0x41,0xda,0x12,0x4d,0xc1,0x0b,0xb6,0x05,0x1c,0x86,0x37,0xe5,0xa8,0x2b,0xa3,0xdb,0xc5,0x0c,0x75,0x87,0xac,0xdb,0x2d,0xb6,0xf0,0x9a,0x8f,0xe6,0x56,0xed,0x4e,0x13,0x03,0xc8,0xe6,0x2d,0xd4,0xd2,0x5c,0xa9,0x5a,0x1a,0x28,0x20,0x32,0xfb,0x56,0x5a,0xde,0xb1,0x09,0x21,0x83,0xbe,0x4d,0x61,0x08,0x11,0xbf,0xa5,0x9a,0x1b,0x3d,0x0e,0x30,0xb7,0x54,0xee,0xd3,0x7f,0x36,0xb0,0x51,0xb9,0x65,0xf7,0xec,0xe1,0xe8,0xac,0x77,0x46,0x1b,0x25,0x38,0xff,0x7e,0x18,0x32,0x7e,0xb3,0xbf,0x47,0x05,0x93,0x3a,0xb4,0xb1,0x17,0x22,0x95,0xea,0x58,0x04,0xde,0x51,0x42,0x84,0xe5,0xae,0x4b,0x0f,0x8a,0xc8,0xd8,0x3e,0x83,0x7a,0xe6,0xbb,0xa8,0x96,0x54,0x8d,0x47,0x79,0x34,0x55,0xbd,0x5a,0xda,0xa0,0x39,0x5f,0x43,0x8c,0xc4,0xf6,0xad,0x21,0xa5,0x61,0xc5,0x42,0x52,0xb7,0x20,0x98,0x81,0xf0,0xa5,0xf2,0x32,0x53,0xb4,0xde,0x1f,0x51,0x87,0x88,0x96,0xeb,0x79,0xd7,0xf4,0xe1,0x60,0x42,0xea,0x6c,0x5e,0xf9,0xa3,0x4a,0xb3,0xa0,0x0f,0x31,0xa3,0x0e,0x9b,0x38,0xa2,0x18,0x33,0x61,0x4d,0x14,0x7c,0x61,0xce,0x26,0x45,0xee,0xbc,0x07,0x0a,0x41,0x9d,0x18,0x8e,0x14,0xb0,0xe2,0x5f,0xa9,0x6e,0x60,0x52,0x79,0xc4,0x87,0x37,0xdd,0x33,0x3a,0x4d,0x59,0x62,0xcd,0x86,0x3d,0x68,0x58,0x25,0x9f,0xcd,0x9d,0xcc,0x5a,0x88,0xc6,0x74,0x76,0xe4,0x98,0x8f,0x36,0x9c,0xff,0x54,0x65,0x61,0x24,0x85,0x35,0xb1,0x45,0x0e,0x64,0x96,0x55,0xa8,0xf6,0x3f,0x04,0x8c,0x8c,0x10,0x97,0xa1,0x54,0xd1,0x1e,0xea,0xb2,0xb4,0x01,0x8c,0x54,0xdc,0xab,0xc0,0x62,0x1c,0xde,0xa4,0x9d,0x4f,0x26,0x3a,0x07,0xd2,0xec,0xc3,0x20,0x7e,0x89,0x54,0xaa,0xba,0x1e,0x4e,0x1a,0x5e,0xc7,0x90,0x3d,0xea,0x35,0x9a,0x48,0x9b,0x1b,0x04,0x2b,0xac,0x90,0xf5,0x47,0x73,0x8c,0xa3,0xa6,0xc1,0x6a,0x0e,0x0a,0x3c,0xde,0x72,0x9e,0x3b,0xf3,0x0e,0x6b,0x36,0xdb,0x4f,0x9a,0x2f,0x9a,0x30,0xc1,0x46,0x03,0x35,0x6d,0x22,0x42,0x81,0x24,0x87,0xb5,0xce,0x5b,0xff,0x79,0xf5,0xee,0x07,0x3b,0xa6,0x12,0xde,0x96,0x62,0x02,0x66,0x4a,0x1b,0x75,0xce,0x59,0x5e,0x01,0x07,0x6d,0x79,0xd7,0x79,0x91,0xa7,0xaa,0x82,0x55,0x45,0x6c,0xb0,0x83,0xd4,0x39,0x39,0x3e,0xe9,0xf7,0x4f,0x86,0x67,0x84,0x12,0x23,0x10,0xa8,0x94,0xd2,0x50,0xf9,0x27,0x45,0xd7,0x8d,0xba,0x6e,0x92,0xb8,0xab,0xae,0x98,0xe9,0x2f,0x29,0xda,0xbb,0x85,0xb7,0x92,0x08,0x1a,0x0d,0x43,0xfe,0x9b,0x3c,0x93,0x40,0x22,0x84,0xf3,0xad,0x88,0x7d,0x24,0x0d,0x15,0x56,0x83,0xc5,0xf0,0x53,0xb3,0xad,0xd6,0x89,0x46,0xa3,0xcc,0x80,0x11,0x7d,0xa3,0xa1,0xa4,0x48,0x85,0xbe,0x14,0xe4,0x5f,0x47,0x37,0x41,0x42,0xb6,0x8b,0x23,0x28,0x05,0x6f,0xb4,0x08,0xb8,0x04,0x5e,0x2c,0x6f,0x45,0x72,0xad,0x94,0x40,0xa8,0x24,0x25,0xbe,0xe4,0xde,0xeb,0xfd,0x29,0xd3,0x98,0x46,0xfa,0xa3,0x53,0x34,0x9b,0xb2,0xcc,0xe1,0x69,0xaf,0xd4,0x98,0x87,0xe3,0xd3,0xe3,0x8d,0x56,0x21,0xae,0x51,0x5c,0x4a,0x38,0xf5,0x96,0x42,0x25,0x58,0x23,0xf6,0x51,0x0d,0x69,0xb0,0x8c,0x4d,0x2e,0xd6,0x33,0x36,0x58,0x88,0x80,0x12,0xf2,0x39,0xc5,0x85,0x09,0xcb,0x6c,0x94,0x54,0x49,0x5b,0x55,0x15,0x5f,0xa9,0x85,0x5a,0x24,0x2d,0xcb,0xce,0xba,0x7a,0x44,0x71,0x16,0x53,0x6c,0xa5,0x99,0x81,0xde,0x3d,0x45,0xc4,0x01,0x0e,0x4a,0x4b,0xef,0x24,0x84,0x91,0x21,0xd3,0x85,0x7c,0x8a,0x79,0xf5,0x83,0xdb,0x48,0x83,0x09,0xe6,0x15,0x9f,0xb9,0x58,0x2c,0x21,0x66,0x93,0xfc,0xad,0x51,0x4b,0x72,0x81,0x80,0xa7,0xaf,0x43,0x90,0xc7,0x6d,0xd8,0x2a,0xac,0x93,0xca,0xa3,0x53,0xd8,0x82,0x22,0x4d,0xf7,0x97,0x49,0x2b,0x13,0xb7,0x81,0xe4,0x7b,0xff,0x0e,0x58,0x9e,0x93,0x4d,0x60,0x66,0x21,0x05,0x45,0x0f,0x3b,0xc5,0x52,0x83,0x32,0x6b,0x37,0x0c,0x5b,0x86,0x15,0x6f,0x11,0x84,0xfe,0x0f,0xc8,0x06,0xd3,0xb6,0x8d,0x00,0xcb,0xef,0xde,0xcd,0x10,0xa4,0x34,0x19,0x87,0xcc,0xa3,0x24,0xa9,0xbf,0x7e,0x5c,0xcf,0xfc,0xa9,0x16,0xb0,0x6c,0x56,0x7a,0xb8,0x1d,0xba,0x58,0x83,0x4a,0x53,0x51,0xea,0x61,0xbe,0xa9,0xcf,0x4f,0xa4,0xf0,0x7b,0x7a,0x53,0xb5,0xeb,0x46,0xdf,0x8c,0xdd,0xe5,0x5f,0xc8,0x92,0x96,0x64,0x48,0x58,0xd3,0xb5,0x71,0x10,0xa0,0x86,0x50,0x53,0xe4,0x06,0xf1,0x45,0xb5,0xe5,0x69,0x17,0xb8,0xa0,0x99,0x11,0x61,0xf2,0x7b,0x00,0x2b,0x37,0x2d,0xb8,0x98,0xb8,0x06,0x46,0x2b,0xce,0x92,0x38,0xc4,0xae,0xc7,0xb4,0xcf,0x82,0x90,0xc6,0xab,0xe2,0xe3,0x5e,0xa7,0xd7,0x19,0x9c,0x9c,0x74,0x7a,0xf6,0xa0,0x6d,0x06,0xd4,0xa0,0xff,0x9f,0x5d,0xbc,0xa8,0x9d,0xbe,0xf9,0xa3,0x68,0xaf,0x2a,0xd0,0x26,0x7a,0x93,0xf6,0x87,0xf0,0x7e,0xd8,0xc5,0x3b,0x45,0x8c,0xfd,0x83,0x58,0xbf,0xdb,0xc5,0x9a,0x60,0x43,0x55,0x85,0x54,0x21,0xa4,0xe7,0x83,0x48,0xdf,0xef,0x22,0x9d,0x27,0x9c,0x17,0x8a,0xfc,0xff,0xd1,0x7a,0xb9,0x8b,0x76,0x85,0x64,0x52,0xdc,0x7e,0x15,0xb9,0xb0,0x5b,0xda,0xc0,0x1f,0x91,0xaf,0x20,0x10,0xa9,0xc4,0x46,0xd5,0x18,0xb7,0x28,0x14,0x76,0x54,0xcc,0xc4,0x7b,0xbe,0x12,0x51,0xdd,0xb4,0x0a,0xb2,0x0d,0xa4,0x05,0x6a,0xbd,0xaf,0x5a,0xce,0x5f,0x84,0x62,0x6a,0x16,0x73,0x6c,0x16,0xdd,0x64,0xa5,0x17,0xef,0x22,0xeb,0xc9,0x17,0xec,0x52,0x2f,0xc3,0x2e,0x1f,0x85,0xdf,0xd3,0xfc,0x3e,0x21,0x22,0x2f,0xa4,0xa5,0x04,0xb7,0x18,0xc0,0x8d,0x53,0x03,0xb5,0x74,0xb0,0x69,0x36,0x9b,0x61,0xed,0xd5,0x0b,0xbc,0xca,0x89,0x96,0xab,0x37,0xd8,0x14,0xc8,0xe1,0x40,0xc5,0x11,0xe2,0x21,0x0b,0xc3,0x73,0xd3,0xa5,0xda,0x5e,0x68,0x98,0xcd,0x9e,0x37,0x41,0xc8,0x69,0xf7,0xa8,0x3b,0xc0,0x76,0xa9,0x81,0xe2,0x5e,0x79,0x04,0xb2,0x1f,0xb3,0xf1,0x29,0xa7,0x3e,0xb4,0x5b,0xde,0x0a,0xa0,0x6c,0x67,0x4a,0xbd,0x14,0x9b,0x30,0xa9,0xb7,0x20,0xe5,0xb8,0xa3,0x41,0xb6,0x19,0x20,0x6a,0xca,0x4d,0xad,0x0d,0xac,0x7a,0x69,0x1e,0x4f,0x18,0xae,0xeb,0xb4,0xec,0x70,0xef,0x12,0x21,0x41,0xa6,0x4d,0x1b,0xfd,0x89,0x46,0x9f,0xa8,0x2b,0x48,0x68,0x63,0x38,0x80,0x9c,0x91,0xbe,0x10,0x42,0x4a,0xa4,0xd4,0x3f,0x0c,0x20,0x8a,0x25,0xea,0xd0,0xd3,0x5c,0x84,0x45,0x52,0xa9,0x12,0x1e,0xca,0x67,0x36,0xe6,0xb4,0xa7,0x2b,0xc9,0x2f,0x79,0x34,0x97,0x0b,0xb5,0xd1,0xa3,0x9f,0xb8,0x5c,0x9a,0x6d,0xa8,0xb0,0x3e,0x43,0xfa,0x25,0xfa,0xc8,0xef,0xdc,0x25,0xc2,0x14,0xfe,0x97,0xf1,0x09,0x0b,0x2e,0x5d,0x96,0xb5,0x68,0xea,0x00,0x53,0xe2,0x9f,0x02,0x01,0x1b,0x6f,0xc9,0xc1,0x0e,0xd5,0x6c,0xe8,0x7a,0xf2,0xa4,0x5d,0xa2,0x10,0x59,0x94,0xde,0x67,0x6e,0x89,0xed,0x63,0x80,0x80,0xbe,0x4e,0xdb,0xd6,0xe3,0x37,0x96,0x07,0x13,0xeb,0x1d,0x07,0x09,0xad,0x5a,0xb2,0x48,0xd3,0x24,0x4c,0x3a,0x1c,0x24,0x29,0xaa,0x7d,0x6f,0x41,0x36,0xd9,0x60,0x84,0x45,0x97,0x14,0x8e,0x75,0x28,0x65,0x5d,0x92,0x2e,0x89,0x3d,0x0d,0x14,0x33,0x96,0x5a,0xb5,0xb0,0xcb,0x83,0x44,0x68,0xd3,0x07,0x9e,0xf5,0x52,0xa8,0x54,0x50,0x82,0xc6,0xb6,0x88,0x0c,0xd9,0x13,0x59,0xe8,0x63,0x3b,0xa3,0xba,0xf3,0x3d,0x0e,0xa6,0x85,0xe3,0x1e,0xd1,0x49,0xda,0x86,0xd1,0x51,0x9e,0xf0,0x3c,0x2d,0x9b,0x53,0x91,0x56,0x83,0x2b,0x75,0x2f,0x07,0x4f,0x6c,0xe8,0xf4,0x5c,0xf3,0x53,0xb6,0x50,0x72,0xc1,0x42,0x22,0xc5,0x5e,0xa8,0x4c,0x17,0x78,0x56,0x80,0xbe,0xad,0x36,0x26,0xc0,0x98,0xdf,0x0f,0x14,0x86,0xbd,0x83,0x00,0x97,0x7e,0x90,0x52,0x04,0x3b,0x49,0xb3,0x98,0xfe,0xd6,0x85,0x9c,0x7a,0xba,0x62,0x2b,0x12,0x8c,0x11,0x03,0xa1,0x5b,0x2f,0x90,0x1b,0x3b,0x74,0xc7,0xfc,0xf7,0xc2,0x51,0xff,0x22,0xfb,0x1d,0x1d,0xb1,0x71,0xc5,0x4c,0x36,0x00,0x00
};
AsyncWebServer webserver(80);
#endif

#if WEBSOCKETS
void handle_message(WebsocketsMessage msg) {
  Serial.print("Message Received from javascript websocket client: ");
  Serial.println(msg.data()); 
  sql = msg.data().c_str();
  Serial.println("======= Filtered data by SQL statement sent to client====================");
  Serial.println(sql.c_str());
  sqlite3_close(db1);
  Serial.println("=========================================================================");
} 
#endif

#if MQTT
std::string sentTopic = "data";
std::string receivedTopic = "command";
MqttBroker broker(1883);
MqttClient myClient(&broker);

void receivedMessage(const MqttClient* source, const Topic& topic, const char* payload, size_t length)
{
  Serial << endl << "Received message on topic " << receivedTopic.c_str() << " with payload " << payload << endl;
    if (receivedTopic == "command")
  {
    mac[0] = atoi(&payload[0]);
    mac[1] = atoi(&payload[3]);
    mac[2] = atoi(&payload[6]);
    mac[3] = atoi(&payload[9]);
    mac[4] = atoi(&payload[12]);
    mac[5] = atoi(&payload[15]);
   }
 }
#endif

const char* ntpServer = "pool.ntp.org";
unsigned long epoch; 

unsigned long getTime() {
  time_t now;
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    //Serial.println("Failed to obtain time");
    return(0);
  }
  time(&now);
  return now;
}

const char* data = "Data requested below:";
static int callback(void *data, int argc, char **argv, char **azColName) {
   int i;
   
   Serial.printf("%s: ", (const char*)data);
   Serial.println();
      
       for (i = 0; i<argc; i++){
       Serial.printf("%s\n", argv[i] ? argv[i] : "NULL");   
       }
     Serial.printf("\n");
     return 0;
}

int db_open(const char *filename, sqlite3 **db) {
   rc = sqlite3_open(filename, db);
   if (rc) {
       Serial.printf("Can't open database: %s\n", sqlite3_errmsg(*db));
       return rc;
   } else {
       Serial.printf("Opened database successfully\n");
   }
   return rc;
}

char *zErrMsg = 0;
int db_exec(sqlite3 *db, const char *sql) {
   Serial.println(sql);
   long start = micros();
   int rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
   if (rc != SQLITE_OK) {
       Serial.printf("SQL error: %s\n", zErrMsg);
       sqlite3_free(zErrMsg);
   } else {
       Serial.printf("Operation done successfully\n");
   }
   Serial.print(F("Time taken in milliseconds: "));
   Serial.println((micros()-start)/1000);
   return rc;
}

void setup() {

  Serial.begin(115200);
  
  delay(500);
  Serial << "Starting client and AP......." << endl;

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {   Serial << '-'; delay(500); }

  Serial << "Connected to " << ssid << " IP address: " << WiFi.localIP() << endl;

  WiFi.softAP(apSSID, apPassword, apChannel, hidden);
  esp_wifi_set_event_mask(WIFI_EVENT_MASK_NONE); // This line is must to activate probe request received event handler.
  Serial << "The AP mac address is " << WiFi.softAPmacAddress().c_str() << endl;
  Serial << "Access point started with SSID " << apSSID << " and webserver started at IP address: " << WiFi.localIP() << endl;
  Serial.print("Websocket Server at Port: ");
  Serial.println(wsport);
  Serial << "Connected to " << ssid << " IP address: " << WiFi.localIP() << endl;
  
  #if ASYNCWEBSERVER
    webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) 
    {
    AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html_gz, sizeof(index_html_gz));
    response->addHeader("Content-Encoding", "gzip");
    request->send(response);
    });
    
    webserver.begin();
#endif
    
#if WEBSOCKETS
    WSserver.listen(wsport);
#endif

#if MQTT
    broker.begin();

  // ============= Client Subscribe ================
    myClient.setCallback(receivedMessage);
    myClient.subscribe(receivedTopic);
    myClient.subscribe(sentTopic);
#endif

#if PROBEREQUESTS
    WiFi.onEvent(probeRequest, SYSTEM_EVENT_AP_PROBEREQRECVED);
    Serial << "Waiting for probe requests ... " << endl;
#endif

  configTime(0, 0, ntpServer);
  epoch = getTime();
  Serial.print("Epoch Time: ");
  Serial.println(epoch);
  
  delay(1000);
     
#if FIRSTTIME   
   if (!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)) {
       Serial.println("Failed to mount file system");
       return;
   }

   // list LITTLEFS contents
   File root = LITTLEFS.open("/");
   if (!root) {
       Serial.println("- failed to open directory");
       return;
   }
   if (!root.isDirectory()) {
       Serial.println(" - not a directory");
       return;
   }
   File file = root.openNextFile();
   while (file) {
       if (file.isDirectory()) {
           Serial.print("  DIR : ");
           Serial.println(file.name());
       } else {
           Serial.print("  FILE: ");
           Serial.print(file.name());
           Serial.print("\tSIZE: ");
           Serial.println(file.size());
       }
       file = root.openNextFile();
   }

   // remove existing file so we start clean for this test.
   LITTLEFS.remove("/test1.db");
   LITTLEFS.remove("/test1.db-journal");

   // Create the db file before trying to open it.
   if (!LITTLEFS.exists("/test1.db")){
      File file = LITTLEFS.open("/test1.db", FILE_WRITE);   //  /littlefs is automatically added to the front 
      file.close();
   }

   // We also need to create the journal file.
   if (!LITTLEFS.exists("/test1.db-journal")){
      File file = LITTLEFS.open("/test1.db-journal", FILE_WRITE);   //  /littlefs is automatically added to the front 
      file.close();
   }

   sqlite3_initialize();

   if (db_open("/littlefs/test1.db", &db1))
       return;

   rc = db_exec(db1, "CREATE TABLE test1 (id INTEGER, Date, Time, Hour, Location, Voltage, RSSI, Temperature, Humidity, Pressure, Light);");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
       }
       sqlite3_close(db1);       
#endif  
   
}

void loop() {

#if MQTT
  broker.loop();  // Don't forget to add loop for every broker and clients
  myClient.loop();
#endif
  
#if WEBSOCKETS
  auto client = WSserver.accept();
  client.onMessage(handle_message);
  processData();
  static auto next=millis();               // The next line is an efficient delay() replacement
  if (millis() > next){next += 10000;}       //let's give time to SQLITE3 to prepare data requested from client.
  
  while (client.available()) {
  client.poll();
  }
#endif  
} // End of loop

void processData()
{
   epoch = getTime();
   
   if (!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)) {
       Serial.println("Failed to mount file system");
       return;
   }

   //Create the db file if it does not exist before trying to open it.
   if (!LITTLEFS.exists("/test1.db")){
      File file = LITTLEFS.open("/test1.db", FILE_WRITE);   //  /littlefs is automatically added to the front 
      file.close();
   }

   // We also need to create the journal file if it does not exist.
   if (!LITTLEFS.exists("/test1.db-journal")){
      File file = LITTLEFS.open("/test1.db-journal", FILE_WRITE);   //  /littlefs is automatically added to the front 
      file.close();
   }

   sqlite3_initialize();

   if (db_open("/littlefs/test1.db", &db1))
       return;
   
   String insert = "insert into test1 values (";
  
               insert += epoch;
               insert += ", ";
               insert += 060321;
               insert += ", ";
               insert += 1535;
               insert += ", ";
               insert += 15;
               insert += ", ";
               insert += 26;
               insert += ", ";
               insert += 28;
               insert += ", ";
               insert += 30;
               insert += ", ";
               insert += 55;
               insert += ", ";
               insert += 65;
               insert += ", ";
               insert += 230;
               insert += ", ";
               insert += 83;
               insert += ")";
               Serial.println(insert);
              
   
   rc = db_exec(db1, insert.c_str());
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   
   /*
   rc = db_exec(db1, "Select * from test1 where  Location = '26' and id = '0601211530'");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   rc = db_exec(db1, "Select * from test1 where Location in ( '26', '27')");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   rc = db_exec(db1, "Select * from test1 where not Location = '27'");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   
   rc = db_exec(db1, "Select * from test1 where Location between '20' and '30'");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   */
   rc = db_exec(db1, "Select min(Temperature) from test1");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   rc = db_exec(db1, "Select max(Temperature) from test1");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   
   rc = db_exec(db1, "Select avg(Temperature) from test1");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   
   rc = db_exec(db1, sql.c_str());
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   sqlite3_close(db1);
   
   // list LITTLEFS contents
   File root = LITTLEFS.open("/");
   if (!root) {
       Serial.println("- failed to open directory");
       return;
   }
   if (!root.isDirectory()) {
       Serial.println(" - not a directory");
       return;
   }
   File file = root.openNextFile();
   while (file) {
       if (file.isDirectory()) {
           Serial.print("  DIR : ");
           Serial.println(file.name());
       } else {
           Serial.print("  FILE: ");
           Serial.print(file.name());
           Serial.print("\tSIZE: ");
           Serial.println(file.size());
       }
       file = root.openNextFile();
   }
 }

#if PROBEREQUESTS

void probeRequest(WiFiEvent_t event, WiFiEventInfo_t info) 
{
    Serial.print("Probe Received :  ");
    for (int i = 0; i < 6; i++) {
    Serial.printf("%02X", info.ap_probereqrecved.mac[i]);
    if (i < 5)Serial.print(":");
    }
    Serial.println();

      if (info.ap_probereqrecved.mac[0] == 6 || info.ap_probereqrecved.mac[0] == 16 || info.ap_probereqrecved.mac[0] == 26 || info.ap_probereqrecved.mac[0] == 36 || info.ap_probereqrecved.mac[0] == 46 || info.ap_probereqrecved.mac[0] == 56 || info.ap_probereqrecved.mac[0] == 66 || info.ap_probereqrecved.mac[0] == 76 || info.ap_probereqrecved.mac[0] == 86 || info.ap_probereqrecved.mac[0] == 96 || info.ap_probereqrecved.mac[0] == 106 || info.ap_probereqrecved.mac[0] == 116 || info.ap_probereqrecved.mac[0] == 126 || info.ap_probereqrecved.mac[0] == 136 || info.ap_probereqrecved.mac[0] == 146 || info.ap_probereqrecved.mac[0] == 156 || info.ap_probereqrecved.mac[0] == 166 || info.ap_probereqrecved.mac[0] == 176 || info.ap_probereqrecved.mac[0] == 186 || info.ap_probereqrecved.mac[0] == 196 || info.ap_probereqrecved.mac[0] == 206 || info.ap_probereqrecved.mac[0] == 216 || info.ap_probereqrecved.mac[0] == 226 || info.ap_probereqrecved.mac[0] == 236 || info.ap_probereqrecved.mac[0] == 246) // only accept data from certain devices.
       {

      //sendCommand();

      if (info.ap_probereqrecved.mac[1] == 06) 
      { // only accept data from device with voltage as a sensor type at byte 1.
               if (device == 06) { for (int i = 0; i < 4; i++) sensorTypes[i] = Livingroom[i];} 
               if (device == 16) { for (int i = 0; i < 4; i++) sensorTypes[i] = Kitchen[i];}
               if (device == 26) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom1[i];} 
               if (device == 36) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom2[i];}
               if (device == 46) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom3[i];} 
               if (device == 56) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom4[i];}
               if (device == 66) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom1[i];} 
               if (device == 76) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom2[i];}
               if (device == 86) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom3[i];} 
               if (device == 96) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom4[i];}
               if (device == 106) { for (int i = 0; i < 4; i++) sensorTypes[i] = Laundry[i];} 
               if (device == 116) { for (int i = 0; i < 4; i++) sensorTypes[i] = Boiler[i];}
               if (device == 126) { for (int i = 0; i < 4; i++) sensorTypes[i] = Workshop[i];} 
               if (device == 136) { for (int i = 0; i < 4; i++) sensorTypes[i] = Garage[i];}
               if (device == 146) { for (int i = 0; i < 4; i++) sensorTypes[i] = Office[i];}
               if (device == 156) { for (int i = 0; i < 4; i++) sensorTypes[i] = Tank[i];} 
               if (device == 166) { for (int i = 0; i < 4; i++) sensorTypes[i] = Solar[i];}
               deviceStatus[0] = info.ap_probereqrecved.mac[2];
               deviceStatus[1] = info.ap_probereqrecved.mac[3];
               deviceStatus[2] = info.ap_probereqrecved.mac[4];
               deviceStatus[3] = info.ap_probereqrecved.mac[5];
      } else {

      device = info.ap_probereqrecved.mac[0];
               
      voltage = info.ap_probereqrecved.mac[1];
      voltage = voltage * 2 / 100;
                  
      sensorValues[0] = info.ap_probereqrecved.mac[2];
      sensorValues[1] = info.ap_probereqrecved.mac[3];
      sensorValues[2] = info.ap_probereqrecved.mac[4];
      sensorValues[3] = info.ap_probereqrecved.mac[5];
              
      }

      if (voltage > 2.50 && voltage < 3.60) 
      {
      
      sprintf (str, "{");
      sprintf (s, "\"%s\":\"%i\"", "Location", device);    strcat (str, s);
      sprintf (s, ",\"%s\":\"%.2f\"", "Voltage", voltage);    strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[0], sensorValues[0]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[1], sensorValues[1]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[2], sensorValues[2]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[3], sensorValues[3]); strcat (str, s);
      sprintf (s, "}"); strcat (str, s);
              
      Serial.println();
      Serial.println("Following ## Sensor Values ## receiced from remote device  & published via MQTT: ");
      Serial.println(str);
      Serial.println();
     
      myClient.publish("sensor", str);
      
      if (voltage < 2.50) {      // if voltage of battery gets to low, print the warning below.
         //myClient.publish("Warning/Battery Low", location);
       }
     }

   if (info.ap_probereqrecved.mac[3] == apChannel) {
     
     sprintf (str, "{");
     sprintf (s, "\"%s\":\"%i\"", "Location", device);    strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "RSSI", info.ap_probereqrecved.rssi); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "MODE", deviceStatus[0]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "CHANNEL", deviceStatus[1]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "IP", deviceStatus[2]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "Sleeptime", deviceStatus[3]); strcat (str, s);
     sprintf (s, "}"); strcat (str, s);
                           
     Serial.println();
     Serial.println("Following ## Device Status ## receiced from remote device & published via MQTT: ");
     Serial.println(str);
     Serial.println();
     myClient.publish("device", str);
     //processData();
    }
  }
    
}
#endif 

Thanks.

Following is original error message from arduino serial console if that helps:

Guru Meditation Error: Core  1 panic'ed (Unhandled debug exception)
Debug exception reason: Stack canary watchpoint triggered (network_event) 
Core 1 register dump:
PC      : 0x4008c018  PS      : 0x00060236  A0      : 0x40086e14  A1      : 0x3ffb85d0  
A2      : 0x00000001  A3      : 0x3ffc8728  A4      : 0x3ffc8728  A5      : 0x00000001  
A6      : 0x00060220  A7      : 0x00000000  A8      : 0x80085428  A9      : 0x3ffb8670  
A10     : 0x3ff000e0  A11     : 0x00000001  A12     : 0x3ffbfbe8  A13     : 0x00000001  
A14     : 0x00060223  A15     : 0x00000000  SAR     : 0x00000008  EXCCAUSE: 0x00000001  
EXCVADDR: 0x00000000  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0x00000000  

ELF file SHA256: 0000000000000000

Backtrace: 0x4008c018:0x3ffb85d0 0x40086e11:0x3ffb86b0 0x4018a69b:0x3ffb86f0 0x4018a772:0x3ffb8710 0x400871ce:0x3ffb8730 0x400876d1:0x3ffb8750 0x401918a3:0x3ffb87c0 0x4011cefc:0x3ffb87f0 0x40119b81:0x3ffb8820 0x40119fdb:0x3ffb8850 0x4011a591:0x3ffb88f0 0x4011ca3d:0x3ffb8950 0x40118da1:0x3ffb89a0 0x40187dfd:0x3ffb8ad0 0x4000bcdd:0x3ffb8af0 0x40148a75:0x3ffb8b10 0x40116e63:0x3ffb8b30 0x4019941b:0x3ffb8b90 0x400d59c9:0x3ffb8bb0 0x400f1b8d:0x3ffb8be0 0x400f460f:0x3ffb8c30 0x40108031:0x3ffb8c80 0x4010e111:0x3ffb8d10 0x4010e16e:0x3ffb8d30 0x4010f5b4:0x3ffb8d50 0x4010f741:0x3ffb8d90 0x401100de:0x3ffb8db0 0x40112b3d:0x3ffb8dd0 0x40105961:0x3ffb8f30 0x40107c91:0x3ffb9110 0x40107e1e:0x3ffb9260 0x40107e61:0x3ffb92a0 0x4010da2b:0x3ffb92d0 0x400d2108:0x3ffb9320 0x400d264b:0x3ffb9340 0x400d2d60:0x3ffb93b0 0x400d19c5:0x3ffb93f0 0x400d4509:0x3ffb9440 0x400d45e4:0x3ffb9530 0x4008993e:0x3ffb9560

Thanks.

that other function is probeRequest(). is probeRequest() a callback function? do you know when probeRequest() is invoked?

yes it is callback function. It is triggered when some remote WiFi device try to send probe request to access point created by ESP32.

Thanks.

does processData() require initialization in setup() to complete for it to run properly in loop()? it may be getting called in probeRequest() before setup() completes.

So stack overflow seems to be the issue - stack canary must be a watchpoint on the end of the stack - canary means monitor (as in the old mining trick of detecting poison gas /low oxygen using a caged bird)

Running a database on a microcontroller is ambitious - even SQLite is heavyweight by microcontroller standards.

perhaps try configuring WiFi.onEvent() after the LITTLEFS stuff has been completed

My guess is that WiFi events are run as tasks with a limited stack available. Setting a flag in "probeRequest" (eg. bool mustProcessDataInLoop = true) and thereby defer the call to "processData" to the main "loop()" may be the sollution.

1 Like

@Danois90 I can try your solution if you give me hint how to implement it. Sorry I am learning to code.

Thanks.

By the way I tried Another database library called LittleDB with same exact code including Proberequest function and it works fine. Only problem was LittleDB library is too slow when I request data via select queries so I am now trying SQLite3 library for database. The working example with LittleDB library is below.

Thanks.

#define PROBEREQUESTS     true   // Receives data from remote ESP8266 devices on network
#define MQTT              true   // Communicate with MQTT clients
#define WEBSOCKETS        true   // Communicate with Websockets clients
#define ASYNCWEBSERVER    true   // Publishes web interface
#define LITTLEDB          true   // Store data
#define FIRSTTIME         true   // Warning - This must be false.Make it true if creating new data and table files for first time.

#include <WiFi.h>

const char* ssid = "";    // Your WiFi SSID
const char* password = ""; // Your WiFi Password
const char* apSSID = "ESP";        // SSID for access point. This must be same on all remote devices.
const char* apPassword = "";       // Password for Access point if required otherwise leave blank.
const int apChannel = 7;           // WiFi Channel number for access point. This must be same on all remote devices.
const int hidden = 0;              // If hidden is 1 probe request event handling does not work ?
int wsport = 8084;                 // Websocket server port
String deviceData;
String sensorData;
int device;

// Channge following according to your remote sensor types for each device.
int Livingroom[4] = {16,26,36,46};
int Kitchen[4] =    {46,36,26,16};
int Bedroom1[4] =   {46,36,26,16};
int Bedroom2[4] =   {16,26,36,36};
int Bedroom3[4] =   {16,26,36,36};
int Bedroom4[4] =   {16,26,36,36};
int Bathroom1[4] =  {16,26,36,36};
int Bathroom2[4] =  {16,26,36,36};
int Bathroom3[4] =  {16,26,36,36};
int Bathroom4[4] =  {16,26,36,36};
int Laundry[4] =    {16,26,36,36};
int Boiler[4] =     {16,26,36,36};
int Workshop[4] =   {16,26,36,36};
int Garage[4] =     {16,26,36,36};
int Office[4] =     {16,26,36,36};
int Tank[4] =       {16,26,36,36};
int Solar[4] =      {16,26,36,36};

//================= No user confiuration require below thi line =================================================

#if PROBEREQUESTS
#include <esp_wifi.h>
char str [256];
char s [70];
float voltage;
uint8_t mac[6];
int sensorValues[4];
int sensorTypes[4];
int deviceStatus[4];
#endif

#if MQTT
#include <TinyMqtt.h>   // Thanks to https://github.com/hsaturn/TinyMqtt
#endif

#if WEBSOCKETS
#include <ArduinoWebsockets.h>  // Thanks to https://github.com/gilmaimon/ArduinoWebsockets
using namespace websockets;
WebsocketsServer WSserver;
String sql;
#endif

#if LITTLEDB
#include <Arduino.h>  // Arduino built in
#include "FS.h"       // Arduino built in
#include <LITTLEFS.h> // Arduino built in
#include <LittleDB.h> // Thanks to https://github.com/pouriamoosavi/LittleDB
#include <ezTime.h>   // Arduino built in
String Timestamp, Date, Day, Time, Hour;
String epoch, dateReceived, dayReceived, timeReceived, hourReceived, rooms, Location,V, S, T, H, P, L;
int8_t res;
String tblPath = "/test_db/test_tbl";
String schemPath = "/test_db/s.test_tbl";
#endif

#if ASYNCWEBSERVER
#include <ESPAsyncWebServer.h>  // Install manually to arduino folder
int index_html_gz_len = 17960;
const uint8_t index_html_gz[] = {
0x1f,0x8b,0x08,0x08,0xa1,0xbf,0xb6,0x60,0x00,0xff,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x2e,0x67,0x7a,0x00,0xed,0x5b,0xeb,0x77,0xe2,0x36,0x94,0xff,0x4c,0xfe,0x0a,0xad,0xdb,0x5d,0xe0,0x0c,0xd8,0x3c,0x92,0x4c,0x86,0x40,0xce,0xce,0x73,0xdb,0xdd,0x4c,0x67,0xda,0xcc,0x6e,0x3f,0x4c,0xe7,0xf4,0x18,0x5b,0x80,0x27,0xc6,0xf2,0xda,0x72,0x12,0x76,0x9a,0xff,0xbd,0xbf,0x2b,0xc9,0xd8,0x80,0x4d,0x98,0xed,0xe3,0xf4,0x43,0x80,0xc3,0x43,0xd2,0xbd,0xba,0x6f,0x5d,0x49,0x97,0xf1,0x42,0x2e,0xc3,0x0b,0x76,0x34,0x5e,0x70,0xd7,0xa7,0xcf,0x25,0x97,0x2e,0xf3,0x16,0x6e,0x92,0x72,0x39,0xb1,0x32,0x39,0xeb,0x9e,0x59,0x17,0xa6,0x39,0x72,0x97,0x7c,0x62,0xdd,0x04,0xfc,0x36,0x16,0x89,0xb4,0x98,0x27,0x22,0xc9,0x23,0x0c,0xbb,0x0d,0x7c,0xb9,0x98,0xf8,0xfc,0x26,0xf0,0x78,0x57,0xfd,0xe8,0xb0,0x20,0x0a,0x64,0xe0,0x86,0xdd,0xd4,0x73,0x43,0x3e,0xe9,0x5b,0x84,0x5c,0x06,0x32,0xe4,0x17,0xef,0x13,0x31,0xe5,0x09,0xff,0xdf,0x8c,0xa7,0xb2,0xc3,0x2e,0x03,0x89,0xc6,0x57,0x2f,0x3a,0xec,0x43,0x10,0xad,0xde,0xfe,0xf8,0xe1,0x43,0x87,0xfd,0xcc,0xa7,0xa9,0xf0,0xae,0xb9,0x4c,0x3b,0xec,0x79,0xba,0x8a,0xbc,0x5b,0x34,0xf0,0xe4,0x86,0x27,0xec,0xdf,0x58,0xf6,0x3e,0x14,0x72,0xec,0x68,0x5c,0x40,0x9a,0x7a,0x49,0x10,0x4b,0x26,0x57,0x31,0x88,0x93,0xfc,0x4e,0x3a,0x9f,0xdd,0x1b,0x57,0xb7,0x5a,0x2c,0x4d,0xbc,0x89,0xb5,0x90,0x32,0x4e,0x47,0x8e,0xe3,0xf9,0xd1,0xe7,0xd4,0xf6,0x42,0x91,0xf9,0xb3,0xd0,0x4d,0xb8,0xed,0x89,0xa5,0xe3,0x7e,0x76,0xef,0x9c,0x30,0x98,0xa6,0xce,0x67,0x90,0x94,0xac,0x9c,0xbe,0xdd,0xef,0xdb,0x03,0xf3,0xcb,0x5e,0x06,0x91,0xfd,0x39,0xb5,0x2e,0xc6,0x8e,0x46,0x79,0x71,0x74,0x34,0x0e,0x83,0xe8,0x9a,0x25,0x3c,0x9c,0x58,0xa9,0x5c,0x85,0x3c,0x5d,0x70,0x8e,0xa9,0x16,0x09,0x9f,0x6d,0xcc,0x05,0x38,0x9f,0x87,0xc1,0x4d,0x62,0x47,0x5c,0x3a,0x51,0xbc,0x74,0xb2,0x18,0xb4,0xff,0x7b,0xdf,0x3e,0xb5,0x9f,0x3a,0x7e,0x90,0x4a,0x47,0x31,0xa3,0xe6,0xf0,0x52,0x4c,0x02,0xdc,0x0a,0x23,0xf8,0xfa,0x86,0xa4,0xeb,0x06,0x11,0x78,0xfe,0xc2,0x94,0x4c,0x47,0xac,0xdf,0xeb,0xfd,0xeb,0x39,0x5b,0xf0,0x60,0xbe,0x90,0x23,0x76,0xfc,0xec,0x66,0x71,0xce,0xa6,0xae,0x77,0x3d,0x4f,0x44,0x16,0xf9,0x5d,0x4f,0x84,0x22,0x19,0xb1,0x6f,0x86,0xc3,0xe1,0x39,0x03,0xfa,0x38,0x74,0x57,0x23,0x36,0x0b,0xf9,0xdd,0x39,0x73,0xc3,0x60,0x1e,0x75,0x03,0xc9,0x97,0xe9,0x88,0x79,0xd0,0x1a,0x4f,0xce,0xd9,0xe7,0x2c,0x95,0xc1,0x6c,0x05,0x40,0xa5,0xc8,0xa2,0x43,0x40,0xd4,0xb3,0x50,0xdc,0x8e,0xd8,0x22,0xf0,0x7d,0x1e,0x61,0x1a,0x91,0xf8,0x3c,0xe9,0x26,0xae,0x1f,0x64,0xc0,0xf0,0x34,0x06,0x4e,0x29,0x32,0x6f,0xd1,0x75,0x3d,0x19,0x88,0x68,0xc4,0x22,0x11,0xf1,0x73,0x76,0x0f,0xca,0x69,0x96,0x0d,0xa2,0x69,0x70,0x4e,0xb5,0xf9,0xb9,0x4b,0x76,0x32,0x9f,0xb6,0x06,0xc7,0x27,0x1d,0x36,0x18,0xf6,0x3a,0xec,0xd9,0xb3,0x76,0x3e,0x29,0xc1,0xc4,0x77,0x2c,0x15,0x61,0xe0,0xd3,0x28,0xb7,0xd5,0x1f,0x9e,0x76,0x58,0xf1,0x66,0x9f,0xac,0xc7,0xae,0x09,0x3c,0x21,0x49,0x55,0x11,0x98,0xc1,0x90,0xba,0x29,0x0f,0xb9,0x07,0x62,0x36,0x69,0x1e,0xd1,0xc8,0x1b,0x0e,0xd2,0x2b,0xa9,0xc3,0xbc,0xa7,0x67,0x20,0xaf,0x4f,0x6f,0x03,0xd0,0xd8,0xb7,0x7b,0x3d,0xcc,0xbc,0x06,0x5f,0x90,0xd8,0x00,0xed,0x65,0x49,0x4a,0x30,0xb1,0x08,0xb4,0x38,0x0d,0x6d,0x46,0x20,0x03,0x25,0x00,0x82,0x82,0x09,0xba,0x18,0x1f,0x8b,0x14,0xbe,0x42,0x24,0xce,0x82,0x3b,0xee,0x9f,0xb3,0x44,0x8b,0x6a,0x38,0xb4,0x87,0x43,0xc5,0x46,0x4c,0x0c,0x91,0xb6,0x09,0x2a,0x95,0x00,0x5b,0x2a,0xa5,0x29,0xfb,0xf8,0xb2,0x65,0x11,0xb1,0xeb,0xfb,0x41,0x34,0x1f,0xf5,0xce,0xd9,0xd2,0x4d,0xe6,0x41,0x54,0x7c,0xeb,0x4e,0x43,0xf8,0x55,0x37,0x95,0x6e,0x22,0x77,0x5a,0x79,0xe4,0x97,0xda,0x82,0x08,0x56,0xce,0x77,0x86,0x9a,0x66,0x35,0xb6,0x92,0x1a,0x16,0x2c,0xe7,0x5f,0xd6,0xd6,0xa7,0x30,0x13,0xf0,0x9d,0xe1,0x5e,0x9b,0x30,0x0c,0xbe,0x6b,0x88,0x36,0x56,0xbc,0xa1,0xbd,0x63,0x12,0x90,0x99,0x90,0x98,0x3f,0x83,0xfa,0x31,0x17,0x5c,0xd0,0x38,0x07,0xbe,0x9a,0x80,0x75,0x34,0x9e,0x0a,0x7f,0x85,0x08,0xf5,0x75,0x61,0xe0,0x60,0xd7,0x0c,0x82,0x19,0xaf,0x8c,0x01,0x8b,0xc1,0x9f,0x14,0xc8,0x80,0x08,0xe8,0x66,0x22,0x59,0x32,0x6d,0xa9,0x13,0x0b,0x81,0x80,0x81,0xdd,0xab,0xd7,0x97,0xaf,0x5f,0x7e,0x60,0x5e,0xe8,0xa6,0xe9,0xc4,0x42,0xac,0x9a,0x42,0xc0,0x16,0x83,0x17,0xa8,0x5f,0x4b,0x37,0xf2,0x2d,0x15,0x94,0xd9,0x84,0x59,0xae,0x02,0x62,0x6c,0x2c,0x62,0x42,0x02,0x5a,0xcd,0x97,0x8d,0x56,0x6d,0xf8,0x6c,0x96,0x88,0x25,0x93,0x20,0xfb,0x57,0x39,0x0d,0xd9,0xed,0x02,0x5c,0x54,0x8f,0x7f,0x15,0xcc,0x03,0xe9,0x86,0xec,0xe7,0x04,0x16,0x5e,0x3d,0xe4,0x79,0xe4,0x86,0x62,0xbe,0x6f,0x44,0x8e,0xe4,0x27,0xa8,0x6c,0x2f,0x8e,0xfa,0x01,0x3f,0x70,0x11,0xc3,0x37,0xc2,0xea,0xde,0x2b,0x2e,0xd9,0xf3,0xf7,0xec,0xe5,0xc2,0x8d,0xa2,0x7d,0x63,0xae,0x42,0xce,0x63,0xa8,0x67,0x59,0x43,0x28,0x8d,0x79,0x2b,0xfc,0x52,0xef,0xd8,0xd1,0x4a,0x20,0x15,0xed,0x53,0x87,0x5e,0xfb,0x0a,0x6d,0x4c,0x0f,0xd2,0xc6,0x65,0x70,0x03,0x47,0x4d,0x84,0x58,0x56,0xf7,0xff,0x57,0x20,0xbd,0x05,0x8f,0xaa,0x3b,0x5f,0x70,0x9f,0x20,0xfb,0x7b,0x7b,0x07,0x35,0xbd,0xae,0x5c,0xec,0x03,0x36,0xdd,0x35,0xd0,0x97,0x2e,0x02,0x63,0xb2,0xaa,0xee,0x7c,0x37,0x9b,0x41,0x12,0x9b,0x7d,0x07,0x8b,0xd1,0x58,0x75,0xbf,0x10,0xa4,0x67,0xb1,0x4d,0xfc,0xbd,0x5e,0xf5,0xbc,0xbd,0x1a,0x5e,0x7a,0x35,0x4c,0xf4,0x86,0x35,0xed,0xc7,0x35,0xed,0x27,0x35,0xed,0xa7,0xd5,0xed,0xfd,0x9a,0x79,0xfb,0x35,0xf3,0xf6,0x6b,0xe6,0xed,0xd7,0xcc,0xdb,0xaf,0x99,0x77,0x50,0xd3,0x3e,0xac,0x69,0x3f,0xae,0x69,0x3f,0xa9,0x69,0x3f,0xad,0x69,0x7f,0x5a,0xd3,0x7e,0x56,0xd3,0xfe,0xac,0x4e,0x6e,0xb5,0x02,0xad,0xe3,0xb8,0x5f,0xc7,0x32,0x92,0x83,0x3a,0x59,0xd7,0x75,0xd4,0x71,0xdd,0xaf,0x63,0xbb,0x5f,0xc7,0x77,0xbf,0x8e,0xf1,0x7e,0x1d,0xe7,0x83,0x3a,0xce,0x07,0xb5,0xba,0xae,0xe3,0x7c,0x50,0xc7,0xf9,0xa0,0x8e,0xf3,0xc1,0x36,0xe7,0x5f,0xeb,0xb3,0x83,0xc2,0x67,0xfd,0xad,0xe0,0xf7,0xe8,0xb2,0x8f,0x2e,0xfb,0xe8,0xb2,0x7f,0xad,0xcb,0x7e,0xa5,0xb7,0x0e,0x0b,0x6f,0xe5,0x8f,0xde,0xfa,0xe8,0xad,0x8f,0xde,0xfa,0x4f,0xf6,0xd6,0xe3,0xc2,0x5b,0x67,0x8f,0xf9,0xf0,0xa3,0xbb,0x3e,0xba,0xeb,0x3f,0xd5,0x5d,0xc3,0x6c,0x19,0x15,0xce,0x3a,0xdf,0x5a,0x5a,0x2f,0x85,0xe7,0xd2,0x97,0x9a,0x63,0x12,0xb7,0xf6,0x00,0xc5,0xad,0xd9,0x6c,0xd7,0x1f,0x65,0x7c,0x27,0xb2,0xe4,0xeb,0x19,0x10,0x31,0x4f,0x5c,0x29,0x92,0x82,0x85,0xc5,0x16,0x0b,0x93,0xea,0xe9,0x6a,0x0e,0x38,0xc6,0x35,0xcd,0x75,0x58,0x6a,0xda,0xc7,0x25,0xf4,0x05,0x2b,0xe3,0x69,0xa2,0x0e,0xcc,0xcd,0x91,0xdc,0x8d,0x9b,0x30,0x57,0x4a,0xd7,0x5b,0xbc,0xbe,0xc1,0x31,0x36,0x88,0x9f,0x65,0x91,0x3a,0x50,0x6b,0x45,0x38,0xd3,0xe9,0x30,0x4e,0xcd,0x1d,0x16,0xe2,0x70,0x8f,0xe3,0xa0,0xb2,0x43,0x47,0xc1,0x2f,0xdd,0x58,0x66,0x09,0x6f,0xb3,0x2f,0x98,0xd0,0x71,0xd8,0x5b,0x2e,0x17,0xc2,0x67,0x38,0x8d,0x63,0x6f,0xde,0x74,0xd8,0x3b,0x92,0x47,0x07,0x07,0x4b,0x38,0x2f,0x03,0x86,0x2b,0x77,0xe6,0x26,0x01,0x46,0x06,0x33,0xd6,0xc2,0xf9,0x76,0xe4,0x8b,0x5b,0x1b,0xa7,0xad,0x6a,0xc2,0x4b,0x83,0x97,0x69,0x64,0x0c,0x87,0xcb,0x3e,0xdf,0xe9,0x6d,0xed,0xa1,0x82,0xfd,0xf6,0x1b,0x9b,0xb9,0x61,0xca,0xdb,0xe7,0x40,0x70,0xaf,0x29,0xfa,0xfe,0x35,0x5b,0xb8,0x29,0x0b,0x64,0xca,0xc4,0x6d,0xc4,0x70,0x11,0x03,0x02,0xd1,0xc5,0x31,0x6e,0x63,0xa2,0x82,0xf5,0x56,0x53,0x44,0xcd,0x27,0x5b,0x13,0x19,0x9c,0xf7,0xe7,0x47,0x47,0xc0,0xfa,0x2e,0xf2,0x38,0x93,0x0b,0x6e,0x98,0x60,0xa1,0x70,0xfd,0x94,0x61,0xa9,0x51,0x8d,0xaf,0xde,0xbd,0x65,0x41,0x8a,0x1b,0x0e,0xd7,0x5f,0x75,0x8c,0x50,0x55,0x87,0xc2,0x89,0xf3,0x68,0xf5,0x63,0x89,0xf3,0x5e,0xe0,0x2c,0x4f,0xac,0xb1,0x75,0x98,0x45,0xf8,0xac,0x4e,0xa1,0x01,0x2d,0x13,0x52,0x91,0x3e,0x81,0xfc,0xd5,0xac,0x6c,0xd0,0x92,0x2f,0xbc,0x6c,0x09,0x60,0x7b,0xce,0xe5,0xeb,0x90,0xd3,0xd7,0x17,0xab,0xef,0xfd,0xd6,0xfa,0x88,0x13,0x94,0x6f,0xc0,0x7e,0x87,0xc6,0x10,0x72,0x2e,0x29,0x38,0x17,0x39,0x63,0xda,0x4c,0xfa,0xfb,0xf0,0x9a,0xb3,0xba,0x76,0xe7,0xa8,0x91,0x8f,0x1f,0x1c,0x40,0x47,0x9f,0x08,0x29,0x4f,0x32,0x3c,0x00,0x68,0xb0,0x0d,0x74,0x7c,0x00,0xd0,0x70,0x1b,0xe8,0xe4,0x00,0xa0,0xe3,0x6d,0xa0,0xd3,0xfd,0x40,0x2a,0x52,0x6d,0x81,0x3c,0xdd,0x07,0xb2,0x8e,0x0d,0xed,0xf3,0x06,0xd3,0x60,0x64,0x49,0x57,0x0b,0x98,0x0f,0x69,0x12,0x37,0x45,0xda,0xa4,0xdc,0x38,0x4e,0x44,0x9c,0x04,0x08,0x67,0x46,0x63,0xcd,0x54,0x8f,0x27,0xb7,0x91,0x8b,0x20,0xb5,0x6f,0xdc,0x30,0x43,0x78,0x41,0x7c,0xc9,0x0f,0x76,0x2d,0x32,0xfe,0xad,0xbe,0xf2,0xc9,0xb2,0xb5,0x56,0xb1,0xa1,0x38,0xd7,0xb4,0xad,0xee,0x04,0x6c,0x73,0xe1,0x40,0x21,0xcb,0xca,0x99,0xca,0x95,0xfb,0xf0,0x90,0xe1,0xc3,0x43,0x8e,0x1f,0x1e,0x72,0xf2,0xf0,0x90,0xd3,0xdd,0x21,0x74,0x07,0xb5,0x3d,0xec,0xe9,0x43,0xc3,0x8c,0x14,0xee,0x75,0x18,0xa8,0x90,0xeb,0xe6,0x91,0xb8,0x92,0xae,0x6a,0x2b,0x8e,0xc0,0x8b,0x36,0x3a,0xf2,0xd6,0xbf,0xca,0x27,0xf5,0xba,0xa5,0x74,0x32,0xbf,0x39,0x64,0x4b,0x2b,0x7f,0x9b,0x5e,0xaa,0xc4,0x55,0xa1,0x9b,0xaa,0x61,0x15,0xfa,0xa9,0x1a,0xf6,0xa7,0xe9,0x88,0x51,0x80,0xa9,0xb4,0xfa,0x5d,0x21,0xc2,0xa5,0xd4,0xe0,0x83,0xe4,0x77,0x98,0x08,0x0f,0xb3,0xee,0xc3,0x85,0x78,0xb8,0x1c,0x0f,0x17,0xe5,0x01,0xd2,0x6c,0x40,0x2e,0xf7,0xea,0x5d,0xbd,0x55,0x48,0xb3,0xfe,0x52,0xeb,0xcf,0x15,0x6d,0x0d,0xe9,0x0f,0x1a,0xe9,0xdf,0x2d,0xe2,0xc3,0xc4,0x4b,0xa2,0xa5,0x10,0x92,0x47,0x12,0x4a,0x0f,0xd4,0x4a,0x8b,0xa0,0xfe,0xdf,0x08,0x2a,0x14,0xca,0x45,0x84,0x52,0x90,0x68,0x8e,0x98,0x8e,0x00,0x2f,0xa2,0x6b,0xbe,0x8a,0x13,0x9e,0xa6,0x3a,0x0f,0x48,0x29,0x11,0xf0,0xb9,0x24,0xd9,0x43,0xda,0x91,0x82,0xd0,0xf0,0x5a,0x37,0x62,0xb6,0xbd,0xda,0x53,0x26,0xa3,0x31,0x52,0x0a,0x53,0xce,0x1c,0x36,0x07,0x22,0x83,0xd0,0xc3,0x90,0x43,0x6c,0x2c,0xfa,0x6a,0xc1,0xda,0x0b,0x97,0xd3,0x58,0x01,0x79,0x4f,0x99,0xc4,0xb7,0xad,0x7c,0x85,0x6b,0xdb,0x2a,0xc1,0x69,0x15,0x59,0x04,0xc5,0xb2,0x6f,0x5b,0x16,0xdd,0xc5,0x5a,0x6d,0x3b,0xcd,0xa6,0xcb,0x40,0x6e,0x75,0xe7,0x89,0x48,0x24,0x5f,0x3e,0x98,0xc1,0x34,0x41,0x47,0x16,0xca,0x66,0x5b,0xdb,0xaa,0xd6,0xca,0x6d,0x6a,0x03,0xda,0x07,0xe1,0x6b,0x14,0xa8,0x21,0x50,0xd1,0xd3,0x71,0x50,0x2a,0x93,0xc8,0x96,0x75,0xa5,0x66,0x96,0x5c,0xe5,0x3e,0xaa,0x03,0x31,0xb8,0xd5,0xbc,0x02,0x1c,0x5d,0xec,0xb3,0x26,0x7b,0x52,0x26,0x41,0xa7,0x76,0x87,0x31,0x68,0xd6,0xd0,0x6f,0x5b,0x4d,0x2a,0x7e,0xa1,0xd4,0x1f,0xe4,0xa1,0xab,0xa9,0xe5,0xdd,0x2c,0xe7,0x6c,0x18,0x7d,0x44,0xee,0x86,0xc1,0xa8,0x46,0x51,0x53,0x69,0x5e,0x90,0x6f,0xfd,0x55,0x6b,0x4c,0x1b,0x04,0x7e,0x21,0x69,0x90,0x98,0x63,0x77,0x45,0x89,0x24,0x44,0x5c,0x45,0xc2,0x13,0xd6,0x74,0x48,0x12,0xd4,0xa7,0x73,0xba,0xca,0xae,0x3c,0x7d,0xcb,0x3b,0xcf,0x95,0xa5,0x43,0x06,0x7b,0x79,0xdb,0x8a,0xd0,0x4a,0x6c,0x85,0xfe,0xff,0x12,0xc2,0xd0,0x6c,0x39,0xd6,0x66,0xe7,0x60,0x83,0x6a,0xf2,0xd6,0x7d,0x44,0xef,0x0b,0x84,0x5f,0xc9,0x81,0x85,0x67,0x4e,0x09,0xa5,0x8a,0xa5,0x2e,0x6a,0xcc,0x93,0xc1,0xad,0xe6,0x4d,0x6e,0xd7,0x34,0x37,0x8e,0x1a,0xd4,0x5b,0x76,0x87,0x96,0x21,0x60,0x3d,0x48,0x99,0x2f,0x95,0x78,0xac,0x2b,0x2c,0x68,0x7b,0x37,0x0e,0xa2,0x38,0x2b,0x57,0x75,0xd0,0x46,0x75,0x62,0x69,0x4c,0x28,0xeb,0x08,0xfe,0x4f,0xed,0x52,0x07,0x67,0x7a,0xc7,0x8a,0x82,0x2c,0xf8,0x88,0xa5,0xe3,0x0f,0xea,0x28,0x98,0xb3,0x85,0x42,0xfb,0xf4,0x7a,0x00,0x79,0x14,0x33,0x5e,0xa4,0xaa,0xaf,0x1c,0xf2,0x7d,0xfa,0x42,0x73,0xa9,0xf2,0x9c,0x44,0xdc,0x62,0x9b,0x8c,0x13,0x38,0xc8,0x01,0x5f,0x86,0x27,0x9a,0x02,0x13,0x48,0x4b,0x53,0xa5,0x31,0x0f,0x43,0x5c,0xd7,0x7b,0xd7,0x13,0x4b,0xed,0xe2,0x2c,0xa6,0x76,0x50,0x22,0x0a,0x57,0xa0,0x3d,0xc9,0xd0,0xa0,0x82,0x30,0xba,0x51,0x2c,0xd3,0x25,0xda,0x47,0xfd,0x53,0x94,0xba,0xa8,0x8a,0x9a,0x75,0x7d,0x14,0x5f,0x9e,0x53,0xc5,0x9d,0x93,0x53,0x40,0xd4,0xfc,0x4b,0xb7,0x3b,0x8e,0x2f,0x0c,0x27,0x34,0x3d,0x79,0xff,0x5b,0x44,0x39,0x17,0x21,0x72,0x43,0x3a,0x84,0x15,0xe4,0xf6,0xd6,0x84,0xf5,0x4e,0x1d,0xbc,0x08,0xe3,0x34,0x93,0x52,0x44,0x14,0xd3,0xc3,0x80,0x88,0x24,0x51,0x7d,0x00,0x50,0xab,0x6d,0xa1,0xf2,0xa1,0x10,0x04,0xc3,0xe6,0xf7,0xea,0xc7,0xcb,0xb1,0xa3,0x01,0xb0,0xf7,0x8e,0x01,0x9d,0x85,0x46,0xf2,0x1e,0x47,0x8d,0x94,0x9f,0x4f,0x7e,0x61,0x80,0x52,0x14,0xb4,0x98,0x36,0xda,0x38,0xea,0x41,0xda,0x12,0x4d,0xc1,0x0b,0xb6,0x05,0x1c,0x86,0x37,0xe5,0xa8,0x2b,0xa3,0xdb,0xc5,0x0c,0x75,0x87,0xac,0xdb,0x2d,0xb6,0xf0,0x9a,0x8f,0xe6,0x56,0xed,0x4e,0x13,0x03,0xc8,0xe6,0x2d,0xd4,0xd2,0x5c,0xa9,0x5a,0x1a,0x28,0x20,0x32,0xfb,0x56,0x5a,0xde,0xb1,0x09,0x21,0x83,0xbe,0x4d,0x61,0x08,0x11,0xbf,0xa5,0x9a,0x1b,0x3d,0x0e,0x30,0xb7,0x54,0xee,0xd3,0x7f,0x36,0xb0,0x51,0xb9,0x65,0xf7,0xec,0xe1,0xe8,0xac,0x77,0x46,0x1b,0x25,0x38,0xff,0x7e,0x18,0x32,0x7e,0xb3,0xbf,0x47,0x05,0x93,0x3a,0xb4,0xb1,0x17,0x22,0x95,0xea,0x58,0x04,0xde,0x51,0x42,0x84,0xe5,0xae,0x4b,0x0f,0x8a,0xc8,0xd8,0x3e,0x83,0x7a,0xe6,0xbb,0xa8,0x96,0x54,0x8d,0x47,0x79,0x34,0x55,0xbd,0x5a,0xda,0xa0,0x39,0x5f,0x43,0x8c,0xc4,0xf6,0xad,0x21,0xa5,0x61,0xc5,0x42,0x52,0xb7,0x20,0x98,0x81,0xf0,0xa5,0xf2,0x32,0x53,0xb4,0xde,0x1f,0x51,0x87,0x88,0x96,0xeb,0x79,0xd7,0xf4,0xe1,0x60,0x42,0xea,0x6c,0x5e,0xf9,0xa3,0x4a,0xb3,0xa0,0x0f,0x31,0xa3,0x0e,0x9b,0x38,0xa2,0x18,0x33,0x61,0x4d,0x14,0x7c,0x61,0xce,0x26,0x45,0xee,0xbc,0x07,0x0a,0x41,0x9d,0x18,0x8e,0x14,0xb0,0xe2,0x5f,0xa9,0x6e,0x60,0x52,0x79,0xc4,0x87,0x37,0xdd,0x33,0x3a,0x4d,0x59,0x62,0xcd,0x86,0x3d,0x68,0x58,0x25,0x9f,0xcd,0x9d,0xcc,0x5a,0x88,0xc6,0x74,0x76,0xe4,0x98,0x8f,0x36,0x9c,0xff,0x54,0x65,0x61,0x24,0x85,0x35,0xb1,0x45,0x0e,0x64,0x96,0x55,0xa8,0xf6,0x3f,0x04,0x8c,0x8c,0x10,0x97,0xa1,0x54,0xd1,0x1e,0xea,0xb2,0xb4,0x01,0x8c,0x54,0xdc,0xab,0xc0,0x62,0x1c,0xde,0xa4,0x9d,0x4f,0x26,0x3a,0x07,0xd2,0xec,0xc3,0x20,0x7e,0x89,0x54,0xaa,0xba,0x1e,0x4e,0x1a,0x5e,0xc7,0x90,0x3d,0xea,0x35,0x9a,0x48,0x9b,0x1b,0x04,0x2b,0xac,0x90,0xf5,0x47,0x73,0x8c,0xa3,0xa6,0xc1,0x6a,0x0e,0x0a,0x3c,0xde,0x72,0x9e,0x3b,0xf3,0x0e,0x6b,0x36,0xdb,0x4f,0x9a,0x2f,0x9a,0x30,0xc1,0x46,0x03,0x35,0x6d,0x22,0x42,0x81,0x24,0x87,0xb5,0xce,0x5b,0xff,0x79,0xf5,0xee,0x07,0x3b,0xa6,0x12,0xde,0x96,0x62,0x02,0x66,0x4a,0x1b,0x75,0xce,0x59,0x5e,0x01,0x07,0x6d,0x79,0xd7,0x79,0x91,0xa7,0xaa,0x82,0x55,0x45,0x6c,0xb0,0x83,0xd4,0x39,0x39,0x3e,0xe9,0xf7,0x4f,0x86,0x67,0x84,0x12,0x23,0x10,0xa8,0x94,0xd2,0x50,0xf9,0x27,0x45,0xd7,0x8d,0xba,0x6e,0x92,0xb8,0xab,0xae,0x98,0xe9,0x2f,0x29,0xda,0xbb,0x85,0xb7,0x92,0x08,0x1a,0x0d,0x43,0xfe,0x9b,0x3c,0x93,0x40,0x22,0x84,0xf3,0xad,0x88,0x7d,0x24,0x0d,0x15,0x56,0x83,0xc5,0xf0,0x53,0xb3,0xad,0xd6,0x89,0x46,0xa3,0xcc,0x80,0x11,0x7d,0xa3,0xa1,0xa4,0x48,0x85,0xbe,0x14,0xe4,0x5f,0x47,0x37,0x41,0x42,0xb6,0x8b,0x23,0x28,0x05,0x6f,0xb4,0x08,0xb8,0x04,0x5e,0x2c,0x6f,0x45,0x72,0xad,0x94,0x40,0xa8,0x24,0x25,0xbe,0xe4,0xde,0xeb,0xfd,0x29,0xd3,0x98,0x46,0xfa,0xa3,0x53,0x34,0x9b,0xb2,0xcc,0xe1,0x69,0xaf,0xd4,0x98,0x87,0xe3,0xd3,0xe3,0x8d,0x56,0x21,0xae,0x51,0x5c,0x4a,0x38,0xf5,0x96,0x42,0x25,0x58,0x23,0xf6,0x51,0x0d,0x69,0xb0,0x8c,0x4d,0x2e,0xd6,0x33,0x36,0x58,0x88,0x80,0x12,0xf2,0x39,0xc5,0x85,0x09,0xcb,0x6c,0x94,0x54,0x49,0x5b,0x55,0x15,0x5f,0xa9,0x85,0x5a,0x24,0x2d,0xcb,0xce,0xba,0x7a,0x44,0x71,0x16,0x53,0x6c,0xa5,0x99,0x81,0xde,0x3d,0x45,0xc4,0x01,0x0e,0x4a,0x4b,0xef,0x24,0x84,0x91,0x21,0xd3,0x85,0x7c,0x8a,0x79,0xf5,0x83,0xdb,0x48,0x83,0x09,0xe6,0x15,0x9f,0xb9,0x58,0x2c,0x21,0x66,0x93,0xfc,0xad,0x51,0x4b,0x72,0x81,0x80,0xa7,0xaf,0x43,0x90,0xc7,0x6d,0xd8,0x2a,0xac,0x93,0xca,0xa3,0x53,0xd8,0x82,0x22,0x4d,0xf7,0x97,0x49,0x2b,0x13,0xb7,0x81,0xe4,0x7b,0xff,0x0e,0x58,0x9e,0x93,0x4d,0x60,0x66,0x21,0x05,0x45,0x0f,0x3b,0xc5,0x52,0x83,0x32,0x6b,0x37,0x0c,0x5b,0x86,0x15,0x6f,0x11,0x84,0xfe,0x0f,0xc8,0x06,0xd3,0xb6,0x8d,0x00,0xcb,0xef,0xde,0xcd,0x10,0xa4,0x34,0x19,0x87,0xcc,0xa3,0x24,0xa9,0xbf,0x7e,0x5c,0xcf,0xfc,0xa9,0x16,0xb0,0x6c,0x56,0x7a,0xb8,0x1d,0xba,0x58,0x83,0x4a,0x53,0x51,0xea,0x61,0xbe,0xa9,0xcf,0x4f,0xa4,0xf0,0x7b,0x7a,0x53,0xb5,0xeb,0x46,0xdf,0x8c,0xdd,0xe5,0x5f,0xc8,0x92,0x96,0x64,0x48,0x58,0xd3,0xb5,0x71,0x10,0xa0,0x86,0x50,0x53,0xe4,0x06,0xf1,0x45,0xb5,0xe5,0x69,0x17,0xb8,0xa0,0x99,0x11,0x61,0xf2,0x7b,0x00,0x2b,0x37,0x2d,0xb8,0x98,0xb8,0x06,0x46,0x2b,0xce,0x92,0x38,0xc4,0xae,0xc7,0xb4,0xcf,0x82,0x90,0xc6,0xab,0xe2,0xe3,0x5e,0xa7,0xd7,0x19,0x9c,0x9c,0x74,0x7a,0xf6,0xa0,0x6d,0x06,0xd4,0xa0,0xff,0x9f,0x5d,0xbc,0xa8,0x9d,0xbe,0xf9,0xa3,0x68,0xaf,0x2a,0xd0,0x26,0x7a,0x93,0xf6,0x87,0xf0,0x7e,0xd8,0xc5,0x3b,0x45,0x8c,0xfd,0x83,0x58,0xbf,0xdb,0xc5,0x9a,0x60,0x43,0x55,0x85,0x54,0x21,0xa4,0xe7,0x83,0x48,0xdf,0xef,0x22,0x9d,0x27,0x9c,0x17,0x8a,0xfc,0xff,0xd1,0x7a,0xb9,0x8b,0x76,0x85,0x64,0x52,0xdc,0x7e,0x15,0xb9,0xb0,0x5b,0xda,0xc0,0x1f,0x91,0xaf,0x20,0x10,0xa9,0xc4,0x46,0xd5,0x18,0xb7,0x28,0x14,0x76,0x54,0xcc,0xc4,0x7b,0xbe,0x12,0x51,0xdd,0xb4,0x0a,0xb2,0x0d,0xa4,0x05,0x6a,0xbd,0xaf,0x5a,0xce,0x5f,0x84,0x62,0x6a,0x16,0x73,0x6c,0x16,0xdd,0x64,0xa5,0x17,0xef,0x22,0xeb,0xc9,0x17,0xec,0x52,0x2f,0xc3,0x2e,0x1f,0x85,0xdf,0xd3,0xfc,0x3e,0x21,0x22,0x2f,0xa4,0xa5,0x04,0xb7,0x18,0xc0,0x8d,0x53,0x03,0xb5,0x74,0xb0,0x69,0x36,0x9b,0x61,0xed,0xd5,0x0b,0xbc,0xca,0x89,0x96,0xab,0x37,0xd8,0x14,0xc8,0xe1,0x40,0xc5,0x11,0xe2,0x21,0x0b,0xc3,0x73,0xd3,0xa5,0xda,0x5e,0x68,0x98,0xcd,0x9e,0x37,0x41,0xc8,0x69,0xf7,0xa8,0x3b,0xc0,0x76,0xa9,0x81,0xe2,0x5e,0x79,0x04,0xb2,0x1f,0xb3,0xf1,0x29,0xa7,0x3e,0xb4,0x5b,0xde,0x0a,0xa0,0x6c,0x67,0x4a,0xbd,0x14,0x9b,0x30,0xa9,0xb7,0x20,0xe5,0xb8,0xa3,0x41,0xb6,0x19,0x20,0x6a,0xca,0x4d,0xad,0x0d,0xac,0x7a,0x69,0x1e,0x4f,0x18,0xae,0xeb,0xb4,0xec,0x70,0xef,0x12,0x21,0x41,0xa6,0x4d,0x1b,0xfd,0x89,0x46,0x9f,0xa8,0x2b,0x48,0x68,0x63,0x38,0x80,0x9c,0x91,0xbe,0x10,0x42,0x4a,0xa4,0xd4,0x3f,0x0c,0x20,0x8a,0x25,0xea,0xd0,0xd3,0x5c,0x84,0x45,0x52,0xa9,0x12,0x1e,0xca,0x67,0x36,0xe6,0xb4,0xa7,0x2b,0xc9,0x2f,0x79,0x34,0x97,0x0b,0xb5,0xd1,0xa3,0x9f,0xb8,0x5c,0x9a,0x6d,0xa8,0xb0,0x3e,0x43,0xfa,0x25,0xfa,0xc8,0xef,0xdc,0x25,0xc2,0x14,0xfe,0x97,0xf1,0x09,0x0b,0x2e,0x5d,0x96,0xb5,0x68,0xea,0x00,0x53,0xe2,0x9f,0x02,0x01,0x1b,0x6f,0xc9,0xc1,0x0e,0xd5,0x6c,0xe8,0x7a,0xf2,0xa4,0x5d,0xa2,0x10,0x59,0x94,0xde,0x67,0x6e,0x89,0xed,0x63,0x80,0x80,0xbe,0x4e,0xdb,0xd6,0xe3,0x37,0x96,0x07,0x13,0xeb,0x1d,0x07,0x09,0xad,0x5a,0xb2,0x48,0xd3,0x24,0x4c,0x3a,0x1c,0x24,0x29,0xaa,0x7d,0x6f,0x41,0x36,0xd9,0x60,0x84,0x45,0x97,0x14,0x8e,0x75,0x28,0x65,0x5d,0x92,0x2e,0x89,0x3d,0x0d,0x14,0x33,0x96,0x5a,0xb5,0xb0,0xcb,0x83,0x44,0x68,0xd3,0x07,0x9e,0xf5,0x52,0xa8,0x54,0x50,0x82,0xc6,0xb6,0x88,0x0c,0xd9,0x13,0x59,0xe8,0x63,0x3b,0xa3,0xba,0xf3,0x3d,0x0e,0xa6,0x85,0xe3,0x1e,0xd1,0x49,0xda,0x86,0xd1,0x51,0x9e,0xf0,0x3c,0x2d,0x9b,0x53,0x91,0x56,0x83,0x2b,0x75,0x2f,0x07,0x4f,0x6c,0xe8,0xf4,0x5c,0xf3,0x53,0xb6,0x50,0x72,0xc1,0x42,0x22,0xc5,0x5e,0xa8,0x4c,0x17,0x78,0x56,0x80,0xbe,0xad,0x36,0x26,0xc0,0x98,0xdf,0x0f,0x14,0x86,0xbd,0x83,0x00,0x97,0x7e,0x90,0x52,0x04,0x3b,0x49,0xb3,0x98,0xfe,0xd6,0x85,0x9c,0x7a,0xba,0x62,0x2b,0x12,0x8c,0x11,0x03,0xa1,0x5b,0x2f,0x90,0x1b,0x3b,0x74,0xc7,0xfc,0xf7,0xc2,0x51,0xff,0x22,0xfb,0x1d,0x1d,0xb1,0x71,0xc5,0x4c,0x36,0x00,0x00
};
AsyncWebServer webserver(80);
#endif

#if WEBSOCKETS
void handle_message(WebsocketsMessage msg) {
  Serial.print("Message Received from javascript websocket client: ");
  Serial.println(msg.data());
  sql = msg.data();
 } 
#endif

#if MQTT
std::string sentTopic = "data";
std::string receivedTopic = "command";
MqttBroker broker(1883);
MqttClient myClient(&broker);
void receivedMessage(const MqttClient* source, const Topic& topic, const char* payload, size_t length)
{
  Serial << endl << "Received message on topic " << receivedTopic.c_str() << " with payload " << payload << endl;
    if (receivedTopic == "command")
  {
    mac[0] = atoi(&payload[0]);
    mac[1] = atoi(&payload[3]);
    mac[2] = atoi(&payload[6]);
    mac[3] = atoi(&payload[9]);
    mac[4] = atoi(&payload[12]);
    mac[5] = atoi(&payload[15]);
   }
 }
#endif

void sendCommand()  {

  esp_wifi_set_mac(ESP_IF_WIFI_AP, mac);
  Serial << "Command sent to remote device :  " << mac[0] << "/" << mac[1] << "/" << mac[2] << "/" << mac[3] << "/" << mac[4] << "/" << mac[5] << "/" << endl;
 }

void setup()
{
  Serial.begin(115200);
  
  delay(500);
  Serial << "Starting client and AP......." << endl;

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {   Serial << '-'; delay(500); }

  Serial << "Connected to " << ssid << " IP address: " << WiFi.localIP() << endl;

  WiFi.softAP(apSSID, apPassword, apChannel, hidden);
  esp_wifi_set_event_mask(WIFI_EVENT_MASK_NONE); // This line is must to activate probe request received event handler.
  Serial << "The AP mac address is " << WiFi.softAPmacAddress().c_str() << endl;
  Serial << "Access point started with SSID " << apSSID << " and webserver started at IP address: " << WiFi.localIP() << endl;
  Serial.print("Websocket Server at Port: ");
  Serial.println(wsport);
  
#if ASYNCWEBSERVER
    webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) 
    {
    AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html_gz, sizeof(index_html_gz));
    response->addHeader("Content-Encoding", "gzip");
    request->send(response);
    });
    
    webserver.begin();
#endif
    
#if WEBSOCKETS
    WSserver.listen(wsport);
#endif

#if MQTT
    broker.begin();

  // ============= Client Subscribe ================
    myClient.setCallback(receivedMessage);
    myClient.subscribe(receivedTopic);
    myClient.subscribe(sentTopic);
#endif

#if PROBEREQUESTS
    WiFi.onEvent(probeRequest, SYSTEM_EVENT_AP_PROBEREQRECVED);
    Serial << "Waiting for probe requests ... " << endl;
#endif

#if LITTLEDB
  waitForSync();
  Serial.println("UTC: " + UTC.dateTime());
  
  Timezone America;
  America.setLocation("America/New_York");
  //America.setPosix("EST--5EDT,M3.2.0,M11.1.0/2");
  Serial.println("EST time: " + America.dateTime());
  Serial.println("Time now is:" + America.dateTime("l ~t~h~e jS ~o~f F Y, g:i A") );
                                          //Saturday the 25th of August 2018, 2:23 PM
  
  //Serial.println(String((now()))); // + buffer); //for milliseconds precision                                      
  Timestamp = String((now())); // + buffer;     //for milliseconds precision
  //Serial.println(" " + America.dateTime("mdy") );                                       
  Date = " " + America.dateTime("mdy");
  Day  = " " + America.dateTime("l");
  //Serial.println(" " + America.dateTime("Hi") );                                       
  Time = " " + America.dateTime("Hi");
  Hour = " " + America.dateTime("H");
  
  delay(1000);
  LITTLEFS.begin(true);
  //LITTLEFS.format();

#if FIRSTTIME   
  res = execQuery("drop table test_tbl"); // For first time only
  res = execQuery("drop db test_db");     // For first time only
  res = execQuery("create db test_db");   // For first time only
#endif
   
  res = execQuery("use db test_db");

#if FIRSTTIME  
  String schem = "Timestamp id, Date text, Day text, Time text, Hour text, Location text, Voltage text, RSSI text, Temperature text, Humidity text, Pressure text, Light text"; // For first time only
  schem.trim(); // For first time only
  res = execQuery("create table test_tbl (" + schem + ")"); // For first time only
#endif   

#endif
}  // End of Setup


void loop()
{
#if MQTT
  broker.loop();  // Don't forget to add loop for every broker and clients
  myClient.loop();
#endif
  
#if WEBSOCKETS
  auto client = WSserver.accept();
  client.onMessage(handle_message);
  
  if (sql.startsWith("select")){
    Serial.println("======= Filtered data by SQL statement ====================");
    res = execQuery(sql);
    getData();
    static auto next=millis();               // The next line is an efficient delay() replacement
    if (millis() > next){next += 300;}       //let's give time to LittleDB to prepare data requested from client.

    //delay(300); //let's give time to LittleDB to prepare data requested from client.
    }
  if (sql.startsWith("remote")) {
    Serial.println("received command for remote device");
    } 
  if (sql.startsWith("gateway")) {
    Serial.println("received command for gateway");
    } 
   if(sql.endsWith("."))
  {
   Serial.println("The string ended with '.'");
  }
  
  Serial.println(sql);

   
  //client.send("Device Data: " + deviceData);
  //client.send("Sensor Data: " + sensorData);
  
  String graphData = "[" + epoch + ",[" + Location + ",[" + V + ",[" + S + ",[" + T + ",[" + H + ",[" + P + ",[" + L;
  client.send(graphData);
  Serial.println(graphData);
  Serial.println("================================================================");

  epoch = ""; Location = ""; V = ""; S = ""; T = ""; H = ""; P = ""; L = ""; // Empty data from prior request.

  while (client.available()) {
  client.poll();
  }
#endif
  
} // End of Loop

#if LITTLEDB
void getData() {
  
  Serial.println("preparing data....");
    int i;
  
    for(i=0; i< selectedRows->rowsLen; i++) {
   
    epoch += getText(selectedRows->rows[i], "Timestamp"); epoch += ",";
    Location += getText(selectedRows->rows[i], "Location"); Location += ",";
    V += getText(selectedRows->rows[i], "Voltage"); V += ",";
    S += getText(selectedRows->rows[i], "RSSI"); S += ",";
    T += getText(selectedRows->rows[i], "Temperature"); T += ",";
    H += getText(selectedRows->rows[i], "Humidity"); H += ",";
    P += getText(selectedRows->rows[i], "Pressure"); P += ",";
    L += getText(selectedRows->rows[i], "Light"); L += ",";
    }
  
  int length = epoch.length(); epoch[length-1] = ']'; // get length of String and remove last comma of String and replce with "]".
  length = Location.length();  Location[length-1] = ']'; // convert 1,2,3,4,5, to 1,2,3,4,5]
  length = V.length(); V[length-1] = ']'; 
  length = S.length(); S[length-1] = ']';         
  length = T.length(); T[length-1] = ']';         
  length = H.length(); H[length-1] = ']';
  length = P.length(); P[length-1] = ']';
  length = L.length(); L[length-1] = ']';
 }
#endif

#if PROBEREQUESTS

void probeRequest(WiFiEvent_t event, WiFiEventInfo_t info) 
{
    Serial.print("Probe Received :  ");
    for (int i = 0; i < 6; i++) {
    Serial.printf("%02X", info.ap_probereqrecved.mac[i]);
    if (i < 5)Serial.print(":");
    }
    Serial.println();

      if (info.ap_probereqrecved.mac[0] == 6 || info.ap_probereqrecved.mac[0] == 16 || info.ap_probereqrecved.mac[0] == 26 || info.ap_probereqrecved.mac[0] == 36 || info.ap_probereqrecved.mac[0] == 46 || info.ap_probereqrecved.mac[0] == 56 || info.ap_probereqrecved.mac[0] == 66 || info.ap_probereqrecved.mac[0] == 76 || info.ap_probereqrecved.mac[0] == 86 || info.ap_probereqrecved.mac[0] == 96 || info.ap_probereqrecved.mac[0] == 106 || info.ap_probereqrecved.mac[0] == 116 || info.ap_probereqrecved.mac[0] == 126 || info.ap_probereqrecved.mac[0] == 136 || info.ap_probereqrecved.mac[0] == 146 || info.ap_probereqrecved.mac[0] == 156 || info.ap_probereqrecved.mac[0] == 166 || info.ap_probereqrecved.mac[0] == 176 || info.ap_probereqrecved.mac[0] == 186 || info.ap_probereqrecved.mac[0] == 196 || info.ap_probereqrecved.mac[0] == 206 || info.ap_probereqrecved.mac[0] == 216 || info.ap_probereqrecved.mac[0] == 226 || info.ap_probereqrecved.mac[0] == 236 || info.ap_probereqrecved.mac[0] == 246) // only accept data from certain devices.
       {

      //sendCommand();

      if (info.ap_probereqrecved.mac[1] == 06) 
      { // only accept data from device with voltage as a sensor type at byte 1.
               if (device == 06) { for (int i = 0; i < 4; i++) sensorTypes[i] = Livingroom[i];} 
               if (device == 16) { for (int i = 0; i < 4; i++) sensorTypes[i] = Kitchen[i];}
               if (device == 26) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom1[i];} 
               if (device == 36) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom2[i];}
               if (device == 46) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom3[i];} 
               if (device == 56) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom4[i];}
               if (device == 66) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom1[i];} 
               if (device == 76) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom2[i];}
               if (device == 86) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom3[i];} 
               if (device == 96) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom4[i];}
               if (device == 106) { for (int i = 0; i < 4; i++) sensorTypes[i] = Laundry[i];} 
               if (device == 116) { for (int i = 0; i < 4; i++) sensorTypes[i] = Boiler[i];}
               if (device == 126) { for (int i = 0; i < 4; i++) sensorTypes[i] = Workshop[i];} 
               if (device == 136) { for (int i = 0; i < 4; i++) sensorTypes[i] = Garage[i];}
               if (device == 146) { for (int i = 0; i < 4; i++) sensorTypes[i] = Office[i];}
               if (device == 156) { for (int i = 0; i < 4; i++) sensorTypes[i] = Tank[i];} 
               if (device == 166) { for (int i = 0; i < 4; i++) sensorTypes[i] = Solar[i];}
               deviceStatus[0] = info.ap_probereqrecved.mac[2];
               deviceStatus[1] = info.ap_probereqrecved.mac[3];
               deviceStatus[2] = info.ap_probereqrecved.mac[4];
               deviceStatus[3] = info.ap_probereqrecved.mac[5];
      } else {

      device = info.ap_probereqrecved.mac[0];
               
      voltage = info.ap_probereqrecved.mac[1];
      voltage = voltage * 2 / 100;
                  
      sensorValues[0] = info.ap_probereqrecved.mac[2];
      sensorValues[1] = info.ap_probereqrecved.mac[3];
      sensorValues[2] = info.ap_probereqrecved.mac[4];
      sensorValues[3] = info.ap_probereqrecved.mac[5];
              
      }

      if (voltage > 2.50 && voltage < 3.60) 
      {
      
      sprintf (str, "{");
      sprintf (s, "\"%s\":\"%i\"", "Location", device);    strcat (str, s);
      sprintf (s, ",\"%s\":\"%.2f\"", "Voltage", voltage);    strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[0], sensorValues[0]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[1], sensorValues[1]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[2], sensorValues[2]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[3], sensorValues[3]); strcat (str, s);
      sprintf (s, "}"); strcat (str, s);
              
      Serial.println();
      Serial.println("Following ## Sensor Values ## receiced from remote device  & published via MQTT: ");
      Serial.println(str);
      Serial.println();
     
      myClient.publish("sensor", str);
      
      if (voltage < 2.50) {      // if voltage of battery gets to low, print the warning below.
         //myClient.publish("Warning/Battery Low", location);
       }
     }

   if (info.ap_probereqrecved.mac[3] == apChannel) {
     
     sprintf (str, "{");
     sprintf (s, "\"%s\":\"%i\"", "Location", device);    strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "RSSI", info.ap_probereqrecved.rssi); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "MODE", deviceStatus[0]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "CHANNEL", deviceStatus[1]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "IP", deviceStatus[2]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "Sleeptime", deviceStatus[3]); strcat (str, s);
     sprintf (s, "}"); strcat (str, s);
                           
     Serial.println();
     Serial.println("Following ## Device Status ## receiced from remote device & published via MQTT: ");
     Serial.println(str);
     Serial.println();

               Timezone America; America.setLocation("America/New_York");
               Timestamp = String((now())); // + buffer;     //for milliseconds precision
               Date = " " + America.dateTime("mdy");
               Time = " " + America.dateTime("Hi");
               Day  = " " + America.dateTime("l");
               Hour = " " + America.dateTime("H");

               String insert = "insert into test_tbl values (";
  
               insert += Timestamp;
               insert += ",";
               insert += Date;
               insert += ",";
               insert += Day;
               insert += ",";
               insert += Time;
               insert += ", ";
               insert += Hour;
               insert += ", ";
               insert += device;
               insert += ", ";
               insert += voltage;
               insert += ", ";
               insert += info.ap_probereqrecved.rssi;
               insert += ", ";
               insert += sensorValues[0];
               insert += ", ";
               insert += sensorValues[1];
               insert += ", ";
               insert += sensorValues[2];
               insert += ", ";
               insert += sensorValues[3];
               insert += ")";
               Serial.println(insert);
               res = execQuery(insert);

               File schemFile = LITTLEFS.open(schemPath);
               File tblFile = LITTLEFS.open(tblPath);
               Serial.println();
               listDir(LITTLEFS, "/", 2);
               }
          }
    }
#endif 

Alternatively, in a full-up FreeRTOS (which is always running on ESP32 whether you know it or not) solution, the call back function specified by WiFi.onEvent() would simply push the event information into a queue. Then, a FreeRTOS task pending on data entering into that queue would wake up and process the event. That task could have sufficient stack space on not run in interrupt context.

@gfvalvo Can you please explain your idea with an example code?

Thanks.

Rudimentary example:

#include "Arduino.h"
#include <WiFi.h>

void connectToWiFi();
void wifiEvent(WiFiEvent_t event);
void handleWiFiEvent(void *pvParameters);

const char SSID[] = "WIFI_SSID";
const char PASSWORD[] = "WIFI_PASSWORD";

QueueHandle_t wiFiEventQueue;

void setup() {
  Serial.begin(115200);
  delay(1000);
  log_i("Starting");
  wiFiEventQueue = xQueueCreate(5, sizeof(WiFiEvent_t));
  xTaskCreatePinnedToCore(handleWiFiEvent, "WiFi Event", 2000, NULL, 2, NULL, 0);
  WiFi.onEvent(wifiEvent);
  connectToWiFi();
}

void loop() {
}

void connectToWiFi() {
  const TickType_t xTicksToWait = pdMS_TO_TICKS(4000);
  while (WiFi.status() != WL_CONNECTED)
  {
    WiFi.disconnect();
    WiFi.begin(SSID, PASSWORD);
    vTaskDelay(xTicksToWait);
  }
}

void wifiEvent(WiFiEvent_t event) {
  xQueueSendToBackFromISR(wiFiEventQueue, &event, 0);
}

void handleWiFiEvent(void *pvParameters) {
  WiFiEvent_t event;
  IPAddress ipAddress;
  for (;;) {
    xQueueReceive(wiFiEventQueue, &event, portMAX_DELAY);
    switch (event) {
      case SYSTEM_EVENT_WIFI_READY:
        log_i("WiFi Ready");
        break;

      case SYSTEM_EVENT_STA_START:
        log_i("Station Start");
        break;

      case SYSTEM_EVENT_STA_DISCONNECTED:
        log_i("WiFi Disconnected");
        connectToWiFi();
        break;

      case SYSTEM_EVENT_STA_CONNECTED:
        log_i("WiFi Connected");
        break;

      case SYSTEM_EVENT_STA_GOT_IP:
        ipAddress = WiFi.localIP();
        log_i("Got IP Address: %d.%d.%d.%d", ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3]);

        break;

      default:
        log_i("WiFi Event: %d", (uint16_t )event);
        break;
    }
  }
}

1 Like

@gfvalvo I tried to implement your solution as shown below but it still panics. May be implemented it wrong way.If I remove call to processData() function at end of proberequest function then everything work as expected.

Can you please review my code to see if I made any mistake ?
Thanks.

// SQLite reference at https://www.w3schools.com/sql/exercise.asp
#define PROBEREQUESTS     true     // Receives data from remote ESP8266 devices on network
#define MQTT              true     // Communicate with MQTT clients
#define WEBSOCKETS        true     // Communicate with Websockets clients
#define ASYNCWEBSERVER    true     // Publishes web interface
#define SQLITE3           true     // Store data
#define FIRSTTIME         true    // Warning - This must be false.Make it true if creating new data and table files for first time.

#include "Arduino.h"
#include <WiFi.h>
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h> // Thanks to https://github.com/siara-cc/esp32_arduino_sqlite3_lib
//#include <SPI.h>
#include <FS.h>
#include <LITTLEFS.h>
#include "time.h"   // Arduino built in
String Timestamp, Date, Day, Time, Hour;
//String dateReceived, dayReceived, timeReceived, hourReceived, rooms, V, S, T, H, P, L;
#define FORMAT_LITTLEFS_IF_FAILED true
int rc;
sqlite3 *db1;
String insert;
int triggerProcessData = 0;
  
const char* ssid = "";    // Your WiFi SSID
const char* password = ""; // Your WiFi Password
const char* apSSID = "ESP";        // SSID for access point. This must be same on all remote devices.
const char* apPassword = "";       // Password for Access point if required otherwise leave blank.
const int apChannel = 7;           // WiFi Channel number for access point. This must be same on all remote devices.
const int hidden = 0;              // If hidden is 1 probe request event handling does not work ?
int wsport = 8084;                 // Websocket server port
String deviceData;
String sensorData;
int device;

#if PROBEREQUESTS
// Channge following according to your remote sensor types for each device.
int Livingroom[4] = {16,26,36,46}; // temperature = 16, humidity= 26, pressure= 36, light= 46, OpenClose = 56, level = 66, presence = 76, motion = 86, rain = 96 etc.
int Kitchen[4] =    {46,36,26,16};
int Bedroom1[4] =   {46,36,26,16};
int Bedroom2[4] =   {16,26,36,36};
int Bedroom3[4] =   {16,26,36,36};
int Bedroom4[4] =   {16,26,36,36};
int Bathroom1[4] =  {16,26,36,36};
int Bathroom2[4] =  {16,26,36,36};
int Bathroom3[4] =  {16,26,36,36};
int Bathroom4[4] =  {16,26,36,36};
int Laundry[4] =    {16,26,36,36};
int Boiler[4] =     {16,26,36,36};
int Workshop[4] =   {16,26,36,36};
int Garage[4] =     {16,26,36,36};
int Office[4] =     {16,26,36,36};
int Tank[4] =       {16,26,36,36};
int Solar[4] =      {16,26,36,36};

//================= No user confiuration require below thi line =================================================


#include <esp_wifi.h>
char str [256];
char s [70];
float voltage;
int rssi;
uint8_t mac[6];
int sensorValues[4];
int sensorTypes[4];
int deviceStatus[4];
#endif

#if MQTT
#include <TinyMqtt.h>   // Thanks to https://github.com/hsaturn/TinyMqtt
#endif

#if WEBSOCKETS
#include <ArduinoWebsockets.h>  // Thanks to https://github.com/gilmaimon/ArduinoWebsockets
using namespace websockets;
WebsocketsServer WSserver;
String sql;
#endif

#if ASYNCWEBSERVER
#include <ESPAsyncWebServer.h>  // Install manually to arduino folder
int index_html_gz_len = 17965;
const uint8_t index_html_gz[] = {
0x1f,0x8b,0x08,0x08,0xad,0x6a,0xbd,0x60,0x00,0xff,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x2e,0x67,0x7a,0x00,0xed,0x5b,0xeb,0x77,0xe2,0x36,0x94,0xff,0x4c,0xfe,0x0a,0xad,0xdb,0x5d,0xe0,0x0c,0xd8,0x3c,0x92,0x4c,0x86,0x40,0xce,0xce,0x73,0xdb,0xdd,0x4c,0x67,0xda,0xcc,0x6e,0x3f,0x4c,0xe7,0xf4,0x18,0x5b,0x80,0x27,0xc6,0xf2,0xda,0x72,0x12,0x76,0x9a,0xff,0xbd,0xbf,0x2b,0xc9,0xd8,0x80,0x4d,0x98,0xed,0xe3,0xf4,0x43,0x80,0xc3,0x43,0xd2,0xbd,0xba,0x6f,0x5d,0x49,0x97,0xf1,0x42,0x2e,0xc3,0x0b,0x76,0x34,0x5e,0x70,0xd7,0xa7,0xcf,0x25,0x97,0x2e,0xf3,0x16,0x6e,0x92,0x72,0x39,0xb1,0x32,0x39,0xeb,0x9e,0x59,0x17,0xa6,0x39,0x72,0x97,0x7c,0x62,0xdd,0x04,0xfc,0x36,0x16,0x89,0xb4,0x98,0x27,0x22,0xc9,0x23,0x0c,0xbb,0x0d,0x7c,0xb9,0x98,0xf8,0xfc,0x26,0xf0,0x78,0x57,0xfd,0xe8,0xb0,0x20,0x0a,0x64,0xe0,0x86,0xdd,0xd4,0x73,0x43,0x3e,0xe9,0x5b,0x84,0x5c,0x06,0x32,0xe4,0x17,0xef,0x13,0x31,0xe5,0x09,0xff,0xdf,0x8c,0xa7,0xb2,0xc3,0x2e,0x03,0x89,0xc6,0x57,0x2f,0x3a,0xec,0x43,0x10,0xad,0xde,0xfe,0xf8,0xe1,0x43,0x87,0xfd,0xcc,0xa7,0xa9,0xf0,0xae,0xb9,0x4c,0x3b,0xec,0x79,0xba,0x8a,0xbc,0x5b,0x34,0xf0,0xe4,0x86,0x27,0xec,0xdf,0x58,0xf6,0x3e,0x14,0x72,0xec,0x68,0x5c,0x40,0x9a,0x7a,0x49,0x10,0x4b,0x26,0x57,0x31,0x88,0x93,0xfc,0x4e,0x3a,0x9f,0xdd,0x1b,0x57,0xb7,0x5a,0x2c,0x4d,0xbc,0x89,0xb5,0x90,0x32,0x4e,0x47,0x8e,0xe3,0xf9,0xd1,0xe7,0xd4,0xf6,0x42,0x91,0xf9,0xb3,0xd0,0x4d,0xb8,0xed,0x89,0xa5,0xe3,0x7e,0x76,0xef,0x9c,0x30,0x98,0xa6,0xce,0x67,0x90,0x94,0xac,0x9c,0xbe,0xdd,0xef,0xdb,0x03,0xf3,0xcb,0x5e,0x06,0x91,0xfd,0x39,0xb5,0x2e,0xc6,0x8e,0x46,0x79,0x71,0x74,0x34,0x0e,0x83,0xe8,0x9a,0x25,0x3c,0x9c,0x58,0xa9,0x5c,0x85,0x3c,0x5d,0x70,0x8e,0xa9,0x16,0x09,0x9f,0x6d,0xcc,0x05,0x38,0x9f,0x87,0xc1,0x4d,0x62,0x47,0x5c,0x3a,0x51,0xbc,0x74,0xb2,0x18,0xb4,0xff,0x7b,0xdf,0x3e,0xb5,0x9f,0x3a,0x7e,0x90,0x4a,0x47,0x31,0xa3,0xe6,0xf0,0x52,0x4c,0x02,0xdc,0x0a,0x23,0xf8,0xfa,0x86,0xa4,0xeb,0x06,0x11,0x78,0xfe,0xc2,0x94,0x4c,0x47,0xac,0xdf,0xeb,0xfd,0xeb,0x39,0x5b,0xf0,0x60,0xbe,0x90,0x23,0x76,0xfc,0xec,0x66,0x71,0xce,0xa6,0xae,0x77,0x3d,0x4f,0x44,0x16,0xf9,0x5d,0x4f,0x84,0x22,0x19,0xb1,0x6f,0x86,0xc3,0xe1,0x39,0x03,0xfa,0x38,0x74,0x57,0x23,0x36,0x0b,0xf9,0xdd,0x39,0x73,0xc3,0x60,0x1e,0x75,0x03,0xc9,0x97,0xe9,0x88,0x79,0xd0,0x1a,0x4f,0xce,0xd9,0xe7,0x2c,0x95,0xc1,0x6c,0x05,0x40,0xa5,0xc8,0xa2,0x43,0x40,0xd4,0xb3,0x50,0xdc,0x8e,0xd8,0x22,0xf0,0x7d,0x1e,0x61,0x1a,0x91,0xf8,0x3c,0xe9,0x26,0xae,0x1f,0x64,0xc0,0xf0,0x34,0x06,0x4e,0x29,0x32,0x6f,0xd1,0x75,0x3d,0x19,0x88,0x68,0xc4,0x22,0x11,0xf1,0x73,0x76,0x0f,0xca,0x69,0x96,0x0d,0xa2,0x69,0x70,0x4e,0xb5,0xf9,0xb9,0x4b,0x76,0x32,0x9f,0xb6,0x06,0xc7,0x27,0x1d,0x36,0x18,0xf6,0x3a,0xec,0xd9,0xb3,0x76,0x3e,0x29,0xc1,0xc4,0x77,0x2c,0x15,0x61,0xe0,0xd3,0x28,0xb7,0xd5,0x1f,0x9e,0x76,0x58,0xf1,0x66,0x9f,0xac,0xc7,0xae,0x09,0x3c,0x21,0x49,0x55,0x11,0x98,0xc1,0x90,0xba,0x29,0x0f,0xb9,0x07,0x62,0x36,0x69,0x1e,0xd1,0xc8,0x1b,0x0e,0xd2,0x2b,0xa9,0xc3,0xbc,0xa7,0x67,0x20,0xaf,0x4f,0x6f,0x03,0xd0,0xd8,0xb7,0x7b,0x3d,0xcc,0xbc,0x06,0x5f,0x90,0xd8,0x00,0xed,0x65,0x49,0x4a,0x30,0xb1,0x08,0xb4,0x38,0x0d,0x6d,0x46,0x20,0x03,0x25,0x00,0x82,0x82,0x09,0xba,0x18,0x1f,0x8b,0x14,0xbe,0x42,0x24,0xce,0x82,0x3b,0xee,0x9f,0xb3,0x44,0x8b,0x6a,0x38,0xb4,0x87,0x43,0xc5,0x46,0x4c,0x0c,0x91,0xb6,0x09,0x2a,0x95,0x00,0x5b,0x2a,0xa5,0x29,0xfb,0xf8,0xb2,0x65,0x11,0xb1,0xeb,0xfb,0x41,0x34,0x1f,0xf5,0xce,0xd9,0xd2,0x4d,0xe6,0x41,0x54,0x7c,0xeb,0x4e,0x43,0xf8,0x55,0x37,0x95,0x6e,0x22,0x77,0x5a,0x79,0xe4,0x97,0xda,0x82,0x08,0x56,0xce,0x77,0x86,0x9a,0x66,0x35,0xb6,0x92,0x1a,0x16,0x2c,0xe7,0x5f,0xd6,0xd6,0xa7,0x30,0x13,0xf0,0x9d,0xe1,0x5e,0x9b,0x30,0x0c,0xbe,0x6b,0x88,0x36,0x56,0xbc,0xa1,0xbd,0x63,0x12,0x90,0x99,0x90,0x98,0x3f,0x83,0xfa,0x31,0x17,0x5c,0xd0,0x38,0x07,0xbe,0x9a,0x80,0x75,0x34,0x9e,0x0a,0x7f,0x85,0x08,0xf5,0x75,0x61,0xe0,0x60,0xd7,0x0c,0x82,0x19,0xaf,0x8c,0x01,0x8b,0xc1,0x9f,0x14,0xc8,0x80,0x08,0xe8,0x66,0x22,0x59,0x32,0x6d,0xa9,0x13,0x0b,0x81,0x80,0x81,0xdd,0xab,0xd7,0x97,0xaf,0x5f,0x7e,0x60,0x5e,0xe8,0xa6,0xe9,0xc4,0x42,0xac,0x9a,0x42,0xc0,0x16,0x83,0x17,0xa8,0x5f,0x4b,0x37,0xf2,0x2d,0x15,0x94,0xd9,0x84,0x59,0xae,0x02,0x62,0x6c,0x2c,0x62,0x42,0x02,0x5a,0xcd,0x97,0x8d,0x56,0x6d,0xf8,0x6c,0x96,0x88,0x25,0x93,0x20,0xfb,0x57,0x39,0x0d,0xd9,0xed,0x02,0x5c,0x54,0x8f,0x7f,0x15,0xcc,0x03,0xe9,0x86,0xec,0xe7,0x04,0x16,0x5e,0x3d,0xe4,0x79,0xe4,0x86,0x62,0xbe,0x6f,0x44,0x8e,0xe4,0x27,0xa8,0x6c,0x2f,0x8e,0xfa,0x01,0x3f,0x70,0x11,0xc3,0x37,0xc2,0xea,0xde,0x2b,0x2e,0xd9,0xf3,0xf7,0xec,0xe5,0xc2,0x8d,0xa2,0x7d,0x63,0xae,0x42,0xce,0x63,0xa8,0x67,0x59,0x43,0x28,0x8d,0x79,0x2b,0xfc,0x52,0xef,0xd8,0xd1,0x4a,0x20,0x15,0xed,0x53,0x87,0x5e,0xfb,0x0a,0x6d,0x4c,0x0f,0xd2,0xc6,0x65,0x70,0x03,0x47,0x4d,0x84,0x58,0x56,0xf7,0xff,0x57,0x20,0xbd,0x05,0x8f,0xaa,0x3b,0x5f,0x70,0x9f,0x20,0xfb,0x7b,0x7b,0x07,0x35,0xbd,0xae,0x5c,0xec,0x03,0x36,0xdd,0x35,0xd0,0x97,0x2e,0x02,0x63,0xb2,0xaa,0xee,0x7c,0x37,0x9b,0x41,0x12,0x9b,0x7d,0x07,0x8b,0xd1,0x58,0x75,0xbf,0x10,0xa4,0x67,0xb1,0x4d,0xfc,0xbd,0x5e,0xf5,0xbc,0xbd,0x1a,0x5e,0x7a,0x35,0x4c,0xf4,0x86,0x35,0xed,0xc7,0x35,0xed,0x27,0x35,0xed,0xa7,0xd5,0xed,0xfd,0x9a,0x79,0xfb,0x35,0xf3,0xf6,0x6b,0xe6,0xed,0xd7,0xcc,0xdb,0xaf,0x99,0x77,0x50,0xd3,0x3e,0xac,0x69,0x3f,0xae,0x69,0x3f,0xa9,0x69,0x3f,0xad,0x69,0x7f,0x5a,0xd3,0x7e,0x56,0xd3,0xfe,0xac,0x4e,0x6e,0xb5,0x02,0xad,0xe3,0xb8,0x5f,0xc7,0x32,0x92,0x83,0x3a,0x59,0xd7,0x75,0xd4,0x71,0xdd,0xaf,0x63,0xbb,0x5f,0xc7,0x77,0xbf,0x8e,0xf1,0x7e,0x1d,0xe7,0x83,0x3a,0xce,0x07,0xb5,0xba,0xae,0xe3,0x7c,0x50,0xc7,0xf9,0xa0,0x8e,0xf3,0xc1,0x36,0xe7,0x5f,0xeb,0xb3,0x83,0xc2,0x67,0xfd,0xad,0xe0,0xf7,0xe8,0xb2,0x8f,0x2e,0xfb,0xe8,0xb2,0x7f,0xad,0xcb,0x7e,0xa5,0xb7,0x0e,0x0b,0x6f,0xe5,0x8f,0xde,0xfa,0xe8,0xad,0x8f,0xde,0xfa,0x4f,0xf6,0xd6,0xe3,0xc2,0x5b,0x67,0x8f,0xf9,0xf0,0xa3,0xbb,0x3e,0xba,0xeb,0x3f,0xd5,0x5d,0xc3,0x6c,0x19,0x15,0xce,0x3a,0xdf,0x5a,0x5a,0x2f,0x85,0xe7,0xd2,0x97,0x9a,0x63,0x12,0xb7,0xf6,0x00,0xc5,0xad,0xd9,0x6c,0xd7,0x1f,0x65,0x7c,0x27,0xb2,0xe4,0xeb,0x19,0x10,0x31,0x4f,0x5c,0x29,0x92,0x82,0x85,0xc5,0x16,0x0b,0x93,0xea,0xe9,0x6a,0x0e,0x38,0xc6,0x35,0xcd,0x75,0x58,0x6a,0xda,0xc7,0x25,0xf4,0x05,0x2b,0xe3,0x69,0xa2,0x0e,0xcc,0xcd,0x91,0xdc,0x8d,0x9b,0x30,0x57,0x4a,0xd7,0x5b,0xbc,0xbe,0xc1,0x31,0x36,0x88,0x9f,0x65,0x91,0x3a,0x50,0x6b,0x45,0x38,0xd3,0xe9,0x30,0x4e,0xcd,0x1d,0x16,0xe2,0x70,0x8f,0xe3,0xa0,0xb2,0x43,0x47,0xc1,0x2f,0xdd,0x58,0x66,0x09,0x6f,0xb3,0x2f,0x98,0xd0,0x71,0xd8,0x5b,0x2e,0x17,0xc2,0x67,0x38,0x8d,0x63,0x6f,0xde,0x74,0xd8,0x3b,0x92,0x47,0x07,0x07,0x4b,0x38,0x2f,0x03,0x86,0x2b,0x77,0xe6,0x26,0x01,0x46,0x06,0x33,0xd6,0xc2,0xf9,0x76,0xe4,0x8b,0x5b,0x1b,0xa7,0xad,0x6a,0xc2,0x4b,0x83,0x97,0x69,0x64,0x0c,0x87,0xcb,0x3e,0xdf,0xe9,0x6d,0xed,0xa1,0x82,0xfd,0xf6,0x1b,0x9b,0xb9,0x61,0xca,0xdb,0xe7,0x40,0x70,0xaf,0x29,0xfa,0xfe,0x35,0x5b,0xb8,0x29,0x0b,0x64,0xca,0xc4,0x6d,0xc4,0x70,0x11,0x03,0x02,0xd1,0xc5,0x31,0x6e,0x63,0xa2,0x82,0xf5,0x56,0x53,0x44,0xcd,0x27,0x5b,0x13,0x19,0x9c,0xf7,0xe7,0x47,0x47,0xc0,0xfa,0x2e,0xf2,0x38,0x93,0x0b,0x6e,0x98,0x60,0xa1,0x70,0xfd,0x94,0x61,0xa9,0x51,0x8d,0xaf,0xde,0xbd,0x65,0x41,0x8a,0x1b,0x0e,0xd7,0x5f,0x75,0x8c,0x50,0x55,0x87,0xc2,0x89,0xf3,0x68,0xf5,0x63,0x89,0xf3,0x5e,0xe0,0x2c,0x4f,0xac,0xb1,0x75,0x98,0x45,0xf8,0xac,0x4e,0xa1,0x01,0x2d,0x13,0x52,0x91,0x3e,0x81,0xfc,0xd5,0xac,0x6c,0xd0,0x92,0x2f,0xbc,0x6c,0x09,0x60,0x7b,0xce,0xe5,0xeb,0x90,0xd3,0xd7,0x17,0xab,0xef,0xfd,0xd6,0xfa,0x88,0x13,0x94,0x6f,0xc0,0x7e,0x87,0xc6,0x10,0x72,0x2e,0x29,0x38,0x17,0x39,0x63,0xda,0x4c,0xfa,0xfb,0xf0,0x9a,0xb3,0xba,0x76,0xe7,0xa8,0x91,0x8f,0x1f,0x1c,0x40,0x47,0x9f,0x08,0x29,0x4f,0x32,0x3c,0x00,0x68,0xb0,0x0d,0x74,0x7c,0x00,0xd0,0x70,0x1b,0xe8,0xe4,0x00,0xa0,0xe3,0x6d,0xa0,0xd3,0xfd,0x40,0x2a,0x52,0x6d,0x81,0x3c,0xdd,0x07,0xb2,0x8e,0x0d,0xed,0xf3,0x06,0xd3,0x60,0x64,0x49,0x57,0x0b,0x98,0x0f,0x69,0x12,0x37,0x45,0xda,0xa4,0xdc,0x38,0x4e,0x44,0x9c,0x04,0x08,0x67,0x46,0x63,0xcd,0x54,0x8f,0x27,0xb7,0x91,0x8b,0x20,0xb5,0x6f,0xdc,0x30,0x43,0x78,0x41,0x7c,0xc9,0x0f,0x76,0x2d,0x32,0xfe,0xad,0xbe,0xf2,0xc9,0xb2,0xb5,0x56,0xb1,0xa1,0x38,0xd7,0xb4,0xad,0xee,0x04,0x6c,0x73,0xe1,0x40,0x21,0xcb,0xca,0x99,0xca,0x95,0xfb,0xf0,0x90,0xe1,0xc3,0x43,0x8e,0x1f,0x1e,0x72,0xf2,0xf0,0x90,0xd3,0xdd,0x21,0x74,0x07,0xb5,0x3d,0xec,0xe9,0x43,0xc3,0x8c,0x14,0xee,0x75,0x18,0xa8,0x90,0xeb,0xe6,0x91,0xb8,0x92,0xae,0x6a,0x2b,0x8e,0xc0,0x8b,0x36,0x3a,0xf2,0xd6,0xbf,0xca,0x27,0xf5,0xba,0xa5,0x74,0x32,0xbf,0x39,0x64,0x4b,0x2b,0x7f,0x9b,0x5e,0xaa,0xc4,0x55,0xa1,0x9b,0xaa,0x61,0x15,0xfa,0xa9,0x1a,0xf6,0xa7,0xe9,0x88,0x51,0x80,0xa9,0xb4,0xfa,0x5d,0x21,0xc2,0xa5,0xd4,0xe0,0x83,0xe4,0x77,0x98,0x08,0x0f,0xb3,0xee,0xc3,0x85,0x78,0xb8,0x1c,0x0f,0x17,0xe5,0x01,0xd2,0x6c,0x40,0x2e,0xf7,0xea,0x5d,0xbd,0x55,0x48,0xb3,0xfe,0x52,0xeb,0xcf,0x15,0x6d,0x0d,0xe9,0x0f,0x1a,0xe9,0xdf,0x2d,0xe2,0xc3,0xc4,0x4b,0xa2,0xa5,0x10,0x92,0x47,0x12,0x4a,0x0f,0xd4,0x4a,0x8b,0xa0,0xfe,0xdf,0x08,0x2a,0x14,0xca,0x45,0x84,0x52,0x90,0x68,0x8e,0x98,0x8e,0x00,0x2f,0xa2,0x6b,0xbe,0x8a,0x13,0x9e,0xa6,0x3a,0x0f,0x48,0x29,0x11,0xf0,0xb9,0x24,0xd9,0x43,0xda,0x91,0x82,0xd0,0xf0,0x5a,0x37,0x62,0xb6,0xbd,0xda,0x53,0x26,0xa3,0x31,0x52,0x0a,0x53,0xce,0x1c,0x36,0x07,0x22,0x83,0xd0,0xc3,0x90,0x43,0x6c,0x2c,0xfa,0x6a,0xc1,0xda,0x0b,0x97,0xd3,0x58,0x01,0x79,0x4f,0x99,0xc4,0xb7,0xad,0x7c,0x85,0x6b,0xdb,0x2a,0xc1,0x69,0x15,0x59,0x04,0xc5,0xb2,0x6f,0x5b,0x16,0xdd,0xc5,0x5a,0x6d,0x3b,0xcd,0xa6,0xcb,0x40,0x6e,0x75,0xe7,0x89,0x48,0x24,0x5f,0x3e,0x98,0xc1,0x34,0x41,0x47,0x16,0xca,0x66,0x5b,0xdb,0xaa,0xd6,0xca,0x6d,0x6a,0x03,0xda,0x07,0xe1,0x6b,0x14,0xa8,0x21,0x50,0xd1,0xd3,0x71,0x50,0x2a,0x93,0xc8,0x96,0x75,0xa5,0x66,0x96,0x5c,0xe5,0x3e,0xaa,0x03,0x31,0xb8,0xd5,0xbc,0x02,0x1c,0x5d,0xec,0xb3,0x26,0x7b,0x52,0x26,0x41,0xa7,0x76,0x87,0x31,0x68,0xd6,0xd0,0x6f,0x5b,0x4d,0x2a,0x7e,0xa1,0xd4,0x1f,0xe4,0xa1,0xab,0xa9,0xe5,0xdd,0x2c,0xe7,0x6c,0x18,0x7d,0x44,0xee,0x86,0xc1,0xa8,0x46,0x51,0x53,0x69,0x5e,0x90,0x6f,0xfd,0x55,0x6b,0x4c,0x1b,0x04,0x7e,0x21,0x69,0x90,0x98,0x63,0x77,0x45,0x89,0x24,0x44,0x5c,0x45,0xc2,0x13,0xd6,0x74,0x48,0x12,0xd4,0xa7,0x73,0xba,0xca,0xae,0x3c,0x7d,0xcb,0x3b,0xcf,0x95,0xa5,0x43,0x06,0x7b,0x79,0xdb,0x8a,0xd0,0x4a,0x6c,0x85,0xfe,0xff,0x12,0xc2,0xd0,0x6c,0x39,0xd6,0x66,0xe7,0x60,0x83,0x6a,0xf2,0xd6,0x7d,0x44,0xef,0x0b,0x84,0x5f,0xc9,0x81,0x85,0x67,0x4e,0x09,0xa5,0x8a,0xa5,0x2e,0x6a,0xcc,0x93,0xc1,0xad,0xe6,0x4d,0x6e,0xd7,0x34,0x37,0x8e,0x1a,0xd4,0x5b,0x76,0x87,0x96,0x21,0x60,0x3d,0x48,0x99,0x2f,0x95,0x78,0xac,0x2b,0x2c,0x68,0x7b,0x37,0x0e,0xa2,0x38,0x2b,0x57,0x75,0xd0,0x46,0x75,0x62,0x69,0x4c,0x28,0xeb,0x08,0xfe,0x4f,0xed,0x52,0x07,0x67,0x7a,0xc7,0x8a,0x82,0x2c,0xf8,0x88,0xa5,0xe3,0x0f,0xea,0x28,0x98,0xb3,0x85,0x42,0xfb,0xf4,0x7a,0x00,0x79,0x14,0x33,0x5e,0xa4,0xaa,0xaf,0x1c,0xf2,0x7d,0xfa,0x42,0x73,0xa9,0xf2,0x9c,0x44,0xdc,0x62,0x9b,0x8c,0x13,0x38,0xc8,0x01,0x5f,0x86,0x27,0x9a,0x02,0x13,0x48,0x4b,0x53,0xa5,0x31,0x0f,0x43,0x5c,0xd7,0x7b,0xd7,0x13,0x4b,0xed,0xe2,0x2c,0xa6,0x76,0x50,0x22,0x0a,0x57,0xa0,0x3d,0xc9,0xd0,0xa0,0x82,0x30,0xba,0x51,0x2c,0xd3,0x25,0xda,0x47,0xfd,0x53,0x94,0xba,0xa8,0x8a,0x9a,0x75,0x7d,0x14,0x5f,0x9e,0x53,0xc5,0x9d,0x93,0x53,0x40,0xd4,0xfc,0x4b,0xb7,0x3b,0x8e,0x2f,0x0c,0x27,0x34,0x3d,0x79,0xff,0x5b,0x44,0x39,0x17,0x21,0x72,0x43,0x3a,0x84,0x15,0xe4,0xf6,0xd6,0x84,0xf5,0x4e,0x1d,0xbc,0x08,0xe3,0x34,0x93,0x52,0x44,0x14,0xd3,0xc3,0x80,0x88,0x24,0x51,0x7d,0x00,0x50,0xab,0x6d,0xa1,0xf2,0xa1,0x10,0x04,0xc3,0xe6,0xf7,0xea,0xc7,0xcb,0xb1,0xa3,0x01,0xb0,0xf7,0x8e,0x01,0x9d,0x85,0x46,0xf2,0x1e,0x47,0x8d,0x94,0x9f,0x4f,0x7e,0x61,0x80,0x52,0x14,0xb4,0x98,0x36,0xda,0x38,0xea,0x41,0xda,0x12,0x4d,0xc1,0x0b,0xb6,0x05,0x1c,0x86,0x37,0xe5,0xa8,0x2b,0xa3,0xdb,0xc5,0x0c,0x75,0x87,0xac,0xdb,0x2d,0xb6,0xf0,0x9a,0x8f,0xe6,0x56,0xed,0x4e,0x13,0x03,0xc8,0xe6,0x2d,0xd4,0xd2,0x5c,0xa9,0x5a,0x1a,0x28,0x20,0x32,0xfb,0x56,0x5a,0xde,0xb1,0x09,0x21,0x83,0xbe,0x4d,0x61,0x08,0x11,0xbf,0xa5,0x9a,0x1b,0x3d,0x0e,0x30,0xb7,0x54,0xee,0xd3,0x7f,0x36,0xb0,0x51,0xb9,0x65,0xf7,0xec,0xe1,0xe8,0xac,0x77,0x46,0x1b,0x25,0x38,0xff,0x7e,0x18,0x32,0x7e,0xb3,0xbf,0x47,0x05,0x93,0x3a,0xb4,0xb1,0x17,0x22,0x95,0xea,0x58,0x04,0xde,0x51,0x42,0x84,0xe5,0xae,0x4b,0x0f,0x8a,0xc8,0xd8,0x3e,0x83,0x7a,0xe6,0xbb,0xa8,0x96,0x54,0x8d,0x47,0x79,0x34,0x55,0xbd,0x5a,0xda,0xa0,0x39,0x5f,0x43,0x8c,0xc4,0xf6,0xad,0x21,0xa5,0x61,0xc5,0x42,0x52,0xb7,0x20,0x98,0x81,0xf0,0xa5,0xf2,0x32,0x53,0xb4,0xde,0x1f,0x51,0x87,0x88,0x96,0xeb,0x79,0xd7,0xf4,0xe1,0x60,0x42,0xea,0x6c,0x5e,0xf9,0xa3,0x4a,0xb3,0xa0,0x0f,0x31,0xa3,0x0e,0x9b,0x38,0xa2,0x18,0x33,0x61,0x4d,0x14,0x7c,0x61,0xce,0x26,0x45,0xee,0xbc,0x07,0x0a,0x41,0x9d,0x18,0x8e,0x14,0xb0,0xe2,0x5f,0xa9,0x6e,0x60,0x52,0x79,0xc4,0x87,0x37,0xdd,0x33,0x3a,0x4d,0x59,0x62,0xcd,0x86,0x3d,0x68,0x58,0x25,0x9f,0xcd,0x9d,0xcc,0x5a,0x88,0xc6,0x74,0x76,0xe4,0x98,0x8f,0x36,0x9c,0xff,0x54,0x65,0x61,0x24,0x85,0x35,0xb1,0x45,0x0e,0x64,0x96,0x55,0xa8,0xf6,0x3f,0x04,0x8c,0x8c,0x10,0x97,0xa1,0x54,0xd1,0x1e,0xea,0xb2,0xb4,0x01,0x8c,0x54,0xdc,0xab,0xc0,0x62,0x1c,0xde,0xa4,0x9d,0x4f,0x26,0x3a,0x07,0xd2,0xec,0xc3,0x20,0x7e,0x89,0x54,0xaa,0xba,0x1e,0x4e,0x1a,0x5e,0xc7,0x90,0x3d,0xea,0x35,0x9a,0x48,0x9b,0x1b,0x04,0x2b,0xac,0x90,0xf5,0x47,0x73,0x8c,0xa3,0xa6,0xc1,0x6a,0x0e,0x0a,0x3c,0xde,0x72,0x9e,0x3b,0xf3,0x0e,0x6b,0x36,0xdb,0x4f,0x9a,0x2f,0x9a,0x30,0xc1,0x46,0x03,0x35,0x6d,0x22,0x42,0x81,0x24,0x87,0xb5,0xce,0x5b,0xff,0x79,0xf5,0xee,0x07,0x3b,0xa6,0x12,0xde,0x96,0x62,0x02,0x66,0x4a,0x1b,0x75,0xce,0x59,0x5e,0x01,0x07,0x6d,0x79,0xd7,0x79,0x91,0xa7,0xaa,0x82,0x55,0x45,0x6c,0xb0,0x83,0xd4,0x39,0x39,0x3e,0xe9,0xf7,0x4f,0x86,0x67,0x84,0x12,0x23,0x10,0xa8,0x94,0xd2,0x50,0xf9,0x27,0x45,0xd7,0x8d,0xba,0x6e,0x92,0xb8,0xab,0xae,0x98,0xe9,0x2f,0x29,0xda,0xbb,0x85,0xb7,0x92,0x08,0x1a,0x0d,0x43,0xfe,0x9b,0x3c,0x93,0x40,0x22,0x84,0xf3,0xad,0x88,0x7d,0x24,0x0d,0x15,0x56,0x83,0xc5,0xf0,0x53,0xb3,0xad,0xd6,0x89,0x46,0xa3,0xcc,0x80,0x11,0x7d,0xa3,0xa1,0xa4,0x48,0x85,0xbe,0x14,0xe4,0x5f,0x47,0x37,0x41,0x42,0xb6,0x8b,0x23,0x28,0x05,0x6f,0xb4,0x08,0xb8,0x04,0x5e,0x2c,0x6f,0x45,0x72,0xad,0x94,0x40,0xa8,0x24,0x25,0xbe,0xe4,0xde,0xeb,0xfd,0x29,0xd3,0x98,0x46,0xfa,0xa3,0x53,0x34,0x9b,0xb2,0xcc,0xe1,0x69,0xaf,0xd4,0x98,0x87,0xe3,0xd3,0xe3,0x8d,0x56,0x21,0xae,0x51,0x5c,0x4a,0x38,0xf5,0x96,0x42,0x25,0x58,0x23,0xf6,0x51,0x0d,0x69,0xb0,0x8c,0x4d,0x2e,0xd6,0x33,0x36,0x58,0x88,0x80,0x12,0xf2,0x39,0xc5,0x85,0x09,0xcb,0x6c,0x94,0x54,0x49,0x5b,0x55,0x15,0x5f,0xa9,0x85,0x5a,0x24,0x2d,0xcb,0xce,0xba,0x7a,0x44,0x71,0x16,0x53,0x6c,0xa5,0x99,0x81,0xde,0x3d,0x45,0xc4,0x01,0x0e,0x4a,0x4b,0xef,0x24,0x84,0x91,0x21,0xd3,0x85,0x7c,0x8a,0x79,0xf5,0x83,0xdb,0x48,0x83,0x09,0xe6,0x15,0x9f,0xb9,0x58,0x2c,0x21,0x66,0x93,0xfc,0xad,0x51,0x4b,0x72,0x81,0x80,0xa7,0xaf,0x43,0x90,0xc7,0x6d,0xd8,0x2a,0xac,0x93,0xca,0xa3,0x53,0xd8,0x82,0x22,0x4d,0xf7,0x97,0x49,0x2b,0x13,0xb7,0x81,0xe4,0x7b,0xff,0x0e,0x58,0x9e,0x93,0x4d,0x60,0x66,0x21,0x05,0x45,0x0f,0x3b,0xc5,0x52,0x83,0x32,0x6b,0x37,0x0c,0x5b,0x86,0x15,0x6f,0x11,0x84,0xfe,0x0f,0xc8,0x06,0xd3,0xb6,0x8d,0x00,0xcb,0xef,0xde,0xcd,0x10,0xa4,0x34,0x19,0x87,0xcc,0xa3,0x24,0xa9,0xbf,0x7e,0x5c,0xcf,0xfc,0xa9,0x16,0xb0,0x6c,0x56,0x7a,0xb8,0x1d,0xba,0x58,0x83,0x4a,0x53,0x51,0xea,0x61,0xbe,0xa9,0xcf,0x4f,0xa4,0xf0,0x7b,0x7a,0x53,0xb5,0xeb,0x46,0xdf,0x8c,0xdd,0xe5,0x5f,0xc8,0x92,0x96,0x64,0x48,0x58,0xd3,0xb5,0x71,0x10,0xa0,0x86,0x50,0x53,0xe4,0x06,0xf1,0x45,0xb5,0xe5,0x69,0x17,0xb8,0xa0,0x99,0x11,0x61,0xf2,0x7b,0x00,0x2b,0x37,0x2d,0xb8,0x98,0xb8,0x06,0x46,0x2b,0xce,0x92,0x38,0xc4,0xae,0xc7,0xb4,0xcf,0x82,0x90,0xc6,0xab,0xe2,0xe3,0x5e,0xa7,0xd7,0x19,0x9c,0x9c,0x74,0x7a,0xf6,0xa0,0x6d,0x06,0xd4,0xa0,0xff,0x9f,0x5d,0xbc,0xa8,0x9d,0xbe,0xf9,0xa3,0x68,0xaf,0x2a,0xd0,0x26,0x7a,0x93,0xf6,0x87,0xf0,0x7e,0xd8,0xc5,0x3b,0x45,0x8c,0xfd,0x83,0x58,0xbf,0xdb,0xc5,0x9a,0x60,0x43,0x55,0x85,0x54,0x21,0xa4,0xe7,0x83,0x48,0xdf,0xef,0x22,0x9d,0x27,0x9c,0x17,0x8a,0xfc,0xff,0xd1,0x7a,0xb9,0x8b,0x76,0x85,0x64,0x52,0xdc,0x7e,0x15,0xb9,0xb0,0x5b,0xda,0xc0,0x1f,0x91,0xaf,0x20,0x10,0xa9,0xc4,0x46,0xd5,0x18,0xb7,0x28,0x14,0x76,0x54,0xcc,0xc4,0x7b,0xbe,0x12,0x51,0xdd,0xb4,0x0a,0xb2,0x0d,0xa4,0x05,0x6a,0xbd,0xaf,0x5a,0xce,0x5f,0x84,0x62,0x6a,0x16,0x73,0x6c,0x16,0xdd,0x64,0xa5,0x17,0xef,0x22,0xeb,0xc9,0x17,0xec,0x52,0x2f,0xc3,0x2e,0x1f,0x85,0xdf,0xd3,0xfc,0x3e,0x21,0x22,0x2f,0xa4,0xa5,0x04,0xb7,0x18,0xc0,0x8d,0x53,0x03,0xb5,0x74,0xb0,0x69,0x36,0x9b,0x61,0xed,0xd5,0x0b,0xbc,0xca,0x89,0x96,0xab,0x37,0xd8,0x14,0xc8,0xe1,0x40,0xc5,0x11,0xe2,0x21,0x0b,0xc3,0x73,0xd3,0xa5,0xda,0x5e,0x68,0x98,0xcd,0x9e,0x37,0x41,0xc8,0x69,0xf7,0xa8,0x3b,0xc0,0x76,0xa9,0x81,0xe2,0x5e,0x79,0x04,0xb2,0x1f,0xb3,0xf1,0x29,0xa7,0x3e,0xb4,0x5b,0xde,0x0a,0xa0,0x6c,0x67,0x4a,0xbd,0x14,0x9b,0x30,0xa9,0xb7,0x20,0xe5,0xb8,0xa3,0x41,0xb6,0x19,0x20,0x6a,0xca,0x4d,0xad,0x0d,0xac,0x7a,0x69,0x1e,0x4f,0x18,0xae,0xeb,0xb4,0xec,0x70,0xef,0x12,0x21,0x41,0xa6,0x4d,0x1b,0xfd,0x89,0x46,0x9f,0xa8,0x2b,0x48,0x68,0x63,0x38,0x80,0x9c,0x91,0xbe,0x10,0x42,0x4a,0xa4,0xd4,0x3f,0x0c,0x20,0x8a,0x25,0xea,0xd0,0xd3,0x5c,0x84,0x45,0x52,0xa9,0x12,0x1e,0xca,0x67,0x36,0xe6,0xb4,0xa7,0x2b,0xc9,0x2f,0x79,0x34,0x97,0x0b,0xb5,0xd1,0xa3,0x9f,0xb8,0x5c,0x9a,0x6d,0xa8,0xb0,0x3e,0x43,0xfa,0x25,0xfa,0xc8,0xef,0xdc,0x25,0xc2,0x14,0xfe,0x97,0xf1,0x09,0x0b,0x2e,0x5d,0x96,0xb5,0x68,0xea,0x00,0x53,0xe2,0x9f,0x02,0x01,0x1b,0x6f,0xc9,0xc1,0x0e,0xd5,0x6c,0xe8,0x7a,0xf2,0xa4,0x5d,0xa2,0x10,0x59,0x94,0xde,0x67,0x6e,0x89,0xed,0x63,0x80,0x80,0xbe,0x4e,0xdb,0xd6,0xe3,0x37,0x96,0x07,0x13,0xeb,0x1d,0x07,0x09,0xad,0x5a,0xb2,0x48,0xd3,0x24,0x4c,0x3a,0x1c,0x24,0x29,0xaa,0x7d,0x6f,0x41,0x36,0xd9,0x60,0x84,0x45,0x97,0x14,0x8e,0x75,0x28,0x65,0x5d,0x92,0x2e,0x89,0x3d,0x0d,0x14,0x33,0x96,0x5a,0xb5,0xb0,0xcb,0x83,0x44,0x68,0xd3,0x07,0x9e,0xf5,0x52,0xa8,0x54,0x50,0x82,0xc6,0xb6,0x88,0x0c,0xd9,0x13,0x59,0xe8,0x63,0x3b,0xa3,0xba,0xf3,0x3d,0x0e,0xa6,0x85,0xe3,0x1e,0xd1,0x49,0xda,0x86,0xd1,0x51,0x9e,0xf0,0x3c,0x2d,0x9b,0x53,0x91,0x56,0x83,0x2b,0x75,0x2f,0x07,0x4f,0x6c,0xe8,0xf4,0x5c,0xf3,0x53,0xb6,0x50,0x72,0xc1,0x42,0x22,0xc5,0x5e,0xa8,0x4c,0x17,0x78,0x56,0x80,0xbe,0xad,0x36,0x26,0xc0,0x98,0xdf,0x0f,0x14,0x86,0xbd,0x83,0x00,0x97,0x7e,0x90,0x52,0x04,0x3b,0x49,0xb3,0x98,0xfe,0xd6,0x85,0x9c,0x7a,0xba,0x62,0x2b,0x12,0x8c,0x11,0x03,0xa1,0x5b,0x2f,0x90,0x1b,0x3b,0x74,0xc7,0xfc,0xf7,0xc2,0x51,0xff,0x22,0xfb,0x1d,0x1d,0xb1,0x71,0xc5,0x4c,0x36,0x00,0x00
};
AsyncWebServer webserver(80);
#endif


#if WEBSOCKETS
void handle_message(WebsocketsMessage msg) {
  
  Serial.print("Message Received from javascript websocket client: ");
  Serial.println(msg.data()); 
  sql = msg.data().c_str();
  Serial.println("======= Filtered data by SQL statement sent to client====================");
  Serial.println(sql.c_str());
  sqlite3_close(db1);
  Serial.println("=========================================================================");
} 
#endif

#if MQTT
std::string sentTopic = "data";
std::string receivedTopic = "command";
MqttBroker broker(1883);
MqttClient myClient(&broker);

void receivedMessage(const MqttClient* source, const Topic& topic, const char* payload, size_t length)
{
  Serial << endl << "Received message on topic " << receivedTopic.c_str() << " with payload " << payload << endl;
    if (receivedTopic == "command")
  {
    mac[0] = atoi(&payload[0]);
    mac[1] = atoi(&payload[3]);
    mac[2] = atoi(&payload[6]);
    mac[3] = atoi(&payload[9]);
    mac[4] = atoi(&payload[12]);
    mac[5] = atoi(&payload[15]);
   }
 }
#endif

const char* ntpServer = "pool.ntp.org";
unsigned long epoch; 

unsigned long getTime() {
  time_t now;
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    //Serial.println("Failed to obtain time");
    return(0);
  }
  time(&now);
  return now;
}

const char* data = "Data requested below:";
static int callback(void *data, int argc, char **argv, char **azColName) {
 
  printf( "\nThis is what you have to do :\n" );
  for ( uint8_t i = 0; i < argc; i++ ){
    static uint8_t counter = 0;
 
 // change these values as you need
  const uint8_t counterMax   = 4;
  const uint8_t argcMax      = 11;
  const uint8_t argLengthMax = 12;
 
  // buffer to store all args
  static char args[argcMax][counterMax][argLengthMax];
 
  // prevent overflow..
  if ( argc > argcMax ){
    argc = argcMax;
  }
 
  // copy args into buffer
  for ( uint8_t i = 0; i < argc; i++ ){
    strcpy( args[i][counter], argv[i] );
  }
 
  // when the args buffer is filled, print values in the desired format
  if ( ++counter == counterMax ){
    printf( "[\n" );
    for ( uint8_t i = 0; i < argc; i++ ){
      printf( "[" );
    for ( uint8_t j = 0; j < counterMax; j++ ){
        printf( "%s", args[i][j] );
        if ( j != counterMax - 1 ){
          printf( "," );
        }
      }
      printf( "]" );
      if ( i != argc - 1 ){
        printf( "," );
      }
      printf( "\n" );
    }
    printf( "]\n" );
    counter = 0;
    }
  }
  return 0;
}
 
int db_open(const char *filename, sqlite3 **db) {
   rc = sqlite3_open(filename, db);
   if (rc) {
       Serial.printf("Can't open database: %s\n", sqlite3_errmsg(*db));
       return rc;
   } else {
       Serial.printf("Opened database successfully\n");
   }
   return rc;
}

char *zErrMsg = 0;
int db_exec(sqlite3 *db, const char *sql) {
   Serial.println(sql);
   long start = micros();
   int rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
   if (rc != SQLITE_OK) {
       Serial.printf("SQL error: %s\n", zErrMsg);
       sqlite3_free(zErrMsg);
   } else {
       Serial.printf("Operation done successfully\n");
   }
   Serial.print(F("Time taken in milliseconds: "));
   Serial.println((micros()-start)/1000);
   return rc;
}


void connectToWiFi();
void wifiEvent(WiFiEvent_t event);
void handleWiFiEvent(void *pvParameters);

QueueHandle_t wiFiEventQueue;

void setup() {
  Serial.begin(115200);
  delay(1000);
  log_i("Starting");
  wiFiEventQueue = xQueueCreate(7, sizeof(WiFiEvent_t));
  xTaskCreatePinnedToCore(handleWiFiEvent, "WiFi Event", 2000, NULL, 2, NULL, 0);
  WiFi.onEvent(wifiEvent);
  connectToWiFi();

  configTime(0, 0, ntpServer);
  epoch = getTime();
  Serial.print("Epoch Time: ");
  Serial.println(epoch);
  
  delay(1000);
  
#if ASYNCWEBSERVER
    webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) 
    {
    AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html_gz, sizeof(index_html_gz));
    response->addHeader("Content-Encoding", "gzip");
    request->send(response);
    });
    
    webserver.begin();
#endif
    
#if WEBSOCKETS
    WSserver.listen(wsport);
#endif
 
#if MQTT
    broker.begin();

  // ============= Client Subscribe ================
    myClient.setCallback(receivedMessage);
    myClient.subscribe(receivedTopic);
    myClient.subscribe(sentTopic);
#endif

#if FIRSTTIME   
   if (!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)) {
       Serial.println("Failed to mount file system");
       return;
   }

   // list LITTLEFS contents
   File root = LITTLEFS.open("/");
   if (!root) {
       Serial.println("- failed to open directory");
       return;
   }
   if (!root.isDirectory()) {
       Serial.println(" - not a directory");
       return;
   }
   File file = root.openNextFile();
   while (file) {
       if (file.isDirectory()) {
           Serial.print("  DIR : ");
           Serial.println(file.name());
       } else {
           Serial.print("  FILE: ");
           Serial.print(file.name());
           Serial.print("\tSIZE: ");
           Serial.println(file.size());
       }
       file = root.openNextFile();
   }

   // remove existing file so we start clean for this test.
   LITTLEFS.remove("/test1.db");
   LITTLEFS.remove("/test1.db-journal");

   // Create the db file before trying to open it.
   if (!LITTLEFS.exists("/test1.db")){
      File file = LITTLEFS.open("/test1.db", FILE_WRITE);   //  /littlefs is automatically added to the front 
      file.close();
   }

   // We also need to create the journal file.
   if (!LITTLEFS.exists("/test1.db-journal")){
      File file = LITTLEFS.open("/test1.db-journal", FILE_WRITE);   //  /littlefs is automatically added to the front 
      file.close();
   }

   sqlite3_initialize();

   if (db_open("/littlefs/test1.db", &db1))
       return;

   rc = db_exec(db1, "CREATE TABLE test1 (id INTEGER, Date, Time, Hour, Location, Voltage, RSSI, Temperature, Humidity, Pressure, Light);");
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
       }
       sqlite3_close(db1);       
#endif  
} // End of setup

void loop() {

#if MQTT
  broker.loop();     // Don't forget to add loop for every broker and clients
  myClient.loop();
#endif
  
#if WEBSOCKETS
  auto client = WSserver.accept();
  client.onMessage(handle_message);
  processData();
  static auto next=millis();               // The next line is an efficient delay() replacement
  if (millis() > next){next += 10000;}       //let's give time to SQLITE3 to prepare data requested from client.
  
  while (client.available()) {
  client.poll();
  }
#endif  
  
} // End of loop

void connectToWiFi() {
  const TickType_t xTicksToWait = pdMS_TO_TICKS(4000);
  while (WiFi.status() != WL_CONNECTED)
  {
    WiFi.disconnect();
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    WiFi.softAP(apSSID, apPassword, apChannel, hidden);
    esp_wifi_set_event_mask(WIFI_EVENT_MASK_NONE); // This line is must to activate probe request received event handler.
  
    vTaskDelay(xTicksToWait);
  }
}

void wifiEvent(WiFiEvent_t event) {
  xQueueSendToBackFromISR(wiFiEventQueue, &event, 0);
  if (triggerProcessData == 1) { 
    processData(); 
    triggerProcessData = 0; 
    } 
}

void handleWiFiEvent(void *pvParameters) {
  WiFiEvent_t event;
  IPAddress ipAddress;
  for (;;) {
    xQueueReceive(wiFiEventQueue, &event, portMAX_DELAY);
    switch (event) {
      case SYSTEM_EVENT_WIFI_READY:
        log_i("WiFi Ready");
        break;

      case SYSTEM_EVENT_STA_START:
        log_i("Station Start");
        break;

      case SYSTEM_EVENT_STA_DISCONNECTED:
        log_i("WiFi Disconnected");
        connectToWiFi();
        break;
      
      
      case SYSTEM_EVENT_STA_CONNECTED:
        log_i("WiFi Connected");
        break;

      case SYSTEM_EVENT_STA_GOT_IP:
        ipAddress = WiFi.localIP();
        log_i("Got IP Address: %d.%d.%d.%d", ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3]);
        break;
      
      case SYSTEM_EVENT_AP_START:
        ipAddress = WiFi.localIP();
        log_i("AP started with SSID: %s", apSSID);
        break;
           
      case SYSTEM_EVENT_AP_PROBEREQRECVED:
        log_i("Probe Received");
        WiFi.onEvent(probeRequest, SYSTEM_EVENT_AP_PROBEREQRECVED);

        break;
        
      default:
        log_i("WiFi Event: %d", (uint16_t )event);
        break;
    }
  }
}

void processData()
{
   epoch = getTime();
   
   if (!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)) {
       Serial.println("Failed to mount file system");
       return;
   }

   //Create the db file if it does not exist before trying to open it.
   if (!LITTLEFS.exists("/test1.db")){
      File file = LITTLEFS.open("/test1.db", FILE_WRITE);   //  /littlefs is automatically added to the front 
      file.close();
   }

   // We also need to create the journal file if it does not exist.
   if (!LITTLEFS.exists("/test1.db-journal")){
      File file = LITTLEFS.open("/test1.db-journal", FILE_WRITE);   //  /littlefs is automatically added to the front 
      file.close();
   }

   sqlite3_initialize();

   if (db_open("/littlefs/test1.db", &db1))
       return;
   
   insert = "insert into test1 values (";
  
               insert += epoch;
               insert += ", ";
               insert += 060321;
               insert += ", ";
               insert += 1535;
               insert += ", ";
               insert += 15;
               insert += ", ";
               insert += 26;
               insert += ", ";
               insert += 28;
               insert += ", ";
               insert += 30;
               insert += ", ";
               insert += 55;
               insert += ", ";
               insert += 65;
               insert += ", ";
               insert += 230;
               insert += ", ";
               insert += 83;
               insert += ")";
               Serial.println(insert);
              
   
   rc = db_exec(db1, insert.c_str());
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
  
   rc = db_exec(db1, sql.c_str());
   if (rc != SQLITE_OK) {
       sqlite3_close(db1);
       return;
   }
   
   sqlite3_close(db1);
   
   // list LITTLEFS contents
   File root = LITTLEFS.open("/");
   if (!root) {
       Serial.println("- failed to open directory");
       return;
   }
   if (!root.isDirectory()) {
       Serial.println(" - not a directory");
       return;
   }
   File file = root.openNextFile();
   while (file) {
       if (file.isDirectory()) {
           Serial.print("  DIR : ");
           Serial.println(file.name());
       } else {
           Serial.print("  FILE: ");
           Serial.print(file.name());
           Serial.print("\tSIZE: ");
           Serial.println(file.size());
       }
       file = root.openNextFile();
   }
 }

#if PROBEREQUESTS
void probeRequest(WiFiEvent_t event, WiFiEventInfo_t info) 
{
    Serial.print("Probe Received :  ");
    for (int i = 0; i < 6; i++) {
    Serial.printf("%02X", info.ap_probereqrecved.mac[i]);
    if (i < 5)Serial.print(":");
    }
    Serial.println();
     
     if (info.ap_probereqrecved.mac[0] == 6 || info.ap_probereqrecved.mac[0] == 16 || info.ap_probereqrecved.mac[0] == 26 || info.ap_probereqrecved.mac[0] == 36 || info.ap_probereqrecved.mac[0] == 46 || info.ap_probereqrecved.mac[0] == 56 || info.ap_probereqrecved.mac[0] == 66 || info.ap_probereqrecved.mac[0] == 76 || info.ap_probereqrecved.mac[0] == 86 || info.ap_probereqrecved.mac[0] == 96 || info.ap_probereqrecved.mac[0] == 106 || info.ap_probereqrecved.mac[0] == 116 || info.ap_probereqrecved.mac[0] == 126 || info.ap_probereqrecved.mac[0] == 136 || info.ap_probereqrecved.mac[0] == 146 || info.ap_probereqrecved.mac[0] == 156 || info.ap_probereqrecved.mac[0] == 166 || info.ap_probereqrecved.mac[0] == 176 || info.ap_probereqrecved.mac[0] == 186 || info.ap_probereqrecved.mac[0] == 196 || info.ap_probereqrecved.mac[0] == 206 || info.ap_probereqrecved.mac[0] == 216 || info.ap_probereqrecved.mac[0] == 226 || info.ap_probereqrecved.mac[0] == 236 || info.ap_probereqrecved.mac[0] == 246) // only accept data from certain devices.
       {
       
      //sendCommand();

      if (info.ap_probereqrecved.mac[1] == 06) 
      { // only accept data from device with voltage as a sensor type at byte 1.
               if (device == 06) { for (int i = 0; i < 4; i++) sensorTypes[i] = Livingroom[i];} 
               if (device == 16) { for (int i = 0; i < 4; i++) sensorTypes[i] = Kitchen[i];}
               if (device == 26) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom1[i];} 
               if (device == 36) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom2[i];}
               if (device == 46) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom3[i];} 
               if (device == 56) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bedroom4[i];}
               if (device == 66) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom1[i];} 
               if (device == 76) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom2[i];}
               if (device == 86) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom3[i];} 
               if (device == 96) { for (int i = 0; i < 4; i++) sensorTypes[i] = Bathroom4[i];}
               if (device == 106) { for (int i = 0; i < 4; i++) sensorTypes[i] = Laundry[i];} 
               if (device == 116) { for (int i = 0; i < 4; i++) sensorTypes[i] = Boiler[i];}
               if (device == 126) { for (int i = 0; i < 4; i++) sensorTypes[i] = Workshop[i];} 
               if (device == 136) { for (int i = 0; i < 4; i++) sensorTypes[i] = Garage[i];}
               if (device == 146) { for (int i = 0; i < 4; i++) sensorTypes[i] = Office[i];}
               if (device == 156) { for (int i = 0; i < 4; i++) sensorTypes[i] = Tank[i];} 
               if (device == 166) { for (int i = 0; i < 4; i++) sensorTypes[i] = Solar[i];}
               deviceStatus[0] = info.ap_probereqrecved.mac[2];
               deviceStatus[1] = info.ap_probereqrecved.mac[3];
               deviceStatus[2] = info.ap_probereqrecved.mac[4];
               deviceStatus[3] = info.ap_probereqrecved.mac[5];
      } else {

      device = info.ap_probereqrecved.mac[0];
               
      voltage = info.ap_probereqrecved.mac[1];
      voltage = voltage * 2 / 100;
                  
      sensorValues[0] = info.ap_probereqrecved.mac[2];
      sensorValues[1] = info.ap_probereqrecved.mac[3];
      sensorValues[2] = info.ap_probereqrecved.mac[4];
      sensorValues[3] = info.ap_probereqrecved.mac[5];
              
      }

      if (voltage > 2.50 && voltage < 3.60) 
      {
      
      sprintf (str, "{");
      sprintf (s, "\"%s\":\"%i\"", "Location", device);    strcat (str, s);
      sprintf (s, ",\"%s\":\"%.2f\"", "Voltage", voltage);    strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[0], sensorValues[0]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[1], sensorValues[1]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[2], sensorValues[2]); strcat (str, s);
      sprintf (s, ",\"%i\":\"%i\"", sensorTypes[3], sensorValues[3]); strcat (str, s);
      sprintf (s, "}"); strcat (str, s);
              
      Serial.println();
      Serial.println("Following ## Sensor Values ## receiced from remote device  & published via MQTT: ");
      Serial.println(str);
      Serial.println();
     
      myClient.publish("sensor", str);
      
      if (voltage < 2.50) {      // if voltage of battery gets to low, print the warning below.
         //myClient.publish("Warning/Battery Low", location);
       }
     }

   if (info.ap_probereqrecved.mac[3] == apChannel) {
     
     sprintf (str, "{");
     sprintf (s, "\"%s\":\"%i\"", "Location", device);    strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "RSSI", info.ap_probereqrecved.rssi); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "MODE", deviceStatus[0]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "CHANNEL", deviceStatus[1]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "IP", deviceStatus[2]); strcat (str, s);
     sprintf (s, ",\"%s\":\"%i\"", "Sleeptime", deviceStatus[3]); strcat (str, s);
     sprintf (s, "}"); strcat (str, s);
                           
     Serial.println();
     Serial.println("Following ## Device Status ## receiced from remote device & published via MQTT: ");
     Serial.println(str);
     Serial.println();
     myClient.publish("device", str);
     
     processData();
    }
  }
 }
#endif

@Danois90 Diagnosis and solution you suggested seems to solve the problem.

Thank you for your help resolving this issue.

I see a few:

  • You're still calling processData() from the event handler context rather than only from the handleWiFiEvent FreeRTOS task.

  • You added 'WiFi.onEvent(probeRequest, SYSTEM_EVENT_AP_PROBEREQRECVED)' to a case inside the switch statement in handleWiFiEvent. Why? That just makes your code the equivalent of what you originally had.

  • Might want to move handleWiFiEvent to Core 1.

  • Might need to adjust stack space allocated to handleWiFiEvent and its priority.

Regardless, the @Danois90 solution is likely best for you since your code is in the Arduino single-task paradigm. You'd need to rewrite it to really take advantage of FreeRTOS's multi-tasking capabilities.

1 Like

@gfvalvo Thank you. I learned some things new from code you provided.

If you are happy with your solution and it works for you, that's great. But I would really encourage you to take advantage of all the great features in the ESP32 and FreeRTOS. There are intro videos on YT (I have not seen them), which may be something for you. You should also bookmark this page for future learning.