ESP32 Arduino Matter 窗帘控制端点 MatterWindowCovering 完全指南:Lift/Tilt 控制、电机校准与回调机制
【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32
导读
MatterWindowCovering是 Arduino ESP32 Matter 库(本仓库 libraries/Matter)提供的一个窗口覆盖(Window Covering)端点类,用于在 Matter 网络中构建电动窗帘、百叶窗、投影幕布等具有升降(Lift)与翻转(Tilt)控制能力的设备。本文以官方文档 docs/en/matter/ep_window_covering.rst 为骨架,结合 MatterWindowCovering.cpp 源码与 MatterWindowCovering.ino 完整示例,系统讲解该端点的 API 全貌、百分比语义、本地电机校准、命令回调流程,以及如何接入 Apple HomeKit、Amazon Alexa 与 Google Home。阅读完本文后,你将能够独立编写并配网一个符合 Matter 标准、可被主流智能家居平台直接识别的窗帘设备固件。
MatterWindowCovering 端点概述
MatterWindowCovering类为 Matter 网络提供一个窗口覆盖端点,实现了 Matter 标准中针对电动百叶窗、遮阳帘及其他具备升降/翻转控制能力的窗口覆盖设备的协议规范。从源码看,它直接继承自MatterEndPoint基类(见 MatterWindowCovering.h),并在底层通过esp_matter::endpoint::window_covering创建真实端点(见 MatterWindowCovering.cpp),功能仅在CONFIG_ESP_MATTER_ENABLE_DATA_MODEL宏开启时编译生效。
核心特性
- Lift 位置与百分比控制(0-100%,Matter 语义:0 = 全开,100 = 全闭)
- Lift 与 Tilt 百分之一精度(percent100ths,0-10000)控制,直接映射 Matter 集群属性
- 本地电机校准,用于物理单位与百分比之间的换算
- 支持多种窗口覆盖类型
- 开、关、升降、翻转、停止命令的回调支持
- 与 Apple HomeKit、Amazon Alexa、Google Home 集成
- 完全遵循 Matter 标准
支持的窗口覆盖类型
以下枚举值定义于 MatterWindowCovering.h,直接对应 Matter 规范中的WindowCovering::Type:
| 枚举值 | 说明 | 支持的能力 |
|---|---|---|
ROLLERSHADE | 卷帘 | Lift |
ROLLERSHADE_2_MOTOR | 双电机卷帘 | Lift |
ROLLERSHADE_EXTERIOR | 户外卷帘 | Lift |
ROLLERSHADE_EXTERIOR_2_MOTOR | 户外双电机卷帘 | Lift |
DRAPERY | 窗帘 | Lift |
AWNING | 遮阳篷 | Lift |
SHUTTER | 百叶窗板 | Tilt |
BLIND_TILT_ONLY | 仅翻转百叶 | Tilt |
BLIND_LIFT_AND_TILT | 升降+翻转百叶 | Lift 和 Tilt |
PROJECTOR_SCREEN | 投影幕布 | Lift |
源码中begin()内通过supportsTilt判断是否为SHUTTER、BLIND_TILT_ONLY或BLIND_LIFT_AND_TILT,仅这三种类型会启用 Tilt 相关特性(tilt::get_id() | position_aware_tilt::get_id()),其余类型仅注册 Lift 能力(见 MatterWindowCovering.cpp)。因此覆盖类型必须在初始化时指定,以确保正确的特性被启用。
典型应用场景
- 电动窗帘 / 电动百叶窗
- 自动化遮阳帘
- 智能窗口覆盖设备
- 投影幕布
- 遮阳篷与幕帘
关键设计语义:理解 Matter 百分比与百分之一精度
使用本 API 前必须掌握两个相互配合的数值体系,它们贯穿全部位置控制方法:
- 百分比(Percent,0-100):面向应用层的简化数值。0 = 完全打开(open),100 = 完全关闭(closed),这是 Matter 在窗口覆盖领域的特殊语义,与常规"100 表示打开"的直觉相反。
- 百分之一精度(Percent100ths,0-10000):Matter 集群属性的原生精度,
1对应0.01%。setCurrentLiftPercent100ths(10000)即代表完全关闭。
在示例代码中,两者换算通过liftPercent * 100完成(见 MatterWindowCovering.ino),而源码的attributeChangeCB()中反向换算为liftPercent100ths / 100(见 MatterWindowCovering.cpp)。
重要提示:本文档整个 API 均采用 Matter 百分比语义——0 表示全开,100 表示全闭。例如begin()的默认参数liftPercent = 0意味着初始化即"完全打开"。
初始化与生命周期
构造函数
MatterWindowCovering();创建一个新的 Matter 窗口覆盖端点对象。通常在全局作用域声明,例如示例中的MatterWindowCovering WindowBlinds;(见 MatterWindowCovering.ino)。
begin()
bool begin( uint8_t liftPercent = 0, uint8_t tiltPercent = 0, WindowCoveringType_t coveringType = ROLLERSHADE, const PositionCalibration *liftCalibration = nullptr, const PositionCalibration *tiltCalibration = nullptr );初始化 Matter 窗口覆盖端点,可指定初始位置、覆盖类型和本地电机校准。
参数说明:
liftPercent:初始升降百分比(0-100,默认 0 = 完全打开)tiltPercent:初始翻转百分比(0-100,默认 0 = 完全打开)coveringType:窗口覆盖类型(默认ROLLERSHADE),决定启用 Lift、Tilt 还是两者liftCalibration:可选的本地升降电机范围(open/closed 物理单位)。在 ESP-Matter 1.5 中不作为 Matter 属性暴露tiltCalibration:可选的本地翻转电机范围。在 ESP-Matter 1.5 中不作为 Matter 属性暴露
函数成功返回true,失败返回false。
从源码实现看(MatterWindowCovering.cpp),begin()依次完成:
- 调用
ArduinoMatter::_init()初始化 Matter 栈; - 校验重复创建(同一端点 id 只能创建一次)与百分比取值范围(超过 100 会记录
log_e并返回false); - 应用传入的校准(
liftCalibration->open/closed写入installedOpenLimitLift/installedClosedLimitLift,tilt 同理); - 按覆盖类型组装 feature flags(Lift 必选,Tilt 视类型而定);
- 通过
wc_endpoint::create()创建端点并写入初始CurrentPosition*Percent100ths属性。
PositionCalibration 结构体
本地电机范围,用于在物理电机单位与 Matter 百分比之间换算。仅存储在固件中,在 ESP-Matter 1.5 中不发布为 Matter 集群属性。
struct PositionCalibration { uint16_t open = 0; uint16_t closed = 65534; };默认值open = 0、closed = 65534对应源码中的安装限位默认值(见 MatterWindowCovering.cpp)。示例中为实际窗帘定义了物理单位(厘米)校准(见 MatterWindowCovering.ino):
// Lift limits in centimeters (physical position at open/closed ends) // Matter percent: 0 = open at open limit, 100 = closed at closed limit const MatterWindowCovering::PositionCalibration LIFT_CALIBRATION = {.open = 0, .closed = 200}; // Tilt limits (absolute values for conversion, not physical units) // Tilt is a rotation, not a linear measurement const MatterWindowCovering::PositionCalibration TILT_CALIBRATION = {.open = 0, .closed = 90};end()
void end();停止处理 Matter 窗口覆盖事件。源码实现仅将started标志置为false(见 MatterWindowCovering.cpp),析构函数也会自动调用它。
Lift 位置控制 API
setLiftPosition / getLiftPosition
bool setLiftPosition(uint16_t liftPosition); uint16_t getLiftPosition();setLiftPosition以本地电机单位(如厘米)设置升降位置,并利用本地电机校准范围换算为 Matter percent100ths。源码中的换算逻辑(MatterWindowCovering.cpp)与 ESP-Matter 的LiftToPercent100ths一致:
- 正常安装(open < closed):
liftPosition <= openLimit映射为 0(全开),>= closedLimit映射为 10000(全闭),中间值线性插值:((liftPosition - openLimit) * 10000) / (closedLimit - openLimit); - 反向安装(open > closed):换算公式相应反转。
setLiftPercentage / getLiftPercentage
bool setLiftPercentage(uint8_t liftPercent); uint8_t getLiftPercentage();setLiftPercentage以百分比设置升降位置(0-100,0 全开、100 全闭)。该方法更新CurrentPositionLiftPercent100ths属性,反映设备实际位置;而TargetPositionLiftPercent100ths属性由 Matter 命令/应用在请求新目标时设置。源码中它只是setCurrentLiftPercent100ths(liftPercent * 100)的封装(见 MatterWindowCovering.cpp)。
注意:当设备到达目标位置时,应调用setOperationalState(LIFT, STALL)指示运动完成。需要亚百分比精度时优先使用setCurrentLiftPercent100ths()。
setCurrentLiftPercent100ths / getCurrentLiftPercent100ths
bool setCurrentLiftPercent100ths(uint16_t liftPercent100ths); uint16_t getCurrentLiftPercent100ths();以 Matter percent100ths(0-10000,0 = 打开,10000 = 关闭)设置当前升降位置。这是向配网方(commissioner)报告实际位置的主要 API。源码实现在写入属性前会校验范围(>10000 返回false)、跳过相同值,并先尝试updateAttributeVal再回退setAttributeVal(见 MatterWindowCovering.cpp)。
Tilt 位置控制 API
bool setTiltPosition(uint16_t tiltPosition); uint16_t getTiltPosition(); bool setTiltPercentage(uint8_t tiltPercent); uint8_t getTiltPercentage(); bool setCurrentTiltPercent100ths(uint16_t tiltPercent100ths); uint16_t getCurrentTiltPercent100ths();Tilt 系列 API 与 Lift 一一对应,但需特别注意:Tilt 是旋转量而非线性量,其"位置"使用用于换算的绝对值,而不是物理单位。文档与源码反复强调这一点(见 MatterWindowCovering.cpp 中TiltToPercent100ths的换算)。百分比语义同样为 0 = 全开、100 = 全闭;setTiltPercentage更新CurrentPositionTiltPercent100ths,运动完成后应调用setOperationalState(TILT, STALL)。
窗口覆盖类型控制
bool setCoveringType(WindowCoveringType_t coveringType); WindowCoveringType_t getCoveringType();setCoveringType设置窗口覆盖类型。从源码看(MatterWindowCovering.cpp),它会写入 Matter 集群的Type属性并同步内部状态;getCoveringType则从集群属性读取并缓存。
安装限位控制(本地电机校准)
以下方法配置本地电机校准,用于在物理电机单位与 Matter 百分比之间换算。它们在 ESP-Matter 1.5 中不暴露为 Matter 集群属性,官方文档建议优先使用setLiftCalibration()/setTiltCalibration(),或在begin()中传入PositionCalibration。
整组校准
bool setLiftCalibration(const PositionCalibration &calibration); PositionCalibration getLiftCalibration(); bool setTiltCalibration(const PositionCalibration &calibration); PositionCalibration getTiltCalibration();setLiftCalibration设置本地升降电机校准范围;getLiftCalibration返回当前范围。实现直接读写内部的installedOpenLimitLift/installedClosedLimitLift(见 MatterWindowCovering.cpp)。示例中正是用WindowBlinds.getLiftCalibration()读取校准值来完成"百分比 → 厘米"的线性换算函数liftPercentToCm()(见 MatterWindowCovering.ino)。
单项限位
bool setInstalledOpenLimitLift(uint16_t openLimit); uint16_t getInstalledOpenLimitLift(); bool setInstalledClosedLimitLift(uint16_t closedLimit); uint16_t getInstalledClosedLimitLift(); bool setInstalledOpenLimitTilt(uint16_t openLimit); uint16_t getInstalledOpenLimitTilt(); bool setInstalledClosedLimitTilt(uint16_t closedLimit); uint16_t getInstalledClosedLimitTilt();setInstalledOpenLimitLift(openLimit):设置完全打开时的本地升降限位(物理单位,如厘米)setInstalledClosedLimitLift(closedLimit):设置完全关闭时的本地升降限位(物理单位,如厘米)setInstalledOpenLimitTilt(openLimit)/setInstalledClosedLimitTilt(closedLimit):设置本地翻转电机限位
注意:Tilt 是旋转量而非线性测量,这些限位仅用于本地位置换算。所有 setter 在started == false时会返回false。
目标位置控制
bool setTargetLiftPercent100ths(uint16_t liftPercent100ths); uint16_t getTargetLiftPercent100ths(); bool setTargetTiltPercent100ths(uint16_t tiltPercent100ths); uint16_t getTargetTiltPercent100ths();以 percent100ths(0-10000,0 全开、10000 全闭)设置目标位置。这设置的是设备应向之移动的目标位置,实际位置应在物理移动后用setLiftPercentage()/setTiltPercentage()更新。从源码看,setter 会写入TargetPositionLiftPercent100ths/TargetPositionTiltPercent100ths属性(见 MatterWindowCovering.cpp),写入后立即触发对应的目标位置回调(见下节)。
在示例的loop()中,用户短按按钮即以 20% 步进循环目标升降位置,核心一行正是WindowBlinds.setTargetLiftPercent100ths(targetLiftPercent * 100)(见 MatterWindowCovering.ino)。
运行状态(Operational Status)控制
完整位图操作
bool setOperationalStatus(uint8_t operationalStatus); uint8_t getOperationalStatus();setOperationalStatus设置完整的运行状态位图。文档建议优先使用setOperationalState()设置单个字段,而不是直接操作完整位图。OperationalStatus属性的位分布(定义于 MatterWindowCovering.h)为:GLOBAL占 bits 0-1(掩码 0x03)、LIFT占 bits 2-3(掩码 0x0C)、TILT占 bits 4-5(掩码 0x30)。
单字段状态设置
bool setOperationalState(OperationalStatusField_t field, OperationalState_t state); OperationalState_t getOperationalState(OperationalStatusField_t field);setOperationalState为特定字段(LIFT或TILT)设置运行状态。GLOBAL字段不能直接设置,它按优先级(LIFT > TILT)自动更新。
field:要设置的字段(LIFT或TILT,GLOBAL不可直接设置)state:运行状态(STALL、MOVING_UP_OR_OPEN或MOVING_DOWN_OR_CLOSE)
源码揭示了GLOBAL的自动推导逻辑(MatterWindowCovering.cpp):
- 拒绝直接设置
GLOBAL; - 仅当该字段状态确实变化时才更新位图:
currentStatus = (currentStatus & ~fieldMask) | (((uint8_t)state << fieldShift) & fieldMask); - 重算
GLOBAL:globalState = (liftState != STALL) ? liftState : tiltState——即 Lift 优先,Lift 处于STALL时才采用 Tilt 状态。
getOperationalState按字段掩码与移位提取对应 2-bit 状态(GLOBAL移 0 位、LIFT移 2 位、TILT移 4 位)。
在示例回调中,goToLiftPercentage()根据目标与当前值的比较,先设置MOVING_UP_OR_OPEN(目标更小,即趋向打开)或MOVING_DOWN_OR_CLOSE(目标更大,即趋向关闭),运动模拟完成后立即设置STALL(见 MatterWindowCovering.ino),stopMotor()则同时将 Lift 与 Tilt 都置为STALL。
事件处理与回调机制
MatterWindowCovering会自动检测 Matter 命令,并在注册了回调时调用相应函数。所有回调类型均为std::function(见 MatterWindowCovering.h),注册方法在头文件中以内联方式实现。回调分两大类:
目标位置回调(TargetPosition属性变化时触发)
| 回调 | 触发条件 |
|---|---|
onOpen() | 收到UpOrOpen命令(目标置为 0% = 全开) |
onClose() | 收到DownOrClose命令(目标置为 100% = 全闭) |
onStop() | 收到StopMotion命令(目标置为当前位置,即停止运动) |
onGoToLiftPercentage() | TargetPositionLiftPercent100ths变化(任何命令、setTargetLiftPercent100ths()或直接属性写入) |
onGoToTiltPercentage() | TargetPositionTiltPercent100ths变化(任何命令、setTargetTiltPercent100ths()或直接属性写入) |
当前位置回调
| 回调 | 触发条件 |
|---|---|
onChange() | CurrentPositionLiftPercent100ths或CurrentPositionTiltPercent100ths变化(调用setLiftPercentage()/setTiltPercentage()之后,或 Matter 控制器直接更新这些属性时) |
重要:onChange()不会在 Matter 命令执行时被自动调用。命令修改的是TargetPosition而非CurrentPosition。要触发onChange(),必须在物理设备实际移动后,由你的onGoToLiftPercentage()或onGoToTiltPercentage()回调调用setLiftPercentage()/setTiltPercentage()来更新CurrentPosition属性。
注意:所有回调都是可选的。如果某个特定回调未注册,则只会调用通用回调onGoToLiftPercentage()或onGoToTiltPercentage()(若已注册)。
onOpen
void onOpen(EndPointOpenCB onChangeCB);设置收到UpOrOpen命令(目标位置置为 0%,全开)时的回调。回调签名为:
bool onChangeCallback();onClose
void onClose(EndPointCloseCB onChangeCB);设置收到DownOrClose命令(目标位置置为 100%,全闭)时的回调,签名同上(bool onChangeCallback();)。
onGoToLiftPercentage
void onGoToLiftPercentage(EndPointLiftCB onChangeCB);设置TargetPositionLiftPercent100ths变化时的回调。触发来源包括:
- Matter 命令:
UpOrOpen、DownOrClose、StopMotion、GoToLiftPercentage - 调用
setTargetLiftPercent100ths() - 直接写入
TargetPositionLiftPercent100ths属性
只要目标升降位置变化,无论通过何种命令或方法触发,该回调都会被调用。回调签名为:
bool onChangeCallback(uint8_t liftPercent);其中liftPercent为目标升降百分比(0-100,0 全开、100 全闭)。
注意:该回调收到的是目标位置。要在物理设备实际移动后更新当前位置(进而触发onChange()),请调用setLiftPercentage()。
onGoToTiltPercentage
void onGoToTiltPercentage(EndPointTiltCB onChangeCB);TargetPositionTiltPercent100ths变化时的回调,触发来源与onGoToLiftPercentage完全对应(GoToTiltPercentage命令等)。回调签名为:
bool onChangeCallback(uint8_t tiltPercent);onStop
void onStop(EndPointStopCB onChangeCB);设置收到StopMotion命令(目标位置置为当前位置,即停止运动)时的回调。签名bool onChangeCallback();。
onChange
void onChange(EndPointCB onChangeCB);设置CurrentPositionLiftPercent100ths或CurrentPositionTiltPercent100ths变化时的回调。这与onGoToLiftPercentage()/onGoToTiltPercentage()(针对TargetPosition属性)不同。
onChange()被调用的时机:
CurrentPositionLiftPercent100ths变化时(调用setLiftPercentage()之后,或 Matter 控制器直接更新该属性)CurrentPositionTiltPercent100ths变化时(调用setTiltPercentage()之后,或 Matter 控制器直接更新该属性)
回调签名为:
bool onChangeCallback(uint8_t liftPercent, uint8_t tiltPercent);参数为当前升降与翻转百分比(均 0-100)。
命令检测的源码实现细节
源码attributeChangeCB()(MatterWindowCovering.cpp)揭示了命令 → 回调的映射规则。以 Lift 目标位置变化为例:
targetLiftPercent100ths == 0→ 判定为UpOrOpen命令,调用_onOpenCB(全开);targetLiftPercent100ths == 10000→ 判定为DownOrClose命令,调用_onCloseCB(全闭);- 目标值等于当前值且当前值不在 0/10000 限位 → 判定为
StopMotion命令,调用_onStopCB; - 无论何种情况,最后总会调用通用回调
_onGoToLiftPercentageCB以兼容所有目标位置变化场景。
Tilt 目标位置变化则直接调用_onGoToTiltPercentageCB。所有回调的返回值通过ret &=聚合,回调返回false时会被记录。
updateAccessory
void updateAccessory();使用当前 Matter 内部状态更新窗口覆盖状态,即以缓存的currentLiftPercent/currentTiltPercent调用已注册回调(见 MatterWindowCovering.cpp)。适用于需要在事件循环中主动同步状态到应用层的场景。
完整实战示例:电动百叶窗固件
仓库提供了可直接编译运行的完整示例 MatterWindowCovering.ino(配套说明见 README.md)。该示例以BLIND_LIFT_AND_TILT类型演示升降 + 翻转双控制,并具备状态持久化、物理按键手动控制、RGB LED 可视化等完整工程要素。
整体流程:命令 → 回调 → 状态回写
示例的完整回调链路清晰展示了本文所述 API 的协作方式:
- Matter 控制器下发命令 →
TargetPosition属性变化; - 触发
onGoToLiftPercentage()/onGoToTiltPercentage()(以及针对开/关/停的onOpen/onClose/onStop); - 应用回调驱动电机,并在运动完成后调用
setLiftPercentage()/setTiltPercentage()(或直接setCurrentLiftPercent100ths()); CurrentPosition属性更新 → 触发onChange()回调(示例中用于刷新 RGB LED 可视化)。
示例关键代码:
// Initialize window covering with BLIND_LIFT_AND_TILT type and local motor calibration WindowBlinds.begin(lastLiftPercent, lastTiltPercent, MatterWindowCovering::BLIND_LIFT_AND_TILT, &LIFT_CALIBRATION, &TILT_CALIBRATION); // Set callback functions WindowBlinds.onOpen(fullOpen); WindowBlinds.onClose(fullClose); WindowBlinds.onGoToLiftPercentage(goToLiftPercentage); WindowBlinds.onGoToTiltPercentage(goToTiltPercentage); WindowBlinds.onStop(stopMotor); // Generic callback for Lift or Tilt change WindowBlinds.onChange([](uint8_t liftPercent, uint8_t tiltPercent) { Serial.printf("Window Covering changed: Lift=%u%%, Tilt=%u%%\r\n", liftPercent, tiltPercent); visualizeWindowBlinds(liftPercent, tiltPercent); return true; }); // Matter beginning - Last step, after all EndPoints are initialized Matter.begin();而goToLiftPercentage()内部展示了"状态上报 + 运动完成"的完整范式(模拟运动中省略了真实电机驱动代码):
bool goToLiftPercentage(uint8_t liftPercent) { // update Lift operational state if (liftPercent > currentLiftPercent) { WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::MOVING_DOWN_OR_CLOSE); } else if (liftPercent < currentLiftPercent) { WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::MOVING_UP_OR_OPEN); } // ... 此处应插入真实电机驱动代码 ... currentLift = liftPercentToCm(liftPercent); currentLiftPercent = liftPercent; // Update CurrentPosition to reflect actual position WindowBlinds.setCurrentLiftPercent100ths(liftPercent * 100); // Set operational status to STALL when movement is complete WindowBlinds.setOperationalState(MatterWindowCovering::LIFT, MatterWindowCovering::STALL); // Store state matterPref.putUChar(liftPercentPrefKey, currentLiftPercent); return true; }硬件与引脚配置
- RGB LED:优先使用
RGB_BUILTIN,未定义时回退到引脚 2;亮度反映升降位置(0% = 熄灭,100% = 全亮),颜色反映翻转角度(红色 = 0%,蓝色 = 100%) - 按键:默认使用
BOOT_PIN(启动按键),短按以 20% 步进循环升降目标(0% → 20% → … → 100% → 0%),长按超过 5 秒执行解除配网(decommission)
构建与烧录要点
根据 README 与 ci.yml(其中fqbn_append: PartitionScheme=huge_app且要求CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y):
- 在 Arduino IDE 中打开
MatterWindowCovering.ino; - 选择目标 ESP32 开发板;
- 分区方案选择"Huge APP (3MB No OTA/1MB SPIFFS)";
- 上传前启用"Erase All Flash Before Sketch Upload";
- 连接开发板后点击 Upload。
若CONFIG_ENABLE_CHIPOBLE未启用(即不使用 BLE 配网),则必须在代码中填写 Wi-Fi 凭据:
const char *ssid = "your-ssid"; // Change this to your WiFi SSID const char *password = "your-password"; // Change this to your WiFi password支持的芯片目标
| SoC | Wi-Fi | Thread | BLE 配网 | 状态 |
|---|---|---|---|---|
| ESP32 | ✅ | ❌ | ❌ | 完全支持 |
| ESP32-S2 | ✅ | ❌ | ❌ | 完全支持 |
| ESP32-S3 | ✅ | ❌ | ✅ | 完全支持 |
| ESP32-C3 | ✅ | ❌ | ✅ | 完全支持 |
| ESP32-C5 | ❌ | ✅ | ✅ | 支持(仅 Thread) |
| ESP32-C6 | ✅ | ❌ | ✅ | 完全支持 |
| ESP32-H2 | ❌ | ✅ | ✅ | 支持(仅 Thread) |
配网说明:ESP32 与 ESP32-S2 不支持 BLE 配网,必须在代码中直接提供 Wi-Fi 凭据;其余目标使用 Matter CHIPoBLE 自动建立 IP 网络。串口日志(波特率 115200)会打印手动配对码与二维码 URL,供配网使用。
状态持久化
示例使用Preferences库保存最后一次的 Lift/Tilt 百分比(键为LiftPercent/TiltPercent)。断电重启后恢复上次状态;无历史状态时默认为 100% 升降(全开)与 0% 翻转,并将恢复后的状态同步给 Matter 控制器。
与真实电机对接的改造建议
示例目前以模拟方式瞬间完成运动,接入真实电机时需关注:
- 电机控制:在
fullOpen()、fullClose()、goToLiftPercentage()、goToTiltPercentage()、stopMotor()中接入实际电机驱动; - 位置反馈:使用编码器或限位开关提供位置反馈——Lift 更新
currentLift(厘米),Tilt 更新currentTiltPercent(旋转百分比); - 运动完成:到达目标后调用
setOperationalState(LIFT, STALL)或setOperationalState(TILT, STALL); - 限位配置:使用
setInstalledOpenLimitLift()/setInstalledClosedLimitLift()/setInstalledOpenLimitTilt()/setInstalledClosedLimitTilt()定义物理行程范围。
串口预期输出
配网并控制后,串口输出形如:
Matter Node is not commissioned yet. Initiate the device discovery in your Matter environment. Commission it to your Matter hub with the manual pairing code or QR code Manual pairing code: 34970112332 QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00 ... Initial state: Lift=100%, Tilt=0% Matter Node is commissioned and connected to the network. Ready for use. Window Covering changed: Lift=100%, Tilt=0% Moving lift to 50% (position: 100 cm) Window Covering changed: Lift=50%, Tilt=0%智能家居平台接入
使用 Matter 兼容的 Hub(如 Apple HomePod、Google Nest Hub 或 Amazon Echo)即可配网设备,配网二维码或手动配对码由串口输出。
- Apple Home:在 iOS "家庭" App 中点 "+" 添加配件,扫描串口二维码或手动输入配对码。设备会以"窗口覆盖/百叶窗"形式出现,可通过滑块控制升降与翻转;
- Amazon Alexa:在 Alexa App 中通过 More > Add Device > Matter 扫描二维码或输入代码完成设置,支持 "Alexa, set blinds to 50 percent" 等语音指令;
- Google Home:在 Google Home App 中通过 "+" > 设置设备 > 新设备 > Matter 设备完成添加,支持滑块与语音控制。
常见问题排查
- 配网时设备不可见:确认 Wi-Fi 或 Thread 连接配置正确;
- 窗帘无响应:检查回调函数是否实现正确、电机控制是否工作;
- 位置不更新:检查是否用正确数值调用了
setLiftPercentage()/setTiltPercentage(); - 状态未持久化:确认
Preferences库已正确初始化且 Flash 未损坏; - RGB LED 不工作:RGB 板需引脚支持 RGB LED 控制;非 RGB 板需引脚支持 PWM(
analogWrite); - Tilt 不工作:确认覆盖类型支持 Tilt(如
BLIND_LIFT_AND_TILT、SHUTTER或BLIND_TILT_ONLY)且已在begin()中指定; - 配网失败:长按按键恢复出厂设置,或在 Arduino IDE 的 Tools 菜单启用 "Erase All Flash Before Sketch Upload",或使用
esptool.py --port <PORT> erase_flash擦除 Flash; - 无串口输出:检查波特率(115200)与 USB 连接。
相关文档与源码索引
- 本文档来源:docs/en/matter/ep_window_covering.rst
- 类声明与枚举定义:libraries/Matter/src/MatterEndpoints/MatterWindowCovering.h
- 完整实现(含属性变化分发与换算逻辑):libraries/Matter/src/MatterEndpoints/MatterWindowCovering.cpp
- 可运行示例:libraries/Matter/examples/MatterWindowCovering/MatterWindowCovering.ino
- 示例说明与智能家居接入:libraries/Matter/examples/MatterWindowCovering/README.md
- Matter 总体介绍:docs/en/matter/matter.rst
- Matter 端点基类:docs/en/matter/matter_ep.rst
- 其他 Matter 端点文档目录:docs/en/matter
【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考