Lua、自动化与开放 API 的协作¶
最后更新:
EVCC 开放 API、Lua 和自动化是三种平级的开发方式。它们共享属性和变量等能力,但运行位置、信任 边界和生命周期不同。需要跨应用访问的车辆数据和受控动作适合 EvccApi;需要在 EVCC 内运行的复杂 逻辑适合 Lua;可视化本地联动适合自动化。第三方应用自己的界面、网络和持久化应留在应用沙箱中。
先选择合适的入口¶
| 需求 | 推荐入口 | 原因 |
|---|---|---|
| 在 EVCC 内快速编排车辆状态和动作 | 自动化 | 图形化配置,规则生命周期由 EVCC 管理 |
| 在 EVCC 内执行循环、HTTP、JSON 或复杂状态机 | Lua | 脚本直接运行在 EVCC 的受信任环境中 |
| 独立 Android 应用读取、监听或受控修改 EVCC 状态 | EvccApi | 有独立应用身份、权限、会话和类型化契约 |
| 把数据发送到远端服务 | 第三方应用自己的网络栈,或小程序 MQTT | EvccApi 本身不是网络 API,也不替应用代理 HTTP |
不要为了复用一段 Lua,把脚本文本交给 Shell 执行。EvccApi 不提供远程 Lua 解释器,Shell 也不是绕过 API 权限模型的后门。
能力对应表¶
| 原能力 | EvccApi 方案 | 主要差异 |
|---|---|---|
property.read() |
readProperty() / readProperties() |
返回类型化值、初始化状态、实际来源和候选项 |
property.info() / property.list() |
resolveProperty() / 分页目录 |
可按名称、ID、来源和区域解析,目录必须分页 |
property.on_change() |
replaceSubscriptions() + 属性回调 |
订阅是当前会话的完整需求集合;先收到初始快照,再收增量 |
property.write() |
writeProperty() / writeProperties() |
需要独立授权;批量写入不是事务,选源失败不会换源重放 |
var.read/list() |
readVariable() / queryVariables() |
可同时看到公开的自定义变量和只读内置变量 |
var.on_change() |
replaceVariableSubscriptions() + 变量回调 |
不会自动监听全部变量;重绑时 SDK 恢复整批集合 |
var.write/delete() |
writeVariable() / deleteVariable() |
受配额、类型、可写性和权限检查 |
| 启动应用、返回桌面、提示 | executeAction() |
使用稳定动作 ID 和 JSON 参数,先查询能力并预检查 |
| 触发另一条自动化 | automation.trigger |
目标规则必须当前可运行,并需要高权限动作授权 |
shell.exec() |
executeShell() / cancel() |
另行授权,且有永久黑名单、超时、输出和并发限制 |
http.*、storage.*、定时器 |
第三方应用自行实现 | 使用应用自己的网络权限、沙箱、协程和 Android 生命周期 |
widget.*、float_btn.*、脚本生命周期 |
无直接映射 | 属于 EVCC 内部界面或脚本运行时,不是跨应用 API |
完整能力以客户端取得的 EvccApiInfo、EvccSessionInfo.grantedPermissions 和
queryCapabilities() 为准。Lua 或自动化手册里出现的能力,不代表开放 API 必然提供同名方法。
Recipe:在独立应用中监听属性¶
Lua 的监听处理器通常接收一次当前值,再持续处理变化。EvccApi 对应流程是:建立会话、整批替换订阅、
接受 INITIAL_SNAPSHOT 建立基线,然后处理 VALUE_CHANGED 或 SOURCE_CHANGED。
private val speed = EvccPropertySelector(
id = 557849089L,
source = EvccApiContract.Source.AUTO,
)
private val client by lazy {
EvccApiClient(applicationContext, listener = object : EvccApiClient.Listener {
override fun onSessionReady(apiInfo: EvccApiInfo, sessionInfo: EvccSessionInfo) {
lifecycleScope.launch(Dispatchers.IO) {
val result = client.replaceSubscriptions(listOf(speed))
check(result.isSuccess) { result.message }
}
}
override fun onPropertyEvent(
record: EvccPropertyRecord,
sequence: Long,
eventType: String,
) {
if (record.status != EvccApiContract.Status.AVAILABLE) return
val value = record.value ?: return
renderSpeed(value.displayValue, record.resolvedSource, eventType)
}
override fun onResyncRequired(expectedSequence: Long, actualSequence: Long) {
// SDK 会重新提交订阅并取得新的初始快照;业务先暂停使用旧的增量基线。
}
})
}
replaceSubscriptions() 不是“追加一个监听”。再次调用时,列表中缺少的旧项目会被取消。多个页面或
模块共享一个客户端时,应先在应用内合并需求,再一次提交完整集合。应用销毁时调用 client.close();
SDK 会处理 Binder 重绑和订阅恢复,但不会替应用决定界面或后台常驻策略。
Recipe:共享状态使用变量¶
需要让 Lua、自动化和第三方应用交换少量业务状态时,使用 EVCC 变量;应用自己的缓存、大对象和高频 遥测仍应保存在应用沙箱中。
val result = withContext(Dispatchers.IO) {
client.writeVariable(
EvccVariableWriteRequest(
requestId = UUID.randomUUID().toString(),
name = "companion_mode",
value = EvccValue.ofString("eco"),
validateOnly = false,
)
)
}
写入前检查本会话是否具备 variable.write。读取结果还要检查 status 和 value.initialized,不要把
缺失、未初始化或权限不足都解释为空字符串。
Recipe:由应用触发一条现有自动化¶
复杂车辆动作可以继续由用户在 EVCC 自动化中配置,第三方应用只请求触发已经存在且当前可运行的规则:
val request = EvccActionRequest(
requestId = UUID.randomUUID().toString(),
actionId = "automation.trigger",
argumentsJson = JSONObject().put("ruleId", ruleId).toString(),
validateOnly = true,
)
val check = withContext(Dispatchers.IO) { client.executeAction(request) }
预检查通过后,使用新的 requestId 并把 validateOnly 改为 false 执行。能力发现中对应的 ID 是
action.automation.trigger,实际请求的动作 ID 是 automation.trigger。用户仍可在 EVCC 中停用规则
或撤销应用权限,客户端必须处理执行时权限失效。
公式与模板表达式¶
EVCC 的公式、模板块和跨属性表达式属于自动化与界面配置能力。EvccApi 1.0 不提供“提交表达式并由 EVCC 求值”的接口,也不会把公式手册中的函数自动变成 Binder 方法。
- 只依赖已读取属性的计算,应在第三方应用内使用明确类型自行完成。
- 必须沿用 EVCC 规则语义的逻辑,应保留在自动化中,由应用读取共享变量或触发规则。
- 不要把公式字符串塞入属性 ID、变量名、动作参数或 Shell,以免得到错误结果或扩大风险边界。
- 如果未来协议新增表达式能力,应以
queryCapabilities()和新版契约为准,不能根据公式手册猜测。
协作验收清单¶
- 使用公开 Contract/Client SDK,不复制 EVCC 主应用内部类。
- 校验 API 主版本,并在用户授权后重新连接。
- 将同步 Binder 调用放到工作线程;回调只做快速入队或界面更新。
- 对
AVAILABLE、未初始化、歧义、断源和权限撤销分别处理。 - 把订阅当完整集合管理,并验证重启后的初始快照和事件缺口重同步。
- 对写入和动作先使用
validateOnly,再用新的requestId实际执行。 - 不把应用网络、数据库、计时器或后台生命周期转嫁给 EVCC。
继续阅读变量与动作、初始化、监听与重同步和 权限与授权。