【智能取暖器DIY】ESP32+blinker接入小爱同学语音控制,定时...
本帖最后由 嘎嘣脆ovo 于 2021-1-15 13:35 编辑【写在前面】
本着认真分享,让其他和我一样有需要的朋友轻松上手,能有参考意义,所以可能较啰嗦。
特别提示:家用电器220V高压危险,请自行判断,无把握请勿操作!本帖只做经验分享,请自行评估风险,若有意外与本人无关。
硬件设备是:乐鑫ESP32、5V继电器 、可拔插220V连接线1平方、220V转5V电源,给继电器供电(ESP32只能输出3.3V,且电源更有保障不占用插座)
环境安装:
1.Ardunio IDE 点此下载。 中国大陆安装方法。
2.Ardunio ESP32 Blinke支持库
Windows:将下载好的blinker库解压到 我的电脑>文档>Arduino>libraries 文件夹中
Mac OS:将下载好的blinker库解压到 文稿>Arduino>libraries 文件夹中
3.Ardunio安装ESP32开发板。选择ESP32 Dev Module。重要!!
ESP32开发板安装方法:在Ardunio IDE——文件——首选项——附加开发板管理网址中加入 https://dl.espressif.com/dl/package_esp32_index.json ;
接着Ardunio IDE——工具——开发板——开发板管理器,搜索 ESP32 安装即可。
【案例一】前些天脸上冒痘,去医院拿了点药,吃完皮肤更干了。冬天房间一干,更是起皮,贼不爽。于是乎,翻出了不知道啥时候公司节日礼品——超声波加湿器。但是,每天手动开关就很烦,希望和温湿度计联动自动开关。于是就研究了下点灯接入小爱。
完整代码跳转查看:
https://github.com/kuole-o/IoT_xiaoai_blinker/blob/main/xiaoai_on_off/xiaoai_on_off.ino加湿器是“微动开关”,(微动开关:按一次on,再按一次off那种)我的加湿器更扯,开始工作后,再按一次电源似乎是无响应,也就是按两次才能off。在qq群一位老哥指导下,实现了相关效果。后来直接换了加湿器,因此这部分代码实现且测试过,但硬件没搞。
完整代码跳转查看:
https://github.com/kuole-o/IoT_xiaoai_blinker/blob/main/xiaoai_MicroSwitch_1on_2off/xiaoai_MicroSwitch_1on_2off.ino
【案例二】
后来发现加湿器效果弱,只能从 35%湿度提升到42%左右,17平的卧室。。于是,干脆下单了米家纯净式加湿器。效果果然上来了不加电,纯蒸发都能保持 55%~60%湿度。
于是乎,又把ESP32改成控制取暖器,夏天控制电风扇。因为想着兼容性强,后面随时控制其他家电,而且继电器还剩一个没用,就按2400w电路设计(导致线材有些粗,1平方的)。下面开干。
[*]首先是控制部分,ESP32控制程序。担心大篇幅代码影响阅读体验,所以完整代码在文末,想现在就看的,用下面链接。
https://github.com/kuole-o/IoT_xiaoai_blinker/blob/main/xiaoai_4_no_off_BlinkerButton5/xiaoai_4_no_off_BlinkerButton5.ino
硬件连接:
[*]ESP32控制引脚13/12/27/25分别链接到继电器1/2/3/4的IN1、IN2、IN3、IN4。ESP32通过microUSB从220V电源上取电。
[*]
[*]继电器输入供电,DC+——电源V+ DC- ——电源V-
[*]
[*]继电器输出:NO常开口分别接拔插式插头——公头。公共端COM一样链接。注意:最好根据线材颜色链接同端口,以免后面错乱。
在不连接负载情况下,对控制板、继电器做控制调试。验证无误后,开始下文的硬件链接。
[*]拆开取暖器,一根3芯控制低温、高温的线,链接到调温旋钮上。此处调节到低温旋钮,用万用表测通断,分辨低温、高温的接头。用电烙铁焊接。
[*]
[*]一根2芯线,控制摇头旋钮的闭合;一根2芯线从取暖器电源线上取电,转给220V降压电源。此处注意连接在“防侧翻保险”后。
[*]
[*]
[*]
至此,硬件电路链接完成。实测效果如下:https://www.bilibili.com/video/BV1yT4y1N7eb
【我的所有相关代码见GitHub】
https://github.com/kuole-o/IoT_xiaoai_blinker
【案例2完整代码】
欢迎一起交流,本人纯外行小白,代码若有不妥望指正!
/* *****************************************************************
Download latest Blinker library here:
https://github.com/blinker-iot/blinker-library/archive/master.zip
Blinker is a cross-hardware, cross-platform solution for the IoT.
It provides APP, device and server support,
and uses public cloud services for data transmission and storage.
It can be used in smart home, data monitoring and other fields
to help users build Internet of Things projects better and faster.
Make sure installed 2.7.4 or later ESP8266/Arduino package,
if use ESP8266 with Blinker.
https://github.com/esp8266/Arduino/releases
Make sure installed 1.0.4 or later ESP32/Arduino package,
if use ESP32 with Blinker.
https://github.com/espressif/arduino-esp32/releases
Docs: https://diandeng.tech/doc
* *****************************************************************
Blinker 库下载地址:
https://github.com/blinker-iot/blinker-library/archive/master.zip
Blinker 是一套跨硬件、跨平台的物联网解决方案,提供APP端、设备端、
服务器端支持,使用公有云服务进行数据传输存储。可用于智能家居、
数据监测等领域,可以帮助用户更好更快地搭建物联网项目。
如果使用 ESP8266 接入 Blinker,
请确保安装了 2.7.4 或更新的 ESP8266/Arduino 支持包。
https://github.com/esp8266/Arduino/releases
如果使用 ESP32 接入 Blinker,
请确保安装了 1.0.4 或更新的 ESP32/Arduino 支持包。
https://github.com/espressif/arduino-esp32/releases
文档: https://diandeng.tech/doc
* *****************************************************************/
#define BLINKER_WIFI
#define BLINKER_MIOT_MULTI_OUTLET //设置为小爱多个插座的模式
#include <Blinker.h>
char i;
char auth[] = "******";
char ssid[] = "******";
char pswd[] = "******";
bool oState = { false };
// 新建组件对象,要和APP组件’数据键名’一致
BlinkerButton Button1("btn_a");
BlinkerButton Button2("btn_b");
BlinkerButton Button3("btn_c");
BlinkerButton Button4("btn_d");
BlinkerButton Button5("btn_all");
// 按下Blinker APP按键1即会执行该函数
void button1_callback(const String & state)
{
BLINKER_LOG("get button state: ", state);
digitalWrite(13, !digitalRead(13));
if (state == "on") {
digitalWrite(13, LOW);
Button1.print("on");
Button1.text("摇头:开");
}
else if (state == "off") {
digitalWrite(13, HIGH);
Button1.print("off");
Button1.text("摇头:关");
}
}
// 按下Blinker APP按键2即会执行该函数
void button2_callback(const String & state)
{
BLINKER_LOG("get button state: ", state);
digitalWrite(12, !digitalRead(12));
if (state == "on") {
digitalWrite(12, HIGH);
Button2.print("on");
Button2.text("低温/弱风");
}
else if (state == "off") {
digitalWrite(12, LOW);
Button2.print("off");
Button2.text("低温/弱风");
}
}
// 按下Blinker APP按键3即会执行该函数
void button3_callback(const String & state)
{
BLINKER_LOG("get button state: ", state);
digitalWrite(27, !digitalRead(27));
if (state == "on") {
digitalWrite(27, HIGH);
Button3.print("on");
Button3.text("高温/强风");
}
else if (state == "off") {
digitalWrite(27, LOW);
Button3.print("off");
Button3.text("高温/强风");
}
}
// 按下Blinker APP按键4即会执行该函数
void button4_callback(const String & state)
{
BLINKER_LOG("get button state: ", state);
digitalWrite(25, !digitalRead(25));
if (state == "on") {
digitalWrite(25, HIGH);
Button4.print("on");
Button4.text("未定义:开");
}
else if (state == "off") {
digitalWrite(25, LOW);
Button4.print("off");
Button4.text("未定义:关");
}
}
// 按下Blinker APP按键5即会执行该函数
void button5_callback(const String & state)
{
BLINKER_LOG("get button state: ", state);
digitalWrite(13, !digitalRead(13));
digitalWrite(12, !digitalRead(12));
if (state == "on") {
digitalWrite(13, HIGH);
digitalWrite(12, HIGH);
Button1.print("on");
Button2.print("on");
Button1.text("摇头:开");
Button2.text("低温/弱风");
}
else if (state == "off") {
digitalWrite(12, LOW);
digitalWrite(13, LOW);
digitalWrite(27, LOW);
Button1.print("off");
Button2.print("off");
Button3.print("off");
Button1.text("摇头:关");
Button2.text("低温/弱风");
Button3.text("高温/强风");
}
}
// 13-摇头/不摇头;12-低温/弱风;27-高温/强风
void miotPowerState(const String & state, uint8_t num)
{
BLINKER_LOG("need set outlet: ", num, ", power state: ", state);
i = 0; //初始化
if (num == 1) {
i = 13;
}
else if (num == 2) {
i = 12;
}
else if (num == 3) {
i = 27;
}
else if (num == 4) {
i = 25;
}
if (state == BLINKER_CMD_ON) {
switch (i) {
case 12:
digitalWrite(27, LOW);
digitalWrite(i, !digitalRead(27));
BlinkerMIOT.powerState("on", num);
BlinkerMIOT.print();
oState = true;
break;
case 27:
digitalWrite(12, LOW);
digitalWrite(i, !digitalRead(12));
BlinkerMIOT.powerState("on", num);
BlinkerMIOT.print();
oState = true;
break;
default:
digitalWrite(i, HIGH);
BlinkerMIOT.powerState("on", num);
BlinkerMIOT.print();
oState = true;
}
}
else if (state == BLINKER_CMD_OFF) {
switch (i) {
case 12:
digitalWrite(27, LOW);
digitalWrite(i, LOW);
BlinkerMIOT.powerState("off", num);
BlinkerMIOT.print();
oState = false;
break;
case 27:
digitalWrite(12, LOW);
digitalWrite(i, LOW);
BlinkerMIOT.powerState("off", num);
BlinkerMIOT.print();
oState = false;
break;
default:
digitalWrite(i, LOW);
BlinkerMIOT.powerState("off", num);
BlinkerMIOT.print();
oState = false;
}
if (num == 0) {
for (uint8_t o_num = 0; o_num < 5; o_num++) {
oState = false;
}
}
}
}
void miotQuery(int32_t queryCode, uint8_t num)
{
BLINKER_LOG("AliGenie Query outlet: ", num, ", codes: ", queryCode);
switch (queryCode)
{
case BLINKER_CMD_QUERY_ALL_NUMBER :
BLINKER_LOG("MIOT Query All");
BlinkerMIOT.powerState(oState ? "on" : "off", num);
BlinkerMIOT.print();
break;
case BLINKER_CMD_QUERY_POWERSTATE_NUMBER :
BLINKER_LOG("MIOT Query Power State");
BlinkerMIOT.powerState(oState ? "on" : "off", num);
BlinkerMIOT.print();
break;
default :
BlinkerMIOT.powerState(oState ? "on" : "off", num);
BlinkerMIOT.print();
break;
}
}
void dataRead(const String & data)
{
BLINKER_LOG("Blinker readString: ", data);
Blinker.vibrate();
uint32_t BlinkerTime = millis();
Blinker.print("millis", BlinkerTime);
}
void setup()
{
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
pinMode(12, OUTPUT);
digitalWrite(12, LOW);
pinMode(27, OUTPUT);
digitalWrite(27, LOW);
pinMode(25, OUTPUT);
digitalWrite(25, LOW);
Blinker.begin(auth, ssid, pswd);
Blinker.attachData(dataRead);
Button1.attach(button1_callback);
Button2.attach(button2_callback);
Button3.attach(button3_callback);
Button4.attach(button4_callback);
Button5.attach(button5_callback);
BlinkerMIOT.attachPowerState(miotPowerState);
BlinkerMIOT.attachQuery(miotQuery);
}
void loop()
{
Blinker.run();
}踩过的坑:
[*]编译时,一定要选择合适的开发板,比如上面我用的那个 ESP32 Dev Module
[*]小爱音箱、小爱同学 两个App的小爱训练是分开的,若要同时支持泛化指令,得都设置一遍。
[*]Ardunio IDE 编辑器很辣鸡,有时候一不留神多一个 { 没发现就报错,建议在其他编辑器里搞好代码,复制到IDE中编译。
[*]买拔插接头,不要带焊锡的,很难剥皮。。
[*]万用表很方便,可以搞一个。
[*]电器里接头处,多用电胶布包扎。
[*]遇到问题,多查资料。
家用电器220V高压危险,请自行判断,无把握请勿操作!本帖只做经验分享,请自行评估风险,若有意外与本人无关。
最后,祝你成功!本帖不定期来瞄一眼,欢迎一起交流。
不错。。。。。。。。。。。。 你这思路非常不错,要是改成8266芯片,然后控制电风扇就非常牛了,控制带红外遥控的电风扇,io口输出高低电平,直接输送到电风扇的按键触发端,这样改电风扇就不用加继电器了,改造成本和难度就非常低了。你们要是弄好程序,我可以负责硬件改造和测试出教程。 int nSignalState = 0;
unsigned long lSignalSovleStartTimer = 0;
unsigned long Number = 0;
long GetTickCount()
{
return millis();
}
这个时间的代码和后面loop对应的时间不是很理解,能注释一下这段吗?谢谢:lol 810986815 发表于 2021-1-19 19:21
你这思路非常不错,要是改成8266芯片,然后控制电风扇就非常牛了,控制带红外遥控的电风扇,io口输出高低电 ...
我GitHub上,有其他几个模拟这种微动开关的例程,测试可以用。延迟200ms 自动关,模拟传统电器上的微动开关
我现在这个,自己用的取暖器、电风扇都能用。不用继电器就有点麻烦,且扩展性不强,不能解耦。 黄非红 发表于 2021-1-20 08:46
int nSignalState = 0;
unsigned long lSignalSovleStartTimer = 0;
unsigned long Number = 0;
int nSignalState = 0; //创建一个整数型变量 nSignalState,且初始值0。判断on还是off
unsigned long lSignalSovleStartTimer = 0; //创建一个无符号长整型的变量lSignalSovleStartTimer ,且初始值0。用来计时,当200ms以上,自动LOW低电位,模拟微动开关按下后抬起手指。
unsigned long Number = 0;//记录第几次,因为我那个加湿器有防误触,开只用微动开关按一次,关要按两次,所以引入这个变量,分别控制开和关。
long GetTickCount()
{
return millis();//millis函数可以用来获取Arduino开机后运行的时间长度,该时间长度单位是毫秒,最长可记录接近50天左右的时间。如果超出记录时间上限,记录将从0重新开始。http://www.taichi-maker.com/homepage/reference-index/arduino-code-reference/millis/
} MARK~~~~~~~~~~~~~ 本帖最后由 花开千树 于 2021-1-27 16:33 编辑
同款继电器,请教一下,我的使用情况如下:
继电器模块外部接电5V,UNO接口6连接IN1和IN2,接口7接IN3和IN4(控制1个电机的正反转)。当我使用接口6给HIGH信号(接口7 LOW信号)时,IN1/IN2的LED正常发光,但是IN3/IN4的LED灯也会发光(亮度不大),此时万用表测量接口7和UNO的GND会有0.2V左右的电压,若断开接口7与继电器模块的线则正常(IN3/4的led不发光),检查很久,都不知道是什么原因。
相反给接口7HIGH信号,就变成IN1/2的LED也会微微发光。
尝试了一下使用两块继电器模块,依然出现相同问题。。。
花开千树 发表于 2021-1-27 16:31
同款继电器,请教一下,我的使用情况如下:
继电器模块外部接电5V,UNO接口6连接IN1和IN2,接口7接IN3和IN4 ...
这。。纯电路知识了,我也不懂你查查资料吧
页:
[1]