IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【Arduino】esp01 Relay 转接板自动ping ip断电重启 -> 正文阅读

[网络协议]【Arduino】esp01 Relay 转接板自动ping ip断电重启

找到一个RGB颜色代码的网站? ? ? ?颜色选择表

目录

创作前情

项目规划

实现过程

?软件实现

app界面如下:

arduino代码如下:

?硬件实现

后续优化


创作前情

? ? 目前使用树莓派装haos来做智能家居服务器,不知道是硬件问题还是哪里的设定问题,时不时挂掉,访问不了,需要手动断电重启,才能恢复,奈何找不到原因,本来是使用了一个米家智能插座来手动断电重启,但需要到用的时候才发现访问不了,需要进入米家重启,体验太差,所以想着如果可以有一个设备可以自己侦测是否正常,如果有问题,自动断电重启,这样会好很多。

项目规划

? ?方案一:使用esphome 来控制断电重启,最方便的一种,但目前没找到,使用esphome 来检测homeassistant是否挂掉的方法,故放弃。

? 方案二: 接入米家,继续使用米家插座来控制断电重启,也是需要先侦测到访问异常,再通过改造米家传感器接入,相对复杂,

? 方案三:借助blinker平台接入,本身使用arduino编程,相对熟悉很多,使用esp8266 ping库直接来侦测访问是否异常,点灯app可以控制断电以及各种状态,

实现过程

  • ?软件实现

? 选择方案三来做,可以在之前浇水的代码上修改来实现相关功能,目前已实现如下功能

  1. 检测访问是否正常,如果不正常则自动断电重启,
  2. app界面可以手动控制继电器状态,达到手动重启,
  3. app显示 ip地址、信号强度,异常次数,最近一次异常时间以及目前访问状态

app界面如下:

arduino代码如下:

/* *****************************************************************

   Blinker 库下载地址:
   https://github.com/blinker-iot/blinker-library/archive/master.zip

   Blinker 是一套跨硬件、跨平台的物联网解决方案,提供APP端、设备端、
   服务器端支持,使用公有云服务进行数据传输存储。可用于智能家居、
   数据监测等领域,可以帮助用户更好更快地搭建物联网项目。

   如果使用 ESP8266 接入 Blinker,
   请确保安装了 2.7.4 或更新的 ESP8266/Arduino 支持包。
   https://github.com/esp8266/Arduino/releases

   如果使用 ESP32 接入 Blinker,
   请确保安装了 1.0.5 或更新的 ESP32/Arduino 支持包。
   https://github.com/espressif/arduino-esp32/releases

   文档: https://diandeng.tech/doc


 * *****************************************************************/

#define BLINKER_WIFI

#include <Blinker.h>
#include <Pinger.h>
#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>

#include <Ticker.h>
#include <arduino-timer.h>
extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}

// Set global to avoid object removing after setup() routine
Pinger pinger;

auto timer = timer_create_default(); // create a timer with default settings
bool ip_timer_flag = true;
bool ip_app_check_flag = true;
bool ip_lost_flag = false;
bool loss_true = false;
bool otaflag = false;
uint32_t read_time = 0;
uint16_t blinker_year, error_time_final, error_time = 0;
uint8_t blinker_month, blinker_mday, blinker_wday, blinker_hour, blinker_min, blinker_sec;
uint8_t a0 = 1, a1 = 1, b0 = 1, b1 = 1, c0 = 1, c1 = 1, d0 = 0, d1 = 1;
uint16_t check_timer_time = 30, check_error_time = 8, clen_error_timer = 600;
String fh, fh0;

char auth[] = "*****************";
char ssid[] = "************";
char pswd[] = "****************";
//---------------------------------引脚配置-----------------------------
#define VCCPIN D3 // 指示灯
#define BUTTON_1 "ButtonKey"
#define BUTTON_2 "onoff"
#define BUTTON_3 "reset"
#define BUTTON_4 "status"
#define BUTTON_5 "ota"
#define TEXTE_time "tex-time"
#define RUN_time "tex-run"
#define TEXTE_ip "tex-ip"
BlinkerButton Button1(BUTTON_1);
BlinkerButton Button2(BUTTON_2);
BlinkerButton Button3(BUTTON_3);
BlinkerButton Button4(BUTTON_4);
BlinkerButton Button5(BUTTON_5);
BlinkerText Text_ip(TEXTE_ip);
BlinkerText Text_time(TEXTE_time);
BlinkerText Text_runtime(RUN_time);
BlinkerNumber Number1("num-xinhao"); // 定义信号强度键名
BlinkerNumber Number2("num-error");  // 定义信号强度键名
BlinkerNumber Number3("error");      // 定义信号强度键名

void button1_callback(const String &state)
{
    // digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    BLINKER_LOG("get button state: ", state);

    if (state == BLINKER_CMD_ON)
    {
        BLINKER_LOG("Toggle on!");
        ip_app_check_flag = true;
        a0 = 1;
        a1 = 1;
        // Button1.icon("icon_1");
        Button1.color("#FF6666");
        Button1.text("检测");
        Button1.print("on");
    }
    else if (state == BLINKER_CMD_OFF)
    {
        BLINKER_LOG("Toggle off!");
        ip_app_check_flag = false;
        a0 = 0;
        a1 = 1;
        // Button1.icon("icon_1");
        Button1.color("#FF6600");
        Button1.text("不检测");
        Button1.print("off");
    }
}

void button2_callback(const String &state)
{
    // digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    BLINKER_LOG("get button state: ", state);

    if (state == BLINKER_CMD_ON)
    {
        BLINKER_LOG("Toggle on!");
        digitalWrite(VCCPIN, LOW);
        b0 = 1;
        b1 = 1;
        Button2.color("#FF6666");
        Button2.text("打开");
        Button2.print("on");
    }
    else if (state == BLINKER_CMD_OFF)
    {
        BLINKER_LOG("Toggle off!");
        digitalWrite(VCCPIN, HIGH);
        b0 = 0;
        b1 = 1;
        Button2.color("#FF6600");
        Button2.text("关闭");
        Button2.print("off");
    }
}

void button3_callback(const String &state)
{
    // digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    BLINKER_LOG("get button state: ", state);

    if (state == BLINKER_CMD_BUTTON_TAP)
    {
        BLINKER_LOG("Button tap!");
        error_time_final = 0;
        // Button3.text("Your button name or describe");
        Button3.print();
    }
}
void button4_callback(const String &state)
{
    // digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    BLINKER_LOG("get button state: ", state);
}
void button5_callback(const String &state)
{
    BLINKER_LOG("button5_callback get button state: ", state);
    if (state == BLINKER_CMD_ON)
    {
        d0 = 1;
        d1 = 1;
        otaflag = true;
        Button5.color("#00b0FF");
        Button5.text("OTA");
        Button5.print("on");
    }
    else if (state == BLINKER_CMD_OFF)
    {
        d0 = 0;
        d1 = 1;
        otaflag = false;
        Button5.color("#607E8B");
        Button5.text("NO OTA");
        Button5.print("off");
    }
}
void heartbeat()
{
    huidiaoneirong();
}
/*********************************************************************************************************
  按键状态回调函数
*********************************************************************************************************/
void huidiaoneirong()
{
    Number1.icon("fal fa-wifi");
    Number1.print(WiFi.RSSI());
    Number2.print(error_time_final);
    Number3.print(error_time);
    Text_ip.print(WiFi.localIP().toString().c_str());
    Text_time.print(fh);
    Text_runtime.print(fh0);
    if ((a1 == 1) && (a0 == 1))
    {
        a1 = 0;
        Button1.color("#66CC66");
        Button1.text("检测");
        Button1.print("on");
    }
    else if ((a1 == 1) && (a0 == 0))
    {
        a1 = 0;
        Button1.color("#FF6600");
        Button1.text("不检测");
        Button1.print("off");
    }
    if ((b1 == 1) && (b0 == 1))
    {
        b1 = 0;
        Button2.print("on");
        Button2.color("#66CC66");
        Button2.text("供电开");
    }
    else if ((b1 == 1) && (b0 == 0))
    {
        b1 = 0;
        Button2.color("#FF6600");
        Button2.text("供电关");
        Button2.print("off");
    }
    if ((c1 == 1) && (c0 == 1))
    {
        c1 = 0;
        Button4.print("on");
        Button4.color("#66CC66");
        Button4.text("正常连接");
    }
    else if ((c1 == 1) && (c0 == 0))
    {
        c1 = 0;
        Button4.color("#FF6600");
        Button4.text("异常连接");
        Button4.print("off");
    }
    if ((d1 == 1) && (d0 == 1))
    {
        d1 = 0;
        Button5.color("#00b0FF");
        Button5.text("OTA");
        Button5.print("on");
    }
    else if ((d1 == 1) && (d0 == 0))
    {
        d1 = 0;
        Button5.color("#607E8B");
        Button5.text("NO OTA");
        Button5.print("off");
    }
}
void dataRead(const String &data)
{
    BLINKER_LOG("Blinker readString: ", data);

    Blinker.vibrate();

    uint32_t BlinkerTime = millis();

    Blinker.print("millis", BlinkerTime);
}

void setup()
{
    Serial.begin(115200);
    BLINKER_DEBUG.stream(Serial);

    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    digitalWrite(LED_BUILTIN, HIGH);
    Blinker.begin(auth, ssid, pswd);
    Blinker.attachData(dataRead);
    Blinker.attachHeartbeat(heartbeat);
    Button1.attach(button1_callback);
    Button2.attach(button2_callback);
    Button3.attach(button3_callback);
    Button4.attach(button4_callback);
    Button5.attach(button5_callback);
    pinsetup();
    ping_ip_set();
    // ota_set();
}

void loop()
{

    Blinker.run();
    get_time_now();        // 更新系统时间
    get_time_now_to_app(); // 运行时间
    checek_ip();
}
/************************
void ota_set()
{
  //  ArduinoOTA.setHostname("ESP8266");
  //  ArduinoOTA.setPassword("1234");
  ArduinoOTA.begin();
  ArduinoOTA.onStart([]() {
    //    display.clear();
    //    display.setFont(ArialMT_Plain_10);
    //    display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
    //    display.drawString(display.getWidth() / 2, display.getHeight() / 2 - 10, "OTA Update");
    //    display.display();
    Serial.println("OTA start");
  });

  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    //    display.drawProgressBar(4, 32, 120, 8, progress / (total / 100) );
    //    display.display();
    Serial.println(progress / (total / 100));
  });

  ArduinoOTA.onEnd([]() {
    //    display.clear();
    //    display.setFont(ArialMT_Plain_10);
    //    display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
    //    display.drawString(display.getWidth() / 2, display.getHeight() / 2, "Restart");
    //    display.display();
    Serial.println("OTA Restart");
  });
  Serial.println("OTA ready");
}
void otaloop() {
  ArduinoOTA.handle();
  //Serial.println("OTA start");
}
*******************************/
/*********************************************************************************************************
  获取时间
*********************************************************************************************************/
void get_time_now()
{

    blinker_year = Blinker.year();   // 年
    blinker_month = Blinker.month(); // 月
    blinker_mday = Blinker.mday();   // 日
    blinker_wday = Blinker.wday();   // 星期
    blinker_hour = Blinker.hour();   // 时
    blinker_min = Blinker.minute();  // 分
    blinker_sec = Blinker.second();  // 秒
}
/*********************************************************************************************************
  获取运行时间并用app显示
*********************************************************************************************************/
void get_time_now_to_app()
{
    String tianbl, shibl, fenbl, miaobl;
    uint8_t tian1 = 0, shi1 = 0, fen1 = 0, miao1 = 0;
    time_t run_time = Blinker.runTime();                        // 获取运行时间,单位为秒
    tian1 = run_time / 86400;                                   // 转化为天
    shi1 = (run_time - tian1 * 86400) / 3600;                   // 转化为时
    fen1 = (run_time - tian1 * 86400 - shi1 * 3600) / 60;       // 转化为分
    miao1 = run_time - tian1 * 86400 - shi1 * 3600 - fen1 * 60; // 转化为秒
    if (tian1 < 10)
    {
        tianbl = String("") + "0" + tian1;
    }
    else
    {
        tianbl = String("") + tian1;
    }
    if (shi1 < 10)
    {
        shibl = String("") + "0" + shi1;
    }
    else
    {
        shibl = String("") + shi1;
    }
    if (fen1 < 10)
    {
        fenbl = String("") + "0" + fen1;
    }
    else
    {
        fenbl = String("") + fen1;
    }
    if (miao1 < 10)
    {
        miaobl = String("") + "0" + miao1;
    }
    else
    {
        miaobl = String("") + miao1;
    }

    if (tian1 == 0 & shi1 == 0 & fen1 == 0)
    {
        fh0 = String("") + miaobl + "秒";
    }
    else if (tian1 == 0 & shi1 == 0)
    {
        fh0 = String("") + fenbl + "分" + miaobl + "秒";
    }
    else if (tian1 == 0)
    {
        fh0 = String("") + shibl + "时" + fenbl + "分" + miaobl + "秒";
    }
    else
    {
        fh0 = String("") + tianbl + "天" + shibl + "时" + fenbl + "分" + miaobl + "秒";
    }
}
/*********************************************************************************************************
  获取最近一次出错时间
*********************************************************************************************************/
void error_time_record()
{
    String month12, day12, hourbl2, minbl2;

    if (blinker_month < 10)
    {
        month12 = String("") + "0" + blinker_month;
    }
    else
    {
        month12 = String("") + blinker_month;
    }

    if (blinker_mday < 10)
    {
        day12 = String("") + "0" + blinker_mday;
    }
    else
    {
        day12 = String("") + blinker_mday;
    }

    if (blinker_hour < 10)
    {
        hourbl2 = String("") + "0" + blinker_hour;
    }
    else
    {
        hourbl2 = String("") + blinker_hour;
    }
    if (blinker_min < 10)
    {
        minbl2 = String("") + "0" + blinker_min;
    }
    else
    {
        minbl2 = String("") + blinker_min;
    }

    fh = String("") + month12 + "/" + day12 + "/" + hourbl2 + ":" + minbl2;
}
/*********************************************************************************************************
  ping检测
*********************************************************************************************************/
void checek_ip()
{
    if (ip_timer_flag == true) // 检测ip timer
    {
        Serial.println("");
        Serial.println("###########################################################################");
        Serial.printf("          检测时间 %d : %d : %d \n", blinker_hour, blinker_min, blinker_sec);
        Serial.println("###########################################################################");
        ip_timer_flag = false;
        if (ip_app_check_flag == true) // app控制检测标志
        {
            ping_ip(); // 检测ip主程序
        }
        Blinker.run();
    }
    timer.tick();
}
void pinsetup()
{
    pinMode(VCCPIN, OUTPUT);
    digitalWrite(VCCPIN, LOW);                            // 蜂鸣器关闭
    timer.every(check_timer_time * 1000, ip_check_timer); // 开启打印寄存器
}

bool ip_check_timer(void *)
{
    ip_timer_flag = true;
    return true; // repeat? true
}

void delay_blinker(int n)
{
    for (uint16_t i = 0; i < n; i++)
    {
        Blinker.delay(500);
        Blinker.run();
        timer.tick();
    }
}
void ping_ip()
{
    // int16_t check_timer_time = 10, check_error_time= 5, clen_error_timer = 300;
    Serial.printf("检测间隔时间:  %d s   判断异常次数 :  %d    清除异常时间 :  %d s  \n", check_timer_time, clen_error_timer / check_timer_time, clen_error_timer);
    Serial.printf("访问 192.168.31.43\n");
    Serial.printf("当前是否访问正常 :  %d    访问异常次数 :  %d    最终访问异常次数 :  %d\n", ip_lost_flag, error_time, error_time_final);

    if (pinger.Ping("192.168.31.43") == false)
    {
    }
    delay_blinker(8);
    if (loss_true == true) // 侦测到异常
    {

        error_time++;
        Serial.println("###########################################################################");
        Serial.printf("访问出错: %d 次\n", error_time);

        if ((ip_lost_flag == false) && (error_time == (clen_error_timer / check_timer_time))) // 超过异常次数时断电恢复
        {
            c0 = 0; // app 显示访问异常
            c1 = 1; // app s设定显示访问异常
            error_time = 0;
            digitalWrite(VCCPIN, HIGH);
            Blinker.delay(1500);
            digitalWrite(VCCPIN, LOW);
            ip_lost_flag = true; // 访问异常标志位打开
            error_time_final++;  // 异常次数+1
            error_time_record(); // 记录异常时间
            Serial.println("###########################################################################");
            Serial.printf("       第 %d 次访问出错\n", error_time_final);
            Serial.println("###########################################################################");
        }

        /*************************************************************************************************
        if (read_time == 0 || (millis() - read_time) >= clen_error_timer * 1000) // 超过一定时间,容错清0
        {
            read_time = millis();
            error_time = 0;
            Serial.println("############################超时容错清0####################################");
        }
        *************************************************************************************************/
    }
    else
    {
        error_time = 0;           // 错误次数清0,重新计数
        if (ip_lost_flag == true) // 如果是异常,第一次恢复后计数清0以及标志位恢复
        {

            Serial.println("###########################################################################");
            Serial.println("          恢复正常访问");
            Serial.println("###########################################################################");
            c0 = 1; // app 显示访问正常
            c1 = 1; // app s设定显示访问正常
            error_time = 0;
            ip_lost_flag = false;
        }
    }
}

void ping_ip_set()
{
    // Begin serial connection at 9600 baud
    Serial.begin(115200);

    // Connect to WiFi access point
    bool stationConnected = WiFi.begin("************", "********************");

    // Check if connection errors
    if (!stationConnected)
    {
        Serial.println("Error, unable to connect specified WiFi network.");
    }
    // Wait connection completed
    Serial.print("Connecting to AP...");
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }
    Serial.print("Ok\n");

    pinger.OnReceive([](const PingerResponse &response)
                     {
    if (response.ReceivedResponse)
    {
      Serial.printf("来自 %s: bytes=%d time=%lums TTL=%d\n",response.DestIPAddress.toString().c_str(),response.EchoMessageSize - sizeof(struct icmp_echo_hdr),response.ResponseTime,response.TimeToLive);
    }
    else
    {
      Serial.printf("请求超时\n");
    }

    // Return true to continue the ping sequence.
    // If current event returns false, the ping sequence is interrupted.
    return true; });

    pinger.OnEnd([](const PingerResponse &response)
                 {
    // Evaluate lost packet percentage
    float loss = 100;
    if (response.TotalReceivedResponses > 0)
    {
      loss = (response.TotalSentRequests - response.TotalReceivedResponses) * 100 / response.TotalSentRequests;
    }
    if ( loss != 100) {

      loss_true = false;
    } else {

      loss_true = true;
    }
       
    // Print packet trip data
    Serial.printf("统计信息 %s:  数据包: 发送 = %lu, 接收 = %lu, 丢失 = %lu (%.2f%% 丢失)\n",response.DestIPAddress.toString().c_str(), response.TotalSentRequests, response.TotalReceivedResponses, response.TotalSentRequests - response.TotalReceivedResponses, loss);
    //Serial.printf(" Packets: Sent = %lu, Received = %lu, Lost = %lu (%.2f%% loss),\n", response.TotalSentRequests, response.TotalReceivedResponses, response.TotalSentRequests - response.TotalReceivedResponses, loss);

    // Print time information
    if (response.TotalReceivedResponses > 0)
    {
      Serial.printf("网络延迟: 最短 = %lums, 最长 = %lums, 平均 = %.2fms\n",response.MinResponseTime,response.MaxResponseTime,response.AvgResponseTime);
      //Serial.printf("    Minimum = %lums, Maximum = %lums, Average = %.2fms\n",response.MinResponseTime,response.MaxResponseTime,response.AvgResponseTime);
    }

    // Print host data
    //Serial.printf("Destination host data:\n");
    //Serial.printf("    IP address: %s\n", response.DestIPAddress.toString().c_str());
    if (response.DestMacAddress != nullptr)
    {
      Serial.printf( "    MAC address: " MACSTR "\n",MAC2STR(response.DestMacAddress->addr));
    }
    if (response.DestHostname != "")
    {
      //Serial.printf("    DNS name: %s\n",response.DestHostname.c_str());
    }

    return true; });

    // Ping default gateway
    Serial.printf("\n\nPinging default gateway with IP %s\n", WiFi.gatewayIP().toString().c_str());
    if (pinger.Ping(WiFi.gatewayIP()) == false)
    {
        Serial.println("Error during last ping command.");
    }
}

串口log打印如下:

可以协助判断运行状态,经过这两三天的调试,确认检测时间30s,也就是没个30s ping树莓派ip一次,会连续判断20次,如果20次都是访问不了的,就控制继电器断电,然后再上电,如果有20次判断有访问正常,则重新计数访问异常次数。

?

  • ?硬件实现

由于esp01 relay需要接线,需要改装数据线,所以想着画块板子通过两条usb线连接,方便后续改变,板子已下单,待收到后验证,

板子回来了,实际效果图如下:

?

后续优化

? ?优化的部分暂时未想好,目前可以基本满足需求。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:55:47  更:2022-11-05 00:56:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 5:29:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计