低功耗ESP8266 4位智能插座(开源)



      打印机等设备太多,长期通电待机功耗大,不同电,使用时又不方便,之前一直使用小K 一位智能插座,连接排插,定时开关所有设备。知道最近玩起ESP8266,学习了Arduino,所以产生了自己DIY智能插座的项目。

     目前已实现功能:1.低功耗设计,采用4只磁保持继电器,只在开关动作时继电器线圈通电,其余时间只有ESP8266待机耗电,用USB电流表测试整个PCB待机电流0.08A,单个继电器动作时电流0.15A。

                             2.断网状态 4位插座可独立使用按键控制,相应LED指示通断状态。

                             3.采用MQTT协议接入Home Assistant,可使用Home Assistant WEB或者手机客户端控制每位开关,同时插座会反馈按键开关操作插座的状态,按动任意按键,插座将局域网IP发送给MQTT订阅主题

                             4.使用ESP8266 WEBserver服务,可网页操作开关通断(同时支持POST参数控制,可接入其他自动控制设备或程序)

                             5.使用ESP8266 EEPROM存储开关状态,重启上电可分别设置每位开关状态为 关闭/开启/保持上次状态(使用WEB配置)

                             6.WEB界面可设置4位开关备注名称

                             7.上电长按第3个按键(电源线端为按键1),可重置EEPROM参数

                             8.WIFI账号密码配网,使用过WiFiManager中文库做WEB配网,但偶尔程序跑飞,所以改成WEB页面配网,断码请自行完善

                             9.WEB配网及内置定时开关功能正在完善中,敬请期待

注意,插座带有220V交流电,非专业人士请勿拆开和改造!该文章仅为展示,如仿制请自行注意安全!!!

本开源项目遵循GPL3.0开源协议,但是如果商用,请您捐助所得净利的20%给慈善项目并且将整个捐款订单公开,如果做不到请不要商用



PCB,为了薅羊毛,分成2块

PCB


2块PCB都焊好原件

PCB拼接起来

PCB正面


PCB背面HC595


打样的PCB,这还只是一小部分

继电器焊好

换个角度

PCB背面


改装对象

公牛插座

型号铭牌

特制螺丝加特制螺丝刀

拆开插座

继续拆

拆LED指示灯

PCB安装试下

固定柱高了


直接截断


这个位置也高了,截断

圈圈全部截断


原开关

只取开关帽


螺柱加强筋顶到PCB了

这个加强筋也顶到了

加强筋直接处理掉

另一边的加强筋

指示灯固定座也搞了,直接截断

PCB装好后,按键基本在中间

背壳4个固定柱档到继电器了,截掉

LED,取前端导光部分

LED导光安装到LED固定座,按键中间打热熔胶,减小与轻触开关之间的间隙

处理后的样子

火线用导线连接铜触片

换个角度

电源模块加高温胶纸绝缘

装好电源模块的样子

LED导光柱加热熔胶固定

火线焊接到PCB

全部连接好

接线特写

装好螺丝,严丝合缝,和原装的一样

正面,也是和原装一模一样


WEB配置及控制界面

Home Assistant WEB界面 支持插座反馈状态

固件升级页面,直接WEB上传bin文件升级


Home Assistant 配置文件 

configuration.yaml 文件添加 “ switch: !include switchs.yaml”


switchs.yaml 文件如下这是1个插座,多个插座自行更改设备名及订阅主题


- platform: mqtt
  name: "GN-B3043-1F773D-K1"      #设备名称,自己设置
  state_topic: "GN-B3043-1F773D/state/K1"    # “GN-B3043-1F773D” MQTT订阅主题,即插座的设备名称,可网页自行设置,设置成Auto 则自动用MAC生产,该地址即自动生成
  command_topic: "GN-B3043-1F773D/set/K1"
  unique_id: "32b33778a2614be0a3290f81afdeaba9"   #实体ID,任意,不重复就行,不设置,Home Assistant会提示无唯一实体ID payload_on: "1"
  payload_off: "0"
  state_on: "1"
  state_off: "0"
  optimistic: false
  qos: 0
  retain: false
  icon: mdi:monitor
- platform: mqtt
  name: "GN-B3043-1F773D-K2"
  state_topic: "GN-B3043-1F773D/state/K2"
  command_topic: "GN-B3043-1F773D/set/K2"
  unique_id: "32b33778a2614be0a3290f81afdeabaa"
  payload_on: "1"
  payload_off: "0"
  state_on: "1"
  state_off: "0"
  optimistic: false
  qos: 0
  retain: false
- platform: mqtt
  name: "GN-B3043-1F773D-K3"
  state_topic: "GN-B3043-1F773D/state/K3"
  command_topic: "GN-B3043-1F773D/set/K3"
  unique_id: "32b33778a2614be0a3290f81afdeabab"
  payload_on: "1"
  payload_off: "0"
  state_on: "1"
  state_off: "0"
  optimistic: false
  qos: 0
  retain: false
  icon: mdi:television-classic

- platform: mqtt
  name: "GN-B3043-1F773D-K4"
  state_topic: "GN-B3043-1F773D/state/K4"
  command_topic: "GN-B3043-1F773D/set/K4"
  unique_id: "32b33778a2614be0a3290f81afdeabac"
  payload_on: "1"
  payload_off: "0"
  state_on: "1"
  state_off: "0"
  optimistic: false
  qos: 0
  retain: false


程序源码 EPS8266_4chazuo__595_V1.8_WEB_202205012_OTA__.rar



#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <WiFiUdp.h>
#include <WiFiManager.h>
#include <EEPROM.h>
#include <PubSubClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>


Ticker flipper;//定义定时器


//#define PIN_POWER 4           //指示灯位于GPIO4  
#define PIN_LED 13           //指示灯位于GPIO2 
#define KEY1 0           //KEY对应值GPI14 
#define KEY2 2           //KEY对应值GPI14 
#define KEY3 4           //KEY对应值GPI14 
#define KEY4 5           //KEY对应值GPI14 




int dspin  = 16;//74HC595的14脚 数据输入引脚SI       数据
int clkpin = 12;//74hc595的11脚 时钟线 SCK          时钟
int latpin = 14;//74hc595的12脚 输出存储器锁存线RCK  锁存

String AutoRigName = "";
// 设备名  如果“Auto”则使用MAC自动生成)
String RIG_IDENTIFIER ; // EEPROM 地址 120

String K1_name = "开关1";   //开关1名称   EEPROM 地址 200
String K2_name = "开关2";   //开关2名称   EEPROM 地址 220
String K3_name = "开关3";   //开关3名称   EEPROM 地址 240
String K4_name = "开关4";   //开关4名称   EEPROM 地址 260


const char ssid[] = "*****";      //WiFi名    EEPROM 地址 140
const char pass[] = "****";   //WiFi密码   EEPROM 地址 160




ADC_MODE(ADC_VCC);//设置ADC模式为读取系统电压

int wifi_flg = 0;//WIFI状态标志   0 未连接 1 连接中  2 配网中  3 WIFI已连接  4 MQTT已连接
int power_time = 0;//倒计时关机 

int K1_flg;//定义开关1状态标志位    EEPROM 地址 101
int K2_flg;//定义开关1状态标志位    EEPROM 地址 102
int K3_flg;//定义开关1状态标志位    EEPROM 地址 103
int K4_flg;//定义开关1状态标志位    EEPROM 地址 104


int O595_1_flg = 255;//定义595 1 标志位
int O595_2_flg = 255;//定义595 1 标志位
int K1_ACflag = 2; // EEPROM 地址 181
int K2_ACflag = 2; // EEPROM 地址 182
int K3_ACflag = 2; // EEPROM 地址 183
int K4_ACflag = 2; // EEPROM 地址 184

uint32_t t=0;//按键计时



WiFiClient espClient;
PubSubClient client(espClient);

const char* mqtt_server = "*******.f3322.org";//mqtt服务地址
const char* clientID ="8266-001"; // 设备id

//WiFiUDP Udp;//实例化WiFiUDP对象
//unsigned int localUdpPort = 4321;  // 自定义本地监听端口
//unsigned int remoteUdpPort = 8629;  // 自定义远程监听端口
//char incomingPacket[255];  // 保存Udp工具发过来的消息
//char  replyPacket[] = "Hi, this is esp8266\n";  //发送的消息,仅支持英文


void callback(char *topic, byte* payload, unsigned int length); //回调函数声明,用于传入mqtt客户端构造函数作为参数
//void write_String(int a,String str);//EEPROM写字符串

//参数: MQTT服务器地址,端口号,回调函数名,承载的连接(WIFI)
PubSubClient mqttClient(mqtt_server, 1833, callback, espClient);
ESP8266WebServer server(80);
ESP8266HTTPUpdateServer httpUpdater;

//变量常量定义:
String postForms() 
{
  String htmlCode = "<!DOCTYPE html><html>\n";
   htmlCode += "<head>\n";
   htmlCode += "<title>GN-B3034智能插座</title>\n";
   htmlCode += "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n";
   htmlCode += "<meta name='viewport' content='width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'/>\n";
   htmlCode += "<style>\n";
   htmlCode += "body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\n";
   htmlCode += "</style>\n";
   htmlCode += "</head>\n";
   htmlCode += "<body>\n";
  htmlCode += "<h1>GN-B3034智能插座控制页面</h1><br>\n";
    htmlCode += "<h3>请输入0或1控制开关</h3><br>\n";
    htmlCode += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/\">\n";
      htmlCode += "    0为关,1为开  <br>\n";
      htmlCode += "开关1<input type=\"text\" name=\"K1_power\" value= \"";
      htmlCode += K1_flg;
      htmlCode += "\" size=\"5\" initial-scale = 2.0 autocomplete=\"off\">(";
      htmlCode += K1_name;
      htmlCode += ")<br>\n";
      htmlCode += "开关2<input type=\"text\" name=\"K2_power\" value= \"";
      htmlCode += K2_flg;
      htmlCode += "\" size=\"5\" initial-scale = 2.0 autocomplete=\"off\">(";
      htmlCode += K2_name;
      htmlCode += ")<br>\n";
      htmlCode += "开关3<input type=\"text\" name=\"K3_power\" value= \"";
      htmlCode += K3_flg;
      htmlCode += "\" size=\"5\" initial-scale = 2.0 autocomplete=\"off\">(";
      htmlCode += K3_name;
      htmlCode += ")<br>\n";
      htmlCode += "开关4<input type=\"text\" name=\"K4_power\" value= \"";
      htmlCode += K4_flg;
      htmlCode += "\" size=\"5\" initial-scale = 2.0 autocomplete=\"off\">(";
      htmlCode += K4_name;
      htmlCode += ")<br>\n";     
      htmlCode += "<input type=\"submit\" value=\"应用\"></form><hr>\n";
      htmlCode += "<h3>系统参数设</h3>\n";
      htmlCode += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/\">\n";
      htmlCode += "网络名称<input type=\"text\" name=\"network_name\" value= \"0\" size=\"20\" initial-scale = 2.0 autocomplete=\"off\">\n";
      htmlCode += "\n";
    htmlCode += "<input type=\"submit\" value=\"修改\">\n";
    htmlCode += "</form>\n";
    htmlCode += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/\">\n";   
    htmlCode += "网络密码<input type=\"text\" name=\"network_password\" value= \"0\" size=\"20\" initial-scale = 2.0 autocomplete=\"off\">\n";
    htmlCode += "<input type=\"submit\" value=\"修改\"></form>\n";
    htmlCode += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/\">\n";    
    htmlCode += "设备名称<input type=\"text\" name=\"RIG_IDENTIFIER\" value= \"";
      htmlCode +=read_String(120);
      htmlCode += "\" size=\"20\" initial-scale = 2.0 autocomplete=\"off\">\n";
htmlCode += "<input type=\"submit\" value=\"修改\">(为Auto时系统自动生成)</form>\n";
htmlCode += "<p>上电开关状态(关闭/开启/保持上次)\n";
htmlCode += "<p> 开关1 | 开关2 | 开关3 | 开关4<br>\n";
htmlCode += "<form name=\"form1\" method=\"post\" action=\"\">\n";
htmlCode += "<label for=\"ACflag\"></label>\n";
htmlCode += "<select name=\"K1_ACflag\" id=\"K1_ACflag\">\n";
htmlCode += "<option value=\"0\"";
if(K1_ACflag == 0){htmlCode += " selected=\"selected\"";}
htmlCode += ">关闭</option>\n";
htmlCode += "<option value=\"1\"";
if(K1_ACflag == 1){htmlCode += " selected=\"selected\"";}
htmlCode += ">开启</option>\n";
htmlCode += "<option value=\"2\"";
if(K1_ACflag == 2){htmlCode += " selected=\"selected\"";}
htmlCode += ">不变</option>\n";
htmlCode += "</select>\n";
htmlCode += "<select name=\"K2_ACflag\" id=\"K2_ACflag\">\n";
htmlCode += "<option value=\"0\"";
if(K2_ACflag == 0){htmlCode += " selected=\"selected\"";}
htmlCode += ">关闭</option>\n";
htmlCode += "<option value=\"1\"";
if(K2_ACflag == 1){htmlCode += " selected=\"selected\"";}
htmlCode += ">开启</option>\n";
htmlCode += "<option value=\"2\"";
if(K2_ACflag == 2){htmlCode += " selected=\"selected\"";}
htmlCode += ">不变</option>\n";
htmlCode += "</select>\n";
htmlCode += "<select name=\"K3_ACflag\" id=\"K3_ACflag\">\n";
htmlCode += "<option value=\"0\"";
if(K3_ACflag == 0){htmlCode += " selected=\"selected\"";}
htmlCode += ">关闭</option>\n";
htmlCode += "<option value=\"1\"";
if(K3_ACflag == 1){htmlCode += " selected=\"selected\"";}
htmlCode += ">开启</option>\n";
htmlCode += "<option value=\"2\"";
if(K3_ACflag == 2){htmlCode += " selected=\"selected\"";}
htmlCode += ">不变</option>\n";
htmlCode += "</select>\n";
htmlCode += "<select name=\"K4_ACflag\" id=\"K4_ACflag\">\n";
htmlCode += "<option value=\"0\"";
if(K4_ACflag == 0){htmlCode += " selected=\"selected\"";}
htmlCode += ">关闭</option>\n";
htmlCode += "<option value=\"1\"";
if(K4_ACflag == 1){htmlCode += " selected=\"selected\"";}
htmlCode += ">开启</option>\n";
htmlCode += "<option value=\"2\"";
if(K4_ACflag == 2){htmlCode += " selected=\"selected\"";}
htmlCode += ">不变</option>\n";      
htmlCode += "</select>\n";
htmlCode += "<input type=\"submit\" value=\"应用\"></form>\n";
htmlCode += "<p>\n";     
htmlCode += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/\">\n";
htmlCode += "开关1名称<input type=\"text\" name=\"K1_name\" value= \"";
htmlCode += K1_name;
      htmlCode += "\" size=\"20\" initial-scale = 2.0 autocomplete=\"off\">\n";
htmlCode += "<input type=\"submit\" value=\"修改\"></form>\n";
htmlCode += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/\">\n";   
htmlCode += "开关2名称<input type=\"text\" name=\"K2_name\" value= \"";
htmlCode += K2_name;
      htmlCode += "\" size=\"20\" initial-scale = 2.0 autocomplete=\"off\">\n";
htmlCode += "<input type=\"submit\" value=\"修改\"></form>\n";
htmlCode += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/\">\n";    
htmlCode += "开关3名称<input type=\"text\" name=\"K3_name\" value= \"";
htmlCode += K3_name;
      htmlCode += "\" size=\"20\" initial-scale = 2.0 autocomplete=\"off\">\n";
htmlCode += "<input type=\"submit\" value=\"修改\"></form>\n";
htmlCode += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/\">\n";    
htmlCode += "开关4名称<input type=\"text\" name=\"K4_name\" value= \"";
htmlCode += K4_name;
      htmlCode += "\" size=\"20\" initial-scale = 2.0 autocomplete=\"off\">\n";
htmlCode += "<input type=\"submit\" value=\"修改\"></form>\n";                   
htmlCode += "<p>\n";      
htmlCode += "<p>power by <a href=\"http://zhigao5191.com\">zhigao</a> 设备名称:";
htmlCode += RIG_IDENTIFIER;
htmlCode += "  设备本地IP:";
htmlCode += WiFi.localIP().toString();
htmlCode += "<br>\n";


htmlCode += "</p>\n";
htmlCode += "</body>\n";
htmlCode += "</html>\n";
return htmlCode;
}


bool autoConfig()
{
  WiFi.begin(ssid,pass);
  for (int i = 0; i < 20; i++)
  {
    int wstatus = WiFi.status();
    if (wstatus == WL_CONNECTED)
    {
      Serial.println("AutoConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      WiFi.printDiag(Serial);
      wifi_flg =3;//WIFI状态标志   0 未连接 1 连接中  2 配网中  3 已连接
      digitalWrite(PIN_LED,LOW);//初始LED灯置为低电平,HIGH表示不亮,LOW表示 亮
       WiFi.setAutoConnect(true);  // 设置自动连接
       WiFi.setAutoReconnect(true);  // 设置自动连接
        //每隔5s 翻转一下led状态,开始连网模式,慢闪
        //   flipper.attach(5, flip2); 
      //flipper.detach();//定时器停止
     // digitalWrite(PIN_LED,HIGH);//初始LED灯置为低电平,HIGH表示点亮,LOW表示点不亮 板载灯 相反
      return true;
      //break;
    }
    else
     {    
         Serial.printf("AutoConfig Waiting......",i);
         
    // Serial.printf("PSW:%s\r\n", i);
     wifi_flg =1;//WIFI状态标志   0 未连接 1 连接中  2 配网中  3 已连接
      Serial.println(wstatus);
      delay(1000);
    }
  }
  Serial.println("AutoConfig Faild!" );
  return false;
  //WiFi.printDiag(Serial);
}


void smartConfig()
{
  WiFi.mode(WIFI_STA);
  Serial.println("\r\nWait for Smartconfig");
  WiFi.beginSmartConfig();
  while (1)
  {
    Serial.print(".");
    if (WiFi.smartConfigDone())
    {
      Serial.println("SmartConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      WiFi.setAutoConnect(true);  // 设置自动连接

       //每隔0.5s 翻转一下led状态,开始连网模式,慢闪
          // flipper.attach(0.5, flip); 
      break;
    }
    delay(1000); // 这个地方一定要加延时,否则极易崩溃重启
  }
}


void rest_setting(){
             write_String(120,"Auto");
             write_String(200,"开关1");
             write_String(220,"开关2");
             write_String(240,"开关3");
             write_String(260,"开关4");
            
            EEPROM.write(181, 2);    // K1_ACflag 将整数型变量i存入EEPROM 181
            EEPROM.write(182, 2);    // K1_ACflag 将整数型变量i存入EEPROM 182
            EEPROM.write(183, 2);    // K1_ACflag 将整数型变量i存入EEPROM 183
            EEPROM.write(184, 2);    // K1_ACflag 将整数型变量i存入EEPROM 184        
            
            EEPROM.write(101, 0);    // K1_flg 将整数型变量i存入EEPROM
            EEPROM.write(102, 0);    // K2_flg 将整数型变量i存入EEPROM
            EEPROM.write(103, 0);    // K3_flg 将整数型变量i存入EEPROM
            EEPROM.write(104, 0);    // K4_flg 将整数型变量i存入EEPROM
            delay(10);
            EEPROM.commit();
             
              }


void setup()
{
  
  pinMode(PIN_LED, OUTPUT); //初始化PIN_LED引脚模式为输出
  digitalWrite(PIN_LED,HIGH);//初始LED灯置为低电平,HIGH表示亮,LOW表示不亮
  pinMode(KEY1, INPUT);//初始化KEY 按键模式为输入
  digitalWrite(KEY1,HIGH);//初始KEY灯置为高电平  
  pinMode(KEY2, INPUT);//初始化KEY 按键模式为输入
  digitalWrite(KEY2,HIGH);//初始KEY灯置为高电平  
  pinMode(KEY3, INPUT);//初始化KEY 按键模式为输入
  digitalWrite(KEY3,HIGH);//初始KEY灯置为高电平  
  pinMode(KEY4, INPUT);//初始化KEY 按键模式为输入
  digitalWrite(KEY4,HIGH);//初始KEY灯置为高电平  
  
  pinMode(dspin, OUTPUT); //数据
  pinMode(clkpin, OUTPUT);//时钟
  pinMode(latpin, OUTPUT);//锁存
  digitalWrite(dspin, LOW);// 
  
  Serial.begin(115200);
  Serial.println("power OPEN");
    
  EEPROM_load();//载入EEPROM设置参数
  LED_setup();//LED状态改变
  OUT595();//595输出状态
  delay(100);  


  
  if(K1_ACflag !=2 ){//状态为2保持上次,否则 根据K1_ACflag状态
                   K1_flg=K1_ACflag;
                   EEPROM.write(101, K1_flg);    // 将整数型变量i存入EEPROM
                   delay(10);
                   EEPROM.commit();
                   }
  K_change(1 , K1_flg);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关 
  delay(50);
  
  if(K2_ACflag !=2 ){//状态为2保持上次,否则 根据K1_ACflag状态
                   K2_flg=K2_ACflag;
                   EEPROM.write(102, K2_flg);    // 将整数型变量i存入EEPROM
                   delay(10);
                   EEPROM.commit();
                   }      
  K_change(2 , K2_flg);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关  
  delay(50);
  
 if(K3_ACflag !=2 ){//状态为2保持上次,否则 根据K1_ACflag状态
                   K3_flg=K3_ACflag;
                   EEPROM.write(103, K3_flg);    // 将整数型变量i存入EEPROM
                   delay(10);
                   EEPROM.commit();
                   }   
  K_change(3 , K3_flg);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关 
  delay(50);
     
  if(K4_ACflag !=2 ){//状态为2保持上次,否则 根据K1_ACflag状态
                   K4_flg=K4_ACflag;
                   EEPROM.write(104, K4_flg);    // 将整数型变量i存入EEPROM
                   delay(10);
                   EEPROM.commit();
                   } 
  K_change(4 , K4_flg);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关
  delay(50); 
   
   Serial.printf("K1_flg:%d\r\n", K1_flg);
   Serial.printf("K2_flg:%d\r\n", K2_flg);
   Serial.printf("K3_flg:%d\r\n", K3_flg);
   Serial.printf("K4_flg:%d\r\n", K4_flg);
   Serial.printf("K1_ACflg:%d\r\n", K1_ACflag);
   Serial.printf("K2_ACflg:%d\r\n", K2_ACflag);
   Serial.printf("K3_ACflg:%d\r\n", K3_ACflag);
   Serial.printf("K4_ACflg:%d\r\n", K4_ACflag);
   Serial.println(read_String(200));
   Serial.println(read_String(220));
   Serial.println(read_String(240));
   Serial.println(read_String(260));
      

     if(digitalRead(KEY4)==LOW){       
                 rest_setting();
                  //LED闪3次
//                  led_ms(500);
                  delay(500);
//                  led_ms(500);
                  delay(500);
//                  led_ms(500);
                  Serial.println("重置设备名称");     
                                }

  //生成设备名称-------------------  
 
  if( RIG_IDENTIFIER.indexOf("Auto")!=-1 ){ //如果名称为AUTO则自动生成ID
     String chipID = ""; //硬件ID
     String chipID2 = ""; //硬件ID
    chipID = String(ESP.getChipId(), HEX);      
    chipID2 = "GN-B3043-" + chipID;
    chipID2.toUpperCase();   
    RIG_IDENTIFIER = chipID2;  
   }
   Serial.print("AUTO_RIG_IDENTIFIER:");
   Serial.println(RIG_IDENTIFIER);
   
   //flipper.attach(5, flip); // 1秒内步中断一次
  //每隔3s 翻转一下led状态,开始连网模式,慢闪
        //   flipper.attach(0.5, flip); 

  
  if (!autoConfig())
  {
    Serial.println("Start module");
 
  //每隔0.1s 翻转一下led状态,开始连网模式,慢闪
           //flipper.attach(0.3, flip); 
    
   // smartConfig(); //airkis配网
    
      if((digitalRead(KEY2)==LOW)&&(digitalRead(KEY3)==LOW)){
                //----------------------WIFIMANAGER配网-----------
      ESP.wdtFeed(); //喂狗
    // 建立WiFiManager对象
    WiFiManager wifiManager;
    
    // 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
    wifiManager.autoConnect(RIG_IDENTIFIER.c_str(), "12345678");
  
    // 如果您希望该WiFi添加密码,可以使用以下语句:
    // wifiManager.autoConnect("AutoConnectAP", "12345678");
    // 以上语句中的12345678是连接AutoConnectAP的密码
    Serial.println();
    Serial.println("WiFi Connected!");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());                    
                                                          }      
 }

  //连接成功,打印WIFI信息
  Serial.println("");
  Serial.println("WIFI SmartConfig Success");
  Serial.printf("SSID:%s", WiFi.SSID().c_str());
  Serial.printf(", PSW:%s\r\n", WiFi.psk().c_str());
  Serial.print("LocalIP:");
  Serial.print(WiFi.localIP());
  Serial.print(" ,GateIP:");
  Serial.println(WiFi.gatewayIP());
  //wifi_flg =3;//WIFI状态标志   0 未连接 1 连接中  2 配网中  3 已连接

  //digitalWrite(PIN_LED,HIGH);//初始LED灯置为低电平,HIGH表示不亮,LOW表示 亮
  
   // EEPROM.begin(64);
   // EEPROM.get(50, remoteUdpPort);    // 将整数型变量i存入EEPROM
   // Serial.printf("RearUdpPort:%d\r\n", remoteUdpPort);
   // delay(10);
   // Udp.beginPacket("255.255.255.255", remoteUdpPort);//配置远端ip地址和端口

   //flipper.attach(10, flip); 
   
    //reconnect();//重连

       
 
     //void ICACHE_FLASH_ATTR user_init(void);   //gpio初始化

 // client.setServer(mqtt_server,1883);
 // client.setCallback(callback);

   if(wifi_flg == 3){
        client.setServer(mqtt_server,1883);
        client.setCallback(callback);

        
        httpUpdater.setup(&server);   
        server.on("/", handleRoot);
        server.begin();
        Serial.println("HTTP server started");           
         reconnect();//重连             
                    }
 
}

//设置反馈 MQTT回调处理
void callback(char* topic,byte* payload, unsigned int length){
 // Serial.print("Message arrived ["); Serial.print(topic);   Serial.print("] ");
  int set_int; 
  String set_str = "";
  String topic2 = topic;

  
 
  for (int i = 0; i < length; i++) {
   set_str += (char)payload[i];    
   }  
     //Serial.println(set_str);
     set_int=set_str.toInt();
  // Serial.println("set_1");
  // Serial.println(set_1);

    
    if(topic2.indexOf("K1")!=-1){
            //Serial.println("K1_flg");
            //Serial.println(K1_flg);
     if( set_int != K1_flg){
            K1_flg = set_int;
            K_change(1 , K1_flg);
            EEPROM_save();
                         }
                             }

    if(topic2.indexOf("K2")!=-1){
            //Serial.println("K1_flg");
            //Serial.println(K1_flg);
     if( set_int != K2_flg){
            K2_flg = set_int;
            K_change(2 , K2_flg);
            EEPROM_save();
                         }
                             }
    if(topic2.indexOf("K3")!=-1){
            //Serial.println("K1_flg");
            //Serial.println(K1_flg);
     if( set_int != K3_flg){
            K3_flg = set_int;
            K_change(3 , K3_flg);
            EEPROM_save();
                         }
                             }
     if(topic2.indexOf("K4")!=-1){
            //Serial.println("K1_flg");
           // Serial.println(K1_flg);
     if( set_int != K4_flg){
            K4_flg = set_int;
            K_change(4 , K4_flg);
            EEPROM_save();
                         }
                             }  
     
                                           
   Serial.println(topic2);   
   Serial.println(set_str);   
                                                       
   
  }




void reconnect() {
  // 循环重新连接,直到连上
     //链接MQTT服务器
    
    
     if (!client.connected()) {
    
    if (client.connect(RIG_IDENTIFIER.c_str())) {               
      Serial.println("MQTT连接成功");                 // 连接mqtt成功
     String zhuti1;     
      zhuti1=RIG_IDENTIFIER + "/set/#";

     client.subscribe(zhuti1.c_str(), 0);               // 一旦连接,订阅主题  RIG_IDENTIFIER + "/set/#"
  
      //wifi_flg = 3;//WIFI状态标志   0 未连接 1 连接中  2 配网中  3 MQTT已连接  4 MQTT连接失败
       
     
    } else {
     
      Serial.println("MQTT链接失败,4秒后重连");
              
      delay(4000);                               
    }
  }
}


//设置PIN ON 低电平
void setPinON(int pinNumber){     //0-15
       
    if (pinNumber >= 8) {

       bitClear(O595_2_flg, pinNumber-8);//n: 被设置为0的位置(右起第一位为0位,第二位为1,以此类推。)    
    }
    else
    {
     bitClear(O595_1_flg, pinNumber);
    }
  
}

//设置PIN OFF 高电平
void setPinOFF(int pinNumber){
       
    if (pinNumber >= 8) {
       bitSet(O595_2_flg, pinNumber-8);//n: 被设置为1的位置(右起第一位为0位,第二位为1,以此类推。)   
    }
    else
    {
     bitSet(O595_1_flg, pinNumber); 
    }
   
}


//改变继电器状态
void K_change(int K_Number, int change_flg){  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关

    String zhuti2;
     zhuti2=RIG_IDENTIFIER + "/state/IP";

                                 // WiFi.localIP().toString().c_str()

     client.publish(zhuti2.c_str(),WiFi.localIP().toString().c_str()); //发送主题和内容  
     if (K_Number == 1) {
             zhuti2=RIG_IDENTIFIER + "/state/K1";
             if (change_flg == 1) {
                        
                        setPinON(11);
                        setPinON(0);
                        OUT595();
                        delay(100);
                        setPinOFF(0);
                        OUT595();
                       
                        
                        client.publish(zhuti2.c_str(),"1"); //发送主题和内容
                                  }
                        else {
                        setPinOFF(11);
                        setPinON(1);
                        OUT595();
                        delay(100);
                        setPinOFF(1);
                        OUT595();  
                        client.publish(zhuti2.c_str(),"0"); //发送主题和内容                                          
                             }      
                        }

     if (K_Number == 2) {
        zhuti2=RIG_IDENTIFIER + "/state/K2";
             if (change_flg == 1) {
                        setPinON(10);
                        setPinON(2);
                        OUT595();
                        delay(100);
                        setPinOFF(2);
                        OUT595();
                        client.publish(zhuti2.c_str(),"1"); //发送主题和内容
                                  }
                        else {
                        setPinOFF(10);
                        setPinON(3);
                        OUT595();
                        delay(100);
                        setPinOFF(3);
                        OUT595();  
                        client.publish(zhuti2.c_str(),"0"); //发送主题和内容                                          
                             }      
                        }

     if (K_Number == 3) {
         zhuti2=RIG_IDENTIFIER + "/state/K3";
             if (change_flg == 1) {
                        setPinON(9);//开LED灯
                        setPinON(7);
                        OUT595();
                        delay(100);
                        setPinOFF(7);
                        OUT595();
                        client.publish(zhuti2.c_str(),"1"); //发送主题和内容
                                  }
                        else {
                        setPinOFF(9);//关LED
                        setPinON(6);
                        OUT595();
                        delay(100);
                        setPinOFF(6);
                        OUT595();  
                        client.publish(zhuti2.c_str(),"0"); //发送主题和内容                                          
                             }      
                        }

     if (K_Number == 4) {
         zhuti2=RIG_IDENTIFIER + "/state/K4";
             if (change_flg == 1) {
                        setPinON(8);
                        setPinON(5);
                        OUT595();
                        delay(100);
                        setPinOFF(5);
                        OUT595();
                        client.publish(zhuti2.c_str(),"1"); //发送主题和内容
                                  }
                        else {
                        setPinOFF(8);//关LED灯
                        setPinON(4);
                        OUT595();
                        delay(100);
                        setPinOFF(4);
                        OUT595(); 
                        client.publish(zhuti2.c_str(),"0"); //发送主题和内容                                           
                             }      
                        } 
                        
           
     }

//输出595状态
void OUT595(){
   digitalWrite(latpin, LOW);//
   shiftOut(dspin, clkpin, MSBFIRST, O595_2_flg);//串行数据输出,高位在先   
   shiftOut(dspin, clkpin, MSBFIRST, O595_1_flg);
   digitalWrite(latpin, HIGH);//锁存
}


//LED状态初始化
void LED_setup(){  

  if (K1_flg == 1) {
        setPinON(11);   
            }
        else
           {
       setPinOFF(11);  
           }
           
  if (K2_flg == 1) {
        setPinON(10);   
            }
        else
           {
       setPinOFF(10);  
           }
 
   if (K3_flg == 1) {
        setPinON(9);   
            }
        else
           {
       setPinOFF(9);  
           }  
           
   if (K4_flg == 1) {
        setPinON(8);   
            }
        else
           {
       setPinOFF(8);  
           }   
}


//载入EEPROM
void EEPROM_load(){  //载入EEPROM数据
   
     EEPROM.begin(1024);
    //EEPROM.get(10, O595_1_flg);    // 将整数型变量i从EEPROM读出
   // EEPROM.get(12, O595_2_flg);    // 将整数型变量i从EEPROM读出
     K1_flg = EEPROM.read(101);    // 将整数型变量i从EEPROM读出
     K2_flg = EEPROM.read(102);    // 将整数型变量i从EEPROM读出
     K3_flg = EEPROM.read(103);    // 将整数型变量i从EEPROM读出
     K4_flg = EEPROM.read(104);    // 将整数型变量i从EEPROM读出
     
     K1_ACflag = EEPROM.read(181);   //K1_ACflag=2; // EEPROM 地址 181
     K2_ACflag = EEPROM.read(182);   //K2_ACflag=2; // EEPROM 地址 182
     K3_ACflag = EEPROM.read(183);   //K3_ACflag=2; // EEPROM 地址 183
     K4_ACflag = EEPROM.read(184);   //K4_ACflag=2; // EEPROM 地址 184
       //EEPROM.write(101, K1_flg);    // 将整数型变量i存入EEPROM
       //EEPROM.write(102, K2_flg);    // 将整数型变量i存入EEPROM
       //EEPROM.write(103, K3_flg);    // 将整数型变量i存入EEPROM
       //EEPROM.write(104, K4_flg);    // 将整数型变量i存入EEPROM

    if(read_String(200).length() > 1){
       K1_name=read_String(200); //String K1_name="开关1" ;   //开关1名称   EEPROM 地址 200
                            }
                             else{K1_name="未设置名称";}                              
    if(read_String(220).length() > 1){
       K2_name=read_String(220); //String K1_name="开关1" ;   //开关12名称   EEPROM 地址 220
                            }
                            else{K2_name="未设置名称";} 
    if(read_String(240).length() > 1){
       K3_name=read_String(240); //String K1_name="开关1" ;   //开关3名称   EEPROM 地址 240
                            }
                            else{K3_name="未设置名称";} 
    if(read_String(260).length() > 1){
       K4_name=read_String(260); //String K1_name="开关1" ;   //开关4名称   EEPROM 地址 260
                             }
                             else{K4_name="未设置名称";} 
                                   
      RIG_IDENTIFIER = read_String(120);    // 读出设备名称,转成指针变量
      //EEPROM.get(100, RIG_IDENTIFIER);    // 读出设备名称
     
     Serial.printf("read_String:%d\r\n", RIG_IDENTIFIER);
     Serial.println(RIG_IDENTIFIER);

    
     }

//保存EEPROM
void EEPROM_save(){
     //EEPROM.begin(1024);
     //EEPROM.put(10, K_flg);    // 将整数型变量i存入EEPROM
     //EEPROM.put(12, O595_2_flg);    // 将整数型变量i存入EEPROM
     
      
       EEPROM.write(101, K1_flg);    // 将整数型变量i存入EEPROM
       EEPROM.write(102, K2_flg);    // 将整数型变量i存入EEPROM
       EEPROM.write(103, K3_flg);    // 将整数型变量i存入EEPROM
       EEPROM.write(104, K4_flg);    // 将整数型变量i存入EEPROM
    // EEPROM.put(10, K1_flg);    // 将整数型变量i存入EEPROM
    // EEPROM.put(20, K2_flg);    // 将整数型变量i存入EEPROM
     //EEPROM.put(30, K3_flg);    // 将整数型变量i存入EEPROM
    // EEPROM.put(40, K4_flg);    // 将整数型变量i存入EEPROM
     //EEPROM.put(100, "Auto");    // 保存设备名称
       //write_String(20,"Auto");
     delay(10);
     EEPROM.commit();
}



void flip() {
  //定时器函数 灯亮灭 一半时间
   reconnect();//重连
  power_time++; // get the current state of GPIO1 pin
  //int state = digitalRead(PIN_LED);  // get the current state of GPIO2 pin
 // digitalWrite(PIN_LED, !state);     // set pin to the opposite state
   Serial.println(power_time);
}







void led_ms(int i) {
  //LED亮i MS
    
   //Serial.print(" 亮");
    digitalWrite(PIN_LED,HIGH);//初始LED灯置为低电平,HIGH表示点亮,LOW表示点不亮  
    delay(i);
   //  Serial.print(" 灭");
    digitalWrite(PIN_LED,LOW);//初始LED灯置为低电平,HIGH表示点亮,LOW表示点不亮  

}





//EEPROM写字符串
void write_String(int a,String str){

  EEPROM.write(a, str.length()); 
  
  for (int i = 0; i < str.length(); i++){
    EEPROM.write(a + 1 + i, str[i]);
  }
  EEPROM.commit();
}

//EEPROM读字符串
String read_String(int a){ 
  String data = "";
  for (int i = 0; i < EEPROM.read(a); i++){
    data += char(EEPROM.read(a + 1 + i));
  }
  return data;
}



//按键检测
void KEY_TOUCH(){
  if((digitalRead(KEY1)==LOW)&&(((millis()-t)>300)||((millis()-t)<0)))
{
  t = millis(); 
  Serial.println("开关触发:1 ");
    if(K1_flg !=1)  
         {
         //setPinON(11);
         K1_flg = 1;
         K_change(1 , 1);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关         
         }
        else {
         // setPinOFF(11);
          K1_flg = 0;
          K_change(1 , 0);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关     
             }
     // OUT595();
      EEPROM_save();
}



if((digitalRead(KEY2)==LOW)&&(((millis()-t)>300)||((millis()-t)<0)))
{
  t=millis(); 
    //power_time = 0;//倒计时关机 
    Serial.println("开关触发:2");
   // Serial.println("开关触发: ");
       
        if(K2_flg !=1)  //检测到按键,计时清零
         {
        // setPinON(10);
         K2_flg = 1;
         K_change(2 , 1);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关  
         }
        else {
        //setPinOFF(10);
        K2_flg = 0;
        K_change(2 , 0);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关  
             }
     // OUT595();
      EEPROM_save();  
} 


    if((digitalRead(KEY3)==LOW)&&(digitalRead(KEY4)==LOW)&&(((millis()-t)>300)||((millis()-t)<0))){
                  t=millis(); 
                  write_String(120,"Auto");
                  //LED闪3次
                  led_ms(500);
                  delay(500);
                  led_ms(500);
                  delay(500);
                  led_ms(500);
                  Serial.println("重置设备名称");                      
                                                          }                    
            else {
              
    if((digitalRead(KEY3)==LOW)&&(((millis()-t)>300)||((millis()-t)<0)))
{
  t=millis(); 
      Serial.println("开关触发:3 ");
        if(K3_flg !=1)  //检测到按键,计时清零
         {
         //setPinON(9);
         K3_flg = 1;
         K_change(3 , 1);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关  
         }
        else {
        //setPinOFF(9);
        K3_flg = 0;
        K_change(3 , 0);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关  
             }
     // OUT595();
      EEPROM_save();  
} 

if((digitalRead(KEY4)==LOW)&&(((millis()-t)>300)||((millis()-t)<0)))
{
  t=millis(); 
       Serial.println("开关触发:4 ");
        if(K4_flg !=1)  //检测到按键,计时清零
         {
         //setPinON(8);
         K4_flg = 1;
         K_change(4 , 1);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关  
         }
        else {
        //setPinOFF(8);
        K4_flg = 0;
        K_change(4 , 0);  //开关继电器 继电器编号 1,2,3,4 改变类型 1为开 0为关  
             }
     // OUT595();
      EEPROM_save();  
}                
                }
                      
        }


void handleRoot() { //http 主页回调函数
  String message = "";
  
  for (uint8_t i = 0; i < server.args(); i++) {
  int K_IN;//网页输入参数
  String server_argName=server.argName(i);
   message += " " + server_argName + ": " + server.arg(i) + "\n";

   if(server_argName.indexOf("K1_power")!=-1){
      K_IN= (server.arg(i)).toInt();
        if (K_IN != K1_flg){
        K1_flg=K_IN;
        K_change(1 , K1_flg);
        EEPROM.write(101,K1_flg);
        delay(10);
        EEPROM.commit(); 
                       }         
                     }                                                                                                                                                                                                                                                                                                                                                                                                                      
    if(server_argName.indexOf("K2_power")!=-1){
      K_IN= (server.arg(i)).toInt();
        if (K_IN != K2_flg){
        K2_flg=K_IN;
        K_change(2 , K2_flg); 
        EEPROM.write(102,K2_flg);
        delay(10);
        EEPROM.commit();
                       }         
                     } 
    if(server_argName.indexOf("K3_power")!=-1){
      K_IN= (server.arg(i)).toInt();
        if (K_IN != K3_flg){
        K3_flg=K_IN;
        K_change(3 , K3_flg);
        EEPROM.write(103,K3_flg);
        delay(10);
        EEPROM.commit(); 
                       }         
                     } 
   if(server_argName.indexOf("K4_power")!=-1){
      K_IN= (server.arg(i)).toInt();
        if (K_IN != K4_flg){
        K4_flg=K_IN;
        K_change(4 , K4_flg);
        EEPROM.write(104,K4_flg);
        delay(10);
        EEPROM.commit();  
                       }         
                     }
    
    if(server_argName.indexOf("RIG_IDENTIFIER")!=-1){    
                      write_String(120,server.arg(i));
                      delay(10);
                      EEPROM.commit();
                                           }
     if(server_argName.indexOf("K1_ACflag")!=-1){ 
                      K1_ACflag = (server.arg(i)).toInt(); 
                      EEPROM.write(181,K1_ACflag);
                      delay(10);
                      EEPROM.commit();
                                           }
     if(server_argName.indexOf("K2_ACflag")!=-1){ 
                      K2_ACflag = (server.arg(i)).toInt(); 
                      EEPROM.write(182,K2_ACflag);
                      delay(10);
                      EEPROM.commit();
                                           }
     if(server_argName.indexOf("K3_ACflag")!=-1){ 
                      K3_ACflag = (server.arg(i)).toInt(); 
                      EEPROM.write(183,K3_ACflag);
                      delay(10);
                      EEPROM.commit();
                                           }                                          
     if(server_argName.indexOf("K4_ACflag")!=-1){ 
                      K4_ACflag = (server.arg(i)).toInt(); 
                      EEPROM.write(184,K4_ACflag);
                      delay(10);
                      EEPROM.commit();
                                           }
     if(server_argName.indexOf("K1_name")!=-1){    
                      K1_name=server.arg(i);
                      write_String(200,K1_name);
                                           }
     if(server_argName.indexOf("K2_name")!=-1){ 
                       K2_name=server.arg(i); 
                      write_String(220,K2_name);
                                           }
     if(server_argName.indexOf("K3_name")!=-1){
                      K3_name=server.arg(i);    
                      write_String(240,K3_name);
                                           }
     if(server_argName.indexOf("K4_name")!=-1){ 
                      K4_name=server.arg(i);   
                      write_String(260,K4_name);                
                                          } 
       //Serial.println(server_argName);
       //Serial.println(server.arg(i));                                   
                }
  if(message.indexOf("post")!=-1){
    
                                  }
   
                                    
                      
   delay(500);// 延时0.5秒                   
  
   server.send(200, "text/html", postForms());

}




void loop() {


    SendData();// 串口命令控制
    
   if (WiFi.status() != WL_CONNECTED){
       wifi_flg =0;//WIFI状态标志   0 未连接 1 连接中  2 配网中  3 已连接
                   }   

   if (WiFi.status() == WL_CONNECTED){
       wifi_flg =3;//WIFI状态标志   0 未连接 1 连接中  2 配网中  3 已连接
                   }  

   
  if(power_time >= 120)  //空闲大于等于 120*5 10分钟 自动关机
    {    
    digitalWrite(PIN_LED,HIGH);//HIGH表示高电平,LOW表示低电平 电源打开
     //Serial.println("空闲时间到");    
    }
   
  if(power_time >= 110)  //空闲大于等于 110*5 550秒 LED闪烁提示
    {   
    led_ms(300);//亮灯xxxMS    
    delay(5000);// 延时3秒 
    }

 //  Serial.print("ESP8266当前系统电压(mV): ");
   // Serial.println(ESP.getVcc());
    
    KEY_TOUCH();//按键检测程序
    ESP.wdtFeed(); //喂狗
   
    if(wifi_flg == 3){
    if(!client.connected()){ //MQTT重连
    reconnect();
             } 
    client.loop(); //MQTT 回调
    server.handleClient();   //HTTP 回调  
                   }
   //Serial.println(wifi_flg);
                
  }


  • No Comments Yet

添加新评论 »

captcha