EVCC 公式与变量系统参考手册¶
最后更新:
EVCC 内置了一套完整的表达式计算引擎,可在控制台卡片、悬浮窗、状态栏信息卡、自动化规则等多个场景中使用。本文档详细说明所有支持的语法、函数和使用方式。
按 EVCC
v2.9.61源码核对,更新日期:2026-08-17。本手册同时包含快速上手和完整参考;Lua 中读取同一套变量的方法见《EVCC Lua 脚本手册》。
快速上手¶
先记住下面五种写法,就能完成大多数配置:
x * 0.1 控制台/悬浮窗中转换当前属性值
$speed * 3.6 读取自定义变量并计算
$prop(557849089) 读取另一个车辆属性
clamp($current + $ble_rotation, 0, 100)
用 BLE 旋钮在 0~100 内调节当前值
温度: {round(x * 0.1)}°C 在文字中嵌入计算结果
基本规则:
x只在控制台、悬浮窗、状态栏信息卡等有“当前属性”的显示表达式中有值;$name或${name}读取 EVCC 变量,$prop(十进制属性ID)读取车辆属性;- 数字可以直接使用
+ - * / % ^、括号和函数; - 固定文字放进表达式时要加英文引号,普通文字中嵌入计算请使用
{...}; - 变量不存在、属性未读到或公式解析失败时,不要假定结果会自动变成
0。
目录¶
- 快速上手
- 1. 在哪里可以使用公式
- 2. 变量引用
- 3. 算术运算符
- 4. 比较运算符
- 5. 函数列表
- 5.1 取整与数值
- 5.2 幂与对数
- 5.3 三角函数
- 5.4 条件与逻辑
- 5.5 比较函数
- 5.6 位运算
- 5.7 映射与插值
- 5.8 格式化指令
- 6. 内置变量
- 7. 模板块语法
- 8. 运算符优先级
- 9. 实用示例
- 10. 注意事项
1. 在哪里可以使用公式¶
| 使用位置 | 字段名 | 变量 x |
$prop / $变量 |
公式计算 | pad() |
|---|---|---|---|---|---|
| 控制台卡片 (INFO) | 运算公式 | ✅ 当前属性值 | ✅ | ✅ | ✅ |
| 悬浮窗信息项 | 转换表达式 | ✅ 当前属性值 | ✅ | ✅ | ✅ |
| 状态栏信息卡 | 转换表达式 | ✅ 当前属性值 | ✅ | ✅ | ✅ |
| EVCC mini 仪表页 | 属性运算公式 | ✅ 当前属性值 | ✅ | ✅ | ✅ |
| 自动化 — 变量值 | 值字段 | ❌ | ✅ | ✅ | ✅ |
| 自动化 — 动作值 | 值/命令字段 | ❌ | ✅ | ✅ | ✅ |
| 自动化 — BLE 数据 | Payload 字段 | ❌ | ✅ | ✅ | ✅ |
模板块 {表达式} |
任意文本 | ✅ (需传入) | ✅ | ✅ | ✅ |
| 控制台卡片 (时间) | 运算公式 | ❌ | ❌ | ❌ | ❌ (此处为日期格式) |
x变量:在控制台/悬浮窗/状态栏的运算公式中,x自动绑定为该卡片监听的车辆属性的当前数值。 统一语法:除时间卡片外,控制台、悬浮窗、状态栏、EVCC mini、自动化变量值和动作参数都使用同一套表达式语法。
2. 变量引用¶
| 语法 | 含义 | 示例 |
|---|---|---|
$变量名 |
引用全局变量的值 | $speed * 3.6 |
${变量名} |
同上,花括号避免歧义 | ${voltage}V |
$prop(属性ID) |
读取车辆属性实时值 | $prop(289410048) |
$prop(属性ID, 区域ID) |
指定区域读取 | $prop(289410048, 1) |
$prop(属性ID, 区域ID)[下标] |
读取数组或结构体 Data 中的指定项;省略区域时默认为 0 |
$prop(577765445)[2] |
数组下标从 0 开始,所以 [2] 是第三项。支持裸逗号数组、[...] 数组和 Data=[...] 结构体显示值;取出的值仍可继续参与公式计算。越界、空值或存在多个无法确定的数组字段时视为无有效值,不会以 0 代替。
$prop(...) 中的属性 ID、区域 ID 目前只接受十进制整数。属性页面里看到的 0x... 十六进制 ID 需要先换算为十进制后再填写;数组下标虽然可以被语法识别为负数,但负下标没有有效值。
变量替换在公式求值之前执行。替换后如果结果是一个数学表达式,会自动进入公式引擎计算。
3. 算术运算符¶
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
+ |
加法 | 5 + 3 |
8 |
- |
减法 | 10 - 4 |
6 |
* |
乘法 | 6 * 7 |
42 |
/ |
除法 | 22 / 7 |
3.142857 |
% |
取模 (余数) | 10 % 3 |
1 |
^ |
幂运算 (右结合) | 2 ^ 10 |
1024 |
() |
括号 (最高优先级) | (2 + 3) * 4 |
20 |
4. 比较运算符¶
比较运算符返回 1(真)或 0(假),主要配合 if() 使用。
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
> |
大于 | x > 100 |
1 或 0 |
< |
小于 | x < 0 |
1 或 0 |
>= |
大于等于 | x >= 60 |
1 或 0 |
<= |
小于等于 | x <= 255 |
1 或 0 |
== |
等于 | x == 0 |
1 或 0 |
!= |
不等于 | x != 1 |
1 或 0 |
5. 函数列表¶
5.1 取整与数值¶
| 函数 | 参数 | 作用 | 示例 |
|---|---|---|---|
round(x) |
1 | 按 floor(x + 0.5) 取最近整数 |
round(3.7) → 4 |
floor(x) |
1 | 向下取整 (向负无穷) | floor(-3.2) → -4 |
ceil(x) |
1 | 向上取整 (向正无穷) | ceil(3.1) → 4 |
trunc(x) |
1 | 向零截断 | trunc(-3.7) → -3 |
abs(x) |
1 | 绝对值 | abs(-5) → 5 |
sign(x) |
1 | 符号函数,返回 -1 / 0 / 1 | sign(-42) → -1 |
frac(x) |
1 | 小数部分 | frac(3.75) → 0.75 |
min(a, b) |
2 | 取较小值 | min(x, 100) |
max(a, b) |
2 | 取较大值 | max(x, 0) |
clamp(x, lo, hi) |
3 | 限定范围 | clamp(x, 0, 255) |
trunc与floor的区别:正数时行为相同,负数时trunc(-3.7)=-3,floor(-3.7)=-4。负数取整提示:当前
round()按floor(x + 0.5)实现,因此round(-1.5)的结果是-1,并不是远离 0 的-2。frac(x)按x - floor(x)计算,所以frac(-3.2)为0.8。
5.2 幂与对数¶
| 函数 | 参数 | 作用 | 示例 |
|---|---|---|---|
sqrt(x) |
1 | 平方根 | sqrt(16) → 4 |
pow(x, y) |
2 | x 的 y 次方 | pow(2, 10) → 1024 |
hypot(a, b) |
2 | 斜边长度 √(a²+b²) | hypot(3, 4) → 5 |
log(x) |
1 | 常用对数 (以10为底) | log(100) → 2 |
ln(x) |
1 | 自然对数 (以e为底) | ln(2.718) ≈ 1 |
5.3 三角函数¶
所有三角函数使用弧度制。可用 rad() / deg() 进行角度与弧度的转换。
| 函数 | 参数 | 作用 |
|---|---|---|
sin(x) |
1 | 正弦 |
cos(x) |
1 | 余弦 |
tan(x) |
1 | 正切 |
asin(x) |
1 | 反正弦,返回弧度 |
acos(x) |
1 | 反余弦,返回弧度 |
atan(x) |
1 | 反正切,返回弧度 |
atan2(y, x) |
2 | 二参数反正切,返回弧度 |
rad(度) |
1 | 角度转弧度 |
deg(弧度) |
1 | 弧度转角度 |
示例:sin(rad(45)) ≈ 0.707
5.4 条件与逻辑¶
| 函数 | 参数 | 作用 | 示例 |
|---|---|---|---|
if(条件, 真值, 假值) |
3 | 条件不为0取真值,否则取假值 | if(x > 100, 100, x) |
and(a, b) |
2 | 逻辑与,两个非零返回1 | and(x > 0, x < 100) |
or(a, b) |
2 | 逻辑或,任一非零返回1 | or(x == 1, x == 3) |
not(a) |
1 | 逻辑非,零返回1,非零返回0 | not(x == 0) |
concat(a, b, ...) |
多个 | 拼接文本 | concat("电量 ", x, "%") |
复合条件示例:
当 x 在 0~100 范围内时返回 x,否则返回 0。 超出温度范围时返回 -999 (错误标记)。5.5 比较函数¶
这些函数与比较运算符(>、< 等)功能相同,在模板块 {...} 中有时更方便使用。
| 函数 | 等价运算符 | 返回值 |
|---|---|---|
eq(a, b) |
a == b |
1 或 0 |
neq(a, b) |
a != b |
1 或 0 |
gt(a, b) |
a > b |
1 或 0 |
lt(a, b) |
a < b |
1 或 0 |
gte(a, b) |
a >= b |
1 或 0 |
lte(a, b) |
a <= b |
1 或 0 |
5.6 位运算¶
操作数会先被截断为整数 (Long) 再进行位运算,结果转回浮点数返回。这在处理 VHAL 属性的位域标志位时非常实用。
| 函数 | 参数 | 作用 | 示例 |
|---|---|---|---|
band(a, b) |
2 | 按位与 (AND) | band(x, 255) 取低8位 |
bor(a, b) |
2 | 按位或 (OR) | bor(x, 4) 设置bit2 |
bxor(a, b) |
2 | 按位异或 (XOR) | bxor(x, 255) 翻转低8位 |
bnot(a) |
1 | 按位取反 (NOT) | bnot(0) → -1 |
shl(a, n) |
2 | 左移 n 位 | shl(1, 3) → 8 |
shr(a, n) |
2 | 右移 n 位 | shr(255, 4) → 15 |
bit(x, n) |
2 | 取第 n 位 (0或1) | bit(x, 3) 取bit3 |
常见用法:
bit(x, 0) → 取最低位 (奇偶判断)
band(x, 255) → 取低 8 位字节
shr(x, 8) → 取高位字节 (16位值)
band(shr(x, 4), 15) → 取 bit4~bit7 (高半字节)
5.7 映射与插值¶
| 函数 | 参数 | 作用 | 示例 |
|---|---|---|---|
map(x, 输入最小, 输入最大, 输出最小, 输出最大) |
5 | 线性映射 | map(x, 0, 4095, 0, 100) |
lerp(a, b, t) |
3 | 线性插值 a+(b-a)*t | lerp(0, 100, 0.3) → 30 |
map 详解:将输入值从一个范围线性映射到另一个范围。
map(x, 0, 255, -40, 215) → 字节值映射为温度 (℃)
map(x, 0, 4095, 0, 100) → 12位ADC值映射为百分比
map(x, 0, 1023, 0, 5) → 10位ADC值映射为电压 (V)
5.8 格式化指令¶
| 指令 | 参数 | 作用 | 示例 |
|---|---|---|---|
pad(表达式, 位数) |
2 | 前导补零 + 溢出保护 | pad(x, 4) |
pad 不是普通的数学函数,而是格式化指令。它的行为:
- 计算内层表达式的值
- 截断为整数
- 限制在
0~10^位数 - 1范围内 (溢出保护) - 以前导零填充到指定位数
| 表达式 | x = 42 | x = 1234 | x = 99999 |
|---|---|---|---|
pad(x, 4) |
0042 |
1234 |
9999 |
pad(x, 6) |
000042 |
001234 |
099999 |
pad(x * 0.1, 3) |
004 |
123 |
999 |
嵌套使用:
6. 内置变量¶
以下变量无需创建,可直接在公式中使用 $变量名 引用。
| 变量名 | 值 | 示例 |
|---|---|---|
$time |
当前时间 HH:mm:ss |
14:30:25 |
$date |
当前日期 yyyy-MM-dd |
2025-03-23 |
$datetime |
日期+时间 | 2025-03-23 14:30:25 |
$timestamp |
Unix 时间戳 (毫秒) | 1711186225000 |
$hour |
当前小时 (00-23) | 14 |
$minute |
当前分钟 (00-59) | 30 |
$bpm |
当前音乐 BPM;无音乐、尚未匹配或匹配失败时为 0 |
128 |
$music_state |
当前音乐状态:playing / paused_or_stopped / none |
playing |
$gps_available |
是否有最近定位缓存,1 有、0 无 |
1 |
$gps_lat / $latitude |
最近定位纬度 | 30.123456 |
$gps_lng / $gps_lon / $gps_long / $longitude |
最近定位经度 | 120.123456 |
$gps_altitude |
海拔(米,无海拔时为空) | 12.3 |
$gps_accuracy |
定位精度(米,无精度时为空) | 8 |
$gps_speed |
定位速度(米/秒,无速度时为空) | 0 |
$gps_bearing |
定位方向角(度,无方向时为空) | 180 |
$gps_provider |
定位来源 | gps |
$gps_time |
定位时间戳 (毫秒) | 1711186225000 |
$gps_age_ms |
定位缓存距离当前的毫秒数 | 2500 |
GPS 变量读取系统最近一次定位缓存,不主动发起定位;如果车机暂时没有定位,$gps_available 返回 0,其他 GPS 值返回空字符串。
音乐变量来自 EVCC 当前音乐转发状态:暂停时 $bpm 会保留当前歌曲已识别到的数值;切歌后尚未匹配、匹配失败,或当前没有音乐会话时返回 0。$bpm 和 $music_state 是只读变量,不能被自动化“设置变量”动作或 Lua var.write() 覆盖。
表达式的比较运算是数值比较,因此可以直接写 $bpm >= 120,但不要在数学表达式里写 $music_state == "playing"。音乐状态请在自动化的“变量比较”中比较字符串,或在 Lua 中用 var.read("music_state") 判断。
上下文变量(仅在特定动作/触发中可用):
| 变量名 | 可用场景 | 含义 |
|---|---|---|
$current |
SET_PROPERTY 动作 | 当前属性的实时值 |
$ble_button |
BLE 按键触发 | 触发的按键编号 (1-14) |
$ble_rotation |
BLE 旋钮触发 | 旋转值: ±1 (不等待角度) 或实际角度 |
7. 模板块语法¶
字符串表达式¶
表达式可以输出文字,但固定文字必须用英文单引号或双引号包起来。只要 + 的任一边是字符串,+ 就表示拼接文本。
"电量 " + x + "%" → x=80 时输出:电量 80%
if($a > 0, "东经 " + $a, "西经 " + abs($a)) → $a=-3 时输出:西经 3
concat("温度 ", round(x * 0.1), "°C") → 拼接多个文本/数字片段
不要把文字裸写在 if() 分支里:
如果整段是普通文字、ADB 命令、包名、日期等,EVCC 会原样保留,不会强行按公式解析。
模板块¶
在自动化变量值中,可以用 {表达式} 在文本中嵌入计算结果,大括号外的文本原样保留。
如果 x = 234,输出:温度: 23.4°C
注意:${变量名} 是变量引用(前面有 $),{表达式} 是模板块(前面没有 $),两者不会冲突。
如果写成 时间: $gps_time*0.001秒,EVCC 只会先替换 $gps_time,不会在混合文本中单独计算后面的 *0.001。这类“文字 + 公式 + 单位”的场景请使用模板块。
8. 运算符优先级¶
从高到低:
()括号、函数调用^幂运算 (右结合:2^3^2=2^(3^2)=512)*/%乘法、除法、取模+-加法、减法><>=<===!=比较 (最低)
示例:x + 1 > y * 2 等价于 (x + 1) > (y * 2)
9. 实用示例¶
数值转换¶
x * 0.1 → 原始值缩放 (如 1234 → 123.4)
(x - 32) * 5 / 9 → 华氏度转摄氏度
x / 3.6 → km/h 转 m/s
map(x, 0, 255, -40, 215) → 字节值映射为温度
条件显示¶
if(x > 100, 100, x) → 超过100封顶为100
if(x == 0, -1, 1000 / x) → 避免除零
if(and(x >= 18, x <= 65), 1, 0) → 判断是否在范围内
VHAL 位域提取¶
bit(x, 0) → 提取最低位 (开关状态)
bit(x, 3) → 提取第3位
band(x, 255) → 取低8位
band(shr(x, 8), 255) → 取第2个字节
if(bit(x, 5) == 1, 1, 0) → 检查bit5是否置位
格式化输出¶
pad(x, 4) → 补零为4位: 42 → "0042"
pad(clamp(x, 0, 9999), 4) → 限制范围 + 补零
pad(band(x, 255), 3) → 取低8位 + 补零为3位
跨属性引用¶
$prop(289410048) * 0.1 → 引用其他属性并缩放
x + $prop(289410049) → 当前属性值 + 另一属性值
hypot(x, $prop(289410049)) → 两个属性的向量合成
自动化变量计算¶
$speed * 3.6 → m/s 转 km/h
clamp($current + $ble_rotation, 0, 100) → 旋钮增减值 (限 0~100)
round($prop(123) / 216 / 10) * 10 → 四舍五入到十位
if($hour >= 22, 1, if($hour < 6, 1, 0)) → 判断是否深夜
if($a > 0, "东经 " + $a, "西经 " + abs($a)) → 按正负值输出方向文字
$bpm * 2 → 读取音乐 BPM 参与计算;无音乐时结果为 0
音乐变量联动¶
自动化里可直接选择“变量比较”触发器或条件:
也可以选择“变量变化”触发器监听歌曲 BPM 或播放状态的变化。music_state 是文本值,不适合放进数值公式中比较。
10. 注意事项¶
Hex 数据不会被误处理¶
BLE 广播等场景的 hex 数据(如 AA BB 01 02)不会被公式引擎误处理。系统有三层保护:
- 纯 hex 数据不含数学运算符和函数调用括号,会被直接放行
- 所有函数名都包含非 hex 字符(G-Z),不会与 hex 数据子串匹配
- 即使意外进入解析器,解析失败会返回原始字符串
数据类型¶
- 所有计算使用 64 位浮点数(Double)。位运算时操作数先截断为 Long
- 比较运算和逻辑函数返回
1.0(真)或0.0(假) - 固定文字必须加引号;
pad()、concat()和字符串分支的if()会返回文本 - 除字符串拼接和字符串分支外,算术、比较和数学函数都要求输入可转为数值;无法解析的文本不会被偷偷当成
0
解析失败与空值¶
$prop(...)没有读到值、数组越界或变量不存在时,原引用会保持未解析状态,不会自动替换成0- 在变量替换场景中,表达式解析失败时会尽量保留原始文本,避免把包名、命令或普通说明误算成公式
- 显示表达式无法得到有效结果时,卡片会按所在组件的兜底逻辑处理;不要依赖“错误公式等于 0”
valueMap 与 displayExpression 的优先级¶
在控制台卡片和悬浮窗中:
- 如果设置了 valueMap(值映射表),则优先使用映射,不执行公式
- 如果没有 valueMap 且设置了 displayExpression(运算公式),才执行公式
- decimalPlaces(小数位数)在公式结果后应用(pad() 会跳过此步)
跨属性依赖¶
在控制台运算公式中使用 $prop(id) 引用其他属性时,系统会自动建立依赖关系:当被引用的属性值变化时,使用它的卡片也会自动刷新。
时间数据源¶
时间类型的卡片,"运算公式"字段的含义不同——它是 Java SimpleDateFormat 时间格式,如 HH:mm、yyyy/MM/dd HH:mm:ss,不是数学表达式。
Geely 属性公式¶
$prop(geely_aidl:signal:0x4061,1) 和 $prop(geely_capi:sensor:0x100100,0) 使用来源、通道、原始 ID、请求区域定位属性。缺失或关闭的来源保持引用未解析,不替换为 0,不转向其他来源。包含 Geely 引用的自动化规则由应用执行。