Energia – Bài 10: Thingspeak với ESP8266 và TIVA C

Mình xin giới thiệu cách để gửi dữ liệu lên thingspeak với TIVA C và ESP8266. Trong các bài viết trước mình có chia sẻ cách lấy dữ liệu với TIVA nhưng đây chỉ là cách cục bộ, tức là chỉ quan sát được tại chỗ, không thể giám sát và theo dõi từ xa được. Nhân tiện kết hợp được TIVA C và ESP8266 thì mình đã có trợ thủ đắc lực có thể giúp đỡ gửi dữ liệu lên trên mây thông qua internet, nhờ đó mình có thể giám sát được dữ liệu ở bất kỳ đâu.

Để dễ hình dung bạn có thể xem hình sau

Ta có thể thấy tất cả mọi thông tin về nhiệt độ, độ ẩm, ánh sáng,… sẽ được TIVA C thu thập, sau đó sẽ gửi lên internet thông qua Wifi ở đây là modul ESP8266, những thông tin được gửi lên sẽ được lưu lại trên một server, server có sẵn được chọn là thingspeak. Từ điện thoại và máy tính ở bất kỳ đâu thì ta cũng có thể truy cập vào thingspeak để quan sát được các thông số mà TIVA C đã gửi lên.

Chuẩn bị

Phần cứng

  • TIVA C Launchpad
  • Dây nối
  • ESP8266 phiên bản từ v1 tới v12 (mình dùng v1) dùng firmware AT command

Phần mềm

  • Energia IDE

Tạo tài khoản thingspeak

Bên thingspeak hơi làm khó chúng ta một chút là phải có tài khoản matwork, do đó mình cứ làm một tài khoản bên đó rồi đăng nhập sang bên này nhé.

Sau khi tạo xong tài khoản và đăng nhập thành công thì chọn New Channel để có kênh mới nhận dữ liệu

Chúng ta có tên, mô tả, và Field 1 – 8 là trường để nhận dữ liệu, thingspeak giới hạn tối đa 8 trường, do đó nếu muốn sử dụng hơn thì chắc phải chọn thằng khác hoặc tự dựng server, nhưng các bạn yên tâm, với 8 trường này thì đủ cho chúng ta có thể thử nghiệm rồi.

Tick chọn public nếu bạn muốn cho mọi người xem được kênh của mình

Phần quan trọng nhất còn lại là lấy API Key để Read và Write dữ liệu lên, bạn chọn vào thẻ API Keys, sau đó copy lại 2 mục Key chỗ Write/Read API Key đê sử dụng trong lập trình

Gửi dữ liệu bằng tay

Mình sẽ thử gửi dữ liệu bằng tay, gõ các đoạn mã gửi cho ESP8266 trước thông qua phần mềm sscom để kiểm tra xem có kết nối và đưa được dữ liệu lên thingspeak không ?

Ta sẽ thử gửi lệnh theo bảng mô tả dưới dây

Lệnh AT Phản hồi Mô tả
AT+CWMODE =1 OK Cài đặt chế độ station
AT+CWJAP = "ten_wifi", "pass" OK Kết nối với mạng wifi
AT+CIPMUX = 1 OK Cài đặt chế độ đa kết nối
AT+CIFSR OK Hiển thị IP
AT+CIPSTART=1,"TCP","184.106.153.149",80 OK Kết nối tới thingspeak địa chỉ 184.106.153.149, port 80 thông qua TCP
AT+CIPSEND=1,44 > Gửi gói tin TCP/IP với 1 là id, 44 là độ dài gói tin
GET /update?key=B549R51BLLQxxxx&field1=67 SEND OKOK Cập nhật thông số field1 với key Write của thingspeak

Kết quả ta sẽ thấy 1 điểm trên biểu đồ và phần update last entry sẽ là thời gian gần nhất

Gửi dữ liệu tự động


Tạm thời yên tâm là kết nối server, gửi dữ liệu thủ công lên đã ổn, giờ tranh thủ lập trình thêm một chút để TIVA C làm nhiệm vụ này thay cho chúng ta

Lại lục chút kiến thức bài cũ ra một chút, thử lại kết nối giữa TIVA C và ESP8266 xem có ổn không, nếu gửi AT nhận OK thì bắt đầu bước tiếp theo thôi

Bước 1: thực hiện lập trình kết nối server thingspeak, cách nối dây các bạn xem trong code luôn nhé

/* Chương trình giao tiếp giữa TIVA và ESP8266 dùng firmware AT-Command của ai-thinker
   Kết nối với server thingspeak
   Tạo bởi Hocarm.org
   Kết nối
   ESP8266   |  TIVA  | Nguồn ngoài
   VCC       |  x     | 3.3v
   GND       |  GND   | GND
   CH_PD     |  x     | 3.3v
   RX        |  PB1   | x
   TX        |  PB0   | x
   Tốc độ baud kết nối với ESP tùy thuộc vào baud của firmware.
*/
char IP[] = "184.106.153.149";
char msg[] = "GET /update?key=xxxxxxxxx"; //Thay xxxxxxxxx bằng key của bạn ở mục API Write key
char aux_str[100];
int leg;
void setup() {
  Serial.begin(115200);   //Cấu hình debug với baud 115200
  Serial1.begin(9600);    //Cấu hình giao tiếp với ESP8266 baud 9600
  sendATcommand("AT", "OK", 3000);                //Kiểm tra kết nối
  sendATcommand("AT+CWMODE=1", "OK", 3000);       //Cấu hình chế độ station
  sendATcommand("AT+CWJAP=\"ten_wifi\",\"mat_khau\"", "OK", 3000);  //Thay ten_wifi và mat_khau của bạn
  sendATcommand("AT+CIPMUX=1", "OK", 3000);       // Bật chế độ đa kết nối
  sendATcommand("AT+CIFSR", "OK", 3000); // Hiển thị ip
  //Kết nối tới server thingspeak
  snprintf(aux_str, sizeof(aux_str), "AT+CIPSTART=1,\"TCP\",\"%s\",80", IP);
  if (sendATcommand2(aux_str, "OK",  "ERROR", 30000) == 1)
  {
    Serial.println("OK Connected Thingspeak");
  }
  sendATcommand("AT+CIPCLOSE=1", "OK", 5000); //Đóng kết nối
}

void loop() {
//  sendATcommand("AT", "OK", 3000);
//  delay(1000);
}
// Hàm gửi lệnh AT
int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // xóa buffer

  delay(100);

  while ( Serial1.available() > 0) Serial1.read();   // đọc input

  Serial1.println(ATcommand);    // Gửi lệnh AT

  x = 0;
  previous = millis();

  // Chờ phản hồi
  do {
    if (Serial1.available() != 0) {
      // Nếu có dữ liệu trong buffer UART, đọc và kiểm tra nó với expected_answer
      response[x] = Serial1.read();
      x++;
      // Nếu đúng thì trả kết quả answer = 1, thoát hàm
      if (strstr(response, expected_answer) != NULL)
      {
        answer = 1;
      }

    }
  } while ((answer == 0) && ((millis() - previous) < timeout)); // Nếu sai thì tiếp tục thử lại cho tới hết thời gian timeout
  Serial.println(response);   // In giá trị nhận được để debug
  return answer;
}
// Hàm gửi lệnh AT 2 để gửi dữ liệu
int8_t sendATcommand2(char* ATcommand, char* expected_answer1,
                      char* expected_answer2, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Khởi tạo lại chuỗi về 0

  delay(100);

  while ( Serial1.available() > 0) Serial1.read();   // Xóa buffer

  Serial1.println(ATcommand);    // Gửi lệnh AT

  x = 0;
  previous = millis();

  // Chờ phản hồi
  do {
    // Nếu có dữ liệu từ UART thì đọc và kiểm tra 
    if (Serial1.available() != 0) {
      response[x] = Serial1.read();
      x++;
      // Trả về giá trị 1 nếu nhận được expected_answer1
      if (strstr(response, expected_answer1) != NULL)
      {
        answer = 1;
      }
      // Trả về giá trị 2 nếu nhận được expected_answer2
      else if (strstr(response, expected_answer2) != NULL)
      {
        answer = 2;
      }
    }
  }
  // Đợi time out
  while ((answer == 0) && ((millis() - previous) < timeout));
  Serial.println(response);   // In giá trị nhận được để debug
  return answer;
}

Kết quả

Bước 2: Thực hiện gửi dữ liệu lên field1 của thingspeak

/* Chương trình giao tiếp giữa TIVA và ESP8266 dùng firmware AT-Command của ai-thinker
   Kết nối với server thingspeak và gửi dữ liệu lên field1
   Tạo bởi Hocarm.org
   Kết nối
   ESP8266   |  TIVA  | Nguồn ngoài
   VCC       |  x     | 3.3v
   GND       |  GND   | GND
   CH_PD     |  x     | 3.3v
   RX        |  PB1   | x
   TX        |  PB0   | x
   Tốc độ baud kết nối với ESP tùy thuộc vào baud của firmware.
*/
char IP[] = "184.106.153.149";
char msg[] = "GET /update?key=xxxxxxxxx"; //Thay xxxxxxxxx bằng key của bạn ở mục API Write key
char aux_str[100];
char cmd[100];
int leg;
int number = 12; // Giá trị sẽ gửi lên thingspeak
void setup() {
  Serial.begin(115200);   //Cấu hình debug với baud 115200
  Serial1.begin(9600);    //Cấu hình giao tiếp với ESP8266 baud 9600
  sendATcommand("AT", "OK", 5000);                //Kiểm tra kết nối
  sendATcommand("AT+CWMODE=1", "OK", 5000);       //Cấu hình chế độ station
  sendATcommand("AT+CWJAP=\"ten_wifi\",\"mat_khau\"", "OK", 5000);  //Thay ten_wifi và mat_khau của bạn
  sendATcommand("AT+CIPMUX=1", "OK", 5000);       // Bật chế độ đa kết nối
  sendATcommand("AT+CIFSR", "OK", 5000); // Hiển thị ip
  //Kết nối tới server thingspeak
  memset(aux_str, '\0', 100);   //Đặt lại giá trị của aux_str
  snprintf(aux_str, sizeof(aux_str), "AT+CIPSTART=1,\"TCP\",\"%s\",80", IP);    //Kết nối server thingspeak
  if (sendATcommand2(aux_str, "OK",  "ERROR", 30000) == 1)
  {
    Serial.println("OK Connected Thingspeak");  //Kiểm tra nếu kết nối thì thông báo
  }
  //Gửi data lên thingspeak
  sprintf(cmd, "%s&field1=%d", msg, number);  //Gộp dữ liệu
  leg = strlen(cmd) + 2;                      // Tính chiều dài dữ liệu, +2 cho ký tự > và dấu cách
  sprintf(aux_str, "AT+CIPSEND=1,%d", leg);   //Gửi kết nối và chờ >
  if (sendATcommand2(aux_str, ">", "ERROR", 30000) == 1)
  {
    sprintf(cmd, "%s&field1=%d", msg, number); //Gửi toàn bộ thông tin có dạng GET /update?key=xxxxxx&field1=xx
    sendATcommand2(cmd, "SEND OK", "ERROR", 10000);
  }
  else
  {
    Serial.println("Failed"); //nếu không gửi được báo failed
  }
   sendATcommand("AT+CIPCLOSE=1", "OK", 5000); //Đóng kết nối
}

void loop() {
//  sendATcommand("AT", "OK", 3000);
//  delay(1000);
}
// Hàm gửi lệnh AT
int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // xóa buffer

  delay(100);

  while ( Serial1.available() > 0) Serial1.read();   // đọc input

  Serial1.println(ATcommand);    // Gửi lệnh AT

  x = 0;
  previous = millis();

  // Chờ phản hồi
  do {
    if (Serial1.available() != 0) {
      // Nếu có dữ liệu trong buffer UART, đọc và kiểm tra nó với expected_answer
      response[x] = Serial1.read();
      x++;
      // Nếu đúng thì trả kết quả answer = 1, thoát hàm
      if (strstr(response, expected_answer) != NULL)
      {
        answer = 1;
      }

    }
  } while ((answer == 0) && ((millis() - previous) < timeout)); // Nếu sai thì tiếp tục thử lại cho tới hết thời gian timeout
  Serial.println(response);   // In giá trị nhận được để debug
  return answer;
}
// Hàm gửi lệnh AT 2 để gửi dữ liệu
int8_t sendATcommand2(char* ATcommand, char* expected_answer1,
                      char* expected_answer2, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Khởi tạo lại chuỗi về 0

  delay(100);

  while ( Serial1.available() > 0) Serial1.read();   // Xóa buffer

  Serial1.println(ATcommand);    // Gửi lệnh AT

  x = 0;
  previous = millis();

  // Chờ phản hồi
  do {
    // Nếu có dữ liệu từ UART thì đọc và kiểm tra 
    if (Serial1.available() != 0) {
      response[x] = Serial1.read();
      x++;
      // Trả về giá trị 1 nếu nhận được expected_answer1
      if (strstr(response, expected_answer1) != NULL)
      {
        answer = 1;
      }
      // Trả về giá trị 2 nếu nhận được expected_answer2
      else if (strstr(response, expected_answer2) != NULL)
      {
        answer = 2;
      }
    }
  }
  // Đợi time out
  while ((answer == 0) && ((millis() - previous) < timeout));
  Serial.println(response);   // In giá trị nhận được để debug
  return answer;
}

Lưu ý:
Bạn cần thay đúng API thingspeak, tên và mật khẩu wifi của bạn vào code
Nếu không kết nối được server thì bạn có thể reset lại kit TIVA
Cần phải đóng kết nối lại sau khi gửi dữ liệu xong bằng AT+CIPCLOSE=1

Kết quả

Ta thấy log bên dưới sẽ khá giống với những gì làm bằng tay thông qua sscom, thế là cũng tạm ổn rồi

Tiếp theo xem thử trên thingspeak xem thế nào

Giá trị mới là 23 đã được cập nhật lên thingspeak, tuyệt vời ông mặt trời 😀

Bạn có thể xem demo thingspeak của hocarm tại

HocARM - ThingSpeak IoT
Demo Thingspeak ESP8266 TIVA - HocARM on ThingSpeak - ThingSpeak is the open IoT platform with MATLAB analytics.

Ngoài ra ta có thể dùng trang check độ dài online nếu muốn kiểm tra về độ dài của chuỗi

Tạm kết

Vậy là mình đã giới thiệu sơ bộ về cách để gửi dữ liệu lên thingspeak với TIVA C và ESP8266 ở mức độ đơn giản nhất. Nếu không có TIVA C thì bạn có thể chọn cách lập trình trực tiếp gửi dữ liệu từ ESP8266 lên thinkspeak luôn, bài này mình xin phép trình bày ở một bài viết sau.