Home Blog [Nhà Ngu] Hướng dẫn tự làm Công tắc WIFI với Blynk

[Nhà Ngu] Hướng dẫn tự làm Công tắc WIFI với Blynk

0
[Nhà Ngu] Hướng dẫn tự làm Công tắc WIFI với Blynk

Điều khiển thiết bị bằng WIFI hay Công tắc WIFI là một ứng dụng cơ bản nhất của Smart Home. Với Blynk chúng ta sẽ thiết kế một bộ công tắc Wifi dùng trong hệ sinh thái “Nhà Ngu”. Nếu bạn chưa biết Nhà Ngu là gì thì hãy đọc bài viết: Tự làm Smart Home mang tên Nhà Ngu

Trước tiên hãy cứ bắt đầu từ việc đơn giản nhất, đó là bật tắt thiết bị như thế nào đã.

Ok, bắt đầu nhé.

Tạo code với Blynk examples

Để chế tạo một công tắc wifi thông minh, chúng ta sẽ sử dụng các công cụ của Blynk Platform.

Blynk hỗ trợ chúng ta rất nhiều trong việc viết code, các bạn truy cập vào link: Examples.blynk.cc

Trong đó là các bài Code, cho từng loại Board và ứng dụng khác nhau.

Chúng ta truy cập vào link trên, Chọn Board là Node MCU, chọn Connection là ESP8266 WIFI, Auth Token cứ để trống, và chọn Exam là Blynk Blink.

Khi đó Blynk sẽ tự Gen ra một đoạn Code.

Blynk Exam

Các bạn nhấn vào Coppy Example sau đó mở Arduino lên và paste vào.

Đổi SSID là tên WIFI nhà bạn, PASS là mật khẩu WIFI nhà bạn.

Sửa code blynk

Auth Token chính là mã ứng dụng của bạn để truy cập vào Blynk API. Cách lấy như sau:

Đăng nhập vào Blynk, nhấn New Project -> Đặt tên dự án, dòng chip Node MCU, kiểu kết nối là WIFI-> Nhấn Create, Blynk sẽ gửi mail về gmail đăng kí Blynk của bạn.

 Blynk-project    Blynk-project   Blynk Token

Coppy mã đó dán vào ô. Auth TokenAuth Token

Tool-Chọn Board Node MCU

Chon board

Sau đó chọn Port và nạp như Arduino bình thường.

Điều khiển LED bằng App Blynk

Blynk hỗ trợ làm công tắc Wifi bằng các Widget, trong bài này chúng ta sử dụng Button Widget. Mỗi một widget sẽ phải mua bằng Enegy, nếu hết Enegy bạn phải bỏ tiền ra mua. Nhưng đừng lo Blynk hỗ trợ cho mỗi Account 1000 enegy, như vậy cũng thoải mái để tạo 1 chiếc công tắc wifi rồi.

Sau khi nạp code vào cho Node MCU, chúng ta mở App Blink

  • Chọn Project vừa tạo. Nhân nút Play (Hình tam giác)
  • Nếu Node MCU được config đúng, App sẽ báo Nha Ngu IOT online
  • Nhấn nút hình vuông (Vị trí nút play vừa nãy) để trở về cửa sổ thiết kế. Nhấn nút cộng để vào Widget Box
  • Chọn Button, nút nhấn sẽ được đưa ra ngoài màn hình. Nhấn vào hình nút nhấn để config

8 Blynk Connect9 Blynk Connect10 Blynk Widget12 Blynk button

Trong phần config Button

  • Thay đổi tên: Cong tac 1. MODE là SWITCH
  • Phần OUTPUT, click vào PN chọn D4. Chính là con led có sẵn trên Node MCU

11 Blynk button13 Blynk button

Nhấn OK và nhấn Play để chạy thử như sau:

Điều khiển LED bằng nút nhấn thực tế

Công tắc WIFI thì ngoài việc điều khiển trên app, thì phải điều khiển được bằng tay nữa. Chúng ta sẽ bắt đầu code phần điều khiển bằng tay nhé.

Chúng ta sẽ sử dụng nút nhấn có sẵn trên Node MCU để điều khiển con LED D4. Trong Pinout Node MCU ta thấy Button đó là D3 (Flash)

NodeMCU ESP8266 Pinout

Đầu tiên, định ngh ĩa D3 là Button, D4 là LED, một biến trạng thái LED là Status = 1 (LED tắt)

Dieu khien thiet bi bang wifi voi Blynk

Trong hàm setup chọn pinmode và ghi giá trị ban đầu cho LED

Dieu khien thiet bi bang wifi voi Blynk (2)

Trong loop() chúng ta kiếm tra nút nhấn Button xem đã được nhấn chưa, Nếu được nhấn thì đảo trạng thái Status và ghi vào LED D4

Dieu khien thiet bi bang wifi voi Blynk 3

Nạp chương trình và test

Vậy là ta đã có thể điều khiển được thiết bị qua cả App và nút nhấn thực tế, nhưng có một lỗi phát sinh đó là. Khi ta thay đổi trạng thái LED bằng nút nhấn, trên App sẽ không biết là chúng ta thay đổi, nên không cập nhật leed App. Điều này làm việc điều khiển trở nên ngu ngu, vì lâu lâu lại phải ấn 2 lần trên App mới chuyển được trạng thái.

Vậy sửa lỗi này như thế nào. Ta đến phần sau nhé

Đồng bộ nút nhấn và App trên công tắc WIFI

Một chiếc công tắc thông minh thì phải giao tiếp được giữa người và thiết bị. Khi con người nhấn nút trên App thì mạch phải phản hồi và ngược lại, khi con người nhấn nút nhấn trên mạch thì App cũng phải cập nhật. Việc giao tiếp qua lại đó gọi là đồng bộ.

Nguyên lý làm việc như sau:

App và Node MCU sẽ giao tiếp với nhau thông qua 1 cổng Vitual (Một luồng dữ liệu)

Khi cổng Vitual này thay đổi giá trị => Mạch sẽ cập nhật và thay đổi giá trị vào D4 (LED) => Khi mạch ghi giá trị lên cổng Vitual, trên App cũng sẽ thay đổi trạng thái

Đầu tiên, ta phải sửa Button trên App là 1 cổng Vitual  thay vì D4.

cong ao blynk

Thêm 2 biến điều khiển. Thêm các câu lệnh như sau:

đồng bộ nút nhấn blynk 1

Trong đó biến:

  • VIRTUAL_PIN_0 dùng để đọc dữ liệu từ cổng V0
  • isPushOnApp: là biến kiểm tra nút nhấn trên App có được ấn hay không
  • HBLYNK_CONNECTED: là hàm thực thi lệnh đồng bộ tất cả trạng thái trên App và mạch, khi chúng kết nối với nhau
  • BLYNK_WRITE(V0): Hàm thực thi khi App ghi dữ liệu vào V0. Ghi giá trị V0 vào biến VIRTUAL_PIN_0. Thay đổi giá trị isPushOnApp = true để báo rằng có nút nhấn được nhấn.

Trong loop. Chúng ta thực hiện như sau

đồng bộ nút nhấn blynk

Khi trên App được nhấn, ta ghi giá trị của V0 lên LED

Khi nút nhấn trên Board được nhấn, ta ghi giá trị lên LED và Ghi giá trị lên V0 trả về App.

Nạp chương trình và chạy thử.

Config wifi không cần code, sử dụng wifimanager

Làm sao có thể kết nối wifi bằng điện thoại mà ko cần phải sửa code. Bạn có thấy các sản phẩm Công tăc WIFI như Sonoff, Xaomi, Tuya … người ta phải nạp code ko? không hề nhé.

Vậy làm như thế nào để chúng ta có thể làm vậy. Có 2 cách ESP8266 hỗ trợ đó là:

Với smart config chúng ta cần phải tự viết App rồi thêm code smartconfig vào, nhưng dự án này dùng Blynk, và Blynk V1 này không hỗ trợ làm việc đó. Vậy nên chúng ta sẽ sử dụng phương án 2, AP config.

AP config là gì?

AP hay Accesspoint là một điểm truy cập wifi, nghĩa là chúng ta sẽ biến ESP8266 thành 1 điểm truy cập wifi. Việc tiếp theo là dùng smartphone, kết nối vào mạng wifi đó, sau đó là điền thông tin vào và truyền ngược lại ESP8266.
Khi nhận được dữ liệu truyền về, ESP8266 sẽ thoát khỏi AP mode và vào lại chế độ Station mode và truy cập vào wifi nhà bạn như bình thường.’

Vậy để làm việc đó một cách đơn giản chúng ta sẽ sử dụng thư viện wifimanager

Cài đặt Wifimanager và ArduinoJson

Để download wifimanager chúng ta vào link: https://github.com/tzapu/WiFiManager

Tiếp đó chúng ta download thư viện ArduinoJson, nhớ chọn V5.0.0 nhé vì nó mới tương thích với thư viện Wifimanager

json

 

Clone hoặc Down zip về, sau đó cài đặt vào thư viện Arduino. Xem hướng dẫn tại đây: Cài thư viện Arduino

Lập trình Wifi Config

Tiếp tục, để lập trình wifi config ta sẽ follow theo các bước sau:

  • Khi khởi động, đọc dữ liệu được ghi sẵn trong bộ nhớ, nếu có dữ liệu, dùng nó để login vào Blynk.
  • Nếu không có dữ liệu, nhảy vào ap mode
  • Nhập thông tin wifi và blynk token
  • Kết nối với wifi và blynk token đó

Một số lưu ý khi lập trình

  • Khi wifi được kết nối với một mạng, nó sẽ được tự động lưu lại, vì thế bạn không cần lưu wifi và mật khẩu vào bộ nhớ
  • Để xóa wifi được lưu chúng ta dùng lệnh WiFi.disconnect();
  • Để xóa tất cả các file trong bộ nhớ dùng lệnh SPIFFS.format();

Đầu tiên, thêm các thư viên

wifimanager 1

Khởi tạo hàm tick để nháy led, báo cho user biết đang trong trạng thái nào. Sử dụng Ticker để để set thời gian nháy bằng hàm: ticker.attach(time, tick);

  • Nháy chậm 0.6s: Đang đọc bộ nhớ và phát wifi bằng AP mode
  • Nháy nhanh 0.2s: Đang ở AP mode, điện thoại đang kết nối với Wifi phát ra
  • Bật: Kết nối Blynk thành công
  • Tắt: Kết nối với Blynk thất bại

tick

Khởi tạo các hàm callback khi vào chế độ AP mode

wifimanager 2

Hàm reset xóa bộ nhớ và ngắt kết nối với wifi cũ

wifimanager 3

Khởi tạo các nguyên mẫu hàm để sử dụng.

wifimanager 4

Kiểm tra trong bộ nhớ có file config.json hay không, nếu có thì parse ra chuỗi và copy ra biến blynk_token

wifimanager 5

Setup Wifimanager, với blynk_token được truyền vào custom_blynk_token. Nếu thiết bị đã được connect với wifi, nó sẽ kết nối với wifi đó và sử dụng blynk_token để truy cập vào Blynk server.
Nếu chưa nhập wifi, sẽ tự động chuyển qua AP mode, với Tên Wifi là Nhà Ngu Công Tắc 1 và pass là 123456789.

Nếu nhập tất cả đúng sẽ connected được, nếu nhập sai wifi và pass ESP sẽ tự reset.

 

wifimanager 6

Sau khi connect thành công, lưu lại blynk_token vào bộ nhớ Flash bằng SPIFFS

wifimanager 7

Tiếp tới connect với Blynk server, nếu connect đúng API led sẽ sáng và hoạt động được luôn. Nếu sai token, đèn sẽ tắt.

wifimanager 8

Để kết nối với mạng wifi khác hoặc app blynk khác,cần xóa wifi và bynk_token, nhấn nút Reset (Nút flash trên kit) ESP sẽ format dữ liệu trong flash và disconnect wifi hiện tại.

wifimanager 9

Hướng dẫn setup wifi

Đầu tiên khi bật lên led sẽ nháy chậm, các bạn connect vào wifi mà ESP phát ra, gõ mật khẩu.

Tiếp tới mở trình duyệt, gõ 192.168.4.1 nếu không tự động được bật lên

Nhập wifi, mật khẩu nhà bạn và mã auth blynk token trong app.

Nhấn kết nối, nếu thành công led sẽ luôn sáng, nếu thất bại led sẽ tắt

Chuẩn bị phần cứng và Source Code

Ở đây mình sử dụng phím touch pad 5k mua ở shopee, với một cái mặt kính công tắc wifi cũng shopee

Nút nhấn ttp các bạn hàn nối điểm A để cho nó ở chế độ nhấn nhả (push) nhé, nếu để mặc định sẽ là kiểu switch.

z2749368262492 01bf4da5a900917db03bc01683a2da1c min

Sau đó dùng băng keo dán vào sau của mặt kính.

z2749368919216 296171a899f690d2c3f8056b8e66eb71 min

Tiếp tới để điều khiển đèn, chúng ta sử dụng module Relay 5V

z2749368872986 1ba6767f8550eb7f067ec5a3e1d8f5d1 min

Cuối cùng là 1 cái nguồn 5V bất kì như sạc điện thoại, pin….

Kết nối nút nhấn với D1, D2, D5 relay với D6, D7, D8. D3 là nút reset mạng và D4 là led trên mạch

Nạp code sau đây và xem kết quả


#include <Arduino.h>
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager
#include <Ticker.h>
#include <ArduinoJson.h>          //https://github.com/bblanchon/ArduinoJson

#define BUTTON_RS D3 // reset
#define LED D4  // led 

#define BUTTON1 D1 
#define BUTTON2 D2
#define BUTTON3 D5 

#define Den1 D6
#define Den2 D7
#define Den3 D8

Ticker ticker;
char blynk_token[34] = "";
bool shouldSaveConfig = false;
boolean checkData = false;

//define vitual pin value
int VIRTUAL_PIN_0;
int VIRTUAL_PIN_1;
int VIRTUAL_PIN_2;
int VIRTUAL_PIN_3;
int OLD_VIRTUAL_PIN_0;
int OLD_VIRTUAL_PIN_1;
int OLD_VIRTUAL_PIN_2;
int OLD_VIRTUAL_PIN_3;

//synching app
BLYNK_CONNECTED() 
{
  Blynk.syncAll();
}
BLYNK_WRITE(V0)
{
  VIRTUAL_PIN_0 = param.asInt();
  checkData = true;
}
BLYNK_WRITE(V1)
{
  VIRTUAL_PIN_1 = param.asInt();
  checkData = true;
}
BLYNK_WRITE(V2)
{
  VIRTUAL_PIN_2 = param.asInt();
  checkData = true;
}
BLYNK_WRITE(V3)
{
  VIRTUAL_PIN_3 = param.asInt();
  checkData = true;
}

//prototype function
void tick();
void configModeCallback (WiFiManager *myWiFiManager);
void saveConfigCallback ();
void clearConfigToken(void);

//begin program
void setup() 
{
  Serial.begin(9600);
  pinMode(BUILTIN_LED, OUTPUT);
  ticker.attach(0.6, tick);
  
  //load config, if new start config
  Serial.println("mounting FS...");
  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");
      File configFile = SPIFFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // Allocate a buffer to store contents of the file.
        std::unique_ptr<char[]> buf(new char[size]);
        configFile.readBytes(buf.get(), size);
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject(buf.get());
        json.printTo(Serial);
        if (json.success()) {
          Serial.println("nparsed json");
          strcpy(blynk_token, json["blynk_token"]);

        } else {
          Serial.println("failed to load json config");
        }
        configFile.close();
      }
    }
  } else {
    Serial.println("failed to mount FS, no config");
  }
  
  //setup wifi manager
  WiFiManagerParameter custom_blynk_token("blynk", "Blynk Token", blynk_token, 32);
  WiFiManager wifiManager;
  wifiManager.setSaveConfigCallback(saveConfigCallback);
  wifiManager.addParameter(&custom_blynk_token);

  //Turn on AP mode 
  wifiManager.setAPCallback(configModeCallback); 
  if (!wifiManager.autoConnect("Nha Ngu Cong tac 1","123456789")) {
    Serial.println("failed to connect and hit timeout");
    //reset and try agai
    ESP.reset();
    delay(1000);
  }

  //if you get here you have connected to the WiFi 
  Serial.println("connected...yeey :)");
  ticker.detach();
  //turn off led blink
  strcpy(blynk_token, custom_blynk_token.getValue());
  //if the first time, save the config
  if (shouldSaveConfig) {
    Serial.println("saving config");
    DynamicJsonBuffer jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();
    json["blynk_token"] = blynk_token;

    File configFile = SPIFFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }

    json.printTo(Serial);
    json.printTo(configFile);
    configFile.close();
    //end save
  }
  Serial.println("local ip");
  Serial.println(WiFi.localIP());

  //Set up button and light
  pinMode(Den1, OUTPUT);
  pinMode(Den2, OUTPUT);
  pinMode(Den3, OUTPUT);
  pinMode(BUTTON1, INPUT_PULLUP);
  pinMode(BUTTON2, INPUT_PULLUP);
  pinMode(BUTTON3, INPUT_PULLUP);
  pinMode(BUTTON_RS, INPUT_PULLUP);

  //Connect to Blynk
  Serial.println("BLYNK Connecting...");
  Blynk.config(blynk_token);
  bool result = Blynk.connect();
  if (result != true)
  {
    Serial.println("BLYNK Connection Fail");
    digitalWrite(BUILTIN_LED, HIGH); 
  }
  else
  {
    Serial.println("BLYNK Connected");
    digitalWrite(BUILTIN_LED, LOW);  
  }
  //set giá trị ban đầu cho V pin
  OLD_VIRTUAL_PIN_0 = VIRTUAL_PIN_0;
  OLD_VIRTUAL_PIN_1 = VIRTUAL_PIN_1;
  OLD_VIRTUAL_PIN_2 = VIRTUAL_PIN_2;
  OLD_VIRTUAL_PIN_3 = VIRTUAL_PIN_3;
}
void loop() {
  Blynk.run();
  if (checkData == true) 
  {
    if(VIRTUAL_PIN_3 != OLD_VIRTUAL_PIN_3)
    {
      Serial.println("Nhan tren APP V3:" + String(VIRTUAL_PIN_3));
      VIRTUAL_PIN_0 = 1;
      VIRTUAL_PIN_1 = 1;
      VIRTUAL_PIN_2 = 1;
      Blynk.virtualWrite(V0, VIRTUAL_PIN_0);
      Blynk.virtualWrite(V1, VIRTUAL_PIN_1);
      Blynk.virtualWrite(V2, VIRTUAL_PIN_2);
      OLD_VIRTUAL_PIN_3 = VIRTUAL_PIN_3;
    }
    if(VIRTUAL_PIN_0 != OLD_VIRTUAL_PIN_0)
    {
      Serial.println("Nhan tren APP V0:" + String(VIRTUAL_PIN_0));
      digitalWrite(Den1, VIRTUAL_PIN_0);
      OLD_VIRTUAL_PIN_0 = VIRTUAL_PIN_0;
    }
    if(VIRTUAL_PIN_1 != OLD_VIRTUAL_PIN_1)
    {
      Serial.println("Nhan tren APP V1:" + String(VIRTUAL_PIN_1));
      digitalWrite(Den2, VIRTUAL_PIN_1);
      OLD_VIRTUAL_PIN_1 = VIRTUAL_PIN_1;
    }
    if(VIRTUAL_PIN_2 != OLD_VIRTUAL_PIN_2)
    {
      Serial.println("Nhan tren APP V2:" + String(VIRTUAL_PIN_2));
      digitalWrite(Den3, VIRTUAL_PIN_2);
      OLD_VIRTUAL_PIN_2 = VIRTUAL_PIN_2;
    }
    checkData == false;
  }
  if (digitalRead(BUTTON1) == 0)
  {
    delay(100);
    if (digitalRead(BUTTON1) != 0)
    {
      VIRTUAL_PIN_0 = !VIRTUAL_PIN_0;
      Blynk.virtualWrite(V0, VIRTUAL_PIN_0);
      digitalWrite(Den1, VIRTUAL_PIN_0);
      Serial.println("Nhan tai Board V0:" + String(VIRTUAL_PIN_0));
    }
  }
  if (digitalRead(BUTTON2) == 0)
  {
    delay(100);
    if (digitalRead(BUTTON2) != 0)
    {
      VIRTUAL_PIN_1 = !VIRTUAL_PIN_1;
      Blynk.virtualWrite(V1, VIRTUAL_PIN_1);
      digitalWrite(Den2, VIRTUAL_PIN_1);
      Serial.println("Nhan tai Board V1:" + String(VIRTUAL_PIN_1));
    }
  }
  if (digitalRead(BUTTON3) == 0)
  {
    delay(100);
    if (digitalRead(BUTTON3) != 0)
    {
      VIRTUAL_PIN_2 = !VIRTUAL_PIN_2;
      Blynk.virtualWrite(V2, VIRTUAL_PIN_2);
      digitalWrite(Den3, VIRTUAL_PIN_2);
      Serial.println("Nhan tai Board V2:" + String(VIRTUAL_PIN_2));
    }
  }
  if (digitalRead(BUTTON_RS) == 0)
  {
    delay(100);
    if (digitalRead(BUTTON_RS) != 0)
    {
      Serial.println("Wifi reset setting");
      SPIFFS.format();
      WiFi.disconnect();
      delay(1000);
      ESP.reset();
      delay(2000);
    }
  }
}

void tick()
{
  int state = digitalRead(BUILTIN_LED);  // get the current state of GPIO1 pin
  digitalWrite(BUILTIN_LED, !state);     // set pin to the opposite state
}

//gets called when WiFiManager enters configuration mode
void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
  //entered config mode, make led toggle faster
  ticker.attach(0.2, tick);
}
//gets called when save config
void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}
void clearConfigToken(void)
{
  Serial.println("Clear Token");
  DynamicJsonBuffer jsonBuffer;
  JsonObject& json = jsonBuffer.createObject();
  json["blynk_token"] = "Blynk_Token";
  File configFile = SPIFFS.open("/config.json", "w");
  Serial.println();
  if (!configFile) {
    Serial.println("failed to open config file for writing");
  }
  json.printTo(Serial);
  json.printTo(configFile);
  configFile.close();
}

 

Kết quả

Vậy là chúng ta đã hoàn thành sản phẩm đầu tiên trong dự án Nhà Ngu IOT, đây là một sản phẩm có thể sử dụng ngoài thực tế, trong gia đình bạn hàng ngày. Thế nhưng vẫn còn 1 số vấn đề như: làm sao để update firmware từ xa (FOTA) cho thiết bị, làm sao để kết nối nó với các môi trường khác để điều khiển qua giọng nói hay lập kịch bản bật tắt đèn.
Tất cả sẽ có trong các phần tiếp theo của dự án Nhà Ngu. Các bạn đón đọc nhé
Đừng quên like và chia sẻ bài viết này tới bạn bè. Và tham gia nhóm Nghiện lập trình để giao lưu và kết bạn với những anh em cùng đam mê.

Theo dõi fanpage của mình tại: https://www.facebook.com/khuenguyencreator
Kênh Youtube: https://www.youtube.com/channel/UCt8cFnPOaHrQXWmVkk-lfvg

4.7/5 – (11 bình chọn)

Rate this post