Heltec-LoRa-WebOTA
สำหรับนักพัฒนา IOT แล้ว การทำ OTA มีความสำคัญมากครับ เพราะจะช่วยให้เราสามารถอัพเดทโปรแกรมให้กับผู้ใช้งานได้ง่ายมาก
โดยในบทความนี้เราจะมาทำการ OTA กันด้วยการ กดรีเซ็ท (SW1) และการตั้งเวลาให้ทำการอัพเดท จาก Server
สำหรับวิธีการกดรีเซ็ทนั้น เราจะใช้การกดและนับจำนวนครั้ง 10 ครั้ง เพื่อป้องกันการเผลอเรอ โดยการนับ จำนวนครั้งเราจะใช้ฟังก์ชั่น Interrupt Serivice Routine ( ISR ) โดยเรามีโค้ดตัวอย่างมาจาก เวบ lastminutesengineer.com โดยบอร์ดหรืออุปกรณ์ของเราจะต้องมีปุ่มสำหรับการกดรีเซ็ทไว้ด้วยตามรูป
เมื่อทำการกดรีเซ็ท SW1 ครบหรือมากกว่า 10 ครั้ง ระบบก็จะทำการดาวน์โหลด ไฟล์ bin ที่เราเตรียมไว้ก่อนหน้าแล้ว จากนั้นระบบก็ทำงานไปตามโปรแกรมใหม่ แต่หากว่าโปรแกรมนั้นเหมือนกับโปรแกรมเดิมที่มีอยู่ในบอร์ดแล้ว มันก็ไม่ใช้โปรแกรมใหม่ครับ
สำหรับโค๊ด ต้นแบบการนับนั้นเป็นดังนี้ครับ
struct Button { const uint8_t PIN; uint32_t numberKeyPresses; bool pressed; }; Button button1 = {36, 0, false}; // GPIO36 void IRAM_ATTR isr() { button1.numberKeyPresses += 1; button1.pressed = true; } void setup() { Serial.begin(115200); pinMode(button1.PIN, INPUT_PULLUP); attachInterrupt(button1.PIN, isr, FALLING); } void loop() { if (button1.pressed) { Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses); button1.pressed = false; } //Detach Interrupt after 1 Minute static uint32_t lastMillis = 0; if (millis() - lastMillis > 60000) { lastMillis = millis(); detachInterrupt(button1.PIN); Serial.println("Interrupt Detached!"); } }
โดย 36 คือ ตำแหน่งขาของ Heltec LoRa esp32
สำหรับวิธีที่ 2 เราจะกำหนดให้โปรแกรมรับสถานะคำสั่งว่าเราต้องการ OTA ที่เวลาไหน โดยเราจะตั้งมาจาก Timer ที่ 10 ของแพลตฟอร์ม หรือ ใครจะดัดแปลงส่งคำสั่งอะไรมากระตุ้นสถานะของ RR_OTA ก็ได้
และยังสามารถกำหนดมาจากแอพมือถืออีกทางหนึ่ง
และ โค้ดสำหรับการทำ OTA นั้นค่อนข้างจะยาว
โดยมีส่วนที่เกี่ยวข้องกับ OTA ดังนี้
บรรทัด 335-390 คือการนำโค้ด ในการนับมารวมในโค้ดหลัก และกำหนดเงื่อนไขเมื่อกดจำนวน 10 ครั้ง แล้ว ให้ไปเรียก ฟังกชั่น ota_run ในบรรทัด 374 โดย ota_run อยู่ในบรรทัดที่ 435-589 นั่นเอง
ส่วนของ OTA ต้องขอขอบคุณอาจารย์ สมศักดิ์ แซ่ลิ้ม จากการอบรมภายใต้โครงการ We Love Smart Farm&IOT ช่วงเดือนกันยายน-พฤศจิกายน 2564 ที่ได้ให้คำแนะนำการใช้งานจนใช้การได้ดีเยี่ยม
ส่วนโค๊ดอื่นๆ ก็แถมมาเหมือนเดิมครับ โดยตั้งใจเก็บไว้ดูกันลืม แต่ในโค๊ดก็เป็นโค๊ดประจำของบอร์ด SMT-IOT-005 จากสมองไอโทีเช่นเคย ที่มีลูกเล่นองค์ประกอบครบถ้วน RS845, Relay มากมาย port อ่าน PZEM, I2C และ AI,DI มากมายก่ายกอง หากสนใจทักทายกันมานะครับ ทางอีเมล์ paipatamp@gmail.com
///////////////////////////////////////////// // DEFINE ///////////////////////////////////////////// #define VERSION "3.0" ///////////////////////////////////////////// // INCLUDE ///////////////////////////////////////////// extern "C" { #include "freertos/FreeRTOS.h" // มีปัญหากับ esp8266 #include "freertos/timers.h" } // CONFIG #include <ArduinoJson.h> #ifdef ESP32 #include <SPIFFS.h> #else #include <FS.h> #endif // WIFI #ifdef ESP32 #include <WiFi.h> #include <WiFiMulti.h> #else #include <ESP8266WiFi.h> #include <ESP8266WiFiMulti.h> #define ARDUINO_EVENT_WIFI_STA_GOT_IP WIFI_EVENT_STAMODE_GOT_IP #define ARDUINO_EVENT_WIFI_STA_DISCONNECTED WIFI_EVENT_STAMODE_DISCONNECTED #endif // OTA #ifdef ESP32 #include <Update.h> #else #include <ESP8266httpUpdate.h> #endif #include <SoftwareSerial.h> // https://github.com/PaulStoffregen/SoftwareSerial #include <Convert.h> #include "ModbusMaster.h" //https://github.com/4-20ma/ModbusMaster #include <ModbusRtu.h> #include <HardwareSerial.h> #include <Arduino.h> #include <Ticker.h> #include "heltec.h" #include <Wire.h> //#include "Wire.h" #include "define.h" #include <math.h> #include <ArduinoJson.h> #include <Arduino_JSON.h> //============== ///============ #define RX_PIN 22 //Serial Receive pin 16 #define TX_PIN 23 //Serial Transmit pin 17 #define MAX485_RE_NEG 25 //LED #define RS485Transmit HIGH #define RS485Receive LOW #define LED 0 float temp,pH ; //========== XYMD02 ========= HardwareSerial RTU_Serial(2); // 1 //#define RXD 22 //#define TXD 23 //#define RS485DE 25 //#define LED 0 Modbus master(0, RTU_Serial, MAX485_RE_NEG); // this is master and RS-232 or USB-FTDI modbus_t telegram[4]; bool restart; uint16_t au16data[8]; float humidity; float temperature; uint8_t RTU_Slave_ID; uint8_t RTU_NEW_Slave_ID; uint8_t Slave_ID; //====== SoftwareSerial RS485Serial(RX_PIN, TX_PIN); //Creation of class object Convert convert; //========== #include <PZEM004Tv30.h> #if !defined(PZEM_RX_PIN) && !defined(PZEM_TX_PIN) #define PZEM_RX_PIN 17 #define PZEM_TX_PIN 13 #endif #if !defined(PZEM_SERIAL) #define PZEM_SERIAL Serial1 #endif #if defined(ESP32) /************************* * ESP32 initialization * --------------------- * * The ESP32 HW Serial interface can be routed to any GPIO pin * Here we initialize the PZEM on Serial2 with RX/TX pins 16 and 17 */ PZEM004Tv30 pzem(PZEM_SERIAL, PZEM_RX_PIN, PZEM_TX_PIN); #elif defined(ESP8266) /************************* * ESP8266 initialization * --------------------- * * Not all Arduino boards come with multiple HW Serial ports. * Serial2 is for example available on the Arduino MEGA 2560 but not Arduino Uno! * The ESP32 HW Serial interface can be routed to any GPIO pin * Here we initialize the PZEM on Serial2 with default pins */ //PZEM004Tv30 pzem(Serial1); #else /************************* * Arduino initialization * --------------------- * * Not all Arduino boards come with multiple HW Serial ports. * Serial2 is for example available on the Arduino MEGA 2560 but not Arduino Uno! * The ESP32 HW Serial interface can be routed to any GPIO pin * Here we initialize the PZEM on Serial2 with default pins */ PZEM004Tv30 pzem(PZEM_SERIAL); #endif // #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); // //========= //#include <WiFi.h> //====== //=================== #include <Adafruit_Sensor.h> #include <DHT.h> // กรณีนี้ต้องใช้คู่กันกับ DHT_U.h #include <DHT_U.h> // See guide for details on sensor wiring and usage: // https://learn.adafruit.com/dht/overview uint32_t delayMS; //=========== #define Slave_ID1 1 // see dip swith if connect to Transpower #include "heltec.h" #include "images.h" #define BAND 915E6 //you can set band here directly,e.g. 868E6,915E6,433E6 // instantiate ModbusMaster object ModbusMaster modbus; /// ///////////////////////////////////////////// // GLOBAL VARIABLES ///////////////////////////////////////////// // CONFIG // OTA WiFiClient otaClient; //=== Ticker _service_rtc; Ticker _service_sensor; Ticker _service_led; //Ticker _service_test_1; //Ticker _service_test_2; //Ticker _service_test_3; TwoWire I2C0 = TwoWire(0); adsGain_t m_gain; uint8_t m_bitShift; uint16_t m_dataRate; uint8_t Relay, gpio_in; uint16_t delayx, count_read; uint8_t i2c_address_adc; int16_t adc0, adc1, adc2, adc3; float volts0, volts1, volts2, volts3; uint32_t lastreading; char cstr[8]; byte global_second, global_minute, global_hour, global_dayOfWeek, global_dayOfMonth, global_month, global_year; //=== double res_dbl0; double res_dbl1; double res_dbl ; unsigned int counter = 0; String rssi = "RSSI --"; String packSize = "--"; String packet ; String RS485_Data[13]; //====== const char* ssid = "xxxxxxxx"; const char* password = "xxxxxxxxx"; const char* ssid1 = "xxxxxxxx"; const char* password1 = "xxxxxxxx"; const char* ssid2 = "xxxxxxxx"; const char* password2 = "xxxxxxxx"; //===== const char* host = "xxxxxxxx.com"; char* code = "xxxxxxxx"; char* dID = "xxxx"; float dustDensity = 35; String response ="0"; String response_c = "0"; String a ; int npress ; // // float temp_0 = 0; float humid_0 = 0; float vHumidity = 0; float vTemperature = 0; float vPower=0; float vVolt=0; float iamp=0; float vEnergy=0; float voltage; float current; float power; float energy; float frequency; float pf; String data0 ; // for data request ; String data1 ; String datasend ; String datasend1 ; String datasend2 ; String data2 ; String data3 , dataa3 ; String data4 , dataa4 ; String data5 ; String data6 ; String data7 ; String data8 ; String data9 ; String JSONSerial = ""; float jdata1,jdata2,jdata3,jdata4; /// === String sdata1 ; String sdata2 ; // standard String sdata3 ; String sdata4 ; String sdata5 ; String sdata6 ; String sdata7 ; String sdata8 ; String sdata11; String sdata12 ; String master_state ; String FlowLowStatus ; String ResetPinValue ; String MainPump ; String PumpA ; String PumpB ; String flowsensor ; String led1 = "00:00"; String led2 = "00:00"; String led3 = "1"; String Time1 ; String Time2 ; String R1,R2,R3,R4,R5,R6,R7,R8 ; String RR1,RR2,RR3,RR4,RR5,RR6,RR7,RR8,R_OTA,RR_OTA ; String CommandR3Slave = "Off" ; // to control R3 on Nano String CommandR4Slave ; // to control R4 on board float data10 = 0; float data11 = 0; float data12 = 0; float data13 = 0; float data14 = 0; float data15 = 0; float data16 = 0; float data17 = 0; float data18 = 0; float data19 = 0; float data20 = 0; float EC ; float temperatureC = 0; float temperatureF = 0; float sensorValue = 0; float rainmm = 0; //int counter = 1; int i ; int sentcount = 0; String url ; int Relay1 = 12 ; int Relay2 = 2 ; // String iddevice = dID; String cccode = code; String ccode = code; long lastMillis = 100; /// === String sentpacket ; String str; char charBuf[100]; // Convent 32bit to float //------------------------------------------------ float HexTofloat(uint32_t x) { return (*(float*)&x); } uint32_t FloatTohex(float x) { return (*(uint32_t*)&x); } //------------------------------------------------ //// GPIO36 User Switch struct Button { const uint8_t PIN; uint32_t numberKeyPresses; bool pressed; }; Button button1 = {36, 0, false}; // GPIO36 void IRAM_ATTR isr() { button1.numberKeyPresses += 1; button1.pressed = true; npress = button1.numberKeyPresses; } //// ///////// void OTA_reset_setup() { pinMode(button1.PIN, INPUT_PULLUP); attachInterrupt(button1.PIN, isr, FALLING); } void OTA_SW_loop() { //RR_OTA = "0"; if (button1.pressed) { Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses); button1.pressed = false; //RR_OTA = "1"; } if(npress >= 10) { npress=0; button1.numberKeyPresses=0; Serial.println("Otrix-OTA: START"); char* ota_host = "xxxxxxxx.com"; uint16_t ota_port = 80; char* ota_path = "/xxxxx/xxxx.bin"; ota_run(ota_host, ota_port, ota_path); //Serial.println("Restarting with new firmware ... "); //restart = true; } /* //Detach Interrupt after 1 Minute static uint32_t lastMillis = 0; if (millis() - lastMillis > 60000) { lastMillis = millis(); detachInterrupt(button1.PIN); Serial.println("Interrupt Detached!"); } */ } /////// /// OTRIXOTA void Otrix_OTA() { if(RR_OTA == "1") { Serial.println("Otrix-OTA: START"); char* ota_host = "xxxxxxxx.com"; uint16_t ota_port = 80; char* ota_path = "/xxxxxx/xxxx.bin"; ota_run(ota_host, ota_port, ota_path); //Serial.println("Restarting with new firmware ... "); //restart = true; } } /// ///////////////////////////////////////////// // CONFIG ///////////////////////////////////////////// ///////////////////////////////////////////// // WIFI ///////////////////////////////////////////// //void wifi_event(WiFiEvent_t event) { // if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) { // ARDUINO_EVENT_WIFI_STA_GOT_IP // Serial.println("WIFI: Connected"); // Serial.print("WIFI: IP="); // Serial.println(WiFi.localIP()); // } else if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) { // ARDUINO_EVENT_WIFI_STA_DISCONNECTED // Serial.println("WIFI: Disconnected"); // } //} ///////////////////////////////////////////// // MQTT ///////////////////////////////////////////// ///////////////////////////////////////////// // OTA Over-The-Air ///////////////////////////////////////////// String ota_getHeaderValue(String header, String headerName) { return header.substring(strlen(headerName.c_str())); } void ota_run(char *ota_host, uint16_t ota_port, char *ota_path) { #ifdef ESP8266 ESPhttpUpdate.update(otaClient, ota_host, ota_port, ota_path); #else // ESP32 long contentLength = 0; bool isValidContentType = false; Serial.println("OTA: READY"); Serial.println("Connecting to: " + String(ota_host)); // Connect to S3 if (otaClient.connect(ota_host, ota_port)) { // Connection Succeed. // Fecthing the bin Serial.println("Fetching Bin: " + String(ota_path)); // Get the contents of the bin file otaClient.print(String("GET ") + ota_path + " HTTP/1.1\r\n" + "Host: " + ota_host + "\r\n" + "Cache-Control: no-cache\r\n" + "Connection: close\r\n\r\n"); // Check what is being sent // Serial.print(String("GET ") + bin + " HTTP/1.1\r\n" + // "Host: " + host + "\r\n" + // "Cache-Control: no-cache\r\n" + // "Connection: close\r\n\r\n"); unsigned long timeout = millis(); while (otaClient.available() == 0) { if (millis() - timeout > 5000) { Serial.println("Client Timeout !"); otaClient.stop(); return; } } // Once the response is available, // check stuff /* Response Structure HTTP/1.1 200 OK x-amz-id-2: NVKxnU1aIQMmpGKhSwpCBh8y2JPbak18QLIfE+OiUDOos+7UftZKjtCFqrwsGOZRN5Zee0jpTd0= x-amz-request-id: 2D56B47560B764EC Date: Wed, 14 Jun 2017 03:33:59 GMT Last-Modified: Fri, 02 Jun 2017 14:50:11 GMT ETag: "d2afebbaaebc38cd669ce36727152af9" Accept-Ranges: bytes Content-Type: application/octet-stream Content-Length: 357280 Server: AmazonS3 {{BIN FILE CONTENTS}} */ while (otaClient.available()) { // read line till /n String line = otaClient.readStringUntil('\n'); // remove space, to check if the line is end of headers line.trim(); // if the the line is empty, // this is end of headers // break the while and feed the // remaining `client` to the // Update.writeStream(); if (!line.length()) { //headers ended break; // and get the OTA started } // Check if the HTTP Response is 200 // else break and Exit Update if (line.startsWith("HTTP/1.1")) { if (line.indexOf("200") < 0) { Serial.println("Got a non 200 status code from server. Exiting OTA Update."); break; } } // extract headers here // Start with content length if (line.startsWith("Content-Length: ")) { contentLength = atol((ota_getHeaderValue(line, "Content-Length: ")).c_str()); Serial.println("Got " + String(contentLength) + " bytes from server"); } // Next, the content type if (line.startsWith("Content-Type: ")) { String contentType = ota_getHeaderValue(line, "Content-Type: "); Serial.println("Got " + contentType + " payload."); if (contentType == "application/octet-stream") { isValidContentType = true; } } } } else { // Connect to S3 failed // May be try? // Probably a choppy network? Serial.println("Connection to " + String(host) + " failed. Please check your setup"); // retry?? // execOTA(); } // Check what is the contentLength and if content type is `application/octet-stream` Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType)); // check contentLength and content type if (contentLength && isValidContentType) { // Check if there is enough to OTA Update bool canBegin = Update.begin(contentLength); // If yes, begin if (canBegin) { Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!"); // No activity would appear on the Serial monitor // So be patient. This may take 2 - 5mins to complete size_t written = Update.writeStream(otaClient); if (written == contentLength) { Serial.println("Written : " + String(written) + " successfully"); } else { Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?" ); // retry?? // execOTA(); } if (Update.end()) { Serial.println("OTA done!"); if (Update.isFinished()) { Serial.println("Update successfully completed. Rebooting."); ESP.restart(); } else { Serial.println("Update not finished? Something went wrong!"); } } else { Serial.println("Error Occurred. Error #: " + String(Update.getError())); } } else { // not enough space to begin OTA // Understand the partitions and // space availability Serial.println("Not enough space to begin OTA"); otaClient.flush(); } } else { Serial.println("There was no content in the response"); otaClient.flush(); } #endif } ///////////////////////////////////////////// // ///////////////////////////////////////////// ////////////////////////////////////////////////////////// void Aboutme() { Serial.println("File name : SMT-005-Dev-303-Asynch-Json-mr-01-01-OK-OTA-Success-Orig"); Serial.println("I2C-AM2315"); Serial.println("PZEM004T V3"); Serial.println("RS485-Soil Sensor"); Serial.println("RE485-XYMD02"); Serial.println("Timer 6,7,8 = Relay 6,7,8 "); delay(2000); } ///////////////////////////////////////////////////////// void setup_XYMD02() { delay(250); Serial.begin(115200); pinMode(LED, OUTPUT); pinMode(MAX485_RE_NEG, OUTPUT); digitalWrite( MAX485_RE_NEG, LOW );//RX RTU_Serial.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN); master.start(); master.setTimeOut( 1000 ); // if there is no answer in 2000 ms, roll over humidity = 0.00; temperature = 0.00; //RTU_Slave_ID = 0; //RTU_NEW_Slave_ID = 1; //Change_Slave_ID(RTU_Slave_ID, RTU_NEW_Slave_ID); } void setup_SMT005(void) { delay(200); pinMode(ESP32_LED, OUTPUT); Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Disable*/, true /*Serial Enable*/); Heltec.display->setContrast(255); Heltec.display->clear(); delay(1000); I2C_Address_Scan(); INIT_MCP23017(); Relay = 0; Write_MCP23017(ADDRESS_MCP23017, MCP23017_GPIOB, Relay);//update off all relay // DS3231 seconds, minutes, hours, day, date, month, year //set_time_ds1307(0, 47, 23, 2, 20, 9, 21); m_bitShift = 0; m_gain = GAIN_TWOTHIRDS; m_dataRate = RATE_ADS1115_128SPS; //RATE_ADS1115_8SPS; //RATE_ADS1115_128SPS; delay(20); count_read = 0; //_service_rtc.attach(1, service_rtc); // interval 1 sec //_service_sensor.attach(5, service_sensor); // interval 5 sec _service_led.attach(0.5, service_led); // interval 500 msec // _service_test_1.attach(1, service_test_1); // _service_test_2.attach(2, service_test_2); // _service_test_3.attach(3, service_test_3); //Show_1_OLED(); //Show_2_OLED(); } //=== void preTransmission() { digitalWrite(MAX485_RE_NEG, HIGH); //Switch to transmit data } void postTransmission() { digitalWrite(MAX485_RE_NEG, LOW); //Switch to receive data } //==== void logo() { Heltec.display->clear(); Heltec.display->drawXbm(0,5,logo_width,logo_height,logo_bits); Heltec.display->display(); } //////// void WiFisetup() { Serial.println(); Serial.print("Connecting to "); Serial.println(ssid1); WiFi.begin(ssid1, password1); delay(1500); if (WiFi.status() != WL_CONNECTED) { delay(500); Serial.println("Failed to connected ssdi1 and WiFi setup "); WiFi.begin(ssid2, password2); delay(1500); if (WiFi.status() != WL_CONNECTED) { delay(500); Serial.println("Failed to connected ssdi 2 and WiFi setup "); } else{ ssid = ssid2; password = password2; } } else{ ssid = ssid1; password = password1; Serial.println(""); Serial.println("WiFi connected OK"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } } //// void RS485_setup() { pinMode(MAX485_RE_NEG, OUTPUT); // Init in receive mode digitalWrite(MAX485_RE_NEG, LOW); // Modbus communication runs at 9600 baud // Serial.begin(9600, SERIAL_8N1); //RS485Serial.begin(9600); // , SERIAL_8N1, RX_PIN, TX_PIN); Serial2.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN); // serial can be no1 , no 2 8N1 modbus.begin(Slave_ID1, Serial2);// Serial2 // Callbacks allow us to configure the RS485 transceiver correctly modbus.preTransmission(preTransmission); modbus.postTransmission(postTransmission); } void Soil_Sensor_RS485_setup() { pinMode(MAX485_RE_NEG, OUTPUT); // Modbus communication runs at 9600 baud RS485Serial.begin(9600); // , SERIAL_8N1, RX_PIN, TX_PIN); } bool state = true; /// for gateway /* void LoRaData(){ Heltec.display->clear(); Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT); Heltec.display->setFont(ArialMT_Plain_10); Heltec.display->drawString(0 , 15 , "Received "+ packSize + " bytes"); Heltec.display->drawStringMaxWidth(0 , 26 , 128, packet); Heltec.display->drawString(0, 0, rssi); Heltec.display->display(); } */ /* void cbk(int packetSize) { packet =""; packSize = String(packetSize,DEC); for (int i = 0; i < packetSize; i++) { packet += (char) LoRa.read(); } rssi = "RSSI " + String(LoRa.packetRssi(), DEC) ; LoRaData(); //sentpacket =packet; } */ /// for gateway void WiFiForwardSetup() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); /* while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } */ Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void setup() { //WIFI Kit series V1 not support Vext control //mqt_setup(); //Serial.begin(115200); Aboutme(); OTA_reset_setup(); setup_XYMD02(); setup_SMT005(); WiFi.setAutoReconnect(true); WiFi.persistent(true); setup_LCD(); WiFiForwardSetup(); Heltec.begin(true /*DisplayEnable Enable*/, true /*Heltec.Heltec.Heltec.LoRa Disable*/, true /*Serial Enable*/, true /*PABOOST Enable*/, BAND /*long BAND*/); // ถ้า true หรือ Enable display จะใช้การ I2C AM2315 ไม่ได้ Heltec.display->init(); Heltec.display->flipScreenVertically(); Heltec.display->setFont(ArialMT_Plain_10); logo(); delay(1500); Heltec.display->clear(); Heltec.display->drawString(0, 0, "Heltec.LoRa Initial success!"); Heltec.display->display(); delay(1000); //RS485_setup(); //Soil_Sensor_RS485_setup(); //LoRa.onReceive(cbk); //LoRa.receive(); } void loop() { /* RS485_loop(); datasend2 = String(res_dbl0)+","+String(res_dbl1)+","+String(45.00)+","+String(25.75)+","+String(100.05); datasend1 = String(cccode)+","+String(177)+","+String(res_dbl0)+","+String(res_dbl1); datasend = datasend1+","+datasend2; */ Otrix_OTA(); // OTA Serial.println("======================================"); Serial.print("Version : ");Serial.println(VERSION); Serial.println("======================================"); Heltec.display->clear(); Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT); Heltec.display->setFont(ArialMT_Plain_10); Heltec.display->drawString(0, 0, "CKC Srithanya : "); Heltec.display->drawString(0, 10, "Data : "); Heltec.display->drawString(0,20, String(datasend1)); Heltec.display->drawString(0,30, String(datasend2)); Heltec.display->display(); counter=counter+1; // send packet // LoRa.beginPacket(); Serial.println("Ser Read position 1 ..."); // serRead(); //delay(2000); // wait for a second //Serial_read_loop(); // remove comment if to connect serial /* * LoRa.setTxPower(txPower,RFOUT_pin); * txPower -- 0 ~ 20 * RFOUT_pin could be RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO * - RF_PACONFIG_PASELECT_PABOOST -- LoRa single output via PABOOST, maximum output 20dBm * - RF_PACONFIG_PASELECT_RFO -- LoRa single output via RFO_HF / RFO_LF, maximum output 14dBm */ /* LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST); LoRa.print(datasend); //LoRa.print(counter); LoRa.endPacket(); */ //Relay_ON_OFF(RELAY5, ON); SMT_loop(); //RS485_loop2(); Energy(); //Soil_SensorTH_loop(); XYMD02_loop(); delay(1000); if (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Failed to connected and will restart WiFi setup "); WiFi.disconnect(); //WiFi.begin(ssid, password); WiFiForwardSetup(); } Forward_loop(); datasend2 = String(data7)+","+String(80)+","+String(90)+","+String(10); datasend1 = String(data3)+","+String(data4)+","+String(55)+","+String(66); datasend = datasend1+","+datasend2; Serial.println(datasend); /* LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST); LoRa.print(datasend); //LoRa.print(counter); LoRa.endPacket(); LoRa.print(counter); */ Serial.println("Start SerRead loop ... "); LCD_display(); LCD_pH(); read_master_status_FromServer(); Relay_Actuator(); LCD_Pump_Status(); LCD_Time_Setting(); LCD_Control_Setting; //data1 = sdata11; //data2 = sdata12; //Relay_Actuator(); //test_on_relay(); //test_off_relay(); OTA_SW_loop(); } // RS485 loop void RS485_loop1() { ///========================= // Toggle the coil at address 0x0002 (Manual Load Control) uint16_t result = modbus.writeSingleCoil(0x0002, state); state = !state; // Read 16 registers starting at 0x3100) result = modbus.readInputRegisters(0x3100, 16); if (result == modbus.ku8MBSuccess) { Serial.print("Vbatt: "); Serial.println(modbus.getResponseBuffer(0x04)/100.0f); Serial.print("Vload: "); Serial.println(modbus.getResponseBuffer(0xC0)/100.0f); Serial.print("Pload: "); Serial.println((modbus.getResponseBuffer(0x0D) + modbus.getResponseBuffer(0x0E) << 16)/100.0f); } ///======= long currentMillis = millis(); if (currentMillis - lastMillis > 1000) { float result = modbus.readHoldingRegisters(0x01,20); // 0x32 is ok for PM2230 from 10 will get 2 voltage // soil sensor from address 02 if (getResultMsg(&modbus, result)) { Serial.println(); float res_dbl = modbus.getResponseBuffer(1); float value = res_dbl; String res = "Voltage A : " + String(res_dbl) + " Vac\r\n"; Serial.println(res); data2 = String(res_dbl); res_dbl = value - modbus.getResponseBuffer(2) ; res = "Voltage B : " + String(res_dbl) + " Vac\r\n"; Serial.println(res); data3 = String(res_dbl); res_dbl = modbus.getResponseBuffer(3); res = "Voltage C : " + String(res_dbl) + " \r\n"; Serial.println(res); data4 = String(res_dbl); res_dbl = modbus.getResponseBuffer(4); res = "Frequency : " + String(res_dbl) + " Vac\r\n"; Serial.println(res); data5 = String(res_dbl); res_dbl = modbus.getResponseBuffer(5); res = "Hz : " + String(res_dbl) + " Vac\r\n"; Serial.println(res); data6 = String(res_dbl); res_dbl = modbus.getResponseBuffer(6)/100; res = "Value 26 : " + String(res_dbl) + " Vac\r\n"; Serial.println(res); data7 = String(res_dbl); res_dbl = modbus.getResponseBuffer(7)/100; res = "Power : " + String(res_dbl) + " watt\r\n"; Serial.println(res); data8 = String(res_dbl); res_dbl = modbus.getResponseBuffer(8); res = "Value 28 : " + String(res_dbl) + " Vac\r\n"; Serial.println(res); //delay(2000); data9 = String(res_dbl); } lastMillis = currentMillis; } } bool getResultMsg(ModbusMaster *node, uint16_t result) { String tmpstr2 = "\r\n"; switch (result) { case node->ku8MBSuccess: return true; break; case node->ku8MBIllegalFunction: tmpstr2 += "Illegal Function"; break; case node->ku8MBIllegalDataAddress: tmpstr2 += "Illegal Data Address"; break; case node->ku8MBIllegalDataValue: tmpstr2 += "Illegal Data Value"; break; case node->ku8MBSlaveDeviceFailure: tmpstr2 += "Slave Device Failure"; break; case node->ku8MBInvalidSlaveID: tmpstr2 += "Invalid Slave ID"; break; case node->ku8MBInvalidFunction: tmpstr2 += "Invalid Function"; break; case node->ku8MBResponseTimedOut: tmpstr2 += "Response Timed Out"; break; case node->ku8MBInvalidCRC: tmpstr2 += "Invalid CRC"; break; default: tmpstr2 += "Unknown error: " + String(result); break; } Serial.println(tmpstr2); return false; } /////////////////////////////////// int value = 0; void Forward_loop() { ++value; Serial.print("connecting to server Otrixiot .... "); Serial.println(host); // Use WiFiClient class to create TCP connections WiFiClient client; const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return; } // We now create a URI for the request String url = "/api/insertData?device_id=" + String(iddevice)+"&code="+String(ccode)+"&data1=" +String(11) +"&data2=" + String(22)+"&data3=" +String(data3)+"&data4=" +String(data4)+"&data5=" +String(55) +"&data6=" +String(6)+"&data7=" +String(7)+"&data8=" +String(8)+"&data9=" +String(9) +"&data10=" +String(10)+"&data11=" +String(11)+"&data12=" +String(12)+"&data13=" +String(13) +"&data14=" +String(14)+"&data15=" +String(15)+"&data16=" +String(16)+"&data17=" +String(17) +"&data18=" +String(18)+"&data19=" +String(19)+"&data20=" +String(20); 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"); unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 5000) { Serial.println(">>> Client Timeout !"); client.stop(); return; } } // Read all the lines of the reply from server and print them to Serial while(client.available()) { String line = client.readStringUntil('\r'); //Serial.print(line); } Serial.println(); Serial.println("closing connection"); delay(1000); } //==== //==== void splint_string(char sz[]){ // สร้างฟังชันต์ชื่อ splint_string กำหนดตัวแปรนำเข้าชื่อ sz ชนิด char แบบอาเรย์ char *p = sz; // สร้างตัวแปรชื่อ p ชนิด Pointer มีค่าเท่ากับ sz char *str; // สร้างตัวแปรชื่อ str ชนิด Pointer int counter = 0; // สร้างตัวแปรชื่อ counter ชนิด int สำหรับทำการนับครั้งที่ตัด while ((str = strtok_r(p, ",", &p)) != NULL){ // วนทำลูป while ซ้ำ โดยเรียกฟังชันต์ strtok_r() โดยทำการตัดค่าใน p เมื่อเจอเครื่องหมาย',' // Serial.print(counter + String(". ")); // แสดงผลจำนวนครั้งที่ตัด // Serial.println(str); // แสดงผลค่าที่ตัดได้ counter++; if (counter ==1){ccode = str;} if (counter ==2){iddevice = str;} if (counter ==3){data1 = str;} if (counter ==4){data2 = str;} if (counter ==5){data3 = str;} if (counter ==6){data4 = str;} if (counter ==7){data5 = str;} if (counter ==8){data6 = str;} } counter = 0; // เคลียร์ค่าใน counter เป็น 0 } void dataread_loop() { //char charBuf[100]; str = packet; str.toCharArray(charBuf, 100); // คัดลอกอักขระของชุดอักขระไปยังตัวแปร charBuf splint_string(charBuf); // เรียกใช้งานฟังชั่น Splint String //delay(1000); } void RS485_loop2() { ///========================= preTransmission(); digitalWrite(RX_PIN,HIGH); ///======= long currentMillis = millis(); if (currentMillis - lastMillis > 1000) { uint8_t result = modbus.readHoldingRegisters(0x02,2); // 0x32 is ok for PM2230 from 10 will get 2 voltage if (getResultMsg(&modbus, result)) { Serial.println(); float res_dbl = modbus.getResponseBuffer(0)/10; float value = res_dbl; String res = "data11 Soil Humidity : " + String(res_dbl) + " %\r\n"; Serial.println(res); sdata11 = String(res_dbl); res_dbl = value - modbus.getResponseBuffer(1)/10 ; res = "data12 Soil Temp : " + String(res_dbl) + " C\r\n"; Serial.println(res); sdata12 = String(res_dbl); } lastMillis = currentMillis; } } void PumpTrial() { Serial.println("Starting pump for 1 minutes ..."); //MainPumpRun(); //delay(1000); } void ResetSystem() { digitalRead(3); ResetPinValue = String(digitalRead(3)); if (ResetPinValue == "1") { PumpTrial(); } } void MainPumpRun() { //Relay_ON_OFF(RELAY8, ON); } void MainPumpStop() { //Relay_ON_OFF(RELAY8, OFF); } void RequestFlowLowStatus() { } //// read control ==== void read_master_status_FromServer() { Serial.print("Reading control command from Server ... connecting to "); Serial.println(host); WiFiClient client; delay(1500); if (client.connect(host, 80)) { Serial.println("reconnecting..."); url = "/api/getRealyStatus/"+String(dID)+"/"+String(code)+"/"+"abZYrshRYR243askdSKSKSK5646dkfmTURDsand"; Serial.print("Requesting URL: "); //Serial.println(url); // comment to prevent hacker client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); delay(2000); String section="header"; while(client.available()) { //Serial.println("Connection available "); String line = client.readStringUntil('\r'); //Serial.print(line); // we’ll parse the HTML body here if (section=="header") { // headers.. if (line=="\n") { // skips the empty space at the beginning section="json"; } } else if (section=="json") { // print the good stuff section="ignore"; String result = line.substring(1); // Parse JSON int size = result.length() + 1; char json[size]; result.toCharArray(json, size); StaticJsonDocument <2000> doc; //StaticJsonBuffer<2000> jsonBuffer; DeserializationError error = deserializeJson(doc, json); //JsonObject& json_parsed = jsonBuffer.parseObject(json); //if (!json_parsed.success()) // { // Serial.println("parseObject() failed"); // return; // } if (error) return; Serial.println("parseObject() OK ..."); //Serial.println(result); // show all json found //String led = json_parsed["led"][0]["status"]; String master_state = doc["result"]["masterStatus"]; String led1 = doc["result"]["relayStatus"]["data6_H"]; String led2 = doc["result"]["relayStatus"]["data6_L"]; String led3 = doc["result"]["relayStatus"]["data3_status"]; String FlowBypass = doc["result"]["relayStatus"]["data5_status"]; String RR1 = doc["result"]["relayStatus"]["data1_status"]; String RR2 = doc["result"]["relayStatus"]["data2_status"]; String RR3 = doc["result"]["relayStatus"]["data3_status"]; String RR4 = doc["result"]["relayStatus"]["data4_status"]; String RR5 = doc["result"]["relayStatus"]["data5_status"]; String RR6 = doc["result"]["relayStatus"]["data6_status"]; // Timer relay 6 in platform String RR7 = doc["result"]["relayStatus"]["data7_status"]; // Timer relay 7 in platform String RR8 = doc["result"]["relayStatus"]["data8_status"]; // Timer relay 8 in platform String R_OTA = doc["result"]["relayStatus"]["data10_status"]; // Timer relay 8 in platform R1 = RR1; R2 = RR2; R3 = RR3; R4 = RR4; R5 = RR5; R6 = RR6; R7 = RR7; R8 = RR8; RR_OTA=String(R_OTA); Serial.println("Relay : "+String(R1)+" "+String(R2)+" "+String(R3)+" "+String(R4)+" "+String(R5)+" "+String(R6)+" "+String(R7)+" "+String(R8)); // string led = json_parsed["table name""][array number]["value of field"] Serial.print("Relay 1 := ");Serial.println(led1); Serial.print("Master state = ");Serial.println(master_state); Serial.print("R8 for Relay : ");Serial.println(R8); Serial.print("RR_OTA1 : ");Serial.println(RR_OTA); Time1 = led1 ; Time2 = led2 ; /* if (R3 == "1") { Relay_ON_OFF(RELAY3, ON); } else { Relay_ON_OFF(RELAY3, OFF); } */ if (master_state == "0") { MainPumpStop(); MainPump = "Stop"; } else { // this loop master_state == "1 if (R7 == "1") { MainPumpRun(); MainPump = "Run" ; //delay(5000); /// check flow sensor //RequestFlowLowStatus(); if (FlowBypass == "1") { MainPumpRun(); Serial.println("Water Pump in By-pass Mode .. please take care ..."); FlowBypass = "By-Pass"; delay(1000); flowsensor ="--"; } else { if(FlowLowStatus == "1") { MainPumpRun(); flowsensor = "OK"; } else { MainPumpStop(); Serial.println("Flow Low pump will stop "); flowsensor = "NOK"; } FlowBypass = "Protecะed"; } } else { Serial.println("Flow low stop pump check and reset the system ... "); flowsensor = "NOK"; MainPumpStop(); } } /* if (led1 = "0") { digitalWrite(13,LOW); digitalWrite(15,LOW); } else { digitalWrite(13,HIGH); digitalWrite(15,HIGH); } */ Serial.print("Pump Start : ");Serial.println(led1); Serial.print("Pump Stop : ");Serial.println(led2); Serial.print("Led3 : ");Serial.println(led3); Serial.print("Master Status : ");Serial.println(master_state); Serial.print("Timer Relay R5 : ");Serial.println(R5); Serial.print("By-Pass Status : ");Serial.println(FlowBypass); Serial.println("Relay : "+String(R1)+" "+String(R2)+" "+String(R3)+" "+String(R4)+" "+String(R5)+" "+String(R6)+" "+String(R7)+" "+String(R8)); RR_OTA=String(R_OTA); Serial.print("RR_OTA2 : ");Serial.println(RR_OTA); // delay(1000); //LCD_Pump_Status(); } // if found json } // end while client available } // end if host connected else { // if you couldn't make a connection: ///Serial.println("connection failed read server 1"); } } void LCD_display() { } void PumpARun() // run Pump A 10 min { if (EC <= 1000) { //digitalWrite(RELAY8,HIGH); //Relay_ON_OFF(RELAY7, ON); Serial.println("Pump A Run"); } else { //digitalWrite(RELAY8,LOW); Relay_ON_OFF(RELAY7, OFF); Serial.println("Pump A Stop"); } } void PumpBRun() // open water valve 12 Vdc { //digitalWrite(Relay2,HIGH); //Relay_ON_OFF(RELAY8, ON); Serial.println("Pump B Run"); } /************************************************************** Function Name : loop Description : Input : Return : **************************************************************/ void SMT_loop() { service_rtc(); service_sensor(); } void service_rtc() { String str1 = ""; ds1307_display_Time(); str1 = ""; Heltec.display->clear(); Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT); Heltec.display->setFont(ArialMT_Plain_24);//ArialMT_Plain_24 ArialMT_Plain_16 if (global_hour < 10) { str1 = "0"; } str1 += String(global_hour) + " : "; if (global_minute < 10) { str1 += "0"; } str1 += String(global_minute) + " : "; if (global_second < 10) { str1 += "0"; } str1 += String(global_second); Heltec.display->drawString(0, 0, str1); Heltec.display->setFont(ArialMT_Plain_16);//ArialMT_Plain_24 ArialMT_Plain_16 str1 = ""; str1 = "Temp : "; str1 += String(data3) + " .C"; // temp Heltec.display->drawString(0, 25, str1); str1 = ""; str1 = "Hum : "; str1 += String(data4) + " %"; // humidity Heltec.display->drawString(0, 45, str1); Heltec.display->display(); } /************************************************************** Function Name : service_sensor Description : Input : Return : **************************************************************/ void service_sensor() { count_read++; if (!AM2315_ReadData()) { Serial.println("Failed to read data from AM2315"); } Serial.print(" >> Count-Read : "); Serial.print(count_read); Serial.print(" >> Temp *C: "); Serial.print(temp); Serial.print(" >> Hum %: "); Serial.println(humidity); data1 = String(temp); data2 = String(humidity); } /************************************************************** Function Name : service_led Description : Input : Return : **************************************************************/ void service_led() { digitalWrite(ESP32_LED, !digitalRead(ESP32_LED)); } /************************************************************** Function Name : AM2315_ReadData Description : Input : Return : **************************************************************/ uint8_t AM2315_ReadData() { uint8_t reply[10]; // Wake up the sensor Wire.beginTransmission(AM2315_I2CADDR); delay(10); Wire.endTransmission(); delay(5); // OK lets ready! Wire.beginTransmission(AM2315_I2CADDR); Wire.write(AM2315_READREG); Wire.write(0x00); // start at address 0x0 Wire.write(4); // request 4 bytes data Wire.endTransmission(); delay(10); // add delay between request and actual read! Wire.requestFrom(AM2315_I2CADDR, 8); for (uint8_t i = 0; i < 8; i++) { reply[i] = Wire.read(); } if (reply[0] != AM2315_READREG) return false; if (reply[1] != 4) return false; // bytes req'd humidity = reply[2]; humidity *= 256; humidity += reply[3]; humidity /= 10; // Serial.print("H"); Serial.println(humidity); temp = reply[4] & 0x7F; temp *= 256; temp += reply[5]; temp /= 10; // Serial.print("T"); Serial.println(temp); // change sign if (reply[4] >> 7) temp = -temp; return true; } //############################################################# //################### ADC ADS1115 ########################### //############################################################# /************************************************************** Function Name : test_read_adc Description : Input : Return : **************************************************************/ void test_read_adc(uint8_t add) { i2c_address_adc = add; adc0 = ReadADC_SingleEnded(0); adc1 = ReadADC_SingleEnded(1); adc2 = ReadADC_SingleEnded(2); adc3 = ReadADC_SingleEnded(3); volts0 = computeVolts(adc0); volts1 = computeVolts(adc1); volts2 = computeVolts(adc2); volts3 = computeVolts(adc3); if (add == ADDRESS_ADC1_U1) { Serial.print(" AIN1: "); Serial.print(" "); Serial.print(volts0, 5); Serial.println("V"); Serial.print(" AIN2: "); Serial.print(" "); Serial.print(volts1, 5); Serial.println("V"); Serial.print(" AIN3: "); Serial.print(" "); Serial.print(volts2, 5); Serial.println("V"); Serial.print(" AIN4: "); Serial.print(" "); Serial.print(volts3, 5); Serial.println("V"); } else { Serial.print(" AIN5: "); Serial.print(" "); Serial.print(volts0, 5); Serial.println("V"); Serial.print(" AIN6: "); Serial.print(" "); Serial.print(volts1, 5); Serial.println("V"); Serial.print(" AIN7: "); Serial.print(" "); Serial.print(volts2, 5); Serial.println("V"); Serial.print(" AIN8: "); Serial.print(" "); Serial.print(volts3, 5); Serial.println("V"); } } /************************************************************** Function Name : ReadADC_SingleEnded Description : Input : Return : **************************************************************/ int16_t ReadADC_SingleEnded(uint8_t channel) { if (channel > 3) { return 0; } // Start with default values uint16_t config = ADS1X15_REG_CONFIG_CQUE_NONE | // Disable the comparator (default val) ADS1X15_REG_CONFIG_CLAT_NONLAT | // Non-latching (default val) ADS1X15_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low (default val) ADS1X15_REG_CONFIG_CMODE_TRAD | // Traditional comparator (default val) ADS1X15_REG_CONFIG_MODE_SINGLE; // Single-shot mode (default) // Set PGA/voltage range config |= m_gain; // Set data rate config |= m_dataRate; // Set single-ended input channel switch (channel) { case (0): config |= ADS1X15_REG_CONFIG_MUX_SINGLE_0; break; case (1): config |= ADS1X15_REG_CONFIG_MUX_SINGLE_1; break; case (2): config |= ADS1X15_REG_CONFIG_MUX_SINGLE_2; break; case (3): config |= ADS1X15_REG_CONFIG_MUX_SINGLE_3; break; } // Set 'start single-conversion' bit config |= ADS1X15_REG_CONFIG_OS_SINGLE; // Write config register to the ADC ADS1115_Write_Reg(ADS1X15_REG_POINTER_CONFIG, config); // Wait for the conversion to complete while (!conversionComplete()) ; // Read the conversion results return getLastConversionResults(); } /************************************************************** Function Name : computeVolts Description : Input : Return : **************************************************************/ float computeVolts(int16_t counts) { // see data sheet Table 3 float fsRange; switch (m_gain) { case GAIN_TWOTHIRDS: fsRange = 6.144f; break; case GAIN_ONE: fsRange = 4.096f; break; case GAIN_TWO: fsRange = 2.048f; break; case GAIN_FOUR: fsRange = 1.024f; break; case GAIN_EIGHT: fsRange = 0.512f; break; case GAIN_SIXTEEN: fsRange = 0.256f; break; default: fsRange = 0.0f; } return counts * (fsRange / (32768 >> m_bitShift)); } /************************************************************** Function Name : getLastConversionResults Description : Input : Return : **************************************************************/ int16_t getLastConversionResults() { // Read the conversion results uint16_t res = ADS1115_Read_Reg(ADS1X15_REG_POINTER_CONVERT) >> m_bitShift; if (m_bitShift == 0) { return (int16_t)res; } else { // Shift 12-bit results right 4 bits for the ADS1015, // making sure we keep the sign bit intact if (res > 0x07FF) { // negative number - extend the sign to 16th bit res |= 0xF000; } return (int16_t)res; } } /************************************************************** Function Name : conversionComplete Description : Input : Return : **************************************************************/ uint8_t conversionComplete() { return (ADS1115_Read_Reg(ADS1X15_REG_POINTER_CONFIG) & 0x8000) != 0; } /************************************************************** Function Name : ADS1115_Write_Reg Description : Input : Return : **************************************************************/ void ADS1115_Write_Reg(uint8_t reg, uint16_t value) { uint8_t temp[4]; temp[0] = reg; temp[1] = value >> 8; temp[2] = value & 0xFF; Wire.beginTransmission(i2c_address_adc); Wire.write(temp[0]); Wire.write(temp[1]); Wire.write(temp[2]); Wire.endTransmission(); } /************************************************************** Function Name : ADS1115_Read_Reg Description : Input : Return : **************************************************************/ uint16_t ADS1115_Read_Reg(uint8_t reg) { uint8_t temp[4]; temp[0] = reg; Wire.beginTransmission(i2c_address_adc); Wire.write(temp[0]); Wire.endTransmission(); Wire.requestFrom(i2c_address_adc, 2); delayMicroseconds(10); temp[0] = Wire.read(); temp[1] = Wire.read(); return ((temp[0] << 8) | temp[1]); } //############################################################# //###################### DS1307 ############################ //############################################################# /************************************************************** Function Name : decToBcd Description : Input : Return : **************************************************************/ byte decToBcd(byte val) { return ( (val / 10 * 16) + (val % 10) ); } /************************************************************** Function Name : bcdToDec Description : Input : Return : **************************************************************/ byte bcdToDec(byte val) { return ( (val / 16 * 10) + (val % 16) ); } /************************************************************** Function Name : set_time_ds1307 Description : Input : Return : **************************************************************/ void set_time_ds1307( byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) { // sets time and date data to DS1307 Wire.beginTransmission(ADDRESS_DS1307); Wire.write(0); // set next input to start at the seconds register Wire.write(decToBcd(second)); // set seconds Wire.write(decToBcd(minute)); // set minutes Wire.write(decToBcd(hour)); // set hours Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday) Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31) Wire.write(decToBcd(month)); // set month Wire.write(decToBcd(year)); // set year (0 to 99) Wire.endTransmission(); } /************************************************************** Function Name : read_time_ds1307 Description : Input : Return : **************************************************************/ void read_time_ds1307( byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { Wire.beginTransmission(ADDRESS_DS1307); Wire.write(0); // set DS3231 register pointer to 00h Wire.endTransmission(); Wire.requestFrom(ADDRESS_DS1307, 7); // request seven bytes of data from DS3231 starting from register 00h *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } /************************************************************** Function Name : ds1307_display_Time Description : Input : Return : **************************************************************/ void ds1307_display_Time() { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS1307 read_time_ds1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // send it to the serial monitor Serial.print(hour, DEC); // convert the byte variable to a decimal number when displayed Serial.print(":"); if (minute < 10) { Serial.print("0"); } Serial.print(minute, DEC); Serial.print(":"); if (second < 10) { Serial.print("0"); } Serial.print(second, DEC); Serial.print(" "); Serial.print(dayOfMonth, DEC); Serial.print("/"); Serial.print(month, DEC); Serial.print("/"); Serial.println(year, DEC); global_second = second; global_minute = minute; global_hour = hour; global_dayOfMonth = dayOfMonth; global_month = month; global_year = year; global_dayOfWeek = dayOfWeek; //Serial.print(" Day of week: "); /*Serial.print(" : "); switch (dayOfWeek) { case 1: Serial.println("Sunday"); break; case 2: Serial.println("Monday"); break; case 3: Serial.println("Tuesday"); break; case 4: Serial.println("Wednesday"); break; case 5: Serial.println("Thursday"); break; case 6: Serial.println("Friday"); break; case 7: Serial.println("Saturday"); break; }*/ } //############################################################# //#################### MCP23017 ############################## //############################################################# /************************************************************** Function Name : test_read_mcp23017 Description : Input : Return : **************************************************************/ void test_read_mcp23017() { gpio_in = Read_GPIO_MCP23017(ADDRESS_MCP23017); //Serial.println(gpio_in); //Serial.println("-------------------------------------"); if (CHECKBIT(gpio_in, 0)) { Serial.println(" Read Logic In GPA-0 P0 = 1 "); } else { Serial.println(" Read Logic In GPA-0 P0 = 0 "); } if (CHECKBIT(gpio_in, 1)) { Serial.println(" Read Logic In GPA-1 P1 = 1 "); } else { Serial.println(" Read Logic In GPA-1 P1 = 0 "); } if (CHECKBIT(gpio_in, 2)) { Serial.println(" Read Logic In GPA-2 P2 = 1 "); } else { Serial.println(" Read Logic In GPA-2 P2 = 0 "); } if (CHECKBIT(gpio_in, 3)) { Serial.println(" Read Logic In GPA-3 P3 = 1 "); } else { Serial.println(" Read Logic In GPA-3 P3 = 0 "); } if (CHECKBIT(gpio_in, 4)) { Serial.println(" Read Logic In GPA-4 P4 = 1 "); } else { Serial.println(" Read Logic In GPA-4 P4 = 0 "); } if (CHECKBIT(gpio_in, 5)) { Serial.println(" Read Logic In GPA-5 P5 = 1 "); } else { Serial.println(" Read Logic In GPA-5 P5 = 0 "); } if (CHECKBIT(gpio_in, 6)) { Serial.println(" Read Logic In GPA-6 P6 = 1 "); } else { Serial.println(" Read Logic In GPA-6 P6 = 0 "); } if (CHECKBIT(gpio_in, 7)) { Serial.println(" Read Logic In GPA-7 P7 = 1 "); } else { Serial.println(" Read Logic In GPA-7 P7 = 0 "); } //Serial.println("-------------------------------------"); delay(100); } /************************************************************** Function Name : test_off_relay Description : Input : Return : **************************************************************/ void test_off_relay() { delayx = 200; Relay_ON_OFF(RELAY1, OFF); delay(delayx); //test_read_mcp23017(); Relay_ON_OFF(RELAY2, OFF); delay(delayx); //test_read_mcp23017(); Relay_ON_OFF(RELAY3, OFF); delay(delayx); //test_read_mcp23017(); Relay_ON_OFF(RELAY4, OFF); delay(delayx); //test_read_mcp23017(); //Relay_ON_OFF(RELAY5, OFF); delay(delayx); //test_read_mcp23017(); Relay_ON_OFF(RELAY6, OFF); delay(delayx); //test_read_mcp23017(); Relay_ON_OFF(RELAY7, OFF); delay(delayx); //test_read_mcp23017(); Relay_ON_OFF(RELAY8, OFF); delay(delayx); //test_read_mcp23017(); } /************************************************************** Function Name : test_on_relay Description : Input : Return : **************************************************************/ void test_on_relay() { delayx = 200; Relay_ON_OFF(RELAY1, ON); delay(delayx); Serial.println("Relay 1 "); //test_read_mcp23017(); Relay_ON_OFF(RELAY2, ON); delay(delayx); Serial.println("Relay 2 "); //test_read_mcp23017(); Relay_ON_OFF(RELAY3, ON); delay(delayx); Serial.println("Relay 3 "); //test_read_mcp23017(); Relay_ON_OFF(RELAY4, ON); delay(delayx); Serial.println("Relay 4 "); //test_read_mcp23017(); Relay_ON_OFF(RELAY5, ON); delay(delayx); Serial.println("Relay 5 "); //test_read_mcp23017(); Relay_ON_OFF(RELAY6, ON); delay(delayx); Serial.println("Relay 6 "); //test_read_mcp23017(); Relay_ON_OFF(RELAY7, ON); delay(delayx); Serial.println("Relay 7 "); //test_read_mcp23017(); Relay_ON_OFF(RELAY8, ON); delay(delayx); Serial.println("Relay 8 "); //test_read_mcp23017(); } /************************************************************** Function Name : Relay_ON_OFF Description : Input : Return : **************************************************************/ void Relay_ON_OFF(uint8_t relayx, uint8_t onoff) { if (onoff) { SETBIT(Relay, relayx); } else { CLEARBIT(Relay, relayx); } Write_MCP23017(ADDRESS_MCP23017, MCP23017_GPIOB, Relay); } /************************************************************** Function Name : INIT_MCP23017 Description : Input : Return : **************************************************************/ void INIT_MCP23017() { // set defaults! // all inputs on port A and B Write_MCP23017(ADDRESS_MCP23017, MCP23017_IODIRA, 0xFF);//input Write_MCP23017(ADDRESS_MCP23017, MCP23017_IODIRB, 0x00);//Relay output // Turn off interrupt triggers Write_MCP23017(ADDRESS_MCP23017, MCP23017_GPINTENA, 0x00); Write_MCP23017(ADDRESS_MCP23017, MCP23017_GPINTENB, 0x00); // Turn off pull up resistors Write_MCP23017(ADDRESS_MCP23017, MCP23017_GPPUA, 0x00); Write_MCP23017(ADDRESS_MCP23017, MCP23017_GPPUB, 0x00); } /************************************************************** Function Name : Read_GPIO_MCP23017 Description : Input : Return : **************************************************************/ uint8_t Read_GPIO_MCP23017(uint8_t addr) { uint8_t x; Wire.beginTransmission(addr); Wire.write(MCP23017_GPIOA); Wire.endTransmission(); delayMicroseconds(10); Wire.requestFrom(addr, 1); while (Wire.available()) { x = Wire.read(); } return x; } /************************************************************** Function Name : Write_MCP23017 Description : Input : Return : **************************************************************/ void Write_MCP23017(uint8_t addr, uint8_t reg, uint8_t dat) { Wire.beginTransmission(addr); //begins talking to the slave device Wire.write(reg); //selects the IODIRA register Wire.write(dat); //this sets all port A pins to outputs Wire.endTransmission(); delayMicroseconds(20); } /************************************************************** Function Name : Show_1_OLED Description : Input : Return : **************************************************************/ void Show_1_OLED(void) { drawLines(); delay(1000); Heltec.display->clear(); drawRect(); delay(1000); Heltec.display->clear(); fillRect(); delay(1000); Heltec.display->clear(); drawCircle(); delay(1000); Heltec.display->clear(); printBuffer(); delay(1000); Heltec.display->clear(); delay(1000); } /************************************************************** Function Name : Show_2_OLED Description : Input : Return : **************************************************************/ void Show_2_OLED(void) { uint16_t del = 500; for (int i = 0; i < 2; i++) { Heltec.display->setTextAlignment(TEXT_ALIGN_CENTER); Heltec.display->clear(); Heltec.display->display(); Heltec.display->screenRotate(ANGLE_0_DEGREE); Heltec.display->setFont(ArialMT_Plain_16); Heltec.display->drawString(64, 32 - 16 / 2, "ROTATE_0"); Heltec.display->display(); delay(del); Heltec.display->clear(); Heltec.display->display(); Heltec.display->screenRotate(ANGLE_90_DEGREE); Heltec.display->setFont(ArialMT_Plain_10); Heltec.display->drawString(32, 64 - 10 / 2, "ROTATE_90"); Heltec.display->display(); delay(del); Heltec.display->clear(); Heltec.display->display(); Heltec.display->screenRotate(ANGLE_180_DEGREE); Heltec.display->setFont(ArialMT_Plain_16); Heltec.display->drawString(64, 32 - 16 / 2, "ROTATE_180"); Heltec.display->display(); delay(del); Heltec.display->clear(); Heltec.display->display(); Heltec.display->screenRotate(ANGLE_270_DEGREE); Heltec.display->setFont(ArialMT_Plain_10); Heltec.display->drawString(32, 64 - 10 / 2, "ROTATE_270"); Heltec.display->display(); delay(del); } Heltec.display->setTextAlignment(TEXT_ALIGN_CENTER); Heltec.display->clear(); Heltec.display->display(); Heltec.display->screenRotate(ANGLE_0_DEGREE); Heltec.display->setFont(ArialMT_Plain_16); Heltec.display->drawString(64, 32 - 16 / 2, "ROTATE_0"); Heltec.display->display(); delay(del); delay(del); Heltec.display->clear(); Heltec.display->display(); } /************************************************************** Function Name : drawLines Description : Input : Return : // Adapted from Adafruit_SSD1306 **************************************************************/ void drawLines(void) { for (int16_t i = 0; i < DISPLAY_WIDTH; i += 4) { Heltec.display->drawLine(0, 0, i, DISPLAY_HEIGHT - 1); Heltec.display->display(); delay(20); } for (int16_t i = 0; i < DISPLAY_HEIGHT; i += 4) { Heltec.display->drawLine(0, 0, DISPLAY_WIDTH - 1, i); Heltec.display->display(); delay(20); } delay(250); Heltec.display->clear(); for (int16_t i = 0; i < DISPLAY_WIDTH; i += 4) { Heltec.display->drawLine(0, DISPLAY_HEIGHT - 1, i, 0); Heltec.display->display(); delay(20); } for (int16_t i = DISPLAY_HEIGHT - 1; i >= 0; i -= 4) { Heltec.display->drawLine(0, DISPLAY_HEIGHT - 1, DISPLAY_WIDTH - 1, i); Heltec.display->display(); delay(20); } delay(250); Heltec.display->clear(); for (int16_t i = DISPLAY_WIDTH - 1; i >= 0; i -= 4) { Heltec.display->drawLine(DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1, i, 0); Heltec.display->display(); delay(20); } for (int16_t i = DISPLAY_HEIGHT - 1; i >= 0; i -= 4) { Heltec.display->drawLine(DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1, 0, i); Heltec.display->display(); delay(20); } delay(250); Heltec.display->clear(); for (int16_t i = 0; i < DISPLAY_HEIGHT; i += 4) { Heltec.display->drawLine(DISPLAY_WIDTH - 1, 0, 0, i); Heltec.display->display(); delay(20); } for (int16_t i = 0; i < DISPLAY_WIDTH; i += 4) { Heltec.display->drawLine(DISPLAY_WIDTH - 1, 0, i, DISPLAY_HEIGHT - 1); Heltec.display->display(); delay(20); } delay(250); } /************************************************************** Function Name : drawRect Description : Input : Return : // Adapted from Adafruit_SSD1306 **************************************************************/ void drawRect(void) { for (int16_t i = 0; i < DISPLAY_HEIGHT / 2; i += 2) { Heltec.display->drawRect(i, i, DISPLAY_WIDTH - 2 * i, DISPLAY_HEIGHT - 2 * i); Heltec.display->display(); delay(20); } } /************************************************************** Function Name : fillRect Description : Input : Return : // Adapted from Adafruit_SSD1306 **************************************************************/ void fillRect(void) { uint8_t color = 1; for (int16_t i = 0; i < DISPLAY_HEIGHT / 2; i += 3) { Heltec.display->setColor((color % 2 == 0) ? BLACK : WHITE); // alternate colors Heltec.display->fillRect(i, i, DISPLAY_WIDTH - i * 2, DISPLAY_HEIGHT - i * 2); Heltec.display->display(); delay(20); color++; } // Reset back to WHITE Heltec.display->setColor(WHITE); } /************************************************************** Function Name : drawCircle Description : Input : Return : // Adapted from Adafruit_SSD1306 **************************************************************/ void drawCircle(void) { for (int16_t i = 0; i < DISPLAY_HEIGHT; i += 2) { Heltec.display->drawCircle(DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2, i); Heltec.display->display(); delay(20); } delay(1000); Heltec.display->clear(); // This will draw the part of the circel in quadrant 1 // Quadrants are numberd like this: // 0010 | 0001 // ------|----- // 0100 | 1000 // Heltec.display->drawCircleQuads(DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 4, 0b00000001); Heltec.display->display(); delay(200); Heltec.display->drawCircleQuads(DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 4, 0b00000011); Heltec.display->display(); delay(200); Heltec.display->drawCircleQuads(DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 4, 0b00000111); Heltec.display->display(); delay(200); Heltec.display->drawCircleQuads(DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 4, 0b00001111); Heltec.display->display(); } /************************************************************** Function Name : printBuffer Description : Input : Return : **************************************************************/ void printBuffer(void) { // Initialize the log buffer // allocate memory to store 8 lines of text and 30 chars per line. Heltec.display->setLogBuffer(5, 30); // Some test data const char* test[] = { "Hello", "World" , "----", "Show off", "how", "the log buffer", "is", "working.", "Even", "scrolling is", "working" }; for (uint8_t i = 0; i < 11; i++) { Heltec.display->clear(); // Print to the screen Heltec.display->println(test[i]); // Draw it to the internal screen buffer Heltec.display->drawLogBuffer(0, 0); // Display it on the screen Heltec.display->display(); delay(500); } } /************************************************************** Function Name : I2C_Address_Scan Description : Input : Return : **************************************************************/ void I2C_Address_Scan(void) { uint8_t count, i; Serial.println(); Serial.println(); Serial.println("-------------------------------- -"); count = 0; Serial.println ("i2c scanner. scanning ..."); for (i = 1; i < 120; i++) { Wire.beginTransmission (i); if (Wire.endTransmission () == 0) { Serial.print ("found address: "); Serial.print (i, DEC); Serial.print (" (0x"); Serial.print (i, HEX); Serial.println (")"); count++; delay(10); } } Serial.println ("done."); Serial.print ("found "); Serial.print (count, DEC); Serial.println (" device(s)."); Serial.println("-------------------------------- -"); Serial.println (""); delay(100); } //*************************************************************************************** //*************************************************************************************** //*************************************************************************************** //*********************************************************************** //*********************************************************************** void Relay_Actuator() { if(R1 == "1") { Relay_ON_OFF(RELAY1, ON); } else { Relay_ON_OFF(RELAY1, OFF); } if(R2 == "1") { Relay_ON_OFF(RELAY2, ON); } else { Relay_ON_OFF(RELAY2, OFF); } if(R3 == "1") { Relay_ON_OFF(RELAY3, ON); } else { Relay_ON_OFF(RELAY3, OFF); } if(R4 == "1") { Relay_ON_OFF(RELAY4, ON); } else { Relay_ON_OFF(RELAY4, OFF); } if(R5 == "1") { Relay_ON_OFF(RELAY5, ON); } else { Relay_ON_OFF(RELAY5, OFF); } if(R6 == "1") { Relay_ON_OFF(RELAY6, ON); } else { Relay_ON_OFF(RELAY6, OFF); } if(R7 == "1") { Relay_ON_OFF(RELAY7, ON); } else { Relay_ON_OFF(RELAY7, OFF); } if(R8 == "1") { Relay_ON_OFF(RELAY8, ON); } else { Relay_ON_OFF(RELAY8, OFF); } } void Energy() { // Print the custom address of the PZEM Serial.print("Custom Address:"); Serial.println(pzem.readAddress(), HEX); // Read the data from the sensor float voltage = pzem.voltage(); float current = pzem.current(); float power = pzem.power(); float energy = pzem.energy(); float frequency = pzem.frequency(); float pf = pzem.pf(); // Check if the data is valid if(isnan(voltage)){ Serial.println("Error reading voltage"); } else if (isnan(current)) { Serial.println("Error reading current"); } else if (isnan(power)) { Serial.println("Error reading power"); } else if (isnan(energy)) { Serial.println("Error reading energy"); } else if (isnan(frequency)) { Serial.println("Error reading frequency"); } else if (isnan(pf)) { Serial.println("Error reading power factor"); } else { // Print the values to the Serial console Serial.print("Voltage: "); Serial.print(voltage); Serial.println("V"); Serial.print("Current: "); Serial.print(current); Serial.println("A"); Serial.print("Power: "); Serial.print(power); Serial.println("W"); Serial.print("Energy: "); Serial.print(energy,3); Serial.println("kWh"); Serial.print("Frequency: "); Serial.print(frequency, 1); Serial.println("Hz"); Serial.print("PF: "); Serial.println(pf); } data4 = String(voltage); data5 = String(current); data6 = String(power); data7 = String(energy); data8 = String(frequency); data9 = String(pf); Serial.println(); } void Soil_SensorTH_loop() { digitalWrite(MAX485_RE_NEG, RS485Transmit); // init Transmit // byte RS485_request[8] = {0x01, 0x04, 0x00, 0x01, 0x00, 0x02, 0x20, 0x0B}; // XYMD02 byte RS485_request[8] = {0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x65, 0xCB}; // standard soil temp& humid // byte RS485_request[8] = {0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x25, 0xCA}; // standard soil humid( 3 ,4 ) // Test // byte RS485_request[8] = {0x01, 0x03, 0x00, 0x03, 0x00, 0x01, 0x25, 0xCA}; // failed // byte RS485_request[8] = {0x01, 0x03, 0x00, 0x03, 0x00, 0x01, 0x65, 0xCB}; // failed // byte RS485_request[8] = {0x01, 0x03, 0x00, 0x03, 0x00, 0x02, 0x65, 0xCB}; // failed // byte RS485_request[8] = {0x01, 0x03, 0x00, 0x03, 0x00, 0x02, 0x25, 0xCA}; // failed // //to find out what I am sending for( byte a=0; a<8; a++ ) { Serial.print(RS485_request[a], HEX); } Serial.println(); RS485Serial.write(RS485_request, sizeof(RS485_request)); RS485Serial.flush(); digitalWrite(MAX485_RE_NEG, RS485Receive); // Init Receive byte RS485_received[13];// 13 RS485Serial.readBytes(RS485_received, 13); // 13 Serial.print("Result : "); // i max = 9 for XY-MD02 , change for other sensor //9 for( byte i=0; i<13; i++ ) { float value_check = RS485_received[i]; if (value_check < 16) { RS485_Data[i]="0"+String(RS485_received[i],HEX); } else { RS485_Data[i]=String(RS485_received[i],HEX); } Serial.print(RS485_Data[i]); Serial.print(" "); } RS485Serial.flush(); Serial.println(); String ttemp = String(RS485_Data[6])+String(RS485_Data[7]); // 5, 6 หยิบค่า HEX มาต่อกันก่อนแปลง String hhumid = String(RS485_Data[3])+String(RS485_Data[4]); // humid เหมือน temp //Conversion from hexadecimal to decimal //data3 = String((float)convert.hexaToDecimal(ttemp)/10,2); // แสดงค่า ทศนิยม 2 ตำแหน่ง data3 = String((float)convert.hexaToDecimal(hhumid)/10,2); // แสดงค่า ทศนิยม 2 ตำแหน่ง //data3 = data4 ; //Serial.print(ttemp);Serial.print(" Temp : converted to decimal: "); //Serial.println(data3); Serial.print(hhumid);Serial.print(" Humid : converted to decimal: "); Serial.println(data3); Serial.println(); // test_convert(); // ok work well delay(5000); } void test_convert() { int dec = 50; String hexa = "131"; //Conversion from binary to decimal Serial.print("A converted to decimal: "); Serial.println(convert.hexaToDecimal(hexa)); int deci = convert.hexaToDecimal(hexa); String bin = String(convert.decimalToBinary(deci)); Serial.print("A = ");Serial.println(bin); } /* void test_convert() { Serial.begin(9600); int dec = 50; //Conversion de decimal a binario Serial.print("50 converted to binary: "); Serial.println(convert.decimalToBinary(dec)); //Conversion de decimal a hexadecimal Serial.print("50 converted to hexadecimal: "); Serial.println(convert.decimalToHexa(dec)); //Conversion de decimal a octal Serial.print("50 converted to octal: "); Serial.println(convert.decimalToOctal(dec)); String hex = "292"; //Conversion from hexadecimal to decimal Serial.print("292 converted to decimal: "); Serial.println(convert.hexaToDecimal(hex)); String bin = "11001111"; //Conversion from binary to decimal Serial.print("11001111 converted to decimal: "); Serial.println(convert.binaryToDecimal(bin)); String oct = "515"; //Conversion from octal to decimal Serial.print("515 converted to decimal: "); Serial.println(convert.octalToDecimal(oct)); } */ void XYMD02_loop() { Read_DATA_SHT20_XYMD02(1);//Modbus ID //Read_Hardware_Parameter_SHT20_XYMD02(1);//Modbus ID data3=dataa3; data4=dataa4; delay(1000); //Read_DATA_SHT20_XYMD02(2);//Modbus ID //Read_Hardware_Parameter_SHT20_XYMD02(2);//Modbus ID } /************************************************************** Function Name : Change_Slave_ID Description : Input : Return : **************************************************************/ void Change_Slave_ID(uint8_t Slave_ID, uint8_t NEW_Slave_ID) { uint8_t loop_poll; au16data[5] = NEW_Slave_ID; telegram[1].u8id = Slave_ID; // slave addrss telegram[1].u8fct = 6; // function code telegram[1].u16RegAdd = 257; // start address in slave telegram[1].u16CoilsNo = 1; // number of elements (coils or registers) to read telegram[1].au16reg = au16data + 5; // pointer to a memory array in the Arduino master.query( telegram[1] ); // send query (only once) delay(5); loop_poll = 1; while (loop_poll) { master.poll(); // check incoming messages delay(2); if (master.getState() == COM_IDLE) { loop_poll = 0; if (master.getLastError() != 0)//ERROR { Serial.print(" ERROR Read >> "); Serial.println(master.getLastError()); } else { Serial.println("............ Write NEW Slave ID OK "); Serial.println("............ Please Restart Sensor "); } } } delay(20); } /************************************************************** Function Name : Read_DATA_SHT20_XYMD02 Description : Input : Return : **************************************************************/ void Read_DATA_SHT20_XYMD02(uint8_t Slave_ID)// { uint8_t loop_poll; telegram[2].u8id = Slave_ID; // slave address Read telegram[2].u8fct = 4; // function code (this one is registers read) telegram[2].u16RegAdd = 0; //257;//1; // start address in slave // 0 for SHT20 telegram[2].u16CoilsNo = 2; // number of elements (coils or registers) to read telegram[2].au16reg = au16data; // pointer to a memory array in the Arduino master.query( telegram[2] ); // send query (only once) loop_poll = 1; delay(5); while (loop_poll) { master.poll(); // check incoming messages delay(2); if (master.getState() == COM_IDLE) { loop_poll = 0; if (master.getLastError() != 0)//ERROR { Serial.print(" ERROR Read >> "); Serial.println(master.getLastError()); } else { // Serial.println("************ READ *************");//debug // Serial.println(au16data[0], DEC);//debug // Serial.println(au16data[1], DEC);//debug temperature = float(au16data[0]) / 10; humidity = float(au16data[1]) / 10; jdata3 = temperature; jdata4 = humidity; dataa3 = String(temperature); dataa4 = String(humidity); data5 = String(temperature); data6 = String(humidity); Serial.println("---------------------------------------------------"); Serial.print(" Temperature = "); Serial.print(temperature); Serial.println(" *C"); Serial.print(" Humidity = "); Serial.print(humidity); Serial.println(" %"); //Serial.println("---------------------------------------------------"); } } } delay(20); } /************************************************************** Function Name : Read_Hardware_Parameter_SHT20_XYMD02 Description : Input : Return : **************************************************************/ void Read_Hardware_Parameter_SHT20_XYMD02(uint8_t Slave_ID) { uint8_t loop_poll; telegram[3].u8id = Slave_ID; // slave address Read telegram[3].u8fct = 3; // function code (this one is registers read) telegram[3].u16RegAdd = 257; // start address in slave telegram[3].u16CoilsNo = 2; // number of elements (coils or registers) to read telegram[3].au16reg = au16data; // pointer to a memory array in the Arduino master.query( telegram[3] ); // send query (only once) loop_poll = 1; delay(5); while (loop_poll) { master.poll(); // check incoming messages delay(2); if (master.getState() == COM_IDLE) { loop_poll = 0; if (master.getLastError() != 0)//ERROR { Serial.print(" ERROR Read >> "); Serial.println(master.getLastError()); } else { //Serial.println("************ READ *************");//debug //Serial.println(au16data[0], DEC);//debug //Serial.println(au16data[1], DEC);//debug //Serial.println("---------------------------------------------------"); Serial.print(" Modbus Slave ID = "); Serial.println(au16data[0], DEC); Serial.print(" Baud Rate = "); Serial.println(au16data[1], DEC); Serial.println("---------------------------------------------------"); } } } delay(20); } //**************************************************************************** //**************************************************************************** //**************************************************************************** //****************************************************************************