UART communication issue with NPK sensor and ESP32 LILYGO-t-sim7000g

Attempting to request NPK and ph data from npkph sensor. using a max485 UART to MODBUS connection. the sensor requires a baud rate of 9600. I believe I'm not using UART correctly and I'm not sure how to fix it. I just get back empty squares and zeros when I try to Serial.read Thank you for the help

#define TINY_GSM_MODEM_SIM7000
#define TINY_GSM_RX_BUFFER 1024 // Set RX buffer to 1Kb
#define SerialAT Serial1
//#define Serial2 Serial2
//include libraries

#include <TinyGsmClient.h>
#include <SPI.h>
#include <SD.h>
#include <Ticker.h>
#include <HTTPClient.h>


//Setting up parameters for RS485
const byte ph[]= {0x01,0x03,0x00,0x06,0x00,0x01,0x64,0x0B};
const byte nit[] = {0x01,0x03,0x00,0x1e,0x00,0x01,0xE4,0x0C};
const byte phos[] = {0x01,0x03,0x00,0x1f,0x00,0x01,0xB5,0xCC};
const byte potass[] = {0x01,0x03,0x00,0x20,0x00,0x01,0x85,0xC0};
byte valph,valnit,valpot,valphos;

byte values[11];
//SoftwareSerial mod(2,3);

#define RE 33
#define DE 32


//GPS variables
String coordinates;
String latstring;
String longstring;

// See all AT commands
#define DUMP_AT_COMMANDS

// set GSM PIN
#define GSM_PIN ""

//GPRS id
const char apn[]  = "mobile";     //SET TO YOUR APN
const char gprsUser[] = "";
const char gprsPass[] = "";

const char* server = "maker.ifttt.com";
const char* resource = "/trigger/collect_soildata/with/key/c8zYBqZPlu8ltgaK56M8NRXACzViMFOpdl9Ejy-9Eg4";
const int port = 80; 

#ifdef DUMP_AT_COMMANDS  // if enabled it requires the streamDebugger lib
  #include <StreamDebugger.h>
  StreamDebugger debugger(SerialAT, Serial);
  TinyGsm modem(debugger);
#else
  TinyGsm modem(SerialAT);
#endif

// TinyGSM Client for Internet connection
TinyGsmClient client(modem);

#define uS_TO_S_FACTOR 1000000ULL  // Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP  60          // Time ESP32 will go to sleep (in seconds)

#define UART_BAUD   115200
#define PIN_DTR     25
#define PIN_TX      27
#define PIN_RX      26
#define PWR_PIN     4

#define SD_MISO     2
#define SD_MOSI     15
#define SD_SCLK     14
#define SD_CS       13
#define LED_PIN     12

int counter, lastIndex, numberOfPieces = 24;
String pieces[24], input;

void setup(){
  // Set console baud rate
  Serial.begin(9600);
  //mod.begin(9600);
  delay(10);
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
  // Set LED OFF
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);

  pinMode(PWR_PIN, OUTPUT);
  digitalWrite(PWR_PIN, HIGH);
  delay(300);
  digitalWrite(PWR_PIN, LOW);

  SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
  if (!SD.begin(SD_CS)) {
    Serial.println("SDCard MOUNT FAIL");
  } else {
    uint32_t cardSize = SD.cardSize() / (1024 * 1024);
    String str = "SDCard Size: " + String(cardSize) + "MB";
    Serial.println(str);
  }

  Serial.println("\nWait...");

  delay(1000);

  SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);


  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  Serial.println("Initializing modem...");
  if (!modem.restart()) {
    Serial.println("Failed to restart modem, attempting to continue without restarting");
  }
}

void loop(){
  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  Serial.println("Initializing modem...");
  if (!modem.init()) {
    Serial.println("Failed to restart modem, attempting to continue without restarting");
  }

  String name = modem.getModemName();
  delay(500);
  Serial.println("Modem Name: " + name);

  String modemInfo = modem.getModemInfo();
  delay(500);
  Serial.println("Modem Info: " + modemInfo);
  

  // Unlock your SIM card with a PIN if needed
  if ( GSM_PIN && modem.getSimStatus() != 3 ) {
      modem.simUnlock(GSM_PIN);
  }
  modem.sendAT("+CFUN=0 ");
  if (modem.waitResponse(10000L) != 1) {
    DBG(" +CFUN=0  false ");
  }
  delay(200);

  /*
    2 Automatic
    13 GSM only
    38 LTE only
    51 GSM and LTE only
  * * * */
  String res;
  // CHANGE NETWORK MODE, IF NEEDED
  res = modem.setNetworkMode(2);
  if (res != "1") {
    DBG("setNetworkMode  false ");
    return ;
  }
  delay(200);

  /*
    1 CAT-M
    2 NB-Iot
    3 CAT-M and NB-IoT
  * * */
  // CHANGE PREFERRED MODE, IF NEEDED
  res = modem.setPreferredMode(1);
  if (res != "1") {
    DBG("setPreferredMode  false ");
    return ;
  }
  delay(200);

  /*AT+CBANDCFG=<mode>,<band>[,<band>…]
   * <mode> "CAT-M"   "NB-IOT"
   * <band>  The value of <band> must is in the band list of getting from  AT+CBANDCFG=?
   * For example, my SIM card carrier "NB-iot" supports B8.  I will configure +CBANDCFG= "Nb-iot ",8
   */
  /* modem.sendAT("+CBANDCFG=\"NB-IOT\",8 ");*/
  
  /* if (modem.waitResponse(10000L) != 1) {
       DBG(" +CBANDCFG=\"NB-IOT\" ");
   }*/
   delay(200);

  modem.sendAT("+CFUN=1 ");
  if (modem.waitResponse(10000L) != 1) {
    DBG(" +CFUN=1  false ");
  }
  delay(200);

  SerialAT.println("AT+CGDCONT?");
  delay(500);
  if (SerialAT.available()) {
    input = SerialAT.readString();
    for (int i = 0; i < input.length(); i++) {
      if (input.substring(i, i + 1) == "\n") {
        pieces[counter] = input.substring(lastIndex, i);
        lastIndex = i + 1;
        counter++;
       }
        if (i == input.length() - 1) {
          pieces[counter] = input.substring(lastIndex, i);
        }
      }
      // Reset for reuse
      input = "";
      counter = 0;
      lastIndex = 0;

      for ( int y = 0; y < numberOfPieces; y++) {
        for ( int x = 0; x < pieces[y].length(); x++) {
          char c = pieces[y][x];  //gets one byte from buffer
          if (c == ',') {
            if (input.indexOf(": ") >= 0) {
              String data = input.substring((input.indexOf(": ") + 1));
              if ( data.toInt() > 0 && data.toInt() < 25) {
                modem.sendAT("+CGDCONT=" + String(data.toInt()) + ",\"IP\",\"" + String(apn) + "\",\"0.0.0.0\",0,0,0,0");
              }
              input = "";
              break;
            }
          // Reset for reuse
          input = "";
         } else {
          input += c;
         }
      }
    }
  } else {
    Serial.println("Failed to get PDP!");
  }

  Serial.println("\n\n\nWaiting for network...");
  if (!modem.waitForNetwork()) {
    delay(10000);
    return;
  }

  if (modem.isNetworkConnected()) {
    Serial.println("Network connected");
  }
  //Aquire sensor readings
  getph();
  getnitrogen();
  getphosphorus();
  getpotassium();  
 // --------GPS--------
  Serial.println("\n---Starting GPS---\n");
  getgps();
  Serial.println("\n---End of GPS---\n");

  // -------GPRS--------
  Serial.println("\n---Starting GPRS TEST---\n");
  senddata();
  Serial.println("\n---End of GPRS TEST---\n");


  // --------TESTING POWER DOWN--------

  // Try to power-off (modem may decide to restart automatically)
  // To turn off modem completely, please use Reset/Enable pins
  modem.sendAT("+CPOWD=1");
  if (modem.waitResponse(10000L) != 1) {
    DBG("+CPOWD=1");
  }
  // The following command does the same as the previous lines
  modem.poweroff();
  Serial.println("Poweroff.");

  // GO TO SLEEP
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(200);
  esp_deep_sleep_start();

  // Do nothing forevermore
  while (true) {
      modem.maintain();
  }
}

void getgps(){
// Set SIM7000G GPIO4 HIGH ,turn on GPS power
  // CMD:AT+SGPIO=0,4,1,1
  // Only in version 20200415 is there a function to control GPS power
  modem.sendAT("+SGPIO=0,4,1,1");
  if (modem.waitResponse(10000L) != 1) {
    DBG(" SGPIO=0,4,1,1 false ");
  }
  modem.enableGPS();
  float lat,  lon;
  while (1) {
    if (modem.getGPS(&lat, &lon)) {
      Serial.printf("lat:%f lon:%f\n", lat, lon);
      break;
    } else {
      Serial.print("getGPS ");
      Serial.println(millis());
    }
    delay(2000);
  }
  modem.disableGPS();
  // Set SIM7000G GPIO4 LOW ,turn off GPS power
  // CMD:AT+SGPIO=0,4,1,0
  // Only in version 20200415 is there a function to control GPS power
  modem.sendAT("+SGPIO=0,4,1,0");
  if (modem.waitResponse(10000L) != 1) {
    DBG(" SGPIO=0,4,1,0 false ");
  }
  //prep to send coordinates
  latstring = String(lat,7);
  longstring = String(lon,7);
  if (lat>0){
    latstring = "0"+String(lat,7);
  }
  if (lon>0){
    longstring = "0"+String(lon,7);
  }
  coordinates = latstring;
  coordinates.concat(longstring);
}

//Connect to GPRS and send JSON data packet
void senddata(){
 Serial.println("Connecting to: " + String(apn));
  if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
    delay(10000);
    return;
  }

  Serial.print("GPRS status: ");
  if (modem.isGprsConnected()) {
    Serial.println("connected");
  //Client connection
  if (!client.connect(server, port)) {
      Serial.println(" fail");
    }
    else {
      Serial.println(" OK");
      String jsonObject = String("{\"value1\":\"") + "sfsfarm(1)" + "\",\"value2\":\"" + 905591009088955 + "\",\"value3\":\"" + coordinates + "\"}";       
      client.println(String("POST ") + resource + " HTTP/1.1");
      client.println(String("Host: ") + server); 
      client.println("Connection: close\r\nContent-Type: application/json");
      client.print("Content-Length: ");
      client.println(jsonObject.length());
      client.println();
      client.println(jsonObject);

      unsigned long timeout = millis();
      while (client.connected() && millis() - timeout < 10000L) {
        // Print available data (HTTP response from server)
        while (client.available()) {
          char c = client.read();
          Serial.print(c);
          timeout = millis();
        }
      }
      Serial.println();
    
      // Close client and disconnect
      client.stop();
      Serial.println(F("Server disconnected"));

    }
   
  } 
  else {
    Serial.println("not connected");
  }
  modem.gprsDisconnect();
  if (!modem.isGprsConnected()) {
    Serial.println("GPRS disconnected");
  } else {
    Serial.println("GPRS disconnect: Failed.");
  }
}

void getph(){
  Serial.flush();
  digitalWrite(DE,HIGH);
  digitalWrite(RE,HIGH);
  delay(10);
  if(Serial.write(ph,sizeof(ph))==8){
    digitalWrite(DE,LOW);
    digitalWrite(RE,LOW);
    delay(200);
    for(byte i=0;i<7;i++){
    //Serial.print(mod.read(),HEX);
  while(Serial.available()){
    values[i] = Serial.read();
  }
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  valph = values[4];
  Serial.println(valph);
}

void getnitrogen(){
  Serial.flush();
  digitalWrite(DE,HIGH);
  digitalWrite(RE,HIGH);
  delay(10);
  if(Serial.write(nit,sizeof(nit))==8){
    digitalWrite(DE,LOW);
    digitalWrite(RE,LOW);
    delay(200);
    for(byte i=0;i<7;i++){
    //Serial.print(mod.read(),HEX);
  while(Serial.available()){
    values[i] = Serial.read();
  }
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  valnit = values[4];
  Serial.println(valnit);
}

void getphosphorus(){
  Serial.flush();
  digitalWrite(DE,HIGH);
  digitalWrite(RE,HIGH);
  delay(10);
  if(Serial.write(phos,sizeof(phos))==8){
    digitalWrite(DE,LOW);
    digitalWrite(RE,LOW);
    delay(200);
    for(byte i=0;i<7;i++){
    //Serial.print(mod.read(),HEX);
  while(Serial.available()){
    values[i] = Serial.read();
  }
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  valphos = values[4];
   Serial.println(valphos);
}

void getpotassium(){
  Serial.flush();
digitalWrite(DE,HIGH);
  digitalWrite(RE,HIGH);
  delay(10);
  if(Serial.write(potass,sizeof(potass))==8){
    digitalWrite(DE,LOW);
    digitalWrite(RE,LOW);
    delay(200);
    for(byte i=0;i<7;i++){
    //Serial.print(mod.read(),HEX);
  while(Serial.available()){
    values[i] = Serial.read();
  }
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  valpot = values[4];
  Serial.println(valpot);
}

This is a pretty long and complex code.

Did you develop this code in small steps yourself or did you take it from somewhere "ready to use"
in both cases if something does not work you should use small test-codes that tests one single thing

testing receiving from your sensor.
testing communicating with the SIM700

post a link to the datasheet of your sensor it might be that adjusting to 9600 baud is not sufficient. There are more parameters than can vay:

  • number of data-bits
  • number of stop-bits
  • parity

This should be described in the datasheet of the sensor

best regards Stefan

did you test each part of the code before trying to integrate them all together?

right off the bat, I use hardware serial on a ESP32 a bit differently then the OP does.
ESP32

#include <HardwareSerial.h>

HardwareSerial GPSSerial ( 1 );
HardwareSerial LIDARSerial ( 2 );

voiding setup()
{

  LIDARSerial.begin ( SerialDataBits, SERIAL_8N1, 26, 25 );
  GPSSerial.begin ( GPS_DataBits, SERIAL_8N1, 2, 15 ); // begin GPS hardware serial

}

might be of help or not.

Yes, I was successful in getting cellular connection and then gps. the sensor part is the only part not working at the moment

I'll try 2 and 15, since I'm not using an SD card, I think I should be able to use them right?

RS485-Soil NPK+PH Sensor.pdf (393.1 KB)
Here is the link for the soil tester, I have successfully completed communication, with the sim7000, and the gps, its just I'm not getting values back with the soil tester that I'm expecting, I just keep getting all F's back

When the soil sensor is in the air and dried off what does it read?

When the soil sensor is in the water what does it read?

Those 2 numbers will be used as calibration points for wet and dry.

Your code is using the standard serial connection which is used for uploading the code and for communicating with the serial monitor.
This serial interface is called "serial"
the difference to the other serial interfaces becomes only obvious if the others were exactly named too:
Serial1
Serial2

or
You have to explicitly define them
here is an example that shows this

the most inportant thing is to define

#include <HardwareSerial.h>
HardwareSerial ESP32Serial1(1);
ESPSerial1.begin(lBaudrate, SERIAL_8N1, 16, 17);

where 16,17 are the Rx /Tx pins

best regards Stefan

I know I'm asking for a lot here, but the board I'm using is a LILYGO-T-SIM7000G, with a esp32-WROVER-E chip, would 18 and 19 work for that configuration you sent? since I'm already using SERIAL1 for my sim card? So would using ESP32Serial(2) work?

What happened when you tried?

I tested Serial1 and Serial2 on a NodeMCU ESP-WROOM-32 MODULE

// ESP32 serial1 and serial2 hardware loop back test 

// see https://circuits4you.com/2018/12/31/esp32-hardware-serial2-example/
/* There are three serial ports on the ESP known as U0UXD, U1UXD and U2UXD.
 * 
 * U0UXD is used to communicate with the ESP32 for programming and during reset/boot.
 * U1UXD is unused and can be used for your projects. Some boards use this port for SPI Flash access though
 * U2UXD is unused and can be used for your projects.
*/

#define RXD1 12  // for loopback jumper these pins
#define TXD1 13

#define RXD2 16
#define TXD2 15

void setup() {
  // Note the format for setting a serial port is as follows: Serial2.begin(baud-rate, protocol, RX pin, TX pin);
  Serial.begin(115200);
  Serial1.begin(9600, SERIAL_8N1, RXD1, TXD1);
  Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);
  Serial.println("ESP32 hardware serial test on Serial1 and Serial2");
  Serial.println("Serial Txd is on pin: "+String(TX));
  Serial.println("Serial Rxd is on pin: "+String(RX));
  Serial.println("Serial1 Txd1 is on pin: "+String(TXD1));
  Serial.println("Serial1 Rxd1 is on pin: "+String(RXD1));
  Serial.println("Serial2 Txd2 is on pin: "+String(TXD2));
  Serial.println("Serial2 Rxd2 is on pin: "+String(RXD2));
}

void loop() { //Choose Serial1 or Serial2 as required
  while (Serial2.available()) {
    Serial.println("Serial2 = " + Serial2.readStringUntil('\n'));
  }
  while (Serial1.available()) {
    Serial.println("Serial1 = " + Serial1.readStringUntil('\n'));
  }
  while (Serial.available()) {
    String s = Serial.readStringUntil('\n');
    if(s.charAt(0)=='1') Serial1.print( s);
    else                 Serial2.print( s);
  }
}

@claytonscheurer the code you are using to talk to your NKP sensor is a slightly modified version of the piece of awful code that is circulating the various "how to" websites.

I've very little knowledge of an ESP32, but it looks like your setup is using a hardware serial port to communicate with the sensor (rather than a software serial port that the UNO based projects use). If you are using a hardware serial port, then you need to wait until the transmission is complete before switching your RS485 module back to receive mode.

Insert a Serial.flush() after your Serial.write() commands in getph(), getnitrogen() etc.

That may work for you but there are other things wrong with the NPK code too. Try formatting your code and it may be clearer to you what will happen in this piece of code:

    for (byte i = 0; i < 7; i++) {
      //Serial.print(mod.read(),HEX);
      while (Serial.available()) {
        values[i] = Serial.read();
      }
      Serial.print(values[i], HEX);
    }

Hi, I am trying to use the max485 uart to modbus reciever with a lilygo-t-sim7000g esp32 module. It is a ESP32 Dev Module. the SoftwareSerial.h library is throwing the library not found which apparently is an issue with softwareserial and esp32?Compilation error: SoftwareSerial.h: No such file or directory
Any solutions to achieve uart communication on an ESP32?

Why are you using software serial, which is known to not work very well with a ESP32, when the ESP32 has several hardware serial ports?

Also that doesn't answer my question so if you don't have a solution that's fine

try this code where a ESP32 is connected to a RS485 module

// RS485 using ESP32 Serial1 pins 16 Tx and Rx 17 and  DE and RE to  pins 18 and 19

#define RS485Serial Serial1  // hardware serial port on MegaESP32

// RS485 VCC ESP32 to to 3.3V
#define RXD2 16  //  ESP32 Serial1 Receive  pin 16 to RO
#define TXD2 17  //  ESP32 Serial1 Transmit pin 17 to DI

// RS485 DE and RE to ESP32 pins 18 and 19
#define DE 18  //RS485 Direction control pin
#define RE 19  //RS485 Direction control pin

#define RS485Transmit HIGH
#define RS485Receive LOW

void setup() 
{
  while (!Serial)   ;
  delay(1000);
  // Start the built-in serial port, probably to Serial Monitor
  Serial.begin(115200);
  Serial.println("ESP32 to RS484 - Use Serial Monitor, type in upper window, ENTER");
  pinMode(DE, OUTPUT);
  pinMode(RE, OUTPUT);
  digitalWrite(DE, RS485Receive);  // Disable RS485 Transmit
  digitalWrite(RE, RS485Receive);  // Disable RS485 Transmit
  RS485Serial.begin(115200, SERIAL_8N1, RXD2, TXD2);       // set the RS485 data rate
}

// loop sending data from Mega to RS485 and receiving data
void loop() {
  if (Serial.available()) {            // Arduino Serial data avaliable?
    digitalWrite(DE, RS485Transmit);   // Enable RS485 Transmit
    digitalWrite(RE, RS485Transmit);   // Enable RS485 Transmit
    RS485Serial.write(Serial.read());  // Send byte to Remote Arduino
    RS485Serial.flush();               // wait for byte to be transmitted
    digitalWrite(DE, RS485Receive);    // Disable RS485 Transmit
    digitalWrite(RE, RS485Receive);    // Disable RS485 Transmit
  }

  if (RS485Serial.available())           // RS485 serial data available?
      Serial.write(RS485Serial.read());  // read character and display it
}

to test it I connected the RS485 module to a USB-RS485 dongle connected to a PC

ESP32 serial monitor displays

test1 from pc
test 2 from pc 1234567890
test3 from pc abcdef

and a terminal emulator on the PC displays (note local echo is on)

test1 from ESP32
test2 1234567890
test3 abcdefghijk
test1 from pc
test 2 from pc 1234567890
test3 from pc abcdef
test4 from ESP32 98765432

Your two topics on the same or similar subject have been merged.

Please do not duplicate your questions as doing so wastes the time and effort of the volunteers trying to help you as they are then answering the same thing in different places.

Please create one topic only for your question and choose the forum category carefully. If you have multiple questions about the same project then please ask your questions in the one topic as the answers to one question provide useful context for the others, and also you won’t have to keep explaining your project repeatedly.

Repeated duplicate posting could result in a temporary or permanent ban from the forum.

Could you take a few moments to Learn How To Use The Forum

It will help you get the best out of the forum in the future.

Thank you.

using Serial1 or Serial2
which can be reconfigured to use different IO-pins

Serial2.begin(Baudrate, SERIAL_8N1, RxPin, TxPin);

SERIAL_8N1: constant for configuring 8 databits No parity 1 stopbit

Here is the issue I'm running into now, I am now using hardware serial but I'm getting an error...Here is the error: Rebooting...
��G�D��!��&1f1�!M�E (9) uart: uart_set_pin(683): tx_io_num error
ESP_ERROR_CHECK failed: esp_err_t 0xffffffff (ESP_FAIL) at 0x4008a1b4
file: "C:\Users\scheurc1\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\cores\esp32\esp32-hal-uart.c" line 167
func: uartBegin
expression: uart_set_pin(uart_nr, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)

abort() was called at PC 0x4008a1b7 on core 1

Backtrace:0x400836d9:0x3ffb26300x4008a1c1:0x3ffb2650 0x4008ee35:0x3ffb2670 0x4008a1b7:0x3ffb26f0 0x400d8702:0x3ffb2710 0x400d5fca:0x3ffb2770 0x400d2f59:0x3ffb27b0 0x400d8936:0x3ffb2820

Here is my new code using HardwareSerial

#define TINY_GSM_MODEM_SIM7000
#define TINY_GSM_RX_BUFFER 1024 // Set RX buffer to 1Kb
#define SerialAT Serial1

//include libraries
#include <TinyGsmClient.h>
#include <SPI.h>
#include <SD.h>
#include <Ticker.h>
#include <HTTPClient.h>
#include <HardwareSerial.h>
HardwareSerial Serialtwo(2);
//Setting up parameters for RS485
const byte ph[]= {0x01,0x03,0x00,0x06,0x00,0x01,0x64,0x0B};
const byte nit[] = {0x01,0x03,0x00,0x1e,0x00,0x01,0xE4,0x0C};
const byte phos[] = {0x01,0x03,0x00,0x1f,0x00,0x01,0xB5,0xCC};
const byte potass[] = {0x01,0x03,0x00,0x20,0x00,0x01,0x85,0xC0};
byte valph,valnit,valpot,valphos;

byte values[11];


#define RE 33
#define DE 32


//GPS variables
String coordinates;
String latstring;
String longstring;

// See all AT commands
#define DUMP_AT_COMMANDS

// set GSM PIN
#define GSM_PIN ""

//GPRS id
const char apn[]  = "mobile";     //SET TO YOUR APN
const char gprsUser[] = "";
const char gprsPass[] = "";

const char* server = "maker.ifttt.com";
const char* resource = "/trigger/collect_soildata/with/key/c8zYBqZPlu8ltgaK56M8NRXACzViMFOpdl9Ejy-9Eg4";
const int port = 80; 

#ifdef DUMP_AT_COMMANDS  // if enabled it requires the streamDebugger lib
  #include <StreamDebugger.h>
  StreamDebugger debugger(SerialAT, Serial);
  TinyGsm modem(debugger);
#else
  TinyGsm modem(SerialAT);
#endif

// TinyGSM Client for Internet connection
TinyGsmClient client(modem);

#define uS_TO_S_FACTOR 1000000ULL  // Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP  60          // Time ESP32 will go to sleep (in seconds)

#define UART_BAUD   115200
#define PIN_DTR     25
#define PIN_TX      27
#define PIN_RX      26
#define PWR_PIN     4

#define SD_MISO     2
#define SD_MOSI     15
#define SD_SCLK     14
#define SD_CS       13
#define LED_PIN     12
#define RXPIN 34
#define TXPIN 35
int counter, lastIndex, numberOfPieces = 24;
String pieces[24], input;

void setup(){
  // Set console baud rate
  Serial.begin(9600);
  Serialtwo.begin(9600,SERIAL_8N1, RXPIN, TXPIN);
  //mod.begin(9600);
  delay(10);
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
  // Set LED OFF
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);

  pinMode(PWR_PIN, OUTPUT);
  digitalWrite(PWR_PIN, HIGH);
  delay(300);
  digitalWrite(PWR_PIN, LOW);

  SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
  if (!SD.begin(SD_CS)) {
    Serial.println("SDCard MOUNT FAIL");
  } else {
    uint32_t cardSize = SD.cardSize() / (1024 * 1024);
    String str = "SDCard Size: " + String(cardSize) + "MB";
    Serial.println(str);
  }

  Serial.println("\nWait...");

  delay(1000);

  SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);


  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  Serial.println("Initializing modem...");
  if (!modem.restart()) {
    Serial.println("Failed to restart modem, attempting to continue without restarting");
  }
}

void loop(){
  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  Serial.println("Initializing modem...");
  if (!modem.init()) {
    Serial.println("Failed to restart modem, attempting to continue without restarting");
  }

  String name = modem.getModemName();
  delay(500);
  Serial.println("Modem Name: " + name);

  String modemInfo = modem.getModemInfo();
  delay(500);
  Serial.println("Modem Info: " + modemInfo);
  

  // Unlock your SIM card with a PIN if needed
  if ( GSM_PIN && modem.getSimStatus() != 3 ) {
      modem.simUnlock(GSM_PIN);
  }
  modem.sendAT("+CFUN=0 ");
  if (modem.waitResponse(10000L) != 1) {
    DBG(" +CFUN=0  false ");
  }
  delay(200);

  /*
    2 Automatic
    13 GSM only
    38 LTE only
    51 GSM and LTE only
  * * * */
  String res;
  // CHANGE NETWORK MODE, IF NEEDED
  res = modem.setNetworkMode(2);
  if (res != "1") {
    DBG("setNetworkMode  false ");
    return ;
  }
  delay(200);

  /*
    1 CAT-M
    2 NB-Iot
    3 CAT-M and NB-IoT
  * * */
  // CHANGE PREFERRED MODE, IF NEEDED
  res = modem.setPreferredMode(1);
  if (res != "1") {
    DBG("setPreferredMode  false ");
    return ;
  }
  delay(200);

  /*AT+CBANDCFG=<mode>,<band>[,<band>…]
   * <mode> "CAT-M"   "NB-IOT"
   * <band>  The value of <band> must is in the band list of getting from  AT+CBANDCFG=?
   * For example, my SIM card carrier "NB-iot" supports B8.  I will configure +CBANDCFG= "Nb-iot ",8
   */
  /* modem.sendAT("+CBANDCFG=\"NB-IOT\",8 ");*/
  
  /* if (modem.waitResponse(10000L) != 1) {
       DBG(" +CBANDCFG=\"NB-IOT\" ");
   }*/
   delay(200);

  modem.sendAT("+CFUN=1 ");
  if (modem.waitResponse(10000L) != 1) {
    DBG(" +CFUN=1  false ");
  }
  delay(200);

  SerialAT.println("AT+CGDCONT?");
  delay(500);
  if (SerialAT.available()) {
    input = SerialAT.readString();
    for (int i = 0; i < input.length(); i++) {
      if (input.substring(i, i + 1) == "\n") {
        pieces[counter] = input.substring(lastIndex, i);
        lastIndex = i + 1;
        counter++;
       }
        if (i == input.length() - 1) {
          pieces[counter] = input.substring(lastIndex, i);
        }
      }
      // Reset for reuse
      input = "";
      counter = 0;
      lastIndex = 0;

      for ( int y = 0; y < numberOfPieces; y++) {
        for ( int x = 0; x < pieces[y].length(); x++) {
          char c = pieces[y][x];  //gets one byte from buffer
          if (c == ',') {
            if (input.indexOf(": ") >= 0) {
              String data = input.substring((input.indexOf(": ") + 1));
              if ( data.toInt() > 0 && data.toInt() < 25) {
                modem.sendAT("+CGDCONT=" + String(data.toInt()) + ",\"IP\",\"" + String(apn) + "\",\"0.0.0.0\",0,0,0,0");
              }
              input = "";
              break;
            }
          // Reset for reuse
          input = "";
         } else {
          input += c;
         }
      }
    }
  } else {
    Serial.println("Failed to get PDP!");
  }

  Serial.println("\n\n\nWaiting for network...");
  if (!modem.waitForNetwork()) {
    delay(10000);
    return;
  }

  if (modem.isNetworkConnected()) {
    Serial.println("Network connected");
  }
  //Aquire sensor readings
  getph();
  getnitrogen();
  getphosphorus();
  getpotassium();  
 // --------GPS--------
  Serial.println("\n---Starting GPS---\n");
  getgps();
  Serial.println("\n---End of GPS---\n");

  // -------GPRS--------
  Serial.println("\n---Starting GPRS TEST---\n");
  senddata();
  Serial.println("\n---End of GPRS TEST---\n");


  // --------TESTING POWER DOWN--------

  // Try to power-off (modem may decide to restart automatically)
  // To turn off modem completely, please use Reset/Enable pins
  modem.sendAT("+CPOWD=1");
  if (modem.waitResponse(10000L) != 1) {
    DBG("+CPOWD=1");
  }
  // The following command does the same as the previous lines
  modem.poweroff();
  Serial.println("Poweroff.");

  // GO TO SLEEP
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(200);
  esp_deep_sleep_start();

  // Do nothing forevermore
  while (true) {
      modem.maintain();
  }
}

void getgps(){
// Set SIM7000G GPIO4 HIGH ,turn on GPS power
  // CMD:AT+SGPIO=0,4,1,1
  // Only in version 20200415 is there a function to control GPS power
  modem.sendAT("+SGPIO=0,4,1,1");
  if (modem.waitResponse(10000L) != 1) {
    DBG(" SGPIO=0,4,1,1 false ");
  }
  modem.enableGPS();
  float lat,  lon;
  while (1) {
    if (modem.getGPS(&lat, &lon)) {
      Serial.printf("lat:%f lon:%f\n", lat, lon);
      break;
    } else {
      Serial.print("getGPS ");
      Serial.println(millis());
    }
    delay(2000);
  }
  modem.disableGPS();
  // Set SIM7000G GPIO4 LOW ,turn off GPS power
  // CMD:AT+SGPIO=0,4,1,0
  // Only in version 20200415 is there a function to control GPS power
  modem.sendAT("+SGPIO=0,4,1,0");
  if (modem.waitResponse(10000L) != 1) {
    DBG(" SGPIO=0,4,1,0 false ");
  }
  //prep to send coordinates
  latstring = String(lat,7);
  longstring = String(lon,7);
  if (lat>0){
    latstring = "0"+String(lat,7);
  }
  if (lon>0){
    longstring = "0"+String(lon,7);
  }
  coordinates = latstring;
  coordinates.concat(longstring);
}

//Connect to GPRS and send JSON data packet
void senddata(){
 Serial.println("Connecting to: " + String(apn));
  if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
    delay(10000);
    return;
  }

  Serial.print("GPRS status: ");
  if (modem.isGprsConnected()) {
    Serial.println("connected");
  //Client connection
  if (!client.connect(server, port)) {
      Serial.println(" fail");
    }
    else {
      Serial.println(" OK");
      String jsonObject = String("{\"value1\":\"") + "sfsfarm(1)" + "\",\"value2\":\"" + 905591009088955 + "\",\"value3\":\"" + coordinates + "\"}";       
      client.println(String("POST ") + resource + " HTTP/1.1");
      client.println(String("Host: ") + server); 
      client.println("Connection: close\r\nContent-Type: application/json");
      client.print("Content-Length: ");
      client.println(jsonObject.length());
      client.println();
      client.println(jsonObject);

      unsigned long timeout = millis();
      while (client.connected() && millis() - timeout < 10000L) {
        // Print available data (HTTP response from server)
        while (client.available()) {
          char c = client.read();
          Serial.print(c);
          timeout = millis();
        }
      }
      Serial.println();
    
      // Close client and disconnect
      client.stop();
      Serial.println(F("Server disconnected"));

    }
   
  } 
  else {
    Serial.println("not connected");
  }
  modem.gprsDisconnect();
  if (!modem.isGprsConnected()) {
    Serial.println("GPRS disconnected");
  } else {
    Serial.println("GPRS disconnect: Failed.");
  }
}

void getph(){
  digitalWrite(DE,HIGH);
  digitalWrite(RE,HIGH);
  delay(10);
  if(Serialtwo.write(ph,sizeof(ph))==8){
    digitalWrite(DE,LOW);
    digitalWrite(RE,LOW);
    delay(200);
    for(byte i=0;i<7;i++){
    //Serial.print(mod.read(),HEX);
    values[i] = Serialtwo.read();
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  valph = values[4];
  Serial.println(valph);
}

void getnitrogen(){
  digitalWrite(DE,HIGH);
  digitalWrite(RE,HIGH);
  delay(10);
  if(Serialtwo.write(nit,sizeof(nit))==8){
    digitalWrite(DE,LOW);
    digitalWrite(RE,LOW);
    delay(200);
    for(byte i=0;i<7;i++){
    //Serial.print(mod.read(),HEX);
    values[i] = Serialtwo.read();
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  valnit = values[4];
  Serial.println(valnit);
}

void getphosphorus(){
  digitalWrite(DE,HIGH);
  digitalWrite(RE,HIGH);
  delay(10);
  if(Serialtwo.write(phos,sizeof(phos))==8){
    digitalWrite(DE,LOW);
    digitalWrite(RE,LOW);
    delay(200);
    for(byte i=0;i<7;i++){
    //Serial.print(mod.read(),HEX);
    values[i] = Serialtwo.read();
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  valphos = values[4];
   Serial.println(valphos);
}

void getpotassium(){
digitalWrite(DE,HIGH);
  digitalWrite(RE,HIGH);
  delay(10);
  if(Serialtwo.write(potass,sizeof(potass))==8){
    digitalWrite(DE,LOW);
    digitalWrite(RE,LOW);
    delay(200);
    for(byte i=0;i<7;i++){
    //Serial.print(mod.read(),HEX);
    values[i] = Serialtwo.read();
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  valpot = values[4];
  Serial.println(valpot);
}