ปัญหา online blynk app แล้ว สถานะอัตโนมัติถูกรีเซท


ระบบการสั่งการทำงาน esp8266 v3 ผ่าน blynk และรายงานสถานะด้วย Line Notify ครับ ฟังก์ชั่นคร่าวๆ
วัตถุประสงค์คือแก้ปัญหาข้างบน กับรบกวนเพื่อนๆ สมาชิกช่วยผม optimize code ให้หน่อยครับ ผมโค๊ดมาดิบเกิน 555+

  1. เปิดปิดอุปกรณ์ทั้ง แบบ แมนนวล, อัตโนมัติ และกึ่งอัตโนมัติ (คือสั่งแบบแมนนวลได้ในขณะที่ตั้งเวลาการทำงานได้)
  2. ใช้ smart phone 4G เป็นตัวปล่อย Wifi Hotspot ให้ esp8266 ออกเน็ต และเชื่อม blynk ได้
  3. ใช้พลังงานที่มีอย่างจำกัดของชุดโซล่าเซลล์ชุดเล็กๆ
  4. ระบบจะดึงเวลาจาก NTP server มาในตอนที่เริ่มโปรแกรมครั้งแรก เพื่อตั้งเวลา และสามารถปิดการเชื่อมต่ออินเตอร์เน็ตโดยระบบยังนับเวลาได้ในตัวมันเอง
  5. สามารถเชื่อมต่ออินเตอร์เน็ตและกดรีเซ็ทเพื่อเริ่มโปรแกรมใหม่ ถือเป็นการอัพเดทเวลาให้กับระบบใหม่อีกด้วย
  6. ระบบสั่งงานผ่าน Relay 4ch แบบ active LOW เพื่อนำคำสั่งไปถึงอุปกรณ์, อุปกรณ์มีทั้งใช้ไฟ DC และ AC
#define BLYNK_PRINT Serial

#include <ESP8266WiFi.h>
#include <time.h>
#include <BlynkSimpleEsp8266.h>
#include <TridentTD_LineNotify.h>

#define LINE_TOKEN  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"  //LINE Token

#define nodeMCU_LED D4 // Nodemcu v2 ใช้ D0 , Nodemcu v3 ใช้ D4
#define WaterPumpRelay D1 //connect to Relay CH.1
#define PhoneChargeRelay D5 //connect to Relay CH.2
#define LEDFrontRelay D2  //connect to Relay CH.3
#define LEDBackRelay D6 //connect to Relay CH.4
#define ManualPump D0 //no relay output only set for blynk read status

const char* ssid = "xxxxxxxxx";             // SSID is set
const char* password = "xxxxxxxxx";     // Password is set 

char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //blynk token

char ntp_server1[20] = "1.asia.pool.ntp.org";
char ntp_server2[20] = "1.th.pool.ntp.org";
char ntp_server3[20] = "time.navy.mi.th";

int timezone = 7 * 3600;  //timezone for Thailand is +7
int dst = 0;

int buttonState = 0;

bool AutoPumpON = false;
bool ManualPumpON = false;
bool PhoneCharge = false;
bool LEDFrontON = false;
bool LEDBackON = false;
bool WaterPumpRunning = false;

//Written by Ruben Marc Speybrouck
unsigned long timeNow = 0;
unsigned long timeLast = 0;

//Time start Settings:
int startingHour = 14;  // set your starting hour here, not below at int hour. This ensures accurate daily correction of time
int seconds = 0;
int minutes = 14;
int hours = startingHour;
int days = 0;

//Accuracy settings
int dailyErrorFast = 0; // set the average number of milliseconds your microcontroller's time is fast on a daily basis
int dailyErrorBehind = 0; // set the average number of milliseconds your microcontroller's time is behind on a daily basis
int correctedToday = 1; // do not change this variable, one means that the time has already been corrected today for the error in your boards crystal. This is true for the first day because you just set the time when you uploaded the sketch.

void setup() {
  
  Serial.begin(115200);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  Blynk.begin(auth, ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println(WiFi.localIP());
  Serial.println("");
 
  //time_t now = time(nullptr);
  //struct tm* p_tm = localtime(&now);

  for (int i=0; i <= 20; i++){
    configTime(timezone, dst, ntp_server1, ntp_server2, ntp_server3);
    Serial.println("\nWaiting for time");
    while (!time(nullptr)) {
      Serial.print(".");
      delay(30000);
    }   
    time_t now = time(nullptr);
    struct tm* p_tm = localtime(&now);
    //Serial.print(".");
    delay(1000);
    if(i==20){
      Serial.println("");
      Serial.print(p_tm->tm_hour); Serial.print(":");
      Serial.print(p_tm->tm_min); Serial.print(":");
      Serial.println(p_tm->tm_sec);
      Serial.println(ctime(&now));
      hours = p_tm->tm_hour;
      minutes = p_tm->tm_min;
      seconds = p_tm->tm_sec;     
    }
  }
  

  // กำหนด Line Token
  LINE.setToken(LINE_TOKEN);
  LINE.notify("ติดต่อเครือข่าย WiFi สำเร็จ");
  LINE.notify(WiFi.localIP().toString().c_str()); 

  pinMode(nodeMCU_LED,OUTPUT);
  pinMode(WaterPumpRelay,OUTPUT); // GPIO 5 or D1
  pinMode(PhoneChargeRelay,OUTPUT); // GPIO 14 or D5
  pinMode(LEDFrontRelay,OUTPUT);  // GPIO 4 or D2
  pinMode(LEDBackRelay,OUTPUT); // GPIO 12 or D6
  pinMode(ManualPump,OUTPUT); // GPIO 16 or D0

  digitalWrite(WaterPumpRelay, HIGH); // GPIO 5 or D1
  digitalWrite(PhoneChargeRelay, HIGH); // GPIO 14 or D5
  digitalWrite(LEDFrontRelay, HIGH);  // GPIO 4 or D2
  digitalWrite(LEDBackRelay, HIGH); // GPIO 12 or D6
  digitalWrite(ManualPump, LOW);  // GPIO 16 or D0

  LINE.notify("ระบบการแจ้งเตือนผ่านไลน์ทำงาน");
}
void loop() {

  timeNow = millis()/1000; // the number of milliseconds that have passed since boot
  seconds = timeNow - timeLast;
  
  //the number of seconds that have passed since the last time 60 seconds was reached.
  if (seconds >= 60) {
  timeLast = timeNow;
  minutes = minutes + 1; }
  
  //if one minute has passed, start counting milliseconds from zero again and add one minute to the clock.
  if (minutes >= 60){
  minutes = 0;
  hours = hours + 1; }
  
  // if one hour has passed, start counting minutes from zero and add one hour to the clock
  if (hours >= 24){
  hours = 0;
  days = days + 1;
  }
  
  //if 24 hours have passed, add one day
  if (hours ==(24 - startingHour) && correctedToday == 0){
  delay(dailyErrorFast*1000);
  seconds = seconds + dailyErrorBehind;
  correctedToday = 1; }
  
  //every time 24 hours have passed since the initial starting time and it has not been reset this day before, add milliseconds or delay the program with some milliseconds.
  //Change these varialbes according to the error of your board.
  // The only way to find out how far off your boards internal clock is, is by uploading this sketch at exactly the same time as the real time, letting it run for a few days
  // and then determining how many seconds slow/fast your boards internal clock is on a daily average. (24 hours).
  if (hours == 24 - startingHour + 2) {
  correctedToday = 0; }
  
  //let the sketch know that a new day has started for what concerns correction, if this line was not here the arduiono // would continue to correct for an entire hour that is 24 - startingHour.
  Serial.print("The time is: ");
  Serial.print(days);
  Serial.print(":");
  Serial.print(hours);
  Serial.print(":");
  Serial.print(minutes);
  Serial.print(":");
  Serial.println(seconds);
    
  //Blynk.run();

  if(WiFi.status() == WL_CONNECTED){
    if (!Blynk.connected()) {
    if(Blynk.connect()) {
      BLYNK_LOG("Reconnected");
    } else {
      BLYNK_LOG("Not reconnected");
      delay(250);
     }
    }
    if(Blynk.connected()) {   // to ensure that Blynk.run() www.eleceasy.com
    Blynk.run();
    }
  }

    //อ่านสถานะ D1,D5,D2,D6 และ D0 เพื่อไปกำหนด สถานะของ Virtual Pin บน แอป Blynk
    //รีเลย์ที่ใช้เป็นแบบ active LOW มี 4 CH
    
    buttonState = digitalRead(WaterPumpRelay); // อ่านค่าสถานะขาD1
    if (buttonState == HIGH) { //ถ้าอ่านค่าสถานะ Relay No.1 เท่ากับ 1 หรือ HIGH ให้กำหนด V1 เท่ากับ 0 บน Blynk
      Blynk.virtualWrite(V1,LOW);
    }
    else { //ถ้าอ่านค่าสถานะ Relay No.1 ไม่เท่ากับ 1 หรือ HIGH ให้กำหนด V1 เท่ากับ 1 หรือ HIGH บน Blynk
      Blynk.virtualWrite(V1,HIGH);
    }

    buttonState = digitalRead(PhoneChargeRelay); // อ่านค่าสถานะขาD5
    if (buttonState == HIGH) { //ถ้าอ่านค่าสถานะ Relay No.2 เท่ากับ 1 หรือ HIGH ให้กำหนด V2 เท่ากับ 0 บน Blynk
      Blynk.virtualWrite(V2,LOW);
    }
    else { //ถ้าอ่านค่าสถานะ Relay No.2 ไม่เท่ากับ 1 หรือ HIGH ให้กำหนด V2 เท่ากับ 1 หรือ HIGH บน Blynk
      Blynk.virtualWrite(V2,HIGH);
    }

    buttonState = digitalRead(LEDFrontRelay); // อ่านค่าสถานะขาD2
      if (buttonState == HIGH) { //ถ้าอ่านค่าสถานะ Relay No.3 เท่ากับ 1 หรือ HIGH ให้กำหนด V3 เท่ากับ 0 บน Blynk
      Blynk.virtualWrite(V3,LOW);
    }
    else { //ถ้าอ่านค่าสถานะ Relay No.3 ไม่เท่ากับ 1 หรือ HIGH ให้กำหนด V3 เท่ากับ 1 หรือ HIGH บน Blynk
      Blynk.virtualWrite(V3,HIGH);
    }

    buttonState = digitalRead(LEDBackRelay); // อ่านค่าสถานะขาD6
    if (buttonState == HIGH) { //ถ้าอ่านค่าสถานะ Relay No.4 เท่ากับ 1 หรือ HIGH ให้กำหนด V4 เท่ากับ 0 บน Blynk
      Blynk.virtualWrite(V4,LOW);
      if (LEDBackON == true){
        LINE.notify("ปิดไฟหลังบ้านแบบควบคุมเอง");
      }
      LEDBackON = false;
    }  
    else { //ถ้าอ่านค่าสถานะ Relay No.4 ไม่เท่ากับ 1 หรือ HIGH ให้กำหนด V4 เท่ากับ 1 หรือ HIGH บน Blynk
      Blynk.virtualWrite(V4,HIGH);
      if (LEDBackON == false){
        LINE.notify("เปิดไฟหลังบ้านแบบควบคุมเอง");
      }
      LEDBackON = true;
    } 

    buttonState = digitalRead(ManualPump); // อ่านค่าสถานะขาD0
    if (buttonState == LOW) { //ถ้าอ่านค่าสถานะ D0 เท่ากับ 0 หรือ LOW ให้กำหนด V5 เท่ากับ 0 บน Blynk
      Blynk.virtualWrite(V5,LOW);
      if ((ManualPumpON == true)){
        LINE.notify("ปิดปั๊มน้ำแบบควบคุมเอง");
      ManualPumpON = false;
      }
      WaterPumpRunning = false;
    }
    else { //ถ้าอ่านค่าสถานะ D0 ไม่เท่ากับ 0 หรือ LOW ให้กำหนด V5 เท่ากับ 1  หรือ HIGH บน Blynk
      Blynk.virtualWrite(V5,HIGH);
      if ((ManualPumpON == false)){
        LINE.notify("เปิดปั๊มน้ำแบบควบคุมเอง");
      ManualPumpON = true;
      }
      WaterPumpRunning = true;
    }

  if(((hours >= 9)&&(hours <= 10)) || (digitalRead(ManualPump) == HIGH)){
    digitalWrite(WaterPumpRelay, LOW);
    Serial.println("Water the plants time");
    if ((AutoPumpON == false) && (digitalRead(ManualPump) == LOW)){
      LINE.notify("เปิดปั๊มน้ำตามเวลาที่ตั้งไว้");
    AutoPumpON = true;
    }
    WaterPumpRunning = true;
  }

  else {
    digitalWrite(WaterPumpRelay, HIGH);
    Serial.println("Dry time");
    if ((AutoPumpON == true) && (digitalRead(ManualPump) == LOW)){
      LINE.notify("ปั๊มน้ำหยุดทำงานในระบบตั้งเวลา");
    AutoPumpON = false;
    }
    WaterPumpRunning = false;
  }
  
  if((hours == 7) || (hours == 11) || (hours == 13) || (hours == 15) || (hours == 17) || (hours == 18) || (hours == 19) || (hours == 21) || (hours == 23) || (hours == 1) || (hours == 3) || (hours == 5)){  
    digitalWrite(PhoneChargeRelay, LOW);
    Serial.println("Phone Charge time");
    if (PhoneCharge == false){
      LINE.notify("ชาร์จมือถือตามเวลาที่ตั้งไว้");
    }
    PhoneCharge = true;
  }

  else {
    digitalWrite(PhoneChargeRelay, HIGH);
    Serial.println("No Phone Charge");
    if (PhoneCharge == true){
      LINE.notify("หยุดชาร์จมือถือตามเวลาที่ตั้งไว้");
    }
    PhoneCharge = false;
  }

  if((hours == 18) || (hours == 20) || (hours == 22) || (hours == 0) || (hours == 2) || (hours == 4)){
    digitalWrite(LEDFrontRelay, LOW);
    //digitalWrite(LEDBackRelay, LOW);
    Serial.println("Front LED ON");
    if (LEDFrontON == false){
      LINE.notify("เปิดไฟหน้าบ้านตามเวลาที่ตั้งไว้");
    }
    LEDFrontON = true;
  }

  else {
    digitalWrite(LEDFrontRelay, HIGH);
    //digitalWrite(LEDBackRelay, HIGH);
    Serial.println("Front LED OFF");
    if (LEDFrontON == true){
      LINE.notify("ไฟหน้าบ้านปิดตามเวลาที่ตั้งไว้");
    }
    LEDFrontON = false;
  }

  digitalWrite(nodeMCU_LED,HIGH);
  delay(500);
  digitalWrite(nodeMCU_LED,LOW);
  delay(500);
 
 }

1 Like

หมายถึง ถ้า Blynk หลุด แล้วต่อใหม่ ระบบไม่จำสถานะครั้งสุดท้ายก่อนหลุด แต่จะเริ่มค่าเริ่มต้นใหม่ ถูกต้องไหมครับ

1 Like

คืออธิบายอย่างงี้นะครับ ระบบทำงานพื้นฐานโดยการสั่งการรีเลย์บางตัวตามเวลาที่ตั้งไว้อยู่แล้ว คือถึงเวลามันจะต่อรีเลย์เองตามโปรแกรม แต่ขณะที่เราเปิดแอพ Blynk ที่มือถือ แล้วกดออนไลน์ สถานะของรีเลย์ที่ทำงานหรือต่อแล้ว จะรีเซทครับ แต่… ถ้าผมกดสั่งผ่าน Blynk ไปที่ GPIO ตัวนั้นๆ ตามรูปด้านบน รีเลย์ตัวนั้นก็จะกลับมาทำงานอีกครั้ง และคราวนี้ถ้ากดซ้ำอีกก็จะตัดและก็ต่อใหม่เพราะอยู่ในเวลาที่ตั้งไว้
สรุปนะครับ มีปัญหาทุกครั้งเวลาที่ผมออนไลน์ app blynk ที่มือถือ
ขอบคุณที่สนใจเข้ามาตอบโพสนะครับ

คือจะเบิลปุ่มที่ ระบบตั้งเวลาเปิดวาล์วอยู่ใช่ไหม แต่มันจะรีเซต ตอนที่เปิด

ถำถามคือเราจะเบิลเพื่อ ปิด หรือ เปิด วาล์วนั้นครับ

อ่านแล้ว ยังงงงง ???

เอาเป็นว่า ปกติ ถ้าเราไม่ เปิดโปรแกรม Blynk แล้วเชื่อมต่อเข้า MCU โปรแกรมใน MCU ก็ทำงานตาม Function ที่มันทำอยู่ตามวงรอบ แต่ถ้า เมื่อไหร่ ก็ตาม เรา เปิดโปรแกรม Blynk แล้วเชื่อมต่อเข้า MCU ก็จะเกิดการหยุดทำงาน ของ MCU จนกว่าเราจะกดปุ่มใด้ ที่โปรแกรม Blynk หรือ กด Start คำสั่ง Timer ก็จะทำงานต่อ

ผมเข้าใจแบบนี้ ถูกต้องไหมครับ

ผมก็ชักจะงง และสิ รอ @mrBov มาขยายความอีกสักหน่อยนะครับ

555 งานอธิบายเป็นงานยากสำหรับผมจริงๆ ครับ
เอาเป็นว่า ถ้าไม่มีการกดปุ่ม play ที่แอพ blynk ระบบการควบคุมด้วย nodeMCU 8266 ที่สั่งงานไปที่ Relay ทำงานได้อย่างไม่มีที่ติครับ
แต่สมมุติว่า ขณะที่ Relay ที่ถูกสั่งให้ทำงานอยู่ คือผมใช้ฝั่ง NO ต่อ ตามโปรแกรมใน mcu และตามเวลาที่ตั้งไว้ ทันทีที่ผมกดปุ่ม play ที่แอพ blynk ปั๊บ Relay ที่ต่ออยู่ จะเปลียนสถานะการทำงานเป็นการตัดวงจรทันที ทั้งๆ ที่เวลาอยู่ในเงื่อนไขของโปรแกรมที่เขียนไว้ ถึงจะรอให้มีการอ่านค่า Virtual Pin แล้ว ก็ยังไม่ทำงานตามโปรแกรม แต่ถ้าผมกดสั่ง ON บน GPIO button จากแอพ blynk วงจรก็จะกลับมาทำงานได้อีกครับ

ใช้คำสั่งคืนค่าต่างๆที่ ESP กำลังทำงานอยู่ บน server ของ Blynk กลับมาที่มือถือของเรา ทุกครั้งที่ connect กับ โปรแกรม Blynk ก็น่าจะแก้ปัญหาได้ครับ

ปกติถ้าเรา Disconnect มือถือออกจาก Blynk โปรแกรมใน Node ESPกับ Blynk จะยังคงทำงานไปเรื่่อย แต่เมื่อไรที่เรา Connect มือถือ ( login Blynk ) blynk server จะมาดึงค่า setting จากมือถือเรา ไปตั้งค่าให้กับ Blynk Server กับ Node ESP เรา ( ค่า default ในการ login ทุกครั้ง จะ Off ทั้งหมด ) จึงเกิดอาการที่เป็นอยู่ปัจจุบัน

2 Likes

ที่คุณ @KD2NYY ตอบตรงกับ คำถามไหมครับ @mrBov

1 Like

ขอบคุณเพื่อนๆ ทั้งสองท่านมากครับ แสดงว่า process การอ่านค่า Virtual Pin กับงานที่เกิดขึ้นจริงมีการขัดแย้งกันใช่มั๊ยครับ รบกวนช่วยแนะนำวิธีการโค๊ดที่จะแก้ปัญหานี้หน่อยครับ
ขอบคุณครับ

ลองศึกษาตามข้อมูลในการใช้ Blynk ดูครับ ติดปัญหา หรือไม่เข้าใจ ตรงไหน เอาข้อมูลตรงจุดน้ำมาถามอีกที่ครับ

ขออภัยนะครับ ที่ไม่เจาะจงบอกตรงๆ ต้องการให้ทำความเข้าใน ในสิ่งที่ตัวเองทำครับ เพราะ ถ้าบอกกันเลย จะไม่มีการ พัฒนา เราก็จะกลายเป็นผู้รับตลอดเวลา

*** พ่อสอนอยู่เสมอ จงสอนให้เขาจับปลา แต่อย่าแจกปลา เพราะ แจกปลากินได้ไม่กี่วัน แต่สอนให้เขาจับปลา เขาจะมีกินตลอดชีวิต ไม่มีอดครับ **

1 Like