logo elektroda
logo elektroda
X
logo elektroda

How I reduced my IoT config page size 11 times by using Javascript instead of static HTML

p.kaczmarek2 
JavaScript code snippet generating dropdown elements.
Here I will show you how I reduced my IoT device pins configuration HTML page from about 90kB down to only 8kB. I will use my OpenBeken project as an example, but the generic idea shown here can easily apply to any other environment creating HTML pages from C (or similiar) code. This topic will assume that user knows the basic of C, HTML and Javascript...

So, in this topic I am referring to OBK configuration page that allows you to set GPIO roles in dropdown lists:
IoT device pin configuration in OpenBK7231
Screenshot of the GPIO configuration page in the OpenBeken project
Before, size of this page was above 90 000 bytes:
Screenshot of a text editor displaying a fragment of HTML code, indicating a file length of 92,698 bytes and 2 lines of code.
It was causing slow loading on multiple platforms.
After the change, size is now:
Screenshot displaying a code snippet in a text editor.

Let's start by checking why the page size is so big in case of this config. We can just view the source of the page in the browser:
HTML code snippet for IoT device pin configuration
Now you can clearly see, that for each of the dropdowns, the list of options is repeated. This is very simple, but also not optimal. This repeats for every GPIO, so if there is 30 available IO pins on a sample platform, then it's repeated 30 times!
A brief look at OBK code confirms that's what is happening:
Code: C / C++
Log in, to see the code

The following is done for every possible pin! We need to optimize that...

In order to optimize it, we will use Javascript. In JS, we will create a single, global pin roles array and then for each dropdown we will insert the items into it with a script. There are, however, two issues to solve:
- we need to also set the active selected element, so people don't lose their settings with each refresh and save
- we need to exclude PWM roles for non-PWM pins.
Let's ignore the PWM issue for now. Let's start with the following draft:
Code: Javascript
Log in, to see the code

Array r is a list of item role names. In my function f, I iterate the pin role names and add them to the dropdown d. There I also check for the selected role, which index must be given when calling f function.
The selected role index can be easily taken from OBK code, but for the reference to the select DOM object I had to modify the code futher. I settled with retrieving it by ID:

Code: Javascript
Log in, to see the code

Now that we have basics done, let's also consider how we can skip PWM roles for non-PWM pins. OBK already knows which pins support PWM, so we can just pass extra argument and then check whether pin role starts with PWM, altough in the future I may just hardcode the index of role (it will be few characters shorter). Note that the 'b' variable is the extra argument I added to the function:
Code: Javascript
Log in, to see the code

So finally I have modified my C code to just print the following Javascript when generating OBK page, of course also replacing the dummy data with the real OBK pin roles:
Screenshot of C code generating a Javascript script for GPIO configuration in the OpenBeken project.
This works and page size is now reduced 9 times, but is it all that we can do?

A brief glance at HTML code shows that there is still room for the improvement:
Screenshot of the HTML code for an IoT device configuration page created with C code.
The channel index div generation can be also procedural. Here is a beautified version of the new code that also generates div:
Code: Javascript
Log in, to see the code

The div creation could be actually separated into another function, as it's done two times, but I don't think it would give me a substantial numbers of characters.
So, now the page size is down to 8kB:
Screenshot of a text editor showing a snippet of JavaScript code.

So, to sum up - generating HTML code from C is very easy, but also not very optimal. In case of the repeating data, like the dropdowns with the same options, it's more efficient to generate a Javascript that will later generate HTML elements. For me, it gave me over one order of magnitude improvement in terms of space used. It also fixed OBK issues, hopefully...
The same principle can be applied also to any other IoT projects, the same problems could occur on ESP and could be also solved in ESP by generating HTML+JS instead of pure HTML, so I hope that everybody learned something.
My sample could be of course improved futher, also with Javascript-compression scripts, but I think the optimization I have managed to get so far is enough for our project.

By the way, if any OBK user is reading it, please check it and let me know. Can you check how your pins page works (especially on Firefox) and then update to test build:
https://github.com/openshwprojects/OpenBK7231T_App/pull/1215
does the page loads faster now? Or better? @divadiow @max4elektroda @dedamraz @miegapele ? Can you test it on multiple OBK platforms?
NOTE: Obk also provides pins setting in the web app, so the following page is not crucial, but it's still good to have it running well.

About Author
p.kaczmarek2
p.kaczmarek2 wrote 11826 posts with rating 9927 , helped 564 times. Been with us since 2014 year.

Comments

Add a comment
DeDaMrAz 11 May 2024 18:01

I had one particular N module that will completely freeze if I went to config pins, this resolved that issue for me! BEFORE: https://obrazki.elektroda.pl/7154115700_1715443251_thumb.jpg AFTER:... [Read more]

max4elektroda 11 May 2024 19:03

Works here on my LN882H, page loads fast (but to be honest, I can't remember how it was before) Having a quick look, you might even save some more bytes. I see some whitespaces and (my thought when... [Read more]

p.kaczmarek2 11 May 2024 19:19

Actually I have LN882H running at the moment with an older build. And for that it seems that old version runs very good as well. There is no noticeable slowdown in the older build. I've tested both Chrome... [Read more]

max4elektroda 11 May 2024 19:29

A really good idea and a huge improvement! Out of curiosity: I expect not too much improvement on the image size? I mean, it was much HTML code, but most was created in loops, IIRC. [Read more]

p.kaczmarek2 11 May 2024 20:21

I didn't check the flash size before change (the main releases system seems to have some issue at the moment) but I would say that change in flash size is very, very small. Keep in mind that the mentioned... [Read more]

max4elektroda 11 May 2024 20:53

May I suggest a small "improvement" (it's a question of "style" vs "size"): If you change function f(alias, id, c, b, ch1, ch2) { let f = document.getElementById("x"); ... [Read more]

p.kaczmarek2 11 May 2024 21:06

That's a good change, we can add it as well, no problem. The only question would be, can't we just use one of existing styles? Or is the proposed solution the shortest one? [Read more]

max4elektroda 11 May 2024 21:49

To be honest I was too lazy to try to dive into the styles, it might be possible to reuse another, but since we would need a class, it would probably not be much shorter... Added after 8 [minutes]:... [Read more]

p.kaczmarek2 11 May 2024 22:13

The second channel field is currently showed only when pin role supports it. For example, button can have two linked channel - one for single click, second for dual click. Futher clicks (like triple click)... [Read more]

divadiow 11 May 2024 22:15

Would it be possible to have the second channel box reveal as soon as supported device is selected rather than having to save to reveal second box then save again after entering required channel numbe... [Read more]

p.kaczmarek2 12 May 2024 00:00

Of course, but it would require keeping a second array with a number of channels that given pin role requires, and then catching the onChange event of the dropdown, so the visibility of the channel fields... [Read more]

divadiow 12 May 2024 16:02

can't say I really noticed a slowness but they're all fast and the page loads fine. chrome. https://obrazki.elektroda.pl/3885064200_1715521417_thumb.jpg https://obrazki.elektroda.pl/5707795900_1715521449_thumb.jpg... [Read more]

max4elektroda 12 May 2024 18:47

I tried to implement this in PR #1228 Just as a first idea I got during this work: At the moment we have the properties of an IO role in several places: - we have the "main" enum ioRole_e in new_pins.h... [Read more]

divadiow 12 May 2024 21:26

nice job! [Read more]

p.kaczmarek2 13 May 2024 14:00

Very good, I will merge it in a moment. Some of things could be improved there (code could be shorter), but it's not crucial. The change from 90kB to 8kB was more important. This is a good idea... [Read more]

max4elektroda 13 May 2024 14:17

Yes, I had my focus on the function, not the size here, but will take another look to shorten the code if the function is proofed ;-). I'm usually using Linux, but if it's not too complicated, I would... [Read more]

p.kaczmarek2 13 May 2024 14:19

If you are using Linux, then maybe you'd be able to help us with porting: a) just self tests to Linux (should be very easy) b) whole simulator to linux (should be relatively easy, as it's SDL, but I... [Read more]

max4elektroda 13 May 2024 14:29

I'm willing to help, but be warned, I'm just a "hobby coder", not a serious "developer" ;-) [Read more]

p.kaczmarek2 13 May 2024 15:52

Well, the first thing would be to compile the simulator (or at least the self tests part, without SDL window) on Linux. How would we go on about that? The win_main.c could be actually compiled on Linux... [Read more]