找到一个RGB颜色代码的网站? ? ? ?颜色选择表
目录
创作前情
项目规划
实现过程
?软件实现
app界面如下:
arduino代码如下:
?硬件实现
后续优化
创作前情
? ? 目前使用树莓派装haos来做智能家居服务器,不知道是硬件问题还是哪里的设定问题,时不时挂掉,访问不了,需要手动断电重启,才能恢复,奈何找不到原因,本来是使用了一个米家智能插座来手动断电重启,但需要到用的时候才发现访问不了,需要进入米家重启,体验太差,所以想着如果可以有一个设备可以自己侦测是否正常,如果有问题,自动断电重启,这样会好很多。
项目规划
? ?方案一:使用esphome 来控制断电重启,最方便的一种,但目前没找到,使用esphome 来检测homeassistant是否挂掉的方法,故放弃。
? 方案二: 接入米家,继续使用米家插座来控制断电重启,也是需要先侦测到访问异常,再通过改造米家传感器接入,相对复杂,
? 方案三:借助blinker平台接入,本身使用arduino编程,相对熟悉很多,使用esp8266 ping库直接来侦测访问是否异常,点灯app可以控制断电以及各种状态,
实现过程
? 选择方案三来做,可以在之前浇水的代码上修改来实现相关功能,目前已实现如下功能
- 检测访问是否正常,如果不正常则自动断电重启,
- app界面可以手动控制继电器状态,达到手动重启,
- 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线连接,方便后续改变,板子已下单,待收到后验证,
板子回来了,实际效果图如下:
?
后续优化
? ?优化的部分暂时未想好,目前可以基本满足需求。
|