Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
stevetearle
Published © GPL3+

Remote Serial Terminal Connectivity From Anywhere DT-06 WiFi

WiFi enable your Arduino device and communicate with it from anywhere using a serial command-response terminal interface.

IntermediateFull instructions provided17,225
Remote Serial Terminal Connectivity From Anywhere DT-06 WiFi

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
DT-06 Wireless WiFi Serial Port Transparent Transmission Module TTL To WiFi
×1
ESP8266 ESP-01
Espressif ESP8266 ESP-01
×1

Software apps and online services

Zip containing Jee Labs ESP Link Firmware V3.0.14 and Expressif Flash tool

Story

Read more

Code

Demo Command - Response Terminal Interface

Arduino
LoadMaster MPPT PV Hotwater controller can be remotely interrogated using a Serial 'Command Response Terminal Interface. This Demo provides a basic idea of the code concepts inloved. Take a look at the Loadmaster project code to see how this interface method can be used to set RTC values etc
/*This is an Example of a Serial Command-response interface.
  Arduino's Serial data can be transparently carried over Wifi using a DT-06 (or ESP8266-01)
  Wifi Modules are loaded with esp-link firmware
  BLE (HM-10) wireless links also work well.
  
  Check Baud on the WifI module is set to match this program
  
  Tested using excellent Android 'Serial WiFI Terminal' and 'Serial Bluetooth Apps' by Kai Moriche.
  
  Sending a '?' +(CRLF) character will cause the Arduino to display a list of serial menu options
  Sending a 'L 1' Turns the Nanos onboard LED On,  L 2 turns it Off (COMMANDS USE CAPITAL LETTERS)
  Sending 'W 23' would save a new Temperature setting of 23 to the EEPROM
  
  Dated : 10th Jam 2020
  V1.01

 Hardware //////////////////////////////////////////////////////////////////////////

    This code uses the main serial port of the Arduino - shared by the USB socket on a Nano.
    When programming you MUST disconnect the DT-06 Wifi module connected to Tx & Rx to avoid data conflicts 
    For the Demo, Power the Arduino from its 5V pins or use a USB 'power only' source.
*/



#include <EEPROM.h>       //1024 Byte EEPROM

byte  LED = 13;          //The Nano's on-board LED
int Volts_ADC = A1;      //We will display volts on A1 when requested

float Volts = 0;
byte TempSet = 0;        //Illustrating a non volatile setting configured via the serial connection

unsigned long msec = 0;
unsigned long Lastmsec = 0;
unsigned long UpdateInterval = 1000;
boolean OutputData = false;

//Variables used in Serial CLI and Message Parsing
const byte numChars = 30;                 // Maximum Char length of received serial messages terminated in a Linefeed.
char receivedChars[numChars];
char RxdSerialMessage[numChars] = {0};    // variables to hold the parsed data

int RxdInt1 = 0;
int RxdInt2 = 0;
float RxdFloat2 = 0;    // Option to receive and use float values within command strings
int RxdInt3 = 0;
int RxdInt4 = 0;
int RxdInt5 = 0;
char CommandChar = 0;
boolean NewData = false;



//************************************ MAIN PROGRAM START - SETUP *******************************
void setup()
{

  Serial.begin(9600);       // Configue Hardware Serial. 
  Serial.flush();           // Clears the Serial RX buffer

  TempSet = EEPROM.read(2);     //Reads a saved setup value from EEPROM address location 2

  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);  //Set Nanos onboard LED initially off


}

//*********************************** MAIN PROGRAM LOOP **************************************
void loop()
{

  SerialRxWithEndMarker();           //Check for data message in serial buffer
                                     //messages seperated by NewLine char

  if (NewData == true) {
    parseData();                 // Function to Split message into command and space seperated values
    //showParsedData();          // FOR TEST ONLY! see what Character command and values are received

    HandleCommand();             //Routine to identify & manage different received command characters
  }

  msec = millis();                                // We use the millis millisecond runtime counter to schedule specific tasks

  if ((msec - Lastmsec) > UpdateInterval) {       //The Code below is executed evert MPPT update interval - 100ms)

    if (OutputData == true) {
      Serial.print(F("Volts on A1 = "));
      Serial.print(0.004887 * analogRead(Volts_ADC));    // read the Volts input A1
      Serial.println("Volts");
    }

    Lastmsec = msec;

  }
}

//****************************PROGRAM MAIN LOOP END ************************************
//****************************SUBROUTINES FOLLOW ***************************************

void HandleCommand (void)
// The first character within a received serial message (from SerialRxWithEndMarker CR/LF) is extracted by the ParseData Subroutine
// this routine identifies and handles the specific command request.
{

  switch (CommandChar) {

    case '?':                  // receiving a ? character will display the Serial Terminal command Menu

      ClearTerminal ();

      Serial.println(F("Serial Command Response Demo V1.0"));
      Serial.println(F("--- Command list: ---"));
      Serial.println("");
      Serial.println(F("? -  Show this Menu!"));
      Serial.println(F("V -  Stream A1 Voltage"));
      Serial.println(F("L -  Control LED"));
      Serial.println(F("S -  Show Rxd message 'S 123 -456 54 67'etc"));
      Serial.print(F("W -  Set Limit"));
      Serial.print(F(" (Currently "));
      Serial.print(TempSet);
      Serial.println(F("°C )"));
      break;


    case 'V':                         //Turns on streaming of Voltage reading on A1

      ClearTerminal ();
      Serial.println(F("Request to Output Voltage has been Received"));
      OutputData = true;
        
      break;
    
      
    case 'L':                         //Calls routine to turn LED on or OFF depending on Rxint1 value

      SetLED();
      break;

    case 'S':                        //Calls routine to display all values in Receive command string

      showParsedData();
      break;
   
   case 'W':                         //Calls routine to set temp limit 0 to 70C and save in EEPROM

      SetTemp();
      break;   
  }
}
  //********************************************************************************************************************************************************
  // Serial print commands used to Clear Telnet Terminal Screen and position Cursor to Home position

  void ClearTerminal (void)
  {
    Serial.write(27);             // ESC command

    Serial.print("[2J");          // Clear Screen...actually fills screen with carriage returns so earlier terminal data is not lost.
    Serial.write(27);
    Serial.print("[H");           // Cursor to Home position
  }



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

void SetTemp(void)                    // Serial command W sets and stores the target temperaturein EEPROM
{
  ClearTerminal ();                   //Clears Serial Terminal Screen and positions Cursor at Home position

  if (RxdInt1 == 0) {
    Serial.print(F(" Current Temp limit is "));
    Serial.print(TempSet);
    Serial.println(F("°C"));

    Serial.println(F("Set the °C limit using 'W HW'  where HW= 1 to 70"));
  }
  else {
    if (RxdInt1 > 0 && RxdInt1 < 71) {
     TempSet = RxdInt1;
     Serial.print(F(" Temperature limit has been set to "));
     Serial.print(TempSet);
     Serial.println(F("°C"));
    
     EEPROM.write(2, TempSet);          //Save temperature threshold to EEPROM address 2.
      
    }

    Serial.print("Temperature Limit = ");
    Serial.print(TempSet);
    Serial.println("°C");

  }
}

//*************************
void SetLED (void)                    // Serial command sets and stores the target water temperature
{
  ClearTerminal ();                   //Clears Serial Terminal Screen and positions Cursor at Home position

  if (RxdInt1 == 2) {
    Serial.print(F("Turn LED off"));
    digitalWrite(LED, LOW);  //LED off
    }
  else if (RxdInt1==1){
    Serial.print(F("Turn LED On"));
    digitalWrite(LED, HIGH);  //LED On
      }
  else{
    Serial.println(F("To Turn the LED ON send 'L 1'"));
    Serial.println(F("To Turn LED off send 'L 2'"));
     }
}


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

void SerialRxWithEndMarker() {
  //("expects to receive strin of characters terminated in a LF. Max buffer size is currently 30 chars, text or Integer and an optional floating point value seperated by a comma");
  //("Enter data in this style "C/I 24.7 CRLF  "   C/I maybe a text command String or Integer value, after the space should be a float value );
  // You can ommit the comma and Float value if not required
  //Note the parsing methods are now implemented in the functions specific to commands

  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

// if (Serial.available() > 0) {
  while (Serial.available() > 0 && NewData == false) {       //reads in new characters from serial buffer
    rc = Serial.read();

    if (rc != endMarker) {                                   //Looks for a new line code to end the message
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string a new serial message has been received
      ndx = 0;
      NewData = true;

    }
  }
}


//****************************************************************************************************
void parseData() {

  // split the data into its parts
  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(receivedChars, " ");  // get the first part of string before the first space Char
  strcpy(RxdSerialMessage, strtokIndx);     // copy it to RxdSerial message - extracts text string at start of a message if required

  CommandChar = receivedChars[0];      //First Char in the initial command string is used to identify the Command

  strtokIndx = strtok(NULL, " ");      // this continues where the previous call left off
  RxdInt1 = atoi(strtokIndx);          // convert the next part of command upto next space to an integer

  strtokIndx = strtok(NULL, " ");
  RxdInt2 = atoi(strtokIndx);          // convert this part to an Int - NOTE Currently Float values are not used in any commands
  //RxdFloat2 = atof(strtokIndx);        // If you want to recieve Floats, - NOTE Currently Float values are not used in any commands

  strtokIndx = strtok(NULL, " ");
  RxdInt3 = atoi(strtokIndx);          // convert this part to a float - NOTE Currently Float values are not used in any commands

  strtokIndx = strtok(NULL, " ");
  RxdInt4 = atoi(strtokIndx);          // convert this part to a float - NOTE Currently Float values are not used in any commands

  strtokIndx = strtok(NULL, " ");
  RxdInt5 = atoi(strtokIndx);          // convert this part to a float - NOTE Currently Float values are not used in any commands

  NewData = false;                      // The last received message has been identified handled

  OutputData = false;                 // Stop Outputting Data values if a new message is received,

}







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

void showParsedData() {
   // Used for testing only to see how command and integer values are extracted

  Serial.print("Initial CommandChar ");
  Serial.println(CommandChar);
  Serial.print("RxdInt1 = ");
  Serial.println(RxdInt1);
  Serial.print("RxdInt2 = ");
  Serial.println(RxdInt2);
  Serial.print("RxdInt3 = ");
  Serial.println(RxdInt3);
  Serial.print("RxdInt4 = ");
  Serial.println(RxdInt4);
  Serial.print("RxdInt5 = ");
  Serial.println(RxdInt5);

}

Credits

stevetearle

stevetearle

3 projects • 41 followers
A semi retired R&D Design Engineer now living on the Isle of Wight, South Coast of the UK

Comments