先看完工的效果视频:
配合hass的情景,可以实现白天开窗通风,晚上回家前一个小时远程控制关窗开空调,或者下雨天联动雨水传感器自动关窗。
具体做法:
一、物料
(1)电机和轨道,某宝里面 "电动开窗器自动窗户平开窗平移开窗器电机遥控wifi智能家居远程控" 就是,由于我们自行集成,所以只要买单机就行,lz由于没有24V的电源,就直接买了220V的版本,一条零线两条火线,接近600大洋,带螺丝。如果你买的是24V的版本,则后续电路和程序会稍微有一点不一样,需要再配合24V的双向电机控制板。如果你是推拉窗,店铺里面也有推拉窗的版本。
(2)ESP8266或ESP32一块,型号随意,有2个以上GPIO可用即可
(3)双路继电器一个,工作电压3v3或5v,触发电平建议3v3,触发电流不要太大,被控端市电。lz买的是 某宝"专芯电子"的"2路继电器模块3.3V单片机扩展板高低电平触发STM32树莓派arduino"
(4)220v转5v700ma开关电源一个,如果用手机变压器给8266供电亦可但是相当于要多一个插头
(5)废旧电器的导线若干,插头一个(零火即可,地线没用,接到窗户上本来就相当于接地了)
(6)一套趁手的工具,电钻、电烙铁等等,电机自带了足够的带钻头的螺丝。
二、电路
电路非常简单,esp8266/32输出两个GPIO连接继电器的触发输入,220v插头输入后一路到5v700ma的开关电源,另一路零线接电机的公共零线,火线输入两路继电器的公共端。电机的两个火线分别接继电器的两路常开端。
如图,渣布局,仅供示意:
如果你的继电器触发电压是5v,或者触发电流比较大,可以考虑使用三极管驱动,原料需要增加如2N2222和1K电阻若干。另外如果你的ESP8266只能3v3供电,还需要AMS1117 LDO一块。
三、软件
我们使用mqtt和homeassistant集成。比较麻烦的是,我们需要让继电器保持触发几秒后就自动断电,来控制窗户的位置,目前成品的esp固件如tosmate似乎都不能做到,所以只能使用ardunio自行编写程序,micropython/lua也可以实现。
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <AutoConnect.h>
#include <PubSubClient.h>
#define MQTT_VERSION MQTT_VERSION_3_1_1
#if defined(ARDUINO_ARCH_ESP8266)
ESP8266WebServer Server;
#elif defined(ARDUINO_ARCH_ESP32)
#endif
AutoConnect Portal(Server);
AutoConnectConfig Config;
WiFiClient wifiClient;
String viewCredential(PageArgument &);
String delCredential(PageArgument &);
PubSubClient client(wifiClient);
const PROGMEM char *MQTT_CLIENT_ID = "window-1";
const PROGMEM char *MQTT_SERVER_IP = "你的MQTT服务器IP";
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883;
const PROGMEM char *MQTT_USER = "MQTT用户名";
const PROGMEM char *MQTT_PASSWORD = "MQTT密码";
// MQTT: topics 这里的主题要与homeassistant中的配置文件中的主题保持一致
const char *MQTT_COMMAND_TOPIC = "window/w1/cmd";
const char *MQTT_STATE_TOPIC = "window/w1/stat";
// payloads by default (on/off)
const char *Payload_d5 = "d5";
const char *Payload_d6 = "d6";
const int OPEN_DELAY_TIME = 7000;
const int CLOSE_DELAY_TIME = 10000;
int state = 0;
// function called to turn on/off the light,注意如果你的GPIO口用的不是D5 D6,请注意修改。
void setLasorState()
{
if (state == 5)
{
digitalWrite(D5, HIGH);
delay(OPEN_DELAY_TIME);
digitalWrite(D5, LOW);
//Serial.println("INFO: Turn light on...");
}
else if (state == 6)
{
digitalWrite(D6, HIGH);
delay(CLOSE_DELAY_TIME);
digitalWrite(D6, LOW);
//Serial.println("INFO: Turn light off...");
} else {
return;
}
}
void publishLasorState()
{
if (state == 5)
{
client.publish(MQTT_STATE_TOPIC, Payload_d5, true);
}
else if (state == 6)
{
client.publish(MQTT_STATE_TOPIC, Payload_d6, true);
}
}
// function called when a MQTT message arrived
void callback(char *p_topic, byte *p_payload, unsigned int p_length)
{
// concat the payload into a string
String payload;
Serial.println("INFO:callback...");
for (uint8_t i = 0; i < p_length; i++)
{
payload.concat((char)p_payload[i]);
}
Serial.println(payload);
// handle message topic
if (String(MQTT_COMMAND_TOPIC).equals(p_topic))
{
if (payload.equals(String(Payload_d5)))
{
state = 5;
}
else if (payload.equals(String(Payload_d6)))
{
state = 6;
}
setLasorState();
publishLasorState();
}
}
void reconnect()
{
// Loop until we're reconnected
while (!client.connected())
{
Serial.print("INFO: Attempting MQTT connection...");
// Attempt to connect
if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD))
{
Serial.println("INFO: connected");
// Once connected, publish an announcement...
publishLasorState();
// ... and resubscribe
client.subscribe(MQTT_COMMAND_TOPIC);
}
else
{
Serial.print("ERROR: failed, rc=");
Serial.print(client.state());
Serial.println("DEBUG: try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
// put your setup code here, to run once:
delay(1000);
Serial.begin(115200);
Serial.println("setup start.");
pinMode(D5, OUTPUT);
pinMode(D6, OUTPUT);
digitalWrite(D5, LOW);
digitalWrite(D6, LOW);
Config.autoReconnect = true;
Portal.config(Config);
Portal.begin();
client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
client.setCallback(callback);
Serial.println("setup done.");
}
void loop() {
// put your main code here, to run repeatedly:
Portal.handleClient();
if (!client.connected())
{
reconnect();
}
client.loop();
delay(10);
}
lz使用的是VSCode+PlatformIO,需要加载三个库 AutoConfig PubSubClient [email protected](新版本目前会和pubsubclient冲突,需要用这个版本)。另外使用了AutoConfig支持网页配网,不需要把wifi密码写死在代码中,具体用法是刷入rom后上电等1分钟,会出现一个叫esp8266的wifi名字,密码12345678,连接后访问网关页面即可配置联网,非常简单。
四、集成
首先集成homeassistant,使用cover类设备,最简单的配置为:
cover:
- platform: mqtt
command_topic: "window/w1/cmd"
payload_open: "d5"
payload_close: "d6"
name: ciwozuochuang
然后可以集成天猫精灵,天猫精灵自带了窗户类目,英文名为window,使用论坛的服务或者别人的gateway的话,可能要自行添加一个code为window的设备类别,行为上,使用打开电源、关闭电源可以控制窗户开关。
|