Project tutorial
Apartment / villa style multi user intercom system

Apartment / villa style multi user intercom system © GPL3+

Intercom system for Apartments/Villas with GSM, without using GSM library, and can also trigger the gate on call, or by giving a missed call

  • 1,002 views
  • 2 comments
  • 0 respects

Components and supplies

About this project

I was involved in installing intercoms for Apartments/villas. One of the client's asked if I was interested in renting out a system as a 7 unit apartment block needed an intercom, but did not have enough finances.

My biggest interest in this product was that I would use a C++ design but without using GSM library, because I could not simultaneously use GSM library and SoftwareSerial library.

HOW IT WORKS:

A visitor would dial the unit number and #, EG: 25#. The system then dials the phone number corresponding to 25. The tenant would answer, (Calls are cut after 40 seconds) and press "1" on their phone to trigger the gate, or do nothing to stop the visitor entering.

The gate can also be triggered by the tenant dialing the gate SIM card number, and cutting the call (At no charge).

Code

intcm_2017_03_running.inoC/C++
/*   Very special thanks to Prakash R.V (I am new to this and searched 100's of sites. This is the first one that I can use 
     to identify incoming call numbers.  http://www.induino.com/2013/11/interfacing-serial-devices-part-3.html
 *   Induino R3 User Guide - Program 17.2 - A Simple program to Respond to an Incomign Call.
     Also thanks to Martin Lorton and Jeremy Blum for the Youtube teachings.*/

/* Apartment / Villa style intercom system withour using GSM library (the reason is so that i can follow on PCmon what is happening,
because GSM library and SoftwareSerial don't work together*/


/* Working, but the next project will allow SMS to change phone numbers with EEPROM and USSD code to find / add airtime
This intercom system is currently being rented out to an apartment block in Umhlanga, South Africa*/


#include <SoftwareSerial.h>                                   
SoftwareSerial pcMon(0,1); //serial port (RX,TX) pcMon (0 ARD RX, 1 ARD TX)
SoftwareSerial SIM900(2,3); // configure serial port (ARDUINO RX, TX) SIM900  
int readyCalling = 4; //READY (GREEN LED) HIGH -- WAIT/ON CALL (BLUE LED) LOW 
int ledError = 5; //Call ended - Reset (Press STAR)
int buzz = 6;
int onCalltrigger = 7; // Input - sensor normally LOW____________________DTMF input trigger high
int driveGate = 8;    //Output to open gate normally LOW
int GSMPower = 9;
int testLed = 13;
int keypad = A0; //keypad input read
int kpdVal = 0;    //set "val" as analogread
byte kpd = 0;
byte numx = 0;
byte numy = 0;
byte numz = 0;
int triggerVal = 0;
int callTriggervalue = 0;
int kpdAdd = 0;
String dialNumber = "0";
int onCallcounter = 0;
int timeCounter = 250;    // Call timer - set here    160=22secs, 80=12secs, 250=40secs
String gsm_input = "";
int noCarrier = 0;
int userTimeout = 150;
int userTimer = 0;
int powerCheck = 0;




void setup() {         

  pcMon.begin(9600);//Serial for monitor               //serial usb
  SIM900.begin(19200); //Serial for GSM    
  pinMode(GSMPower, OUTPUT); //GSM startup
  pinMode(driveGate, OUTPUT); //gateTrigger
  pinMode(buzz, OUTPUT); //buzzer
  pinMode(readyCalling, OUTPUT); //READY (GREEN LED) HIGH -- WAIT/ON CALL (BLUE LED) LOW 
  pinMode(onCalltrigger, INPUT); //onCalltrigger
  pinMode(ledError, OUTPUT);  //Call ended - Reset
  pinMode(testLed, OUTPUT);
  delay(100);}


void loop() 
{ 
        powerCheck = 1;
        startUploop ();
        SIM900.print("AT+CLIP=1\r"); // turn on caller ID notification
  do {
      digitalWrite (buzz, LOW);
      digitalWrite (readyCalling, HIGH); 
      delay (20);
      kpdVal = analogRead (keypad);
      callTimeloop ();
      if (SIM900.available()) // Check data ouput of the GSM modem to identify incoming calls / messages.
      inComingloop (); 
      if (kpdVal <= 50)
      { delay (20);  }
      else
      dialSystemloop ();
      }
  while (powerCheck >= 0);
} //___________________________________loop end


void startUploop () {
        digitalWrite (GSMPower, HIGH);
        delay (1000);
        digitalWrite (GSMPower, LOW);
        digitalWrite (testLed, HIGH);
        delay (4000);
        digitalWrite (testLed, LOW);
        delay (4000);
        digitalWrite (testLed, HIGH);
        delay (4000);
        digitalWrite (testLed, LOW);
        delay (200);    }

void dialSystemloop ()  { 
        digitalWrite (buzz, HIGH);
        kpdVal = analogRead (keypad);
        delay (100);
        
              if ((818 < kpdVal) && (kpdVal < 870))       //Keypad is  (Hash pressed) Ready to dial
              {
                         pcMon.println("# Has been pressed");      //Ready to dial the kpdVal ref phone number
                         kpdAdd = ((numx * 100) + (numy * 10) + numz);
                         digitalWrite (buzz, HIGH);
                         delay (100);
                         digitalWrite (buzz, LOW);
                         pcMon.println (kpdAdd);             //serial usb
                         digitalWrite (readyCalling, LOW);    // Call starting here  
                         kpdNumberloop();
                                    if (kpdAdd == 0)  {
                                    badCall ();
                                    pcMon.println("Phone number doesn't exist");    }
                         else { pcMon.print ("Number dialling");    
                         callSomeone(); // ______call someone
                         delay (200);  
                         //badCall();
                         pcMon.println("End of actual call and hung up");  }                        
              } 
        kpdValueloop ();   }  



void callTimer(){   // set with timeCounter at start
      do  {
      onCallcounter = (onCallcounter + 1);   delay (150);
      kpdVal = analogRead (keypad); 
      if ((735 < kpdVal) && (kpdVal < 775)){      //Force call to end - * key has been pressed
            onCallcounter = (timeCounter + 1);      //******************SET_CALL_TIME        
            pcMon.println("* Forced End");}  
      callTriggervalue = digitalRead (onCalltrigger); 
      if (callTriggervalue == 1) {  
            pcMon.print (" callTriggervalue ");
            pcMon.println (callTriggervalue);
            digitalWrite (driveGate, HIGH); //gateTrigger
            digitalWrite (buzz, HIGH);
            delay (800);
            digitalWrite (driveGate, LOW);
            digitalWrite (buzz, LOW);
            callTriggervalue = 0;
            }
      String gsm_input="";                        // reading GSM messages to find "No carrier"
      gsm_input += (char)SIM900.read();
      delay(3); 
      gsm_input.trim();
      pcMon.print (gsm_input);
      if      ((gsm_input == "N")|| (gsm_input == "B")) (noCarrier++);      //Finding "No carrier" or "Busy" message
      else if (((noCarrier == 1)&&(gsm_input == "O")) || ((noCarrier == 1)&&(gsm_input == "U"))) (noCarrier++);
      else if (((noCarrier == 2)&&(gsm_input == "C")) || ((noCarrier == 2)&&(gsm_input == "S"))) (noCarrier++);
      else if (((noCarrier == 3)&&(gsm_input == "A")) || ((noCarrier == 3)&&(gsm_input == "Y")))
          {
            noCarrier = 0;
            SIM900.println("ATH");   // hang up
            pcMon.print("No Carrier / Busy - Hung Up");
            onCallcounter = (timeCounter + 1);
          }
      } 
      while (onCallcounter <= timeCounter); 
      onCallcounter = 0;
      badCall (); }



void callSomeone() {
  pcMon.println("Calling someone (callSomeone loop)");
  pcMon.println(dialNumber);
  SIM900.print("ATD");             // dial
  SIM900.print(dialNumber);
  SIM900.println(";");
  pcMon.println("GSM900 on call");
  callTimer();//____________for loop timer, * key, and inCalltrigger
  delay(200);            // wait for short while...
  SIM900.println("ATH");   // hang up
  pcMon.println("GSM900 Hung up");  }

void callTimeloop ()  {
        kpdAdd = ((numx * 100) + (numy * 10) + numz);
        if  ((userTimer > userTimeout) && (kpdAdd > 1))
        { userTimer = 0;
        badCall (); } 
        //pcMon.print (kpdAdd);
        if (kpdAdd != 0)
        { userTimer = (userTimer + 1);
        //pcMon.print (userTimer);
        }  }



void badCall () {  
    digitalWrite (buzz, HIGH); 
    pcMon.println("Badcall");           //serial usb
    digitalWrite (ledError, HIGH);
    delay (400);
    digitalWrite (ledError, LOW);
    digitalWrite (buzz, LOW);
    SIM900.println("ATH");   // hang up
    numx = 0; numy = 0; numz = 0; kpd = 0;     }


void kpdValueloop () {
  digitalWrite (readyCalling, LOW);  delay (50);
  if ((775 < kpdVal) && (kpdVal < 818))
  kpd = 0;
  if ((735 < kpdVal) && (kpdVal < 775)) //Star key pressed
      {  
      badCall();//  (Star key pressed)                     
      pcMon.print("* Pressed (Badcall)");        
      }  
  if ((699 < kpdVal) && (kpdVal < 735))
  kpd = 9;
  if ((669 < kpdVal) && (kpdVal < 699))
  kpd = 8;
  if ((636 < kpdVal) && (kpdVal < 669))
  kpd = 7;
  if ((609 < kpdVal) && (kpdVal < 636))
  kpd = 6;
  if ((585 < kpdVal) && (kpdVal < 609))
  kpd = 5;
  if ((561 < kpdVal) && (kpdVal < 585))
  kpd = 4;
  if ((540 < kpdVal) && (kpdVal < 561))
  kpd = 3;
  if ((521 < kpdVal) && (kpdVal < 540))
  kpd = 2;
  if ((480 < kpdVal) && (kpdVal < 521))
  kpd = 1;
  digitalWrite (buzz, LOW);
  digitalWrite (readyCalling, HIGH); 
  numx = byte(numy);
  numy = byte(numz);
  numz = byte(kpd);
  pcMon.print(numx);                   
  pcMon.print(numy);                   
  pcMon.println(numz);        
  kpdVal = analogRead (keypad);
  userTimer = 0;
  if (kpdVal >= 10)
          {    
            kpdVal = analogRead (keypad);
                do
                      {    
                        delay (200);     
                        kpdVal = analogRead (keypad);
                      }
                while (kpdVal >= 10);
          }
  else (kpdVal = 0);
  digitalWrite (readyCalling, HIGH);     }

void kpdNumberloop () {
          //Keypad code will assign one of the following number to dial
          //South Africa has +27 dialing code. Numbers are actually 0825626856 if dialled within the country on a normal phone
         if      (kpdAdd ==   1) dialNumber = "+27825626856" ;
         else if (kpdAdd ==   2) dialNumber = "+27836488874" ;
         else if (kpdAdd ==   3) dialNumber = "+27836488874" ;
         else if (kpdAdd ==   4) dialNumber = "+27825588558" ;
         else if (kpdAdd ==   5) dialNumber = "+27315612009" ;
         else if (kpdAdd ==  55) dialNumber = "+27788251770" ;
         else if (kpdAdd == 555) dialNumber = "+27834143115" ;
         else if (kpdAdd ==  14) dialNumber = "+27825580777" ;
         else if (kpdAdd == 101) dialNumber = "+27724069399" ;
         else if (kpdAdd == 103) dialNumber = "+27731293378" ;
         else if (kpdAdd == 104) dialNumber = "+27824427459" ;
         else if (kpdAdd == 105) dialNumber = "+27735453481" ;
         else if (kpdAdd ==  99) dialNumber = "+27812705553" ; // Pierre
         else if (kpdAdd == 100) dialNumber = "+27720500415" ; // Cindy
         else if (kpdAdd == 200) dialNumber = "+27794380279" ; // Siya
         else if (kpdAdd == 300) dialNumber = "+27315647561" ; // Office
         else (kpdAdd = 0);  }

 
void inComingloop ()  {
      // To respond to number (If it is below) and trigger the gate, else ignore
      String gsm_input="";
      while(SIM900.available()) // read the data into a variable as long as the buffer is not empty
      {    gsm_input += (char)SIM900.read();
           delay(5);    }  // Playaround with this timing if you have missing serial data / garbled Serial data coming from the GSM modem
      gsm_input.trim(); // Trim all the leading / trailing white spaces from the input
    
      if(find_string(gsm_input,"+CLIP") ) // Check if "+CLIP" is there, If it contains, it means there is an incoming call
      {     pcMon.println("Incoming Call - Waiting - New command");
            // Check if the Input received from the GSM modem contains the Authenticated Number
                  if      (find_string(gsm_input, "+27812705553" )) authenticCall (); //99 Pierre  -------  ODENVILLEA NUMBERS
                  else if (find_string(gsm_input, "+27720500415" )) authenticCall (); //100 Cindy
                  else if (find_string(gsm_input, "+27794380279" )) authenticCall (); //200 Siya
                  //else if (find_string(gsm_input, "+27315647561" )) authenticCall (); //300 Office  
                  else if (find_string(gsm_input, "+27825626856" )) authenticCall (); //1
                  else if (find_string(gsm_input, "+27836488874" )) authenticCall (); //3
                  else if (find_string(gsm_input, "+27825588558" )) authenticCall (); //4
                  else if (find_string(gsm_input, "+27315612009" )) authenticCall (); //5
                  else if (find_string(gsm_input, "+27788251770" )) authenticCall (); //5
                  else if (find_string(gsm_input, "+27834143115" )) authenticCall (); //5
                  else if (find_string(gsm_input, "+27825580777" )) authenticCall (); //14
                  else if (find_string(gsm_input, "+27724069399" )) authenticCall (); //101
                  else if (find_string(gsm_input, "+27731293378" )) authenticCall (); //103
                  else if (find_string(gsm_input, "+27824427459" )) authenticCall (); //104
                  else if (find_string(gsm_input, "+27735453481" )) authenticCall (); //105 
            else  nonAuthentic ();
        SIM900.println("ATH"); // Hang up on the incoming Call once We know its a authenticated call  
      }             }

void authenticCall ()  {     
       pcMon.println("Authenticated Call");
       delay (80);
       digitalWrite (readyCalling, LOW);
       digitalWrite (driveGate, HIGH); //gateTrigger
       delay (800);
       digitalWrite (readyCalling, HIGH);
       digitalWrite (driveGate, LOW);   } 

void nonAuthentic ()  {
       pcMon.println("Not Authenticated Call");
       digitalWrite (ledError, HIGH); //Error
       delay (800);
       digitalWrite (ledError, LOW);    }

// A Function to locate a given search string in a given base string
boolean find_string(String base, String search)
{  int len = search.length(); // find the length of the base string
for(int m = 0; m<(base.length()-len);m++)// Iterate from the beginning of the base string till the end minus length of the substring
{  if(base.substring(m,(m+len))==search) // Check if the extracted Substring Matches the Search String
{  return true;   }  }   // if it matches exit the function with a true value 
return false;  } // if the above loop did not find any matches, control would come here and return a false value 
    

Schematics

Arduino Nano wiring diagram
Basic wiring from Arduino
Arduino nano wiring diagram rdm7kfqyst
Audio feedback blocker
When talking, the GSM module would echo back the speech, so this part would "Block" the microphone when speaker had audio running.
Cd4016 feedback blocker gza2ra7ous
Front panel LED's
LED's light up.
Green = Ready (Enter number)
Blue = Wait / On call
Red = Cancel / End call
Front panel leds 2ixotcp9yg
Intercom and accessories photo
A photo of the front "Door station" unit and the separate control unit (Arduino / Amplifier / Gate relay / DTMF tone decoder)
Intercom and all accessories 8t51m0prvo
Keypad diagram
Using resistors to read front panel keypad. The resistor arrays will cause a specific voltage to an analog pin of the Arduino, which will decipher into a specific digit.
Keypad diagram sosaolenj5
Power supply for SIM800
An LM317 is used to create a specific 3.4 volts for the GSM. The GSM would blow if set to over 3.8 volts.
Lm317 gsm power supply 3koptrxvar
Product front panel
Just a picture of the installed product.
Micah intercom front sx7ewmphwn
DTMF tone decoder
This tone decoder detects the tenant pressing a "1" on their phone during a call, and would the trigger the relay, which is connected to the gate, and triggers the gate (Open contact output).
Stc8870 dtmf tone decoder qbmocwo5um
Audio Amplifier
Anything can be used here, but all this does is take audio signal from the output of the GSM module, and amplify it into the speaker.
Tda2003 audio amplifier hzzv77buzf
Serial data voltage converter
Converts 5 volts and 3 volts for RX and TX communication between Nano and the GSM module
Tx and rx nano to gsm800 cifzpidtww

Comments

Add projectSign up / Login