Skip to content

Commit 6a68825

Browse files
authored
Feature/timer (#12)
* chores: MQTT is now disabled by default and configurable. * feature: Now we have timers to run functions periodically.
1 parent 39113a7 commit 6a68825

File tree

4 files changed

+67259
-131514
lines changed

4 files changed

+67259
-131514
lines changed

webscreen/globals.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
#include "log.h"
44

55
// Declare the global script filename variable
6-
extern String g_script_filename;
6+
extern String g_script_filename;
7+
8+
// Add this new global flag
9+
extern bool g_mqtt_enabled;

webscreen/lvgl_elk.h

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <NimBLEDevice.h>
99

1010
#include <WiFi.h> // WiFi library that also provides WiFiClient
11+
#include <WiFiClientSecure.h>
1112
#include <ArduinoJson.h>
1213
#include <PubSubClient.h> // For MQTT
1314

@@ -356,6 +357,57 @@ static jsval_t js_delay(struct js *js, jsval_t *args, int nargs) {
356357
return js_mknull();
357358
}
358359

360+
// LVGL Timer Bridging Functions
361+
362+
// This C++ function will be the callback for LVGL. It will execute a JS function.
363+
static void elk_timer_cb(lv_timer_t *timer) {
364+
char *func_name = (char *)timer->user_data;
365+
366+
if (func_name != NULL && js != NULL) {
367+
// Construct a snippet of JavaScript to call the function, e.g., "my_func();"
368+
char snippet[64];
369+
snprintf(snippet, sizeof(snippet), "%s();", func_name);
370+
371+
// Use js_eval to execute the function call.
372+
jsval_t res = js_eval(js, snippet, strlen(snippet));
373+
if (js_type(res) == JS_ERR) {
374+
LOGF("[TIMER CB] Error executing JS function '%s': %s\n", func_name, js_str(js, res));
375+
}
376+
}
377+
}
378+
379+
// This is the function we will expose to JavaScript.
380+
// It creates an LVGL timer that will call our C++ callback.
381+
static jsval_t js_create_timer(struct js *js, jsval_t *args, int nargs) {
382+
// Expects: function name (string), period in ms (number)
383+
if (nargs < 2) {
384+
LOG("create_timer expects: function_name, period_ms");
385+
return js_mknull();
386+
}
387+
388+
size_t func_name_len;
389+
char *func_name_str = js_getstr(js, args[0], &func_name_len);
390+
double period = js_getnum(args[1]);
391+
392+
if (!func_name_str || func_name_len == 0) {
393+
return js_mknull();
394+
}
395+
396+
char *name_for_timer = (char *)malloc(func_name_len + 1);
397+
if (!name_for_timer) {
398+
LOG("Failed to allocate memory for timer callback name");
399+
return js_mknull();
400+
}
401+
memcpy(name_for_timer, func_name_str, func_name_len);
402+
name_for_timer[func_name_len] = '\0';
403+
404+
// Create the LVGL timer
405+
lv_timer_create(elk_timer_cb, (uint32_t)period, name_for_timer);
406+
407+
LOGF("Created LVGL timer to call JS function '%s' every %dms\n", name_for_timer, (int)period);
408+
return js_mknull();
409+
}
410+
359411
// sd_read_file(path)
360412
static jsval_t js_sd_read_file(struct js *js, jsval_t *args, int nargs) {
361413
if (nargs != 1) return js_mknull();
@@ -430,6 +482,50 @@ static jsval_t js_sd_list_dir(struct js *js, jsval_t *args, int nargs) {
430482
return js_mkstr(js, fileList, fileListLen);
431483
}
432484

485+
// Helper function to convert a JS string to a JS number
486+
static jsval_t js_to_number(struct js *js, jsval_t *args, int nargs) {
487+
if (nargs != 1) {
488+
return js_mknum(0); // Return 0 if no argument
489+
}
490+
491+
// If it's already a number, just return it.
492+
if (js_type(args[0]) == JS_NUM) {
493+
return args[0];
494+
}
495+
496+
// Get the string value from the JS argument
497+
size_t len;
498+
const char *str = js_getstr(js, args[0], &len);
499+
if (!str) {
500+
return js_mknum(0); // Return 0 if not a valid string
501+
}
502+
503+
// Convert the C-string to a double and return as a JS number
504+
return js_mknum(atof(str));
505+
}
506+
507+
// Helper function to convert a JS number to a JS string
508+
static jsval_t js_number_to_string(struct js *js, jsval_t *args, int nargs) {
509+
if (nargs != 1) {
510+
return js_mkstr(js, "", 0);
511+
}
512+
513+
uint8_t type = js_type(args[0]);
514+
515+
if (type == JS_NUM) {
516+
char buf[32];
517+
double num = js_getnum(args[0]);
518+
// Using "%.17g" is how the Elk engine itself formats numbers
519+
snprintf(buf, sizeof(buf), "%.17g", num);
520+
return js_mkstr(js, buf, strlen(buf));
521+
} else if (type == JS_STR) {
522+
// If it's already a string (like from parse_json_value), just return it
523+
return args[0];
524+
}
525+
526+
return js_mkstr(js, "", 0);
527+
}
528+
433529
/******************************************************************************
434530
* F) Load GIF from SD => g_gifBuffer => "M:mygif"
435531
******************************************************************************/
@@ -3011,6 +3107,9 @@ void register_js_functions() {
30113107
js_set(js, global, "wifi_status", js_mkfun(js_wifi_status));
30123108
js_set(js, global, "wifi_get_ip", js_mkfun(js_wifi_get_ip));
30133109
js_set(js, global, "delay", js_mkfun(js_delay));
3110+
js_set(js, global, "create_timer", js_mkfun(js_create_timer));
3111+
js_set(js, global, "toNumber", js_mkfun(js_to_number));
3112+
js_set(js, global, "numberToString", js_mkfun(js_number_to_string));
30143113

30153114
// bridging for indexOf / substring
30163115
js_set(js, global, "str_index_of", js_mkfun(js_str_index_of));
@@ -3180,12 +3279,10 @@ static void elk_task(void *pvParam) {
31803279
// 4) Now keep running lv_timer_handler() or your lvgl_loop
31813280
// so that the UI remains active
31823281
for(;;) {
3183-
// Check Wi-Fi and MQTT, handle reconnections
3184-
wifiMqttMaintainLoop();
3282+
if (g_mqtt_enabled) {
3283+
wifiMqttMaintainLoop();
3284+
}
31853285
lv_timer_handler();
31863286
vTaskDelay(pdMS_TO_TICKS(5));
31873287
}
3188-
3189-
// If you ever want to exit the task, do:
3190-
// vTaskDelete(NULL);
31913288
}

0 commit comments

Comments
 (0)