
Chain DualKey 是一款基于 ESP32-S3FN8 主控芯片的可编程双键输入开发板。正面集成了 2 个可热插拔的蓝轴机械键盘按键和 2 颗可编程 RGB LED,提供良好的交互反馈。板载 350mAh 锂电池,结合低功耗设计,具备不错的续航表现。产品预装 Chain 宏键盘固件,支持 USB / BLE 连接,可以模拟 HID 输入设备。设备上电后,可连接设备的 AP 热点,通过内置网页为本机或扩展节点配置 HID 功能映射,实现多种控制功能。该开发板采用 M5Stack Chain 系列可扩展设计,提供两个 HY2.0-4P 扩展接口,支持左右侧扩展并连接其他传感器设备。配合 ESP32-S3 内置的 USB-OTG 外设功能,适用于智能家居、键盘外设、宏键盘等各种场景。
步骤 1. 创建新设备

步骤 2. 创建设备名称
CONTINUE。
New Device Setup。
NEXT。
步骤 3. 选择设备类型
ESP32-S3。
SKIP。
步骤 4. 编辑 YAML 文件
EDIT,我们可以通过 YAML 文件自定义设备功能。
Master 作为系统的主控制器。在连接扩展传感器时,需要正确区分连接方向以及 ID 编号顺序。
方向选择
根据扩展传感器连接在 Master 的哪一侧,选择对应的 uart_id:
chain_uart_leftchain_uart_rightID 编号规则
chain_id 表示扩展传感器相对于 Master 的位置:
配置示例
uart_id: chain_uart_leftchain_id: 1uart:
- id: chain_uart_right
tx_pin: GPIO6
rx_pin: GPIO5
baud_rate: 115200
- id: chain_uart_left
tx_pin: GPIO48
rx_pin: GPIO47
baud_rate: 115200
sensor:
- platform: adc
pin: GPIO10
name: "ADC_BAT"
update_interval: 1s
- platform: adc
pin: GPIO2
name: "ADC_VBUS"
update_interval: 1s
- platform: adc
pin: GPIO9
name: "ADC_CHARGE"
update_interval: 1s
output:
- platform: gpio
id: pwr_en
pin: GPIO40
light:
- platform: esp32_rmt_led_strip
id: key_light_raw
internal: true
pin: GPIO21
num_leds: 2
chipset: ws2812
rgb_order: GRB
restore_mode: ALWAYS_OFF
- platform: partition
name: "Key Light 1"
id: key_light_1
segments:
- id: key_light_raw
from: 0
to: 0
- platform: partition
name: "Key Light 2"
id: key_light_2
segments:
- id: key_light_raw
from: 1
to: 1
binary_sensor:
- platform: gpio
name: "KEY_2"
pin:
number: GPIO17
inverted: true
mode: INPUT_PULLUP
filters:
- delayed_on: 10ms
- delayed_off: 10ms
on_press:
- light.turn_on:
id: key_light_2
transition_length: 0ms
on_release:
- light.turn_off: key_light_2
- platform: gpio
name: "KEY_1"
pin:
number: GPIO0
inverted: true
mode: INPUT_PULLUP
filters:
- delayed_on: 10ms
- delayed_off: 10ms
on_press:
- light.turn_on:
id: key_light_1
transition_length: 0ms
on_release:
- light.turn_off: key_light_1
- platform: gpio
name: "SWITCH_1"
pin:
number: GPIO7
mode: INPUT
- platform: gpio
name: "SWITCH_2"
pin:
number: GPIO8
mode: INPUT external_components:
- source: github://m5stack/esphome-yaml/components
components: [m5stack_chain_key]
refresh: 0s
binary_sensor:
- platform: m5stack_chain_key
id: chain_key_1
name: "Chain Key Button"
uart_id: xx
chain_id: xx
update_interval: 50ms
output:
- platform: m5stack_chain_key
id: chain_key_rgb_r
chain_key_id: chain_key_1
channel: rgb_red
- platform: m5stack_chain_key
id: chain_key_rgb_g
chain_key_id: chain_key_1
channel: rgb_green
- platform: m5stack_chain_key
id: chain_key_rgb_b
chain_key_id: chain_key_1
channel: rgb_blue
light:
- platform: rgb
name: "Key RGB"
red: chain_key_rgb_r
green: chain_key_rgb_g
blue: chain_key_rgb_b external_components:
- source: github://m5stack/esphome-yaml/components
components: [m5stack_chain_angle]
refresh: 0s
sensor:
- platform: m5stack_chain_angle
id: chain_angle_1
name: "Chain Angle"
uart_id: xx
chain_id: xx
update_interval: 50ms
output:
- platform: m5stack_chain_angle
id: chain_angle_rgb_r
chain_angle_id: chain_angle_1
channel: rgb_red
- platform: m5stack_chain_angle
id: chain_angle_rgb_g
chain_angle_id: chain_angle_1
channel: rgb_green
- platform: m5stack_chain_angle
id: chain_angle_rgb_b
chain_angle_id: chain_angle_1
channel: rgb_blue
light:
- platform: rgb
name: "Angle RGB"
red: chain_angle_rgb_r
green: chain_angle_rgb_g
blue: chain_angle_rgb_b external_components:
- source: github://m5stack/esphome-yaml/components
components: [m5stack_chain_encoder]
refresh: 0s
sensor:
- platform: m5stack_chain_encoder
id: chain_encoder_1
name: "Chain Encoder"
uart_id: xx
chain_id: xx
update_interval: 100ms
output:
- platform: m5stack_chain_encoder
id: chain_encoder_rgb_r
chain_encoder_id: chain_encoder_1
channel: rgb_red
- platform: m5stack_chain_encoder
id: chain_encoder_rgb_g
chain_encoder_id: chain_encoder_1
channel: rgb_green
- platform: m5stack_chain_encoder
id: chain_encoder_rgb_b
chain_encoder_id: chain_encoder_1
channel: rgb_blue
light:
- platform: rgb
name: "Encoder RGB"
red: chain_encoder_rgb_r
green: chain_encoder_rgb_g
blue: chain_encoder_rgb_b
binary_sensor:
- platform: m5stack_chain_encoder
name: "Encoder Button"
chain_encoder_id: chain_encoder_1 external_components:
- source: github://m5stack/esphome-yaml/components
components: [m5stack_chain_joystick]
refresh: 0s
sensor:
- platform: m5stack_chain_joystick
id: chain_joystick_x
name: "Chain Joystick X"
uart_id: xx
chain_id: xx
axis: x
update_interval: 50ms
- platform: m5stack_chain_joystick
name: "Chain Joystick Y"
uart_id: xx
chain_id: xx
axis: y
update_interval: 50ms
output:
- platform: m5stack_chain_joystick
id: chain_joystick_rgb_r
chain_joystick_id: chain_joystick_x
channel: rgb_red
- platform: m5stack_chain_joystick
id: chain_joystick_rgb_g
chain_joystick_id: chain_joystick_x
channel: rgb_green
- platform: m5stack_chain_joystick
id: chain_joystick_rgb_b
chain_joystick_id: chain_joystick_x
channel: rgb_blue
light:
- platform: rgb
name: "Joystick RGB"
red: chain_joystick_rgb_r
green: chain_joystick_rgb_g
blue: chain_joystick_rgb_b
binary_sensor:
- platform: m5stack_chain_joystick
name: "Joystick Button"
chain_joystick_id: chain_joystick_x external_components:
- source: github://m5stack/esphome-yaml/components
components: [m5stack_chain_tof]
refresh: 0s
sensor:
- platform: m5stack_chain_tof
id: chain_tof_1
name: "Chain ToF"
uart_id: xx
chain_id: xx
update_interval: 100ms
output:
- platform: m5stack_chain_tof
id: chain_tof_rgb_r
m5stack_chain_tof_id: chain_tof_1
channel: rgb_red
- platform: m5stack_chain_tof
id: chain_tof_rgb_g
m5stack_chain_tof_id: chain_tof_1
channel: rgb_green
- platform: m5stack_chain_tof
id: chain_tof_rgb_b
m5stack_chain_tof_id: chain_tof_1
channel: rgb_blue
light:
- platform: rgb
name: "ToF RGB"
red: chain_tof_rgb_r
green: chain_tof_rgb_g
blue: chain_tof_rgb_b 下面的代码示例是根据上图所示的连接顺序进行配置的。

使用的模块:Chain Angle、Chain Encoder、Chain ToF、Chain Joystick、Chain Key。
此配置块用于引入所有 Chain 系列相关的外部组件。如果某个模块(例如 Chain Encoder 或 Chain ToF)不使用,可以从 components 列表中删除对应项。
external_components:
- source: github://m5stack/esphome-yaml/components
components: [m5stack_chain_angle,m5stack_chain_encoder,m5stack_chain_tof,m5stack_chain_joystick,m5stack_chain_key]
refresh: 0s 使用的模块:主控左/右侧 HY2.0 接口上的所有 Chain 系列模块共用的 UART 总线。
captive_portal:
uart:
- id: chain_uart_right
tx_pin: GPIO6
rx_pin: GPIO5
baud_rate: 115200
- id: chain_uart_left
tx_pin: GPIO48
rx_pin: GPIO47
baud_rate: 115200 在本示例中,chain_uart_right 和 chain_uart_left 分别对应主控右侧和左侧的 HY2.0 接口。后续 Chain 模组的 uart_id 需要与实际连接方向保持一致。
使用的模块:Chain Encoder、Chain Angle、Chain ToF、Chain Joystick(X/Y)、DualKey 电池相关 ADC 传感器。
在本示例中,主控右侧按顺序连接了 Chain Encoder(ID 1)、Chain Angle(ID 2)、Chain ToF(ID 3),左侧连接了 Chain Joystick(ID 1,X/Y 两个轴)。同时还启用了电池电量相关的 ADC 通道(BAT、VBUS、CHARGE)作为传感器。
sensor:
- platform: m5stack_chain_encoder
id: chain_encoder_1
name: "Encoder"
uart_id: chain_uart_right
chain_id: 1
update_interval: 100ms
- platform: m5stack_chain_tof
id: chain_tof_1
name: "ToF Distance"
uart_id: chain_uart_right
chain_id: 3
update_interval: 100ms
- platform: m5stack_chain_angle
id: chain_angle_1
name: "Angle"
uart_id: chain_uart_right
chain_id: 2
update_interval: 100ms
- platform: m5stack_chain_joystick
id: chain_joystick_x
name: "Joystick X"
uart_id: chain_uart_left
chain_id: 1
axis: x
update_interval: 100ms
- platform: m5stack_chain_joystick
name: "Joystick Y"
uart_id: chain_uart_left
chain_id: 1
axis: y
update_interval: 100ms
- platform: adc
pin: GPIO10
name: "ADC_BAT"
update_interval: 1s
- platform: adc
pin: GPIO2
name: "ADC_VBUS"
update_interval: 1s
- platform: adc
pin: GPIO9
name: "ADC_CHARGE"
update_interval: 1s 使用的模块:Chain Encoder、Chain Key、Chain Joystick、Chain Angle、Chain ToF 的 RGB 灯以及 DualKey 的电源控制。
output:
- platform: gpio
id: pwr_en
pin: GPIO40
- platform: m5stack_chain_encoder
id: chain_encoder_rgb_r
chain_encoder_id: chain_encoder_1
channel: rgb_red
- platform: m5stack_chain_encoder
id: chain_encoder_rgb_g
chain_encoder_id: chain_encoder_1
channel: rgb_green
- platform: m5stack_chain_encoder
id: chain_encoder_rgb_b
chain_encoder_id: chain_encoder_1
channel: rgb_blue
- platform: m5stack_chain_key
id: chain_key_rgb_r
chain_key_id: chain_key_1
channel: rgb_red
- platform: m5stack_chain_key
id: chain_key_rgb_g
chain_key_id: chain_key_1
channel: rgb_green
- platform: m5stack_chain_key
id: chain_key_rgb_b
chain_key_id: chain_key_1
channel: rgb_blue
- platform: m5stack_chain_joystick
id: chain_joystick_rgb_r
chain_joystick_id: chain_joystick_x
channel: rgb_red
- platform: m5stack_chain_joystick
id: chain_joystick_rgb_g
chain_joystick_id: chain_joystick_x
channel: rgb_green
- platform: m5stack_chain_joystick
id: chain_joystick_rgb_b
chain_joystick_id: chain_joystick_x
channel: rgb_blue
- platform: m5stack_chain_angle
id: chain_angle_rgb_r
chain_angle_id: chain_angle_1
channel: rgb_red
- platform: m5stack_chain_angle
id: chain_angle_rgb_g
chain_angle_id: chain_angle_1
channel: rgb_green
- platform: m5stack_chain_angle
id: chain_angle_rgb_b
chain_angle_id: chain_angle_1
channel: rgb_blue
- platform: m5stack_chain_tof
id: chain_tof_rgb_r
m5stack_chain_tof_id: chain_tof_1
channel: rgb_red
- platform: m5stack_chain_tof
id: chain_tof_rgb_g
m5stack_chain_tof_id: chain_tof_1
channel: rgb_green
- platform: m5stack_chain_tof
id: chain_tof_rgb_b
m5stack_chain_tof_id: chain_tof_1
channel: rgb_blue 其中 pwr_en GPIO 输出用于控制 Chain 扩展总线的供电,通常需要保持开启,以保证连接在总线上的模块可以正常工作。
使用的模块:DualKey 上的 WS2812 按键灯,以及各 Chain 模组上的 RGB 指示灯。
light:
- platform: esp32_rmt_led_strip
id: key_light_raw
internal: true
pin: GPIO21
num_leds: 2
chipset: ws2812
rgb_order: GRB
restore_mode: ALWAYS_OFF
- platform: partition
name: "Key1 LED"
id: key_light_1
segments:
- id: key_light_raw
from: 1
to: 1
- platform: partition
name: "Key2 LED"
id: key_light_2
segments:
- id: key_light_raw
from: 0
to: 0
- platform: rgb
name: "Encoder RGB"
red: chain_encoder_rgb_r
green: chain_encoder_rgb_g
blue: chain_encoder_rgb_b
- platform: rgb
name: "Key RGB"
red: chain_key_rgb_r
green: chain_key_rgb_g
blue: chain_key_rgb_b
- platform: rgb
name: "Joystick RGB"
red: chain_joystick_rgb_r
green: chain_joystick_rgb_g
blue: chain_joystick_rgb_b
- platform: rgb
name: "Angle RGB"
red: chain_angle_rgb_r
green: chain_angle_rgb_g
blue: chain_angle_rgb_b
- platform: rgb
name: "ToF RGB"
red: chain_tof_rgb_r
green: chain_tof_rgb_g
blue: chain_tof_rgb_b 这一部分配置了 DualKey 上每个按键的 RGB 背光(通过 key_light_raw 分区成 key_light_1 和 key_light_2),同时也为各个 Chain 模组定义了对应的 RGB 灯光实体,方便在 Home Assistant 中分别控制。
使用的模块:DualKey 上的机械按键和侧边拨码开关,以及 Chain Key、Chain Encoder、Chain Joystick 上的按键。
这一部分定义了所有与按键相关的输入:两个机械键(KEY 1、KEY 2)及其对应的背光联动、总线上一个 Chain Key 模组的按键、编码器按键、摇杆按键,以及两个侧边开关(SWITCH 1、SWITCH 2)。你可以根据实际使用场景在 Home Assistant 中重命名这些实体。
binary_sensor:
- platform: gpio
name: "KEY 2"
pin:
number: GPIO17
inverted: true
mode: INPUT_PULLUP
filters:
- delayed_on: 10ms
- delayed_off: 10ms
on_press:
- light.turn_on:
id: key_light_2
transition_length: 0ms
on_release:
- light.turn_off: key_light_2
- platform: gpio
name: "KEY 1"
pin:
number: GPIO0
inverted: true
mode: INPUT_PULLUP
filters:
- delayed_on: 10ms
- delayed_off: 10ms
on_press:
- light.turn_on:
id: key_light_1
transition_length: 0ms
on_release:
- light.turn_off: key_light_1
- platform: m5stack_chain_key
id: chain_key_1
name: "Key Module Button"
uart_id: chain_uart_left
chain_id: 2
update_interval: 50ms
- platform: m5stack_chain_encoder
name: "Encoder Button"
chain_encoder_id: chain_encoder_1
- platform: m5stack_chain_joystick
name: "Joystick Button"
chain_joystick_id: chain_joystick_x
- platform: gpio
name: "SWITCH 1"
pin:
number: GPIO7
mode: INPUT
- platform: gpio
name: "SWITCH 2"
pin:
number: GPIO8
mode: INPUT INSTALL 进行烧录,并等待完成。
SAVE 和 INSTALL,在弹出的对话框中选择 Manual Download。
Download,并选择 Factory format(Previously Modern) 选项下载固件。
CONNECT 连接设备。

INSTALL。

Settings -> Device & services 查看设备。
Discover 区域中找到对应的设备。

