/*專門為自己用的模板*/
/*包含的頭文件*/
#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();
}
|