LVGLStudio AI 编程
需要 v0.2.0 及以上版本。
LVGLStudio 内置了一个只监听本机(127.0.0.1)的 HTTP 服务,供 AI 编程工具(Claude Code、Cursor、Cline 等)直接操作你的工程。
关键在于:它不只是让 AI 改代码,还让 AI 自己验证改得对不对 —— 读编译日志、拿运行画面、模拟触摸和旋钮。全程不用你截图确认,也不用你替它点按钮。
它解决什么问题
没有这组接口时,AI 写完代码只能交给你看效果。它看不到编译报错的完整信息,也看不到画面跑出来是什么样,于是常常是”看起来写完了”,实际编译不过,或者界面根本没画出来。
有了这组接口,AI 可以自己走完一个闭环:
改代码 → 重新运行 → 看运行态 → 读日志 → 看画面 → 模拟点击验证 → 再改
这个循环里的每一步都不需要你介入。对 AI 工具来说,这意味着它从”代写代码”变成了”能自己调试”。
接入只需三步
1. 启动 LVGLStudio
服务随应用启动自动开启(默认状态),不需要任何额外设置。如果你之前在「设置」里关掉了它,需要先重新打开。
2. 读连接信息
服务启动成功后,会在 ~/.LVGLStudio/connection.md 写出一个自描述的入口文件,里面包含服务地址、访问令牌(token)和上手说明:
---
version: 0.2.0
baseUrl: http://127.0.0.1:8848
docUrl: http://127.0.0.1:8848/doc
token: …64 位十六进制…
---
不需要注册任何东西,也不用安装插件或配置文件。AI 工具拿到这个文件路径,读一遍就知道该连哪里。
3. 带 token 调用
除 /doc 外的所有接口都需要携带 token,三种传法任选其一:
Authorization: Bearer <token>
X-LVGL-Token: <token>
?token=<token>
第一个请求
# 从入口文件里取出服务地址和 token
CFG=$HOME/.LVGLStudio/connection.md
BASE=$(sed -n 's/^baseUrl: //p' "$CFG")
TOKEN=$(sed -n 's/^token: //p' "$CFG")
# 看看有哪些工程
curl "$BASE/api/project/list" -H "Authorization: Bearer $TOKEN"
能做什么
| 分类 | 能力 |
|---|---|
| 工程 | 列出 / 查询 / 新建 / 修改 / 删除工程,获取官方演示模板列表 |
| 文件 | 列出目录、读取源码、新建、改写、改名、移动、删除 |
| 预览 | 打开 / 关闭预览窗口,查询当前开着的预览 |
| 运行态 | 查程序跑到哪一步了:读工程 / 编译中 / 已运行 / 失败 |
| 日志 | 读取预览窗口里那份编译日志与 printf 输出,失败时带文件名、行列号、出错源码 |
| 画面 | 取预览窗口渲染出的那张画面,存成图片直接看 |
| 输入 | 往运行中的程序注入触摸与编码器事件,验证交互是否生效 |
| 重跑 | 改完代码重新编译运行,并清空上一次的日志 |
后四行是让 AI 能自我验证的关键,也是这一版的主要能力。
观测与验证:闭环怎么走
1. 打开预览,然后等它真的跑起来
窗口打开 ≠ 程序跑起来了 —— 预览要真正编译一遍,可能成功也可能失败。先看运行态:
curl "$BASE/api/preview/status?project=my-demo" -H "Authorization: Bearer $TOKEN"
它会告诉你程序现在处在哪一步:
| 运行态 | 含义 | 该做什么 |
|---|---|---|
loading |
正在读工程 | 等 |
compiling |
正在编译链接(要几十秒) | 等,别重复触发重跑 |
running |
已经跑起来了 | 可以注入输入、拿画面 |
failed |
编译或启动失败 | 读错误信息,再取日志看详情 |
idle |
还没开始 | 触发重跑 |
unknown |
窗口没应答 | 看 error 里的说明,分两种情况,见下 |
轮询它就能知道该等还是该动手,不用 sleep 猜时间。 这一步很重要:编译要几十秒,不等就取日志只会拿到一个空壳。
停在 unknown?看 error 分两种,处理方式相反
error 里写着 |
真实情况 | 该做什么 |
|---|---|---|
| 页面可能还没加载完 | 窗口刚开,页面还没挂上 | 等一会儿再问一次 |
| 程序运行到某一步后没能再出来 | 程序卡住了,窗口不会再有反应 | 别等了,去查代码 |
第二种要特别注意:程序在预览窗口里跑,一旦它进了出不去的循环,窗口就再也醒不过来 —— 日志停在最后一行、界面不刷新。工具只能告诉你”卡住了”,不会替你猜是哪一行的问题,需要你(或者 AI)自己看日志最后几行,确定程序停在哪一步,再排查那之后调用的代码。
遇到这种情况直接重新触发重跑:
curl -X POST "$BASE/api/preview/restart" -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d '{"project":"my-demo"}'
2. 编译没过?看日志
curl "$BASE/api/preview/logs?project=my-demo" -H "Authorization: Bearer $TOKEN"
拿到的是预览窗口里那份日志,和界面上看到的完全是同一份。编译失败时报错带文件名、行列号、出错源码,AI 可以直接照着改,不用把整段日志转述给你。
默认只返回末尾若干行(排查时”最后发生了什么”才是关键)。要全部内容在后面加 &tail=0。
3. 跑起来了?看画面
curl "$BASE/api/preview/screenshot?project=my-demo" \
-H "Authorization: Bearer $TOKEN" \
| sed -n 's/.*"data" *: *"\([^"]*\)".*/\1/p' | base64 -d > shot.png
取回的是程序真正画出来的那张图,尺寸和你工程里设的分辨率一致。AI 能直接看这张图,判断布局对不对、控件有没有重叠、文字有没有截断 —— 这是它第一次能”看到”自己的运行结果。
4. 交互对不对?注入输入
程序跑起来了,但按钮点了有没有反应,还得试一下:
# 依次点一下画面中某个位置
curl -X POST "$BASE/api/preview/input" -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"project":"my-demo","type":"touch","phase":"move","x":120,"y":120}'
curl -X POST "$BASE/api/preview/input" -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"project":"my-demo","type":"touch","phase":"down","x":120,"y":120}'
curl -X POST "$BASE/api/preview/input" -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"project":"my-demo","type":"touch","phase":"up","x":120,"y":120}'
也可以注入编码器(type 换成 encoder,key 传 LV_KEY_LEFT / LV_KEY_ENTER 等)来测方向键和确认键。
两个容易踩的点:
- 点击要分三次调用:
move→down→up,并且down和up之间隔开一点时间。程序不是实时读取输入的,同一瞬间按下抬起会被忽略。 - 坐标必须在画面范围内:有效范围是
0..width-1×0..height-1,也就是你工程里设的分辨率。越界会被直接拒绝并在报错里告诉你范围。
注入完再取一次截图,对比前后画面,就知道这次点击到底有没有生效 —— 这是 AI 判断”交互是否实现”的唯一可靠方式。
5. 改完代码?重新跑
curl -X POST "$BASE/api/preview/restart" -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d '{"project":"my-demo"}'
注意:再次调用「打开预览」不会重新编译,预览是幂等的,窗口已经开着就直接复用。改了代码要靠这个接口重跑。
它会清空上一次的日志,所以取到的日志只反映这一次运行,不会混着上次的报错。
完整示例
CFG=$HOME/.LVGLStudio/connection.md
BASE=$(sed -n 's/^baseUrl: //p' "$CFG")
TOKEN=$(sed -n 's/^token: //p' "$CFG")
H="Authorization: Bearer $TOKEN"
# 1. 建工程,带上官方示例模板
curl -X POST "$BASE/api/project/create" -H "$H" -H "Content-Type: application/json" \
-d '{"name":"my-demo","demoId":"lvgl-widget-demo"}'
# 2. 打开预览
curl -X POST "$BASE/api/preview/open" -H "$H" -H "Content-Type: application/json" \
-d '{"project":"my-demo"}'
# 3. 等它跑起来(compiling 要几十秒,别急)
until [ "$(curl -s "$BASE/api/preview/status?project=my-demo" -H "$H" \
| sed -n 's/.*"phase":"\([a-z]*\)".*/\1/p')" = "running" ]; do sleep 5; done
# 4. 确认画面真的画出来了
curl "$BASE/api/preview/screenshot?project=my-demo" -H "$H" \
| sed -n 's/.*"data" *: *"\([^"]*\)".*/\1/p' | base64 -d > shot.png
完整文档在哪
接口会随版本演进,所以完整清单不在本页维护,而是由应用自己在运行时提供:
curl "$BASE/doc"
返回一份 Markdown 文档,包含每个接口的参数、返回结构和错误码,永远和你正在运行的版本一致。把它整份喂给你的 AI 工具即可。
另外 GET $BASE/doc/resource 是一份内置资源清单:能用的字体、图片、控件、demo 函数都在里面,每一项都核对过确实可用。写代码前先拉它 —— 不在清单里的符号不存在,照上游 LVGL 文档写名字会直接编译失败。
注意这份清单的分工:它只回答“这个运行环境里哪些东西确实存在”,不解释控件怎么用、参数什么意思、LVGL 8 和 9 的写法差异 —— 那些属于 LVGL 官方文档的职责,以官方文档为准。清单里另外标出了这个环境特有的坑(哪些东西没编进来、哪些符号要自己 extern、哪些行为和上游不一样),那部分才是它真正要帮你的。
注意事项
printf和puts可以直接用,不用加任何头文件。它们的输出会进到预览窗口下方的运行时控制台,和编译日志是同一份,GET /api/preview/logs就能读到 —— AI 可以据此判断程序跑到哪一步、执行到哪个分支。输出是即时的,程序里fflush也不会让它提前消失。- LVGL 本身怎么写,查 LVGL 官方文档。这份站点文档和应用内置的
/doc只负责”这个环境里有什么、出错怎么查”,不重复官方文档的内容。 - token 每次启动都会变,并在应用退出时随入口文件一起删除。不要缓存,用之前重新读一次
~/.LVGLStudio/connection.md。收到401基本就是这个原因。 - 可以在应用里开关。托盘菜单或应用菜单的「设置」窗口里有一个开关,关掉会立即停止服务并删除入口文件,正在连接的 AI 工具会调用失败。
- 端口默认 8848,被占用时会自动往后顺延,所以不要写死地址,一切以入口文件里的
baseUrl为准。 - 新建的工程是空的,只有配置没有源文件。创建时带上示例模板参数,或自己写一份
main.c,否则跑起来是个空程序。 - 先读再写。读文件用
GET /api/file/read,确认内容后再改,能避免覆盖掉你没预期的代码。 - 删除操作不可撤销。
rmdir是递归删除,会连带子目录和文件一起删掉,调用前请确认路径。 - 改工程配置是整体覆盖。分辨率、LVGL 版本、编译宏这几项之间不是合并关系,建议先查一次当前配置,在其基础上改完整份回传。
- 服务只监听本机回环地址,不会暴露到局域网或公网。
连不上?
按这个顺序排查:先确认应用在运行、~/.LVGLStudio/connection.md 存在;再看「设置」里服务开关是否打开;最后比对文件里的地址。详细说明见 帮助页 · AI 编程接口排障。
本软件为免费开放使用的项目。