
1. 从 Air8101 到 AirUISuntime 时间应用到底解决什么问题Suntime 是 OpenLuat 生态里一个专门做日出日落时间计算的模块跑在 LuatOS 上配合 AirUI 轻量化图形框架能在 Air8101 这类工业引擎模组上做出一个完整的「日出日落时间」app。它能做什么简单说你给它一个城市或者经纬度它算出当天的日出、日落时刻再顺手把白昼时长、黄昏结束、正午参考时间一起算出来最后在屏幕上做一个倒计时——距离日落还有几小时几分钟。适合谁适合手上有一块 Air8101 畅玩板、想学 LuatOS AirUI 做嵌入式 UI 的开发者也适合做低资源硬件时间类功能验证的工程师。我试过在 PC 模拟器上先把界面跑通再烧到真机整个过程踩的坑主要集中在图片资源路径和 AirUI 的 image 组件加载上。这篇文章会把 Suntime 的初始化配置、AirUI 页面绑定、Air8101 烧录验证这几步拆开讲每一步都给可复制的命令和配置。另外开发过程中如果要用 AI 工具辅助生成代码API 调用的 Key 管理可以走 TaoToken 统一通道后面会给出具体配置。先明确一个概念Air8101 是工业引擎主机的一种以 Air8101 系列模组为主控出厂自带 engine_host 软件支持开机欢迎界面、待机界面、主菜单、WiFi 设置、系统设置和应用市场。你开发的 app 不是出厂固件的一部分而是通过应用市场下载安装后运行的。所以 Suntime 这个 app 的代码要放到app_store/vertical_app目录下每个子目录是一个独立 app。分辨率这块要注意Suntime 的 UI 基于竖屏 480×800 设计这是「你的 app 基准分辨率」。Air8101 引擎整机的物理分辨率是 480×854出厂软件会自动把 480×800 自适应到 480×854不需要 app 做特殊处理。也就是说你按 480×800 设计真机上能正常跑。Suntime 的核心功能就四块配置城市或自动定位、展示当日日出日落时刻、同步白昼时长和黄昏/正午参考时间、倒计时。听起来不复杂但要在 Air8101 上跑通涉及 LuatOS 的 Suntime 库调用、AirUI 的窗口和控件绑定、资源文件的路径映射还有真机烧录验证。下面按步骤来。2. TaoToken 前置统一 Key 通道管理 API 调用在开始写 Suntime 代码之前先把 AI 辅助开发这条链路理顺。你用 Trae 或者其他 AI 工具生成 LuatOS 代码时如果用的是收费大模型需要配置 API Key。TaoToken 的作用就是把这些 Key 统一管起来一个通道走通模型对话、代码生成、文档查询这些调用。TaoToken 是什么它是一个 API 统一接入层把不同模型的调用收敛到一个 Base URL 和一套 Key 上。你能做什么在 Trae、Cline、Claude Code 这类工具里把 Base URL 指向 TaoToken 的 API 地址Key 用 TaoToken 生成的 KeyModel ID 填你要用的模型就能统一管理调用。适合谁适合同时用多个 AI 工具、不想在每个工具里分别配 Key 的开发者。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。注意 API 地址后面不加 UTM 参数直接写就行。具体到 Suntime 开发场景你在 Trae 里配置 luatos-docs-code 智能体时需要选一个模型。如果选收费模型就在 Trae 的模型设置里填 TaoToken 的 Base URL 和 Key。这样你在 Trae 里发的每一条「生成 Suntime 代码」的请求都走 TaoToken 通道。配置的时候有三个东西必须填全Base URL、API Key、Model ID。少一个都会报 401 或者 model not found。Base URL 填https://taotoken.net/apiKey 在 TaoToken 控制台的 API Keys 页面生成Model ID 根据你用的模型填比如claude-sonnet-4-20250514或者gpt-4o这类。如果你只是想让 AI 帮你润色一段 Suntime 的 Lua 代码或者解释一个 AirUI 的报错可以用模型对话功能地址是 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel-chat 。如果是长期做 LuatOS 编码和 Agent 任务建议看 Coding Plan地址是 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding-plan 。Key 生成在控制台地址是 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentconsole 。接入文档在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc 。这里要提醒一句TaoToken 是合法的 API 接入通道不是中转不要把它理解成别的东西。你用它管理的是自己订阅的模型调用Key 是你自己生成的调用量也是你自己控制的。配置好之后在 Trae 里验证一下发一条「你好请回复 OK」的请求如果能正常返回说明通道通了。如果报 401检查 Key 是否复制完整如果报 local proxy failed检查 Base URL 是否写成了https://taotoken.net/api而不是别的路径如果报 reading choices 相关错误检查 Model ID 是否拼写正确。3. 可复制配置Suntime 初始化与 AirUI 页面绑定这一章是核心给出 Suntime 在 LuatOS 上的初始化配置、AirUI 窗口绑定、以及资源路径的完整代码片段。你直接复制到自己的项目里改改就能用。3.1 项目目录结构先在app_store/vertical_app下建 Suntime 目录结构如下Suntime/ ├── main.lua ├── meta.json ├── icon.png ├── user/ │ ├── suntime_win.lua │ ├── config.lua │ └── message.lua ├── res/ │ ├── sunrise.png │ ├── sunset.png │ └── bg.png └── libs/main.lua是入口user/放业务逻辑res/放图片资源libs/放扩展库如果出厂软件已包含就不用重复放。3.2 main.lua 入口配置PROJECT SUNTIME VERSION 001.999.000 log.info(main, PROJECT, VERSION) require suntime_win sys.publish(OPEN_SUNTIME_WIN) sys.run()前四行是项目信息配置和打印和 LuatOS 完整项目格式保持一致。require suntime_win加载 user 目录下的窗口模块sys.publish发布打开窗口的事件。sys.run()在沙箱环境里会被禁用但保留是为了格式统一。3.3 meta.json 元数据{ app_name_cn: 日出日落, app_name_en: suntime, version: 1.0.0, publish_time: 2026-04-23 12:00:00, category: 工具, description: 展示当日日出日落时刻、白昼时长与倒计时, resolution: 480x800, supported_models: { Air8101: [ { firmware_id: 104, min_firmware_version: 2010 }, { firmware_id: 105, min_firmware_version: 2010 } ] }, zip_size_kb: 120, origin_size_kb: 350 }version 必须是 x.y.z 格式从 1.0.0 开始。supported_models 里填 Air8101 的 firmware_id 和最低固件版本。3.4 Suntime 初始化配置在user/suntime_win.lua里做 Suntime 的初始化。Suntime 库的核心是设置经纬度和时区然后调用计算函数。local suntime require suntime local config { latitude 39.9042, longitude 116.4074, timezone 8, city 北京 } local function init_suntime() suntime.set_location(config.latitude, config.longitude, config.timezone) local result suntime.get_today() if not result then log.error(suntime, 计算失败检查经纬度参数) return nil end log.info(suntime, 日出, result.sunrise, 日落, result.sunset) log.info(suntime, 白昼时长, result.day_length, 分钟) return result endsuntime.set_location设置纬度、经度、时区。suntime.get_today()返回当天的日出日落数据包含 sunrise、sunset、day_length、dawn_end、noon 这些字段。如果返回 nil先检查经纬度是否在合法范围内。3.5 AirUI 窗口绑定AirUI 的窗口用 exwin 扩展库管理。在suntime_win.lua里创建窗口、绑定控件、刷新数据。local exwin require exwin local win_id nil local label_sunrise, label_sunset, label_countdown local function create_ui() win_id exwin.open({ name suntime_win, layout vertical, width 480, height 800 }) local img_sunrise airui.image({ parent win_id, src /luadb/sunrise.png, x 60, y 120, w 80, h 80 }) label_sunrise airui.label({ parent win_id, text --:--, x 160, y 140, font_size 32 }) local img_sunset airui.image({ parent win_id, src /luadb/sunset.png, x 60, y 260, w 80, h 80 }) label_sunset airui.label({ parent win_id, text --:--, x 160, y 280, font_size 32 }) label_countdown airui.label({ parent win_id, text 计算中..., x 60, y 420, font_size 24 }) end local function refresh_ui(data) if not data then return end label_sunrise:set_text(data.sunrise) label_sunset:set_text(data.sunset) local now os.time() local sunset_ts data.sunset_timestamp if sunset_ts and sunset_ts now then local diff sunset_ts - now local hours math.floor(diff / 3600) local mins math.floor((diff % 3600) / 60) label_countdown:set_text(string.format(距离日落还有 %d 小时 %d 分钟, hours, mins)) else label_countdown:set_text(今日日落已过) end end local function on_open() create_ui() local data init_suntime() refresh_ui(data) end sys.subscribe(OPEN_SUNTIME_WIN, on_open)这里的关键点图片路径用/luadb/xxx.pngAirUI 会自动映射到 app 的 res 目录。exwin.open创建窗口airui.image和airui.label创建控件。refresh_ui里做倒计时计算用os.time()拿当前时间戳和日落时间戳做差。3.6 资源路径映射规则AirUI 的路径映射规则要记清楚不然图片加载会报failed to get image info代码中路径实际映射/luadb/icon.png/icon.png应用图标/luadb/xxx.lua按优先级映射到/xxx.lua、/user/xxx.lua、/libs/xxx.lua/luadb/xxx.png非 lua/res/xxx.png/ram/xxx/ram/xxx内存文件系统/xxx其他/data/xxx所以图片放res/目录代码里写/luadb/图片名.png就行。注意图片文件名不能有中文否则识别不了。4. 验证请求PC 模拟器跑通与 Air8101 烧录代码写完了先在 PC 模拟器上验证再烧到 Air8101 真机。4.1 PC 模拟器运行把app_store文件夹复制到 LuatOS PC 模拟器所在目录。模拟器目录下有luatos-pc-64bit.exe和cmd快捷方式。双击 cmd输入luatos-pc-64bit.exe D:\git\LuatOS-develop\module\Air8101\project\AirUIFrame\ui_play_board\factory\ D:\git\LuatOS-develop\script\libs\回车后模拟器启动显示 Air8101 UI 畅玩板的出厂软件界面。鼠标模拟左右滑屏翻到第三页能看到 Suntime 的图标。点击图标运行 app。如果图片正常显示日出日落时刻和倒计时都出来了说明代码没问题。如果图片不显示看日志里有没有lv_image_set_src: failed to get image info有的话检查图片路径和文件名。4.2 验证 Suntime 计算结果在模拟器里点开 Suntime看日志输出I/user.suntime 日出 05:42 日落 18:56 I/user.suntime 白昼时长 794 分钟对比一下手机天气 app 里的日出日落时间误差在几分钟内是正常的因为 Suntime 用的是天文算法和气象台的数据源可能略有差异。4.3 Air8101 真机烧录真机烧录需要 Air8101 畅玩板一块、Type-C 数据线一根、Win10 及以上电脑。烧录工具用 LuatOS 的烧录软件选择对应的固件版本。烧录步骤把 Air8101 通过 Type-C 连到电脑打开烧录工具选择LuatOS-SoC_V2027_Air8101固件加载app_store目录点击下载。烧录完成后模组自动重启进入出厂软件界面。在真机上滑到 Suntime 图标点击运行。真机的物理分辨率是 480×854出厂软件会自动把 480×800 的 UI 自适应过去界面不会变形。4.4 验证时间同步Air8101 真机如果连了 WiFi可以通过 SNTP 同步网络时间。日志里会看到I/user.sntp 高精度时间戳 1776931384.647这个时间戳用于倒计时计算。如果没连 WiFiSuntime 会用模组内部 RTC 时间可能有偏差。建议在 app 启动时先触发一次 SNTP 同步再计算日出日落。4.5 验证 AirUI 刷新倒计时需要定时刷新。在suntime_win.lua里加一个定时器sys.timerLoopStart(function() local data suntime.get_today() refresh_ui(data) end, 60000)每 60 秒刷新一次更新倒计时显示。真机上观察几分钟看倒计时是否在走。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth开发过程中遇到的报错分两类一类是 TaoToken 通道配置问题一类是 Suntime/AirUI 代码问题。分开说。5.1 TaoToken 通道报错401 UnauthorizedKey 没填、填错、或者过期了。去 TaoToken 控制台的 API Keys 页面重新生成一个复制完整注意不要有多余空格。在 Trae 的模型设置里Base URL 填https://taotoken.net/apiKey 填新生成的Model ID 填对。local proxy failedBase URL 写错了。检查是不是写成了https://taotoken.net/api/v1或者其他路径。正确的就是https://taotoken.net/api后面不加东西。如果还报错检查网络是否能访问 taoToken.net。reading choices 相关错误通常是 Model ID 拼写错误或者模型不支持当前请求格式。检查 Model ID 是否和 TaoToken 文档里列的一致。比如claude-sonnet-4-20250514不要写成claude-sonnet-4。OAuth 报错如果你在 Claude Code 里配置 TaoTokenOAuth 流程可能和直接填 Key 不一样。Claude Code 的配置在~/.claude/settings.json或者项目级的.claude/settings.json。配置片段如下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: 你的TaoToken Key } }注意 Claude Code 用的是ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY这两个环境变量。如果报 OAuth 错误检查是不是没走 API Key 模式而是走了 OAuth 模式。在 settings.json 里显式配置 API Key 就能绕过 OAuth。5.2 Suntime/AirUI 报错图片不显示日志报lv_image_set_src: failed to get image info: /app_store/air_quality/icon.png这是 AirUI 在加载图片时找不到文件。检查三点图片是否放在res/目录下代码里路径是否写成了/luadb/图片名.png图片文件名是否有中文。如果图片名是日出.png改成sunrise.png。app 打不开日志报require enter: suntime_win后没下文检查user/suntime_win.lua是否存在main.lua里的require名字是否和文件名一致。LuatOS 的 require 不带.lua后缀。倒计时不刷新检查sys.timerLoopStart是否在窗口打开后调用。如果放在on_open外面窗口还没创建就启动定时器会报 nil 错误。真机上界面错位检查meta.json里的resolution是否写成了480x800。如果写成480*800解析会出错。烧录后 app 不出现检查app_store目录是否完整复制到了烧录工具的加载路径。meta.json里的supported_models是否包含 Air8101 的 firmware_id。5.3 三件套配置检查如果你在 Trae 里用 Cline MCP 或者 Codex auth.json 配置 TaoToken确保三件套齐全Base URLhttps://taotoken.net/apiAPI KeyTaoToken 控制台生成 Model ID根据模型填Codex 的auth.json配置片段{ openai_api_key: 你的TaoToken Key, openai_api_base: https://taotoken.net/api }Cline MCP 的配置在 Cline 设置里选 OpenAI CompatibleBase URL 填https://taotoken.net/apiAPI Key 填 TaoToken KeyModel ID 填你要用的模型。CC Switch 的配置类似在切换模型时选自定义填 Base URL 和 Key。6. 语义一致 CTA按场景分流Suntime 在 Air8101 上的开发核心链路是LuatOS 的 Suntime 库做时间计算AirUI 做界面绑定PC 模拟器验证真机烧录。这条链路跑通后你可以把同样的模式套到其他时间类 app 上比如倒计时、闹钟、日程提醒。开发过程中如果遇到 AI 工具配置问题按场景分流排障和接入问题看 API Keys 和接入文档。API Keys 在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi-keys 接入文档在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc 。验证模型是否通用模型对话地址是 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel-chat 。长期做 LuatOS 编码和 Agent 任务看 Coding Plan地址是 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding-plan 。Claude Code 接入 Anthropic 模型的配置参考 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentclaudecode-anthropic 。最后说一个实际经验Suntime 的图片资源导出时让 AI 把表情和图标都转成 30×30 透明背景的 PNG文件名用英文。这一步偷懒的话后面在 AirUI 里加载图片会反复报错改文件名改到崩溃。另外Trae 生成的第一版代码大概率不能直接跑图片路径和控件坐标都要调耐心对着日志改改到模拟器上正常显示再烧真机。