文章目录[隐藏]
前言
Demo下载地址
百度云链接:点击跳转 提取码:8266
最新版代码:点击前往
最近在研究ESP8266模块,入手了几个模块,但是没找到合适的控制程序于是自己研究代码,写了巴法云控制的和点灯科技控制的,点灯科技只能绑定一个米家帐号进行控制,于是就选择了巴法云平台,上个模块图,我写的Demo是针对这种的样子的模块,淘来的ESP-01s和ESP-01s继电器
一、项目介绍
1、开关控制方式:
通过发送on\off控制开关、使用米家、小度、天猫精灵等控制开关、GPIO2接VCC引脚或断开控制开关
2、SmartConfig配网:
关注微信公众号巴法云,在底部 配网–微信配网或者通过airKiss,即可配置网络(配网时关闭5G信号,或者取消名称合并)
3、重置配网:
15秒内连续开关5次,进行重置配网
4、断电记忆模式切换:
通过发送keep、inon、inoff(1:保持, 2:常开, 3:常关)进行切换
5、通过MQTT设备云方式接入网络
二、使用步骤
1.文件目录
- 文件夹:Toss_Bemfa_MIOT_LIGHT_1.1.2
- 文件1:Toss_Bemfa_MIOT_LIGHT_1.1.2.ino(程序文件)
- 文件2:PubSubClient.h(MQTT用到的库文件)
- 文件3:PubSubClient.cpp(MQTT用到的库文件)
- 文件4:tosser.h(我自己自定义的库,把配网步骤进行了封装)
- 文件5:tosser.cpp(我自己自定义的库,把配网步骤进行了封装)
2.代码部分
文件 Toss_Bemfa_MIOT_LIGHT_1.1.2.ino的代码
/***************************************************************************************************
版本号:1.1.2
版本介绍:
1、修复断电记忆模式切换无效的BUG
//
//
版本号:1.1.0
版本介绍:
1、控制:
通过发送on\off控制开关、使用米家、小度、天猫精灵等控制开关、GPIO2空接或者接VCC引脚控制开关
2、配网:
关注微信公众号巴法云,在底部 配网--微信配网或者通过airKiss,即可配置网络(配网时关闭5G信号,或者取消名称合并)
3、重置配网:
15秒内连续开关5次,进行重置配网
4、断电记忆模式切换:
通过发送keep、inon、inoff(1:保持, 2:常开, 3:常关)进行切换
5、通过MQTT设备云方式接入网络
********************************************************************************* ******************/
#include <ESP8266WiFi.h> //默认,加载WIFI头文件
#include "PubSubClient.h" //默认,加载MQTT库文件
#include <EEPROM.h>
#include <tosser.h>
//********************需要修改的部分*******************//
#define ID_MQTT "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f" //用户私钥,控制台获取
const char* topic = "ledlight002"; //主题名字,可在巴法云控制台自行创建,名称随意
//**************************************************//
const char* mqtt_server = "bemfa.com"; //默认,MQTT服务器
const int mqtt_server_port = 9501; //默认,MQTT服务器
WiFiClient espClient;
PubSubClient client(espClient);
/******************************************************************
控制开关函数、机械开关操作函数
*******************************************************************/
const int pinRelay = 0; //需要控制的led引脚
const int GPIO2 = 2; //机械开关接正极的引脚
// 读写EEPROM相关的常量:读入长度EEP_bgn,开始写入位置EEP_stt
const int EEP_bgn = 515; // 读入515字节
const int EEP_stt = 512; // 开始读取或写入位置(512:模式, 513:断电前状态)
int Relay_mode; // 断电记忆(1:保持, 2:常开, 3:常关)
bool Relay_state; // GPIO0引脚断电前状态
// 初始化灯控制函数
void turnOn();
void turnOff();
void KeySwitch();
//相关函数初始化
void turnOn_count(); // 打开5次开关相应的操作
/**************************************************************************
开关操作函数
***************************************************************************/
// 打开灯
void turnOn() {
Serial.println("Turn ON");
digitalWrite(pinRelay, LOW);
turnOn_count();
EEPROM.begin(EEP_bgn);
EEPROM.write(EEP_stt + 1, 0);
EEPROM.end();
}
// 关闭灯
void turnOff() {
Serial.println("Turn OFF");
digitalWrite(pinRelay, HIGH);
EEPROM.begin(EEP_bgn);
EEPROM.write(EEP_stt + 1, 1);
EEPROM.end();
}
// GPIO2机械开关动作判断
void KeySwitch() {
static bool is_btn = digitalRead(GPIO2);//按钮的标志位,用来逻辑处理对比,判断按钮有没有改变状态
bool is = digitalRead(GPIO2); //按钮状态
if ( is != is_btn)
{
bool is_led = digitalRead(pinRelay);
digitalWrite(pinRelay, !digitalRead(pinRelay));
if (is_led == 0) turnOff();
else turnOn();
is_btn = digitalRead(GPIO2); //更新按钮状态
}
}
/**************************************************************************
Time_interval时间内开关5次
***************************************************************************/
int count; // 开关灯次数计数
uint32_t Time_start; // 开关开始计数时间
int Time_interval = 15000; // 开关间隔设置15秒
void turnOn_count() {
count++;
// 如果count值为5,则归零,否则自加1
if (count == 5) {
// 如果时间没有溢出,且在时间差内,重置wifi
uint32_t nowTime = millis();
if (nowTime > Time_start && nowTime - Time_start <= Time_interval) {
tosser.wifiReset(); // 重置WIFI函数
}
count = 0;
}
else if (count == 1) {
// 如果count值为1,重置开始时间
Time_start = millis();
}
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Topic:");
Serial.println(topic);
String msg = "";
for (int i = 0; i < length; i++) {
msg += (char)payload[i];
}
Serial.print("Msg:");
Serial.println(msg);
if (msg == "on") {
turnOn();//开灯函数
} else if (msg == "off") {
turnOff();//关灯函数
} else if (msg == "keep") {
EEPROM.begin(EEP_bgn);
EEPROM.write(EEP_stt, byte(1));
EEPROM.end();
} else if (msg == "inon") {
EEPROM.begin(EEP_bgn);
EEPROM.write(EEP_stt, byte(2));
EEPROM.end();
} else if (msg == "inoff") {
EEPROM.begin(EEP_bgn);
EEPROM.write(EEP_stt, byte(3));
EEPROM.end();
}
msg = "";
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(ID_MQTT)) {
Serial.println("connected");
Serial.print("subscribe:");
Serial.println(topic);
//订阅主题,如果需要订阅多个主题,可发送多条订阅指令client.subscribe(topic2);client.subscribe(topic3);
client.subscribe(topic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
// 初始化
void setup() {
Serial.begin(115200);
// 读取继电器断电器状态
EEPROM.begin(EEP_bgn);
Relay_mode = byte(EEPROM.read(EEP_stt));
Relay_state = bool(EEPROM.read(EEP_stt + 1));
// 初始化IO PIN输出
pinMode(pinRelay, OUTPUT);
if (Relay_mode == byte(1)) {
digitalWrite(pinRelay, Relay_state ? HIGH : LOW);
} else if (Relay_mode == byte(2)) {
digitalWrite(pinRelay, LOW);
} else {
digitalWrite(pinRelay, HIGH);
}
// 引脚LED_BUILTIN(GPIO2)初始化
pinMode(GPIO2, OUTPUT);
digitalWrite(GPIO2, LOW);
EEPROM.end();
// 初始化tosser
tosser.startUp();
client.setServer(mqtt_server, mqtt_server_port);//设置mqtt服务器
client.setCallback(callback); //mqtt消息处理
}
//循环
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
KeySwitch();
}
PubSubClient库文件
PubSubClient库文件是从巴法云的Demo中拿到的,下载地址:点击跳转
tosser库文件
这是我自己封装的库文件,为了让主程序看起来更简洁,我把用来智能配网的方法封装到了库里边
tosser.h 文件:
/*******************
智能配网
*******************/
#ifndef tosser_h
#define tosser_h
//导入Arduino核心头文件
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <EEPROM.h>
#include <Ticker.h>
class tosserClass {
private:
struct config_type
{
char stassid[32]; // WIFI名称
char stapswd[64]; // WIFI密码
uint8_t magic; // 运行模式
};
public:
//tosserClass(); //构造函数,在建立对象的时候执行
//~tosserClass(); //析构函数,在函数完成的最后一刻执行
void startUp(); // 智能选择运行模式
void wifiReset(); // 重置WIFI
};
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_tosser)
extern tosserClass tosser;
#endif
#endif
tosser.cpp 文件:
/*******************
智能配网
*******************/
#include <Arduino.h>
#include"tosser.h"
/**************************************************************************
读取EEPROM,加载WIFI相关参数()、选择设备运行模式(运行、配网)
***************************************************************************/
void tosserClass::startUp()
{
config_type config;
uint8_t *p = (uint8_t*)(&config);
// 读取EEPROM的网络配置信息
EEPROM.begin(511);
for (int i = 0; i < sizeof(config); i++)
{
*(p + i) = EEPROM.read(i);
}
WiFi.mode(WIFI_STA); // STA模式
// 如果没有配置网络,则配置,保存,重启
if (config.magic != 0xAA) {
WiFi.beginSmartConfig();
int cnt = 0; // 循环体运行次数
bool flag_ok = false; // 配网是否完成
// 等待配置网络......
while (true) {
ESP.wdtFeed();
delay(500);
// 如果配置完成,跳出循环
if (flag_ok == true) continue; // continue;
// 如果smartConfig智能配网完成,保存配置,延时重启
if (WiFi.smartConfigDone()) {
strcpy(config.stassid, WiFi.SSID().c_str()); // WIFI名称
strcpy(config.stapswd, WiFi.psk().c_str()); // WIFI密码
config.magic = 0xAA; // 运行模式
// 网络配置信息写入EEPROM
for (int i = 0; i < sizeof(config); i++)
{
EEPROM.write(i, *(p + i));
}
EEPROM.end();
// 延时重启
Ticker delayTimer;
delayTimer.attach(10, []() {
ESP.restart();
});
flag_ok = true;
}
cnt++;
// 如果超时没有连接,重启
if (cnt >= 360) {
ESP.restart();
}
}
}
// 否则开始连接网络
else {
WiFi.begin(config.stassid, config.stapswd); // 连接路由器
}
while (WiFi.status() != WL_CONNECTED) {//检查是否连接成功
delay(500);
Serial.print(".");
}
uint8_t mac[6];
WiFi.macAddress(mac);
Serial.print("MAC: ");
Serial.print(mac[5], HEX);
Serial.print(":");
Serial.print(mac[4], HEX);
Serial.print(":");
Serial.print(mac[3], HEX);
Serial.print(":");
Serial.print(mac[2], HEX);
Serial.print(":");
Serial.print(mac[1], HEX);
Serial.print(":");
Serial.println(mac[0], HEX);
Serial.println("wifi config ok");
}
/***********************************************************
重置WIFI配置,然后延时重启系统
***********************************************************/
void tosserClass::wifiReset() {
Serial.println("\r\n Restore Factory....... ");
config_type config;
uint8_t *p = (uint8_t*)(&config);
strcpy(config.stassid, "");
strcpy(config.stapswd, "");
config.magic = 0x00;
// 网络配置信息写入EEPROM
EEPROM.begin(511);
for (int i = 0; i < sizeof(config); i++)
{
EEPROM.write(i, *(p + i));
}
EEPROM.commit();
// 延时重启
Ticker delayTimer;
delayTimer.attach(500, []() {
ESP.restart();
});
while (true) {
ESP.wdtFeed();
delay(100);
}
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_tosser)
tosserClass tosser;
#endif
总结
总结:
本人非专业人士,C语言和C++不太精通,以上教程纯属照猫画虎,如有缺陷,请大神指正,Demo经过测试,可以正常使用,暂时未发现q其它BUG。
版权声明:本文为CSDN博主「toss007」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44658419/article/details/122280022
暂无评论