mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-19 16:56:34 +00:00
Partition Wizard can be loaded dynamically (#19980)
* Partition Wizard can be loaded dynamically * Centralize config * Don't display duplicate buttons * Fix test
This commit is contained in:
parent
e81ec38661
commit
de1b5929b8
@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- NeoPool sensor delta trigger (command ``NPTelePeriod``) (#19973)
|
- NeoPool sensor delta trigger (command ``NPTelePeriod``) (#19973)
|
||||||
- NeoPool store settings on unified file system (#19973)
|
- NeoPool store settings on unified file system (#19973)
|
||||||
- NeoPool command ``NPBoost`` (#19973)
|
- NeoPool command ``NPBoost`` (#19973)
|
||||||
|
- Partition Wizard can be loaded dynamically
|
||||||
|
|
||||||
### Breaking Changed
|
### Breaking Changed
|
||||||
|
|
||||||
|
@ -596,6 +596,24 @@ void load_global_info(bvm *vm, void *fp)
|
|||||||
be_global_release_space(vm);
|
be_global_release_space(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bclosure* be_bytecode_load_from_fs(bvm *vm, void *fp)
|
||||||
|
{
|
||||||
|
int version = load_head(fp);
|
||||||
|
if (version == BYTECODE_VERSION) {
|
||||||
|
bclosure *cl = be_newclosure(vm, 0);
|
||||||
|
var_setclosure(vm->top, cl);
|
||||||
|
be_stackpush(vm);
|
||||||
|
load_global_info(vm, fp);
|
||||||
|
load_proto(vm, fp, &cl->proto, -1, version);
|
||||||
|
be_stackpop(vm, 2); /* pop the closure and list */
|
||||||
|
be_fclose(fp);
|
||||||
|
return cl;
|
||||||
|
}
|
||||||
|
bytecode_error(vm, be_pushfstring(vm,
|
||||||
|
"invalid bytecode version."));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bclosure* be_bytecode_load(bvm *vm, const char *filename)
|
bclosure* be_bytecode_load(bvm *vm, const char *filename)
|
||||||
{
|
{
|
||||||
void *fp = be_fopen(filename, "rb");
|
void *fp = be_fopen(filename, "rb");
|
||||||
@ -603,22 +621,9 @@ bclosure* be_bytecode_load(bvm *vm, const char *filename)
|
|||||||
bytecode_error(vm, be_pushfstring(vm,
|
bytecode_error(vm, be_pushfstring(vm,
|
||||||
"can not open file '%s'.", filename));
|
"can not open file '%s'.", filename));
|
||||||
} else {
|
} else {
|
||||||
int version = load_head(fp);
|
return be_bytecode_load_from_fs(vm, fp);
|
||||||
if (version == BYTECODE_VERSION) {
|
|
||||||
bclosure *cl = be_newclosure(vm, 0);
|
|
||||||
var_setclosure(vm->top, cl);
|
|
||||||
be_stackpush(vm);
|
|
||||||
load_global_info(vm, fp);
|
|
||||||
load_proto(vm, fp, &cl->proto, -1, version);
|
|
||||||
be_stackpop(vm, 2); /* pop the closure and list */
|
|
||||||
be_fclose(fp);
|
|
||||||
return cl;
|
|
||||||
}
|
|
||||||
bytecode_error(vm, be_pushfstring(vm,
|
|
||||||
"invalid bytecode version '%s'.", filename));
|
|
||||||
}
|
}
|
||||||
bytecode_error(vm, be_pushfstring(vm,
|
|
||||||
"invalid bytecode file '%s'.", filename));
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* BE_USE_BYTECODE_LOADER */
|
#endif /* BE_USE_BYTECODE_LOADER */
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
void be_bytecode_save(bvm *vm, const char *filename, bproto *proto);
|
void be_bytecode_save(bvm *vm, const char *filename, bproto *proto);
|
||||||
bclosure* be_bytecode_load(bvm *vm, const char *filename);
|
bclosure* be_bytecode_load(bvm *vm, const char *filename);
|
||||||
|
bclosure* be_bytecode_load_from_fs(bvm *vm, void *fp);
|
||||||
bbool be_bytecode_check(const char *path);
|
bbool be_bytecode_check(const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
BIN
tasmota/berry/modules/Partition_Wizard/partition_wizard.bec
Normal file
BIN
tasmota/berry/modules/Partition_Wizard/partition_wizard.bec
Normal file
Binary file not shown.
@ -1141,6 +1141,8 @@
|
|||||||
// Note that only one cipher is enabled: ECDHE_RSA_WITH_AES_128_GCM_SHA256 which is very commonly used and highly secure
|
// Note that only one cipher is enabled: ECDHE_RSA_WITH_AES_128_GCM_SHA256 which is very commonly used and highly secure
|
||||||
#define USE_BERRY_WEBCLIENT_USERAGENT "TasmotaClient" // default user-agent used, can be changed with `wc.set_useragent()`
|
#define USE_BERRY_WEBCLIENT_USERAGENT "TasmotaClient" // default user-agent used, can be changed with `wc.set_useragent()`
|
||||||
#define USE_BERRY_WEBCLIENT_TIMEOUT 2000 // Default timeout in milliseconds
|
#define USE_BERRY_WEBCLIENT_TIMEOUT 2000 // Default timeout in milliseconds
|
||||||
|
#define USE_BERRY_PARTITION_WIZARD // Add a button to dynamically load the Partion Wizard from a bec file online (+1.3KB Flash)
|
||||||
|
#define USE_BERRY_PARTITION_WIZARD_URL "http://ota.tasmota.com/tapp/partition_wizard.bec"
|
||||||
#define USE_BERRY_TCPSERVER // Enable TCP socket server (+0.6k)
|
#define USE_BERRY_TCPSERVER // Enable TCP socket server (+0.6k)
|
||||||
// #define USE_BERRY_ULP // Enable ULP (Ultra Low Power) support (+4.9k)
|
// #define USE_BERRY_ULP // Enable ULP (Ultra Low Power) support (+4.9k)
|
||||||
// Berry crypto extensions below:
|
// Berry crypto extensions below:
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef USE_ZIGBEE
|
#if defined(USE_ZIGBEE) || defined(USE_BERRY)
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#include <vfs_api.h>
|
#include <vfs_api.h>
|
||||||
@ -43,6 +43,12 @@ public:
|
|||||||
_seek = 0;
|
_seek = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlashFileImpl(const void* buf, size_t len) {
|
||||||
|
_buf = (const char*)buf;
|
||||||
|
_len = len;
|
||||||
|
_seek = 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~FlashFileImpl() {}
|
virtual ~FlashFileImpl() {}
|
||||||
|
|
||||||
size_t write(const uint8_t *buf, size_t size) {
|
size_t write(const uint8_t *buf, size_t size) {
|
||||||
|
@ -93,6 +93,9 @@ public:
|
|||||||
int32_t timeout = 0; // Berry heartbeat timeout, preventing code to run for too long. `0` means not enabled
|
int32_t timeout = 0; // Berry heartbeat timeout, preventing code to run for too long. `0` means not enabled
|
||||||
bool rules_busy = false; // are we already processing rules, avoid infinite loop
|
bool rules_busy = false; // are we already processing rules, avoid infinite loop
|
||||||
bool web_add_handler_done = false; // did we already sent `web_add_handler` event
|
bool web_add_handler_done = false; // did we already sent `web_add_handler` event
|
||||||
|
#ifdef USE_BERRY_PARTITION_WIZARD
|
||||||
|
bool partition_wizard_loaded = false; // did we already load Parition_Wizard
|
||||||
|
#endif // USE_BERRY_PARTITION_WIZARD
|
||||||
bool autoexec_done = false; // do we still need to load 'autoexec.be'
|
bool autoexec_done = false; // do we still need to load 'autoexec.be'
|
||||||
bool repl_active = false; // is REPL running (activates log recording)
|
bool repl_active = false; // is REPL running (activates log recording)
|
||||||
// output log is stored as a LinkedList of buffers
|
// output log is stored as a LinkedList of buffers
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
#define XDRV_52 52
|
#define XDRV_52 52
|
||||||
|
|
||||||
#include <berry.h>
|
#include <berry.h>
|
||||||
|
extern "C" {
|
||||||
|
#include "be_bytecode.h"
|
||||||
|
#include "be_var.h"
|
||||||
|
}
|
||||||
#include "berry_tasmota.h"
|
#include "berry_tasmota.h"
|
||||||
#ifdef USE_MATTER_DEVICE
|
#ifdef USE_MATTER_DEVICE
|
||||||
#include "berry_matter.h"
|
#include "berry_matter.h"
|
||||||
@ -757,6 +761,85 @@ void HandleBerryConsole(void)
|
|||||||
WSContentStop();
|
WSContentStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display a Button to dynamically load the Partition Wizard
|
||||||
|
void HandleBerryPartiionWizardLoaderButton(void) {
|
||||||
|
bvm * vm = berry.vm;
|
||||||
|
static const char PARTITION_WIZARD_NAME[] = "partition_wizard";
|
||||||
|
if (!berry.partition_wizard_loaded) {
|
||||||
|
if (be_global_find(vm, be_newstr(vm, PARTITION_WIZARD_NAME)) < 0) { // the global name `partition_wizard` doesn't exist
|
||||||
|
WSContentSend_P("<form id=but_part_mgr style='display: block;' action='tapp' method='get'><input type='hidden' name='n' value='Partition_Wizard'/><button>[Load Partition Wizard]</button></form><p></p>");
|
||||||
|
} else {
|
||||||
|
berry.partition_wizard_loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleBerryPartitionWizardLoader(void) {
|
||||||
|
if (BerryBECLoader(USE_BERRY_PARTITION_WIZARD_URL)) {
|
||||||
|
// All good, redirect
|
||||||
|
Webserver->sendHeader("Location", "/part_wiz", true);
|
||||||
|
Webserver->send(302, "text/plain", "");
|
||||||
|
berry.partition_wizard_loaded = true;
|
||||||
|
} else {
|
||||||
|
Webserver->sendHeader("Location", "/mn?", true);
|
||||||
|
Webserver->send(302, "text/plain", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if successful
|
||||||
|
bool BerryBECLoader(const char * url) {
|
||||||
|
bvm *vm = berry.vm;
|
||||||
|
|
||||||
|
HTTPClientLight cl;
|
||||||
|
cl.setUserAgent(USE_BERRY_WEBCLIENT_USERAGENT);
|
||||||
|
cl.setConnectTimeout(USE_BERRY_WEBCLIENT_TIMEOUT); // set default timeout
|
||||||
|
cl.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||||
|
|
||||||
|
if (!cl.begin(url)) {
|
||||||
|
AddLog(LOG_LEVEL_INFO, "BRY: unable to load URL '%s'", url);
|
||||||
|
// cl.end();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t http_connect_time = millis();
|
||||||
|
int32_t httpCode = cl.GET();
|
||||||
|
if (httpCode != 200) {
|
||||||
|
AddLog(LOG_LEVEL_INFO, "BRY: unable to load URL '%s' code %i", url, httpCode);
|
||||||
|
// cl.end();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t sz = cl.getSize();
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, "BRY: Response http_code %i size %i bytes in %i ms", httpCode, sz, millis() - http_connect_time);
|
||||||
|
// abort if we exceed 32KB size, things will not go well otherwise
|
||||||
|
if (sz >= 32767 || sz <= 0) {
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, "BRY: Response size too big %i bytes", sz);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a bytes object at top of stack.
|
||||||
|
// the streamwriter knows how to get it.
|
||||||
|
uint8_t * buf = (uint8_t*) be_pushbytes(vm, nullptr, sz);
|
||||||
|
StreamBeBytesWriter memory_writer(vm);
|
||||||
|
int32_t written = cl.writeToStream(&memory_writer);
|
||||||
|
cl.end(); // free allocated memory ~16KB
|
||||||
|
|
||||||
|
size_t loaded_sz = 0;
|
||||||
|
const void * loaded_buf = be_tobytes(vm, -1, &loaded_sz);
|
||||||
|
|
||||||
|
FlashFileImplPtr fp = FlashFileImplPtr(new FlashFileImpl(loaded_buf, loaded_sz));
|
||||||
|
File * f_ptr = new File(fp); // we need to allocate dynamically because be_close calls `delete` on it
|
||||||
|
bclosure* loaded_bec = be_bytecode_load_from_fs(vm, f_ptr);
|
||||||
|
be_pop(vm, 1);
|
||||||
|
if (loaded_bec != NULL) {
|
||||||
|
be_pushclosure(vm, loaded_bec);
|
||||||
|
be_call(vm, 0);
|
||||||
|
be_pop(vm, 1);
|
||||||
|
}
|
||||||
|
be_gc_collect(vm); // force a GC to free the buffer now
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
@ -839,6 +922,9 @@ bool Xdrv52(uint32_t function)
|
|||||||
XdrvMailbox.index++;
|
XdrvMailbox.index++;
|
||||||
} else {
|
} else {
|
||||||
WSContentSend_P(HTTP_BTN_BERRY_CONSOLE);
|
WSContentSend_P(HTTP_BTN_BERRY_CONSOLE);
|
||||||
|
#ifdef USE_BERRY_PARTITION_WIZARD
|
||||||
|
HandleBerryPartiionWizardLoaderButton();
|
||||||
|
#endif // USE_BERRY_PARTITION_WIZARD
|
||||||
callBerryEventDispatcher(PSTR("web_add_button"), nullptr, 0, nullptr);
|
callBerryEventDispatcher(PSTR("web_add_button"), nullptr, 0, nullptr);
|
||||||
callBerryEventDispatcher(PSTR("web_add_console_button"), nullptr, 0, nullptr);
|
callBerryEventDispatcher(PSTR("web_add_console_button"), nullptr, 0, nullptr);
|
||||||
}
|
}
|
||||||
@ -858,6 +944,9 @@ bool Xdrv52(uint32_t function)
|
|||||||
berry.web_add_handler_done = true;
|
berry.web_add_handler_done = true;
|
||||||
}
|
}
|
||||||
WebServer_on(PSTR("/bc"), HandleBerryConsole);
|
WebServer_on(PSTR("/bc"), HandleBerryConsole);
|
||||||
|
#ifdef USE_BERRY_PARTITION_WIZARD
|
||||||
|
Webserver->on("/tapp", HTTP_GET, HandleBerryPartitionWizardLoader);
|
||||||
|
#endif // USE_BERRY_PARTITION_WIZARD
|
||||||
break;
|
break;
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
case FUNC_SAVE_BEFORE_RESTART:
|
case FUNC_SAVE_BEFORE_RESTART:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user