0

I have been working on monitoring an aquaculture , where I log the environment variables (temp. , humidity, gas sensor data) to firebase and control feeding mechanism via an app(where data can also be viewed)

The setup has all sensors connected to Uno Board, which transmits data serially to esp8266.

Pin 2 of Uno is connected to Pin 2 of esp8266

Pin 3 of Uno is connected to Pin 3 of esp8266

Right now the boards are being powered by USB ports in the computer.

My understanding is that, once all the data are read, the Serial.available() becomes 0 and the while() loop will not execute again, but it worked again and reads data.. to avoid sending same data over and over again(to FireBase), I used Boolean values to take care of.

The data should be available only once per 30 seconds, so after a string is fully read, I was able to see that pgm entered into while() loop and reads one/two values


// uploaded to esp8266 Lolin(wemos) d1 r2 and mini 

#include<ESP8266WiFi.h>
#include<FirebaseArduino.h>
#include<SoftwareSerial.h> 

// Set these to run example.
#define FIREBASE_HOST "@#$%^.firebaseio.com" 
#define FIREBASE_AUTH "********" 

#define WIFI_SSID "###########"
#define WIFI_PASSWORD "&^*^*%$#" 

SoftwareSerial esp(D2,D3);

float temp_fb;
float gas_fb;
float hum_fb;

unsigned long last_chk = 0 ; 
unsigned long time_elapsed; 

bool t_ar , h_ar , g_ar = false ; //chk arrival of all data b4 sending

char r;  
String cu_st = "c"; 

int found = 1;

void setup() {
  Serial.begin(9600);
  esp.begin(4800);

  // connect to wifi.
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting"); 
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

void loop() 
{
  time_elapsed = millis(); 
  if(time_elapsed - last_chk > 5000){ 
    Serial.print("checking for data from arduino...\tfeeder state\t");
    Serial.println(cu_st);
    last_chk = time_elapsed;
    time_elapsed = millis();
  }
   while(esp.available()>0)
  { 
     if(found == 1)
     {
      Serial.println("................found data...............") ;
      found = 0;
     } 
     r = esp.read(); 
     //Serial.print("first char\t"); just for debugging purposes 
     //Serial.println(r); 
     switch(r)
     {

      case 't':
      {
        Serial.println("got t...") ;
        t_ar = true;
        temp_fb = esp.readStringUntil(',').toFloat(); 
        break ;
      }

      case 'g':
      {
          Serial.println("got g...") ;
          g_ar = true;

          gas_fb = esp.readStringUntil(',').toFloat();;
          break ;
      }

      case 'h':
      {
        Serial.println("got h...") ;
        h_ar = true;

        hum_fb = esp.readStringUntil(',').toFloat();
        break ;   
      }

      case 'c':  
      {
        cu_st = "c" ;
        Firebase.setString("feeder" ,"c");
      }
      default: break; 

     }

  }

  found = 1 ; 

  if(g_ar and t_ar and h_ar)
  {
     //writing to firebase  
     Serial.println("got the set.. to fb now"); 
     Firebase.setFloat("GAS SENSORinst" ,gas_fb);
     Firebase.setFloat("HUMIDITY SENSORinst" ,hum_fb);
     Firebase.setFloat("TEMP SENSORinst" ,temp_fb);
     Firebase.pushFloat("GAS SENSOR" ,gas_fb);
     Firebase.pushFloat("HUMIDITY SENSOR" ,hum_fb);
     Firebase.pushFloat("TEMP SENSOR" ,temp_fb);
  }

  t_ar , h_ar , g_ar = false ;

  cu_st = Firebase.getString("feeder");


   if (cu_st == "o")
   {
    Serial.println("\t\trecd req to feed"); 
    esp.print('o');   
   }

} 

The arduino sends data every 30 Sec. The servo connected to Arduino was having jitters every time the data was being sent(apparently due to not enough power to supply for all devices connected and both Softwareserial and servo having same timer) so I have added a LED just for trial
For some reason, if block in close_feed() is always executed.

//uploaded to arduino Uno 
#include <SoftwareSerial.h>
#include<TimerOne.h>


SoftwareSerial ArduinoUno(3,2);
#include<Servo.h>
#include "DHT.h"

//Servo feeder;

int send_rate = 30000; //every 30 secs send data
unsigned long last_time_stamp = 0;
unsigned long cur_time = 0;

String sen_vals = "";
#define led 13
int feeding = 0 ;
const int gas = 0;//gas sensor o/p
#define DHTPIN 8
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  ArduinoUno.begin(4800);
  pinMode(led,OUTPUT);
  //feeder.attach(11);
  //feeder.write(85);
  Timer1.initialize(10000); //every 10 millisecond check for arrival of feed command
  Timer1.attachInterrupt(feed_cmd); //chk feed_cmd for every 10 mS
   dht.begin();

  pinMode (3,INPUT); //recieve from esp
  pinMode (2,OUTPUT); //transmit to esp


}

void feed_cmd()
{
  while(ArduinoUno.available())
  {
    char valve = ArduinoUno.read();

    if(valve=='o')
    {
       digitalWrite(led, HIGH);
       //feeder.write(0);
       feeding = 1;
       ArduinoUno.print("c");
       valve = "";
    }
  }
}

void close_feed()
{
  if(feeding == 1)
  {

    feeding = 0;
    delay(5000);
    //feeder.write(85);
    digitalWrite(led,LOW);
    Serial.println("I am closing feeder");

   }
}

void send_data()
{
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  String ht = String('h')+String(h)+String(',')+String('t')+String(t)+String(',');

  float raw_v = analogRead(gas);  
  String g = String('g')+String(raw_v)+String(',');

  sen_vals = ht + g ;

  Serial.println(sen_vals);
  ArduinoUno.print(sen_vals);
}

void loop()
{
  // put your main code here, to run repeatedly:

  close_feed();
  cur_time = millis();
  if(cur_time > last_time_stamp + send_rate)
  {

    last_time_stamp = cur_time;
    send_data();

  }

}

Some how some blocks are executed even when they shouldn't be.. I wrote the code, but I cant figure out where the code fails, used a lot of serial prints to see how the flow of the code, but it only confused me further!

If somebody can take a look at this code and point out the flaws..I'll greatly appreciate it.

EDIT: I have changed he code as suggested below, but now the Arduino is receiving random things as input(pic attached) I have added the changed code too(I know this post is getting bigger and bigger, but i thought making changes to already existing code here won't be good for readability )

void setup() {
  Serial.begin(9600);
  esp.begin(4800);

  // connect to wifi.
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting"); 
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

void loop() 
{
  time_elapsed = millis(); 
  if(time_elapsed - last_chk > 5000){ 
    Serial.print("checking for data from arduino...\tfeeder state\t");
    Serial.println(cu_st);
    last_chk = time_elapsed;
    time_elapsed = millis();
  }
   while(esp.available()>0)
  { 
     if(found == 1)
     {
      Serial.println("................found data...............") ;
      found = 0;
     } 
     r = esp.read(); 
     //Serial.print("first char\t");
     //Serial.println(r); 
     switch(r)
     {

      case 't':
      {
        Serial.println("got t...") ;
        t_ar = true;
        temp_fb = esp.parseFloat(); 
        break ;
      }

      case 'g':
      {
          Serial.println("got g...") ;
          g_ar = true;

          gas_fb = esp.parseFloat();;
          break ;
      }

      case 'h':
      {
        Serial.println("got h...") ;
        h_ar = true;
        hum_fb = esp.parseFloat();
        break ;   
      }
      default: break; 

     }

  }

  found = 1 ; 

  if(g_ar and t_ar and h_ar)
  {
     //writing to firebase  
     Serial.println("got the set.. to fb now"); 
     Firebase.setFloat("GAS SENSORinst" ,gas_fb);
     Firebase.setFloat("HUMIDITY SENSORinst" ,hum_fb);
     Firebase.setFloat("TEMP SENSORinst" ,temp_fb);
     Firebase.pushFloat("GAS SENSOR" ,gas_fb);
     Firebase.pushFloat("HUMIDITY SENSOR" ,hum_fb);
     Firebase.pushFloat("TEMP SENSOR" ,temp_fb);
  }

  t_ar , h_ar , g_ar = false ;
  if (cu_st == "c")
  {
    sent = 0; 
  }
  cu_st = Firebase.getString("feeder");  
   if (cu_st == "o")
   {
    Serial.println("\t\trecd req to feed"); 
    if(sent == 0)
    {
      esp.print('o');
      sent =1; 
      cu_st = "c";    
      Serial.println("setting feeder to close in firebase");
      Firebase.setString("feeder" ,"c");

   }

  }
}   

#include <SoftwareSerial.h>

SoftwareSerial ArduinoUno(3,2);
#include<Servo.h>
#include "DHT.h"

//Servo feeder;

int send_rate = 30000; //every 30 secs send data
unsigned long last_time_stamp = 0;
unsigned long cur_time = 0;
unsigned long close_time = 0;
unsigned long open_time = 0;
#define led 13
int feeder = 0 ;
const int gas = 0;//gas sensor o/p
#define DHTPIN 8
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  ArduinoUno.begin(4800);
  pinMode(led,OUTPUT);
  //feeder.attach(11);
  //feeder.write(85); //closing position
   dht.begin();

  pinMode (3,INPUT); //recieve from esp
  pinMode (2,OUTPUT); //transmit to esp


}

void feed_cmd()
{
  while(ArduinoUno.available())
  {
    char valve = ArduinoUno.read();
    Serial.print("feeder cmd recd ");
    Serial.println(valve);
    if(valve=='o')
    {
       digitalWrite(led, HIGH);
       //feeder.write(0); //open position
       open_time = millis();
       feeder = 1 ;
       Serial.println("I am opening feeder");
    }
  }
}

void close_feed()
{

  if(feeder == 1)
  {
   close_time = millis();
   if(close_time - open_time > 5000)
  {
    feeder = 0;
    digitalWrite(led , LOW);
    Serial.println("I am closing feeder") ;
  }
  }
}

void send_data()
{
  float h = dht.readHumidity();

  float t = dht.readTemperature();

  float raw_v = analogRead(gas);  

  ArduinoUno.print("h");
  ArduinoUno.print(h);
  ArduinoUno.print(",t");
  ArduinoUno.print(t);
  ArduinoUno.print(",g");
  ArduinoUno.print(raw_v);
  ArduinoUno.print(",\n");
}

void loop()
{
  // put your main code here, to run repeatedly:

  feed_cmd();
  close_feed();
  cur_time = millis();
  if(cur_time - last_time_stamp > send_rate)
  {

    last_time_stamp = cur_time;
    send_data();

  }

}

here's a pic showing random char Thanks for your time!!!

1 Answer 1

1

I cannot really narrow down the source of your observed problems, since the problem descriptions are not clear enough. But there are some obvious problems/potential for making it better in your code.

In the Uno Code:

  • It is totally unnecessary to use a timer interrupt for reading the SoftwareSerial interface. Instead you should write your loop() function non-blocking, meaning, that it does not wait for something to happen, but it will execute other code in the meantime (so no delay in close_feed()). Then you can just read the serial data in the loop function. You are saving a timer this way.

  • In send_data() you are using the String class to concat a string of human readable data together and then send it. Using the String class in that way is evil, since on every concat operation it will allocate a new buffer for the string, deleting the old one. That makes Swiss cheese out of your heap memory (called heap fragmentation). That can lead to instability. Look at Majenko's blog entry about the Evils of Arduino Strings for more information. Instead of concatting you should simply print the information one after another:

    Serial.print("h");
    Serial.print(h);
    Serial.print(",t");
    Serial.print(t);
    

    and so forth.

  • Your handling of the millis() function should be different. It will roll over after 52 days. To prevent, that your code misfunctions at that time, you need to always take the time difference:

    if(cur_time - last_time_stamp > send_rate)
    

    instead of

    if(cur_time > last_time_stamp + send_rate)
    

In the ESP Code:

  • Your SoftwareSerial read code seems weird to me, but I think it should work. I would introduce a message protocol to the data stream, meaning to mark the end of a full message (a message containing one frame with all relevant data) with a special delimiter character, for example a newline character \n. Then you can read the message until this character into a buffer and then process the message as a whole.

That's about what I can say to this point. If you need a more focused answer, you have you describe further and more detailed the symptoms (what behavior you are seeing and what you expected).

6
  • thanks for pointing out some good practices and details ... will work this out... Feb 18, 2020 at 9:35
  • As far as the issues go, I'm struggling to put it to words... Eg. When the pgm starts, there's no pblm, but when I give command to open from App, it just starts printing I am closing feeder continuously , that shouldn't be happening right, because we set feeding =0 and only way it goes into if block of close_feed() is if feed_cmd() got invoked again, but that shouldn't happen because we've already read from the incoming serial.. Hope I've explained my issue!!! Feb 18, 2020 at 9:44
  • You send the feeding character o continuously based on the Firebase value "feeder". It that value reset directly after you have set it? If not, meaning if the Firebase value "feeder " stays "o", the esp will continuously send the character 'o', which will cause the Arduino to continuously close the feeder.
    – chrisl
    Feb 18, 2020 at 9:53
  • Yes, I get the flow now.... But I thought once Arduino receives the open cmd, by sending "c" to esp, which in turn writes to firebase , this shouldn't be happening I'll re-write it so that esp itself will send "c" to firebase right after sending open cmd to arduino... (funnily enough, that's how i had it earlier, but since the feeder valve was not responding, i thought maybe the value change was changing too quick and "c" was being read skipping "o" cmd ) Feb 18, 2020 at 10:02
  • You should only send the "o" cmd once to the Uno. Even if you immediately send "c" back to the ESP, the ESP most likely will already have send several "o" commands to the Uno. So just send it once instead of continuously
    – chrisl
    Feb 18, 2020 at 10:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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