自制WIFI开关

不到23元即可自制一个WIFI开关并接入米家,使用小爱同学、APP或网页控制。(小米官方的智能开关要59。。。)网页控制使用到了巴法云。

演示

开始

开始之前,你需要准备:

  • 一些配件(在下面)
  • Arduino IDE
  • 一双手

配件

配件图

左上角为ESP-01S模块,左下角为ESP-01S Relay模块(继电器),两者在某宝一起购买需9.4元

右上角为ESP-01S下载器,某宝售卖7.8元

右下角为220V转5V模块,某宝5.1元

以上共计22.3元

开始之前

打开你的Arduino IDE

进入首选项(Preferences),找到附加开发板管理器地址(Additional Board Manager URLs),并在其后添加如下信息:
http://arduino.esp8266.com/stable/package_esp8266com_index.json

之后点击工具 - 开发板 - 开发板管理器,进入开发板管理器界面

找到 esp8266 并安装

安装完成后,重启 Arduino IDE 。在工具 - 开发板选项中即会看到 ESP8266 开发板的选项

编程

写入以下代码:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>


//巴法云服务器地址默认即可
#define TCP_SERVER_ADDR "bemfa.com"
//服务器端口,tcp创客云端口8344
#define TCP_SERVER_PORT "8344"

#define BLINKER_WIFI
#define BLINKER_MIOT_LIGHT

#include <Blinker.h>

const int Switch_Pin = 0;              //单片机Switch引脚值,GPIO0引脚

//********************需要修改的部分*******************//
// 以下为巴法云部分
#define DEFAULT_STASSID  "ChinaNet-*****"     //WIFI名称,区分大小写,不要写错
#define DEFAULT_STAPSW   "********"  //WIFI密码
String UID = "123456";  //用户私钥,可在控制台获取,修改为自己的UID
String TOPIC =   "switch";         //主题名字,可在控制台新建

// 以下为Blinker部分
BlinkerButton Button_Switch("btn-switch");

char auth[] = "";// 设备秘钥
char ssid[] = DEFAULT_STASSID;
char pswd[] = DEFAULT_STAPSW;


//最大字节数
#define MAX_PACKETSIZE 512
//设置心跳值30s
#define KEEPALIVEATIME 30*1000



//tcp客户端相关初始化,默认即可
WiFiClient TCPclient;
String TcpClient_Buff = "";
unsigned int TcpClient_BuffIndex = 0;
unsigned long TcpClient_preTick = 0;
unsigned long preHeartTick = 0;//心跳
unsigned long preTCPStartTick = 0;//连接
bool preTCPConnected = false;



//相关函数初始化
//连接WIFI
void doWiFiTick();
void startSTA();

//TCP初始化连接
void doTCPClientTick();
void startTCPClient();
void sendtoTCPServer(String p);

//Switch 控制函数
void turnOnSwitch();
void turnOffSwitch();

void switch_callback(const String & state)
{
    BLINKER_LOG("get switch state: ", state);

    if (state == BLINKER_CMD_ON) {
        turnOnSwitch();
        Button_Switch.print("on");
    }
    else {
        turnOffSwitch();
        Button_Switch.print("off");
    }
}

void miotPowerState(const String & state)
{
    BLINKER_LOG("need set power state: ", state);

    if (state == BLINKER_CMD_ON) {
        turnOnSwitch();

        BlinkerMIOT.powerState("on");
        BlinkerMIOT.print();
    }
    else if (state == BLINKER_CMD_OFF) {
        turnOffSwitch();

        BlinkerMIOT.powerState("off");
        BlinkerMIOT.print();
    }
}

/*
  *发送数据到TCP服务器
 */
void sendtoTCPServer(String p){
  
  if (!TCPclient.connected()) 
  {
    Serial.println("Client is not readly");
    return;
  }
  TCPclient.print(p);
  Serial.println("[Send to TCPServer]:String");
  Serial.println(p);
}


/*
  *初始化和服务器建立连接
*/
void startTCPClient(){
  if(TCPclient.connect(TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT))){
    Serial.print("\nConnected to server:");
    Serial.printf("%s:%d\r\n",TCP_SERVER_ADDR,atoi(TCP_SERVER_PORT));
    
    String tcpTemp="";  //初始化字符串
    tcpTemp = "cmd=1&uid="+UID+"&topic="+TOPIC+"\r\n"; //构建订阅指令
    sendtoTCPServer(tcpTemp); //发送订阅指令
    tcpTemp="";//清空
    
    preTCPConnected = true;
    preHeartTick = millis();
    TCPclient.setNoDelay(true);
  }
  else{
    Serial.print("FaiSwitch connected to server:");
    Serial.println(TCP_SERVER_ADDR);
    TCPclient.stop();
    preTCPConnected = false;
  }
  preTCPStartTick = millis();
}


/*
  *检查数据,发送心跳
*/
void doTCPClientTick(){
 //检查是否断开,断开后重连
   if(WiFi.status() != WL_CONNECTED) return;

  if (!TCPclient.connected()) {//断开重连

  if(preTCPConnected == true){

    preTCPConnected = false;
    preTCPStartTick = millis();
    Serial.println();
    Serial.println("TCP Client disconnected.");
    TCPclient.stop();
  }
  else if(millis() - preTCPStartTick > 1*1000)//重新连接
    startTCPClient();
  }
  else
  {
    if (TCPclient.available()) {//收数据
      char c =TCPclient.read();
      TcpClient_Buff +=c;
      TcpClient_BuffIndex++;
      TcpClient_preTick = millis();
      
      if(TcpClient_BuffIndex>=MAX_PACKETSIZE - 1){
        TcpClient_BuffIndex = MAX_PACKETSIZE-2;
        TcpClient_preTick = TcpClient_preTick - 200;
      }
      preHeartTick = millis();
    }
    if(millis() - preHeartTick >= KEEPALIVEATIME){//保持心跳
      preHeartTick = millis();
      Serial.println("--Keep alive:");
      sendtoTCPServer("cmd=0&msg=keep\r\n");
    }
  }
  if((TcpClient_Buff.length() >= 1) && (millis() - TcpClient_preTick>=200))
  {//data ready
    TCPclient.flush();
    Serial.println("Buff");
    Serial.println(TcpClient_Buff);
    if((TcpClient_Buff.indexOf("&msg=on") > 0)) {
      turnOnSwitch();
    }else if((TcpClient_Buff.indexOf("&msg=off") > 0)) {
      turnOffSwitch();
    }
   TcpClient_Buff="";
   TcpClient_BuffIndex = 0;
  }
}

void startSTA(){
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin(DEFAULT_STASSID, DEFAULT_STAPSW);
}



/**************************************************************************
                                 WIFI
***************************************************************************/
/*
  WiFiTick
  检查是否需要初始化WiFi
  检查WiFi是否连接上,若连接成功启动TCP Client
  控制指示灯
*/
void doWiFiTick(){
  static bool startSTAFlag = false;
  static bool taskStarted = false;
  static uint32_t lastWiFiCheckTick = 0;

  if (!startSTAFlag) {
    startSTAFlag = true;
    startSTA();
    Serial.printf("Heap size:%d\r\n", ESP.getFreeHeap());
  }

  //未连接1s重连
  if ( WiFi.status() != WL_CONNECTED ) {
    if (millis() - lastWiFiCheckTick > 1000) {
      lastWiFiCheckTick = millis();
    }
  }
  //连接成功建立
  else {
    if (taskStarted == false) {
      taskStarted = true;
      Serial.print("\r\nGet IP Address: ");
      Serial.println(WiFi.localIP());
      startTCPClient();
    }
  }
}
//打开
void turnOnSwitch(){
  Serial.println("Turn ON");
  digitalWrite(Switch_Pin,LOW);
}
//关闭
void turnOffSwitch(){
  Serial.println("Turn OFF");
    digitalWrite(Switch_Pin,HIGH);
}


// 初始化,相当于main 函数
void setup() {
  Serial.begin(115200);
  BLINKER_DEBUG.stream(Serial);

  pinMode(Switch_Pin,OUTPUT);
  digitalWrite(Switch_Pin,HIGH);

  Blinker.begin(auth, ssid, pswd);
  Button_Switch.attach(switch_callback);
  BlinkerMIOT.attachPowerState(miotPowerState);

  
  Serial.println("Beginning...");
}

//循环
void loop() {
  doWiFiTick();
  doTCPClientTick();
  
  Blinker.run();
}

注册巴法云后在控制台选择TCP创客云

创建一个新主题switch

注册Blinker(点灯科技)下载APP

点击右上角加号

选择独立设备-网络接入-点灯科技

复制key到代码中

如果你是新手:

在主界面选择新的设备-界面配置,粘贴图片下方的配置保存

如果你是老手:

请参考点灯科技官网的文档自行设计界面

Blinker配置:

{¨config¨{¨headerColor¨¨transparent¨¨headerStyle¨¨dark¨¨background¨{¨img¨¨assets/img/headerbg.jpg¨}}¨dashboard¨|{¨type¨¨btn¨¨ico¨¨fad fa-siren-on¨¨mode¨Ê¨t0¨¨点我开关灯¨¨clr¨¨#389BEE¨¨t1¨¨文本2¨¨bg¨É¨cols¨Í¨rows¨Í¨key¨¨btn-switch¨´x´Ë´y´Ì¨speech¨|÷¨lstyle¨Ë}{ß9¨tex¨ßE¨卧室灯¨ßIßJßKËßB´´ßLÍßMÊßN¨tex-272¨´x´É´y´ÉßP|÷ßQÊßG¨#FFF¨}÷¨actions¨|¦¨cmd¨¦¨switch¨‡¨text¨‡¨on¨¨打开?name¨¨off¨¨关闭?name¨—÷¨triggers¨|{¨source¨ßX¨source_zh¨¨开关状态¨¨state¨|ßZßb÷¨state_zh¨|¨打开¨¨关闭¨÷}÷}

将WIFI名称及密码、巴法云私钥填入代码中

修改完代码后,通过下载器上传到ESP-01S

动手

你现在要做的就是把这些配件连起来并开始拆家

注:为了安全,改装前记得把总电源关了,我为了图方便没有断电直接上手了(可以看到图中我的卧室灯还是正常亮着的)

通电之后打开点灯APP或巴法云,看到设备已经在线了,说明你已经成功完成上述步骤。

现在,请你按下点灯APP的按钮,或者是在巴法云后台发送“on”,检查你的灯是否能正常亮起。

请各位根据实际情况,自行采取解决方案。

结语

岁月流逝,时代变迁。科技改变人们的生活。我们用着自己的双手,打造出自己的世界。

我是一名准高三学生党,目前还未满17周岁,若是文章中有什么不足之处,请各位尽情指出,我会虚心接受。

 

知乎:https://zhuanlan.zhihu.com/p/391265146

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注