บันทึกการฝึกงานประจำวัน โดย นางสาวณัฐนิช เจริญกิจ

4 มิถุนายน 2567

งานที่ได้รับมอบหมายคือการใช้ Arduino OPTA ให้สามารถทำงานร่วมกับ MQTT โดยใช้เซ็นเซอร์ตรวจจับอุณหภูมิ และ ตรวจจับแสงร่วมด้วย โดยในวันแรกเริ่มจากการศึกษาหาข้อมูลเกี่ยวกับ MQTT และ Arduino OPTA

งานที่ได้ทำในวันนี้

  • ทดลองเล่น Arduino OPTA กับโปรแกรม Arduino PLC IDE ให้สามารถเชื่อมต่อและส่งข้อมูลหากันได้

link : https://youtu.be/jSVzVAaLURM?si=CXrpVnToBDBU6ikI

5 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • หาข้อมูลทำงานของการใช้ Arduino OPTA กับการทำงานร่วมกับ MQTT
  • ศึกษาข้อมูลเกี่ยวกับ MQTT
  • หาข้อมูลเซ็นเซอร์ที่ใช้ควบคุมแสง และอุณหภูมิและความชื้น โดยเลือกที่การสื่อสารแบบ I2C หรือ RS485

ข้อมูลเซ็นเซอร์

https://docs.google.com/document/d/1oI1ew-Da6GK_8S-1gyNs-q1flLhN9S3CtBR6bTGYz4M/edit?usp=sharing

ที่มา

link : https://aws.amazon.com/th/what-is/mqtt/

link : https://medium.com/@iot24hours/ทำความรู้จักกับ-mqtt-protocol-สำหรับระบบ-iot-ที่จำเป็นต้องรู้-9508957a8b61

link : https://youtu.be/Gu9txMng_nQ?si=mHZXic-37guzO5vT

6 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • ศึกษาการใช้งาน MQTT และทดลองเชื่อมต่อกับการทำงานร่วมกับ MQTT โดยให้ส่งข้อความไปแสดงใน HiveMQ โดยใช้โปรแกรม Arduino IDE และควบคุมไฟ LED
  • หาเซ็นเซอร์ที่ใช้ควบคุมแสง อุณหภูมิและความชื้น โดยใช้ Arduino wifi rev 2 ในการทดลอง

โค้ดการทดลอง

โค้ดนี้เป็นการทดลองโดยใช้ Arduino wifi rev 2 เชื่อต่อกับ HiveMQ และรับค่าแสงจากเซ็นเซอร์ LDR เข้ามาควบคุมการเปิด/ปิดไฟ LED

หมายเหตุ :โค้ดนี้ยังไม่รวมการรับค่าอุณหภูมิและความชื้น

Library ที่ใช้

  • WiFiNINA
  • PubSubClient
  • ArduinoJson
#include <SPI.h>
#include <WiFiNINA.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

#define LED_PIN 4
#define LDR_PIN A0

// Wi-Fi Credentials
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)


// MQTT Broker Details
String device_id = "Device0001";
const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
const char* mqtt_user = "Device0001";
const char* mqtt_password = "Device0001";
const char* mqtt_clientId = "Device_Device0001";
const char* topic_publish = "JPLearning_SensorData";
const char* topic_subscribe = "JPLearning_CommandRequest";

WiFiClient wifiClient;
PubSubClient mqtt_client(wifiClient);

// Data Sending Time
unsigned long CurrentMillis, PreviousMillis, DataSendingTime = (unsigned long) 1000 * 10;

// Variable
byte lightStatus;

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);

  Serial.println("\n\nWelcome to JP Learning\n");

  // Start the Wi-Fi connection
  setup_wifi();
  
  // Connect to MQTT broker
  mqtt_client.setServer(mqtt_server, mqtt_port);
  mqtt_client.setCallback(callback);
  mqtt_connect();
}

void loop() {
  // MQTT handling
  if (!mqtt_client.loop()) {
    mqtt_connect();
  }

  // LDR value handling and MQTT publishing
  int LDR_Value = analogRead(LDR_PIN);
  if (LDR_Value == 0) {
    Serial.println("\n\nFailed to read from LDR sensor!");
  } else {
    Serial.println("\n\nLDR Value: " + String(LDR_Value));
    Serial.println("Light: " + String(lightStatus) + " " + String(lightStatus == 1 ? "ON" : "OFF"));

    // Devices State Sync Request
    CurrentMillis = millis();
    if (CurrentMillis - PreviousMillis > DataSendingTime) {
      PreviousMillis = CurrentMillis;

      // Publish LDR Data
      String pkt = "{";
      pkt += "\"device_id\": \"Device00001\", ";
      pkt += "\"type\": \"Light\", ";
      pkt += "\"value\": " + String(LDR_Value) + "";
      pkt += "}";
      mqtt_publish((char*) pkt.c_str());
    }
  }
}

void setup_wifi() {
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void mqtt_connect() {
  while (!mqtt_client.connected()) {
    Serial.println("Attempting MQTT connection...");
    if (mqtt_client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.println("MQTT Client Connected");
      mqtt_publish((char*)("Hi from " + device_id).c_str());
      mqtt_subscribe(topic_subscribe);
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void mqtt_publish(char * data) {
  mqtt_connect();
  if (mqtt_client.publish(topic_publish, data)) {
    Serial.println("Publish \"" + String(data) + "\" ok");
  } else {
    Serial.println("Publish \"" + String(data) + "\" failed");
  }
}

void mqtt_subscribe(const char * topic) {
  if (mqtt_client.subscribe(topic)) {
    Serial.println("Subscribe \"" + String(topic) + "\" ok");
  } else {
    Serial.println("Subscribe \"" + String(topic) + "\" failed");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String command;
  Serial.print("\n\nMessage arrived [");
  Serial.print(topic);
  Serial.println("] ");
  for (int i = 0; i < length; i++)
    command += (char)payload[i];

  if (command.length() > 0)
    Serial.println("Command receive is : " + command);

  DynamicJsonDocument doc(1024);
  deserializeJson(doc, command);
  JsonObject obj = doc.as<JsonObject>();

  String id = obj["device_id"];
  String type = obj["type"];
  String value = obj["value"];
  Serial.println("\nCommand device_id is : " + id);
  Serial.println("Command type is : " + type);
  Serial.println("Command value is : " + value);

  if (id == device_id && type == "Light") {
    if (value == "1") {
      lightStatus = 1;
      digitalWrite(LED_PIN, HIGH);
      Serial.println("\nLED ON by Application");

      mqtt_publish((char*) command.c_str());
    } else {
      lightStatus = 0;
      digitalWrite(LED_PIN, LOW);
      Serial.println("\nLED OFF by Application");

      mqtt_publish((char*) command.c_str());
    }
  }
}

ปัญหาที่พบระหว่างการทำงาน

  • ในระหว่างทำมีการลองเปลี่ยนข้อมูลหัวข้อ Topic เกิดข้อผิดพลาดของโค้ดคือข้อมูลไม่ส่งไปหา Topic ใหม่

7 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • เข้าไปช่วยตรวจรับ Hololens โดยตรวจสอบว่าเครื่องมีหนิหหรือใช้งานผิดปกติหรือไม่

10 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • ค้นคว้าการทำงานของ OPTA
  • ทดลองนำ Arduino OPTA เชื่อต่อกับ MQTT

Arduino OPTA

Arduino Opta เป็นอุปกรณ์ PLC ขนาดเล็กที่ปลอดภัยและสามารถใช้งานง่ายพร้อมด้วยความสามารถ IoT ระดับอุตสาหกรรม ออกแบบร่วมกับ Finder ผู้ผลิตอุปกรณ์อัตโนมัติทางอุตสาหกรรมและอาคารชั้นนำ  

Arduino Opta มี 3 รุ่น ได้แก่ 

  • Arduino Opta Lite มีอินเตอร์เฟสผ่านทาง USB Type-C, Ethernet 
  • Arduino Opta RS485 มีอินเตอร์เฟสผ่านทาง USB Type-C, Ethernet, RS-485 แบบ Half Duplex 
  • Arduino Opta WiFi มีอินเตอร์เฟสผ่านทาง USB Type-C, Ethernet, RS-485 แบบ Half Duplex, Wi-Fi + BLE 

คุณสมบัติของ Arduino Opta: 

  • MCU – ไมโครคอนโทรลเลอร์ STMicroelectronics STM32H747XI พร้อม Arm Cortex-M7 1 คอร์ สูงสุด 480 MHz, Arm Cortex-M4 1 คอร์ สูงสุด 240 MHz, flash ขนาด 2MB , SRAM ขนาด 1MB  (ตามที่พบในบอร์ด Portenta H7 ทั้งหมด
  • พื้นที่เก็บข้อมูล – Flash QSPI ขนาด 16MB  
  • I/O 
  • 8x อินพุตดิจิตอล/อนาล็อก (0-10V) 
  • 4x เอาต์พุตหน้าสัมผัสรีเลย์ปกติเปิด (NO relay), พิกัด 10 A 
  • การเชื่อมต่ออินเทอร์เฟซ 
  • พอร์ต Ethernet RJ45 สำหรับ LAN หรือ MODBUS TCP/IP 
  • พอร์ตเสริม RS485 สำหรับการเชื่อมต่อ MODUS RTU 
  • โมดูลรวมเสริม WiFi & BLE 
  • USB – พอร์ต USB 2.0 Type-C 1 ช่อง, การเขียนโปรแกรมหรือการบันทึกข้อมูล (ผ่าน memory stick) 
  • ความปลอดภัย – ATECC608B secure element 
  • อื่นๆ – ปุ่ม RTC, ปุ่มรีเซ็ตและปุ่มผู้ใช้, ไฟ LED แสดงสถานะต่างๆ สำหรับ I/O และอีเธอร์เน็ต 
  • การจ่ายแรงดัน – อินพุต 12…24 V DC 
  • ขนาด – ประมาณ 90 x 85 x 69 มม. (ติดตั้งรางปีกนก DIN Rail) 
  • น้ำหนัก – 210 กรัม 
  • Ingress Protection (มาตรฐานการป้องกัน) IP20 

พอร์ตการเชื่อมต่อ 

ปัญหาที่พบระหว่างการทำงาน

  • ในครั้งแรก Arduino OPTA เชื่อ Broker MQTT มีปัญหาที่การเชื่อต่อ failed เนื่องจากการใช้ไลบรารีหรือโค้ดบางส่วนที่ต้องปรับให้ทำงานกับ Arduino OPTA ได้

ที่มา

link :https://docs.arduino.cc/hardware/opta

11 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • ทดลองใช้ Arduino OPTA ร่วมกับ HiveMQ และ MQTTX

โค้ดการทดลอง

โค้ดนี้เป็นทดลองใช้ Arduino OPTA ร่วมกับ HiveMQ โดยรับค่าแสงจากเซ็นเซอร์ LDR เข้ามาควบคุมการเปิด/ปิดไฟ LED ซึ่งจะแสดงสถานะการเชื่อมต่อ Wi-Fi และ MQTT การอ่านค่า LDR และการควบคุม LED ผ่านคำสั่ง MQTT รวมถึงการส่งข้อมูล LDR ไปยัง MQTT broker ทุก ๆ 10 วินาที

หมายเหตุ :โค้ดนี้ยังไม่รวมการรับค่าอุณหภูมิและความชื้น

Library ที่ใช้

  • WiFi
  • PubSubClient
  • ArduinoJson
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

#define LED_Pin LED_D0
#define LDR_Pin A0

char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

String device_id = "LDR_SENSOR_1"; // ชื่ออุปกรณ์ที่ต้องการตั้ง
const char* mqtt_server = "mqtt-dashboard.com"; 
const int mqtt_port = 1883;
const char* mqtt_user = "Nattanit"; // ชื่อ User ที่ต้องการตั้ง
const char* mqtt_password = "Nattanit"; // Password ที่ User ต้องการตั้ง
const char* mqtt_clientId = "clientId-gaGnJtBAzp";
const char* topic_publish = "M2MQTT_Unity/test12"; // Publisher: ส่งข้อมูลไปยัง MQTT Broker
const char* topic_subscribe = "M2MQTT_Unity/test2"; // Subscriber: รับข้อมูลจาก MQTT Broker

WiFiClient wifiClient;
PubSubClient mqtt_client(wifiClient);

// Data Sending Time
unsigned long CurrentMillis, PreviousMillis, DataSendingTime = (unsigned long) 1000 * 10;

// Variable
byte lightStatus;

void setup() {
  Serial.begin(115200);
  
  pinMode(LED_Pin, OUTPUT);

  Serial.println("\n\nWelcome to OPTA\n");

  // Start the Wi-Fi connection
  setup_wifi();
  
  // Connect to MQTT broker
  mqtt_client.setServer(mqtt_server, mqtt_port);
  mqtt_client.setCallback(callback);
  mqtt_connect();

  // Subscribe ไปยัง topic ที่ต้องการรับค่าควบคุม LED
  mqtt_subscribe(topic_subscribe);
}

void loop() {
  // MQTT handling
  if (!mqtt_client.loop()) {
    mqtt_connect();
  }
  mqtt_client.loop();

  // LDR value handling and MQTT publishing
  int LDR_Value = analogRead(LDR_Pin);
  if (LDR_Value == 0) {
    Serial.println("\n\nFailed to read from LDR sensor!");
  } else {
    Serial.println("\n\nLDR Value: " + String(LDR_Value));
    Serial.println("Light: " + String(lightStatus) + " " + String(lightStatus == 1 ? "ON" : "OFF"));
    delay(1000);
    // Devices State Sync Request
    CurrentMillis = millis();
    if (CurrentMillis - PreviousMillis > DataSendingTime) {
      PreviousMillis = CurrentMillis;

      // Publish LDR Data
      String pkt = "{";
      pkt += "\"device_id\": \"LDR_SENSOR_1\", ";
      pkt += "\"type\": \"Light\", ";
      pkt += "\"value\": " + String(LDR_Value) + "";
      pkt += "}";
      mqtt_publish((char*) pkt.c_str());
    }
  }
}

void setup_wifi() {
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void mqtt_connect() {
  while (!mqtt_client.connected()) {
    Serial.println("Attempting MQTT connection...");
    if (mqtt_client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.println("MQTT Client Connected");
      mqtt_publish((char*)("Hi from " + device_id).c_str());
      mqtt_subscribe(topic_subscribe);
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void mqtt_publish(char * data) {
  mqtt_connect();
  if (mqtt_client.publish(topic_publish, data)) {
    Serial.println("Publish \"" + String(data) + "\" ok");
  } else {
    Serial.println("Publish \"" + String(data) + "\" failed");
  }
}

void mqtt_subscribe(const char * topic) {
  if (mqtt_client.subscribe(topic)) {
    Serial.println("Subscribe \"" + String(topic) + "\" ok");
  } else {
    Serial.println("Subscribe \"" + String(topic) + "\" failed");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String command;
  Serial.print("\n\nMessage arrived [");
  Serial.print(topic);
  Serial.println("] ");
  for (int i = 0; i < length; i++) {
    command += (char)payload[i];
  }

  if (command.length() > 0) {
    Serial.println("Command received is : " + command);
  }

  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, command);
  if (error) {
    Serial.print("Failed to parse JSON: ");
    Serial.println(error.c_str());
    return;
  }
  JsonObject obj = doc.as<JsonObject>();
  String id = obj["device_id"];
  String type = obj["type"];
  String value = obj["value"];
  Serial.println("\nCommand device_id is : " + id);
  Serial.println("Command type is : " + type);
  Serial.println("Command value is : " + value);

  if (id == device_id && type == "Light") {
    if (value == "1") {
      lightStatus = 1;
      digitalWrite(LED_Pin, HIGH);
      Serial.println("\nLED ON by Application");

      mqtt_publish((char*) command.c_str());
    } else {
      lightStatus = 0;
      digitalWrite(LED_Pin, LOW);
      Serial.println("\nLED OFF by Application");
      mqtt_publish((char*) command.c_str());
    }
  }
}

ปัญหาที่พบระหว่างการทำงาน

  • ในการทำงานช่วงแรกๆปัญหา Arduino OPTA ไม่อ่านค่า LDR หรือ่านค่าเป็น 0 หรือเป็นค่า error

12 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • ทดลองการใช้ Arduino OPTA ต่อจากเมื่อวานให้เสร็จสมบรูณ์
  • ทดลองใช้ Arduino OPTA ร่วมกับ HiveMQ และ MQTTX ร่วมกับการส่งข้อมูลจาก Unity เข้ามาควบคุมไฟ LED ให้สามารถเปิดปิดได้
  • ศึกษาว่า QoS คืออะไร

MQTT มีสามระดับของ QoS เพื่อจัดการกับการส่งข้อความ :

  • QoS 0: ส่งข้อความเพียงครั้งเดียว โดยไม่รับประกันการส่งถึง
  • QoS 1: ส่งข้อความอย่างน้อยหนึ่งครั้ง โดยมีการรับประกันการส่ง
  • QoS 2: ส่งข้อความเพียงครั้งเดียว โดยมีการรับประกันการส่งและการจัดการการส่งซ้ำ

ปัญหาที่พบ

  • อ่านค่าจาก LDR ได้ จะพบว่าอ่านค่าได้น้อยกว่าจากการอ่านค่าใน Arduion WiFi rev 2

สิ่งที่ได้เรียนรู้

  • หลังจากทดลองให้ Arduino OPTA อ่านค่า LDR ได้ ก็จะพบว่าค่าที่อ่านได้นั้นมีค่าน้อยกว่าการอ่านค่าใน Arduion WiFi rev 2 เกิดจากการที่เราจ่ายไฟให้กับ LDR เป็นไฟ 5 V เหมือนตอนที่ทดลองกับ Arduion WiFi rev 2 ทำให้กระแสไหลน้อย ดังนั้นจึงแก้จากการเพิ่มกระแสเข้าไปให้ LDR เป็น 12 V โดยตอนทดลองใช้ไฟร่วมกับ Arduino OPTA เลย

13 มิถุนายน 2567

งานที่ได้ทำในวันนนี้

  • ทดลองใช้ Arduino OPTA กับเซ็นเซอร์ BH1750FVI ที่เป็นการสื่อสารแบบ I2C และเซ็นเซอร์ XY-MD02 ที่เป็นการสื่อสารแบบ RS485

ปัญหาที่พบ

  • Arduino OPTA ไม่มีช่องรับสัญญาณแบบ I2C ทำให้ไม่สามรถใช้งานเซ็นเซอร์ BH1750FVI ได้ โดยค้นหาช่องการเชื่อต่อทั้งจากใน Google

สิ่งที่ได้เรียนรู้

  • จากที่โดยค้นหาช่องการเชื่อต่อ I2C ทั้งจากใน Google ,YouTube และ Document ของ Arduino OPTA ไม่พบช่องสัญญาณ I2C หรือ ใน Arduino OPTA มีช่อง Port for communication and connection of auxiliary modules ที่เป็นช่องแยกมีคนเคยทำไว้ แต่หลักๆแล้วช่องนี้ไม่ได้ออกแบบมาเพื่อเชื่อต่อ I2C โดยเฉพาะ

14 – 19 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • ทดลองใช้ Arduino OPTA กับเซ็นเซอร์ XY-MD02 ที่เป็นการสื่อสารแบบ RS485
  • ทดลองใช้ Arduino WiFi Rev2 กับเซ็นเซอร์ XY-MD02 ที่เป็นการสื่อสารแบบ RS485

ปัญหาที่พบ

  • Arduino OPTA ไม่สามารถส่งค่าสื่อสารกับเซ็นเซอร์ได้ โดยเมื่อส่งค่าไปเรียกค่าอุณหภูมิและความชื้นแล้ว เซ็นเซอร์ไม่ตอบค่ากลับมา

สิ่งที่ได้เรียนรู้

  • การเชื่อต่อ RS485 สาย Arduino OPTA กับ เซนเซอร์ XY-MD02 ใน Arduion OPTA จะมี Port การเชื่อมต่อ RS485 แบบ A(-) และ B(+) และในเซ็นเซอร์ XY-MD02 จะมี Port การเชื่อมต่อ RS485 แบบ A(+) และ B(-) ซึ่งในงานนี้ที่เราจะใช้งานให้ยึด Port ที่เป็น A ,B เป็นหลักไปเลย เช่น ต่อสาย A(-) ของ Arduino OPTA เข้ากับ ช่อง A(+) ของเซ็นเซอร์ XY-MD02
  • การอ่าน data sheet ของเซ็นเซอร์ XY-MD02
    • Funciotn ต่างๆที่มีไว้ควบคุมการเขียนใน register ของ RS485
    • วิธีการที่เซ็นเซอร์อ่านค่าเมื่อได้รับการส่งค่า

เมื่อส่งค่าไปถามใน register Starting Address Hi และ Starting Address Li ข้อมูลจะตอบกลับมาเป็นจำนวน 2 Bytes ซึ่งค่าอุหภูมิในช่องแรกที่ตอบกลับมา(ไฮไลต์สีเหลือง) ให้นำมาต่อกับช่องที่ 2(ไฮไลต์สีฟ้า) แล้วเปลี่ยนค่าจาก Hex เป็น decimal

ที่มา

link :https://iot-kmutnb.github.io/blogs/sensors/xy-md02

20 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • รวมโค้ดส่วนต่างๆ ของ Arduino WiFi Rev 2 ที่ได้ทดลองกับเซ็นเซอร์และการส่งค่าเข้าด้วยกัน ให้ทำงานกับ MQTT และ Unity ให้เป็นระบบที่ทำงานร่วมกันได้
#include <SPI.h>
#include <WiFiNINA.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <BH1750.h>
#include <SoftwareSerial.h>
#include <ModbusMaster.h>
#include "arduino_secrets.h"

// MQTT Setup
const char* mqtt_server = "0.tcp.ap.ngrok.io";
const int mqtt_port = 12537;
const char* mqtt_user = "Nattanit";
const char* mqtt_password = "1234";
const char* mqtt_clientId = "clientId-gaGnJtBAzp";
const char* topic_publish_light = "M2MQTT_Unity/sensor/BH1750FVI";
const char* topic_subscribe = "M2MQTT_Unity/LED";
const char* topic_temperature_humidity = "M2MQTT_Unity/sensor/xy_md02";

// Device Setup
String device_id = "Sensors";
WiFiClient wifiClient;
PubSubClient mqtt_client(wifiClient);

// BH1750 Setup
#define LED_Pin 13
BH1750 lightMeter;

// XY-MD02 Setup
SoftwareSerial mySerial(2, 3); // RX, TX
#define MAX485_DE 4
#define MAX485_RE_NEG 5
ModbusMaster node;

// Data Sending Time
unsigned long CurrentMillis, PreviousMillis, DataSendingTime = 10000; // 10 seconds

// Variable
byte lightStatus;

void preTransmission() {
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission() {
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}

void setup() {
  Serial.begin(115200);
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  pinMode(LED_Pin, OUTPUT); // Ensure LED pin is set as OUTPUT
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);

  Serial.println("\n\nWelcome to All_Sensors\n");

  // Start the Wi-Fi connection
  setup_wifi();

  // Connect to MQTT broker
  mqtt_client.setServer(mqtt_server, mqtt_port);
  mqtt_client.setCallback(callback);
  mqtt_connect();

  // Initialize the BH1750 sensor
  Wire.begin();
  if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
    Serial.println(F("BH1750 Advanced begin"));
  } else {
    Serial.println(F("Error initializing BH1750"));
  }

  // Initialize the ModbusMaster for XY-MD02
  mySerial.begin(9600);
  node.begin(1, mySerial);
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

void loop() {
  // MQTT handling
  if (!mqtt_client.loop()) {
    mqtt_connect();
  }

  // Read LDR value and publish via MQTT
  float lux = lightMeter.readLightLevel();
  if (lux < 0) {
    Serial.println("\n\nFailed to read from BH1750 sensor!");
  } else {
    Serial.println("\n\nBH1750 Lux Value: " + String(lux, 2)); // Two decimal places
    Serial.println("Light: " + String(lightStatus) + " " + String(lightStatus == 1 ? "ON" : "OFF"));

    // Publish BH1750 data
    StaticJsonDocument<200> doc;
    doc["device_id"] = device_id;
    doc["type"] = "Light";
    doc["sensor"] = "BH1750FVI";
    doc["value"] = String(lux, 2); // Two decimal places

    char jsonBuffer[512];
    serializeJson(doc, jsonBuffer);
    mqtt_publish(topic_publish_light, jsonBuffer);
    Serial.println();
  }

  // Read XY-MD02 data and publish via MQTT
  uint8_t result = node.readInputRegisters(1, 2);
  if (result == node.ku8MBSuccess) {
    float temp = node.getResponseBuffer(0) / 10.0f;
    float humi = node.getResponseBuffer(1) / 10.0f;
    Serial.print("Temp: ");
    Serial.println(String(temp, 2)); // Two decimal places
    Serial.print("Humi: ");
    Serial.println(humi);
   

    // Publish Temperature and Humidity data
    StaticJsonDocument<200> doc;
    doc["device_id"] = device_id;
    doc["type"] = "XY-MD02";
    doc["temperature"] = String(temp, 2); // Two decimal places
    doc["humidity"] = humi;

    char buffer[512];
    serializeJson(doc, buffer);
    mqtt_publish(topic_temperature_humidity, buffer);
  }

  delay(3000); // Delay before next iteration
}

void setup_wifi() {
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(SECRET_SSID);

  WiFi.begin(SECRET_SSID, SECRET_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void mqtt_connect() {
  while (!mqtt_client.connected()) {
    Serial.println("Attempting MQTT connection...");
    if (mqtt_client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.println("MQTT Client Connected");
      mqtt_publish(topic_publish_light, (char*)("Hi from " + device_id).c_str());
      mqtt_subscribe(topic_subscribe);
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void mqtt_publish(const char * topic, char * data) {
  mqtt_connect();
  if (mqtt_client.publish(topic, data)) {
    Serial.println("Publish \"" + String(data) + "\" to topic \"" + String(topic) + "\" ok");
  } else {
    Serial.println("Publish \"" + String(data) + "\" to topic \"" + String(topic) + "\" failed");
  }
}

void mqtt_subscribe(const char * topic) {
  if (mqtt_client.subscribe(topic)) {
    Serial.println("Subscribe \"" + String(topic) + "\" ok");
  } else {
    Serial.println("Subscribe \"" + String(topic) + "\" failed");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String command;
  Serial.print("\n\nMessage arrived [");
  Serial.print(topic);
  Serial.println("] ");
  for (int i = 0; i < length; i++) {
    command += (char)payload[i];
  }

  if (command.length() > 0) {
    Serial.println("Command received is : " + command);
  }

  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, command);
  if (error) {
    Serial.print("Failed to parse JSON: ");
    Serial.println(error.c_str());
    return;
  }

  JsonObject obj = doc.as<JsonObject>();
  String id = obj["device_id"];
  String type = obj["type"];
  String value = obj["value"];
  Serial.println("\nCommand device_id is : " + id);
  Serial.println("Command type is : " + type);
  Serial.println("Command value is : " + value);

  if (id == device_id && type == "LED") {
    if (value == "1") {
      lightStatus = 1;
      digitalWrite(LED_Pin, HIGH);
      Serial.println("\nLED ON by Application");

      mqtt_publish(topic_publish_light, (char*) command.c_str());
    } else if (value == "0") {
      lightStatus = 0;
      digitalWrite(LED_Pin, LOW);
      Serial.println("\nLED OFF by Application");

      mqtt_publish(topic_publish_light, (char*) command.c_str());
    } else {
      Serial.println("\nInvalid value received for LED control.");
    }
  }
}

ปัญหาที่พบ

  • ระหว่างการรวมโค้ดเมื่อทำงานรวมกันแล้วมี Error

21 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • ทดลองใช้ Arduino OPTA ซ็นเซอร์ BH1750FVI และ เซ็นเซอร์ XY-MD02 ที่ทำงานเสร็จสมบูรณ์
  • ทดสอบและแก้ไขโค้ดให้สมบูรณ์และใช้งานกับ Unity ได้ดีมากขึ้น

โค้ดการทดลอง

โค้ดการทำงานของ Arduino WiFi Rve 2 โดยรับค่าแสงจากเซ็นเซอร์ BH1750FVI และรับค่าอุณหภูมิจากเซ็นเซอร์ XY-MD02 ซึ่งจะส่งข้อมูลผ่าน MQTT ไปหายัง Unity ที่ทำงานเสร็จสมบูรณ์ และสามารถควบคุมการเปิด/ปิดไฟได้

#include <SPI.h>
#include <WiFiNINA.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <BH1750.h>
#include <SoftwareSerial.h>
#include <ModbusMaster.h>
#include "arduino_secrets.h"

// MQTT Setup
const char* mqtt_server = "0.tcp.ap.ngrok.io";
const int mqtt_port = 12655;
const char* mqtt_user = "Nattanit";
const char* mqtt_password = "1234";
const char* mqtt_clientId = "clientId-gaGnJtBAzp";
const char* topic_publish_light = "M2MQTT_Unity/sensor/BH1750FVI";
const char* topic_subscribe = "M2MQTT_Unity/LED";
const char* topic_temperature_humidity = "M2MQTT_Unity/sensor/xy_md02";

// Device Setup
String device_id = "Sensors";
WiFiClient wifiClient;
PubSubClient mqtt_client(wifiClient);

// BH1750 Setup
#define LED_Pin 13
BH1750 lightMeter;

// XY-MD02 Setup
SoftwareSerial mySerial(2, 3); // RX, TX
#define MAX485_DE 4
#define MAX485_RE_NEG 5
ModbusMaster node;

// Data Sending Time
unsigned long CurrentMillis, PreviousMillis, DataSendingTime = 10000; // 10 seconds

// Variable
byte lightStatus;

void preTransmission() {
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission() {
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}

void setup() {
  Serial.begin(115200);
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  pinMode(LED_Pin, OUTPUT); // Ensure LED pin is set as OUTPUT
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);

  Serial.println("\n\nWelcome to All_Sensors\n");

  // Start the Wi-Fi connection
  setup_wifi();

  // Connect to MQTT broker
  mqtt_client.setServer(mqtt_server, mqtt_port);
  mqtt_client.setCallback(callback);
  mqtt_connect();

  // Initialize the BH1750 sensor
  Wire.begin();
  if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
    Serial.println(F("BH1750 Advanced begin"));
  } else {
    Serial.println(F("Error initializing BH1750"));
  }

  // Initialize the ModbusMaster for XY-MD02
  mySerial.begin(9600);
  node.begin(1, mySerial);
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

void loop() {
  // MQTT handling
  if (!mqtt_client.loop()) {
    mqtt_connect();
  }

  // Read LDR value and publish via MQTT
  float lux = lightMeter.readLightLevel();
  if (lux < 0) {
    Serial.println("\n\nFailed to read from BH1750 sensor!");
  } else {
    Serial.println("\n\nBH1750 Lux Value: " + String(lux, 2)); // Two decimal places
    Serial.println("Light: " + String(lightStatus) + " " + String(lightStatus == 1 ? "ON" : "OFF"));

    // Publish BH1750 data
    StaticJsonDocument<200> doc;
    doc["device_id"] = device_id;
    doc["type"] = "Light";
    doc["sensor"] = "BH1750FVI";
    doc["value"] = String(lux, 2); // Two decimal places

    char jsonBuffer[512];
    serializeJson(doc, jsonBuffer);
    mqtt_publish(topic_publish_light, jsonBuffer);
    Serial.println();
  }

  // Read XY-MD02 data and publish via MQTT
  uint8_t result = node.readInputRegisters(1, 2);
  if (result == node.ku8MBSuccess) {
    float temp = node.getResponseBuffer(0) / 10.0f;
    float humi = node.getResponseBuffer(1) / 10.0f;
    Serial.print("Temp: ");
    Serial.println(String(temp, 2)); // Two decimal places
    Serial.print("Humi: ");
    Serial.println(humi);
   

    // Publish Temperature and Humidity data
    StaticJsonDocument<200> doc;
    doc["device_id"] = device_id;
    doc["type"] = "XY-MD02";
    doc["temperature"] = String(temp, 2); // Two decimal places
    doc["humidity"] = humi;

    char buffer[512];
    serializeJson(doc, buffer);
    mqtt_publish(topic_temperature_humidity, buffer);
  }

  delay(3000); // Delay before next iteration
}

void setup_wifi() {
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(SECRET_SSID);

  WiFi.begin(SECRET_SSID, SECRET_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void mqtt_connect() {
  while (!mqtt_client.connected()) {
    Serial.println("Attempting MQTT connection...");
    if (mqtt_client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.println("MQTT Client Connected");
      mqtt_publish(topic_publish_light, (char*)("Hi from " + device_id).c_str());
      mqtt_subscribe(topic_subscribe);
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void mqtt_publish(const char * topic, char * data) {
  mqtt_connect();
  if (mqtt_client.publish(topic, data)) {
    Serial.println("Publish \"" + String(data) + "\" to topic \"" + String(topic) + "\" ok");
  } else {
    Serial.println("Publish \"" + String(data) + "\" to topic \"" + String(topic) + "\" failed");
  }
}

void mqtt_subscribe(const char * topic) {
  if (mqtt_client.subscribe(topic)) {
    Serial.println("Subscribe \"" + String(topic) + "\" ok");
  } else {
    Serial.println("Subscribe \"" + String(topic) + "\" failed");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String command;
  Serial.print("\n\nMessage arrived [");
  Serial.print(topic);
  Serial.println("] ");
  for (int i = 0; i < length; i++) {
    command += (char)payload[i];
  }

  if (command.length() > 0) {
    Serial.println("Command received is: " + command);
  }

  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, command);
  if (error) {
    Serial.print("Failed to parse JSON: ");
    Serial.println(error.c_str());
    return;
  }

  JsonObject obj = doc.as<JsonObject>();
  String id = obj["device_id"];
  String type = obj["type"];
  String value = obj["value"];
  Serial.println("\nCommand device_id is: " + id);
  Serial.println("Command type is: " + type);
  Serial.println("Command value is: " + value);

  if (id == device_id && type == "LED") {
    if (value == "1") {
      lightStatus = 1;
      digitalWrite(LED_Pin, HIGH);
      Serial.println("\nLED ON by Application");
    } else if (value == "0") {
      lightStatus = 0;
      digitalWrite(LED_Pin, LOW);
      Serial.println("\nLED OFF by Application");
    } else {
      Serial.println("\nInvalid value received for LED control.");
    }
  }
}

ไฟล์ arduino_secrets.h

#define SECRET_SSID " your_SSID" //ชื่อ WiFi
#define SECRET_PASS " your_PASSWORD" //ญฟหหไนำก WiFi

ตัวอย่างโค้ดและวงจร

link : https://www.cybertice.com/product/4530/xy-md02-เซ็นเซอร์วัดอุณหภูมิและความชื้น-sht20-temperature-and-humidity-transmitter-detection-sensor-?gad_source=1

link : https://www.allnewstep.com/product/3344/bh1750fvi-arduino-sensor-เซ็นเซอร์วัดความเข้มแสง

24 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • ในช่วงเช้าทำการศึกษาเกี่ยวกับ RS485 และเตรียมตัวสำหรับการนำเสนองานให้กับอาจาร์ยจากคณะมันติมีเดียที่เข้ามาเยี่ยมชม
  • นำเสนองานจากโปรเจ็คที่ได้รับมอบหมายการทำงานของ Arduino Opta ร่วมกับ MQTT

25 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • เขียนโค้ด RS485 และการใช้ modbus pull ในการดูค่าและกำหนด Slave Id ของเซ็นเซอร์ XY-MD02

สิ่งที่ได้เรียนรู้

  • การใช้งานโปรแกรม modbus pull
  • การกำหนดค่า Slave Id ของเซ็นเซอร์ XY-MD02
  • การเขียนโค้ดไปอ่านค่า register เซ็นเซอร์ XY-MD02

26 -27 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • ออกบูธนำเสนองาน ณ งาน Academic Support fair 2024 ให้กับผู้เข้าเยี่ยมชมนิทัศการ
  • นำเสนองานให้กับผอ.โรงเรียนดรุณสิกขาลัย และผู้บริหารสยามพิวรรธน์

28 มิถุนายน 2567

งานที่ได้ทำในวันนี้

  • รวบรวมโค้ดต่างๆของ Arduion OPTA ทั้งเซ็นเซอร์แสง LDR เข้ากับเซ็นเซอร์ XY-MD02 ที่สื่อสารแบบ RS485 ที่เสร็จสมบรูณ์แล้ว

โค้ดการทดลอง

โค้ดนี้เป็นโค้ดการทำงานของ Arduino OPTA ที่รับค่าแสงจากเซ็นเซอร์ LDR และค่าอุณหภูมิและความชื้นจากบเซ็นเซอร์ XY-MD02 ที่สื่อสารแบบ RS485 โดยจะส่งข่อมูลไปที่ MQTT ละสามารถเปิด/ปิดไป LED ได้จาก Unity ที่เสร็จสมบรูณ์แล้ว

#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h"
#include <ArduinoModbus.h>
#include <ArduinoRS485.h>

int LED_Pin = D2;
#define LDR_Pin A0

char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

String device_id = "SENSORS";
const char* mqtt_server = "0.tcp.ap.ngrok.io";
const int mqtt_port = 17493;
const char* mqtt_user = "Nattanit";
const char* mqtt_password = "1234";
const char* mqtt_clientId = "clientId-UJ4PTJOEzd";
const char* topic_publish = "M2MQTT_Unity/sensor/LDR";
const char* topic_subscribe = "M2MQTT_Unity/LED";
const char* topic_temperature = "M2MQTT_Unity/sensor/temperature";
const char* topic_humidity = "M2MQTT_Unity/sensor/humidity";

WiFiClient wifiClient;
PubSubClient mqtt_client(wifiClient);

constexpr auto baudrate { 9600 };
constexpr auto bitduration { 1.f / baudrate };
constexpr auto preDelayBR { bitduration * 9.6f * 3.5f * 1e6 };
constexpr auto postDelayBR { bitduration * 9.6f * 3.5f * 1e6 };

unsigned long CurrentMillis, PreviousMillis, DataSendingTime = 1000;
byte lightStatus;

void setup() {
  Serial.begin(115200);
  pinMode(LED_Pin, OUTPUT);
  
  Serial.println("\n\nWelcome to OPTA\n");
  
  setup_wifi();
  
  mqtt_client.setServer(mqtt_server, mqtt_port);
  mqtt_client.setCallback(callback);
  mqtt_connect();
  
  mqtt_subscribe(topic_subscribe);
  
  RS485.setDelays(preDelayBR, postDelayBR);
  if (!ModbusRTUClient.begin(baudrate, SERIAL_8E1)) {
    Serial.println("Failed to start Modbus RTU Client!");
    while (1);
  }
}

void loop() {
  if (!mqtt_client.loop()) {
    mqtt_connect();
  }
  mqtt_client.loop();

  int LDR_Value = analogRead(LDR_Pin);
  if (LDR_Value == 0) {
    Serial.println("\n\nFailed to read from LDR sensor!");
  } else {
    Serial.println("\n\nLDR Value: " + String(LDR_Value));
    Serial.println("Light: " + String(lightStatus) + " " + String(lightStatus == 1 ? "ON" : "OFF"));
    delay(3000);
    CurrentMillis = millis();
    if (CurrentMillis - PreviousMillis > DataSendingTime) {
      PreviousMillis = CurrentMillis;
      String pkt = "{";
      pkt += "\"device_id\": \"SENSORS\", ";
      pkt += "\"type\": \"Light\", ";
      pkt += "\"value\": " + String(LDR_Value) + "";
      pkt += "}";
      mqtt_publish((char*) pkt.c_str());
      Serial.println();
      readInputRegisterValues();
    }
  }
}

void setup_wifi() {
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void mqtt_connect() {
  while (!mqtt_client.connected()) {
    Serial.println("Attempting MQTT connection...");
    if (mqtt_client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.println("MQTT Client Connected");
      mqtt_publish((char*)("Hi from " + device_id).c_str());
      mqtt_subscribe(topic_subscribe);
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void mqtt_publish(char * data) {
  mqtt_connect();
  if (mqtt_client.publish(topic_publish, data)) {
    Serial.println("Publish \"" + String(data) + "\" ok");
  } else {
    Serial.println("Publish \"" + String(data) + "\" failed");
  }
}

void mqtt_publish_temperature(float temperature) {
  char buf[8]; // เก็บข้อมูลที่ได้จากการแปลง

  // แปลงค่า float เป็น string ที่มี 2 ตำแหน่งทศนิยม
  String temperatureString = String(temperature, 2); 

  DynamicJsonDocument doc(128);
  doc["device_id"] = "SENSORS";
  doc["type"] = "Temperature";
  doc["value"] = temperatureString;

  char jsonBuffer[128];
  serializeJson(doc, jsonBuffer);

  mqtt_connect();
  if (mqtt_client.publish(topic_temperature, jsonBuffer)) {
    Serial.println("Publish \"" + String(jsonBuffer) + "\" ok");
  } else {
    Serial.println("Publish \"" + String(jsonBuffer) + "\" failed");
  }
}

void mqtt_publish_humidity(float humidity) {
  char buf[8]; // เก็บข้อมูลที่ได้จากการแปลง

  // แปลงค่า float เป็น string ที่มี 2 ตำแหน่งทศนิยม
  String humidityString = String(humidity, 2); 

  DynamicJsonDocument doc(128);
  doc["device_id"] = "SENSORS";
  doc["type"] = "Humidity";
  doc["value"] = humidityString;

  char jsonBuffer[128];
  serializeJson(doc, jsonBuffer);

  mqtt_connect();
  if (mqtt_client.publish(topic_humidity, jsonBuffer)) {
    Serial.println("Publish \"" + String(jsonBuffer) + "\" ok");
  } else {
    Serial.println("Publish \"" + String(jsonBuffer) + "\" failed");
  }
}


void mqtt_subscribe(const char * topic) {
  if (mqtt_client.subscribe(topic)) {
    Serial.println("Subscribe \"" + String(topic) + "\" ok");
  } else {
    Serial.println("Subscribe \"" + String(topic) + "\" failed");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String command;
  Serial.print("\n\nMessage arrived [");
  Serial.print(topic);
  Serial.println("] ");
  for (int i = 0; i < length; i++) {
    command += (char)payload[i];
  }

  if (command.length() > 0) {
    Serial.println("Command received is : " + command);
  }

  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, command);
  if (error) {
    Serial.print("Failed to parse JSON: ");
    Serial.println(error.c_str());
    return;
  }

  JsonObject obj = doc.as<JsonObject>();
  String id = obj["device_id"];
  String type = obj["type"];
  String value = obj["value"];
  Serial.println("\nCommand device_id is : " + id);
  Serial.println("Command type is : " + type);
  Serial.println("Command value is : " + value);

  if (id == device_id && type == "LED") {
    if (value == "1") {
      lightStatus = 1;
      digitalWrite(LED_Pin, HIGH);
    } else {
      lightStatus = 0;
      digitalWrite(LED_Pin, LOW);
    }
  }
}


void readInputRegisterValues() {
  DynamicJsonDocument doc(1024);

  if (!ModbusRTUClient.requestFrom(2, INPUT_REGISTERS , 0x01, 1)) {
    Serial.print("Read temperature failed! ");
    Serial.println(ModbusRTUClient.lastError());
  } else {       
    int16_t temperature_raw = ModbusRTUClient.read();
    float temperature = temperature_raw / 10.0;

    Serial.print("Temperature: ");
    Serial.print(temperature, 2);
    Serial.println(" °C\t");

    doc["temperature"] = temperature;

    char jsonBuffer[128];
    serializeJson(doc, jsonBuffer);

    mqtt_publish_temperature(temperature);

    while (ModbusRTUClient.available()) {
      Serial.print(ModbusRTUClient.read());
      Serial.print(' ');
    }
    Serial.println();
  }

  if (!ModbusRTUClient.requestFrom(2, INPUT_REGISTERS , 0x02, 1)) {
    Serial.print("Read humidity failed! ");
    Serial.println(ModbusRTUClient.lastError());
  } else {
    uint16_t humidity_raw = ModbusRTUClient.read();
    float humidity = humidity_raw / 10.0;

    Serial.print("Humidity: ");
    Serial.print(humidity, 2);
    Serial.println(" %");

    doc["humidity"] = humidity;

    char jsonBuffer[128];
    serializeJson(doc, jsonBuffer);

    mqtt_publish_humidity(humidity);

    while (ModbusRTUClient.available()) {
      Serial.print(ModbusRTUClient.read());
      Serial.print(' ');
    }
    Serial.println();
  }
}

ไฟล์ arduino_secrets.h

#define SECRET_SSID " your_SSID" //ชื่อ WiFi
#define SECRET_PASS " your_PASSWORD" //รหัส WiFi

สิ่งที่ได้เรียนรู้

  • การเขียนโค้ดควบคุมเซ็นเซอร์ XY-MD02 โดยใช้การสื่อสารแบบ RS485 อ่านทั้งค่าอุณหภูมิและความชื้น

1 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ช่วงเช้าจัดทำรูปเล่มรายงาน
  • ช่วงบ่ายทดลองใช้แขนกล โดยควบคุมให้หยิบขวดน้ำจากจุดที่ 1 ไปยังจุดที่ 2 และนำกลับมาวางไว้ที่จุดที่ 1 และทำซ้ำไปเรื่อยๆ

สิ่งที่ได้เรียนรู้

  • การใช้งานแขนกล
  • วิธีการควบคุม อุปกรณ์หรือเครื่องมือต่างๆที่สามารถทำได้
  • ได้ทดลองเขียนโปรแกรมควบคุมแขนกล

2 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • จัดทำรูปเล่มรายงาน

สิ่งที่ได้เรียนรู้

  • การใช้งานเครื่องมือใน Word ที่โปรมากขึ้น
  • วิธีการจัดเรียนหน้า การใส่หัวข้อ

3 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ช่วงเช้าทำรูปเล่มรายงาน
  • ช่วงบ่ายทดลองเล่น HoloLens โดยทดลองเล่นการหยิบจับ 3D เคลื่อนไหวไปมา ย่อ ขยาย

สิ่งที่ได้เรียนรู้

  • การใช้งาน HoloLens วิธีการควบคุม การใช้งานเบื้องต้น
  • ได้ทดลอง HoloLens มีลักษณะอย่างไร ทำงานอย่างไร

4 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • จัดทำรูปเล่มรายงาน

5 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • จัดทำรูปเล่ม

8 กรกฎาคม 2567

งานที่ทำในวันนี้

  • จัดระบบสายไฟที่ต่อกับ Arduino OPTA ที่ใช้ในงานวัด AR ให้เป็นระเบียบมากขึ้น และลกอุปกรณ์ที่ไม่จำเป็นออก
  • ทดลองให้ Unity ที่ใข้ Tools MRTK3 ในการควบคุม การเปิด/ปิดไฟกับ Arduino OPTA ที่สื่อสารกันผ่าน MQTT

สิ่งที่ได้เรียนรู้

  • การลดรูปแบบวงจรให้น้อยลง
  • การเขียนโค้ดให้ทำงานร่วมกับ Unity ผ่าน MQTT

9 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ทดลองใช้ Arduino OPTA ควบคุมรถผ่าน MQTT ให้สามารถสั่งการได้จาก Hololens
  • ศึกษาอุปกรณ์ที่ใช้ติดตั้งรถ
  • ทดลองเขียนโค้ดควบคุมมอเตอร์

ปัญหาที่พบ

  • ติดปัญหาล้อหมุนช้า เนื่องจากมีล้อบางอันของรถหลวม และไม่เท่ากัน

สิ่งที่ได้เรียนรู้

  • การเขียนโค้ดควบคุมมอเตอร์ผ่าน MQTT
  • ศึกษาหาข้อมูลของอุปกรณ์ต่างที่ใช้ในการควบคุมรถ

10 กรกฎาคม 2567

งานที่ทำในวันนี้

  • ทดลองเขียนโค้ดควบคุมรถต่อ โดยวันนี้ทั้งสองล้อสามารถทำงานได้แล้ว
  • สามารถสั่งการจาก MQTT ได้
  • หาโมดูลที่จะนำมาประกอบกับ Arduino OPTA กับ เซ็นเซอร์แสง และอุณหภมิ ที่ใช้รับค่าจาก Unity เพื่อไปแสดงข้อมูลของวัด

ปัญหาที่พบ

  • ไม่เจอโมดูลที่สามารถใช้กับขนาด LED ที่ต้องการ

สิ่งที่ได้เรียนรู้

  • การเขียนโปรแกรมให้สามารถควบคุมมอเตอร์ และทำงารร่วมกับ MQTT

11 กรกฎาคม 2567

งานที่ทำในวันนี้

  • ทำการทดลองต่อ โดยทำการเขียนโค้ดควบคุมมอเตอร์ให้ไปข้างหน้า ซ้าย ขวา และถอยหลัง
  • ทำการทดลองให้ Arduino OPTA เชื่อมต่อเชื่อต่อกับกับ MQTT แบบ Web Socket Secure

ปัญหาที่พบ

  • ยังไม่สามารถวิ่งถอยหลังได้ ทำให้ต้องหาข้อมูลว่าต้องใช้อุปกรณ์อะไรมาช่วยเสริมให้รถสามารถวิ่งถอยหลังได้
  • ยังไม่เจอโมดูลที่สามารถใช้กับขนาด LED ที่ต้องการ
  • ไม่สามารถเชื่อต่อ Arduino OPTA เข้าเก็บ Web Socket Secure เนื่องจากไม่มีไลบรารีมาลองรับ

สิ่งที่ได้เรียนรู้

  • การเขียนโปรแกรมควบคุมมอเตอร์ให้ขยับซ้าย ขวา
  • ได้ทดลองเขียนโปรแกรมให้ Arduino OPTA ใช้งานกับ Web Socket Secure

12 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ทดลองใช้ Arduino OPTA ควบคุมรถผ่าน MQTT ให้สามารถสั่งการได้จาก hololens โดยเพิ่ม Motor Drive Module L298N เข้าไปเพื่อให้สามารถทำให้ตัวรถวิ่งถอยหลังได้
  • ปรับแก้ไขโค้ดเพื่อให้สามารถทำงานได้

สิ่งที่ได้เรียนรู้

  • การใช้งาน Motor Drive Module L298N

15 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ศึกษาการใช้ 3D Printer
  • ค้นหาโมเดลรางสแตนเรท
  • ทดลองปริ้น DIN Rail stand เพื่อที่จะนำมาประกอบกับสแตนเลสสำหรับเป็นรางให้ Arduino OPTA ในงานและเซ็นเซอร์สำหรับงานวัด AR
  • ทดลองใช้ Unity ให้สามารถอัปโหลดลง Hololens

ปัญหาที่พบ

  • เมื่อลองทำ Unity ตามคริป บางอย่างใน Unity ไม่เหมือนกับคริปที่กำลังทดลองทำ ทำให้ต้องทดลองเวอร์ชั่นต่างๆใหม่

สิ่งที่ได้เรียนรู้

  • การใช้เครื่อง 3D Printer
  • การใช้โปรแกรม UltiMaker Cura
  • การใช้งาน Unity การตั้งค่าต่างๆที่เอาไว้ใช้สำหรับการใช้งานกับ HoloLens
  • การเลือกใช้งานของพลาสติกชนิดต่างๆ

16 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ค้นหาโมเดลที่ใช้สำหรับการทำเป็นกรอบไว้ใส่ไฟ LED ที่ใช้เปิดปิดไฟของงานวัด AR Temple
  • ค้นหาโมเดลที่ใช้ยึดเครื่องปริ้น 3D
  • ทดลองใช้ Unity ให้สามารถอัปโหลดลง HoloLens ต่อ

ปัญหาที่พบ

  • ไม่เจอโมดูลที่สามารถใช้กับขนาด LED ที่ต้องการ
  • เมื่อลองลง Unity ใหม่แล้ว พบปัญหากับ Visual Studio 2022 ติดปัญหาปุ่มที่ใช้สำหรับการเชื่อต่อเข้ากับ HoloLens ไม่มีเหมือนในคลิป ทำให้ต้องลองลงหลายๆเวอร์ชั่น

สิ่งที่ได้เรียนรู้

  • การใช้งาน Unity
  • การอัปโหลดและการตั้งค่าต่างๆใน Unity ที่ใช้เชื่อมต่อกับ HoloLens
  • การตั้งค่าต่างๆใน Visual Studio 2022 ที่ใช้เชื่อมต่อกับ HoloLens

17 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ออกแบบตัวจับสำหรับการยึดหลอดไฟ LED เข้ากับราง
  • หาโมเดลสำหรับการยึดตัวจับ LED เข้ากับรางสแตรนเรท
  • ทดลองควบคุม รถ ที่ควบคุมจาก Arduino OPTA จาก MQTT และควบคุมการเคลื่อนไหวจาก HoloLens

สิ่งที่ได้เรียนรู้

  • การออกแบบโมเดล 3D ที่ใช้สำหรับยึด LED

18 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ออกแบบตัวจับสำหรับการยึดหลอดไฟ LED เข้ากับราง
  • หาโมเดลสำหรับการยึดตัวจับ LED เข้ากับราง

ปัญหาที่พบ

  • เมื่อออกแบบตัวยึด LED มาแล้ว คำนวญด้านการใส่ผิดทำให้ต้องหาโมเดลที่ใช้ยึดเข้ากับรางใหม่
  • โมเดลที่หาได้ส่วนใหญ่มีขนาดใหญ่เกินไป และไม่สามารถแก้ไขขนาดได้

สิ่งที่ได้เรียนรู้

  • การออกแบบที่ต้องใช้การความคิดที่ถี่ถ้วนมากขึ้น

19 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ปรับแก้โมเดลตัวยึด LED และ โมเดลสำหรับการยึดเข้ากับราง
  • ทดลองประกอบโมเดล (เสร็จเรียบร้อย)

สิ่งที่ได้เรียนรู้

  • การออกแบบโมเดลต่างๆ

22 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ทดลองให้ Arduino OPTA เชื่อมต่อกับ MQTT แบบ Web Socket Secure
  • ทดลองการเขียนไลบรารีเพื่อให้ใช้งานกับ Web Socket Secure

ปัญหาที่พบ

  • เมื่อทดลองให้ Arduino OPTA เชื่อมต่อกับ Web Socket Secure ไม่สามารถเชื่อมต่อได้ หรือเมื่อเชื่อมต่อได้ ไม่สามารถเข้าถึง Broker ได้
  • เมื่อลองเขียนไลบรารียังไม่สามารถใช้งานได้ เนื่องจากขาดองค์ประกอบหลายอย่าง

สิ่งที่ได้เรียนรู้

  • การใช้ mosquitto ในการเชื่อมต่อกับ MQTT

23 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ทดลองให้ Arduino OPTA เชื่อต่อกับ MQTT แบบ Web Socket ก่อนที่จะไปทำแบบ Web Socket Secure
  • ทดลองให้ Arduino OPTA การควบคุมผ่าน Hololens โดยสื่อสารกันผ่าน MQTT

ปัญหาที่พบ

  • Arduino OPTA ยังไม่สามารถเชื่อมต่อแบบ Web Socket ได้ เนื่องจากการไม่สามารถเรียกใช้บรารี่ websocket client เพราะ Arduino OPTA ไม่รองรับ
  • เมื่อลงให้ Hololens ควบคุม Arduino OPTA แล้วพบว่าไม่สามารถถอยหลังได้ เนื่องจากสายที่เชื่อมต่อจากมอเตอร์ขาด

สิ่งที่ได้เรียนรู้

  • ข้อมูลที่ไลบรารี websocket client ใช้ในการเขียนกับ ESP32

25 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ซ่อมสายจากมอเตอร์ที่ขาด
  • ทดลองใช้ ESP32 ในการเชื่อต่อกับ Web Socket และ Web Socket Secure
  • ทดลองใช้ Arduino OPTA กับ HoloLens ในการควบคุมรถผ่าน MQTT

ปัญหาที่พบ

  • เมื่ออัปโหลดโค้ดไปแล้วไม่สามารถเชื่อต่อกับ Broker ของ MQTT ที่เชื่อมต่อผ่าน Port 8080 และProt 443ได้

สิ่งที่ได้เรียนรู้

  • การเขียนโปรแกรม ESP32 เพื่อเชื่อต่อกับ Web Socket และ Web Socket Secure

26 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • ทดลองเขียน Arduino OPTA กับ Web Socket และ Web Socket Secure

ปัญหาที่พบ

  • Arduino OPTA ติดปัญหาการเข้าถึงไลบรารีที่ใช้เชื่อต่อกับ Web Socket และ Web Socket Secure
  • เมื่ออัปโหลดโค้ดไปแล้วไม่สามารถเชื่อต่อกับ Broker ของ MQTT ที่เชื่อมต่อผ่าน Port 8080 และProt 443ได้

สิ่งที่ได้เรียนรู้

  • Arduino OPTA สามารถสื่อสารได้แค่แบบ TCP

30 กรกฎษคม 2567

สิ่งที่ได้ทำในวันนี้

  • จัดทำสไลด์สำหรับพรีเซ็นสรุปฝึกงาน
  • แก้ไขโค้ดรถให้สมบรูณ์
  • ทดลองการทำงานของระบบวัด AR

โค้ดการทดลอง

โค้ดนี้เป็นการใช้ Arduino OPTA ในการรับคำสั่งจาก HoloLens ในการควบคุมการเคลื่อนที่ของรถ โดยใช้การสื่อสารผ่าน MQTT

#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h"

const int LEFT_MOTOR_IN1 = D0;   // Left Motor Input 1
const int LEFT_MOTOR_IN2 = D1;   // Left Motor Input 2
const int RIGHT_MOTOR_IN3 = D2;  // Right Motor Input 3
const int RIGHT_MOTOR_IN4 = D3;  // Right Motor Input 4

char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

String device_id = "MOTORS";
const char* mqtt_server = "0.tcp.ap.ngrok.io";
const int mqtt_port = 15683;
const char* mqtt_user = "Unity";
const char* mqtt_password = "1234";
const char* mqtt_clientId = " ";  // Unique MQTT client ID
const char* topic_subscribe = "M2MQTT_Unity/robot/control";
 
WiFiClient wifiClient;
PubSubClient mqtt_client(wifiClient);

void setup() {
  Serial.begin(115200);
  pinMode(LEFT_MOTOR_IN1, OUTPUT);
  pinMode(LEFT_MOTOR_IN2, OUTPUT);
  pinMode(RIGHT_MOTOR_IN3, OUTPUT);
  pinMode(RIGHT_MOTOR_IN4, OUTPUT);

  Serial.println("\n\nWelcome to OPTA\n");

  setup_wifi();

  mqtt_client.setServer(mqtt_server, mqtt_port);
  mqtt_client.setCallback(callback);
  mqtt_connect();

  mqtt_subscribe(topic_subscribe);
}

void loop() {
  if (!mqtt_client.connected()) {
    mqtt_connect();
  }
  mqtt_client.loop();
}

void setup_wifi() {
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void mqtt_connect() {
  while (!mqtt_client.connected()) {
    Serial.println("Attempting MQTT connection...");
    if (mqtt_client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.println("MQTT Client Connected");
      mqtt_subscribe(topic_subscribe);
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void mqtt_subscribe(const char* topic) {
  if (mqtt_client.subscribe(topic)) {
    Serial.println("Subscribe \"" + String(topic) + "\" ok");
  } else {
    Serial.println("Subscribe \"" + String(topic) + "\" failed");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String command;
  Serial.print("\n\nMessage arrived [");
  Serial.print(topic);
  Serial.println("] ");
  for (int i = 0; i < length; i++) {
    command += (char)payload[i];
  }

  if (command.length() > 0) {
    Serial.println("Command received is : " + command);
  }

  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, command);
  if (error) {
    Serial.print("Failed to parse JSON: ");
    Serial.println(error.c_str());
    return;
  }

  String id = doc["device_id"];
  String type = doc["type"];
  String value = doc["value"];

  Serial.println("\nCommand device_id is : " + id);
  Serial.println("Command type is : " + type);
  Serial.println("Command value is : " + value);

  if (id == device_id && type == "CONTROL" && value == "stop") {
    stopMoving();
    return;
  }

  if (id == device_id && type == "CONTROL") {
    if (value == "left") {
      moveLeft();
    } else if (value == "right") {
      moveRight();
    } else if (value == "forward") {
      moveForward();
    } else if (value == "backward") {
      moveBackward();
    }
  }
}

void moveRight() {
  digitalWrite(LEFT_MOTOR_IN1, LOW); // Stop left motor
  digitalWrite(LEFT_MOTOR_IN2, LOW); // Stop left motor
  digitalWrite(RIGHT_MOTOR_IN3, HIGH); // Right motor forward
  digitalWrite(RIGHT_MOTOR_IN4, LOW); // Right motor forward
  delay(500); // Replace with millis() for non-blocking delay
  stopMoving();
}

void moveLeft() {
  digitalWrite(LEFT_MOTOR_IN1, HIGH); // Left motor forward
  digitalWrite(LEFT_MOTOR_IN2, LOW); // Left motor forward
  digitalWrite(RIGHT_MOTOR_IN3, LOW); // Stop right motor
  digitalWrite(RIGHT_MOTOR_IN4, LOW); // Stop right motor
  delay(500); // Replace with millis() for non-blocking delay
  stopMoving();
}

void moveForward() {
  digitalWrite(LEFT_MOTOR_IN1, HIGH);
  digitalWrite(LEFT_MOTOR_IN2, LOW);
  digitalWrite(RIGHT_MOTOR_IN3, HIGH);
  digitalWrite(RIGHT_MOTOR_IN4, LOW);
  delay(500); // Replace with millis() for non-blocking delay
  stopMoving();
}

void moveBackward() {
  digitalWrite(LEFT_MOTOR_IN1, LOW);
  digitalWrite(LEFT_MOTOR_IN2, HIGH);
  digitalWrite(RIGHT_MOTOR_IN3, LOW);
  digitalWrite(RIGHT_MOTOR_IN4, HIGH);
  delay(500); // Replace with millis() for non-blocking delay
  stopMoving();
}

void stopMoving() {
  digitalWrite(LEFT_MOTOR_IN1, LOW);
  digitalWrite(LEFT_MOTOR_IN2, LOW);
  digitalWrite(RIGHT_MOTOR_IN3, LOW);
  digitalWrite(RIGHT_MOTOR_IN4, LOW);
} 

ไฟล์ arduino_secrets.h

#define SECRET_SSID " your_SSID" //ชื่อ WiFi
#define SECRET_PASS " your_PASSWORD" //รหัส WiFi

ปัญหาที่พบ

  • รถมีการวิ่งสลับซ้าย ขวา เมื่อกดปุ่มซ้ายรถวิ่งไปทางขวา เนื่องจากโค้ดกำหนดให้เมื่อกดซ้ายมอเตอร์ด้านซ้ายทำงาน เมื่อกดปุ่มขวารถวิ่งไปทางซ้าย เนื่องจากโค้ดกำหนดให้เมื่อกดขวามอเตอร์ด้านขวาทำงาน

สิ่งที่ได้เรียนรู้

  • การขวบคุมมอเตอร์ในการวิ่งซ้าย ขวา

31 กรกฎาคม 2567

งานที่ได้ทำในวันนี้

  • เขียนบล็อกและจะตกแต่งบล็อก
  • ถ่ายวีดีโอการทดลอง
  • แก้ไขสไลด์
  • นำเสนองาน