LVGLStudio AI 编程

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 编程接口排障。

本软件为免费开放使用的项目。

有想说的评论一句吧!