Examples for lvgl in micropython

I would like to contribute to the lvgl documentation by porting some C examples to micropython. Docs even have the corresponding section but it is always empty.
At the moment all the C examples are automatically included from a particular commit of lv_examples repository, so creating a pull request is tricky.
What would be the best way to proceed with micropython?
Should we create a separate repository like lv_mpy_examples?

I think it would be nice to have such examples as many people using micropython are not very familiar with C syntax and with exact logic of how micropython bindings are generated.

1 Like

@Stepan_Snigirev That would be great!

Micropython examples can also run in the web browser on https://littlevgl.github.io/sim/micropython/ports/javascript/lvgl_editor.html.

Here is a very simple example.

This can be useful when discussing and sharing micropython examples.
Maybe it’s worth adding such link to each example so the user could run it interactively and not only see the source code.

@kisvegabor Could you advise what would be the best way to include Micropython examples in the docs?

Similarly to the C examples they can be easily added to the docs. See lv_bar for example.

To add an example:

  • Create a py file like this
  • Add a reference to it in the related index.rst file

Ok, then I will start writing a pull request for the rework branch of the lv_examples repository.

Would it be useful to include a “try it online” link for these examples?
Something like this for the Bar: https://littlevgl.github.io/sim/micropython/ports/javascript/lvgl_editor.html?script_direct=dcbe9591cc09227f3a8ebd762e581cd7f53709de

How do you store these scripts? Do they have some kind of lifetime?

1 Like

I think that adding a “try it online” link is a good idea.

When using the script_direct option, the script and its versions are stored on a private git repository. Currently there’s no lifetime although this may change in the future.

There is another option - you can use the script parameter to pass a url to a script on github (or gist).
For example:

(you need to use either https://raw.githubusercontent.com or https://gist.githubusercontent.com)

If you store the examples on github as independent python scripts, this would be a better choice than using the script_direct option.

I started porting the examples, some of them work fine, with others I have questions:


Online demo
How to set highlighted days? I can’t pass a list, so I assume I need to make a C array somehow…
I can highlight one day though:

d = lv.calendar_date_t()
d.year = 2018
d.month = 10
d.day = 23
calendar.set_highlighted_dates(d, 1)


In C example LV_CANVAS_BUF_SIZE_INDEXED_1BIT macro is used to calculate the size of the byte array for canvas. I think it would be nice to expose such macros as functions in lv module. Is it possible?

At the moment I am calculating it manually:

def bufsize(w, h, bits, indexed=False):
    size = (w * bits // 8 + 1) * h
    if indexed:
        size += 4 * (2**bits)
    return size


Online demo
In the chart example I have troubles with setting points directly. C code in the example looks like this:

    ser2->points[0] = 90;
    ser2->points[1] = 70;
  // ...

In micropython I am currently using set_next function everywhere:

# Set points on 'dl2'
points = [90, 70, 65, 65, 65, 65, 65, 65, 65, 65]
for p in points:
    chart.set_next(ser2, p)

I was not able to set values of the points directly. Is there a way?
I don’t think it is strictly necessary, just wondering.

At the moment I am done up to ddlist :slight_smile:
Hopefully I will finish in a few days and make a pull request.

We need to change lv_calendar_set_highlighted_dates prototype on lvgl sources.

If instead of lv_calendar_date_t *highlighted, set_highlighted_dates received lv_calendar_date_t[] highlighted, then the Micropython Binding would recognize this as an array and allow you use a python list.

This is done, for example, on chart where lv_coord_t y_array[] is passed as a function argument.
lvgl defines set_points as:

void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y_array[]);

and you can do this in Micropython:

chart.set_points(series1, [10,20,30,20,10,40,50,90,95,90])

Another example is lv_line_set_points where each element is a lv_point_t struct.
You can do something like this:

l = lv.line(scr)

@kisvegabor - Can we change lv_calendar_set_highlighted_dates prototype to receive an array? Can you think of other examples where we should receive an array instead of a pointer to struct?

The Micropython Binding is scanning the preprocessed lvgl headers.
This means it can’t process any macros, comments, etc.

A workaround for this is to define a function in addition to a macro that wraps the macro.
The function can be static inline so it wouldn’t cost anything in C, but it would still be visible to the binding script.

I suggest collecting a list of macros which are important to Micropython, and make a PR with corresponding static inline functions to lvgl repo.

Yes, as I mentioned arrays are supported. See this example.

I think the online simulator is based on older code, before arrays support was added.
But you can check this using the unix (linux) port of lv_micropython.

@embeddedt Could you comment on this? When was the simulator compiled? Could you explain the procedure of creating a new javascript simulator from lv_micropython sources?

Nice progress! :+1:

Sure, even in dev-6.1.
Probably there are other function that we miss but we could find it only with systematically reading the API. Probably @Stepan_Snigirev will find the other problematic places too.

The simulator is out-of-date. I am planning to merge master into it, but I haven’t had a chance to do so yet.

I created a pull request with most of the examples.

Remaining problems:

  • how to work with tasks in micropython?
  • some functions don’t accept lists:
    • calendar.set_highlighted_dates
    • tileview.set_valid_positions
  • ddlist.get_selected_str() and roller.get_selected_str() require passing a string as an argument and change it in place. Would be better to return a string.
  • not sure how to get information from lv.event_get_data() in ta example (it’s used to trigger action on \n)

@embeddedt, would it be possible to add a new url type for the online simulator?

All the MicroPython examples don’t have any initialization code, but all of them can use the same init code in the simulator. Then we could easily include “Try it online” link next to the example in the doc, and reference to the same code.

The goal is to make urls like this working: https://littlevgl.github.io/sim/micropython/ports/javascript/lvgl_editor.html?script=https://raw.githubusercontent.com/littlevgl/lv_examples/rework/src/lv_ex_bar/lv_ex_bar_1.py

If we add another url parameter - instead of &script=... we use something like &example=..., we could make such urls working. Internally the online editor could just add a few lines of code before the script. Something like:

import imp, sys
import display_driver
import lvgl as lv

scr = lv.obj()
# Load the screen

# Here we put the actual script provided in the &example=<url> parameter

Let’s continue this discussion on the PR.

Instead of “&example=”, how about “&init_script=” ?
The simulator would first and run the init_script if it is present, and only then run will run script. It is more general and can be used on contexts other than examples. It would allow specifying different init scripts on different occasions if needed.

Something like:

@Stepan_Snigirev, @embeddedt, what do you think?

I like it. With &init_script=... it will be possible to create examples for themes / custom styles / animations and other stuff that share the same main script.

It would be nice to see both init script and main script in the editor, maybe something like this:

##### init script ###

import lvgl as lv
# ... the rest of init script

##### main script ###

btn = lv.btn(lv.scr_act())
# ... the rest of main script

Actually, the init script would be included separately (e.g. a file from GitHub raw content) and the main script would be in the editor. Would that work?

I’ve fixed in dev-6.1.

Yes, it will definitely work with all current examples.

Awesome! I will complete the examples then!

@embeddedt both the script and the init_script can be files on GitHub.
Why not display both as @Stepan_Snigirev suggested?

The advantage is that if someone clicks “save” to save it on snippetbin, both will be saved as a single script. This script on snippetbin would be self-contained and runnable.

What do you think?

I think that’s confusing. That means that once someone clicks “save” the first time, both scripts get combined into a single script (and the init_script gets dropped from the URL).

If they’re going to be a single script after saving, they might as well be a single script from the start.

I thought about it again. Why is init_script necessary? Can’t someone just import another script that does the initialization?

hi, i find init_script a bit confusing PYTHONSTARTUP would feel more natural

on a side note, i noticed some people complaining on irc (freenode #micropython) about the git header micropython version (1.9!) on esp32 on their own build. i believe the javascript port is still also affected when doing custom builds, though i made that remark some time ago.

init_script or PYTHONSTARTUP would help to create “Try it online” links automatically that load files from the lv_example repository. In this case if we change or add new examples, “Try it online” links will always remain up-to-date.

Python scripts in lv_examples are minimal - they don’t have any initialization code and they assume that lvgl is already imported and initialized, and display driver is loaded.

If we would start making online demos now we would need to create a separate collection of scripts with all the init stuff and maintain them separately. I feel that it would just double the work…