ESP8266-01模块接入巴法云,SmartConfig智能配网,设置断电记忆模式,可以使用米家控制和普通开关控制


前言

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。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

toss007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值