Weight scale with GSM capabilities - guidance and improvements needed

Hi people.

I’m building a weight scale using a HX711 load sensor and a Tinysine GSM Shield on an Arduino UNO.
I want to use it as a beehive scale for measuring the weight of the beehive two times a day and sending a SMS to my phone to inform me about the state of the beehive. I also have included a DHT11 and a DS18B20 sensor for measuring the temperature and humidity inside and outside of the beehive, and a DS1307 RTC for keeping time.

I have pretty much the whole project working as I have built both the metal frame for the load sensor and the Arduino circuit for the sensors.

The code is included below. It is working. The only problem is that it seems that the code or the Arduino kind of gets stuck and the feedback from the Serial monitor appears as below:

Ok, Time = 16:30:34, Date (D/

However, it only seems to be a problem only for the communication between the Arduino and the PC and it does not affect the weighing and SMS part of the code.

What I ask is if you would make any improvements on the code for it to run better.

As you see, I already stopped using the String function and used the dtostrf and strcpy/strcat to convert the several variables to a char array for sending the SMS.

/*
  Load Cell
  E+ -> RED
  E- -> BLACK
  A- -> WHITE
  A+ -> GREEN

  A1 -> HX711 CLK
  A0 -> DOUT
  5V -> VCC
  GND -> GND
*/

#include "LowPower.h"
#include "HX711.h"  //You must have this library in your arduino library folder
#include "DHT.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include "SIM900.h"
#include <SoftwareSerial.h>
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include "sms.h"
SMSGSM sms;
tmElements_t tm;

#define DOUT  A0
#define CLK  A1
#define DHTPIN  4
#define DHTTYPE DHT11
#define ONE_WIRE_BUS 5
HX711 scale(DOUT, CLK);

DHT dht(DHTPIN, DHTTYPE);

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

float calibration_factor = -42870; // ΕΜ: @29.999kg

//Global variables
float h; // humidity
float t1; // temperature
float t2; // temperature
float w; // weight
float dif; // difference
float lastWeight = 0;

int hour1 = 8; int min1 = 0;
int hour2 = 22; int min2 = 0;

int numdata;
boolean started = false;
char smsbuffer[160];
char n[20];

//debug begin
char sms_position;
char phone_number[20]  = "xxxxxxxxxx"; 
char sms_text[160];
int i = 0;

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

  dht.begin();
  sensors.begin();

  //  Serial.println(F("HX711 Calibration"));
  //  Serial.println(F("Remove all weight from scale"));
  //  Serial.println(F("After readings begin, place known weight on scale"));
  //  Serial.println(F("Press a,s,d,f to increase calibration factor by 10,100,1000,10000 respectively"));
  //  Serial.println(F("Press z,x,c,v to decrease calibration factor by 10,100,1000,10000 respectively"));
  //  Serial.println(F("Press t for tare"));
  scale.set_scale();
  scale.tare(); //Reset the scale to 0

  long zero_factor = scale.read_average(); //Get a baseline reading
  //  Serial.print(F("Zero factor: ")); //This can be used to remove the need to tare the scale. Useful in permanent scale projects.
  //  Serial.println(zero_factor);

  readSensors();
  delay(500);
  readSensors();
}

void loop() {
  readTime();

  if (((tm.Hour == hour1) & (tm.Minute == min1)) | ((tm.Hour == hour2) & (tm.Minute == min2))) {
    startGSM();

    readSensors();

    sendSMSread();
  }

  if (Serial.available()) {
    char temp = Serial.read();
    if (temp == '+' || temp == 'a')
      calibration_factor += 10;
    else if (temp == '-' || temp == 'z')
      calibration_factor -= 10;
    else if (temp == 's')
      calibration_factor += 100;
    else if (temp == 'x')
      calibration_factor -= 100;
    else if (temp == 'd')
      calibration_factor += 1000;
    else if (temp == 'c')
      calibration_factor -= 1000;
    else if (temp == 'f')
      calibration_factor += 10000;
    else if (temp == 'v')
      calibration_factor -= 10000;
    else if (temp == 't')
      scale.tare();  //Reset the scale to zero
  }

  scale.power_down();
  for (int j = 0; j <= 54; j++) {
    LowPower.idle(SLEEP_1S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF);
  }
  LowPower.idle(SLEEP_500MS, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF);
  scale.power_up();
}

void readSensors() {
  sensors.requestTemperatures(); // Send the command to get temperatures

  h = dht.readHumidity();
  // DHT11
  t1 = dht.readTemperature();
  // DS18B20
  t2 = sensors.getTempCByIndex(0);
  w = scale.get_units(10);

  dif = w - lastWeight;
  lastWeight = w;
  scale.set_scale(calibration_factor); 

  //Serial.print(F("Reading: "));
  //Serial.print(w, 3); 
  //Serial.print(F(" kg")); 
  //Serial.print(F(", calibration_factor: "));
  //Serial.print(calibration_factor);
  //Serial.print(F(", weight difference: "));
  //Serial.print(dif, 3); 
  //Serial.print(F(" kg"));
  //Serial.print(F(", T1 (*C): ")); // DHT11
  //Serial.print(t1);
  //Serial.print(F(", T2 (*C): ")); // DS18B20
  //Serial.print(t2);
  //Serial.print(F(", H (%): "));
  //Serial.print(h);
  //Serial.println();
}

void startGSM() {
  if (!started)
  {
    Serial.println(F("GSM Shield testing."));
    if (gsm.begin(4800))
    {
      Serial.println(F("\nstatus=READY"));
      started = true;
    }
    else {
      Serial.println(F("\nstatus=IDLE"));
    }
  }
}

void sendSMSread() {
  if ((started) & (i == 0)) {
    // convert floats w, dif, t1, t2, h to char arrays with 3 decimal points
    char wbuffer[10];
    dtostrf(w, 7, 3, wbuffer);
    char dbuffer[10];
    dtostrf(dif, 7, 3, dbuffer);
    char t1buffer[10];
    char t2buffer[10];
    dtostrf(t1, 5, 2, t1buffer);
    dtostrf(t2, 5, 2, t2buffer);
    char hbuffer[10];
    dtostrf(h, 5, 2, hbuffer);

    //
    //    String msg = String("ZIGARIA 1, Reading: ") + wbuffer + String(" kg, difference: ") + dbuffer  + String(" kg, T1 (*C): ") + String(t1) + String(", T2 (*C): ") + String(t2) + String(", H (%): ") + String(h);
    //    msg.toCharArray(sms_text, 160);

    strcpy(sms_text, "ZIGARIA 1, Reading: ");
    strcat(sms_text, wbuffer);
    strcat(sms_text, " kg, difference: ");
    strcat(sms_text, dbuffer);
    strcat(sms_text, " kg, T1 (*C): ");
    strcat(sms_text, t1buffer);
    strcat(sms_text, ", T2 (*C): ");
    strcat(sms_text, t2buffer);
    strcat(sms_text, ", H (%): ");
    strcat(sms_text, hbuffer);

    Serial.println(sms_text);
    delay(100);

    if (sms.SendSMS(phone_number, sms_text)) {
      Serial.println(F("\nSMS sent OK"));
      i++;
    }
  }
}

void readTime() {

  if (RTC.read(tm)) {
    Serial.print(F("Ok, Time = "));
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print(", Date (D/M/Y) = ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
  }
  else {
    if (RTC.chipPresent()) {
      Serial.println(F("The DS1307 is stopped.  Please run the SetTime"));
      Serial.println(F("example to initialize the time and begin running."));
      Serial.println();
    }
    else {
      Serial.println(F("DS1307 read error!  Please check the circuitry."));
      Serial.println();
    }
  }
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}

Any guidance and suggestions for improvements are welcome.

Thanks in advance.

Ektor

  if (((tm.Hour == hour1) & (tm.Minute == min1)) | ((tm.Hour == hour2) & (tm.Minute == min2))) {

The logical OR is ||, not |.

That condition will be true for 60 seconds at a time. The loop() function could iterate millions of times while it is true.

  if ((started) & (i == 0)) {

The logical AND is &&, not &.

    char t1buffer[10];
    char t2buffer[10];
    dtostrf(t1, 5, 2, t1buffer);
    dtostrf(t2, 5, 2, t2buffer);

Does you temperature sensor really give you results to 0.01 degrees?

int i = 0;

One letter global variable names are a REALLY BAD IDEA.

Thanks for the quick reply.

I'll search about the logical OR and AND to better understand the use of them.

PaulS:

char t1buffer[10];

char t2buffer[10];
dtostrf(t1, 5, 2, t1buffer);
dtostrf(t2, 5, 2, t2buffer);




Does you temperature sensor really give you results to 0.01 degrees?

Yeah, the DS18B20 sensor returns temperature down to 0.01 degrees Celsius. Not that it is important or needed. Would it be better to just do it to 0.1 degrees?

PaulS:
That condition will be true for 60 seconds at a time. The loop() function could iterate millions of times while it is true.

What do you mean by that? For which condition? Is it causing a problem?

Also, do you have any idea about the Serial monitor stucking?

Ektor