GPIO Viewer update from 1.0.7 to 1.5.0

This commit is contained in:
Theo Arends 2024-01-27 23:58:00 +01:00
parent 1e7bbfcc00
commit af9d4cadd8
6 changed files with 273 additions and 32 deletions

View File

@ -0,0 +1,25 @@
/////////////////////////////////////////////////////////////////////
// compressed by tools/unishox/compress-html-uncompressed.py
/////////////////////////////////////////////////////////////////////
const size_t HTTP_GV_PAGE_SIZE = 465;
const char HTTP_GV_PAGE_COMPRESSED[] PROGMEM = "\x3D\x0F\xE1\x10\x98\x1D\x19\x0C\x64\x85\x50\xD0\x8F\xC3\xD0\x55\x0D\x09\x05\x7C"
"\x3C\x7C\x3E\xDF\x1F\x67\xE1\xE8\x29\xD8\x87\xE1\xE9\x5B\x41\x33\xF0\xFA\xF2\x3A"
"\xD1\x0F\x10\xC2\xD2\xC4\x46\x7A\xC7\xDF\xCF\x43\xB0\x10\x6A\x1E\x83\x5D\x5A\x0C"
"\x55\xFF\xCE\x8F\x87\xD9\x0B\x2A\x2B\x23\x07\x59\xCF\x9F\x67\xE1\xE8\x43\xAF\xCD"
"\x0A\xFB\x30\x7C\x3E\xCF\xAF\x1F\x67\xE1\xE8\x16\xF1\xA2\xFB\x08\xF8\x7D\xE8\x79"
"\xC7\xD8\x21\x57\x31\x66\x7A\x1E\x71\xD3\x43\xC3\xEC\x10\xB2\x6E\xB1\xAC\xF8\x7D"
"\x99\xEB\x1F\x19\x9F\xA3\xED\x07\x9D\x4F\xA8\xF8\x7D\x8F\xE8\x94\x28\xF8\x23\x33"
"\xD0\xD9\xD6\x3F\xA2\x50\xA3\xA9\x6F\x6D\x6D\x84\x75\xF8\x3B\x09\x9F\x0E\x43\xA3"
"\x3E\xCF\xC3\xD0\xBC\x1F\xF4\x65\x2A\x2B\x32\x18\xCF\x87\xD8\xDC\x10\x58\x4C\xFB"
"\x41\xFF\x3D\xEC\xFE\x8F\x6F\x2F\x7C\x33\xE1\xF6\x43\xC4\x30\xB4\xB0\x10\x78\x25"
"\x23\x31\x6C\xE8\x6B\xF1\xF6\x7E\x1E\x87\x60\x20\xE2\xC0\x8F\xC0\x47\xA8\xC8\x27"
"\xE1\x4D\xD0\x24\xE3\xE0\x83\xC0\xD5\xFB\xCE\xBC\x76\x0D\xBD\xE3\xA0\x7E\xF1\xF6"
"\x7E\x1E\x87\x60\x20\xF1\x1C\x3B\x04\x32\x3F\x0F\x41\x34\xCD\x68\x87\xC3\xEE\xC6"
"\x0C\x3E\xCF\xC3\xD0\xEC\x13\x4C\xC1\x0F\x79\x3F\x07\xF7\x84\xC1\xF3\xA0\xF0\xCD"
"\xC3\xF7\xE7\x55\xBC\x3D\xE4\x7C\x47\xB7\x46\x1E\x67\xD9\xF5\xE3\xEC\xEA\x19\x9F"
"\xA3\xCC\xFB\x3E\x84\x3E\xCE\xA3\x1F\x6C\xBC\x68\xE8\x31\x45\xFB\x1A\x79\x9F\x67"
"\xD0\x88\x8D\x08\x71\xF6\x7B\x8F\x2A\x01\x8B\xC0\x49\xD8\x08\x3A\x49\xD8\x2A\x2B"
"\x86\x84\x7E\x1B";
#define HTTP_GV_PAGE Decompress(HTTP_GV_PAGE_COMPRESSED,HTTP_GV_PAGE_SIZE).c_str()

View File

@ -0,0 +1,24 @@
const char HTTP_GV_PAGE[] PROGMEM =
"<!DOCTYPE html>"
"<html lang='en'>"
"<head>"
"<title>%s - GPIO Viewer</title>" // SettingsTextEscaped(SET_DEVICENAME).c_str()
"<meta charset='UTF-8'>"
"<base href='%s'>" // GV_BASE_URL
"<link rel='icon' href='favicon.ico'>"
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
"<script type='module' crossorigin src='GPIOViewerVue.js'>"
"</script>"
"<link rel='stylesheet' crossorigin href='assets/main.css'>"
"</head>"
"<body>"
"<div id='app'></div>"
"<script>"
"window.gpio_settings = {"
"ip:'%s'," // WiFi.localIP().toString().c_str()
"port:'%d'," // GV_PORT
"freeSketchRam:'%d KB'" // ESP_getFreeSketchSpace() / 1024
"};"
"</script>"
"</body>"
"</html>";

View File

@ -470,8 +470,7 @@
#define USE_ENHANCED_GUI_WIFI_SCAN // Enable Wi-Fi scan output with BSSID (+0k5 code) #define USE_ENHANCED_GUI_WIFI_SCAN // Enable Wi-Fi scan output with BSSID (+0k5 code)
// #define USE_WEBSEND_RESPONSE // Enable command WebSend response message (+1k code) // #define USE_WEBSEND_RESPONSE // Enable command WebSend response message (+1k code)
// #define USE_WEBGETCONFIG // Enable restoring config from external webserver (+0k6) // #define USE_WEBGETCONFIG // Enable restoring config from external webserver (+0k6)
// #define USE_GPIO_VIEWER // Enable GPIO Viewer to see realtime GPIO states (+4k code) // #define USE_GPIO_VIEWER // Enable GPIO Viewer to see realtime GPIO states (+6k code)
// #define GV_BASE_URL "https://thelastoutpostworkshop.github.io/microcontroller_devkit/gpio_viewer/assets/"
// #define GV_SAMPLING_INTERVAL 100 // [GvSampling] milliseconds - Use Tasmota Scheduler (100) or Ticker (20..99,101..1000) // #define GV_SAMPLING_INTERVAL 100 // [GvSampling] milliseconds - Use Tasmota Scheduler (100) or Ticker (20..99,101..1000)
#define USE_EMULATION_HUE // Enable Hue Bridge emulation for Alexa (+14k code, +2k mem common) #define USE_EMULATION_HUE // Enable Hue Bridge emulation for Alexa (+14k code, +2k mem common)
#define USE_EMULATION_WEMO // Enable Belkin WeMo emulation for Alexa (+6k code, +2k mem common) #define USE_EMULATION_WEMO // Enable Belkin WeMo emulation for Alexa (+6k code, +2k mem common)

View File

@ -501,6 +501,10 @@ uint32_t ESP_getFreeSketchSpace(void) {
return ESP.getFreeSketchSpace(); return ESP.getFreeSketchSpace();
} }
uint32_t ESP_getHeapSize(void) {
return ESP.getHeapSize();
}
uint32_t ESP_getFreeHeap(void) { uint32_t ESP_getFreeHeap(void) {
// ESP_getFreeHeap() returns also IRAM which we don't use // ESP_getFreeHeap() returns also IRAM which we don't use
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); return heap_caps_get_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
@ -558,6 +562,18 @@ uint8_t* FlashDirectAccess(void) {
return data; return data;
} }
uint32_t ESP_getPsramSize(void) {
return ESP.getPsramSize();
}
uint32_t ESP_getFreePsram(void) {
return ESP.getFreePsram();
}
uint32_t ESP_getMaxAllocPsram(void) {
return ESP.getMaxAllocPsram();
}
extern "C" { extern "C" {
#if ESP_IDF_VERSION_MAJOR >= 5 #if ESP_IDF_VERSION_MAJOR >= 5
// bool IRAM_ATTR __attribute__((pure)) esp_psram_is_initialized(void) // bool IRAM_ATTR __attribute__((pure)) esp_psram_is_initialized(void)
@ -948,6 +964,18 @@ String GetCodeCores(void) {
#endif #endif
} }
uint32_t ESP_getChipCores(void) {
return ESP.getChipCores();
}
uint32_t ESP_getChipRevision(void) {
return ESP.getChipRevision();
}
String ESP_getEfuseMac(void) {
return String(ESP.getEfuseMac());
}
/*********************************************************************************************\ /*********************************************************************************************\
* High entropy hardware random generator * High entropy hardware random generator
* Thanks to DigitalAlchemist * Thanks to DigitalAlchemist

View File

@ -85,6 +85,10 @@ uint32_t ESP_getSketchSize(void) {
return ESP.getSketchSize(); return ESP.getSketchSize();
} }
uint32_t ESP_getHeapSize(void) {
return 32768; // Using default heap (No PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED)
}
uint32_t ESP_getFreeHeap(void) { uint32_t ESP_getFreeHeap(void) {
return ESP.getFreeHeap(); return ESP.getFreeHeap();
} }
@ -98,6 +102,10 @@ float ESP_getFreeHeap1024(void) {
} }
*/ */
uint32_t ESP_getMaxAllocHeap(void) {
return ESP.getFreeHeap();
}
uint32_t ESP_getFlashChipId(void) { uint32_t ESP_getFlashChipId(void) {
return ESP.getFlashChipId(); return ESP.getFlashChipId();
} }
@ -110,6 +118,18 @@ uint32_t ESP_getFlashChipSize(void) {
return ESP.getFlashChipSize(); return ESP.getFlashChipSize();
} }
uint32_t ESP_getPsramSize(void) {
return 0;
}
uint32_t ESP_getFreePsram(void) {
return 0;
}
uint32_t ESP_getMaxAllocPsram(void) {
return 0;
}
void ESP_Restart(void) { void ESP_Restart(void) {
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0 // ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP.reset(); ESP.reset();
@ -197,6 +217,48 @@ String GetCodeCores(void) {
return F(""); return F("");
} }
uint32_t ESP_getChipCores(void) {
return 1;
}
uint32_t ESP_getChipRevision(void) {
return 1;
}
String ESP_getEfuseMac(void) {
uint32_t mac0 = *(uint32_t*)(0x3FF00050);
uint32_t mac1 = *(uint32_t*)(0x3FF00054);
uint32_t mac3 = *(uint32_t*)(0x3FF0005C);
uint32_t mach = 0;
uint32_t macl = 0;
if (mac3 != 0) {
mach = ((mac3 >> 16) & 0xFF) << 16;
mach |= ((mac3 >> 8) & 0xFF) << 8;
mach |= mac3 & 0xFF;
}
else if (((mac1 >> 16) & 0xFF) == 0) {
mach = 0x18FE34;
}
else if (((mac1 >> 16) & 0xFF) == 1) {
mach = 0xACD074;
}
String macStr = "";
if (mach > 0) {
macl = ((mac1 >> 8) & 0xFF) << 16;
macl |= (mac1 & 0xFF) << 8;
macl |= (mac0 >> 24) & 0xFF;
uint64_t maca = ((uint64_t)mach << 24) | macl;
// Need uint64ToString with base 10 as ESP8266 WStrings does not support uint64_t
while (maca > 0) {
macStr = String((uint32_t)(maca % 10), 10) + macStr;
maca /= 10;
}
}
return String(macStr);
}
/*********************************************************************************************\ /*********************************************************************************************\
* High entropy hardware random generator * High entropy hardware random generator
* Thanks to DigitalAlchemist * Thanks to DigitalAlchemist

View File

@ -17,6 +17,15 @@
#define XDRV_121 121 #define XDRV_121 121
//#define GV_INPUT_DETECTION // Report type of digital input
#define GV_USE_ESPINFO // Provide ESP info
#ifdef ESP32
#ifndef GV_USE_ESPINFO
#define GV_USE_ESPINFO // Provide ESP info
#endif
#endif
#ifndef GV_PORT #ifndef GV_PORT
#define GV_PORT 5557 // SSE webserver port #define GV_PORT 5557 // SSE webserver port
#endif #endif
@ -27,29 +36,15 @@
#define GV_KEEP_ALIVE 1000 // milliseconds - If no activity after this do a heap size event anyway #define GV_KEEP_ALIVE 1000 // milliseconds - If no activity after this do a heap size event anyway
#ifndef GV_BASE_URL #ifndef GV_BASE_URL
#define GV_BASE_URL "https://thelastoutpostworkshop.github.io/microcontroller_devkit/gpio_viewer/assets/" #define GV_BASE_URL "https://thelastoutpostworkshop.github.io/microcontroller_devkit/gpio_viewer_1_5/"
#endif #endif
/*
#ifdef ESP8266
#ifndef GV_BASE_URL
#undef GV_BASE_URL // Fix compiler warning
#define GV_BASE_URL "https://ota.tasmota.com/tasmota/gpio_viewer/assets/"
#endif
#endif // ESP8266
#ifdef ESP32
#ifndef GV_BASE_URL
#undef GV_BASE_URL // Fix compiler warning
#define GV_BASE_URL "https://ota.tasmota.com/tasmota32/gpio_viewer/assets/"
#endif
#endif // ESP32
*/
const char *GVRelease = "1.0.7"; const char *GVRelease = "1.5.0";
#ifdef USE_UNISHOX_COMPRESSION #ifdef USE_UNISHOX_COMPRESSION
#include "./html_compressed/HTTP_GV_PAGE.h" #include "./html_compressed/HTTP_GV_PAGE_150.h"
#else #else
#include "./html_uncompressed/HTTP_GV_PAGE.h" #include "./html_uncompressed/HTTP_GV_PAGE_150.h"
#endif #endif
const char HTTP_GV_EVENT[] PROGMEM = const char HTTP_GV_EVENT[] PROGMEM =
@ -62,7 +57,12 @@ const char HTTP_GV_EVENT[] PROGMEM =
enum GVPinTypes { enum GVPinTypes {
GV_DigitalPin = 0, GV_DigitalPin = 0,
GV_PWMPin = 1, GV_PWMPin = 1,
GV_AnalogPin = 2 GV_AnalogPin = 2,
#ifdef GV_INPUT_DETECTION
GV_InputPin = 3,
GV_InputPullUp = 4,
GV_InputPullDn = 5
#endif // GV_INPUT_DETECTION
}; };
struct { struct {
@ -78,6 +78,26 @@ struct {
bool sse_ready; bool sse_ready;
} GV; } GV;
#ifdef GV_INPUT_DETECTION
int GetPinMode(uint8_t pin) {
#ifdef ESP8266
if (pin > MAX_GPIO_PIN -2) { return -1; } // Skip GPIO16 and Analog0
#endif // ESP8266
#ifdef ESP32
if (pin > MAX_GPIO_PIN) { return -1; }
#endif // ESP32
uint32_t bit = digitalPinToBitMask(pin);
uint32_t port = digitalPinToPort(pin);
volatile uint32_t *reg = portModeRegister(port);
if (*reg & bit) { return OUTPUT; } // ESP8266 = 0x01, ESP32 = 0x03
volatile uint32_t *out = portOutputRegister(port);
return ((*out & bit) ? INPUT_PULLUP : INPUT); // ESP8266 = 0x02 : 0x00, ESP32 = 0x05 : x01
}
#endif // GV_INPUT_DETECTION
void GVStop(void) { void GVStop(void) {
GV.sse_ready = false; GV.sse_ready = false;
GV.ticker.detach(); GV.ticker.detach();
@ -100,6 +120,9 @@ void GVBegin(void) {
GV.WebServer->on("/", GVHandleRoot); GV.WebServer->on("/", GVHandleRoot);
GV.WebServer->on("/release", GVHandleRelease); GV.WebServer->on("/release", GVHandleRelease);
GV.WebServer->on("/free_psram", GVHandleFreePSRam); GV.WebServer->on("/free_psram", GVHandleFreePSRam);
GV.WebServer->on("/sampling", GVHandleSampling);
GV.WebServer->on("/espinfo", GVHandleEspInfo);
GV.WebServer->on("/partition", GVHandlePartition);
GV.WebServer->on("/events", GVHandleEvents); GV.WebServer->on("/events", GVHandleEvents);
GV.WebServer->begin(); GV.WebServer->begin();
@ -112,24 +135,21 @@ void GVHandleRoot(void) {
char* content = ext_snprintf_malloc_P(HTTP_GV_PAGE, char* content = ext_snprintf_malloc_P(HTTP_GV_PAGE,
SettingsTextEscaped(SET_DEVICENAME).c_str(), SettingsTextEscaped(SET_DEVICENAME).c_str(),
GV_BASE_URL, GV_BASE_URL,
GV_PORT,
WiFi.localIP().toString().c_str(), WiFi.localIP().toString().c_str(),
WiFi.localIP().toString().c_str(), GV_PORT, GV_PORT,
GV.sampling,
#ifdef ESP32
ESP.getPsramSize() / 1024,
#else
0,
#endif // ESP32
ESP_getFreeSketchSpace() / 1024); ESP_getFreeSketchSpace() / 1024);
if (content == nullptr) { return; } // Avoid crash if (content == nullptr) { return; } // Avoid crash
GV.WebServer->send_P(200, "text/html", content); GV.WebServer->send_P(200, "text/html", content);
free(content); free(content);
} }
void GVWebserverSendJson(String &jsonResponse) {
GV.WebServer->send(200, "application/json", jsonResponse);
}
void GVHandleRelease(void) { void GVHandleRelease(void) {
String jsonResponse = "{\"release\":\"" + String(GVRelease) + "\"}"; String jsonResponse = "{\"release\":\"" + String(GVRelease) + "\"}";
GV.WebServer->send(200, "application/json", jsonResponse); GVWebserverSendJson(jsonResponse);
} }
void GVHandleFreePSRam(void) { void GVHandleFreePSRam(void) {
@ -140,7 +160,85 @@ void GVHandleFreePSRam(void) {
} else } else
#endif #endif
jsonResponse += "No PSRAM\"}"; jsonResponse += "No PSRAM\"}";
GV.WebServer->send(200, "application/json", jsonResponse); GVWebserverSendJson(jsonResponse);
}
void GVHandleSampling(void) {
String jsonResponse = "{\"sampling\": \"" + String(GV.sampling) + "\"}";
GVWebserverSendJson(jsonResponse);
}
void GVHandleEspInfo(void) {
#ifdef GV_USE_ESPINFO
const FlashMode_t flashMode = ESP.getFlashChipMode(); // enum
String jsonResponse = "{\"chip_model\":\"" + GetDeviceHardware();
jsonResponse += "\",\"cores_count\":\"" + String(ESP_getChipCores());
jsonResponse += "\",\"chip_revision\":\"" + String(ESP_getChipRevision());
jsonResponse += "\",\"cpu_frequency\":\"" + String(ESP.getCpuFreqMHz());
jsonResponse += "\",\"cycle_count\":" + String(ESP.getCycleCount());
jsonResponse += ",\"mac\":\"" + ESP_getEfuseMac();
jsonResponse += "\",\"flash_mode\":" + String(flashMode);
#ifdef ESP8266
jsonResponse += ",\"flash_chip_size\":" + String(ESP.getFlashChipRealSize());
#else
jsonResponse += ",\"flash_chip_size\":" + String(ESP.getFlashChipSize());
#endif
jsonResponse += ",\"flash_chip_speed\":" + String(ESP.getFlashChipSpeed());
jsonResponse += ",\"heap_size\":" + String(ESP_getHeapSize());
jsonResponse += ",\"heap_max_alloc\":" + String(ESP_getMaxAllocHeap());
jsonResponse += ",\"psram_size\":" + String(ESP_getPsramSize());
jsonResponse += ",\"free_psram\":" + String(ESP_getFreePsram());
jsonResponse += ",\"psram_max_alloc\":" + String(ESP_getMaxAllocPsram());
jsonResponse += ",\"free_heap\":" + String(ESP_getFreeHeap());
jsonResponse += ",\"up_time\":\"" + String(millis());
jsonResponse += "\",\"sketch_size\":" + String(ESP_getSketchSize());
jsonResponse += ",\"free_sketch\":" + String(ESP_getFreeSketchSpace());
jsonResponse += "}";
#else
String jsonResponse = "{\"chip_model\":\"" + GetDeviceHardware() + "\"}";
#endif // GV_USE_ESPINFO
GVWebserverSendJson(jsonResponse);
}
void GVHandlePartition(void) {
String jsonResponse = "["; // Start of JSON array
#ifdef ESP32
bool firstEntry = true; // Used to format the JSON array correctly
esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);
// esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
// Loop through partitions
while (iter != NULL) {
const esp_partition_t *partition = esp_partition_get(iter);
// Add comma before the next entry if it's not the first
if (!firstEntry)
{
jsonResponse += ",";
}
firstEntry = false;
// Append partition information in JSON format
jsonResponse += "{";
jsonResponse += "\"label\":\"" + String(partition->label) + "\",";
jsonResponse += "\"type\":" + String(partition->type) + ",";
jsonResponse += "\"subtype\":" + String(partition->subtype) + ",";
jsonResponse += "\"address\":\"0x" + String(partition->address, HEX) + "\",";
jsonResponse += "\"size\":" + String(partition->size);
jsonResponse += "}";
// Move to next partition
iter = esp_partition_next(iter);
}
// Clean up the iterator
esp_partition_iterator_release(iter);
#endif // ESP32
jsonResponse += "]"; // End of JSON array
GVWebserverSendJson(jsonResponse);
} }
void GVHandleEvents(void) { void GVHandleEvents(void) {
@ -240,7 +338,6 @@ void GVMonitorTask(void) {
else { else {
// Read digital GPIO // Read digital GPIO
pintype = GV_DigitalPin;
int value = digitalRead(pin); int value = digitalRead(pin);
originalValue = value; originalValue = value;
if (value == 1) { if (value == 1) {
@ -248,6 +345,12 @@ void GVMonitorTask(void) {
// } else { // } else {
// currentState = 0; // currentState = 0;
} }
#ifdef GV_INPUT_DETECTION
int pin_mode = GetPinMode(pin);
pintype = (INPUT == pin_mode) ? GV_InputPin : (INPUT_PULLUP == pin_mode) ? GV_InputPullUp : GV_DigitalPin;
#else
pintype = GV_DigitalPin;
#endif
} }
if (originalValue != GV.lastPinStates[pin]) { if (originalValue != GV.lastPinStates[pin]) {