我建造 Garage MC 是因为我想了解更多关于电子学的知识。作为奖励,我想下次我出去让车库门开着时,它会节省我的屁股。
*我在 2021 年 1 月 6 日添加了一个更新,其中包含 OTA 更新和 MQTT 到 Home Assistant(详情如下)*
在这个项目之前,我从亚马逊购买了一个兼容 Arduino 的入门套件。所以我是电子产品的初学者,只是学习绳索。但我确实受益于 15 年前做一些计算机编程,所以我能够在 Arduino IDE 上快速学习 C++ 编码。
车库开门器:首先,我必须确定我是否可以轻松地将微控制器与我的 Liftmaster 车库开门器连接起来。幸运的是,Liftmaster 使用两条线在常开(认为是打开的开关)状态下连接回壁挂式遥控器。当按下壁挂式遥控器上的按钮时,它会通过“短路”电线并触发门打开或关闭来短暂完成电路。哦,别忘了检查这些电线上的电压……Liftmaster 手册上说这些电线大约是 20 伏(不是 120 伏),但您的设备可能会有所不同。
微控制器:接下来,我必须决定如何将 Garage MC 连接到互联网。我最初考虑使用 ENC28J60 以太网板,虽然我更喜欢硬线连接,但将线路连接到我的路由器会比它的价值更麻烦。我研究了 wifi 板并决定使用 NodeMCU ESP8266,因为它们成本低且具有多个 GPIO 引脚。
手机应用程序:有多种方法可以通过手机连接到 NodeMCU,包括通过 SMS 消息、将 NodeMCU 用作 Web 服务器等。对我来说,使用 Blynk 应用程序是启动和运行最简单、最快捷的方式。
车库门监控:我决定使用两个霍尔效应传感器来监控车库门的位置。可能已经可以从 Liftmaster 单元获取门的位置甚至行进方向。但是,如果有人拉动紧急释放绳并手动打开门,传感器仍会通知我门已打开。
NodeMCU:我首先将 NodeMCU 插入面包板并通过 USB 连接到我的计算机为其供电。下面的链接有一个很好的教程,用于在 Arduino IDE 上初始设置 NodeMCU:
Blynk :接下来,我将 NodeMCU 连接到互联网和手机上的 Blynk 应用程序。
面包板:是时候添加组件了。虽然我是在装上所有组件后制作了 Fritzing 电路图,但我在这里添加了它,以便更容易参考...
项目代码:我附上了我的项目的完整代码。我试图评论它,但如果有什么你不明白,或者我可以改进,请告诉我。我在教程中添加了一些小代码片段来强调一些事情,例如:
首先是继电器(控制器):我使用的继电器是一个单通道继电器,触发“LOW”以激活。继电器需要 5 伏电压,所以我使用 NodeMCU 上的 VIN 引脚为其供电。继电器有两个用途。
我使用了两个函数来触发我的继电器,使其无阻塞。在我的 Blynk 应用程序中按下按钮时,它会调用一个函数来激活门。请注意,“ActivateDoor()”仅在按下按钮时(上升 = 1)很重要,而不是在释放按钮时,否则您将激活门两次。ActivateDoorRelay 函数将继电器引脚设置为“LOW”,然后设置一个 300 毫秒的计时器,而不是使用“delay()”。然后定时器触发第二个功能将引脚重置为“HIGH”以关闭继电器。我正在检查该州的原因
BLYNK_WRITE(V10) {
if (param.asInt()) { // only do it on button "rising=1"
ActivateDoor(); // trigger the door
}
}
void ActivateDoor() {
activateState = garageState; // get garage state when the button was pressed
long songLength = PlaySong(); // Play a song
// Wait for the song to finish, then activate the relay
myTimer.setTimeout(songLength, ActivateDoorRelay);
}
void ActivateDoorRelay() {
// only trigger the relay if the state hasn't changed since the button press
if (garageState == activateState) {
digitalWrite(RELAY1_PIN, LOW); // trigger the relay to activate the door
myTimer.setTimeout(300, ActivateDoorRelayReset); // Wait 300ms
}
}
void ActivateDoorRelayReset() {
digitalWrite(RELAY1_PIN, HIGH); // Deactivate the door relay
Blynk.virtualWrite(V10, 0); // Reset the Blynk app switch
}
霍尔效应传感器(监视器):霍尔效应传感器监控车库门的位置。传感器是非锁定的并且是数字的(它可以感应或不感应磁铁;模拟输出传感器将测量磁铁的强度)。我在车库门上使用了两个钕磁铁(一起使它们更坚固)来触发传感器。我有一些 CAT6 电缆,所以我将它从车库天花板上的 NodeMCU 连接到每个霍尔传感器。车库门可以处于三种状态之一(因为我不在乎门的移动方向):
我不喜欢轮询事件的发生。因此,霍尔传感器使用“中断”来指示状态变化(例如门关闭移动)。中断就是当霍尔传感器发生状态变化时,它会中断程序代码以立即运行一个短函数。
// Interrupt Declarations
// ESP boards need ICACHE_RAM_ATTR included
void ICACHE_RAM_ATTR InterruptDoorClosed();
void ICACHE_RAM_ATTR InterruptDoorOpen();
// this is only a snippet from the "setup" function
void setup() {
// Interrupts set for the two hall sensors activated on a CHANGE of state
// the Hall sensors require a pullup resistor, I used the internal pullup
pinMode(HALL_CLOSED_PIN,INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(HALL_CLOSED_PIN), InterruptDoorClosed, CHANGE);
pinMode(HALL_OPEN_PIN,INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(HALL_OPEN_PIN), InterruptDoorOpen, CHANGE);
}
// Interrupt for the Hall Sensor at the Door CLOSED point
// activated on CHANGE and Sets a timer to immediately CheckGarageState
void InterruptDoorClosed() {
hallClosedState = digitalRead(HALL_CLOSED_PIN); // get the sensor state
myTimer.setTimeout(10, GarageStateChanged); // run the function in 10ms
}
// Interrupt for the Hall Sensor at the Door OPEN point
// activated on CHANGE and Sets a timer to immediately CheckGarageState
void InterruptDoorOpen() {
hallOpenState = digitalRead(HALL_OPEN_PIN); // get the sensor state
myTimer.setTimeout(10, GarageStateChanged); // run the function in 10ms
}
被动压电蜂鸣器:当门被远程激活(使用 Blynk 应用程序)时,我想提醒车库里的任何人门即将移动。所以我加了一个蜂鸣器来播放一首短歌。我在电路中添加了一个 100 欧姆的电阻,尽管我不确定是否有必要。我还让这首歌不阻塞。尽管这需要我获得歌曲的长度,所以我在完成之前不会激活门。
LED :最后,我添加了两个 LED,一个绿色和一个红色。每个 LED 在其电路中都需要一个 220 欧姆的电阻器。绿色 LED 表示 Garage MC 已连接到 Blynk 服务器。红色 LED 表示 Garage MC 已失去连接。
我的编程流程:如果您通常不在代码中使用计时器,我的程序流程可能难以掌握。它基本上是这样工作的:
我希望 Garage MC 看起来是半专业的,所以我决定将所有组件安装在 Perfboard 上(带有预钻孔的单个铜垫)。有了这个,我必须学习如何焊接。这不一定是困难的,但可能很难做好。
案例:一台 3D 打印机在我儿子的圣诞清单上。希望圣诞老人能通过,因为我也想使用它。事实证明,我有一个旧的 Chamberlain myQ(现在是“Merlin”),我将它拆开、切割和钻孔,然后把它变成一个项目案例。我认为结果没问题,即使继电器伸出底部。
Perfboard :根据机箱的大小,我选择了适合机箱的 perfboard,并且几乎适合 NodeMCU。正如您在我的图表中看到的那样,每侧的顶部引脚不适合(D0 和 A0),但无论如何我都没有使用它们。我没有删除它们,它们只是没有连接到任何东西。
我在 Perfboard 上焊接了两个插头引脚(16 个引脚长,但 NodeMCU 每侧有 15 个引脚)。因此,NodeMCU 位于底部的 15 个引脚上。我主要在 Perfboard 底部焊接连接线(有几个例外)和顶部的组件。长话短说……
并将其安装在车库门开启器上方的车库中(黄色 CAT6 电缆通过门轨连接到霍尔传感器)..
电源:天花板上有一个用于 Liftmaster 开启器的电源插座。所以我决定让事情变得简单。我插入了旧的黑莓手机充电器并使用旧的 USB 电缆为 Garage MC 供电。
我实际上对我的最终结果很满意。但是我会做一些改变:
在 Covid 呆在家里的圣诞假期期间,我开始学习和设置 Home Assistant。因此,我决定让 Garage MC 报告回来并由 Home Assistant 控制。因此,我决定对我的代码进行以下更改:添加 OTA 更新,并添加 MQTT 以与 Home Assistant 通信。
OTA 更新
这是我自 10 月以来对 Garage MC 所做的第一次更新,因为坦率地说,它不需要更新。但是,爬梯子进行更新很痛苦,所以我实施了 OTA 更新。
我在我的 Blynk 应用程序中添加了一个开关,以便打开和关闭 OTA 更新,因为我不希望它一直运行。接下来,我添加了#include
我添加了一个 MD5 散列密码,一个超时(关闭更新过程以防我忘记),并让 LED 闪烁,这样我就知道 GarageMC 处于“更新模式”。全局变量如下:
// OTA variables
#define CLIENT_NAME "GarageMC" // For MQTT topics, MQTT Client ID, and ArduinoOTA
const char ota_pass[] = SECRET_OTA_PWD;
const unsigned long OTA_TIMEOUT = 600000; // Turn off OTA after 10 min. if no update
unsigned long otaTimeout = 0; // End time for OTA = millis()+OTA_TIMEOUT
bool otaOn = false; // set to "true" to turn on OTA updates
const int OTA_BLINK_DELAY = 300; // blink the leds while OTA is ON
unsigned long otaBlinkTimer = 0; // next led blink time
在 setup() 中,我按如下方式初始化 OTA:
ArduinoOTA.setHostname(CLIENT_NAME);
ArduinoOTA.setPasswordHash(ota_pass);
ArduinoOTA.onStart([]() {
DEBUG_PRINTLN("OTA Starting update");
digitalWrite(WIFI_ON_PIN, true);
digitalWrite(WIFI_OFF_PIN, true);
});
ArduinoOTA.onEnd([]() {
DEBUG_PRINTLN("OTA Finished");
});
我的主循环已更新,因此如果打开 OTA 更新,其他一切都会停止(我发现如果 Blynk 仍在运行,更新会很慢或失败)。
if (otaOn) {
ArduinoOTA.handle();
if (millis() > otaTimeout) { // timeout if no upload, then restart
ESP.restart();
}
// blink the red and green leds while OTA is on
if (millis() > otaBlinkTimer) {
SetWifiLeds(!digitalRead(WIFI_ON_PIN));
otaBlinkTimer = millis() + OTA_BLINK_DELAY;
}
} else {
if (Blynk.connected()) {Blynk.run();} // run Blynk if it's connected
myTimer.run(); // Blynk Events Timer (run either way)
// MQTT - loop or reconnect if needed
mqttLoop();
}
最后,当我在 Blynk 应用程序中拨动开关时,它会向虚拟引脚 V0 发送一条消息(off=1 和 on =2,但我希望它是一个布尔值):
BLYNK_WRITE(V0) {
otaOn = param.asInt() - 1;
DEBUG_PRINTLN((String)"V0: " + otaOn);
if (otaOn) { // OTA turned ON
otaTimeout = millis() + OTA_TIMEOUT; // Timeout end time
ArduinoOTA.begin(); // Start the OTA service
} else { // OTA turned OFF
ESP.restart(); // Restart to turn stop ArduinoOTA service
}
}
从 Arduino IDE 处理 OTA 更新所需的一切。我喜欢这样一个事实,除非我通过拨动 Blynk 中的开关来采取行动,否则它不会运行。
MQTT 到家庭助理
我不会进入家庭助理,因为我只是在学习它。但我建议在 YouTube 上搜索 JuanMTech。而且我只是几乎不了解 MQTT,所以在那里也不会有太大帮助。我使用了流行的#include
最简单的方法是连接到 MQTT 代理:
// subscribe to the control topic which can "activate" the garage door (open/close)
const char topicGarageControl[] = CLIENT_NAME"/control";
// publish to the state topics, the state of the door
const char topicGarageState[] = CLIENT_NAME"/state";
WiFiClient espClient;
PubSubClient client(espClient); // client for connection to MQTT broker
client.setServer(mqtt_server, mqtt_port); // server to connect to
client.setCallback(callback); // the "callback" function for subscribed topics
client.connect(mqtt_client_name, mqtt_user, mqtt_pass); // connect to MQTT broker
// after connecting, subscribe to topics you want
client.subscribe(topicGarageControl);
当车库门状态发生变化(open->ajar->closed)时,我将更改发布到 Home Assistant:
// topic = CLIENT_NAME/state
// payload = door state (open/ajar/closed)
client.publish(topic.c_str(), payload.c_str(), retain);
到目前为止,一切都很好。现在我只需要找出 Home Assistant 来处理数据!
我故意没有详细介绍设置 Blynk 应用程序和控件的具体细节。虽然我添加了原理图,但我也没有详细介绍我的生产布线等。我相信我们自己尝试会学到更多。话虽如此,如果您遇到困难或需要帮助才能使项目正常运行(或想知道我为什么要做某事),请给我发消息,我很乐意提供帮助。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !