ESP-HMI Editor — User Guide

Full reference: widgets, attributes, scripts, hardware bindings, Arduino, tools, devices, and firmware. Same content as HELP.md. Editor version and release notes: in the app, Help → Changelog (currently 2.16). Community: Discord.

1. What this is

Visual HMI designer for ESP32 displays (Elecrow CrowPanel, Waveshare ESP32 LCDs, generic SPI TFTs, custom boards). Nextion-style widgets and serial language, compiled to .ehmi instead of .tft.

Open index.html. For Web Serial upload use Chrome/Edge and python -m http.server 8765 then http://localhost:8765/. After code changes: Ctrl+F5.

1b. GitHub save / open (your repo, free)

No paid cloud. You push into a repository you own. GitHub does not store a token you can look up later — you create a Personal Access Token, copy it once, and paste it into the editor. File → Save still downloads a local .hmi.json.

A. Create the repository

  1. Sign in at github.com.
  2. New repository — name e.g. test_esp-hmi.
  3. Public or private. Tick Add a README so branch main exists.
  4. Create repository.

B. Create a fine-grained token (recommended)

  1. Profile picture → Settings.
  2. Left sidebar, bottom → Developer settings.
  3. Personal access tokensFine-grained tokensGenerate new token.
  4. Token name e.g. ESP-HMI Editor. Set an expiration.
  5. Resource owner = you. Repository access = Only select repositories → pick the repo from A.
  6. Permissions → Repository permissions → Contents → Read and write. If this stays “No access”, Test connection can still succeed and Save will 403.
  7. Generate token. Copy github_pat_… immediately — GitHub will not show it again.

Direct link: github.com/settings/personal-access-tokens

C. Classic token (also works)

Tokens (classic)Generate new token (classic) → enable the repo scope → copy ghp_…. That token can access all your private repos; prefer the fine-grained one.

D. Connect and save

  1. File → GitHub repo…
  2. Token = the PAT. Owner = username. Repository = repo name only (not the URL). Branch = main. Folder = hmi-projects.
  3. Save settings then Test connection (login only — not a save).
  4. Save current project (or File → Save to GitHub). That commits the files.

Repo layout: hmi-projects/untitled/project.hmi.json plus pictures/ and gmovs/.

E. Open from GitHub

File → Open from GitHub… → Refresh list → Open. On another PC, paste the same token and repo first.

F. 403 on Save

Test can say “Connected” while Save is refused. Edit the PAT: repository selected, Contents = Read and write, generate a new token, paste it. If the repo has no commits, add a README on GitHub first.

Token is stored only in this browser. Use Forget token on a shared PC.

2. Main window

Toolbox (drag widgets) · Canvas at device resolution · Attributes grid · Pages/Fonts/Pictures/Gmov · Event tabs · Output. Round devices draw a circle; corners of the square buffer are unused on glass.

3. Keyboard

KeyAction
Ctrl+N / O / SNew v2 / Open / Save
Ctrl+Z / Y / DUndo / Redo / Duplicate
DelDelete widget
Arrows / Shift+ArrowsNudge 1 / 10 px
Ctrl+EnterCompile
F5 / F1 / EscSimulator / Help / Close dialogs

Edit → Bring forward / Send backward changes stacking order (who is on top and who gets the touch).

4. Colors

All colors are RGB565 (0–65535): Black 0, White 65535, Red 63488, Green 2016, Blue 31, Gray 33840, Yellow 65504.

5. Common attributes (every widget)

AttrMeaning
objnameUnique name on the page. Used in scripts: nTemp.val=24.
idNumeric id (read-only). Sent in touch packets.
x y w hPosition and size in device pixels. Pictures scale with w×h.
xcen0 left, 1 center, 2 right.
ycen0 top, 1 center, 2 bottom.
vis1 show, 0 hide on LCD / Debug. Designer still shows it faded so you can select it. vis bStart,0
transparancy (transp)0–100. 0 opaque, 100 fully see-through. t0.transp=50. Every widget.

6. Pages

objname, id, bco (solid color), sta (0 crop / 1 solid / 2 stretch image), pic (background picture id), lock (0 unlocked / 1 locked). A locked page cannot be edited until you unlock it (Pages list button, Attributes, or Edit menu). Click empty canvas to edit the page. page home or page 0 switches pages.

7. Widgets

Text (t)

A label, not the box you type into. txt string · font · pco text color · bco fill · sta 0 crop / 1 solid / 2 image · style 0 rectangle / 1 rounded / 2 oval / 3 circle · pic / picc background / crop image · isbr wrap · pw password dots.

t0.txt="Hello"

Text input (ti)

The enter / edit box for the QWERTY keypad and numpad. Drop Text input + a keypad, tap the box, then tap keys. txt typed string · pw 1 password dots.

ti0.txt=""
kb0.txt="ti0"

Number (n)

val integer · same look attrs as Text · lenth digit width · format 0 dec / 1 hex / 2 HEX.

nTemp.val=186

Button (b)

Momentary. txt · pco/bco normal · pco2/bco2 pressed · sta style pic pic2.

Dual-state (bt)

Toggle. val 0/1 · txt/txt2 · off colors pco/bco · on colors pco2/bco2 · pic/pic2.

Progress (j)

val 0–100 · pco bar · bco track · sta/pic.

Battery (bat)

Charge icon. val 0–100 (or minval/maxval) · pco fill · pco2 low (≤20%) · bco empty · sta 0 crop / 1 solid / 2 image · style 0 icon / 1 icon+%. Example: bat0.val=72.

4G signal (tw)

Rising bars with a network label (same layout as a phone status icon). txt is the label — set 4G, 3G, 2G, 5G, LTE in Attributes. val 0–100 maps to 0–4 bars · pco bars+text · pco2 off bars · style 0 bars only / 1 bars+label. Examples: tw0.txt="5G" · tw0.val=75.

Wi-Fi (wf)

Signal rings. val 0–100 maps to 0–4 rings · pco on · pco2 off · style 0 icon / 1 icon+%. Example: wf0.val=80.

Slider (h)

val · minval maxval · pco knob · bco track · wid thickness. Example: nSpeed.val=hSpeed.val on Release.

Gauge (z)

val · minval maxval · font value/tick typeface · fco font color · pco needle · bco face · pco2 red zone · wid thickness · style 0 arc / 1 dial / 2 speedometer / 3 half.

Checkbox (c) / Radio (r)

val 0/1. Radio: only one on the page stays on.

Picture (p)

pic resource id · fit 0 stretch / 1 contain / 2 cover. Change at runtime (Nextion): p0.pic=2.

p0.pic=2
hmiSetInt("p0.pic", 2);
Serial.print("p0.pic=2");
Serial.write(0xFF); Serial.write(0xFF); Serial.write(0xFF);

Icon (ic)

Small glyph or custom image. Default 32×32 — drag handles to resize. val built-in glyph (0 home · 1 settings · 2 power · 3 play · 4 pause · 5 stop · 6 left · 7 right · 8 up · 9 down · 10 menu · 11 check · 12 close · 13 plus · 14 minus · 15 warning · 16 info · 17 heart · 18 star · 19 bell · 20 lock · 21 user · 22 search · 23 edit · 24 trash · 25 download · 26 upload · 27 clock · 28 mail · 29 light) · pic custom Pictures id (-1 = glyph) · fit 0 stretch / 1 contain / 2 cover · pco glyph colour · sta 3 transparent (default) · style 0 outline / 1 filled · wid stroke px. Tools → Icon Resizer scales a PNG to 16–96 px and can drop it as an Icon widget.

ic0.val=2
ic0.pco=RED
icLogo.pic=3

Picture list (pl)

Vertical scrolling list of project pictures (max 32). Import images on the Pictures tab, then drop Picture list from the toolbox. Default name pl0, default ids 0|1|2.

How to use: set ch (count) and txt (pic ids, 0|2|5) in Attributes. gdh row height · wid gap · fit 0 stretch / 1 contain / 2 cover · val selected row. Tick en (auto scroll) to loop continuously · tim ms per pixel (smaller = faster) · dir 0 down / 1 up. Drag to scroll by hand, tap a row to select.

CommandMeaning
add pl0,2Append picture id 2
add pl0,1,5Insert picture 5 at index 1
del pl0,0Remove index 0
cle pl0Empty the list
pl0.ch=4Set count (pad / truncate)
pl0.txt="0|2|5"Replace the whole list
pl0.val=2Select row 2
pl0.add=3Same as add pl0,3
pl0.del=1Same as del pl0,1
pl0.en=1Start auto-scroll (0 stops)
pl0.tim=25Auto-scroll speed (ms / pixel)
pl0.dir=1Scroll up (0 down)
get pl0.valRead selected index
add pl0,2
add pl0,1,5
del pl0,0
cle pl0
pl0.ch=4
pl0.txt="0|2|5|1"
pl0.en=1
pl0.tim=25
Serial.print("add pl0,2");
Serial.write(0xFF); Serial.write(0xFF); Serial.write(0xFF);

hmiSetInt("pl0.add", 3);
hmiSetInt("pl0.en", 1);
int sel = hmiGetInt("pl0.val");

Hotspot (m)

Invisible hit area (dashed in the editor).

Shape (sh)

Vector shape. style 0 rectangle / 1 rounded / 2 oval / 3 circle / 4 triangle / 5 diamond / 6 pentagon / 7 hexagon / 8 star / 9 arrow / 10 line / 11 polygon / 12 freehand · sta 0 outline / 1 fill / 2 fill+outline · bco fill colour · pco outline · wid outline px · dir triangle/arrow/line · txt polygon points x,y;x,y (0–1000). Polygon: Draw points then click in the box; Done drawing / Fit to path shrinks the widget box to the drawing. Freehand: click-drag; the box snaps to the sketch on release.

sh0.bco=RED
sh0.style=8
sh0.txt="100,200;900,200;500,900"

QWERTY keypad (kb)

On-screen keyboard. Tap a Text input, then tap keys. Bottom-left 123 opens digits and symbols; #+= opens more special characters; ABC returns to letters. txt optional pin · val 0 lower / 1 SHIFT / 2 symbols / 3 more symbols · style 0 letters / 1 letters + number row.

Numpad (np)

Numeric keypad. Tap a Number/Text then type, same as QWERTY. Always has a decimal . next to 0. style 0 decimal + backspace / 1 decimal + Enter. Number widgets only accept 0–9; use Text input for decimals.

np0.txt="nTemp"

Waveform (s)

add s0,0,128 · cle s0,0 · ch channels · pco0–3 · gdc grid · bco.

Bar graph (bg)

1–10 bars. ch count · val bar 0 · val1val9 other bars · minval/maxval · dir 0 left / 1 right / 2 up / 3 down · wid gap px · pco0pco9 bar colors · bco · sta/pic same as other widgets · gdh grid step (0 off) · style 0 rectangle / 1 rounded.

bg0.val=62
bg0.val1=40
bg0.ch=4

ESP32 Camera (cam)

Shows JPEG snapshots from a second ESP32-CAM on the same Wi-Fi. Same-chip OV2640 + SPI LCD is not supported (pins and RAM collide).

path e.g. http://192.168.1.20/capture · en 1 run / 0 stop (tap toggles) · tim ms between frames · fit 0 stretch / 1 contain / 2 cover. Set Device → Edit → Wi-Fi SSID / password so the HMI can join the LAN. Then Export + flash, then Upload.

cam0.en=1
cam0.path="http://192.168.1.20/capture"

QR (qr)

txt payload · pco/bco ink/paper.

GMOV (gm)

gmov animation id · en play · loop. gm0.gmov=1 · play gm0,1,1.

Timer (tm) — not a widget

type 51 · vscope global/local · tim ms · en run. Script goes in Timer Event.

tmPoll.en=1
tmPoll.tim=200
hmiSetInt("tmPoll.en", 1);
hmiSetInt("tmPoll.tim", 200);
int on = hmiGetInt("tmPoll.en");

Variable (va) — not a widget

Not drawn. type 52 · vscope global/local · sta Number/String · val or txt. Use from event scripts, Debug, UART, and Arduino.

vaRun.val=1
tStatus.txt=vaNote.txt
hmiSetInt("vaRun.val", 1);
int run = hmiGetInt("vaRun.val");
hmiSetText("vaNote.txt", "ready");

Scrolling text (g)

Marquee. Same look as Text · dir 0 left / 1 right / 2 up / 3 down · tim ms/step · en run. Long txt stays on one line (no wrap). g0.txt="Alarm…" g0.en=1.

Xfloat (x)

Fixed-point. Display is val / 10^vvs1. vvs0 digits before decimal (pad) · vvs1 after. Example: val=1234 vvs1=212.34.

Crop (q)

Window into a project picture. pic · cropx / cropy source offset · widget w×h is the crop size. Runtime: q0.pic=2.

TouchCap (tc)

Signature pad. Draw in the simulator. pco pen · bco fill · wid width · val stroke count. Clear: cle tc0.

Switch (sw)

Pill toggle. Press flips val. pco ON track · bco OFF track.

ComboBox (cb)

Dropdown. txt items (\r or |) · val selected index. Simulator: click to open, click a row to pick.

TextSelect (ts)

Always-open list. txt lines · val index · pco2/bco2 selected row.

SLText (sl)

Single-line text (no wrap). Same look attrs as Text.

DataRecord (dr)

Table / log. path optional file · txt rows · val highlighted row. First line is a header.

FileBrowser (fb)

path folder header · txt file names · click a row to set val.

FileStream (fs)

Transfer status. path · txt status · en 1 streaming. Click toggles in the simulator; hook real I/O in user_app.cpp.

Video (vd)

vid / gmov resource · from 0 resource / 1 file · path URL · en play · loop.

vd0.vid=1
vd0.en=1
play vd0,1,1
hmiSetInt("vd0.vid", 1);

Audio (au)

vid resource · from · path · en · loop. Nextion: play 0,2,1.

play au0,2,1
au0.en=1
hmiSetText("au0.path", "/sd/beep.wav");

ExPicture (ex)

from 0 resource / 1 file · pic id · path URL or /sd/logo.png · fit. Runtime: ex0.pic=2.

8. Pictures, fonts, GMOV, icons

+ Pic imports images. Click a thumbnail with a page selected to set the page background; with a text/number/button selected to set pic. Drag onto the canvas to place.

Font Generator (Tools): TTF or system font → bitmap atlas → Fonts tab → set widget font.

Built-in LCD faces (font 0–3) are ASCII only (space through ~). They have no °, µ, or . The firmware draws a small ring for ° / / so 24.5°C still looks right. For other symbols, use ASCII (*C, uA) or generate a bitmap font with charset Digits / units (includes ° %).

GMOV Generator: PNG sequence, GIF (Chrome/Edge), or video → frames + delay + loop → Gmov tab → drag onto the canvas.

Icon Resizer (Tools): PNG/JPG → square 16 / 24 / 32 / 48 / 64 / 96 px (keeps transparency) → Pictures, or drop as an Icon widget. Use Image Resizer for full-screen photos.

9. Event scripts — every instruction

Tabs: Touch Press, Touch Release, Preinitialize, Timer. One instruction per line. // comments. Autocomplete: Enter/Tab insert, ↑↓ move, Esc close, Ctrl+Space. Compatible with the Nextion instruction set. if/while/for belong in events, not UART. No spaces in parameter lists. Colors: BLACK 0 · WHITE 65535 · BLUE 31 · GREEN 2016 · RED 63488 · GRAY 33840 · YELLOW 65504 · BROWN 48192.

Assignments

InstructionParametersExample
obj.attr=valuedestination = number, string, color, or another attributet0.txt="Hello" · nTemp.val=186 · n0.val=hSpeed.val · b0.bco=RED
txt+= / txt-=append string / delete N chars from the endt0.txt+=" °C" · t0.txt-=4
+= -= *= /= %=integer math on .valn0.val+=10 · n0.val/=3
++ / --nonen0.val++
&= |= ^= <<= >>=bitmask or shift countn0.val&=255 · n0.val<<=1

page pid

pid = page name or index. Runs Preinitialize.

page home
page 0

ref cid

cid = objname or id. 0 = whole page.

ref t0
ref 0

ref_stop / ref_star

No parameters. Pause / resume waveform refresh.

click cid,event

cid = name or id. event = 1 press, 0 release.

click bStart,1
click 4,0

vis cid,state

cid = name, id, or 255 (all). state = 0 hide on LCD / Debug, 1 show. The designer keeps hidden widgets faded so you can still edit them.

vis bStart,0
vis 255,0

tsw cid,state

Enable/disable touch. Same cid rules as vis. state 0 off, 1 on.

tsw b0,0

get attrib

Send to host: 0x70 string or 0x71 int32le. attrib = n0.val, t0.txt, 123, "ok".

get nTemp.val
get t0.txt

sendme

No parameters. Returns current page id (0x66).

print attrib · prints attrib,length

Raw serial, no return header. Strings = ASCII. Numbers = 4-byte LE. length 0 = all.

print t0.txt
prints t0.txt,4
prints n0.val,2

printh hex [hex …]

Raw hex bytes, space-separated (this command allows spaces).

printh 0D 0A
printh 65 00 01 01

com_stop / com_star / code_c

No parameters. Pause / resume serial execution; drop the serial queue.

cov src,dest,length

Number ↔ text. Types must differ. length 0 = natural; >0 pads or keeps last N digits.

cov n0.val,t0.txt,0
cov n0.val,t0.txt,4
cov t0.txt,n0.val,0

covx src,dest,length,format

Same as cov. format: 0 int, 1 commas, 2 hex.

covx n0.val,t0.txt,0,1
covx n0.val,t0.txt,4,2

substr src,dest,start,count

Copy count chars from src starting at start (0 = first) into dest.

substr va0.txt,t0.txt,0,5

strlen txt,len · btlen txt,len

Write string length into a number. ASCII: both are the same.

strlen t0.txt,n0.val

spstr src,dest,key,index

Split src on delimiter key (quoted). Put piece index (0 = first) in dest.

spstr va0.txt,t0.txt,",",0
spstr "ab|cd|ef",t0.txt,"|",2

add wave,channel,value

wave = waveform name or id. channel 0–3. value 0–255 or an attribute.

add s0,0,128
add s0,0,h0.val

addt wave,channel,qty

Transparent waveform bytes from the host (simulator treats like add).

addt s0,0,20

cle wave,channel

Clear a waveform channel (255 = all), a TouchCap (cle tc0), or a Picture list (cle pl0).

cle s0,0
cle s0,255
cle tc0
cle pl0

Picture list — add / del / cle

When the first argument is a Picture list (pl0): add pl0,2 appends pic 2 · add pl0,1,5 inserts pic 5 at index 1 · del pl0,0 removes index 0 · cle pl0 empties. Also pl0.ch=4 · pl0.txt="0|2|5" · pl0.val=2 · pl0.en=1 auto-scroll · pl0.tim=25 · pl0.dir=0. On a waveform, add s0,0,128 is still widget, channel, sample.

add pl0,2
del pl0,1
pl0.en=1

wepo / repo attrib,addr

Write / read 1 KB EEPROM (RAM in the simulator). Number = 4 bytes LE. String + trailing 0. addr 0–1023.

wepo n0.val,10
repo n0.val,10
wepo t0.txt,20

call name[,arg…]

Run a function from Arduino → Globals (auto-registered on Export). Args: numbers, n0.val, or one "string". int return → sys0.

call startPump
call setSpeed,180
call setSpeed,n0.val
call sayHello,"HI"
call readRaw
nTemp.val=sys0

randset min,max

Range for the rand system variable.

randset 1,100
n0.val=rand

rest · delay=ms · touch_j · doevents

rest — reset to page 0. delay=100 — parsed (simulator does not wait). touch_j — calibrate (log only). doevents — refresh inside a loop.

cls color

cls BLACK

fill x,y,w,h,color

Filled rect. (x,y) top-left.

fill 20,20,150,50,RED

line x1,y1,x2,y2,color

line 20,30,170,200,BLUE

draw x1,y1,x2,y2,color

Hollow rect. (x1,y1) top-left, (x2,y2) bottom-right.

draw 10,10,70,70,GREEN

cir / cirs x,y,r,color

Hollow / filled circle. Center (x,y), radius r.

cir 100,100,30,RED
cirs 100,100,30,RED

pic x,y,picid

pic 10,20,0

picq x,y,w,h,picid

Crop w×h at (x,y) from picture picid and draw it there.

picq 20,50,30,20,0

xpic destx,desty,w,h,srcx,srcy,picid

Crop w×h from (srcx,srcy) of picid; draw at (destx,desty).

xpic 20,50,30,20,15,15,0

xstr x,y,w,h,font,pco,bco,xcen,ycen,sta,text

Draw text in a box. xcen 0 left / 1 center / 2 right. ycen 0 top / 1 center / 2 bottom. sta 0 crop / 1 solid / 2 image / 3 none. text = "OK" or t0.txt.

xstr 10,10,100,30,1,WHITE,GREEN,1,1,1,"OK"

move cid,x1,y1,x2,y2,priority,time

Move widget to (x2,y2). priority 0–100, time ms (runtime jumps to dest).

move t0,0,0,100,80,50,120

setlayer cid1,cid2

Place cid1 above cid2. cid2 = 255 → top.

setlayer t0,n0
setlayer t0,255

play ch,resource,loop

Start Audio, Video, or GMOV (Nextion). ch = id or name. loop 0 once / 1 repeat.

play 0,2,1
play au0,2,1
play vd0,1,1

findfile path,result

Sets result to 1 if a project picture matches path.

findfile "logo.png",n0.val

if / else if / else · while · for

Event scripts only. Braces on their own lines. Compare with == != > < >= <=. Join with && || and no spaces.

if(nTemp.val>80)
{
  tStatus.txt="HOT"
}else if(nTemp.val<0)
{
  tStatus.txt="COLD"
}else
{
  tStatus.txt="ok"
}

while(n0.val<10)
{
  n0.val++
  doevents
}

for(sys0=0;sys0<8;sys0++)
{
  n0.val=sys0
}

System variables

NameMeaningExample
dim / dimsBacklight 0–100. Widget paths work. dim=0 is off.dim=40 · dim=hDim.val
dpPage index (write changes page)n0.val=dp
baud / baudsUART baudbauds=115200
bkcmd0 silent · 1 errors · 2 also OKbkcmd=2
sendxy1 = send touch coordinatessendxy=1
sleep / wup / thupSleep, wake page, wake on touchsleep=1
randRandom (after randset)n0.val=rand
sys0 sys1 sys2Scratch ints. call return → sys0n0.val=sys0
rtc0rtc6Y M D h m s weekdaynYear.val=rtc0
pio0pio7 / pwm4pwm7GPIO / PWMpio1=1

10. Host UART

ASCII command + three bytes FF FF FF.

Serial2.print("nTemp.val=186");
Serial2.write(0xFF); Serial2.write(0xFF); Serial2.write(0xFF);
First byteMeaning
0x00 / 0x01 / 0x1ABad instruction / OK / bad name
0x65Touch: page, component id, 1=press 0=release
0x66Current page (sendme)
0x70 / 0x71String / int32le from get

See examples/host_arduino/host_arduino.ino.

11. Simulator

F5 / Debug: click widgets, type host commands, watch return codes. Round panels are circular here too.

The instruction terminal sends Nextion ASCII commands (ended with FF FF FF) to the simulator, the LCD (Connect LCD — same COM port as Upload), or both. Tick the checkboxes to choose. get n0.val replies show in the log when the panel firmware includes USB return-code mirroring. Close Arduino Serial Monitor first. Upload disconnects the debug serial session so it can use the port.

12. Hardware bindings (v2)

Hardware tab: widget ↔ GPIO/sensor on this ESP32. Types: analog, analog map, NTC, digital in/out, PWM, DHT11/22 temp/hum, DS18B20, BME280 (needs Adafruit lib), custom userRead_<name>().

value = raw * scale + offset. A ! on a pin means the LCD already uses it.

13. Arduino tab (v2)

hmiSetInt("nTemp.val", t);
hmiSetText("tStatus.txt", "OK");
int speed = hmiGetInt("hSpeed.val");
hmiSetInt("vaRun.val", 1);
hmiSetInt("tmPoll.en", 1);

Export downloads a complete Arduino sketch ZIP. Unzip, open the .ino in Arduino IDE, click Upload.

13b. Access from user code

Timers, variables, and widgets share one path language. Use it in event scripts, the Arduino tab, or UART.

PathWhenExample
obj.attrCurrent page, unique name, or global timer/variablevaRun.val · tmPoll.en · nTemp.val
page.obj.attrObject on another pagehome.nTemp.val · settings.hDim.val

Arduino

CommandExample
hmiSetInt("path", n)hmiSetInt("vaRun.val", 1);
hmiGetInt("path")int run = hmiGetInt("vaRun.val");
hmiSetText("path", "s")hmiSetText("tStatus.txt", "OK");
hmiGetText("path")String s = hmiGetText("vaNote.txt");
hmiSetInt("nTemp.val", 24);       // Number
hmiSetInt("zTemp.val", 24);       // Gauge
hmiSetInt("jLoad.val", 40);       // Progress
hmiSetInt("btCool.val", 1);       // Dual-state
hmiSetInt("bStart.vis", 0);       // hide a widget
hmiSetInt("vaRun.val", 1);        // Variable (Number)
hmiSetText("vaNote.txt", "ok");   // Variable (String)
hmiSetInt("tmPoll.tim", 200);     // Timer period
hmiSetInt("tmPoll.en", 1);        // start timer
hmiSetInt("p0.pic", 2);           // Picture resource
hmiSetInt("q0.pic", 1);           // Crop source
hmiSetInt("ex0.pic", 3);          // ExPicture
hmiSetInt("gm0.gmov", 1);         // GMOV clip
hmiSetInt("gm0.en", 1);
hmiSetInt("vd0.vid", 1);          // Video resource
hmiSetInt("vd0.en", 1);
hmiSetText("au0.path", "/sd/beep.wav");
hmiSetInt("au0.en", 1);
hmiSetInt("home.nTemp.val", 24);  // other page
int t = hmiGetInt("nTemp.val");
int on = hmiGetInt("tmPoll.en");

Event script / Debug

vaRun.val=1
tmPoll.en=1
tmPoll.tim=200
nTemp.val=24
tStatus.txt="RUN"
vis bStart,0
if(vaRun.val==1)
{
  tStatus.txt="RUN"
}

UART (other MCU)

Serial2.print("vaRun.val=1");
Serial2.write(0xFF); Serial2.write(0xFF); Serial2.write(0xFF);
Serial2.print("tmPoll.en=1");
Serial2.write(0xFF); Serial2.write(0xFF); Serial2.write(0xFF);
Serial2.print("nTemp.val=24");
Serial2.write(0xFF); Serial2.write(0xFF); Serial2.write(0xFF);
Serial2.print("p0.pic=2");
Serial2.write(0xFF); Serial2.write(0xFF); Serial2.write(0xFF);
Serial2.print("vd0.vid=1");
Serial2.write(0xFF); Serial2.write(0xFF); Serial2.write(0xFF);
Serial2.print("play 0,2,1");
Serial2.write(0xFF); Serial2.write(0xFF); Serial2.write(0xFF);

14. Devices

Grouped: Elecrow · Waveshare (including round 1.28 / 2.1 / 2.8C ●) · SPI LCD (ILI9341, ST7789, GC9A01 round, ILI9488, ST7796, custom) · Generic · Custom. Tags show [SPI] or [RGB].

Device → Edit… sets bus, driver, resolution, UART, GPIO, Flash Size, and Partition Scheme (same names as Arduino IDE Tools, including Custom). Custom writes partitions.csv into the Arduino ZIP. RGB 5"/7" leave few free pins. Pin maps were checked against official Elecrow GitHub / Waveshare wiki tables — see HELP.md §15.1. CrowPanel Basic 7.0 uses EK9716BD3 + EK73002ACGB (not generic RGB565; Advance 7.0 is SC7277). -1 means expander or unused, not a GPIO. Do not drive GPIO2 as backlight on Waveshare 4.3/5/7 (that pin is red data).

15. Compile and flash

ActionResult
CompileChecks names, scripts, bindings, SPI/RGB pins, display/touch drivers, PSRAM
Save / Open.hmi.json source
ExportArduino sketch ZIP. Warns first on wrong pins, incompatible drivers, missing PSRAM, or unsupported touch
Export LVGL UI C / toolbar LVGLUI-only LVGL v9 C ZIP. No firmware. Call ui_init() after your display exists. Version 9.4 / 9.5 / 9.6
UploadWeb Serial UI file (optional after the first flash)
Unzip → open SketchName.ino in Arduino IDE
Libraries: LovyanGFX + ArduinoJson 7.x
Board: ESP32 Dev Module  or  ESP32S3 Dev Module
Partition Scheme: Huge APP
Upload

The UI is compiled into ui.ehmi on LittleFS (editor Upload). Before Export, the editor lists configuration mistakes (SPI pins vs the preset, RGB on a non-S3, ILI9341 on an RGB bus, XPT2046 without TOUCH_CS, GT911/CST816 without TOUCH_SDA/TOUCH_SCL, flash/PSRAM GPIOs). Device → Edit shows the same check live. RGB panels still need Arduino IDE PSRAM = OPI PSRAM. If Partition Scheme is Custom, the ZIP includes partitions.csv — Arduino IDE Tools → Partition Scheme = Custom.

16. Cheat sheet

page home
t0.txt="Hello"
nTemp.val=24
vaRun.val=1
tmPoll.en=1
vis bStart,0
dim=50
if(vaRun.val==1)
{
  tStatus.txt="RUN"
}

More detail, firmware API, and limitations: HELP.md in this folder.