How to update label


i know this should be simple but i cant get it to work and cant find a clear answer here yet.

What MCU/Processor/Board and compiler are you using?

esp32 inside a lilygo t-watch. vscode with platformIO

What LVGL version are you using?

What do you want to achieve?

i have made button that sends a command to a remote device, i want to display the device response in a label

What have you tried so far?


Code to reproduce

void esp_app_main_setup( uint32_t tile_num ) {

esp_app_main_tile = mainbar_get_tile_obj( tile_num );
lv_style_copy( &esp_app_main_style, mainbar_get_style() );

lv_obj_t * returnDataObj = lv_label_create(esp_app_main_tile, NULL);
lv_label_set_long_mode(returnDataObj, LV_LABEL_LONG_SROLL_CIRC);     //Circular scroll
lv_obj_set_width(returnDataObj, 150);
lv_label_set_text(returnDataObj, "test data?");
lv_obj_align(returnDataObj, esp_app_main_tile, LV_ALIGN_CENTER, 0, 30);


void sendGcode(){
Serial.print("Connecting to ");

if (!client.connect(host, port)) {
    Serial.println("Connection failed.");


int maxloops = 0;

while (!client.available() && maxloops < 1000)
    delay(1); //delay 1 msec
if (client.available() > 0){

    //read back one line from the server
    returnData = client.readStringUntil('\r');

    #define MAX_STRING_SIZE 50
    char testChar[MAX_STRING_SIZE];
    snprintf(testChar, MAX_STRING_SIZE, "%s", returnData.c_str());
    lv_label_set_text(returnDataObj, testChar);

    Serial.println("client.available() timed out ");
    lv_label_set_text(returnDataObj, "client timed out");

Serial.println("Closing connection.");


Screenshot and/or video

currently the sending of the command works, if i remove the attempts to update then the data is recieved( printed to serial) but as it is results in hard crash/device freeze.

returnDataObj is probably NULL. It looks like you may be shadowing it inside esp_app_main_setup.

i appreciate the response, but am still confused. what do you mean by shadowing? maybe im not understanding how its supposed to work, i thought the setup was for setting up size, aligntment, parentage, initial display, etc. i moved the whole returnDataObj into a recurring task and got SOMETHING to display, but i think the numbers are stacking and never clearing. and does being NULL make it un-assignable?

You need to store a reference to the object in a global variable, however you need to make sure you are not redeclaring the global variable inside your setup function, otherwise the global never gets touched as the name is taken by the local variable within the function.

It sounds like you have now moved the initialization into a task, which is not a good idea as the label will keep being created over and over. You should keep the label creation and setup in the esp_app_main_setup function, and just ensure that there is a global variable in the file which both functions can reference.

i think i got it.
i had ‘lv_obj_t * returnDataObj;’ up just below the includes, and again in the setup. deleting the second ‘lv_obj’ and just going to obj = whatev, then i can call lv_set_label whenever

1 Like

only i cant, calling lv_set_label outside the recurring task apparently freezes the system? is that normal?

It should work as long as there is only one OS thread or a mutex. Are you calling it from a second OS thread?

everything im using exists only in the scope of this screen/file. i dont know enough about how the esp32 handles cores (or what a mutex is) to be definitive, but my calls are unique to the page im using them on and have not attempted to add them to other parts of the code. the full page is here if that helps, ive commented out the ones that are problematic

This should work. Have you enabled LVGL logging? It would be good to know if anything relevant gets printed.

delighted to hear that it SHOULD work. i searched through the source repo looking for lv_conf.h and the only place im finding it is a library for the hardware (ttgo watch). so i set log to 1 and LOG_LEVEL to INFO, but i dont see any new output. i tried to make a new lv_conf file with just the debug, that did not go well. i thought it might have been related to the esp hanging when it wasnt getting a tcp response so i started leaving the remote server off for testing, but then it ‘recovered’ (screen went blank/off, i pressed pwr button and got home screen, logs didnt show reboot), and showed the updated label saying connection refused or whatever it was supposed to show on error. the second button, which does nothing but print out to serial and update the label, hard crashes/hangs every time. i get the serial output saying the second button was pressed then silence. no response from screen, no response to button press, will display frozen screen until pwr is long held. not sure if i have properly enabled logs at this point…

copied the whole lv_conf.h from the source library to the project folder. enabled logs, set trace, enabled printf, still nothing i havnt seen before on the serial monitor. am i missing a printf(lv_log_something)?

Here’s a quick way to test if the log is working the way it should. Add this line after lv_init:

LV_LOG_WARN("=== log test");

If you don’t see that line get printed on the serial monitor, the log is not working.

so here is the danger of arduino and libraries: again found no trace of lv_init in the watch project, only the hardware library. enabled printf there and learned that trace logs are sufficiently numerous to slow the esp32 down. fortunately when it crashes it stops producing more.

[I][touch.cpp:160] touch_read(): touched @ 224,22 1
Trace: idnev read finished (lv_hal_indev.c #155 _lv_indev_read())
Trace: indev read task finished (lv_indev.c #129 _lv_indev_read_task())
Trace: lv_refr_task: started (lv_refr.c #177 _lv_disp_refr_task())
Trace: lv_img_design: start to draw image (lv_img.c #664 lv_img_design())
Trace: image draw: image found in the cache (lv_img_cache.c #101 _lv_img_cache_open())
Trace: lv_img_design: start to draw image (lv_img.c #664 lv_img_design())
Trace: image draw: image found in the cache (lv_img_cache.c #101 _lv_img_cache_open())
Trace: image draw: image found in the cache (lv_img_cache.c #101 _lv_img_cache_open())
Trace: lv_refr_task: ready (lv_refr.c #310 _lv_disp_refr_task())
Trace: indev read task started (lv_indev.c #77 _lv_indev_read_task())
Trace: idnev read started (lv_hal_indev.c #153 _lv_indev_read())
Trace: idnev read finished (lv_hal_indev.c #155 _lv_indev_read())
second button clicked
Error: lv_label_set_text (lv_label.c #182 lv_label_set_text())
Error: NULL pointer (0x00000000) (lv_debug.c #127 lv_debug_log_error())

guh. i was using the wrong variable name. working fine now. thank you!

No problem! Glad you were able to track down the cause.

With regards to the excessive logs, I suggest setting the logging level to INFO or WARN unless you’re having a specific problem in the moment. That will usually tell you the important information about a crash without overwhelming the debug channel.

Hello, I have some tabs, if I update the string of the label, I do see some pixels being rewritten but doesn’t erase the previous occupied pixels,I tried this on a label I had but looks like is not refreshing correctly:

strcpy(serial_log_text, "Jump");
        lv_label_set_text_static(serial_log, NULL);
        lv_event_send(serial_log, LV_EVENT_REFRESH, NULL);

If I click on another tab and go back to the one where the label is, it does show everything now correctly.

Screen Shot 2022-10-26 at 17.34.35
Screen Shot 2022-10-26 at 17.34.27
Screen Shot 2022-10-26 at 17.35.19