将 Yeelight 烛光氛围灯接入 Home Assistant
在五年前的文章将 Yeelight 烛光氛围灯接入 Apple HomeKit 中,笔者介绍了通过 Homebridge 控制 Yeelight 烛光氛围灯的方法。然而,笔者在将 Homebridge 相关代码迁移(使用 AI 转写)到 ESPHome 平台,并尝试在 Home Assistant 中使用时,发现原版代码的蓝牙交互实际上存在问题。yee.js 使用了0x43,0x67,0xde,0xad,0xbe,0xbf作为蓝牙连接后认证的 payload,但这实际上无效;即使 ESP32 和灯连接上了蓝牙,过一段时间后就会断开,下次控制时又需要重新连接。
经过搜索,笔者找到了两个重要的参考:I need Help to use esp32 to Control Yeelight Candla BLE Lamp with MQTT / HomeAssisant 以及“失联” 7 年的 Yeelight 烛光氛围灯,上线 HomeKit 平台 | 新人报到 - 少数派。根据这些资料,如果不完成配对,蓝牙每过一段时间就会被强制断开,和笔者遇到的情况一致。而测试成功的交互流程是,连接蓝牙后发送0x43,0x40,0x02进行认证,此时灯会进入配对模式,亮度会闪烁,之后旋转氛围灯,就可以配对成功。
基于此,笔者重新编写了 ESPHome 配置文件,供参考。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128substitutions:
YEELIGHT_PAIR_BUTTON_PIN: GPIO0
YEELIGHT_STATUS_LED_PIN: GPIO2
YEELIGHT_SERVICE_UUID: "0000FE87-0000-1000-8000-00805f9b34fb"
YEELIGHT_NOTIFY_UUID: "8F65073D-9F57-4AAA-AFEA-397D19D5BBEB"
YEELIGHT_CONTROL_UUID: "AA7D3F34-2D4F-41E0-807F-52FBF8CF7443"
YEELIGHT_MAC: "F8:24:41:XX:XX:XX"
esphome:
name: yeelight
platformio_options:
board_build.flash_mode: dio
esp32:
board: esp32dev
framework:
type: esp-idf
logger:
api:
ota:
platform: esphome
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
binary_sensor:
- platform: gpio
name: yeelight_pair_button
pin:
number: $YEELIGHT_PAIR_BUTTON_PIN
inverted: true
on_click:
- script.execute: script_yeelight_pair
internal: true
ble_client:
- mac_address: $YEELIGHT_MAC
id: ble_yeelight
sensor:
- platform: ble_client
id: sensor_yeelight_notify
type: characteristic
ble_client_id: ble_yeelight
internal: true
service_uuid: $YEELIGHT_SERVICE_UUID
characteristic_uuid: $YEELIGHT_NOTIFY_UUID
notify: true
lambda: |-
if (x.size() > 4 && x[0] == 0x43 && x[1] == 0x45) {
bool power = (x[2] == 0x01);
float brightness = (float)x[3] / 100.0;
auto target = id(yeelight_candle);
target->remote_values.set_state(power);
target->remote_values.set_brightness(brightness);
target->publish_state();
ESP_LOGD("yeelight", "Sync - Power: %s, Brightness: %.0f%%", power ? "ON" : "OFF", brightness * 100);
}
return NAN;
light:
- platform: monochromatic
name: "Yeelight Candela"
id: yeelight_candle
output: output_yeelight_brightness
on_turn_on:
- script.execute: script_yeelight_on
on_turn_off:
- script.execute: script_yeelight_off
- platform: binary
id: yeelight_status_led
output: output_yeelight_status
internal: true
output:
- platform: template
id: output_yeelight_brightness
type: float
write_action:
- script.execute:
id: script_yeelight_brightness
value: !lambda return state;
- platform: gpio
id: output_yeelight_status
pin: $YEELIGHT_STATUS_LED_PIN
script:
- id: script_yeelight_pair
then:
- script.execute: script_yeelight_off
- script.execute: script_yeelight_on
- ble_client.ble_write:
id: ble_yeelight
service_uuid: $YEELIGHT_SERVICE_UUID
characteristic_uuid: $YEELIGHT_CONTROL_UUID
value: [0x43, 0x67, 0x02] # enable pulse mode
- light.turn_on: yeelight_status_led
- delay: 10s
- light.turn_off: yeelight_status_led
- id: script_yeelight_on
then:
- ble_client.ble_write:
id: ble_yeelight
service_uuid: $YEELIGHT_SERVICE_UUID
characteristic_uuid: $YEELIGHT_CONTROL_UUID
value: [0x43, 0x40, 0x01]
- id: script_yeelight_off
then:
- ble_client.ble_write:
id: ble_yeelight
service_uuid: $YEELIGHT_SERVICE_UUID
characteristic_uuid: $YEELIGHT_CONTROL_UUID
value: [0x43, 0x40, 0x02]
- id: script_yeelight_brightness
parameters:
value: float # 0% - 100%
then:
- ble_client.ble_write:
id: ble_yeelight
service_uuid: $YEELIGHT_SERVICE_UUID
characteristic_uuid: $YEELIGHT_CONTROL_UUID
value: !lambda return { 0x43, 0x42, (uint8_t)(value * 100) };
笔者做的主要更改是支持了sensor_yeelight_notify,它监听灯的状态变化,并将状态同步到 ESPHome 的 light 实体上。这样,无论是通过 Home Assistant 控制灯,还是直接旋转灯进行亮度调节,ESPHome 都能正确地获取灯的状态并更新。
使用方式是:
- 将上述代码保存为
yeelight.yaml,并替换其中的YEELIGHT_MAC为实际的灯的 MAC 地址(可以先扫描附近的 BLE 设备,然后根据名称yeelight_ms或者yl_candela找到灯),配对按键使用的GPIO0也可以根据情况修改。 - 通过
esphome run yeelight.yaml将代码烧录到 ESP32 上。 - 确保灯处于蓝牙连接范围内。
- 通过
esphome logs yeelight.yaml查看日志,在配对成功前,可以看到 ESP32 和灯的蓝牙连接间歇性断开,虽然 ESP32 会自动重连,但是此时操作的延迟会很大。 - 趁着连接成功的间隙,按下配对按钮(这里使用的是
GPIO0,通常是 ESP32 开发板的BOOT按钮),等待 ESP32 开发板上的 LED 亮起,氛围灯也开始闪烁时,表示开始配对,此时旋转灯进行配对。 - 配对成功后,ESP32 和灯的连接会保持稳定,此时就可以添加进 Home Assistant,来控制灯的开关和亮度了。