Monday, August 11, 2014

Remote communication between Arduino and smartphone

I developed this little device to check an analog sensor installed in a remote area using my phone. The idea is to check the level of fuel in generators we install in remote areas. So far, we had to drive there to check and refuel them. Now, we can check the level of fuel in each generator anytime and we can organize a refuelling trip more efficiently, only when necessary. The communication between the Arduino and the phone are simple text SMS.

COMPONENTS AND WIRING

To interface the arduino to the GSM network you need a GSM shield and a SIM card. I recommend the genuine Arduino GSM/GPRS shield, which has more functions, but here I'm using a SIM900 GSM/GPRS shield, which is enough for this project, and much cheaper. In Australia I bought a 20$ Vodafone simcard because it lasts one year without recharging, but I pay more than 28c per SMS (national and international). I'm sure you can get a better deal if you have time to look around.

The sensor: my employer gave me a fuel sensor to play with. It's a floating arm that moves the contact on a resistive rail. I measured the resistance across this resistor: 11 ohms when the arm is at the top (tank full), 185 ohms when the arm is completely down (tank empty). It's very important to know this value. The output value I want to see is a percentage from 0% (tank empty) to 100% (tank full).


If we connect this variable resistance in series with a fixed resistor we create a voltage divider: when we apply 5 volts we'll see a voltage drop across each resistor, and their sum will be 5 volts. The value of the fixed resistor should be about the same range of the variable. In this case I have a 68 ohms resistor. The voltage drop across resistors in series is proportional to their resistance. I wired up the circuit to measure the voltage drop across the fixed resistor with the analog input A5.


As usual, I connected a LCD to display the value in real time on the device.
The power comes from a 12V DC power supply in parallel with a 9.6V battery pack (8 x rechargable AA). When the generator is off, the batteries power the Arduino. When the generator is on, the power supply powers the Arduino and charges the batteries. To do that the power supply must have a higher voltage than the battery. The input voltage range (recommended) for the Arduino Uno is 7V to 12V.
It took me many hours to understand which pins are not used by the GSM shield. After many unsuccessful tries I was able to use pin 13,12,11,6,5,4 to run the LCD, without interfering with the operations of the shield.


SKETCH

We know the value read in the analog input is 0 to 1023, where 1023 correspond to 5 Volts. We have to apply Kirchoff Law to calculate the minimum and maximum value across the resistance, and then map this value to give an output value between 0 and 100%.

1023 * 68 / (185+68) = 275
1023 * 68 / (11+68) = 880

There is always a little error so, after few tries, I changed those values to 280 and 850 to give exactly 0 to 100% (it was close enough anyway).

I don't want to store the SMS on the SIM card, so I delete everything at the start of the program. This makes sure there is enough space to receive a command. Without this it stopped working suddenly and I couldn't understand why: the SIM was full.

A friend created an Android app to send a message to the device just pressing "test". The app sends a SMS starting with "a". The Arduino receive the message and it knows that "a" means "how much fuel is left?". It replies to the sender with the reading from the sensor.

Also, I want it to send an alarm SMS to a set "emergency phone" when the level of fuel passes the 50%, 25% and 10%.

#include <LiquidCrystal.h>
#include "SIM900.h"
#include <SoftwareSerial.h>
#include "sms.h"
SMSGSM sms;

LiquidCrystal lcd(13, 12, 11, 6, 5, 4);

int numdata;
boolean started=false;
char smsbuffer[160];
char n[20];
char sms_position;
char phone_number[20];
char sms_text[100];
int i;
char alarm_phone[20] = "+61439021813";

String dataString;
boolean alarm50 = false;
boolean alarm25 = false;
boolean alarm10 = false;


void setup()
{
  lcd.begin(16, 2);
  lcd.print("Testing...");
//  Serial.begin(9600);
//  Serial.println("GSM Shield testing.");
  if (gsm.begin(4800))
    {
//    Serial.println("\nstatus=READY");
    started=true;
    }
//    else Serial.println("\nstatus=IDLE");
  for(i=1;i<=20;i++)
    {
    sms.DeleteSMS(i);
    }
}

void loop()
{
  int val=(map(analogRead(A5), 280, 850, 0, 100));
  constrain (val, 0, 100);
  lcd.clear();
  lcd.print("Fuel:");
  lcd.setCursor(6,0);
  lcd.print(val);
  lcd.setCursor(9,0);
  lcd.print("%");
  delay(500);
 
  if(started)
    {
    sms_position=sms.IsSMSPresent(SMS_UNREAD);
    if (sms_position)
      {
//     Serial.print("SMS postion:");
//     Serial.println(sms_position,DEC);
      sms.GetSMS(sms_position, phone_number, sms_text, 100);
//      Serial.println(phone_number);
//      Serial.println(sms_text);
      sms.DeleteSMS(1);
      if(sms_text[0] == 'a')
        {
        dataString = "";
        dataString += "Fuel: ";
        dataString += (val);
        dataString += "%";
//        Serial.println(dataString);
        char charBuf[50];
        dataString.toCharArray(charBuf, 50);
        if (sms.SendSMS(phone_number, charBuf));
//        Serial.println("\nSMS sent OK");  
        }
      }
      else
      {
        if(val < 50 && !alarm50)
          {
          if (sms.SendSMS(alarm_phone, "Fuel < 50%"));
//          Serial.println("\nAlarm50 sent OK");
          alarm50 = true;
          }
          if(val < 25 && !alarm25)
          {
          if (sms.SendSMS(alarm_phone, "Fuel < 50%"));
//          Serial.println("\nAlarm25 sent OK");
          alarm25 = true;
          }
          if(val < 10 && !alarm10)
          {
          if (sms.SendSMS(alarm_phone, "Fuel < 50%"));
//          Serial.println("\nAlarm10 sent OK");
          alarm10 = true;
          }
//        Serial.println("NO NEW SMS,WAITING");
      }
  }
}

VIDEOS



No comments:

Post a Comment