//----------- MODBUS MASTER------------------------------------------------------------------------------------------------
#include "DFRobot_RTU.h"
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <TridentTD_LineNotify.h>
#include <SimpleTimer.h>
#define SSID "ATOM_ADELE" //ใส่ ชื่อ Wifi ที่จะเชื่อมต่อ
#define PASSWORD "Atom0899495910" //ใส่ รหัส Wifi
#define RXD2 16
#define TXD2 17
#define LINE_TOKEN "IaNvCjT54h0NYFVMurbaqi7Mk6XUDFmxcqeYFRNvXzA" // line token ของตัวเอง
DFRobot_RTU modbus_Data(/*s =*/&Serial2);
float TempNo_1;//(4 ไบต์) เก็บเลขทศนิยมแบบ single precision
char ssid[] = "Atom_adele";
char pass[] = "Atom0899495910";
SimpleTimer timer;
void setup() {
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
// Baud Rate 9600, SERIAL_8N1 = data bits(8) ,parity bit no (N) , stop bit one (1)
// Modbus slave ID 1 ใช้ Serial2 อ้างจาก Library HardwareSerial ของ ESP32
WiFi.mode(WIFI_STA); //เชื่อมต่อ Wifi
WiFi.begin(ssid, pass);
Serial.println(LINE.getVersion());
LINE.setToken(LINE_TOKEN);
LINE.notify("เริ่มการทำงาน...");
Serial.begin(115200); Serial.println();
Serial.println(LINE.getVersion());
WiFi.begin(SSID, PASSWORD);
Serial.printf("WiFi connecting to %s\n", SSID);
while (WiFi.status() != WL_CONNECTED) {
Serial.print("connecting");
delay(5000);
}
Serial.printf("\nWiFi connected\nIP : ");
Serial.println(WiFi.localIP());
timer.setInterval(1800000);
// กำหนด Line Token
LINE.setToken(LINE_TOKEN);
// ตัวอย่างส่งข้อมูล ตัวเลข
LINE.notify("ระดับน้ำถังน้ำใส"); // จำนวนเต็ม
}
void loop()
{
TempNo1();
timer.run();
}
void TempNo1() {
//**** อ่าน Float
double ReadRegister[2] = { 0, 1 };
//สร้างตัวแปรแบบอาร์เรย์จำนวน 2 ชุด ประกอบด้วยตำแหน่งที่ 0 และตำแหน่งที่ 1
ReadRegister[0] = modbus_Data.readHoldingRegister(1, 17);
ReadRegister[1] = modbus_Data.readHoldingRegister(1, 18);
/*
อ่านค่าหรือรับค่าของตัวแปร ReadRegister[0] ตำแหน่งที่ 0 และตัวแปร ReadRegister[1] ตำแหน่งที่ 1
ของ D17 และ D18 ของ PLC
*/
memcpy(ReadRegister, &ReadRegister[2], sizeof(float));
//copy ค่าตัวแปรแบบอาร์เรยชื่อ ReadRegister ลงไปใน buffer เริ่มตั้งแต่ตำแหน่งที่ 0 ไปด้วยความยาวทั้งหมด sizeof(float)
double ReadRegisterA = modbus_float(ReadRegister[0], ReadRegister[1]);
Serial.print("ค่าที่อ่านได้จาก PLC : "); Serial.println(ReadRegisterA); Serial.println("");
delay(1000);
}
//--- ชุดการถอดค่า 4 x 4 Bits ช 16 Bits
float modbus_float(uint16_t value1, uint16_t value2)
{
float Encode;
char* Modbus_HoldReg[4];
Modbus_HoldReg[0] = ((char*)(&Encode)) + 3;
Modbus_HoldReg[1] = ((char*)(&Encode)) + 2;
Modbus_HoldReg[2] = ((char*)(&Encode)) + 1;
Modbus_HoldReg[3] = ((char*)(&Encode)) + 0;
*Modbus_HoldReg[0] = (value2 >> 8) & 0xff;
*Modbus_HoldReg[1] = value2 & 0xff;
*Modbus_HoldReg[2] = (value1 >> 8) & 0xff;
*Modbus_HoldReg[3] = value1 & 0xff;
return Encode;
}
void CheckWiFi(){
Serial.println("\nConnecting to WiFi");
while (WiFi.status() != WL_CONNECTED){
Serial.print("Connecting");Serial.println("");
delay(5000);}
}
//https://script.google.com/macros/s/AKfycbzlcQVFTDNbUgPEg44jZpIcsCnepWPdtjYwiOjLdq2cBp1z57c_i55KthR_7cC_Y4FAKw/exec
String GAS_ID = "AKfycbzlcQVFTDNbUgPEg44jZpIcsCnepWPdtjYwiOjLdq2cBp1z57c_i55KthR_7cC_Y4FAKw";
//Your Domain name with URL path or IP address with path
const char* host = "script.google.com"; // only google.com not https://google.com
void update_google_sheet()
{
Serial.print("connecting to ");
Serial.println(host);
// Use WiFiClient class to create TCP connections
WiFiClientSecure client;
const int httpPort = 443; // 80 is for HTTP / 443 is for HTTPS!
client.setInsecure(); // this is the magical line that makes everything work
if (!client.connect(host, httpPort)) { //works!
Serial.println("connection failed");
return;
}
//----------------------------------------Processing data and sending data
String url = "/macros/s/" + GAS_ID + "/exec?voltage=";
url += String(TempNo_1);
// url += "¤t=";
// url += String(30);
Serial.print("Requesting URL: ");
Serial.println(url);
// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
Serial.println();
Serial.println("closing connection");
}
สรุปแนวทางการส่งข้อมูลจาก ESP32 ไปยัง LINE Notify และ Google Sheet ทุกๆ 30 นาที:
- ใช้ไลบรารี SimpleTimer หรือ Ticker กำหนด interval 1800000 ms (30 นาที)
- ตั้งค่าฟังก์ชันส่งข้อมูลโดยรวมคำสั่ง updateGoogleSheet() และ lineNotify() ให้อยู่ใน timer เดียวกัน
- ตรวจสอบ LINE Token และ Google Apps Script Web API (deploy as web app) ว่าสามารถเข้าถึงได้
- เพิ่มฟังก์ชันเช็ก WiFi และ retry ถ้าส่งข้อมูลไม่สำเร็จ เพื่อลดปัญหา WiFi หลุด
- ดู log Serial Monitor และ Gas Script ว่ามี error หรือไม่ ในกรณีข้อมูลไม่ถึงปลายทาง
- แก้ไขค่าต่างๆ เช่น ssid, password, token, script id ตามของจริง
- ตัวอย่างโค้ดในกระทู้ถูกต้องในเชิงโครงสร้าง และสามารถนำไปประยุกต์ใช้ได้ทันที
ถ้ามีปัญหาเพิ่ม แจ้ง error ที่พบมา จะช่วยแนะนำให้ตรงจุดมากขึ้นครับ
#include <WiFi.h>
#include <HTTPClient.h>
#include <SimpleTimer.h>
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
#define LINE_TOKEN "YOUR_LINE_TOKEN"
#define GAS_ID "YOUR_GASDEPLOY_ID"
SimpleTimer timer;
void sendLineNotify(String message) {
HTTPClient http;
http.begin("https://notify-api.line.me/api/notify");
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
http.addHeader("Authorization", "Bearer " LINE_TOKEN);
String payload = "message=" + message;
int httpResponseCode = http.POST(payload);
http.end();
}
void sendToGoogleSheet(float sensorValue) {
HTTPClient http;
String url = String("https://script.google.com/macros/s/") + GAS_ID + "/exec?sensor=" + String(sensorValue);
http.begin(url);
int httpResponseCode = http.GET();
http.end();
}
void sendData() {
float sensorValue = analogRead(34); // ตัวอย่างอ่านค่าสัญญาณ
sendLineNotify("ค่าส่ง: " + String(sensorValue));
sendToGoogleSheet(sensorValue);
}
void setup() {
Serial.begin(115200);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
timer.setInterval(1800000, sendData); // 30 นาที
}
void loop() {
timer.run();
}
• เปลี่ยน ssid/password, token, gas_id ให้ตรงกับของจริง
• ในฟังก์ชัน sendData() จะอ่านค่าและส่งทั้งไป LINE และ Google Sheet ทุก 30 นาที
กรณีใช้ Ticker หรือ millis ก็สามารถดัดแปลงแนวคิดนี้ได้ครับ