极物科技 | Control4 对接 - DALI 彩色灯具驱动(DT8)
前言
在智能控制领域,"协议壁垒"与"系统稳定性"始终是绕不开的难题。极物科技(Zeewo)以 "重构空间交互体验" 为使命,通过自研的 极物 OS,实现了 KNX、DALI、CAN、RS485 等多种总线协议在单一主机上的深度融合。
我们认为,一个真正优秀的智能系统,不仅要实现灯光、遮阳、温控、音乐、安防等全生态设备的无界融合 ,更要确保本地运行、断网可用 ,并具备WEB 远程调试 和 OTA 固件升级的能力。基于此底层架构,我们推出了诸如带双路 DALI 的 KNX 主机、HomeKit 网桥等核心硬件,并将极物 OS 成功接入了 Apple HomeKit、小度、纯血鸿蒙及 HomeAssistant 等主流生态系统。
一句话概述:本文详细解析极物网关 DALI 彩色灯具驱动(DT8 双色温)的 Control4 DriverWorks 实现,涵盖非线性亮度映射、DT8 色温控制及高级场景定时。
本文聚焦于 极物 DALI 彩色灯具驱动(DT8)的完整实现,重点展示非线性亮度映射表、DT8 色温控制协议、双 Proxy 架构及高级场景定时功能,并提供完整代码供 C4 集成商参考。
1. 驱动概述
1.1 驱动定位
DALI 彩色灯具驱动(DT8)是极物网关针对 DT8 双色温灯具 的 Control4 驱动,相比基础调光驱动,核心差异在于:
- 非线性亮度映射:内置 101 级 C4 亮度 → DALI 亮度查表,确保人眼感知的线性亮度变化
- DT8 色温控制:支持 2000K~7000K 色温调节,符合 IEC 62386 DT8 标准
- 双 Proxy 架构:亮度代理(5001)+ 色温代理(5002)独立控制
1.2 驱动文件结构
Aolebach-Dail-Device_Color_3.3.0/
├── driver.xml # 驱动元数据与配置定义
├── driver.lua # 驱动主逻辑
├── dali.lua # DALI 协议封装(含非线性亮度映射表)
├── proxy.lua # Proxy 代理逻辑
├── action.lua # 动作处理
├── adance_sence_timer.lua # 高级场景定时
├── const.lua # 常量定义
├── documentation.rtf # 驱动文档说明
└── Aolebach-Dail-Device_Color.c4zproj # C4 Composer 工程文件
1.3 通讯参数
| 参数 | 规格 |
|---|---|
| 网关 Proxy ID | 1(DALI_GATE_WAY_PROXY_ID) |
| 亮度 Proxy ID | 5001(DALI_BRIGHT_PROXY_ID) |
| 色温 Proxy ID | 5002(DALI_COLOR_PROXY_ID) |
| 亮度范围 | 0 ~ 100(C4 侧) → 非线性映射 → 0 ~ 254(DALI 侧) |
| 色温范围 | 2000K ~ 7000K |
| 场景数量 | 16 组(Scene 0 ~ Scene 15) |
2. 驱动配置(driver.xml)
xml
<devicedata>
<manufacturer>Aolebach</manufacturer>
<name>奥乐巴赫 Dali 灯具 彩色</name>
<model>Dali Dimmer Color</model>
<version>2023060514</version>
<control>lua_gen</control>
<driver>DriverWorks</driver>
<proxies qty="2">
<proxy proxybindingid="5001" name="DALI-调光">light_v2</proxy>
<proxy proxybindingid="5002" name="DALI-色温">light_v2</proxy>
</proxies>
<capabilities>
<dimmer>True</dimmer>
<set_level>True</set_level>
<ramp_level>True</ramp_level>
<on_off>True</on_off>
<has_leds>False</has_leds>
<load_group_support>True</load_group_support>
<advanced_scene_support>True</advanced_scene_support>
<supports_target>True</supports_target>
</capabilities>
<config>
<properties>
<property>
<name>DALI 地址</name>
<type>STRING</type>
<readonly>false</readonly>
<default>0</default>
</property>
<property>
<name>地址类型</name>
<type>LIST</type>
<items>
<item>单灯</item>
<item>分组</item>
<item>全局</item>
</items>
<default>单灯</default>
</property>
<property>
<name>Debug Mode</name>
<type>LIST</type>
<items>
<item>Off</item>
<item>Print</item>
<item>Log</item>
<item>Print and Log</item>
</items>
<default>Off</default>
</property>
</properties>
</config>
</devicedata>
3. 非线性亮度映射(核心亮点)
3.1 为什么需要非线性映射
人眼对亮度的感知是对数关系而非线性关系。如果直接将 C4 的 0~100 线性映射到 DALI 的 0~254,会导致:
- 低亮度区间(0~30%)变化过于明显
- 高亮度区间(70~100%)变化不明显
- 用户体验不佳,调光手感不自然
3.2 非线性映射表
极物驱动内置了两张 101 级映射表,分别用于 C4 → DALI 和 DALI → C4 的双向转换:
lua
-- C4 亮度 (0-100) → DALI 亮度 (0-254)
local c4_bright = {
0, 2, 5, 7, 10, 12, 15, 17, 20, 22, 25, 27, 30, 33, 35, 38, 40, 43, 45, 48,
50, 53, 55, 58, 60, 63, 66, 68, 71, 73, 76, 78, 81, 83, 86, 88, 91, 93, 96, 99,
101, 104, 106, 109, 111, 114, 116, 119, 121, 124, 127, 129, 132, 134, 137, 139,
142, 144, 147, 149, 152, 154, 157, 160, 162, 165, 167, 170, 172, 175, 177, 180,
182, 185, 187, 190, 193, 195, 198, 200, 203, 205, 208, 210, 213, 215, 218, 220,
223, 226, 228, 231, 233, 236, 238, 241, 243, 246, 248, 251, 254
}
-- DALI 亮度 (0-254) → C4 亮度 (0-100)
local dali_bright = {
0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7,
8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15,
16, 16, 16, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23,
24, 24, 24, 25, 25, 25, 26, 26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 31, 31,
31, 32, 32, 33, 33, 33, 34, 34, 35, 35, 35, 36, 36, 37, 37, 37, 38, 38, 38, 39,
39, 40, 40, 40, 41, 41, 42, 42, 42, 43, 43, 44, 44, 44, 45, 45, 46, 46, 46, 47,
47, 48, 48, 48, 49, 49, 49, 50, 50, 51, 51, 51, 52, 52, 53, 53, 53, 54, 54, 55,
55, 55, 56, 56, 57, 57, 57, 58, 58, 59, 59, 59, 60, 60, 61, 61, 61, 62, 62, 62,
63, 63, 64, 64, 64, 65, 65, 66, 66, 66, 67, 67, 68, 68, 68, 69, 69, 70, 70, 70,
71, 71, 72, 72, 72, 73, 73, 74, 74, 74, 75, 75, 75, 76, 76, 77, 77, 77, 78, 78,
79, 79, 79, 80, 80, 81, 81, 81, 82, 82, 83, 83, 83, 84, 84, 85, 85, 85, 86, 86,
87, 87, 87, 88, 88, 88, 89, 89, 90, 90, 90, 91, 91, 92, 92, 92, 93, 93, 94, 94,
94, 95, 95, 96, 96, 96, 97, 97, 98, 98, 98, 99, 99, 99, 100
}
3.3 查表转换函数
lua
function dali_bright_c4_to_device(bright)
-- C4 亮度 (0-100) → DALI 亮度 (0-254) 查表
local real_value = c4_bright[bright + 1]
return real_value
end
function dali_bright_device_to_c4(bright)
-- DALI 亮度 (0-254) → C4 亮度 (0-100) 查表
local real_value = dali_bright[bright + 1]
return real_value
end
3.4 色温转换
lua
function dali_color_c4_to_device(color)
-- C4 色温等级 (0-100) → 色温值 (2000-7000K)
local real_value = math.floor(((7000 - 2000) / 100) * color + 2000)
return real_value
end
function dali_color_device_to_c4(color)
-- 色温值 (2000-7000K) → C4 色温等级 (0-100)
local real_value = math.floor(100 * (color - 2000) / 5000)
return real_value
end
4. 驱动核心实现
4.1 设备结构体
lua
require "utils"
require "ao_timer"
require "dali"
require "proxy"
require "const"
require "action"
adance_timer = require "adance_sence_timer"
local g_dali_proxy_bound_status = false
-- DALI 设备结构体
local g_dali_device = {
address_num = "99",
address_type = "unknow",
brightness_now = 100,
color_now = 2000,
brightness_last = 100,
color_last = 2000,
is_sensor_open = false
}
4.2 属性变更回调
lua
function OnPropertyChanged(strProperty)
local value = Properties[strProperty]
if (value == nil) then
value = ''
end
if (strProperty == 'DALI 地址') then
g_dali_device.address_num = tostring(value)
elseif (strProperty == '地址类型') then
if (value == "单灯") then
g_dali_device.address_type = "shortaddress"
elseif (value == "分组") then
g_dali_device.address_type = "group"
elseif (value == "全局") then
g_dali_device.address_type = "broadcast"
end
end
Print(g_dali_device)
end
4.3 延迟初始化
lua
function OnDriverLateInit(dit)
for property, _ in pairs(Properties) do
OnPropertyChanged(property)
end
gTestTimer = AddTimer(gTestTimer, 3)
LUMI_CMD.GET_CONNECTED_STATE(DALI_BRIGHT_PROXY_ID, nil, nil)
TEMP_CMD.GET_CONNECTED_STATE(DALI_COLOR_PROXY_ID, nil, nil)
C4:AddVariable("IS_OPEN_BY_SENSOR", 0, "BOOL")
end
4.4 Proxy 分发
lua
function ReceivedFromProxy(idBinding, strCommand, tParams)
if (idBinding == DALI_BRIGHT_PROXY_ID) then
proxy_bright_control(g_dali_device, strCommand, tParams)
is_sensor_set(0)
elseif (idBinding == DALI_COLOR_PROXY_ID) then
proxy_color_control(g_dali_device, strCommand, tParams)
is_sensor_set(0)
elseif (idBinding == DALI_GATE_WAY_PROXY_ID) then
proxy_info_update(g_dali_device, strCommand)
end
end
5. 亮度控制指令
5.1 指定亮度控制
lua
function dali_control_bright_value(args, bright)
local frame_data = {
driver_data = {
address_num = args.address_num,
address_type = args.address_type,
cmd_name = "- DIRECT ARC POWER CONTROL",
cmd_type = "normal",
dali_index = "1",
cmd_value = tostring(dali_bright_c4_to_device(bright))
},
frame_type = "request",
frame_driver = "light-dali",
frame_result = "ok"
}
dbg("bright " .. bright)
C4:SendToProxy(DALI_GATE_WAY_PROXY_ID, JSON:encode(frame_data), {})
end
5.2 最大/最小亮度
lua
function dali_control_bright_max(args)
local frame_data = {
driver_data = {
address_num = args.address_num,
address_type = args.address_type,
cmd_name = "5 RECALL MAX LEVEL",
cmd_type = "normal",
dali_index = "1",
cmd_value = "10"
},
frame_type = "request",
frame_driver = "light-dali",
frame_result = "ok"
}
C4:SendToProxy(DALI_GATE_WAY_PROXY_ID, JSON:encode(frame_data), {})
end
function dali_control_bright_min(args)
local frame_data = {
driver_data = {
address_num = args.address_num,
address_type = args.address_type,
cmd_name = "6 RECALL MIN LEVEL",
cmd_type = "normal",
dali_index = "1",
cmd_value = "10"
},
frame_type = "request",
frame_driver = "light-dali",
frame_result = "ok"
}
C4:SendToProxy(DALI_GATE_WAY_PROXY_ID, JSON:encode(frame_data), {})
end
5.3 关灯
lua
function dali_control_bright_off(args)
local frame_data = {
driver_data = {
address_num = args.address_num,
address_type = args.address_type,
cmd_name = "1 OFF",
cmd_type = "normal",
dali_index = "1",
cmd_value = "0"
},
frame_type = "request",
frame_driver = "light-dali",
frame_result = "ok"
}
C4:SendToProxy(DALI_GATE_WAY_PROXY_ID, JSON:encode(frame_data), {})
end
6. 场景控制
lua
function dali_control_goto_sence(args, sence_num)
local frame_data = {
driver_data = {
address_num = args.address_num,
address_type = args.address_type,
cmd_name = tostring(sence_num) .. " GO TO SCENE " .. tostring(sence_num),
cmd_type = "normal",
dali_index = "1",
cmd_value = tostring(sence_num)
},
frame_type = "request",
frame_driver = "light-dali",
frame_result = "ok"
}
C4:SendToProxy(DALI_GATE_WAY_PROXY_ID, JSON:encode(frame_data), {})
end
7. 动作处理(action.lua)
lua
function lua_normal_action(tParams, dali_device)
for cmd, cmdv in pairs(tParams) do
if cmd == "ACTION" then
if cmdv == "LUMI_TO_MAX" then
dali_control_bright_max(dali_device)
elseif cmdv == "LUMI_TO_MIN" then
dali_control_bright_min(dali_device)
elseif cmdv == "LUMI_TO_OFF" then
dali_control_bright_off(dali_device)
elseif cmdv == "TEMP_TO_COLD" then
dali_control_color_max_cold(dali_device)
elseif cmdv == "TEMP_TO_WARM" then
dali_control_color_max_warm(dali_device)
elseif cmdv == "GOTO_SENCE_0" then
dali_control_goto_sence(dali_device, 0)
-- ... Scene 1 ~ Scene 15 类似
end
end
end
end
8. 注意事项
⚠️ 非线性映射
DT8 彩色灯具驱动使用非线性亮度映射表,确保人眼感知的线性亮度变化
基础调光灯具驱动使用线性映射(
math.floor(level * 255 / 100))两种驱动不可混用,需根据灯具类型选择对应驱动
⚠️ 色温范围DT8 色温范围为 2000K ~ 7000K
C4 侧使用 0~100 等级制,驱动内部自动转换
⚠️ 双 Proxy 架构亮度 Proxy(5001)和色温 Proxy(5002)独立工作
网关侧会自动处理亮度与色温的协同调度
9. 相关文档
- 《极物科技 | Control4 对接 - 系统架构与驱动开发概述》
- 《极物科技 | Control4 对接 - DALI 网关驱动》
- 《极物科技 | Control4 对接 - DALI 调光灯具驱动》
关于极物科技(ZEEWO)
极物科技(Zeewo)致力于为用户提供智能控制系统及硬件产品。我们以总线系统为技术底座,以**"稳定、可靠、快速响应"**为产品底线,是国内少有的拥有 KNX、DALI 全套软硬件自主研发能力的厂商之一。
我们的核心能力:
- 系统架构:自研极物 OS,支持多协议无界融合(KNX/DALI/CAN/RS485/IP)。
- 核心硬件:带双路 DALI 的 KNX 主机、超薄全金属定制面板、各类智选传感器及网关。
- 生态互联:深度融入 Apple HomeKit、Matter、小度、HomeAssistant 及纯血鸿蒙生态。
- 调试交付:独家支持 ETS 导出 XML 直接导入进行 APP 免编程调试,支持远程 WEB 运维。
我们的市场覆盖:
服务网点已覆盖全国核心城市(含长三角、珠三角、成渝等),并以高品质的方案深耕家居生活、酒店民宿、企业办公、疗愈康养、餐馆会所等多个细分领域。
极物科技 | Control4 对接 - DALI 彩色灯具驱动(DT8)

(如果您在开发或落地中遇到技术问题,欢迎通过官网或后台私信与我交流探讨)