PDA

View Full Version : ESP8266 - dùng Blynk tắt mở theo điều kiện thời gian (time schedule)



CKD
10-06-2020, 03:54:15 PM
Chào các bạn!
Rất lâu rồi mới quay lại viết bài trên diễn đàn. Vì đã lâu không tham gia vào việc chế cháo cnc nên cũng không biết phải trao đổi thêm những gì.

Nay viết bài này cũng không liên quan gì đến CNC, mượn phòng Arduino để trao đổi/chia sẻ về việc lập trình ESP8266 một dự án mà mình có chia sẻ video trên youtube.

Nhu cầu là dùng ESP8266, lập lịch hẹn và tắt mở (relay chẵng hạn) theo lịch đã được lập trước đó.


https://www.youtube.com/watch?v=52MWqVxzYYw

Mô tả:

1. Lập trình Arduino, dùng phần cứng ESP8266. Kết nối qua wifi đến máy chủ Blynk.
2. Đăng ký tài khoản Blynk, tạo dự án mới (New Project), trong dự án đó có thêm vào

RTC (xem link (https://docs.blynk.cc/#widgets-other-rtc)) đã được config đúng múi giờ.
78234
Time Input (xem link (https://docs.blynk.cc/#widgets-interface-time-input)), tùy nhu cầu mà cài đặt, phần OUPUT đặt cho nó một Virtual PIN mà bạn muốn. Lưu ý xem thêm ấy cái ví dụ (VD 1 (https://github.com/blynkkk/blynk-library/blob/master/examples/Widgets/TimeInput/SimpleTimeInput/SimpleTimeInput.ino), VD 2 (https://github.com/blynkkk/blynk-library/blob/master/examples/Widgets/TimeInput/AdvancedTimeInput/AdvancedTimeInput.ino), VD 3 (https://github.com/blynkkk/blynk-library/blob/master/examples/Widgets/TimeInput/UpdateTimeInputState/UpdateTimeInputState.ino))
Thêm các Widgets hay ABC XYZ gì đó tùy bạn muốn.

3. Lập trình trên giao diện IDE cùa Arduino. Mấy phần khai báo, sử dụng, kết nối wifi, kết nối Blynk các bạn tự tham khảo thêm trên internet. Mình sẽ chỉ chi sẽ phần xử lý thời gian (time chedule) cho nó ngắn gọn.
Khai báo sử dụng thư viện, có 2 thư viện cần cho việc này: WidgetRTC.h và TimeLib.h (xem link (https://github.com/PaulStoffregen/Time)), ngoài ra còn các thư viện khác để có thể sử dụng ESP8266 và Blynk, các bạn tự thêm vào :D


// khai báo biến cần dùng
unsigned int TimeStart, TimeStop;
byte dayStartSelect = 0;
byte dayStopSelect = 0;

// timeInput là Virtual PIN mà mình đã setting trong dự án Blynk
// đoạn chương trình bên dưới sẽ tự động làm việc mỗi khi có sự thay đổi Time Input trên app Blynk

BLYNK_WRITE(timeInput)
{
TimeInputParam t(param); //blynk-library/src/WidgetTimeInput.h

// Process start time
if (t.hasStartTime())
{
TimeStart = t.getStartHour()*60 + t.getStartMinute();
}
else TimeStart = 0;

// Process stop time

if (t.hasStopTime())
{
TimeStop = t.getStopHour()*60 + t.getStopMinute();
}
else TimeStop = 0;

// Process Blynk TimeInput weekdays (1. Mon, 2. Tue, 3. Wed, 4. Thu, 5. Fri, 6. Sat, 7. Sun)
// Process RTC weekday(); (1. Sun, 2. Mon, 3. Tue, 4. Wed, 5. Thu, 6. Fri, 7. Sat)
// Bit dayStart/StopSelect (0. None 1. Sun, 2. Mon, 3. Tue, 4. Wed, 5. Thu, 6. Fri, 7. Sat)
dayStartSelect = 0;
dayStopSelect = 0;
for (int i = 1; i <= 7; i++)
{
if (t.isWeekdaySelected(i))
{
if (i == 7) bitWrite(dayStartSelect, 1, 1);
else bitWrite(dayStartSelect, i+1, 1);
if (TimeStop < Time1Start)
if (i == 6) bitWrite(dayStopSelect, 1, 1);
else if (i == 7) bitWrite(dayStopSelect, 2, 1);
else bitWrite(dayStopSelect, i+2, 1);
else
if (i == 7) bitWrite(dayStopSelect, 1, 1);
else bitWrite(dayStopSelect, i+1, 1);
}
}
}



// khai báo biến cần dùng
bool timeOnOff = false;

// đoạn chương trình sẽ kiểm tra điều kiện và bật/tắt biến timeOnOff

void TimeAuto()
{
unsigned int times = hour()*60 + minute();
byte today = weekday(); //the weekday now (Sunday is day 1, Monday is day 2)

if (bitRead(dayStartSelect, today))
{
if (TimeStart == TimeStop) timeOnOff = false;
else if (TimeStart <= times) timeOnOff = true;
}
if (bitRead(dayStopSelect, today))
{
if ((TimeStart < TimeStop ) && (TimeStop <= times)) timeOnOff = false;
if ((TimeStop < TimeStart) && (TimeStop <= times) && (times < TimeStart)) timeOnOff = false;
if ((TimeStop < TimeStart) && !bitRead(dayStartSelect, today) && (TimeStop <= times)) timeOnOff = false;
}
}
void TimeAuto() sẽ đặt vào trong void loop của chương trình chính.
kiểm tra biến timeOnOff và thực thi công việc tùy theo nhu cầu (tắt mở relay chẵng hạn)

Chúc các bạn thành công!

CKD
11-06-2020, 01:01:33 PM
Cập nhật full code để anh em thử nghiệm nhe.
Soft dùng Arduino IDE
Hardware dùng ESP8266 V1



/************************************************** ***********
* Ví dụ tắt mở theo lịch hẹn trước
* Người viết: Phạm Duy Anh - phamduyanh@gmail.com
* Chia sẻ trên: cncprovn.com và youtube
*
* Ví dụ được tạo từ Example -> Blynk -> Boards_Wifi -> ESP8266_Standalone
* Mạch dùng ESP8266 V1, dung lượng 1MB, không có LED built IN.
* Do đó mình sẽ dùng widget displays LED để hiển thị trạng thái biến timeOnOff
* Đồng thời dùng Serial Monitor để theo dõi trạng thái TimeInput và timeOnOff
*
* Thư viện cần thêm:
* #include <TimeLib.h>
* #include <WidgetRTC.h>
*
* Thay đổi theo nhu cầu các biến:
* YourAuthToken
* YourNetworkName
* YourPassword
* #define LEDV V0 // hiển thị trạng thái biến timeOnOff
* #define timeShow V1 // hiển thị thời gian thự của thiết bị
* #define timeInput V2 // nhận dữ liệu cài đặt thời gian
*
* Khởi tạo các Widget
* WidgetLED LED(LEDV);
* WidgetRTC rtc;
*
* Chương trình
* showTime() // hiển thị thời gian thự của thiết bị mỗi giây một lần
* TimeAuto() // so sánh thời gian thực và lịch cài đặt
* twoDigits(int digits) // chuyển đổi thành 2 ký tự
*
* Lưu ý:
* Việc truy cập blynk chỉ nên thực hiện mỗi giây/lần hoặc chậm hơn.
*
************************************************** ***********/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h> //https://github.com/PaulStoffregen/Time
#include <WidgetRTC.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "YourAuthToken";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";

// khai báo biến cần dùng
bool timeOnOff = false;
bool oldtimeOnOff;
bool isFirstConnect;
unsigned int TimeStart, TimeStop;
byte dayStartSelect = 0;
byte dayStopSelect = 0;

int oldSecond, nowSecond;

#define LEDV V0 // hiển thị trạng thái biến timeOnOff
#define timeShow V1 // hiển thị giờ thật của thiết bị
#define timeInput V2 // nhận dữ liệu cài đặt thời gian
#define PinOut 2 //led built in

WidgetLED LED(LEDV);
WidgetRTC rtc;

void setup()
{
// Debug console
Serial.begin(9600);
Blynk.begin(auth, ssid, pass);

pinMode(PinOut, OUTPUT);
digitalWrite(PinOut, !timeOnOff);
}

void loop()
{
Blynk.run();
TimeAuto();
showTime();
}

BLYNK_CONNECTED()
{
Blynk.syncAll();
rtc.begin();
}

// timeInput là Virtual PIN mà mình đã setting trong dự án Blynk
// đoạn chương trình bên dưới sẽ tự động làm việc mỗi khi có sự thay đổi Time Input trên app Blynk

BLYNK_WRITE(timeInput)
{
Serial.println("Time Input");
TimeInputParam t(param); //blynk-library/src/WidgetTimeInput.h

// Process start time
if (t.hasStartTime())
{
TimeStart = t.getStartHour()*60 + t.getStartMinute();
}
else TimeStart = 0;

// Process stop time

if (t.hasStopTime())
{
TimeStop = t.getStopHour()*60 + t.getStopMinute();
}
else TimeStop = 0;

// Process Blynk TimeInput weekdays (1. Mon, 2. Tue, 3. Wed, 4. Thu, 5. Fri, 6. Sat, 7. Sun)
// Process RTC weekday(); (1. Sun, 2. Mon, 3. Tue, 4. Wed, 5. Thu, 6. Fri, 7. Sat)
// Bit dayStart/StopSelect (0. None 1. Sun, 2. Mon, 3. Tue, 4. Wed, 5. Thu, 6. Fri, 7. Sat)
dayStartSelect = 0;
dayStopSelect = 0;
for (int i = 1; i <= 7; i++)
{
if (t.isWeekdaySelected(i))
{
if (i == 7) bitWrite(dayStartSelect, 1, 1);
else bitWrite(dayStartSelect, i+1, 1);
if (TimeStop < TimeStart)
if (i == 6) bitWrite(dayStopSelect, 1, 1);
else if (i == 7) bitWrite(dayStopSelect, 2, 1);
else bitWrite(dayStopSelect, i+2, 1);
else
if (i == 7) bitWrite(dayStopSelect, 1, 1);
else bitWrite(dayStopSelect, i+1, 1);
}
}
}

// đoạn chương trình sẽ kiểm tra điều kiện và bật/tắt biến timeOnOff

void TimeAuto()
{
unsigned int times = hour()*60 + minute();
byte today = weekday(); //the weekday now (Sunday is day 1, Monday is day 2)

if (bitRead(dayStartSelect, today))
{
if (TimeStart == TimeStop) timeOnOff = false;
else if (TimeStart <= times) timeOnOff = true;
}
if (bitRead(dayStopSelect, today))
{
if ((TimeStart < TimeStop ) && (TimeStop <= times)) timeOnOff = false;
if ((TimeStop < TimeStart) && (TimeStop <= times) && (times < TimeStart)) timeOnOff = false;
if ((TimeStop < TimeStart) && !bitRead(dayStartSelect, today) && (TimeStop <= times)) timeOnOff = false;
}
}

void showTime()
{
nowSecond = second();
if (oldSecond != nowSecond)
{
oldSecond = nowSecond;

String currentTime;
if (isPM()) currentTime = twoDigits(hourFormat12()) + ":" + twoDigits(minute()) + ":" + twoDigits(second()) + " PM";
else currentTime = twoDigits(hourFormat12()) + ":" + twoDigits(minute()) + ":" + twoDigits(second()) + " AM";
Blynk.virtualWrite(timeShow, currentTime);

if (oldtimeOnOff != timeOnOff)
{
if (timeOnOff)
{
LED.on();
digitalWrite(PinOut, !timeOnOff);
Serial.println("Time schedule is ON");
}
else
{
LED.off();
digitalWrite(PinOut, !timeOnOff);
Serial.println("Time schedule is OFF");
}
oldtimeOnOff = timeOnOff;
}
}
}

String twoDigits(int digits)
{
if(digits < 10) return "0" + String(digits);
else return String(digits);
}

anhcos
12-06-2020, 08:11:02 AM
Ngon quá Duy Anh, code này quá phù hợp vì a đang làm cái nhà kính với giàn năng lượng xanh, để demo là chủ yếu.
Xài một số cảm biến nhiệt độ, độ ẩm bức xạ,... cả nồng độ khí Co2 nữa do nhà là hệ thống kín.

CKD
12-06-2020, 10:33:01 AM
Ngon quá Duy Anh, code này quá phù hợp vì a đang làm cái nhà kính với giàn năng lượng xanh, để demo là chủ yếu.
Xài một số cảm biến nhiệt độ, độ ẩm bức xạ,... cả nồng độ khí Co2 nữa do nhà là hệ thống kín.

A dùng cảm biến gì thế?

anhcos
12-06-2020, 11:03:11 AM
Cứ mỗi cảm biến sẽ mua cả cái phổ thông và cái tốt để so sánh và lấy dữ liệu về rồi tinh chỉnh sao cho ổn định.
VD đo độ ẩm/nhiệt độ thì mua cả cái chỉ có nhiệt độ, cái chỉ có độ ẩm và cả loại kết hợp.

CKD
27-06-2020, 02:48:40 PM
Nội dung code phía trên có một lỗi là khi nó đang vận hành mà mình vọc cái Time Input thì có một số trường hợp nó chạy sai.
Mình đã viết lại đoãn code mới với cách giải kiểu khác. Kết quả đã sửa (fix) được lỗi trên.

Ngày trong tuần nếu được chọn thì sẽ là ngày để mở.
Thời gian cài đặt mở sẽ so sánh với thời gian thực. Thời gian tắt thì tùy, nếu thời gian tắt có giá trị bé hơn thời gian mở thì sẽ là trường hợp mở vào tối hôm nay và tắt vào sáng ngày mai. Tính năng này cũng đã được kiểm tra Ok.

Lỗi cụ thể thế nào thì các bạn xem clip nhe :D


https://www.youtube.com/watch?v=OK91Vt2pfX4

Phần code thế này, copy & pate thay thế cho cả cái function BLYNK_WRITE(timeInput) và TimeAuto()

copy & pate TimeAuto()


void TimeAuto()
{
unsigned int times = hour()*60 + minute();
byte today = weekday(); //the weekday now (Sunday is day 1, Monday is day 2)

if (TimeStart == TimeStop)
{
timeOnOff = false;
}
else if (TimeStart < TimeStop)
if (bitRead(dayStartSelect, today - 1))
if ((TimeStart <= times) && (times < TimeStop)) timeOnOff = true;
else timeOnOff = false;
else timeOnOff = false;
else if (TimeStart > TimeStop)
{
if ((TimeStop <= times) && (times < TimeStart)) timeOnOff = false;
else if ((TimeStart <= times) && bitRead(dayStartSelect, today - 1)) timeOnOff = true;
else if ((TimeStop > times) && bitRead(dayStopSelect, today)) timeOnOff = true;
}
}

copy & pate BLYNK_WRITE(timeInput)


BLYNK_WRITE(timeInput)
{
Serial.println("Time Input");
TimeInputParam t(param); //blynk-library/src/WidgetTimeInput.h

// Process start time
if (t.hasStartTime())
{
TimeStart = t.getStartHour()*60 + t.getStartMinute();
}
else TimeStart = 0;

// Process stop time

if (t.hasStopTime())
{
TimeStop = t.getStopHour()*60 + t.getStopMinute();
}
else TimeStop = 0;


// Process Blynk TimeInput weekdays 7. Sun, 1. Mon, 2. Tue, 3. Wed, 4. Thu, 5. Fri, 6. Sat
// Process RTC weekday(); 1. Sun, 2. Mon, 3. Tue, 4. Wed, 5. Thu, 6. Fri, 7. Sat
// Bit dayStartSelect 0. Sun, 1. Mon, 2. Tue, 3. Wed, 4. Thu, 5. Fri, 6. Sat
// Bit dayStopSelect = dayStartSelec + 1 0. None, 1. Sun, 2. Mon, 3. Tue, 4. Wed, 5. Thu, 6. Fri, 7. Sat
dayStartSelect = 0;
dayStopSelect = 0;
for (int i = 1; i <= 7; i++)
if (t.isWeekdaySelected(i))
if (i == 7)
{
bitWrite(dayStartSelect, 0, 1);
bitWrite(dayStopSelect, 1, 1);
}
else
{
bitWrite(dayStartSelect, i, 1);
bitWrite(dayStopSelect, i+1, 1);
}
}