2

The client always reply with "ThisCodeTurnsTheUnoOnn" or ThisCodeTurnsTheUnoOff" based on some conditions.

This piece of code is inside arduino uno's void loop().

Expected behavior:

The arduino read the reply and turn the digital pin 13 to HIGH if the onCount is 22 after matching every character one by one with the client's reply which was "ThisCodeTurnsTheUnoOnn" and the other way around:

The arduino read the reply and turn the digital pin 13 to LOW if the offCount is 22 after matching every character one by one with the client's reply which was "ThisCodeTurnsTheUnoOff".

and the digital pin 13 should always remain in the previous state if the new client's reply was the same as previous reply. (e.g. if client's reply was "ThisCodeTurnsTheUnoOff" and the arduino turn the digital pin 13 to LOW, then in next loop the client's reply was same "ThisCodeTurnsTheUnoOff" and the arduino should keep the digital pin 13 in LOW state).

Actual behavior:

CASE : client's reply was "ThisCodeTurnsTheUnoOff" and the arduino turn the digital pin 13 to LOW, then in next loop the client's reply was same "ThisCodeTurnsTheUnoOff" and the arduino should keep the digital pin 13 in LOW state but the arduino turns the digital pin 13 HIGH when entering the next loop(void loop()) then turns back to LOW after entered the loop(void loop()).

  // available() will return the number of characters
  // currently in the receive buffer.

  const int solenoidValve = 13;

  char onCode[23] = "ThisCodeTurnsTheUnoOnn";
  char offCode[23] = "ThisCodeTurnsTheUnoOff";

  int onCount = 0;
  int offCount = 0;

  while (client.available())
  {
    char c = client.read();

    if(c == onCode[onCount])
    {
      onCount++;


      if(onCount == 22)
      {
        digitalWrite(solenoidValve, HIGH); 
        break;
      }
    }
    else
    {
      onCount = 0;
    }

    if(c == offCode[offCount])
    {
          offCount++;

          if(offCount == 22)
          {
            digitalWrite(solenoidValve, LOW);
            break;
          }
    }
    else
    {
      offCount = 0;
    }
    Serial.write(c);
  }

The complete code, in case the logical errors is not within the above piece of code:

#include <SoftwareSerial.h> 
#include <SparkFunESP8266WiFi.h>

//////////////////////////////
// WiFi Network Definitions //
//////////////////////////////
// Replace these two character strings with the name and
// password of your WiFi network.
const char mySSID[] = "SSID";
const char myPSK[] = "PASSWORD";
const int solenoidValve = 13;
char onCode[23] = "ThisCodeTurnsTheUnoOnn";
char offCode[23] = "ThisCodeTurnsTheUnoOff";

//water flow calculation variables
volatile int flow_frequency; // Measures flow sensor pulses
unsigned int l_hour; // Calculated litres/hour
unsigned char flowsensor = 2; // Sensor Input
unsigned long currentTime;
unsigned long cloopTime;

//////////////////
// HTTP Strings //
//////////////////
const char destServer[] = "192.168.0.101"; //private ip //[Kugan] 07/8/16 try4 : changed Global IP to Local IP for testing Code ID:1132
const uint16_t port = 8080; // Code ID: 1126 [Kugan] added variable port  
const String httpRequest = "GET /aquosdb/getStatus.php HTTP/1.1\n"
                           "Host: 192.168.0.101\n" //private ip [note for myself: dont forget to change IP]
                           "Connection: close\n\n"; //[Kugan] 07/8/16 try4 : changed Global IP to Local IP for testing Code ID:1132


// All functions called from setup() are defined below the
// loop() function. They modularized to make it easier to
// copy/paste into sketches of your own.
void setup() 
{
   pinMode(flowsensor, INPUT);
   digitalWrite(flowsensor, HIGH); // Optional Internal Pull-Up
   Serial.begin(9600);
   attachInterrupt(0, flow, RISING); // Setup Interrupt
   sei(); // Enable interrupts
   currentTime = millis();
   cloopTime = currentTime;

  // Serial Monitor is used to control the demo and view
  // debug information.
  Serial.begin(9600);
  //serialTrigger(F("Press any key to begin.")); //[Kugan] 28/7/16 try3 : disabled serial trigger for self automation Code ID:1130

  // initializeESP8266() verifies communication with the WiFi
  // shield, and sets it up.
  initializeESP8266();

  // connectESP8266() connects to the defined WiFi network.
  connectESP8266();

  // displayConnectInfo prints the Shield's local IP
  // and the network it's connected to.
  displayConnectInfo();

  //serialTrigger(F("Press any key to connect client."));  //[Kugan] 28/7/16 try3 : disabled serial trigger for self automation Code ID:1130
  //valveControl();
}

void loop() 
{
  setFlow();
  //delay(500); // [Kugan] 29/7/16 try3 : added delay to debug connection bug Code ID:1131
  valveControl();
}

void initializeESP8266()
{
  // esp8266.begin() verifies that the ESP8266 is operational
  // and sets it up for the rest of the sketch.
  // It returns either true or false -- indicating whether
  // communication was successul or not.
  // true
  int test = esp8266.begin();
  if (test != true)
  {
    Serial.println(F("Error talking to ESP8266."));
    errorLoop(test);
  }
  Serial.println(F("ESP8266 Shield Present"));
}

void connectESP8266()
{
  esp8266.disconnect(); // Code ID:1125 [Kugan] To disconnect from previously connected wifi AP
  delay(100);           // esp8266 has auto-reconnect function to connect previously connected AP

  // The ESP8266 can be set to one of three modes:
  //  1 - ESP8266_MODE_STA - Station only
  //  2 - ESP8266_MODE_AP - Access point only
  //  3 - ESP8266_MODE_STAAP - Station/AP combo
  // Use esp8266.getMode() to check which mode it's in:
  int retVal = esp8266.getMode();
  if (retVal != ESP8266_MODE_STA)
  { // If it's not in station mode.
    // Use esp8266.setMode([mode]) to set it to a specified
    // mode.
    retVal = esp8266.setMode(ESP8266_MODE_STA);
    if (retVal < 0)
    {
      Serial.println(F("Error setting mode."));
      errorLoop(retVal);
    }
  }
  Serial.println(F("Mode set to station"));

  // esp8266.status() indicates the ESP8266's WiFi connect
  // status.
  // A return value of 1 indicates the device is already
  // connected. 0 indicates disconnected. (Negative values
  // equate to communication errors.)
  retVal = esp8266.status();
  if (retVal <= 0)
  {
    Serial.print(F("Connecting to "));
    Serial.println(mySSID);
    // esp8266.connect([ssid], [psk]) connects the ESP8266
    // to a network.
    // On success the connect function returns a value >0
    // On fail, the function will either return:
    //  -1: TIMEOUT - The library has a set 30s timeout
    //  -3: FAIL - Couldn't connect to network.
    retVal = esp8266.connect(mySSID, myPSK);
    delay(60);
    if (retVal < 0)
    {
      Serial.println(F("Error connecting"));
      errorLoop(retVal);
    }
  }
}

void displayConnectInfo()
{
  char connectedSSID[20];
  memset(connectedSSID, 0, 20);
  // esp8266.getAP() can be used to check which AP the
  // ESP8266 is connected to. It returns an error code.
  // The connected AP is returned by reference as a parameter.
  int retVal = esp8266.getAP(connectedSSID);
  if (retVal > 0)
  {
    Serial.print(F("Connected to: "));
    Serial.println(connectedSSID);
  }

  // esp8266.localIP returns an IPAddress variable with the
  // ESP8266's current local IP address.
  IPAddress myIP = esp8266.localIP();
  Serial.print(F("My IP: ")); Serial.println(myIP);
}

void flow() // Interrupt function
{
   flow_frequency++;
}

void setFlow()
{
   // To use the ESP8266 as a TCP client, use the 
  // ESP8266Client class. First, create an object:
  ESP8266Client client1;
  client1.stop(); //[Kugan] 28/7/16 try2 : added Code ID:1127

  // ESP8266Client connect([server], [port]) is used to 
  // connect to a server (const char * or IPAddress) on
  // a specified port.
  // Returns: 1 on success, 2 on already connected,
  // negative on fail (-1=TIMEOUT, -3=FAIL).
  int retVal = client1.connect(destServer, port); //Code ID:1126 [Kugan] created variable port
  if (retVal <= 0)
  {
    Serial.println(retVal);  //[Kugan] 28/7/16 try2 : added Code ID:1130 for debugging
    Serial.println("flow");
    Serial.println(F("Failed to connect to server."));

    initializeESP8266(); // [Kugan] 28/7/16 try2 : added Code ID:1129 reinitialize, connect, and display connection info
    connectESP8266();
    displayConnectInfo();

    return;
  }



   currentTime = millis();
   // Every second, calculate and print litres/hour
   if(currentTime >= (cloopTime + 1000))
   {
      cloopTime = currentTime; // Updates cloopTime
      // Pulse frequency (Hz) = 7.5Q, Q is flow rate in L/min.
      l_hour = (flow_frequency * 60 / 7.5); // (Pulse frequency x 60 min) / 7.5Q = flowrate in L/hour
      flow_frequency = 0; // Reset Counter
   }

  // print and write can be used to send data to a connected
  // client connection.
  String httpPostRequest = "GET /aquosdb/setFlow.php?data=" + String(l_hour) + " HTTP/1.1\n" //sets the water flow value
                           "Host: 192.168.0.101\n" //private ip
                           "Connection: close\n\n"; //[Kugan] 07/8/16 try4 : changed Global IP to Local IP for testing Code ID:1132
  client1.print(httpPostRequest);


  while (client1.available()) // [Kugan] 28/7/16 Code ID: 1128  to clear the buffer
    Serial.write(client1.read()); // read() gets the FIFO char

  if (client1.connected())
    client1.stop(); // stop() closes a TCP connection.  
}

void valveControl()
{
  // To use the ESP8266 as a TCP client, use the 
  // ESP8266Client class. First, create an object:
  ESP8266Client client;
  client.stop(); //[Kugan] 28/7/16 try2 : added Code ID:1127 stop any existing connections

  // ESP8266Client connect([server], [port]) is used to 
  // connect to a server (const char * or IPAddress) on
  // a specified port.
  // Returns: 1 on success, 2 on already connected,
  // negative on fail (-1=TIMEOUT, -3=FAIL).
  int retVal = client.connect(destServer, port); // Code ID:1126 [Kugan] created variable port
  if (retVal <= 0)
  {
    Serial.println(retVal);  // [Kugan] 28/7/16 try2 : added Code ID:1130 for debugging
    Serial.println("valve");
    Serial.println(F("Failed to connect to server."));

    initializeESP8266(); // [Kugan] 28/7/16 try2 : added Code ID:1129 reinitialize, connect, and display connection info
    connectESP8266();
    displayConnectInfo();

    return;
  }

  // print and write can be used to send data to a connected
  // client connection.
  client.print(httpRequest);

  // available() will return the number of characters
  // currently in the receive buffer.
  int onCount = 0;
  int offCount = 0;

  while (client.available())
  {
    char c = client.read();

    if(c == onCode[onCount])
    {
      onCount++;


      if(onCount == 22)
      {
        digitalWrite(solenoidValve, HIGH); 
        break;
      }
    }
    else
    {
      onCount = 0;
    }

    if(c == offCode[offCount])
    {
          offCount++;

          if(offCount == 22)
          {
            digitalWrite(solenoidValve, LOW);
            break;
          }
    }
    else
    {
      offCount = 0;
    }
    Serial.write(c);
  }


  // connected() is a boolean return value - 1 if the 
  // connection is active, 0 if it's closed.
  if (client.connected())
    client.stop(); // stop() closes a TCP connection.
}

// errorLoop prints an error code, then loops forever.
void errorLoop(int error)
{
  Serial.print(F("Error: ")); Serial.println(error);
  Serial.println(F("Looping forever."));
  for (;;)
    ;
}

// serialTrigger prints a message, then waits for something
// to come in from the serial port.
void serialTrigger(String message)
{
  Serial.println();
  Serial.println(message);
  Serial.println();
  while (!Serial.available())
    ;
  while (Serial.available())
    Serial.read();
}

Thanks in advance for your efforts to answer my question.

  • The sample code looks fine, and shouldn't cause your problem. So my guess is that there is something wrong in the rest of the code. Either that or the board is somehow resetting. – Gerben Sep 10 '16 at 13:57
1

The biggest obstacle to you getting this working is the somewhat bizarre way you are working out what has been sent to you, by counting characters that match and waiting until they reach 22.

Instead you should read the input character by character and place them into an array. Discard anything past the 22nd character so it doesn't overflow the array. Then you can compare what is in that array to strings stored in flash (using the F() macro) and the strcmp_P() function.

-2

Too many mistakes in that code to identify ONE as the cause for your bug!

E.g., onCode[23] for a 22 char string. Should be onCode[22].

E.g., if(offCount == 22) but with a zero index you should be checking at offCount == 21.

E.g., using a 'break' command inside an 'if' inside another 'if' inside a 'while', its not going to behave as you might expect.

There is much more to describe about the problems of you code but not in the scope of Arduino, its just about C/C++ in general. Code structure etc.

My suggestion is to simplify your method by using a single char code instead of a long string, at least until you get it working. For example use: oncode = 1, offcode = 2.

Once you get it to work with a single char code, then move forward to a longer one if you need it

  • 1
    onCode[23] for a 22 char string. Should be onCode[22]. - no, it should be 23. You're forgetting the terminating NULL character. In actuality it shouldn't be either, it should be a PROGMEM string, simplest to place directly inline with F(). – Majenko Sep 10 '16 at 10:22
  • 1
    using a 'break' command inside an 'if' inside another 'if' inside a 'while', its not going to behave as you might expect. Why? break has no effect on the if, only the while. – Majenko Sep 10 '16 at 10:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.