esp8266网页配置wifi 及Blinker秘钥,实现远程开灯-Arduino中文社区 - Powered by Discuz! Archiver

xiaomadema 发表于 2021-8-2 12:14

esp8266网页配置wifi 及Blinker秘钥,实现远程开灯

经过一段时间的学习借鉴,写了一段可以web配网,配Blinker秘钥的程序,借鉴很多大佬,从零开始一步一步慢慢琢磨,还有很多不完善的还希望大家多多指正!
首先要感谢以下大佬,程序主要借鉴他们的程序,稍加改动,从中学到很多
远程点灯的教程已经有很多,但是每个设备烧些之前都要改一下blinker的秘钥很麻烦,通过本程序就可以统一烧录,web配置秘钥,省掉很多麻烦。

==================感谢以下大佬的教程及代码=========================
csdn // perseverance52 //至强ESP8266Web配网,利用FS闪存文件系统+EEPROM双重记录配网信息和其他相关参数设定
太极创客 // http://www.taichi-maker.com/   //物联网零基础教程
点灯科技 //https://www.diandeng.tech/home
单片机菜鸟 // 深入学习 esp8266 wifimanager源码解析(打造专属自己的web配网)
哔哩哔哩//提供学习平台
阳阳学编程 //https://www.feiyangkeji.com/

代码开源,希望大家多指正,提供宝贵意见,共同研究学习
===========================================================

==============================
需要用到的材料有以下
esp8266-esp01
继电器
烧写器
220变5伏变压器

================================
连接图

===============================

代码如下,我已经打包,代码单独不能运行,缺少data文件,我一并打包上传

=============================代码有多余的参数并未删除,不影响执行===================================
#include <ESP8266WiFi.h>
#define BLINKER_ALIGENIE_LIGHT //天猫精灵
#define BLINKER_MIOT_LIGHT   //设置小爱同学控制为语音控制灯设备
#define BLINKER_DUEROS_LIGHT //设置小度灯类库
#define BLINKER_WIFI      //blinker库不调用该库可能出现编译失败问题
#define BLINKER_MQTT    //blinker库不调用该库可能出现app不上线问题
#include <ESP8266WebServer.h>
#include <FS.h> //闪存文件系统
#include <ArduinoJson.h>//json数据处理库(第三方)
#include <Blinker.h>

String ssid, password, location0, apikey0;//定义blinker用到的参数
int pinRelay = 0;//定义输出端口号 IO0号端口


BlinkerButton Button1("btn-abc");//在点灯科技app里面新建一个开关按钮 名字命名为btn-abc
BlinkerNumber Number1("num-abc");//在点灯科技app里面新建一个开关按钮 名字命名为num-abc 显示文本1:信号强度单位:db

ESP8266WebServer server(80); //创建Web服务端口为80
IPAddress apIP(192, 168, 4, 1);//esp8266-AP-IP地址


void setup() {
pinMode(pinRelay, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(pinRelay, HIGH);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);//blinker的调试状态回显
BLINKER_DEBUG.debugAll();
peiwang();
Blinker.attachHeartbeat(heartbeat);//心跳包
Button1.attach(button1_callback); //绑定按键执行回调函数
BlinkerDuerOS.attachPowerState(duerPowerState); //小度语音操作注册函数
BlinkerMIOT.attachPowerState(miotPowerState); //小爱语音操作注册函数
BlinkerAliGenie.attachPowerState(aligeniePowerState);//天猫语音操作注册函数
}



void peiwang() {

if (SPIFFS.begin()) {   // 打开闪存文件系统
    Serial.println("");
    Serial.println("闪存文件系统打开成功");
}
else {
    Serial.println("");
    Serial.println("闪存文件系统打开失败");
}

if (SPIFFS.exists("/config.json"))   // exists 判断有没有config.json这个文件
{
    Serial.println("存在配置信息,正在自动连接");

    const size_t capacity = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + 156; //分配一个内存空间
    DynamicJsonDocument doc(capacity);// 声明json处理对象

    File configJson = SPIFFS.open("/config.json", "r");
    deserializeJson(doc, configJson); // json数据序列化
    const char* ssid = doc["ssid"];            Serial.println(ssid);
    const char* password = doc["password"];    Serial.println(password);
    const char* location = doc["location0"];   Serial.println(location);
    const char* apikey = doc["apikey0"];       Serial.println(apikey);

    WiFi.mode(WIFI_STA); // 更换wifi模式      //WiFi.mode(WIFI_AP_STA);//设置模式为AP+STA
    Serial.println("开始联网!");
    Blinker.begin(location, ssid, password);
    int s = 1;
    while (!Blinker.connect()) {
      digitalWrite(LED_BUILTIN, HIGH);
      delay(500);
      digitalWrite(LED_BUILTIN, LOW);
      delay(500);
      Serial.println(s++);
      if (s > 10) {
      Serial.println("联网失败!重新配网");
      peiwang1();
      removeConfig();
      break;
      }
    }
    if (Blinker.connect() == 1) {
      Serial.println("联网成功!");
      digitalWrite(LED_BUILTIN, LOW);
      Serial.println("获取的IP地址:");
      Serial.println(WiFi.localIP());
      configJson.close();//关闭缓存
    }
}
else {
    Serial.println("不存在配置信息,正在打开web配网模式");
    peiwang1();
}
}

void peiwang1() {
WiFi.mode(WIFI_AP);
WiFi.softAP("智能开关配网"); //这里是配网模式下热点的名字和密码,热点配网。
Serial.println(WiFi.softAPIP());
server.on("/", handleRoot);//web首页监听
server.on("/set", handleConnect); // 配置ssid密码监听,感觉跟express的路由好像
server.begin();
}

void loop() {
server.handleClient();
KeySwitch();
Blinker.run();
}

void handleRoot() { //展示网页的关键代码
if (SPIFFS.exists("/index.html")) {//先判断文件系统中是否有文件
    File index = SPIFFS.open("/index.html", "r");//打开文件
    Serial.println("发现网页!");
    server.streamFile(index, "text/html");//发送响应信息
    index.close();
} else {
    Serial.println("网页不存在!");
}
}

void handleConnect() { //处理配置信息的函数
ssid = server.arg("ssid");   //arg是获取请求参数
password = server.arg("password");
location0 = server.arg("location"); //从JavaScript发送的数据中找laction的值
apikey0 = server.arg("apikey"); //从JavaScript发送的数据中找apikey的值
server.send(200, "text/html", "<meta charset='UTF-8'>保存成功");
delay(500);//等待保存成功回显时间
Blinker.begin(location0.c_str(), ssid.c_str(), password.c_str());
int a = 0;
while (!Blinker.connect()) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    Serial.println(a++);
    Blinker.run();
    if (a > 20) {
      Serial.println("重启esp8266配网!");
      delay(50);
      ESP.restart();
    }
}
Serial.println("联网成功!");
digitalWrite(LED_BUILTIN, LOW);
Serial.println("获取的IP地址:");
Serial.println(WiFi.localIP());
removeConfig(); // 不管有没有配置先删除一次再说。
String payload; // 拼接构造一段字符串形式的json数据长{"ssid":"xxxxx","password":"xxxxxxxxxxx","location0":"xxxx","apikey0":"xxxx"}
payload += "{\"ssid\":\"";
payload += ssid;
payload += "\",\"password\":\"";
payload += password;
payload += "\",\"location0\":\"";
payload += location0;
payload += "\",\"apikey0\":\"";
payload += apikey0;
payload += "\"}";
File wifiConfig = SPIFFS.open("/config.json", "w");
wifiConfig.println(payload);//将数据写入config.json文件中
Serial.println("配置文件写入成功!");
wifiConfig.close();
}


void removeConfig() {//移除缓存中配置信息文件
if (SPIFFS.exists("/config.json")) { // 判断有没有config.json这个文件
    if (SPIFFS.remove("/config.json")) {
      Serial.println("删除旧配置");
    }
    else {
      Serial.println("删除旧配置失败");
    }
}
}


void KeySwitch()   //机械开关动作判断
{
delay(500);
static bool is_btn = digitalRead(LED_BUILTIN);//按钮的标志位,用来逻辑处理对比,判断按钮有没有改变状态
bool is = digitalRead(LED_BUILTIN);   //按钮状态
if ( is != is_btn)
{
    bool is_led = digitalRead(pinRelay);

    digitalWrite(pinRelay, !digitalRead(pinRelay));
    if (is_led == 0)
    {
      button1_callback(BLINKER_CMD_OFF);
    }
    else
    {
      button1_callback(BLINKER_CMD_ON);
    }
    is_btn = digitalRead(LED_BUILTIN);//更新按钮状态
}   
}

// 按下按键即会执行该函数
void button1_callback(const String & state) //按钮回调函数
{
BLINKER_LOG("get button state:", state); //获取按钮状态 写进字符串
if (state == "on")                      //如果按钮状态为开
{
    digitalWrite(pinRelay, LOW);         //继电器给低电平
    // 反馈开关状态
    kaideng();
}
else if (state == "off")               //如果按钮状态为关
{
    // 反馈开关状态
    digitalWrite(pinRelay, HIGH);       //继电器给高电平
    guandeng();
}
}


void kaideng() {
Button1.print("on");       //把按钮状态更改为开
Button1.icon("fas fa-lightbulb");
Button1.color("#000000");
Button1.text("已经关灯");
Number1.print(100-abs(WiFi.RSSI()));//信号强度
}


void guandeng() {
Button1.print("off");               //把按钮状态更改为关
Button1.icon("fas fa-lightbulb");
Button1.color("#fddb00");
Button1.text("已经开灯");
Number1.print(100-abs(WiFi.RSSI()));//信号强度
}

void heartbeat()//心跳包
{
Button1.icon("fas fa-lightbulb");
Number1.print(100-abs(WiFi.RSSI()));//信号强度
}
//天猫精灵
void aligeniePowerState(const String & state)
{
BLINKER_LOG("need set power state: ", state);
if (state == BLINKER_CMD_ON)
{
    digitalWrite(pinRelay, LOW);
    BlinkerAliGenie.powerState("off");
    BlinkerAliGenie.print();
    kaideng();
}
else if (state == BLINKER_CMD_OFF) {
    digitalWrite(pinRelay, HIGH);
    BlinkerAliGenie.powerState("off");
    BlinkerAliGenie.print();
    guandeng();
}
}

//小爱电源类回调
void miotPowerState(const String & state)
{
BLINKER_LOG("need set power state: ", state);
if (state == BLINKER_CMD_ON) {
    BlinkerMIOT.powerState("on");
    BlinkerMIOT.print();
    kaideng();

}
else if (state == BLINKER_CMD_OFF) {
    BlinkerMIOT.powerState("off");
    BlinkerMIOT.print();
    guandeng();

}
}


//小度电源类回调
void duerPowerState(const String & state)
{
BLINKER_LOG("need set power state: ", state);

if (state == BLINKER_CMD_ON) {
    BlinkerDuerOS.powerState("on");
    BlinkerDuerOS.print();
    kaideng();
}
else if (state == BLINKER_CMD_OFF) {
    BlinkerDuerOS.powerState("off");
    BlinkerDuerOS.print();
    guandeng();
}
}





zjdaty 发表于 2021-9-3 21:43

#include <ESP8266WiFi.h>
#define BLINKER_ALIGENIE_LIGHT //天猫精灵
#define BLINKER_MIOT_LIGHT   //设置小爱同学控制为语音控制灯设备//kaiguan
#define BLINKER_DUEROS_LIGHT //设置小度灯类库
#define BLINKER_WIFI
#define BLINKER_MQTT
#include <ESP8266WebServer.h>
#include <FS.h> //闪存文件系统
#include <ArduinoJson.h>//json数据处理库(第三方)
#include <Blinker.h>

char auth[] = "22222222";
char ssid1[] = "2222222";//你家的WiFi名字
char pswd[] = "22222222";//你家WiFi的密码
String ssid, password, location0, apikey0;//定义blinker用到的参数
int pinRelay = 0;//定义输出端口号 IO0号端口


BlinkerButton Button1("btn-abc");//在点灯科技app里面新建一个开关按钮 名字命名为btn-abc
BlinkerButton Button2("btn-abd");
BlinkerNumber Number1("num-abc");//在点灯科技app里面新建一个开关按钮 名字命名为num-abc 显示文本1:信号强度单位:db

ESP8266WebServer server(80); //创建Web服务端口为80
IPAddress apIP(192, 168, 4, 1);//esp8266-AP-IP地址


void setup() {
pinMode(pinRelay, OUTPUT); //设置pinRelay脚为输出状态
pinMode(LED_BUILTIN, OUTPUT);//设置Led_Builtin为输出状态
digitalWrite(pinRelay, HIGH);/*输出HIGH电平,继电器模块闭合*/
digitalWrite(LED_BUILTIN, LOW);//设置Led_Builtin为低电平
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);//blinker的调试状态回显
BLINKER_DEBUG.debugAll();
peiwang();
//Blinker.begin(auth, ssid1, pswd);
Blinker.attachHeartbeat(heartbeat);//心跳包
Button1.attach(button1_callback); //绑定按键执行回调函数
Button2.attach(button2_callback);
BlinkerDuerOS.attachPowerState(duerPowerState); //小度语音操作注册函数
BlinkerMIOT.attachPowerState(miotPowerState); //小爱语音操作注册函数
BlinkerAliGenie.attachPowerState(aligeniePowerState);//天猫语音操作注册函数
button1_callback(BLINKER_CMD_OFF);
}



void peiwang() {

if (SPIFFS.begin()) {   // 打开闪存文件系统
    Serial.println("");
    Serial.println("闪存文件系统打开成功");
}
else {
    Serial.println("");
    Serial.println("闪存文件系统打开失败");
}

if (SPIFFS.exists("/config.json"))   // exists 判断有没有config.json这个文件
{
    Serial.println("存在配置信息,正在自动连接");

    const size_t capacity = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + 156; //分配一个内存空间
    DynamicJsonDocument doc(capacity);// 声明json处理对象

    File configJson = SPIFFS.open("/config.json", "r");
    deserializeJson(doc, configJson); // json数据序列化
    const char* ssid = doc["ssid"];            Serial.println(ssid);
    const char* password = doc["password"];    Serial.println(password);
    const char* location = doc["location0"];   Serial.println(location);
    const char* apikey = doc["apikey0"];       Serial.println(apikey);

    WiFi.mode(WIFI_STA); // 更换wifi模式      //WiFi.mode(WIFI_AP_STA);//设置模式为AP+STA
    Serial.println("开始联网!");
    Blinker.begin(auth, ssid, password);
    //Blinker.begin(auth, ssid1, pswd);
    int s = 1;
    while (!Blinker.connect()) {
      digitalWrite(LED_BUILTIN, HIGH);
      delay(500);
      digitalWrite(LED_BUILTIN, LOW);
      delay(500);
      Serial.println(s++);
      if (s > 10) {
      Serial.println("联网失败!重新配网");
      peiwang1();
      removeConfig();
      break;
      }
    }
    if (Blinker.connect() == 1) {
      Serial.println("联网成功!");
      digitalWrite(LED_BUILTIN, LOW);
      Serial.println("获取的IP地址:");
      Serial.println(WiFi.localIP());
      configJson.close();//关闭缓存
    }
}
else {
    Serial.println("不存在配置信息,正在打开web配网模式");
    peiwang1();
}
}

void peiwang1() {
WiFi.mode(WIFI_AP);
WiFi.softAP("智能开关配网"); //这里是配网模式下热点的名字和密码,热点配网。
Serial.println(WiFi.softAPIP());
server.on("/", handleRoot);//web首页监听
server.on("/set", handleConnect); // 配置ssid密码监听,感觉跟express的路由好像
server.begin();
}

void loop() {
server.handleClient();
KeySwitch();
Blinker.run();
}

void handleRoot() { //展示网页的关键代码
if (SPIFFS.exists("/index.html")) {//先判断文件系统中是否有文件
    File index = SPIFFS.open("/index.html", "r");//打开文件
    Serial.println("发现网页!");
    server.streamFile(index, "text/html");//发送响应信息
    index.close();
} else {
    Serial.println("网页不存在!");
}
}

void handleConnect() { //处理配置信息的函数
ssid = server.arg("ssid");   //arg是获取请求参数
password = server.arg("password");
location0 = server.arg("location"); //从JavaScript发送的数据中找laction的值
apikey0 = server.arg("apikey"); //从JavaScript发送的数据中找apikey的值
server.send(200, "text/html", "<meta charset='UTF-8'>保存成功");
delay(500);//等待保存成功回显时间
//Blinker.begin(location0.c_str(), ssid.c_str(), password.c_str());
Blinker.begin(auth, ssid.c_str(), password.c_str());
int a = 0;
while (!Blinker.connect()) {
    digitalWrite(LED_BUILTIN, HIGH);
    Blinker.delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    Blinker.delay(500);
    Serial.println(a++);
    Blinker.run();
    if (a > 20) {
      Serial.println("重启esp8266配网!");
      delay(50);
      ESP.restart();
    }
}
Serial.println("联网成功!");
digitalWrite(LED_BUILTIN, LOW);
Serial.println("获取的IP地址:");
Serial.println(WiFi.localIP());
removeConfig(); // 不管有没有配置先删除一次再说。
String payload; // 拼接构造一段字符串形式的json数据长{"ssid":"xxxxx","password":"xxxxxxxxxxx","location0":"xxxx","apikey0":"xxxx"}
payload += "{\"ssid\":\"";
payload += ssid;
payload += "\",\"password\":\"";
payload += password;
payload += "\",\"location0\":\"";
payload += location0;
payload += "\",\"apikey0\":\"";
payload += apikey0;
payload += "\"}";
File wifiConfig = SPIFFS.open("/config.json", "w");
wifiConfig.println(payload);//将数据写入config.json文件中
Serial.println("配置文件写入成功!");
wifiConfig.close();
}


void removeConfig() {//移除缓存中配置信息文件
if (SPIFFS.exists("/config.json")) { // 判断有没有config.json这个文件
    if (SPIFFS.remove("/config.json")) {
      Serial.println("删除旧配置");
    }
    else {
      Serial.println("删除旧配置失败");
    }
}
}


void KeySwitch()   //机械开关动作判断
{
//Blinker.delay(500);
static bool is_btn = digitalRead(LED_BUILTIN);//按钮的标志位,用来逻辑处理对比,判断按钮有没有改变状态
bool is = digitalRead(LED_BUILTIN);   //按钮状态
if ( is != is_btn)
{
    bool is_led = digitalRead(pinRelay);

    digitalWrite(pinRelay, !digitalRead(pinRelay));
    if (is_led == 0)
    {
      button1_callback(BLINKER_CMD_OFF);
    }
    else
    {
      button1_callback(BLINKER_CMD_ON);
    }
    is_btn = digitalRead(LED_BUILTIN);//更新按钮状态
}
}

// 按下按键即会执行该函数
void button1_callback(const String & state) //按钮回调函数
{
BLINKER_LOG("get button state:", state); //获取按钮状态
//digitalWrite(pinRelay, !digitalRead(pinRelay));

if (state == BLINKER_CMD_ON)                      //如果按钮状态为开
{
    digitalWrite(pinRelay, LOW);         //低电平,继电器吸合
    kaideng();
   
    //开灯
}
else if (state == BLINKER_CMD_OFF)               //如果按钮状态为关
{
    // 反馈开关状态
    digitalWrite(pinRelay, HIGH);       //高电平,继电器断开
    guandeng();
   //关灯
}

Blinker.delay(20);
Blinker.vibrate();
}

// 按下按键即会重新配网
void button2_callback(const String & state) //按钮回调函数
{
    Serial.println("重启esp8266配网!");
    removeConfig();
    peiwang();

}

void kaideng() {


Button1.icon("fas fa-lightbulb");
Button1.color("#fddb00");
Button1.text("已经开灯");
Button1.print("on");       //把按钮状态更改为开
Number1.print(100 - abs(WiFi.RSSI())); //信号强度
}


void guandeng() {

Button1.icon("fas fa-lightbulb");
Button1.color("#000000");
Button1.text("已经关灯");
Button1.print("off");               //把按钮状态更改为关
Number1.print(100 - abs(WiFi.RSSI())); //信号强度
}

void heartbeat()//心跳包
{

if (digitalRead(pinRelay) == HIGH)
{
   
    Button1.icon("fas fa-lightbulb");
    Button1.color("#000000");
    Button1.text("已经关灯");
    Button1.print("off");       //把按钮状态更改为关

}
else if (digitalRead(pinRelay) == LOW)
{
   
    Button1.icon("fas fa-lightbulb");
    Button1.color("#fddb00");
    Button1.text("已经开灯");
    Button1.print("on");               //把按钮状态更改为开
}

//Button1.icon("fas fa-lightbulb");
Number1.print(100 - abs(WiFi.RSSI())); //信号强度
}
//天猫精灵
void aligeniePowerState(const String & state)
{
BLINKER_LOG("need set power state: ", state);
if (state == BLINKER_CMD_ON)
{
    digitalWrite(pinRelay, LOW);
    BlinkerAliGenie.powerState("off");
    BlinkerAliGenie.print();
    kaideng();
}
else if (state == BLINKER_CMD_OFF) {
    digitalWrite(pinRelay, HIGH);
    BlinkerAliGenie.powerState("off");
    BlinkerAliGenie.print();
    guandeng();
}
}

//小爱电源类回调
void miotPowerState(const String & state)
{
BLINKER_LOG("need set power state: ", state);
if (state == BLINKER_CMD_ON) {
    digitalWrite(pinRelay, LOW);
    BlinkerMIOT.powerState("on");
    BlinkerMIOT.print();
    kaideng();

}
else if (state == BLINKER_CMD_OFF) {
    digitalWrite(pinRelay, HIGH);
    BlinkerMIOT.powerState("off");
    BlinkerMIOT.print();
    guandeng();

}
}


//小度电源类回调
void duerPowerState(const String & state)
{
BLINKER_LOG("need set power state: ", state);

if (state == BLINKER_CMD_ON) {
    BlinkerDuerOS.powerState("on");
    BlinkerDuerOS.print();
    kaideng();
}
else if (state == BLINKER_CMD_OFF) {
    BlinkerDuerOS.powerState("off");
    BlinkerDuerOS.print();
    guandeng();
}
}

weiqinglong51 发表于 2021-8-3 02:35

6666666666

xiaomadema 发表于 2021-8-3 13:19

loop循环中调用的delay函数这一句需要注释掉,忘记注释了,需要的非系统自带的库可以去太极创客网站看一下他们的视频教程,有很多是有教程的

原田夜吴 发表于 2021-8-3 15:13

这个是不是得要注册和风气象的账号才能活动apikey?不写这key能不能联网? 连这个是为了可以远程控制开关么?

xiaomadema 发表于 2021-8-3 16:12

代码中我把和风的那个改成blinker密钥了,还有一个apikey没有用到,配网的时候空着就可以,考虑后期还要开发天气,所以就保留了

zjdaty 发表于 2021-8-7 21:07

大佬 我想要这个上电启动的功能应该怎么修改比较好

xiaomadema 发表于 2021-8-8 20:10

blinker默认的吧?上电自动连接

s464813920 发表于 2021-8-9 00:06

折腾了一天了。示例都可以使用 论坛上复制的代码和你这个打包的代码就是一直错误
Arduino:1.8.15 (Windows 10), 开发板:"Generic ESP8266 Module, 80 MHz, Flash, Disabled (new aborts on oom), Disabled, All SSL ciphers (most compatible), 32KB cache + 32KB IRAM (balanced), Use pgm_read macros for IRAM/PROGMEM, dtr (aka nodemcu), 26 MHz, 40MHz, DOUT (compatible), 1MB (FS:64KB OTA:~470KB), 2, nonos-sdk 2.2.1+100 (190703), v2 Lower Memory, Disabled, None, Only Sketch, 115200"
webconfig:9:10: fatal error: ArduinoJson.h: No such file or directory

    9 | #include <ArduinoJson.h>//json数据处理库(第三方)

      |          ^~~~~~~~~~~~~~~

compilation terminated.

exit status 1
ArduinoJson.h: No such file or directory
在文件 -> 首选项开启
“编译过程中显示详细输出”选项
这份报告会包含更多信息。

xiaomadema 发表于 2021-8-9 09:08

需要json库第三方的库下载加压到Arduino\libraries目录里

xiaomadema 发表于 2021-8-9 21:44

普通的单开物理开关可以接上,按照图片上的接线方法,既可以物理开关打开关闭,同时也可以手机app开关,小爱同学代码有点问题,测试发现不能控制,目前测试天猫精灵没有问题,后期研究下代码.改好了再发,增加一个电动开关控制方式
页: [1] 2 3 4 5 6 7
查看完整版本: esp8266网页配置wifi 及Blinker秘钥,实现远程开灯