有現成不需銲接電路就可以使用的模組了
網拍搜尋 esp8266 relay
底板加ESP-01 全部不到台幣200元
這有一篇軟體安裝教學,用網頁翻譯一下很好懂
http://nothans.com/measure-wi-fi-signal-levels-with-the-esp8266-and-thingspeak
第一版 第二版
與前兩個版本比較起來增加了網頁功能,可遠端強制重開被監控的設備
如果你的草稿是使用上圖中的USB設備傳送的請記得測試運作的話不要在這個設備上面運作,
否則Wi-Fi斷線後或重新連線時會發生 wdt reset 訊息 RST CAUSE:2, BOOT MODE:(1,7)
否則Wi-Fi斷線後或重新連線時會發生 wdt reset 訊息 RST CAUSE:2, BOOT MODE:(1,7)
以下紅字部分依現場環境調整後上傳
/* for Arduino IDE 1.6.13
2018-04-10 修正運作中WiFi斷線後重新連線異常部分
2017-12-01 device x5
2017-07-19 for 8266Relay公版,relay off 防呆
2017-04-24 按鈕依狀態改變顏色
2017-04-24 add watchdog on/off
2017-04-23 add Web control Relay
2017-04-19 WiFi error count change to power Volt
2017-03-20 可選擇是否啟用 ThingSpeak 紀錄狀態& log Rssi
2016-10-03 簡化程式碼,增加被測裝置數量
2016-09-27 功能測試完成
for arduinoIDE 1.6.12 支援 ADC_MODE(ADC_VCC 但檔案目錄不支援中文,否則會檢查編譯錯誤
** 避免使用 gpio 16 , 以免不穩或無法運作
big5 to html code http://www.convertstring.com/zh_TW/EncodeDecode/HtmlEncode
定義update區域欄位
1: 0=loss, 1=Device Active, 2= local boot
2: 0=loss, 1=Device Active, 2= local boot
3: 0=loss, 1=Device Active, 2= local boot
4: 0=loss, 1=Device Active, 2= local boot
5: Run Level
6: reboot count
7: Power Volt
8: WiFi RSSI
thingspeak Server 只傳單一區域值第一筆之後的資料沒辦法再進資料庫
reedited for ESP8266 2016-09-17 by yulie~
H/W ESP8266
Network service check ipaddress & port
2015-07-26 by yulie~
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
MDNSResponder mdns;
ESP8266WebServer server(80);
boolean watchDog =1; // Device ip_1 1=看門狗開啟
boolean logger = 1; //1=ture 啟用 ThingSpeak紀錄狀態 , 0=false 停用 ThingSpeak紀錄狀態
word chkTime = 60; // Sec 檢測連狀態間隔時間
byte actTime = 120; // 次 檢測連狀態正常達該次數後發 Active 紀錄 dev0 or dev1
byte wait = 5; // 次 檢測連線狀態失敗達該次數後關電重啟 only for Device ip_1
word wifiFail = 600; // Sec Wi-Fi connect fail Reboot wait time
byte off_time = 15; // Sec 設備斷電該秒數之後重開
const char* Ctl_username = "Admin"; //Relay控制認證帳號
const char* Ctl_password = "0487"; //Relay控制認證密碼
const char* wd_username = "admin"; //WatchDog認證帳號
const char* wd_password = "8787"; //WatchDog認證密碼
String webPage = ""; //網頁內容(rePage)
///* //*****for my home NEW *****------------------------------------------------------------------
const byte Relay_1 = 0; // 使用第0腳控制繼電器
const byte LED = 2; // 使用第0腳控LED 顯示ip_1 狀態是否在線
const byte D1_pin = 0; //網頁控制的遙控開關腳位 #1
const byte D2_pin = 2; //網頁控制的遙控開關腳位 #2
const char* ssid = "WiFi_SSID"; // 連線名稱SSID
const char* password = "WiFi_PASSWORD"; // 連線密碼
char ip_1[] = "www.google.com"; word port_1 = 80; // 被檢查ip位址 & port
char ip_2[] = "192.168.1.31"; word port_2 = 80; // 被檢查ip位址 & port
char ip_3[] = "192.168.1.81"; word port_3 = 23; // 被檢查ip位址 & port
char ip_4[] = "192.168.1.51"; word port_4 = 23; // 被檢查ip位址 & port
char ip_5[] = "192.168.1.61"; word port_5 = 80; // 被檢查ip位址 & port
const char* Host = "ESP8266_Monitor"; //設備名稱
const char* html = "<h1>Device view</h1>"; //網頁標題
const char* D1_sta_1 = "Router ON"; // digitalRead = 1 敘述文字
const char* D1_sta_0 = "Router OFF"; // digitalRead = 0 敘述文字
const char* D2_sta_1 = " LED ON"; // digitalRead = 1 敘述文字
const char* D2_sta_0 = " LED OFF"; // digitalRead = 0 敘述文字
const String GET = "GET /update?key=XXXXXXXXXXXXX"; //--------- for 網路設備重開記錄
const char* thingspeakID = "-----------";
///*
// Mac address should be different for each device in your LAN
byte arduino_mac[] = { 0x00, 0x09, 0x37, 0x16, 0x89, 0x40 };
IPAddress device_ip (192, 168, 1, 5);
IPAddress dns_ip (168, 95, 192, 1);
IPAddress gateway_ip (192, 168, 1, 254);
IPAddress subnet_mask(255, 255, 255, 0);
//*/
//*/ //------------------------------------------------------------------
char serverIP[] = "api.thingspeak.com"; word serverPort = 80;
unsigned long t, u, v, w = 0;
byte actCoun, devFail, status_1, status_1a, status_2, status_2a, status_3, status_3a, status_4, status_4a, status_5, status_5a;;;
word WiFi_fail, reboot_count;
int rssi;
byte old_watchDog;
void setup() {
t, u, v, w = millis();
Serial.begin(115200);
WiFi.hostname(Host); //no set default ESP_XXXXXX (MAC)
// WiFi.config(device_ip, gateway_ip, subnet_mask); //disable to DHCP
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
/*
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Connect Failed! Rebooting...10Sec...");
delay(20000);
ESP.restart();
}
*/ if (mdns.begin("esp8266", WiFi.localIP())) {
Serial.println("MDNS responder started");
}
pinMode(Relay_1, OUTPUT); pinMode(LED, OUTPUT);
// preparing GPIOs
pinMode(D1_pin, OUTPUT); digitalWrite(D1_pin, LOW);
pinMode(D2_pin, OUTPUT); digitalWrite(D2_pin, LOW);
for (byte i = 0; i < 6; i++) {
digitalWrite(LED, !HIGH); delay(500); digitalWrite(LED, !LOW); delay(500); //LED閃5下
}
if (logger == 1) updata(2, 2, 2, 2, 2, 0, 9); //開機信息
digitalWrite(LED, chkdev(ip_1, port_1)); //LED 顯示裝置"ip_1"是否連線
// rePage();
/* //不認證
server.on("/", []() { server.send(200, "text/gtml", webPage); }); //無認證
server.on("/D1_On", []() {digitalWrite(D1_pin, LOW); delay(100); rePage(); server.send(200, "text/html", webPage); });
server.on("/D1_Off", []() {digitalWrite(D1_pin, HIGH); delay(100); rePage(); server.send(200, "text/html", webPage); });
server.on("/D2_On", []() {digitalWrite(D2_pin, LOW); delay(100); rePage(); server.send(200, "text/html", webPage); });
server.on("/D2_Off", []() {digitalWrite(D2_pin, HIGH); delay(100); rePage(); server.send(200, "text/html", webPage); });
*/
// /*
//認證不過狀態不會變
//server.on("/", []() { if (!server.authenticate(www_username, www_password))return server.requestAuthentication(); server.send(200, "text/html", webPage); });
server.on("/", []() {rePage(); server.send(200, "text/html", webPage); });
server.on("/wd_on", []() { if (!server.authenticate(wd_username, wd_password))return server.requestAuthentication(); watchDog = 1; rePage(); server.send(200, "text/html", webPage); });
server.on("/wd_off", []() { if (!server.authenticate(wd_username, wd_password))return server.requestAuthentication(); watchDog = 0; rePage(); server.send(200, "text/html", webPage); });
server.on("/D1_On", []() { if (!server.authenticate(Ctl_username, Ctl_password))return server.requestAuthentication(); digitalWrite(D1_pin, !HIGH); rePage(); server.send(200, "text/html", webPage); });
server.on("/D1_Off", []() { if (!server.authenticate(Ctl_username, Ctl_password))return server.requestAuthentication(); digitalWrite(D1_pin, !LOW ); rePage(); server.send(200, "text/html", webPage); });
server.on("/D2_On", []() { digitalWrite(D2_pin, HIGH); rePage(); server.send(200, "text/html", webPage); });
server.on("/D2_Off", []() { digitalWrite(D2_pin, LOW ); rePage(); server.send(200, "text/html", webPage); });
server.on("/reboot", []() { if (!server.authenticate(Ctl_username, Ctl_password))return server.requestAuthentication(); rebootPower_1(); rePage(); server.send(200, "text/html", webPage); });
//*/
server.begin(); Serial.println("HTTP server started");
server.begin();
Serial.print("Open http://");
Serial.print(WiFi.localIP());
Serial.println("/ in your browser to see it working");
}
void rePage() { //更新webPage內容
webPage = html;
//頁面上第1個按鈕,依ON/OFF狀態改變按鈕背景顏色
webPage += "<p><a href=\"/wd_on\"><button type=\"button\" style=\"background-color:";
webPage += ((watchDog)?"#FF5050":"#DDDDDD"), //依狀態改變ON按鈕背景顏色
webPage += ";color:#000000;\">ON</button></a> "; //按鈕字型顏色
webPage += "<a href=\"/wd_off\"><button type=\"button\" style=\"background-color:";
webPage += ((!watchDog)?"#7FFF7F":"#DDDDDD"), //依狀態改變OFF按鈕背景顏色
webPage += ";color:#000000;\">OFF</button></a>"; //按鈕字型顏色
webPage += "watchDog: ";
webPage += ip_1;
webPage += " -> ";
webPage += ((watchDog)?"ON":"OFF"), // digitalRead=1 直接顯示 ON , digitalRead=0 直接顯示 OFF,
webPage += "</p>";
//頁面上第2個按鈕,依ON/OFF狀態改變按鈕背景顏色
webPage += "<p><a href=\"/D1_On\"><button type=\"button\" style=\"background-color:";
webPage += (!digitalRead( D1_pin )?"#FF5050":"#DDDDDD"), //依狀態改變(ON反向)按鈕背景顏色
webPage += ";color:#000000;\">ON</button></a> "; //按鈕字型顏色
webPage += "<a href=\"/D1_Off\"><button type=\"button\" style=\"background-color:";
webPage += (digitalRead( D1_pin )?"#7FFF7F":"#DDDDDD"), //依狀態改變OFF按鈕背景顏色
webPage += ";color:#000000;\">OFF</button></a>"; //按鈕字型顏色
webPage += " #0 Pin ";
webPage += D1_pin;
webPage += " -> ";
webPage += ((digitalRead( D1_pin ))?D1_sta_1:D1_sta_0), // D1_pin=1 顯示 lampON 字串 ,D1_pind=0 顯示 lampOFF 字串( ! 為使顯示狀態反向,實際上低電位繼電器模組為On)
webPage += "</p>";
//頁面上第3個按鈕,依ON/OFF狀態改變按鈕背景顏色
webPage += "<p><a href=\"/D2_On\"><button type=\"button\" style=\"background-color:";
webPage += (digitalRead( D2_pin )?"#FF5050":"#DDDDDD"), //依狀態改變ON按鈕背景顏色
webPage += ";color:#000000;\">ON</button></a> "; //按鈕字型顏色
webPage += "<a href=\"/D2_Off\"><button type=\"button\" style=\"background-color:";
webPage += (!digitalRead( D2_pin )?"#7FFF7F":"#DDDDDD"), //依狀態改變(OFF反向)按鈕背景顏色
webPage += ";color:#000000;\">OFF</button></a>"; //按鈕字型顏色
webPage += " #2 Pin ";
webPage += D2_pin;
webPage += " -> ";
webPage += ((digitalRead( D2_pin ))?D2_sta_1:D2_sta_0), // digitalRead=1 顯示 lampON 字串 , digitalRead=0 顯示 lampOFF 字串
webPage += "</p>";
// webPage += "<p><a href=\"https://thingspeak.com/channels/101630\">View device logger</a></p>"; //加入連結及敘述
webPage += "<p><a href=\"https://thingspeak.com/channels/";
webPage +=thingspeakID;
webPage +="\">View device logger</a></p>";
// webPage += "<iframe width=\"450\" height=\"260\" style=\"border: 1px solid #cccccc;\" src=\"https://thingspeak.com/channels/101630/charts/1?bgcolor=%23ffffff&color=%23d62020&dynamic=true&results=24&title=%E5%85%A7%E9%83%A8+IP&type=line\"></iframe>";
webPage += "<p>WiFi RSSI ";
webPage += WiFi.RSSI();
webPage += " dBm</p>";
webPage += "<p> </p>""<p> Power By ESP8266~</p>"; // 純顯示文字
/*
//頁面上按鈕,不依ON/OFF狀態改變按鈕背景顏色
webPage += "<p><a href=\"/wd_on\"><button type=\"button\" style=\"background-color:dddddd;color:#ffffff;\">ON</button></a> ";
webPage += " <a href=\"/wd_off\"><button type=\"button\" style=\"background-color:#cccccc;color:#ffffff;\">OFF</button></a>";
webPage += " device: ";
webPage += ip_1;
webPage += " -> ";
webPage += ((watchDog)?"Watchdog ON":"Watchdog OFF"), // digitalRead=1 直接顯示 ON , digitalRead=0 直接顯示 OFF,
webPage += "</p>";
webPage += "<p><a href=\"D1_On\"><button>ON</button></a> <a href=\"D1_Off\"><button>OFF</button></a>";
webPage += " #0 Pin ";
webPage += D1_pin;
webPage += " -> ";
webPage += ((digitalRead( D1_pin ))?D1_sta_1:D1_sta_0), // D1_pin=1 顯示 lampON 字串 ,D1_pind=0 顯示 lampOFF 字串( ! 為使顯示狀態反向,實際上低電位繼電器模組為On)
webPage += "</p>";
webPage += "<p><a href=\"D2_On\"><button>ON</button></a> <a href=\"D2_Off\"><button>OFF</button></a>";
webPage += " #2 Pin ";
webPage += D2_pin;
webPage += " -> ";
webPage += ((digitalRead( D2_pin ))?D2_sta_1:D2_sta_0), // digitalRead=1 顯示 lampON 字串 , digitalRead=0 顯示 lampOFF 字串
webPage += "</p>";
*/
}
void loop() {
if(millis() - w >=500 && watchDog !=old_watchDog){
w=millis();
Serial.print("watchDog =");
Serial.println(watchDog);
old_watchDog=watchDog;
if(digitalRead(Relay_1)==HIGH)rebootPower_1(); // Relay N.C connect (device power down) 2017-07-19 add 防呆
}
server.handleClient();
//=============== 2018-04-10 add ===========================================================
if (millis() - t >= 30000 && WiFi.status() != WL_CONNECTED ) { // 連接到指定的 WiFi SSID 如果連線AP 失敗時執行這一段程式
t = millis();
Serial.println("WiFi Connect Failed! wait...30Sec..ReConnect.");
for (byte i = 0; i < 6; i++) {digitalWrite(LED, HIGH); delay(100); digitalWrite(LED, LOW); delay(100);} //LED閃5下
delay(30000);
WiFi_fail++;
WiFi_fail = constrain ( WiFi_fail, 0, 65534); // 限制該值在0~100 之間
Serial.println(WiFi_fail);
if (WiFi.status() != WL_CONNECTED ){
Serial.println("Esp8266 WiFi ReConnect... ");
WiFi.begin(ssid, password);
//ESP.restart();
}
else{
Serial.println("-------------------------------------->>ESP8266 Wi-Fi Link UP..... ");
// if(WiFi_fail != 0 )ESP.restart();
}
if (WiFi_fail >= wifiFail) { //connect Wifi fail over 3min Run
rebootPower_1();
WiFi_fail = 0;
}
}
//=============== 2018-04-10 add end===========================================================
if (millis() - u > (chkTime * 1000)) { //30000 mS on chk
u = millis();
actCoun++;
Serial.println(" ");
status_1 = chkdev(ip_1, port_1); //回傳"0"為斷線, 回傳為"1"連線
status_2 = chkdev(ip_2, port_2);
status_3 = chkdev(ip_3, port_3);
status_4 = chkdev(ip_4, port_4);
status_5 = chkdev(ip_5, port_5);
digitalWrite(LED, status_1); //顯示裝置"ip_1"是否連線
//任何裝置狀態改變時上傳
if (status_1 != status_1a || status_2 != status_2a || status_3 != status_3a || status_4 != status_4a || status_5 != status_5a) { //任何裝置狀態改變
Serial.println(" Detect status change......");
status_1a = status_1; status_2a = status_2; status_3a = status_3; status_4a = status_4; status_5a = status_5; //狀態更新,做為下一次狀態比較用
if ( status_1 == 1 && logger == 1)updata(status_1, status_2, status_3, status_4, status_5, reboot_count, 6); //上傳
}
if (status_1 == 1) devFail = 0; //斷線計數歸零
else {
devFail++; //裝置斷線計數,給重開設備判斷用
actCoun = 0;
}
// device 0 or device 1 每60次傳送一次存活信息
if (actCoun >= actTime && logger == 1 )updata(status_1, status_2, status_3, status_4, status_5, reboot_count,4);
//裝置矢聯達指定次數則啓動繼電器關機重開
if (devFail >= wait) {
if(watchDog == 1)rebootPower_1(); //watchDog 開啟才執行
devFail = 0;
WiFi_fail = 0;
}
//showCount(); //for debug
//reboot_count != 0 or WiFi_fail != 0 and connect OK send infomation...
if ((reboot_count != 0 || WiFi_fail != 0) && status_4 == 1 && logger == 1) updata(status_1, status_2, status_3, status_4, status_5, reboot_count,0);
}
}
//-------------------------------------------------------------------------------void updata()
word updata(word field1, word field2, word field3, word field4, word field5, word field6, word field7) {
rssi = WiFi.RSSI();
// float volt = analogRead(A0) * 0.0125 ;
// volt = (analogRead(A0) * (1.0 / 1024) * 12.83) ; // 220K + 18.6k 分壓 , (220 + 18.6)/18.6=12.83
WiFiClient client;
if (client.connect(serverIP, serverPort)) {
String getStr = GET +
"&field1=" + String((float)field1, 0) + // active 01
"&field2=" + String((float)field2, 0) + // active 02
"&field3=" + String((float)field3, 0) + // active 03
"&field4=" + String((float)field4, 0) + // active 04
"&field5=" + String((float)field5, 0) + // active 05
"&field6=" + String((float)field6, 0) + // reboot_count
"&field7=" + String((float)field7, 0) + //input Volt
"&field8=" + String((float)rssi, 2) + // RSSI
" HTTP/1.1\r\n";;
client.print( getStr );
client.print( "Host: api.thingspeak.com\n" );
client.print( "Connection: close\r\n\r\n" );
delay(10);
// 處理遠端伺服器回傳的訊息,程式碼可以寫在這裡!
Serial.println(getStr);
client.stop();
actCoun = 0; //如果狀態傳送就將先前的存活計數歸零
WiFi_fail = 0;
reboot_count = 0;
}
else { //連線失敗執行此段程式
Serial.print(ip_1); Serial.print(" : "); Serial.print(port_1); Serial.println(" ThingSpeak Server disconnection ---- X ");
}
client.stop();
}
//------------------------------------------------------------------------------- check device
byte chkdev(char* IP, word PORT) {
WiFiClient client; delay(200);
if (client.connect(IP, PORT)) { //連線成功執行此段程式
Serial.print(IP); Serial.print(" : "); Serial.print(PORT); Serial.println(" check device connected ");
return 1; //傳回值"1"
}
else if (client.connect(IP, PORT)) { //第一次連線不成功執行此段程式
Serial.print(IP); Serial.print(" : "); Serial.print(PORT); Serial.println(" check device connected ");
return 1; //傳回值"1"
}
else { //兩次連線失敗執行此段程式
Serial.print(IP); Serial.print(" : "); Serial.print(PORT); Serial.println(" check device disconnection ---- X ");
return 0; //傳回值"0"
}
}
//-------------------------------------------------------------------------------status_1, status_2
void showCount() { //for debug
Serial.print("status_1 : "); Serial.println(status_1); Serial.print("status_2 : "); Serial.println(status_2);
Serial.print("WiFi_fail : "); Serial.println(WiFi_fail); Serial.print("reboot_count : "); Serial.println(reboot_count);
uint32_t getVcc = ESP.getVcc(); float voltaje = ESP.getVcc(); Serial.println("core Volt : "); Serial.print(voltaje / 1024);
Serial.println(" V");
}
//-------------------------------------------------------------------------------void rebootPower_1()
void rebootPower_1() {
digitalWrite(Relay_1, HIGH); // Relay N.C connect (device power down)
Serial.print("power down~ Wait "); Serial.print(off_time); Serial.println(" Sec ..");
delay(off_time * 1000); //device power down (off_time) sec
digitalWrite(Relay_1, LOW);
Serial.println("power up");
reboot_count++;
}