/*专门为自己用的模板*/
/*包含的头文件*/
#include <Arduino.h>
#include <NTPClient.h>//
#include <EEPROM.h>//EEPROM】
#include <PubSubClient.h>//网络连接相关
#include <ESP8266WiFi.h>//wifi相关
#include <ESP8266WiFiMulti.h>//wifi相关
#include <WiFiUdp.h>//wifi相关
#include <ESP8266Ping.h>//ping网络
#include <Ticker.h> //时间调度器
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <EspSaveCrash.h>//模块重启
#define USE_SERIAL Serial
/*************声明所需其他功能参数***********************************/
Ticker myTicker; //建立一个需要定时调度的对象
WiFiClient espClient;
ESP8266WiFiMulti WiFiMulti;
const char* mqtt_server = "0.0.0.0";//服务器地址
PubSubClient client(espClient);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
/**********************************************************************/
/* 功能描述:eeprom结构体操作*/
struct config_type
{
char fabu[64]; //发布ID
};
config_type config;
/**************************************************/
/*定义项目所需要的变量*/
float Voltage;//电压储存变量
char V[32];//电压运算结果储存数组
char TAGE[32]="V电压:";
char address[64]="http://0.0.0.0/";//升级文件服务器地址
char bin[64];//储存升级地址的中间数组
char Bin[64]=".bin";
uint32_t chipid;
uint8_t MAC_array_AP[6];//MAC地址数组
char MAC_char_AP[18];//MAC地址数组
char string[64];//数据转化数组
char id[64]="xzx/";//切记用中文/要不远程OTA升级会出错。
int information=1,shi,fen,miao,count;//计数
bool upgrade = false; // 升级触发标志变量
char UP[10]="升级";
char cache[10];//升级触发缓存变量可以用于别的地方
int aa=1,bb=1,cc=1,dd=1,a=0,b=0,c=0,d=0;
/************************变量******************************/
/**********定义项目所需要的IO端口****************************/
int A= 12;//A
int B= 13;//A
int C= 14;//A
int D= 16;//A
int state =02;//状态指示灯
/*************************功能函数****************/
/*************处理升级文件服务器地址以及文件名*************************/
void Take()//预处理升级地址
{
int len = strlen(id);
for(int i=0;i<8;i++)//获取数组长度取需要的信息
{
len--;
}
for(int i=0;i<len;i++){ bin[ i]=id[ i]; }//赋值给其他数组
strcat( bin, Bin );//信息合并
strcat( address, bin );//信息合并
}
/*检测wifi连接20秒超时*/
bool autoConfig()//连接到网络方法
{
WiFi.begin();
for (int i = 0; i < 10; i++)
{
int wstatus = WiFi.status();
if (wstatus == WL_CONNECTED){
WiFi.printDiag(Serial);
return true;
}
else
{
Serial.print("等待连接网络......");//自动配置等待
Serial.println(i);
delay(1000);
}
}
return false;
}
/*获取到IP地址后自动连接网络方法*/
void smartConfig()//wifi配置方法
{
WiFi.mode(WIFI_STA);
Serial.println("请配置wifi连接");
WiFi.beginSmartConfig();
count=80;
Serial.println("开始倒计时,计时结束还未配置重启模块");
while (1)
{
digitalWrite(state,!digitalRead(state));//指示灯闪烁提示配网
Serial.print(">");
Serial.print(count);
count--;
if (WiFi.smartConfigDone())
{
WiFi.setAutoConnect(true); // 设置自动连接
break; }
delay(1000); // 这个地方一定要加延时,否则极易崩溃重启
if(count==0){ count=80;
ESP.restart();
}
}
}
/***********************************************************/
/******************收到MQTT数据处理***************************/
void callback(char* topic, byte* payload, unsigned int length)//收到MQTT数据处理方法
{
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[ i]);//收到的信息打印到串口
cache[ i]=(char)payload[ i];//收到的信息复制给缓存数组
}
if ((char)payload[0] == '1')
{
/*这里可以让模块收到信息执行命令*/
}
}
/**********************数组比对是否相等******************************/
void comparison()//升级命令判断方法
{
const int SIZE = 5;
bool arraysEqual = true; // 标志变量
count = 0; //循环控制变量
while (arraysEqual && count < SIZE)//用while控制对比结果相等就完整循环,不等就立即退出,返回标志量结果
{
if (cache[count] != UP[count])
arraysEqual = false;
count++;
} //显示合适的消息
if (arraysEqual)
{ Serial.println("相等");
upgrade=true;//升级控制位
}
else
{
Serial.println("不等");
upgrade=false;//升级控制位
}
}
/*********************连接服务器方法***************************/
void reconnect() //连接服务器方法
{
count=5;
while (!client.connected()) {
Serial.println("以连接服务器");
if (client.connect(("%s\r\n",MAC_char_AP),"账号","密码"))//mqtt账号和密码
{
client.publish(config.fabu ,"ok");//发布的信息
client.subscribe(("%s\r\n", string));//订阅的信息
}
else
{
delay(100);
count--;
Serial.print("网络连接中断即将重启设备");
Serial.print(count);
if(count==0){ ESP.restart(); }
}
}
}
/***************时间获取方法****************************/
void Networktime()//时间获取方法
{
timeClient.update(); //获取网络时间
shi =timeClient.getHours()+7; //接收小时时间
fen = timeClient.getMinutes(); // 接收分钟时间
miao =timeClient.getSeconds(); // 接收秒钟时间
if(shi==24){shi=0;}if(shi==25){shi=1;}if(shi==26){shi=2;}if(shi==27){shi=3;}
if(shi==28){shi=4;}if(shi==29){shi=5;}if(shi==30){shi=6;}//将时间变量与现时时间匹配
}
/**************************数据转换*****************/
void dataconversion()//数据转换方法
{
chipid= ESP.getChipId(); //获取ID号
itoa(chipid, string, 10);//将ID号转换
strcat( id, string );//将ID号与订阅信息合并
strcpy(config.fabu, id);//将合并后的信息传入发布变量
}
void MAC()//获取MIC地址
{
for (int i = 0; i < sizeof(MAC_array_AP); ++i){ //获取MIC地址
sprintf(MAC_char_AP, "%s%02x:", MAC_char_AP, MAC_array_AP[ i]); }//打印MIC地址
}
/*******************************网络连接方法*************************/
void Connect()//网络连接判断
{
if (!autoConfig()){
Serial.println("启动模块网络配置");//启动模块
smartConfig();
}
}
/*****************AD转换方法***************************************/
void ADC()
{
Voltage=analogRead(A0)*0.0048828125;
dtostrf(Voltage,1,2,V);//将带小数点的电压值转换为数组中
// itoa( Voltage,V,10);//将电压转换为整数到数组
strcat( V,TAGE );//将ID号与订阅信息合并
delay(10);
Serial.println(("%s\r\n", V));
Serial.println(Voltage);
client.publish(config.fabu,("%s\r\n",V)); //将电压数据发布到MQTT
delay(10);
}
/***************************服务器远程升级方法************************/
void Upgrade()//服务器升级函数
{
if ((WiFiMulti.run() == WL_CONNECTED))
{count++;
if(count==20){ESP.restart();}//尝试20次升级如果都失败重启模块
WiFiClient client;
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
t_httpUpdate_return ret = ESPhttpUpdate.update(client, ("%s\r\n",address));
switch (ret) {
case HTTP_UPDATE_FAILED:
if(count==20){ESP.restart();}//尝试20次升级如果都失败重启模块
USE_SERIAL.printf("HTTP更新失败错误 (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
ESP.restart();
break;
case HTTP_UPDATE_NO_UPDATES:
if(count==20){ESP.restart();}//尝试20次升级如果都失败重启模块
USE_SERIAL.println("HTTP_UPDATE_NO_更新");
ESP.restart();
break;
case HTTP_UPDATE_OK:
USE_SERIAL.println("更新HTTP u OK");
break;
}
}
}
/*************************模块启动准备*************************/
void startUP()//启动效果
{
digitalWrite(state, LOW);//打开指示模块开始工作
for (uint8_t t = 5; t > 0; t--)
USE_SERIAL.printf("[start-up] Get ready %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
/********************************初始化方法*****************************/
void setup() //初始化
{
/*初始化代码*/
dataconversion();//ID数据转换方法
timeClient.begin();
USE_SERIAL.begin(115200);
pinMode(state, OUTPUT);//定义指示灯引脚为输出功能
digitalWrite(state, HIGH);//定义指示灯引脚初始为高电平
// pinMode(state,INPUT);//定义指示灯引脚为输入功能
// digitalWrite(state, LOW);//定义指示灯引脚初始为低电平
// digitalWrite(state,!digitalRead(state)); //取反指示灯引脚
// delay(1);//延时函数
pinMode(A, INPUT);
pinMode(B, INPUT);
pinMode(C, INPUT);
pinMode(D, INPUT);
USE_SERIAL.println();
startUP();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
Connect();//网络连接判断
WiFi.softAPmacAddress(MAC_array_AP);
MAC();
Serial.println("初始化完成");
myTicker.attach(2, tickerHandle); //初始化调度任务,1=1秒执行一次tickerHandle()
Take();//运行转换信息任务
}
void tickerHandle() //任务调度器/实现多任务运行
{
/*需要执行的任务*/
// Serial.println(millis()); //打印当前时间
Serial.println("任务调度器");
comparison(); //判断升级信息
/*代码代码代码代码代码代码代码代码代码代码代码代码
代码代码代码代码代码代码代码代码代码代码代码代码代码代码代码
码代码代码代码代码代码代码代码代码代码代码代码代码代*/
}
/************************************主循环方法*****************************/
void loop()//主循环方法
{
int INA = digitalRead(A);
int INB = digitalRead(B);
int INC = digitalRead(C);
int IND = digitalRead(D);
if(INA==0)
{
while(aa){
client.publish(config.fabu ,"A");
aa=0;
a=1;
}
}//发布的信息
if(INB==0)
{
while(bb){
client.publish(config.fabu ,"B");
bb=0;
b=1;
}
}//发布的信息
if(INC==0)
{
while(cc){
client.publish(config.fabu ,"C");
cc=0;
c=1;
}
}//发布的信息
if(IND==0)
{
while(dd){
client.publish(config.fabu ,"D");
dd=0;
d=1;
}
}//发布的信息
if(INA==1)
{
while(a){
client.publish(config.fabu ,"a");
a=0;
aa=1;
}
}//发布的信息
if(INB==1)
{
while(b){
client.publish(config.fabu ,"b");
b=0;
bb=1;
}
}//发布的信息
if(INC==1)
{
while(c){
client.publish(config.fabu ,"c");
c=0;
cc=1;
}
}//发布的信息
if(IND==1)
{
while(d){
client.publish(config.fabu ,"d");
d=0;
dd=1;
}
}//发布的信息
Networktime();//获取实时时间
while(information)
{
Serial.print("实时时间时:");
Serial.print(shi);
Serial.print("时");
Serial.print(fen);
Serial.print("分");
Serial.print(miao);
Serial.println("秒");
Serial.print("MAC:");
Serial.println(MAC_char_AP);
Serial.printf("无线网络名称:%s\r\n", WiFi.SSID().c_str());
Serial.printf("无线网络密码:%s\r\n", WiFi.psk().c_str());
Serial.print("IP地址: ");
Serial.println(WiFi.localIP());
Serial.print("连接的服务器地址:");
Serial.println(mqtt_server);
Serial.println("MQTT用户名:xzx 密码:xzx123456");
Serial.print("订阅的主题:");
Serial.println(string);
Serial.print("发布的主题:");
Serial.println(config.fabu);
Serial.print("模块自己的ID号:");
Serial.println(chipid);
Serial.print("升级文件的服务器地址:");
Serial.println(address);
Serial.print("升级文件命名名称:");
Serial.println(bin);
Serial.println("以上时模块所有信息:此程序是一个MQTT连接的程序");
information=0;
}
//ESP.deepSleep(1200000000, WAKE_RF_DEFAULT);//休眠20分钟//模块低功耗模式启动方法需要将GP016与模块的RST相连,参数为微妙,最大大约71分钟 遇到此方法模块就低功耗休眠
/*远程升级*/
if(upgrade) {Serial.println("模块自动升级");delay(100);Upgrade();}//升级
if (!client.connected()) {
reconnect();
}
client.loop();
}
|