跳转至

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() 和新版契约为准,不能根据公式手册猜测。

协作验收清单

  1. 使用公开 Contract/Client SDK,不复制 EVCC 主应用内部类。
  2. 校验 API 主版本,并在用户授权后重新连接。
  3. 将同步 Binder 调用放到工作线程;回调只做快速入队或界面更新。
  4. 对 AVAILABLE、未初始化、歧义、断源和权限撤销分别处理。
  5. 把订阅当完整集合管理,并验证重启后的初始快照和事件缺口重同步。
  6. 对写入和动作先使用 validateOnly,再用新的 requestId 实际执行。
  7. 不把应用网络、数据库、计时器或后台生命周期转嫁给 EVCC。

继续阅读变量与动作、初始化、监听与重同步和 权限与授权。