บอร์ด ESP32LoRa-Part-1

ก่อนอื่นต้องขออภัยคุณลูกค้าผู้ให้การสนับสนุนบอร์ดรุ่นนี้ ที่คู่มือรวมเล่มออกมาหลังจากจัดจำหน่ายบอร์ดไปหมดแล้ว คงเหลือไว้สำหรับดูเล่นและไว้ซ้อมมือบอร์ดเดียว

บอร์ดนี้ถูกออกแบบมาเพื่อตอบโจทย์หลายอย่างด้วยกันและความต้องการให้ประหยัดที่สุดที่มีประสิทธิภาพมากที่สุด

องค์ประกอบและความสามารถของบอร์ด

  1. MCU : ESP32-Doit 30 pins
  2. Input :
    • I2C
    • RS485
    • UART
    • ADC 4 channel
  3. Output : 4 x Relay (NO+NC) , Coil 4 Vdc, Load 220 Vac 10A max
  4. RTC : Onboard DS
  5. ADS1115 ขยายการเชื่อมต่อ
  6. Power Supply : 12 Vdc
  7. Coomunication : WiFI, LoRa
  8. Programming : Arduino IDE

การประยุกต์ใช้งาน สามารถใช้ได้กับ สมาร์ทฟาร์ม สมาร์ทโฮม บอร์ดหลักสามารถควบคุมอุปกรณ์ได้ 4 ตัวและสามารถเชื่อมต่อควบคุม RS485 Relay ได้ตามความต้องการ

  • ตัวอย่างเซนเซอร์ที่แนะนำใช้งาน
  • I2C , AM2315 , LCD
  • RS485 , SHT20(XYMD01) , XYMD02 , Soil moisture, Soil NPK sensor , Power meter
  • UART , PZEM
  • ADC , pH , EC analog meter, DHT11, DHT21

สำหรับการเชื่อมต่อขาเราจะนำมาแสดงไว้เฉพาะส่วนสำคัญๆ ครับ

ไลบรารีที่จำเป็นสำหรับการใช้งานบอร์ดนี้ให้เต็มประสิทธิภาพ

  1. Converter ตามลิงก์นี้
  2. Arduino Json ตามตัวอย่างด้านล่าง
  3. ModbusMaster ตามลิงก์นี้
  4. MosbusRTU ตามลิงก์นี้
  5. LiquidCrytsal_I2C จาก Arduino IDE
  6. LoRa ตามลิงก์นี้
  7. PZEM จาก Arduino IDE หรือ ลิงก์นี้
  8. SoftwareSerial จาก Arduino IDE
  9. ESP32SoftwareSerial ตามลิงก์นี้
  10. HardwareSerial จากการติดตั้ง ESP32 หรือตามลิงก์นี้
  11. Arduino จากการติดตั้ง Arduino IDE เริ่มต้น
  12. SPI จากการติดตั้ง ESP32 หรือตามลิงก์นี้
  13. Ticker จากการติดตั้ง ESP32 หรือตามลิงก์นี้
  14. WiFi จากการติดตั้ง ESP32 หรือตามลิงก์นี้

โดยบางไลบรารี สามารถติดตั้งจาก Arduino IDE ได้เลย

และขอเน้นว่าให้ตั้งค่าบอร์ดเป็น Version 1.0.6 ครับ มิฉะนั้นจะมีปัญหาบางประการเช่น รุ่นของ LoRa , I2C

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

/////////////////////////////////////////////
// DEFINE
/////////////////////////////////////////////

#define VERSION "3.0"
// เพื่อการตรวจเชค OTA
/////////////////////////////////////////////

/////////////////////////////////////////////

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  ระหว่าง ESP32 กับ ESP8266
#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>

//// สำหรับการเชื่อมต่อ SPI  LoRa
#include <SPI.h>              // include libraries
#include <Ticker.h>
#include <LoRa.h>
#include <Wire.h>
////
#include "define.h"   // สำหรับเรียกไฟล์ define.h ในโฟลเดอร์เดียวกัน
#include <math.h>
#include <ArduinoJson.h>
#include <Arduino_JSON.h>

//==============

///====== สำหรับการสื่อสาร  RS485  ขั้วสีแดง
#define RX_PIN     16    //Serial Receive pin 16 
#define TX_PIN     17    //Serial Transmit pin 17
#define MAX485_RE_NEG    15    //LED
#define RS485Transmit    HIGH
#define RS485Receive     LOW
#define  LED      0
float temp, pH ;

//========== XYMD02 = RS485 สำหรับอ่าน XYMD02 และ SHT20
HardwareSerial RTU_Serial(2); // 1
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;


//====== สำหรับการวัดไฟฟ้าด้วย PZEM
#include <PZEM004Tv30.h>

#if !defined(PZEM_RX_PIN) && !defined(PZEM_TX_PIN)
#define PZEM_RX_PIN 4
#define PZEM_TX_PIN 5
#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 <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;
//===========
/*
  # This sample code is used to test the pH meter V1.0.
  # Editor : YouYou
  # Ver    : 1.0
  # Product: analog pH meter
  # SKU    : SEN0161
*/
//#define SensorPin A0            //pH meter Analog output to Arduino Analog Input 0
#define Offset -2.00            //deviation compensate
#define LED 13
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth  20    // 40 times of collection
int pHArray[ArrayLenth];   //Store the average value of the sensor feedback
int pHArrayIndex = 0;

//
#define Slave_ID1    1  // see dip swith if connect to Transpower 
#define BAND    915E6  //you can set band here directly,e.g. 868E6,915E6,433E6
// instantiate ModbusMaster object

ModbusMaster modbus;

// 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;
uint8_t     veri;

uint8_t     LED_State;
uint32_t    Interval_Time_Old[4];
uint16_t    Interval[4];

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];

//======สำหรับ WiFi ที่จะเชื่อมต่อ  หากมาหลายตัวในบริเวณใกล้กัน
const char* ssid      = "Asenal2021_2G";
const char* password  = "kb75699212";
const char* ssid1     = "Asenal2021_2G";
const char* password1 = "kb75699212";
const char* ssid2     = "Asenal2021_2G";
const char* password2 = "kb75699212";

//===== Server config , ID, Code
//const char* host = "http://192.168.1.34";
const char* host = "myiotcity.com";
char* code = "123rr";
char* dID = "204";

//=== PM 2.5
float dustDensity = 35;
String response = "0";
String response_c = "0";
String a ;

//=== กด เพื่อ OTA
int npress ;

//== ตั้งค่ารอบเพื่อการ รีสตาร์ท
int cnt = 7200; // every 24 hrs cycle = 12 second
//

//== ตัวแปรใช้งานทั่วไป
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 v0, v1, v2, v3;
float voltage;
float current;
float power;
float energy;
float frequency;
float pHValue;

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 , dataa5 ;
String data6 , dataa6 ;
String data7 ;
String data8 ;
String data9 ;
String JSONSerial = "";
float jdata1, jdata2, jdata3, jdata4, jjdata3, jjdata4, jdata5, jdata6 ;
float tempdiff = 0 ;
float tempdiff_Max = 5;
float humdiff = 0 ;

/// ===
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, R9, R10 ;
String RR1, RR2, RR3, RR4, RR5, RR6, RR7, RR8, RR9, RR10, 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 ;

int LoRa_counter = 0;
//
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);
}
//------------------------------------------------
//== GPIO12 User Switch  นับการกดเพื่อ OTA
struct Button {
  const uint8_t PIN;
  uint32_t numberKeyPresses;
  bool pressed;
};

Button button1 = {12, 0, false}; // GPIO12

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 SW1 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 = "otrixiot.com";
    uint16_t ota_port = 80;
    char* ota_path = "/otaaa/sompoch/Dev32101.bin";
    ota_run(ota_host, ota_port, ota_path);
    //Serial.println("Restarting with new firmware ... ");
    //restart = true;
  }

}

/// OTRIXOTA
void Otrix_OTA()
{
  if (RR_OTA == "1") {
    Serial.println("Otrix-OTA: START");
    char* ota_host = "otrixiot.com";
    uint16_t ota_port = 80;
    char* ota_path = "/otaaa/sompoch/Dev32101.bin";
    ota_run(ota_host, ota_port, ota_path);
    //Serial.println("Restarting with new firmware ... ");
    //restart = true;
  }
}

/////////////////////////////////////////////
// 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 : Mungmee-001-SMT-005-Dev-308-J6-OTA-RST-Test");
  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 ");

}

/////////////////////////////////////////////////////////

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;

  // this is utility donot delete , used for change slave id
  //RTU_Slave_ID = 1;
  //RTU_NEW_Slave_ID = 2;
  //Change_Slave_ID(RTU_Slave_ID, RTU_NEW_Slave_ID);

}

void setup_SMT005(void)
{
  delay(200);
  pinMode(ESP32_LED, OUTPUT);

  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, LOW);
  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(RELAY4, OUTPUT);

  //test_relay(); delay(250);

  Wire.begin(SDA0, SCL0, 100000); //100000

  I2C_Address_Scand();
  Relay = 0;

  // DS3231 seconds, minutes, hours, day, date, month, year
  //set_time_ds1307(0, 20, 16, 1, 27, 3, 22);
  //LoRa_setup();


  LoRa.setPins(RFM95_CS, RFM95_RST, RFM95_IRQ); // set CS, reset, IRQ pin
  if (!LoRa.begin(915E6)) {         // initialize ratio at 915 MHz
    Serial.println("LoRa init failed. Check your connections.");
    while (true);                   // if failed, do nothing
  }
  delay(100);


  veri = LoRa.readRegister(0x42); // Semtech ID relating the silicon revision
  Serial.println("");

  Serial.print(">> Registers RFM95 VERSION = ");
  Serial.println(veri);

  Serial.println("");


  Serial.println(">> Dump - Registers RFM95 ");
  LoRa.dumpRegisters(Serial);
  delay(500);

  m_bitShift  = 0;
  m_gain      = GAIN_TWOTHIRDS;
  m_dataRate  = RATE_ADS1115_128SPS; //RATE_ADS1115_8SPS; //RATE_ADS1115_128SPS;
  delay(20);

  Interval[0] = 1000;   // ADS1115
  Interval[1] = 1000;   // RTC
  Interval[2] = 250;    // LED

  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);


}

//===
void setup_LCD()
{
  lcd.begin();
  lcd.setCursor(0, 0);
  lcd.print("Samong IOT");
  lcd.setCursor(0, 2);
  lcd.print("Samong Thailand");

}
void LCD_energy()
{

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("  Energy con.");
  lcd.setCursor(0, 1);
  lcd.print("Volt   :         Vac");
  lcd.setCursor(0, 2);
  lcd.print("Current:         A");
  lcd.setCursor(10, 1);
  lcd.print(data7);
  lcd.setCursor(10, 2);
  lcd.print(data8);
  delay(2000);
}

void LCD_weather()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Farm Weather");
  lcd.setCursor(0, 1);
  lcd.print("Temp'c  :       'c");
  lcd.setCursor(0, 2);
  lcd.print("Humid   :       %");
  lcd.setCursor(10, 1);
  lcd.print(data3);
  lcd.setCursor(10, 2);
  lcd.print(data4);
  delay(2000);
}

void LCD_pH()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   pH-EC Status");
  lcd.setCursor(0, 1);
  lcd.print("pH  :        ");
  lcd.setCursor(0, 2);
  lcd.print("EC  :         us/cm2");
  lcd.setCursor(7, 1);
  lcd.print(pHValue);
  lcd.setCursor(7, 2);
  lcd.print(pHValue);
  delay(2000);
}

void LCD_Pump_Status()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Pump Status");
  lcd.setCursor(0, 1);
  lcd.print("Main Pump :      ");
  lcd.setCursor(0, 2);
  lcd.print("Pump A    :      ");
  lcd.setCursor(0, 3);
  lcd.print("Pump B    :      ");
  lcd.setCursor(13, 1);
  lcd.print(MainPump);
  lcd.setCursor(13, 2);
  lcd.print(flowsensor);
  lcd.setCursor(13, 3);
  lcd.print(PumpB);
  delay(2000);

}

void LCD_Time_Setting()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Time Setting");
  lcd.setCursor(0, 1);
  lcd.print("Pump Start:      ");
  lcd.setCursor(0, 2);
  lcd.print("Pump Stop :      ");
  lcd.setCursor(0, 3);
  lcd.print("Pump A,B  : same ");
  lcd.setCursor(12, 1);
  lcd.print(Time1);
  lcd.setCursor(12, 2);
  lcd.print(Time2);
  delay(2000);

}
void LCD_Control_Setting()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("    Control Value");
  lcd.setCursor(0, 1);
  lcd.print("Value : High  -  Low");
  lcd.setCursor(0, 2);
  lcd.print("pH    :             ");
  lcd.setCursor(0, 3);
  lcd.print("EC    :             ");
  lcd.setCursor(10, 2);
  lcd.print(led3);
  lcd.setCursor(10, 3);
  lcd.print(led1);

  delay(2000);

}

//===
void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, HIGH); //Switch to transmit data
}
void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, LOW); //Switch to receive data
}
//====
void logo()
{



}
////////
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

/// 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 LoRa_setup()
{
  delay(500);
  //Serial.begin(115200);
  Serial.println("");
  Serial.println(" >> ESP32_RFM95_SX1276_LoRaReceiver");

  LoRa.setPins(RFM95_CS, RFM95_RST, RFM95_IRQ); // set CS, reset, IRQ pin
  if (!LoRa.begin(915E6)) {         // initialize ratio at 915 MHz
    Serial.println("LoRa init failed. Check your connections.");
    while (true);                   // if failed, do nothing
  }
  Serial.println("");

  //Serial.println(">> Dump - Registers");
  //LoRa.dumpRegisters(Serial);
  //Wire.begin(SDA0, SCL0, 100000);
  //I2C_Address_Scand();
  //delay(2000);
  //set_time_ds1307(0, 1, 9, 5, 1, 11, 21);
}
void LoRa_Receive_loop()
{
  // try to parse packet
  Serial.println("LoRa loop ... ");
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    // received a packet
    Serial.print("Received packet '");

    // read packet
    while (LoRa.available()) {
      Serial.print((char)LoRa.read());
    }

    // print RSSI of packet
    Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
  }

}
void setup()
{
  Aboutme();
  OTA_reset_setup();
  setup_XYMD02();
  //delay(100000);
  setup_SMT005();
  pH_setup();
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);
  setup_LCD();
  WiFiForwardSetup();

  //LoRa.onReceive(cbk);
  //LoRa.receive();
}

void loop()
{
  Otrix_OTA(); // OTA

  Serial.println("======================================");
  Serial.print("Version : "); Serial.println(VERSION);
  Serial.println("======================================");

  counter = counter + 1;

  ESP32_BoardTest_loop();

  SMT_loop();

  Energy();
  pH_loop();
  XYMD02_loop();
  //LoRa_setup();

  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();

  //Serial.println("Start SerRead loop ... ");
  LCD_display();
  LCD_pH();
  LCD_energy();
  LCD_weather();
  LCD_pH();

  read_master_status_FromServer();
  LCD_Time_Setting();
  LCD_Control_Setting();
  Relay_Actuator();
  LCD_Pump_Status();
  //data1 = sdata11;
  //data2 = sdata12;
  OTA_SW_loop();
  //LoRa_Receive_loop();
  Restart_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 .... ");
  //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(data7) + "&data2="
               + String(data8) + "&data3=" + String(data3) + "&data4=" + String(data4) + "&data5=" + String(v0)
               + "&data6=" + String(pHValue) + "&data7=" + String(data7) + "&data8=" + String(data8) + "&data9=" + String(data9)
               + "&data10=" + String(data10) + "&data11=" + String(data11) + "&data12=" + String(22) + "&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 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 RR9 = doc["result"]["relayStatus"]["data9_status"]; // Timer relay 9 in platform
        String RR10 = doc["result"]["relayStatus"]["data10_status"]; // Timer relay 10 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; R9 = RR9; R10 = RR10;
        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(R9) + " " + String(R10));
        // 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) + " " + String(R9) + " " + String(R10));
        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();   // only AM2315
}

void service_rtc()
{
  String  str1 = "";

  ds1307_display_Time();

  str1 = "";

  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);
  str1 = "";
  str1 = "Temp1 : ";
  str1 += String(data3) + " .C"; // temp

  str1 = "";
  str1 = "Hum1   : ";
  str1 += String(data4) + "  %";  // humidity

  str1 = "";
  str1 = "Temp2 : ";
  str1 += String(data5) + " .C"; // temp


  str1 = "";
  str1 = "Hum2   : ";
  str1 += String(data6) + "  %";  // humidity

  str1 = "";
  str1 = "Volt  : ";
  str1 += String(data7) + " V"; // volt


  str1 = "";
  str1 = "Amp   : ";
  str1 += String(data8) + "  A";  // current


}

/**************************************************************
  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;
}

////================
///=================
////================
void ESP32_Board_setup()
{
  delay(100);
  Serial.begin(115200);

  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, LOW);


  test_relay(); delay(250);
  test_relay(); delay(250);

  Wire.begin(SDA0, SCL0, 100000); // 100000

  I2C_Address_Scand();
  delay(1000);

  LoRa.setPins(RFM95_CS, RFM95_RST, RFM95_IRQ); // set CS, reset, IRQ pin
  if (!LoRa.begin(915E6)) {         // initialize ratio at 915 MHz
    Serial.println("LoRa init failed. Check your connections.");
    while (true);                   // if failed, do nothing
  }
  delay(100);

  veri = LoRa.readRegister(0x42); // Semtech ID relating the silicon revision
  Serial.println("");

  Serial.print(">> Registers RFM95 VERSION = ");
  Serial.println(veri);

  Serial.println("");


  Serial.println(">> Dump - Registers RFM95 ");
  LoRa.dumpRegisters(Serial);
  delay(500);


  m_bitShift  = 0;
  m_gain      = GAIN_TWOTHIRDS;  //
  m_dataRate  = RATE_ADS1115_128SPS; //RATE_ADS1115_8SPS; //RATE_ADS1115_128SPS;
  delay(100);

  Interval[0] = 1000;   // ADS1115
  Interval[1] = 1000;   // RTC
  Interval[2] = 250;    // LED
}
////=========
void ESP32_BoardTest_loop()
{
  //test_rtc();
  //test_ads1115();
  delay(2);

  if (millis() - Interval_Time_Old[0] >= Interval[0])//ADC ADS1115
  {
    Interval_Time_Old[0] = millis();
    test_ads1115();
  }

  if (millis() - Interval_Time_Old[1] >= Interval[1])//RTC
  {
    Interval_Time_Old[1] = millis();
    test_rtc();
  }

  if (millis() - Interval_Time_Old[2] >= Interval[2])//LED
  {
    Interval_Time_Old[2] = millis();
    if (LED_State)
    {
      LED_State = 0;
      digitalWrite(PIN_LED, LOW);
    }
    else
    {
      LED_State = 1;
      digitalWrite(PIN_LED, HIGH);
    }
  }
}


//#############################################################
//###################  ADC ADS1115  ###########################
//#############################################################

/********************************************************************
  Function Name  : test_ads1115
  Description    :
********************************************************************/
void test_ads1115()
{
  float     volts[4];
  volts[0] = 0.00;
  volts[1] = 0.00;
  volts[2] = 0.00;
  volts[3] = 0.00;

  volts[0] = read_voltage_adc(0);//0-3
  volts[1] = read_voltage_adc(1);//0-3
  volts[2] = read_voltage_adc(2);//0-3
  volts[3] = read_voltage_adc(3);//0-3

  Serial.print(" >>   ADC CH0   =   "); Serial.print(volts[0], 3); Serial.println(" V ");
  Serial.print(" >>   ADC CH1   =   "); Serial.print(volts[1], 3); Serial.println(" V ");
  Serial.print(" >>   ADC CH2   =   "); Serial.print(volts[2], 3); Serial.println(" V ");
  Serial.print(" >>   ADC CH3   =   "); Serial.print(volts[3], 3); Serial.println(" V ");

  Serial.println("");
  //delay(100);
  v0 = volts[0];
  v1 = volts[1];
  v2 = volts[2];
  v3 = volts[3];
}



/********************************************************************
  Function Name  : test_rtc
  Description    :
********************************************************************/
void test_rtc()
{
  Serial.println("========================================================");
  Serial.print(" CLOCK : ");
  ds1307_display_Time();
  Serial.println("========================================================");
  //delay(850);
}

/********************************************************************
  Function Name  : read_voltage_adc
  Description    :
********************************************************************/
float read_voltage_adc(uint8_t ch)
{
  float f = 0.0;
  int16_t   adc;
  adc = ReadADC_SingleEnded(ch);
  f = computeVolts(adc);
  return (f - 0.007);//adj offset
}
/********************************************************************
  Function Name  : ReadADC_SingleEnded
  Description    :
********************************************************************/
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    :
********************************************************************/
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    :
********************************************************************/
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    :
********************************************************************/
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(ADS1115_I2C_ADDRESS);
  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(ADS1115_I2C_ADDRESS);
  Wire.write(temp[0]);
  Wire.endTransmission();

  Wire.requestFrom(ADS1115_I2C_ADDRESS, 2);
  delayMicroseconds(10);

  temp[0] = Wire.read();
  temp[1] = Wire.read();

  Wire.endTransmission();

  return ((temp[0] << 8) | temp[1]);
}



//#############################################################
//######################   DS1307  ############################
//#############################################################
/********************************************************************
  Function Name  : decToBcd
  Description    :
********************************************************************/
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}


/********************************************************************
  Function Name  : bcdToDec
  Description    :
********************************************************************/
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}


/********************************************************************
  Function Name  : set_time_ds1307
  Description    :
********************************************************************/
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    :
********************************************************************/
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          :
**************************************************************/
/********************************************************************
  Function Name  : ds1307_display_Time
  Description    :
********************************************************************/
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);

  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          :
**************************************************************/

/**************************************************************
  Function Name   : test_off_relay
  Description     :
  Input           :
  Return          :
**************************************************************/
void test_off_relay()
{

}

/**************************************************************
  Function Name   : test_on_relay
  Description     :
  Input           :
  Return          :
**************************************************************/
void test_on_relay()
{

}

/********************************************************************
  Function Name  : test_relay
  Description    :
********************************************************************/
void test_relay()
{
  uint16_t del = 250;

  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(RELAY4, OUTPUT);
  digitalWrite(RELAY1, LOW);
  digitalWrite(RELAY2, LOW);
  digitalWrite(RELAY3, LOW);
  digitalWrite(RELAY4, LOW);

  digitalWrite(RELAY1, HIGH);
  delay(del);
  digitalWrite(RELAY2, HIGH);
  delay(del);
  digitalWrite(RELAY3, HIGH);
  delay(del);
  digitalWrite(RELAY4, HIGH);
  delay(del);
  digitalWrite(RELAY1, LOW);
  delay(del);
  digitalWrite(RELAY2, LOW);
  delay(del);
  digitalWrite(RELAY3, LOW);
  delay(del);
  digitalWrite(RELAY4, LOW);
  delay(del);
}

/**************************************************************
  Function Name   : Relay_ON_OFF
  Description     :
  Input           :
  Return          :
**************************************************************/

/**************************************************************
  Function Name   : INIT_MCP23017
  Description     :
  Input           :
  Return          :
**************************************************************/

/**************************************************************
  Function Name   : Read_GPIO_MCP23017
  Description     :
  Input           :
  Return          :
**************************************************************/


/**************************************************************
  Function Name   : Write_MCP23017
  Description     :
  Input           :
  Return          :
**************************************************************/


/**************************************************************
  Function Name   : Show_1_OLED
  Description     :
  Input           :
  Return          :
**************************************************************/


/**************************************************************
  Function Name   : Show_2_OLED
  Description     :
  Input           :
  Return          :
**************************************************************/

/**************************************************************
  Function Name   : drawLines
  Description     :
  Input           :
  Return          :
  // Adapted from Adafruit_SSD1306
**************************************************************/


/**************************************************************
  Function Name   : drawRect
  Description     :
  Input           :
  Return          :
  // Adapted from Adafruit_SSD1306
**************************************************************/


/**************************************************************
  Function Name   : fillRect
  Description     :
  Input           :
  Return          :
  // Adapted from Adafruit_SSD1306
**************************************************************/


/**************************************************************
  Function Name   : drawCircle
  Description     :
  Input           :
  Return          :
  // Adapted from Adafruit_SSD1306
**************************************************************/


/**************************************************************
  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.

  // 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++)
  {

    delay(500);
  }
}

/**************************************************************
  Function Name   : I2C_Address_Scan
  Description     :
  Input           :
  Return          :
**************************************************************/
void I2C_Address_Scand(void)
{
  uint8_t count, i;
  Serial.println();
  Serial.println();
  Serial.println("------------------------------------------------");
  count = 0;

  Serial.println ("i2c scanner. scanning ...");
  Wire.begin();

  for (i = 8; 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).");
}


//***************************************************************************************
//***************************************************************************************
//***************************************************************************************

//***********************************************************************
//***********************************************************************

void Relay_Actuator()
{
  digitalWrite(RELAY1, HIGH);
  digitalWrite(RELAY2, HIGH);
  digitalWrite(RELAY3, HIGH);
  digitalWrite(RELAY4, HIGH);
}

void Energy() {
  // Print the custom address of the PZEM
  Serial.print("PZEM 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);

  }

  data7 = String(voltage);
  data8 = String(current);
  data9 = String(power);
  data10 = energy;
  data11 = frequency;
  data12 = pf;
  Serial.println();

}

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;
  jjdata3 = jdata3;
  jjdata4 = jdata4;
  delay(1000);
  Read_DATA_SHT20_XYMD02(3);//Modbus ID
  data5 = dataa5;
  data6 = dataa6;
  delay(1000);
  //Read_Hardware_Parameter_SHT20_XYMD02(2);//Modbus ID
  tempdiff = jjdata3 - jdata5;
  humdiff = jjdata4 - jdata6;
  Serial.println(" Temp  diff = " + String(tempdiff));
  Serial.println(" Humid diff = " + String(humdiff));
  if (tempdiff < tempdiff_Max )
  {
    Run_evap();
  }
  else
  {
    Run_fan();
  }
}

void Run_evap()
{
  //Relay_ON_OFF(RELAY1, ON);
  //Relay_ON_OFF(RELAY2, ON);
}

void Run_fan()
{
  //Relay_ON_OFF(RELAY1, ON);
  //Relay_ON_OFF(RELAY1, OFF);
}
/**************************************************************
  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 for MD02 ; // 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;
        jdata5 = temperature;
        jdata6 = humidity;

        dataa3 = String(temperature);
        dataa4 = String(humidity);
        dataa5 = String(temperature);
        dataa6 = String(humidity);
        Serial.println("---------------------------------------------------");
        Serial.print(" Temperature(#" + String(Slave_ID) + ")   =  ");
        Serial.print(temperature);
        Serial.println("  *C");

        Serial.print(" Humidity(#" + String(Slave_ID) + ")      =  ");
        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);
}
void Restart_loop() {

  Serial.println(cnt);   // แสดงค่าตัวเลขแต่ละรอบ

  // เมื่อรันครบ 10 รอบ (10วินาที) ให้สั่ง reset
  if (cnt == 0) {
    Serial.println("Reset..");
    ESP.restart();       // คำสั่งรีเซ็ต ESP

  }

  cnt--;                 // ลดค่าตัวแปร cnt ไปรอบละ 1 หน่วย
  delay(1000);           // รอ 1 วินาที
}


void pH_setup(void)
{
  //pinMode(LED,OUTPUT);
  //Serial.begin(115200);
  Serial.println("pH meter experiment!");    //Test the serial monitor
}
void pH_loop(void)
{
  static unsigned long samplingTime = millis();
  static unsigned long printTime = millis();
  static float pH_voltage;


  v0 = read_voltage_adc(0);//0-3
  //pHArray[pHArrayIndex++]=v0;
  //if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
  //pH_voltage = avergearray(pHArray, ArrayLenth);
  pHValue = 3.5 * v0 + Offset;
  //voltage+Offset;
  //samplingTime=millis();


  Serial.print("Voltage:");
  Serial.print(pH_voltage, 2);
  Serial.print("    pH value: ");
  Serial.print(pHValue, 2);
  data5 = String(pHValue);
}
double avergearray(int* arr, int number) {
  int i;
  int max, min;
  double avg;
  long amount = 0;
  if (number <= 0) {
    Serial.println("Error number for the array to avraging!/n");
    return 0;
  }
  if (number < 5) { //less than 5, calculated directly statistics
    for (i = 0; i < number; i++) {
      amount += arr[i];
    }
    avg = amount / number;
    return avg;
  } else {
    if (arr[0] < arr[1]) {
      min = arr[0]; max = arr[1];
    }
    else {
      min = arr[1]; max = arr[0];
    }
    for (i = 2; i < number; i++) {
      if (arr[i] < min) {
        amount += min;      //arr<min
        min = arr[i];
      } else {
        if (arr[i] > max) {
          amount += max;  //arr>max
          max = arr[i];
        } else {
          amount += arr[i]; //min<=arr<=max
        }
      }//if
    }//for
    avg = (double)amount / (number - 2);
  }//if
  return avg;
}
//****************************************************************************
//****************************************************************************
//****************************************************************************
//****************************************************************************

ส่วนที่ 1 Include & Define

sdasda

/////////////////////////////////////////////
// DEFINE
/////////////////////////////////////////////

#define VERSION "3.0"
// เพื่อการตรวจเชค OTA
/////////////////////////////////////////////

/////////////////////////////////////////////

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  ระหว่าง ESP32 กับ ESP8266
#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>

//// สำหรับการเชื่อมต่อ SPI  LoRa
#include <SPI.h>              // include libraries
#include <Ticker.h>
#include <LoRa.h>
#include <Wire.h>
////
#include "define.h"   // สำหรับเรียกไฟล์ define.h ในโฟลเดอร์เดียวกัน
#include <math.h>
#include <ArduinoJson.h>
#include <Arduino_JSON.h>

//==============

///====== สำหรับการสื่อสาร  RS485  ขั้วสีแดง
#define RX_PIN     16    //Serial Receive pin 16 
#define TX_PIN     17    //Serial Transmit pin 17
#define MAX485_RE_NEG    15    //LED
#define RS485Transmit    HIGH
#define RS485Receive     LOW
#define  LED      0
float temp, pH ;

//========== XYMD02 = RS485 สำหรับอ่าน XYMD02 และ SHT20
HardwareSerial RTU_Serial(2); // 1
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;


//====== สำหรับการวัดไฟฟ้าด้วย PZEM
#include <PZEM004Tv30.h>

#if !defined(PZEM_RX_PIN) && !defined(PZEM_TX_PIN)
#define PZEM_RX_PIN 4
#define PZEM_TX_PIN 5
#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 <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;
//===========
/*
  # This sample code is used to test the pH meter V1.0.
  # Editor : YouYou
  # Ver    : 1.0
  # Product: analog pH meter
  # SKU    : SEN0161
*/
//#define SensorPin A0            //pH meter Analog output to Arduino Analog Input 0
#define Offset -2.00            //deviation compensate
#define LED 13
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth  20    // 40 times of collection
int pHArray[ArrayLenth];   //Store the average value of the sensor feedback
int pHArrayIndex = 0;

//
#define Slave_ID1    1  // see dip swith if connect to Transpower 
#define BAND    915E6  //you can set band here directly,e.g. 868E6,915E6,433E6
// instantiate ModbusMaster object

ModbusMaster modbus;

// 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);

ส่วนที่ 2 Variable

dfgdfg

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;
uint8_t     veri;

uint8_t     LED_State;
uint32_t    Interval_Time_Old[4];
uint16_t    Interval[4];

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];

//======สำหรับ WiFi ที่จะเชื่อมต่อ  หากมาหลายตัวในบริเวณใกล้กัน
const char* ssid      = "Asenal2021_2G";
const char* password  = "kb75699212";
const char* ssid1     = "Asenal2021_2G";
const char* password1 = "kb75699212";
const char* ssid2     = "Asenal2021_2G";
const char* password2 = "kb75699212";

//===== Server config , ID, Code
//const char* host = "http://192.168.1.34";
const char* host = "myiotcity.com";
char* code = "123rr";
char* dID = "204";

//=== PM 2.5
float dustDensity = 35;
String response = "0";
String response_c = "0";
String a ;

//=== กด เพื่อ OTA
int npress ;

//== ตั้งค่ารอบเพื่อการ รีสตาร์ท
int cnt = 7200; // every 24 hrs cycle = 12 second
//

//== ตัวแปรใช้งานทั่วไป
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 v0, v1, v2, v3;
float voltage;
float current;
float power;
float energy;
float frequency;
float pHValue;

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 , dataa5 ;
String data6 , dataa6 ;
String data7 ;
String data8 ;
String data9 ;
String JSONSerial = "";
float jdata1, jdata2, jdata3, jdata4, jjdata3, jjdata4, jdata5, jdata6 ;
float tempdiff = 0 ;
float tempdiff_Max = 5;
float humdiff = 0 ;

/// ===
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, R9, R10 ;
String RR1, RR2, RR3, RR4, RR5, RR6, RR7, RR8, RR9, RR10, 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 ;

int LoRa_counter = 0;
//
String iddevice = dID;
String cccode = code;
String ccode =  code;
long lastMillis = 100;
/// ===
String sentpacket ;
String str;
char charBuf[100];

Leave a Reply

Your email address will not be published.