HomeKit ESP32 Control Light III

快把你家的灯接入HomeKit吧其三(整合篇)

我的回合,抽卡。发动魔法卡–融合!

第一篇文章中介绍了如何控制LED的亮灭,而第二篇文章中介绍了如何控制舵机旋转到指定的角度,那么现在让它们融合起来了吧!

融合前的检测

在LED的Demo中,每次开灯关灯操作都会调用**led_write(bool status)**函数,所以我们只需要根据传进来的status值,旋转舵机到对应的角度即可。

先让我们从mcpwm_servo_control_example.c中提取出需要的方法, 内容如下:

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
// 引入的头文件

#include "driver/mcpwm.h"
#include "soc/mcpwm_periph.h"
#include "esp_attr.h"

// 舵机参数的宏定义
#define SERVO_MIN_PULSEWIDTH 500 // 最小脉冲时间ms
#define SERVO_MAX_PULSEWIDTH 2500 // 最大脉冲时间ms
#define SERVO_MAX_DEGREE 180 // 舵机最大可旋转角度

// 初始化2号端口为PWM
static void mcpwm_example_gpio_initialize(void)
{
printf("initializing mcpwm servo control gpio......\n");
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 18); //Set GPIO 2 as PWM0A, to which servo is connected
}

// 该方法输入目标角度,输出对应高电平脉冲宽度单位us
static uint32_t servo_per_degree_init(uint32_t degree_of_rotation)
{
uint32_t cal_pulsewidth = 0;
cal_pulsewidth = (SERVO_MIN_PULSEWIDTH + (((SERVO_MAX_PULSEWIDTH - SERVO_MIN_PULSEWIDTH) * (degree_of_rotation)) / (SERVO_MAX_DEGREE)));
return cal_pulsewidth;
}

// 开灯函数
void turn_on(void *arg)
{
uint32_t angle;
//1. mcpwm gpio 初始化
mcpwm_example_gpio_initialize();
//2. 初始化 mcpwm 配置
printf("Configuring Initial Parameters of mcpwm......\n");
mcpwm_config_t pwm_config;
pwm_config.frequency = 50; // 舵机信号频率为50Hz,每个周期时长20ms
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //应用上面配置到 PWM0A & PWM0B
// 旋转角度
printf("Angle of rotation: %d\n", 0);
// 计算60度对应的脉冲宽度
angle = servo_per_degree_init(60);
printf("pulse width: %dus\n", angle);
mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, angle);
vTaskDelay(10); //Add delay, since it takes time for servo to rotate, generally 100ms/60degree rotation at 5V
vTaskDelete(NULL);
}

// 关灯函数
void turn_off(void *arg)
{
uint32_t angle;
//1. mcpwm gpio 初始化
mcpwm_example_gpio_initialize();
//2. 初始化 mcpwm 配置
printf("Configuring Initial Parameters of mcpwm......\n");
mcpwm_config_t pwm_config;
pwm_config.frequency = 50; //frequency = 50Hz, i.e. for every servo motor time period should be 20ms
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //ConfigurePWM0A & PWM0B with above settings
printf("Angle of rotation: %d\n", 0);
// 计算120度对应的脉冲宽度
angle = servo_per_degree_init(120);
printf("pulse width: %dus\n", angle);
mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, angle);
vTaskDelay(10); //Add delay, since it takes time for servo to rotate,generally 100ms/60degree rotation at 5V
vTaskDelete(NULL);
}

// 最后修改led_write函数为
void led_write(bool on)
{
if (on)
{
// 接收到开灯命令,执行开灯任务
xTaskCreate(turn_on, "turn_on", 4096, NULL, 5, NULL);
}
else
{
// 接收到关灯命令,执行关灯任务
xTaskCreate(turn_off, "turn_off", 4096, NULL, 5, NULL);
}
}

完整的文件位于
HomeKitServoLight.c

来瞅一瞅效果吧。

现在舵机就听我们的指令了哦!

再配合上一个简陋的结构,就可以控制开关了。
servo_on_light

别担心,最终的成品可不会这样寒酸。
本系列还没有结束,还有第四部分的结构设计,尽请期待吧!

下期预告:快把你家的灯接入HomeKit吧其四(结构设计篇)

参考资料:
ESP-IDF 编程指南

Espressif IoT Development Framework

HomeKit ESP32 Control Light II

快把你家的灯接入HomeKit吧其二(舵机篇)

上一篇文章中已经熟悉了如何烧录程序到ESP32,并且成功的点亮了一盏LED灯,如果你动手能力强的话。
那么上一节就是教会了你做了一个支持HomeKit的灯。

本篇会将上一篇中的LED替换成一个舵机。至于为什么使用舵机,是因为我不想破坏开关的原有结构,想使用一种非侵入式的方法去拓展现有的灯开关。

重新启用环境变量

如果你看完上一篇文章后重启了电脑,或者关闭了子系统,那么就得重新配置一下ESP-IDF的环境变量,也可能还需要重新将设备挂载到子系统上。
使用命令

1
. $HOME/esp/esp-idf/export.sh

即可

控制舵机

0x01 控制信号

要想控制舵机,就得发送正确的指令。我使用的舵机长这个样子:
servo
信号频率为50Hz.所谓的指令就是每个周期内,高电平脉冲的持续时间(宽度/长度)。

视频中红色为实际信号,可以看到,随着高电平的持续时间变长,舵机的角度也越来越大。

持续时间 对应角度
0.50ms
1.50ms 90°
2.50ms 180°

0x02控制相关代码

对于这种由脉冲信号控制的舵机,可以使用PWM来进行控制。查阅官方的指南,可以很容易的找到相关例子,甚至直接有现成的Demo可以使用(不得不说官方的例子真的很详细)。
好了,这下子也不用自己写了(还好不用,不然就得用for循环+延时,手动的凑出脉冲信号来控制了)
直接到mcpwm_servo_control_example.c
复制或者下载即可,为了方便,可以复制到上一篇文章中的led.c中去,不过要记得先把之前所有的内容注释掉,因为以后还要使用到那些代码。
其中

1
2
3
#define SERVO_MIN_PULSEWIDTH 1000 //Minimum pulse width in microsecond
#define SERVO_MAX_PULSEWIDTH 2000 //Maximum pulse width in microsecond
#define SERVO_MAX_DEGREE 90 //Maximum angle in degree upto which servo can rotate

需要修改一下,依据我的舵机参数,将其修改为

1
2
3
#define SERVO_MIN_PULSEWIDTH 500 //Minimum pulse width in microsecond
#define SERVO_MAX_PULSEWIDTH 2500 //Maximum pulse width in microsecond
#define SERVO_MAX_DEGREE 180 //Maximum angle in degree upto which servo can rotate

又因为我的板子没有引出18号引脚,所以还是修改为上篇文章中的2号引脚吧

1
2
3
4
5
static void mcpwm_example_gpio_initialize(void)
{
printf("initializing mcpwm servo control gpio......\n");
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 18); //Set GPIO 18 as PWM0A, to which servo is connected
}

改为

1
2
3
4
5
6
static void mcpwm_example_gpio_initialize(void)
{
printf("initializing mcpwm servo control gpio......\n");
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 2); //Set GPIO 2 as PWM0A, to which servo is connected
}
至此,代码就修改完成了。

0x03 烧录进去吧

烧录过程没什么好说的,就是和之前大差不差。

编译好项目以后

1
make -C examples/esp32/led all

先进行earse_flash

1
make -C examples/esp32/led erase_flash

再进行flash。

1
make -C examples/esp32/led flash

0x04 看看效果吧

servo
由于烧录进去的代码只是为了控制舵机,所以是无法被添加到HomeKit里面的。
当烧录完成后,舵机就会缓慢的从0度转到180度,然后快速的回到0度,再次从0度转到180度,然后无限循环。

注:

控制具体转到多少度的代码如下,建议眼熟一下,下篇文章会用到。

1
2
3
4
// 先计算出目标角度对应的高电平持续时间
angle = servo_per_degree_init(count);
// 设置PWM信号
mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, angle);

下期预告:快把你家的灯接入HomeKit吧其三(整合篇)

参考资料:

ESP-IDF 编程指南

Espressif IoT Development Framework

HomeKit ESP32 Control Light

快把你家的灯接入HomeKit吧其一(LED篇)

由于我住的地方没有床头没有灯的开关,每次都得下床才可以关灯。碰巧上次多买了一块ESP32,再碰巧的是大黄猫不久前给我发了个通过HomeKit控制他家ESP8266的视频。于是就有了这篇文章。
目标很明确,那就是ESP32接入HomeKit然后通过Siri控制我的开关。

准备工作 *

环境 环境 环境,配置好环境才可以开始工作,本质上最繁琐的还是配置环境。

我使用的操作系统是Windows 10 18363.719

但是真正的开发环境是位于Windows Subsystem for Linux上的Ubuntu 18.04 LTS(该操作系统可以到Windows 10自带的MicroSoft Store上进行下载)
没错,我套了一层娃。

0x01 下载esp-homekit-demo

https://github.com/maximkulkin/esp-homekit-demo.git

打开终端,进入你喜欢的文件夹,使用命令

1
git clone https://github.com/maximkulkin/esp-homekit-demo.git

下载esp-homekit-demo
clone_repo

0x02 下载esp32开发环境

cd到~并使用mkdir创建esp文件夹并cd进入
mkdir_enter
这里是由于我已经创建过了这个文件了,所以创建失败

下载esp-idf

1
git clone --recursive https://github.com/espressif/esp-idf.git

0x03 设置工具

执行命令,整个过程都是自动的,缺少的依赖工具也会自动下载,可能最大的阻碍来自网络,所以可以考虑使用代理。

1
2
cd ~/esp/esp-idf
./install.sh

该过程很耗时,请耐心等待。

0x04 设置环境变量

执行命令

1
. $HOME/esp/esp-idf/export.sh

现在一切就绪,让我们使用一个LED来进行开发环境验证以及练手吧。Here we go.

点亮你的LED

0x01 初始化并同步项目

回到esp-homekit-demo文件夹,并使用命令

1
git submodule update --init --recursive

0x02 配置wifi

在esp-homekit-demo文件夹下,有一个wifi.h.sample文件,内容为

1
2
#define WIFI_SSID "mywifi"
#define WIFI_PASSWORD "mypassword"

将其中的mywifi替换成目标Wi-Fi的SSID,mypassword替换为目标Wi-Fi的密码。
然后将文件重命名为wifi.h

0x04 挂载设备到子系统上

由于Ubuntu只是我们的子系统,所以它并不能直接检测到插在电脑上的ESP32,需要将其挂载到子系统上才可以检测到。别担心,操作很简单,只需复制命令即可。
首先要做的是把你的ESP32插在主机上,然后到Windows的设备管理器中查看端口号,这里以我的电脑为例子
check_com_port
可以看到我的ESP32是在COM3口上的,所以在终端里面执行命令

1
2
3
sudo chmod 666 /dev/ttyS3
stty -F /dev/ttyS3 -a
stty -F /dev/ttyS3 sane 115200

这样,我的ESP32就接入了子系统的ttyS3接口上

0x03 配置开发板相关参数

在终端里,回到之前的esp-homekit-demo文件夹,并使用命令

1
make -C examples/esp32/led menuconfig

选择Serial flasher config,并将端口号改为ttyS3
enter_serial_config
select_port
使用esc退出并保存

0x04 编译工程

使用命令

1
make -C examples/esp32/led all

该过程也很耗时,还请耐心等待。
当出现
build_done
说明构建顺利完成

0x05 烧录程序

为了防止之前烧录的程序产生影响,所以在每次烧录之前需要擦除flash

使用命令

1
make -C examples/esp32/led erase_flash

当出现Serial port /dev/ttyS3

Connecting…….

时候可能需要按住ESP32板子上的boot键几秒然后松手才可以正常清除和烧录

执行烧录命令

1
make -C examples/esp32/led flash

同样可能需要按下boot键几秒

0x06接入外设查看效果

LED的demo工程里面,启用的GPIO为2号,所以我们需要将LED接入2号引脚。
由于我手上没有单独的LED,所以使用一块LED灯板进行演示。
2号引脚接在LED的正极,LED的负极接在GND上。

打开你的iPhone,然后启动”家庭”,点击添加配件,选择我没有或无法扫描代码。
此时可以在附近的配件里面查看到Sample LED,选中它。虽然会提示未认证的配件,但是不用理会,电机仍然添加。然后输入代码11111111。稍等片刻即可添加成功。
现在就可以对着手机说”嘿,Siri,开灯”或者”嘿,Siri, 关灯”。
turn_off
turn_on

下期预告:快把你家的灯接入HomeKit吧其二(舵机篇)

参考资料:
在Win10的Linux子系统下搭建ESP32的开发环境

ESP-IDF 编程指南

Espressif IoT Development Framework

Build instructions ESP32

© 2025 Do U Find IT? All Rights Reserved.
Theme by hiero