第5节 ESP32-S3-RLCD-4.2 配置示例
本节以 微雪 ESP32-S3-RLCD-4.2 为例,演示如何综合运用前几节学到的知识——
external_components、I²C / SPI 总线声明、不同类型组件的添加方式。各外设独立成段,可按需选取。
本节以 微雪 ESP32-S3-RLCD-4.2 为示例板,配置中用到的引脚、芯片型号都与这块板一一对应。若开发板型号不同,请参考相应原理图调整引脚与芯片配置。
1. 准备工作
- 硬件:微雪 ESP32-S3-RLCD-4.2 一块、USB-C 数据线一根,可选 18650 电池一节。
- 网络:可用的 2.4 GHz Wi-Fi,HA 主机与开发板在同一子网。
- 前置:已完成第 1—4 节。本节会大量复用第 3、4 节中介绍的向导流程、
substitutions、external_components、!secret等概念,遇到陌生字段可查阅对应小节。
ESP32-S3-RLCD-4.2 板载外设比 ESP32-S3-Zero 丰富——反射式 LCD、温湿度传感器、电池监测、双麦克风、扬声器、两枚按键,本节按外设分段,每段只关注对应组件的添加方式,不强求一份贯穿始终的大配置。各段可独立使用,按需组合即可。
2. 硬件资源速览
2.1 板载外设
| 外设 | 型号 | 总线 | 说明 |
|---|---|---|---|
| 显示屏 | ST7305 反射式单色 LCD | SPI | 400×300 分辨率,4.2 英寸,环境光下可视 |
| 温湿度 | SHTC3 | I²C (0x70) | — |
| 音频 DAC | ES8311 | I²C + I²S | 驱动扬声器输出 |
| 音频 ADC | ES7210 | I²C + I²S | 采集双麦克风 |
| RTC | PCF85063A | I²C | 当前配置暂不接入 |
| 存储 | microSD 卡槽 | SPI | 当前配置暂不接入 |
| 电池 | 18650 电池座 + ADC | GPIO4 | 3 倍分压,需要软件还原 |
| 按键 | BOOT × 1、KEY × 1 | GPIO | 低电平有效 |
| 扩展 | 2×8 针 2.54 mm 排针 | — | 预留用户扩展 |
2.2 GPIO 引脚分配
| GPIO | 功能 |
|---|---|
| GPIO0 | BOOT button (active low) |
| GPIO4 | Battery ADC |
| GPIO5 | Display DC |
| GPIO8 | I²S DOUT (speaker) |
| GPIO9 | I²S BCLK |
| GPIO10 | I²S DIN (microphone) |
| GPIO11 | SPI CLK (display) |
| GPIO12 | SPI MOSI (display) |
| GPIO13 | I²C SDA |
| GPIO14 | I²C SCL |
| GPIO16 | I²S MCLK |
| GPIO18 | KEY button (active low) |
| GPIO40 | Display CS |
| GPIO41 | Display RESET |
| GPIO45 | I²S LRCLK |
| GPIO46 | Speaker amplifier enable |
GPIO46 控制扬声器功放的使能信号——只有把它拉高,DAC 输出才会经功放送到扬声器。后续配置中会用一个 switch.gpio 把它默认置位 on,让设备启动后即可输出音频。
2.3 直接使用社区配置
devices.esphome.io 上已经收录了这块板的现成配置。搜索 ESP32-S3-RLCD-4.2 可找到该板的社区配置,复制后修改 Wi-Fi 凭据即可直接使用。
本节以下按外设拆解,展示每类组件如何添加到配置中,可按需选取片段加入配置。
3. 基础配置
按第 3 节的流程,用 ESPHome 向导新建一台设备:芯片选 ESP32-S3,向导完成后点 SKIP,进入 YAML 编辑器。
向导生成的初始配置如下(每台设备的 name、密钥、密码不同,此处为示意):
esphome:
name: esp32-s3-rlcd-42
friendly_name: ESP32-S3-RLCD-4.2
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
logger:
api:
encryption:
key: "<向导自动生成>"
ota:
- platform: esphome
password: "<向导自动生成>"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "Esp32-S3-Rlcd-42"
password: "<向导自动生成>"
captive_portal:
api.encryption.key、ota.password、ap.password 是向导随机生成、和这台设备绑定的凭据;esphome.name 决定设备的 mDNS 主机名。直接复制别人的 YAML 整段替换会丢掉这些值,导致 HA 接入失败、OTA 失败或 mDNS 解析不到设备。
本节后续所有片段都是"在向导生成的 YAML 末尾追加"——保留上面这段不动,后续片段在此基础上追加。
在向导的输出之后,再追加两段——这是本节示例都需要的"额外基础":
# 8 MB 八线 PSRAM:显示屏帧缓冲、音频缓冲都依赖它
psram:
mode: octal
speed: 80MHz
# ST7305 驱动(社区组件,未进入 ESPHome 主线)
external_components:
- source: github://kylehase/ESPHome-ST7305-RLCD
components: [st7305_rlcd]
几处关键点:
psram:— ESP32-S3-RLCD-4.2 板载 8 MB 八线 PSRAM,显示屏帧缓冲和音频缓冲都依赖它。模式必须是octal,速度 80 MHz。缺少这一段,编译可通过,但运行时会因内存不足而崩溃。framework.type: esp-idf— 向导默认就是esp-idf,保持不变即可。部分组件(如常见问题中提到的esp-nn)只支持 ESP-IDF 框架。external_components:— ST7305 驱动尚未进入 ESPHome 主线,通过kylehase/ESPHome-ST7305-RLCD引入。语法在 第 4.3.4 节 介绍过。
后续各节的 YAML 片段也都"追加"到这份配置后面,可按需挑选——只需点亮的,追加显示屏配置;需要温湿度的,再追加传感器与按键;依此类推。同一顶层键(如 sensor:、switch:)出现多次时,按第 4 节 YAML 锚点部分介绍的写法合并。
4. 显示屏:ST7305 反射式 LCD
ST7305 是一块单色反射式 LCD,没有背光,靠环境光反射成像,刷新率低但功耗极小。它通过 SPI 与主控通信,只用到 CLK 和 MOSI 两根数据线(单向写入,不需要 MISO)。
spi:
clk_pin: GPIO11
mosi_pin: GPIO12
display:
- platform: st7305_rlcd
model: WAVESHARE_400X300
id: my_display
width: 400
height: 300
cs_pin: GPIO40
dc_pin: GPIO5
reset_pin: GPIO41
data_rate: 1MHz
update_interval: 1min
show_test_card: true
platform: st7305_rlcd— 来自第 3 节末尾引入的外部组件。data_rate: 1MHz— ST7305 对时序要求不高,1 MHz 足够,更高频率对 ST7305 没有实际提升,且可能引入通信错误。update_interval: 1min— 反射式屏幕没有显示余晖问题,但写屏耗电也耗 CPU,1 分钟刷一次足以应付显示日期、温湿度等场景。show_test_card: true— 首次上电时显示一张测试图,方便确认接线正确。
烧录后屏幕显示测试图,即表明 SPI 接线与驱动均正常。

4.1 绘制简单画面
确认显示正常后,删除 show_test_card: true 一行,通过 lambda 自行绘制内容。显示文字需要先声明字体——gfonts:// 会在编译时自动下载 Google Fonts:
font:
- file: "gfonts://Roboto"
id: font_title
size: 24
- file: "gfonts://Roboto"
id: font_big
size: 48
再把 display: 中的 show_test_card: true 替换为 lambda,画一个带标题栏的简单画面:
display:
- platform: st7305_rlcd
model: WAVESHARE_400X300
id: my_display
width: 400
height: 300
cs_pin: GPIO40
dc_pin: GPIO5
reset_pin: GPIO41
data_rate: 1MHz
update_interval: 1min
lambda: |-
// 外边框
it.rectangle(0, 0, 400, 300);
// 顶部标题栏
it.filled_rectangle(0, 0, 400, 48);
it.print(200, 24, id(font_title), COLOR_OFF, TextAlign::CENTER, "ESP32-S3-RLCD-4.2");
// 居中大字
it.print(200, 170, id(font_big), TextAlign::CENTER, "Hello ESPHome");

绘制坐标系以屏幕左上角为原点 (0, 0),x 向右、y 向下。几个常用方法:
it.print(x, y, 字体, [颜色,] [对齐,] "文本")— 绘制文本,TextAlign::CENTER让坐标作为文本中心。it.rectangle(x, y, w, h)/it.filled_rectangle(...)— 空心 / 实心矩形。it.line(x1, y1, x2, y2)— 直线。
单色屏的颜色只有 COLOR_ON(点亮)和 COLOR_OFF(熄灭)两种。标题栏用实心矩形填充后,文字需指定 COLOR_OFF 才能在深色背景上显示为反色。
显示屏组件不会在 HA 中生成实体——它只是一块"画布"。lambda 的完整绘图接口参见 Display Rendering Engine。
以上画的是静态内容。接入传感器后,还能在画面中显示温湿度、电量等实时读数,完整示例见后文"显示传感器读数"。
5. 传感器与按键
5.1 I²C 总线
SHTC3、ES8311、ES7210 共享同一条 I²C 总线,只需声明一次:
i2c:
sda: GPIO13
scl: GPIO14
scan: true
id: bus_a
scan: true 在上电时扫描总线并把检测到的从机地址打印在 LOGS 中。首次上电时查看日志,应至少出现 0x18(ES8311)、0x40 或 0x42(ES7210)、0x70(SHTC3)这几个地址;若缺失,后续传感器和音频将无法正常工作。
5.2 SHTC3 温湿度
sensor:
- platform: shtcx
address: 0x70
update_interval: 60s
i2c_id: bus_a
temperature:
name: "Temperature"
id: temp_sensor
humidity:
name: "Humidity"
id: hum_sensor
shtcx 平台同时覆盖 SHTC1/SHTC3。temperature 和 humidity 各自带 name,HA 中会生成两个独立的数值实体;id 供显示屏一节的 lambda 引用。
5.3 电池电压与电量百分比
板上电池座到 GPIO4 经过 3 倍分压,因此读到的电压需要乘 3 才是真实电池电压。再用一个 copy 平台,把电压线性映射成 0—100% 的电量百分比:
sensor:
# ……承接 5.2 SHTC3
- platform: adc
id: bat_voltage
name: "Battery Voltage"
pin: GPIO4
attenuation: 12db
update_interval: 60s
filters:
- multiply: 3.0
- platform: copy
source_id: bat_voltage
id: bat_level
name: "Battery Level"
unit_of_measurement: "%"
filters:
- calibrate_linear:
- 2.5 -> 0.0
- 4.2 -> 100.0
- clamp:
min_value: 0
max_value: 100
attenuation: 12db— ESP32-S3 的 ADC 默认量程只能测到约 0.95 V,必须设衰减把上限抬到约 3.1 V,否则满电的 18650 经分压后(约 1.4 V)会超出量程。calibrate_linear把 2.5 V → 0%、4.2 V → 100% 做线性映射,对应 18650 的放空到满电电压;clamp限制在 0—100 之间,避免超出范围的电压被错误地折算成负数或大于 100。
5.4 用户按键
板上 BOOT(GPIO0)和 KEY(GPIO18)两枚按键都是低电平有效,按第 4.2.1 节的写法配置即可。要绑触发动作(如翻页、切换显示模式),可在 on_press: 下添加 lambda 或其他动作,后文音频一节的按键绑定即是一例。
binary_sensor:
- platform: gpio
name: "Boot Button"
pin:
number: GPIO0
inverted: true
mode: INPUT
- platform: gpio
name: "Key Button"
pin:
number: GPIO18
inverted: true
mode: INPUT
5.5 显示传感器读数
传感器就位后,把显示屏一节中的 font: 与 display: 替换为下面这份完整配置,屏幕即可显示温湿度与电池电量——画面分三块:顶部标题栏、中部温湿度、底部电量条。
font:
- file: "gfonts://Roboto"
id: font_label
size: 18
- file: "gfonts://Roboto@700"
id: font_value
size: 48
- file: "gfonts://Roboto"
id: font_title
size: 22
display:
- platform: st7305_rlcd
model: WAVESHARE_400X300
id: my_display
width: 400
height: 300
cs_pin: GPIO40
dc_pin: GPIO5
reset_pin: GPIO41
data_rate: 1MHz
update_interval: 30s
lambda: |-
// 顶部标题栏(反色)
it.filled_rectangle(0, 0, 400, 40);
it.print(200, 20, id(font_title), COLOR_OFF, TextAlign::CENTER, "ESP32-S3-RLCD-4.2");
// 温度(左半)
it.print(20, 52, id(font_label), "TEMP");
it.printf(20, 72, id(font_value), "%.1f", id(temp_sensor).state);
it.print(160, 92, id(font_label), "C");
// 湿度(右半)
it.print(210, 52, id(font_label), "HUMIDITY");
it.printf(210, 72, id(font_value), "%.0f", id(hum_sensor).state);
it.print(330, 92, id(font_label), "%");
// 分隔线
it.line(0, 150, 400, 150);
// 电池电压与电量
it.print(20, 162, id(font_label), "BATTERY");
it.printf(380, 162, id(font_label), TextAlign::TOP_RIGHT,
"%.2f V (%.0f%%)", id(bat_voltage).state, id(bat_level).state);
// 电量进度条:先画边框,再按百分比填充
int bx = 20, by = 192, bw = 360, bh = 30;
it.rectangle(bx, by, bw, bh);
int fill = (int)((bw - 4) * id(bat_level).state / 100.0);
if (fill > 0) it.filled_rectangle(bx + 2, by + 2, fill, bh - 4);
几处要点:
it.printf与it.print类似,但支持%.1f、%.0f等 C 格式化占位符,后面依次接要显示的值。- 数值通过
id(temp_sensor).state、id(bat_level).state读取,对应 5.2、5.3 节声明的传感器。 - 进度条由两步组成:
it.rectangle画边框,再按电量百分比算出填充宽度,用it.filled_rectangle填充。
为避免额外声明字形,单位用 ASCII 字母书写(C、%)。若要显示度数符号 °C,需在对应 font 的 glyphs 中显式加入 °,否则屏上无法显示。
至此,显示屏、传感器、按键已全部就位。烧录后 HA 中会出现 Temperature、Humidity、Battery Voltage、Battery Level、Boot Button、Key Button 几个实体,屏幕则显示温湿度与电量画面。


6. 音频:扬声器与麦克风
板载的扬声器(ES8311 DAC)和麦克风(ES7210 ADC)共用一条 I²S 总线。下面分别给出扬声器与麦克风的验证方法,可在搭建完整语音助手之前先确认硬件正常。
6.1 扬声器:按钮播放铃声
用 rtttl 组件让扬声器播放一段旋律(铃声)。rtttl 采用诺基亚时代的 RTTTL 铃声格式,旋律直接由设备合成,无需下载音频文件,声音也比短促的提示音更明显:
i2s_audio:
- id: i2s_shared
i2s_lrclk_pin: GPIO45
i2s_bclk_pin: GPIO9
i2s_mclk_pin: GPIO16
audio_dac:
- platform: es8311
id: es8311_dac
bits_per_sample: 16bit
sample_rate: 16000
speaker:
- platform: i2s_audio
id: spk
i2s_audio_id: i2s_shared
i2s_dout_pin: GPIO8
dac_type: external
audio_dac: es8311_dac
sample_rate: 16000
bits_per_sample: 16bit
# 功放使能:须打开才有输出
switch:
- platform: gpio
name: "Speaker Enable"
pin: GPIO46
restore_mode: RESTORE_DEFAULT_ON
# RTTTL 铃声:直接通过扬声器合成播放
rtttl:
speaker: spk
gain: 80%
button:
- platform: template
name: "Play Tune"
on_press:
- rtttl.play: "NokiaTune:d=4,o=5,b=225:8e6,8d6,4f#,4g#,8c#6,8b,4d,4e,8b,8a,4c#,4e,2a"
烧录后,HA 中出现 Play Tune 按钮,点击即播放铃声,表明扬声器与功放正常。Speaker Enable(GPIO46)控制功放使能,未启用时无输出;音量过小可调高 rtttl.gain。

rtttl.play 后面是一段 RTTTL 字符串,换成其他旋律即可播放不同铃声,例如:
# 简单上行音阶
- rtttl.play: "scale:d=4,o=5,b=160:c,d,e,f,g,a,b,c6"
# 警报声
- rtttl.play: "siren:d=8,o=5,b=100:d,e,d,e,d,e,d,e"
6.2 扬声器:让设备朗读文本
rtttl 已能确认扬声器正常。若想让设备朗读任意文本(例如播报通知或温湿度),可以接入 HA 的 TTS。该功能依赖网络与 HA 的 TTS 服务,属于进阶用法。
与 6.1 节不同,朗读走媒体播放通道,需把扬声器封装为 media_player,并用 mixer 同时支持「媒体」与「公告」两条音频流(i2s_audio、audio_dac 与前文重复,合并到一份配置时只保留一处):
speaker:
- platform: i2s_audio
id: spk
i2s_audio_id: i2s_shared
i2s_dout_pin: GPIO8
dac_type: external
audio_dac: es8311_dac
sample_rate: 16000
bits_per_sample: 16bit
- platform: mixer # 汇流:媒体 + 公告
id: spk_mixer
output_speaker: spk
source_speakers:
- id: media_in # mixer 自行创建的两路输入
- id: announce_in #(id 不能与下面的重采样器重名)
- platform: resampler # 管线 → 重采样 → mixer 对应输入
id: media_src
output_speaker: media_in
- platform: resampler
id: announce_src
output_speaker: announce_in
switch:
- platform: gpio
name: "Speaker Enable"
pin: GPIO46
restore_mode: RESTORE_DEFAULT_ON
media_player:
- platform: speaker
id: spk_player
name: "RLCD Speaker"
media_pipeline: # 媒体浏览器、TTS 朗读走这条
speaker: media_src
format: FLAC
sample_rate: 16000
num_channels: 1
announcement_pipeline: # 带 announce 的播放走这条
speaker: announce_src
format: FLAC
sample_rate: 16000
num_channels: 1
音频链路为:管线 → 重采样器(media_src / announce_src)→ mixer 输入(media_in / announce_in)→ mixer → 物理扬声器 spk。注意 mixer 的输入 id 与重采样器 id 必须各不相同,否则会因 id 重复而校验失败。
烧录后,HA 中出现一个名为 RLCD Speaker 的媒体播放器。在 HA 的 TTS 对话框中输入文本、点击「朗读」,设备即可读出。
TTS 音频由 HA 在运行时生成,并通过一个 HTTP 地址交给设备下载(http://<HA>:8123/api/tts_proxy/…)。若 LOGS 中出现 ESP_ERR_HTTP_CONNECT 或 esp-tls select() timeout,表明设备无法访问该地址(此时本地 rtttl、files: 仍正常,因为它们在编译时已打包进固件,不经网络)。
在 HA 设置 → 系统 → 网络 → 本地网络 中,将内部 URL 设为设备可直接访问的形式:使用局域网 IP(避免 .local)、使用 http://(不用 https://,自签证书会握手超时)、端口 8123,且与设备同一网段,例如 http://192.168.1.10:8123。
6.3 麦克风:唤醒词日志
麦克风无法直接试听,可用设备端唤醒词检测间接验证——它完全运行在 ESP32 上,不需要 HA 的语音服务。检测到唤醒词时打印一条日志:
audio_adc:
- platform: es7210
id: es7210_adc
bits_per_sample: 16bit
sample_rate: 16000
mic_gain: 24dB
microphone:
- platform: i2s_audio
id: mic
i2s_audio_id: i2s_shared # 复用 6.1 声明的同一条 I²S 总线
i2s_din_pin: GPIO10
adc_type: external
sample_rate: 16000
bits_per_sample: 16bit
pdm: false
# 计数:每检测到一次唤醒词加一
globals:
- id: wake_count
type: int
restore_value: false
initial_value: "0"
micro_wake_word:
microphone:
microphone: mic
channels: 0
gain_factor: 4
models:
- model: hey_jarvis
on_wake_word_detected:
- lambda: 'id(wake_count) += 1;'
- component.update: my_display # 立即刷新屏幕
将检测结果显示在屏幕上,比查看日志更直观。下面是一份独立的显示配置,每唤醒一次计数加一:
font:
- file: "gfonts://Roboto"
id: font_title
size: 22
- file: "gfonts://Roboto@700"
id: font_value
size: 64
display:
- platform: st7305_rlcd
model: WAVESHARE_400X300
id: my_display
width: 400
height: 300
cs_pin: GPIO40
dc_pin: GPIO5
reset_pin: GPIO41
data_rate: 1MHz
update_interval: 60s
lambda: |-
it.print(200, 40, id(font_title), TextAlign::TOP_CENTER, "Say \"Hey Jarvis\"");
it.print(200, 130, id(font_title), TextAlign::TOP_CENTER, "Wake count");
it.printf(200, 165, id(font_value), TextAlign::TOP_CENTER, "%d", id(wake_count));
整份配置中 display: 只能有一个。这里的显示配置与"显示传感器读数"一节的是两份独立示例,按当前测试目的择一使用即可。
micro_wake_word 需要在 esp32.framework.components 中加入 espressif/esp-nn==1.1.2,编译时还会自动下载唤醒词模型。烧录后对着麦克风说 "Hey Jarvis",屏幕上的计数随即加一,表明麦克风与 I²S 采集链路正常。

7. 本节常见问题
- 点击 Play Tune 无声:确认
Speaker Enable已打开(GPIO46 控制功放使能);TTS 朗读无声则多为 HA 内部 URL 配置问题,参见朗读一节的提示。 - 唤醒词无响应:确认
framework.components已加入esp-nn、模型已下载;可适当调高gain_factor,并确认对着麦克风讲话。 - 电池电压始终为 0 或超出量程:检查
attenuation是否为12db,multiply: 3.0是否正确,确认电池实际电压在 2.5—4.2 V 范围内。