Mini allarme con chiamate GSM

Software EgoAlarmA volte è utile avere un modulo che effettua chiamate sul cellulare nel caso si verifichi un qualche evento, come ad esempio un allarme.

In questo articolo viene presentata la logica di controllo ed il sistema di segnalazione tramite chiamate GSM e messaggi SMS.

Alla fine di questa guida avrai un dispositivo che farà chiamate e invierà SMS ai numeri che imposterai, al verificarsi di un evento come ad esempio la chiusura di un contatto.

Il sistema è composto da Arduino Uno, comandabile via seriale USB, ed il modem GSM Keyestudio KS0254 basato su SIM800C.

Di seguito i link per comprarli:

Modem GSM

Modulo per chiamate e sms su rete cellulare

Arduino UNO

Arduino della stessa ditta del modulo GSM. Il modulo sopra si monta “on top”.

Comprare una SIM per allarme (o provare con quella del proprio telefono).

Istruzioni passo passo

Se vuoi puoi aiutare questo sito comprando l’ultima versione del software:

Software EgoGSM per miniallarme

Oppure puoi comprare il tutto già montato:

EgoGsmAlarm: allarme GSM

Come prima cosa compra i due moduli sopra indicati. Se li compri passando dai link proposti, aiuti questo sito.

Comprare anche una SIM con il traffico adatto. Prima di inserirla del modulo, inseriscila in un cellulare e togli il pin.

Dopo scarica il software per programmare Arduino:

https://www.arduino.cc/en/Main/Software

Installa il software.

Scarica le librerie specifiche da questa pagina:

https://www.domoticachepassione.it/wp/download/richiesta-software-allarme-gsm/

Una volta ottenuto il file egogsmlib.zip, scompattalo.

Le quattro cartelle

SIM800H

EgoMiniTimer

EgoSignalManager

EgoStringUtil

vanno spostate nella cartella delle librerie di Arduino.
In Windows la cartella è dentro

Documenti

nella cartella

Arduino.

A questo punto lanciare il software Arduino.

Nella pagina che appare copiare ed incollare il seguente sorgente:

/*  * * * * * * * * * * * * * * * * * * * * * * * * * * *
 Code by Ennio Balocchi 
 https://www.domoticachepassione.it
 */
 


#include <SoftwareSerial.h>

#include "Timer.h"

//ci vuole altrimenti non lo trova compilando in arduino
#include "EgoStringUtil.h"
#include "EgoSignalManager.h"
//Per vedere come gestire la memoria
//https://www.arduino.cc/en/Tutorial/Memory
//https://www.arduino.cc/en/Reference/PROGMEM

#include <avr/pgmspace.h>
Timer EgoSignalManager::timer;

typedef void (*SimpleFunction) ();
const char* const EgoSignalManager::inputDescr0[] ={"Sens tranquillo"};
const char* const EgoSignalManager::inputDescr1[] ={"Sens attivo"};
int* EgoSignalManager::simulateTimerId;


const char* const EgoSignalManager::outputDescr0[]={  "o1 L", "o2 L"};
const char* const EgoSignalManager::outputDescr1[]={ "o1 H", "o4 H"};

//byte EgoSignalManager::statusN=1;
//const char* const EgoSignalManager::statusDescr0[]={"Per spento","Int spento"};
//const char* const EgoSignalManager::statusDescr1[]={"Per acceso","Int acceso"};
const char* const EgoSignalManager::statusDescr0[]={"Per spento"};
const char* const EgoSignalManager::statusDescr1[]={"Per acceso"};


char seq=0;
//numero di cicli di chiamate
#define CALLATTEMPT 2
char tentativi=0;

byte EgoSignalManager::inputSnapShot;
byte EgoSignalManager::outputSnapShot;
int  EgoSignalManager::statusSnapShot;


String EgoSignalManager::inputString;

//se un pin va a 1
//imposta il contatore di impulsi al valore N ed il contatore di secondi a N
//ogni volta che da 0 va a 1 decrementa il contatore di impulsi
//ogni volta che passa un secondo decrementa il contatore di secondi
//se il contatore di secondi va a 0 e il contatore di impulsi supera il conteggio allora invia allarme
byte EgoSignalManager::inputPulseN[]=      {1,1};
byte EgoSignalManager::inputPulseCounter[]={0,0};
long EgoSignalManager::inputTimerN[]=      {1000,1000};
long EgoSignalManager::inputTimer[]=       {0,0};

byte EgoSignalManager::simulateInputs=0; //setta a 1 i bit degli input da forzare
byte EgoSignalManager::simulateValues=0; //valore per i bit da simulare;
const byte zone=1;
//byte zona[]={B01110000,B10001010};
byte zona[]={B00000001};
void doCheckTriggerSeAllarmeAcceso(byte pin){
#ifdef DEBUG
  Serial.println("Check trigger se allarme acceso "+String(pin));
#endif
  for(byte z=0;z<zone;z++){//per ogni zona
    if(bitRead(EgoSignalManager::statusSnapShot,z)==HIGH){//se zona accesa
      #ifdef DEBUG
       Serial.println("Zona accesa "+String(z));
       Serial.println(bitRead(zona[z],pin),BIN);
       Serial.println(zona[z],BIN);
      #endif
      if(bitRead(zona[z],pin)){ //se il pin fa parte della zona
        Serial.println("pin "+String(pin)+" attivo e allarme acceso, controllo timer"); 
        EgoSignalManager::doCheckTrigger1(pin); //fa partire i timer per controllare se non è un disturbo ma è allarme vero. Se allarme vero viene richiamato doTrigger
      }
    }
  }
         
}

void doPreAllarme(byte pin){
  
         
}


///////////////////////////////


////////////////////////////7


DoActionFunction EgoSignalManager::doAction0[]={
 EgoSignalManager::doPrintIn0,doActivateAlarm
 };
DoActionFunction EgoSignalManager::doAction1[]={
  doAllarme,doDeactivateAlarm
  };

void doCheckAllarme(byte pin){
  //if(bitRead(EgoSignalManager::statusSnapShot,ALLARME_ACCESO)==HIGH){
    //segnala 
  //}
         
}
void doCheckPreAllarme(byte pin){
  //if(bitRead(EgoSignalManager::statusSnapShot,ALLARME_ACCESO)==HIGH){
    //segnala 
  //}
         
}
DoActionFunction EgoSignalManager::doTrigger[]={
  doAllarme
  };
DoActionFunction EgoSignalManager::doShortTrigger[]={
  doPreAllarme
 
  };

//SoftwareSerial gsmSerial(7, 8); // RX, TX

#include <sim800cmd.h>

unsigned char gsmcmd=0;
char* number[]={"+39329800",NULL,NULL,NULL,NULL};

unsigned char numbers=1;

#define MAXNUMBERS 5
#define NUMBERS 1

//application callback function
void fundebug(void)
{
}
//initialize the library instance
//fundebug is an application callback function,when someon is calling.
Sim800Cmd sim800demo(fundebug);
void sendSMS(String msg){
  for(char i=0;i<numbers;i++){
    //char p1[number[i].length()+1];
    //number[i].toCharArray(p1,number[i].length()+1);
    char p2[msg.length()+1];
    
    msg.toCharArray(p2,msg.length()+1);
    p2[msg.length()]='\0';
    
    //sim800demo.sendSMSDirectly(number[i],p2);
    //sim800demo.sendSimpleSMS(p1,p2);
    char* n=sim800demo.asciiToUCS2(number[i]);
    char* m=sim800demo.asciiToUCS2(p2);
    sim800demo.sendSMS(n,m);
    free(n);
    free(m);
    sim800demo.atsendcmd("AT",200,200);
    
    
  }
}

void doActivateAlarm(byte pin){
  EgoSignalManager::statusHigh(0);
}
void doDeactivateAlarm(byte pin){
  EgoSignalManager::statusLow(0);
}
void doAllarme(byte pin){
  
  if(bitRead(EgoSignalManager::statusSnapShot,0)==LOW){//se zona non accesa
    return;
  }
  Serial.print(F("Allarme: "));
  Serial.println(EgoSignalManager::inputDescr1[pin]);
  EgoSignalManager::outputHigh(1);
  String s=F("allarme");
  Serial.println(s);
  sendSMS(s);
  //EgoSignalManager::timer.after(10*1000,EgoSignalManager::outputHigh(0),pin);
  EgoSignalManager::timer.after(60000,EgoSignalManager::outputLow,1);
  gsmcmd=1;
}

void commandPlugin(String inputS){
  
  //Serial.println("sono qui");
  //Serial.print(inputS);
  //Serial.println("<-");
  //Serial.print("invece inputstring ");
  //Serial.println(inputS);
  if (inputS.startsWith("call")) {
    
    gsmcmd=1;
    
  }
  if (inputS.startsWith("add:")) {
    String s=EgoStringUtil::tail(inputS,':');
    s.trim();
    addNumber(s);
    
  }
  if (inputS.startsWith("clear")) {
    
    for(char i=0;i<numbers;i++){
      free(number[i]);
    }
    numbers=0;
    
  }
  if (inputS.startsWith("list")) {
    listNumbers();
    
  }
  if (inputS.startsWith("send:")) {
     String s=EgoStringUtil::tail(inputS,':');
     sendSMS(s);
//     Serial.print("s=");
//     Serial.println(s);
//     for(char i=0;i<numbers;i++){
//      //char p1[number[i].length()+1];
//      //number[i].toCharArray(p1,number[i].length()+1);
//      char p2[s.length()+1];
//      
//      s.toCharArray(p2,s.length()+1);
//      p2[s.length()-1]='\0';
//      //Serial.print("p2=");
//      //Serial.println(p2);
//      
//      sim800demo.sendSMSDirectly(number[i],p2);
//     }
     
  }
  if (inputS.startsWith("stop")) {
    tentativi=0;
    seq=0;
    gsmcmd=0;
  }
  if (inputS.startsWith("reset")) {
    digitalWrite(9,HIGH);
    delay(2000);
    digitalWrite(9,HIGH);
    resetSw();
  }
  if (inputS.startsWith("cmd:")) {
    String s=EgoStringUtil::tail(inputS,':');
    _Serial.println(s);
  }
  
}

Plugin EgoSignalManager::cmdPlugin=commandPlugin;

void smsFunc(){
  Serial.println("Ricevuto");
  
}
void resetHw(){
    Serial.println(F("reset hw"));
    pinMode(9,OUTPUT);
    digitalWrite(9,HIGH);//
    delay(2000);
    digitalWrite(9,LOW);//
}
void resetSw(){
    Serial.println("iniziamo...");
    //initialize the digital pin as an output.
    pinMode(13,OUTPUT);
    resetHw();
    //delay(3000);
    //digitalWrite(12,HIGH);//
    //initialize SIM800H,return 1 when initialize success.
    byte i=0;//tentativi
    while((sim800demo.sim800init()) == 0){
      Serial.print(F("attempt "));
      Serial.println(i);
      delay(10);
      if(i>=3){//tentativi
        resetHw();
        i=0;
      }
      i++;
    };
    Serial.println("inizializzazione completata.");
//    EgoSignalManager::setCmdPlugin(commandPlugin);
    sim800demo.setSMSEnablePrompt(OPEN);
    sim800demo.setSMSHandlefunction(smsFunc);
}


//the setup routine runs once when you press reset:
void setup()
{
  EgoSignalManager::init();
  //start serial connection
  Serial.begin(19200);
  //configure pin2 as an input and enable the internal pull-up resistor
    EgoSignalManager::setupIn();
    EgoSignalManager::setupOutLow();
    resetSw();
}


void call(byte n){
  unsigned char csq = 0;
  //To obtain the signal strength, return 1 when obtain success.
  sim800demo.cancelCall();
  if( sim800demo.callReadCSQ(&csq) )
   {
      Serial.print(F("chiamo "));
      Serial.println(number[n]);
       //Make Voice Call
       char *_str;
        _str = (char *)malloc(strlen(number[n])+2);
       strcpy(_str,number[n]);
       strcat(_str,";");
       sim800demo.dialTelephoneNumber(_str);
       free(_str);
       delay(20000);
       sim800demo.cancelCall();
       
   }
}

//the loop routine runs over and over again forever:
void loop()
{
   EgoSignalManager::loop();

  //Signal strength
 
  if(gsmcmd==1){//chiama
   
    call(seq);
    seq++;
    if(seq>=numbers){
      seq=0;
      tentativi++;
      if(tentativi>=CALLATTEMPT){
        tentativi=0;
        gsmcmd=0;
      }
      
      
    }
    
  }

  
// digitalWrite(13,HIGH);//turn the LED on by making the voltage HIGH
// delay(500);
// digitalWrite(13,LOW);//turn the LED off by making the voltage LOW
// delay(500);
}
//void addNumber(String num){
//  if(numbers>=MAXNUMBERS){
//    Serial.println("too many numbers.");
//    return;
//  }
//  char m=min((num.length()),(strlen(number[numbers])+1));
//  for(char i=0;i<m;i++){
//    number[numbers][i]=num[i];
//  }
//  number[numbers][m]='\0';
//  numbers++;
//}
void addNumber(String num){
  if(numbers>=MAXNUMBERS){
    Serial.println("too many numbers.");
    return;
  }
  char l=num.length()+1;
  char* str = (char *)malloc(l);
  num.toCharArray(str,l);
  number[numbers]=str;
  numbers++;
}

void listNumbers(){
  
  for(char i=0;i<numbers;i++){
    Serial.println(number[i]);
  }
  
}

void serialEvent() {
  EgoSignalManager::readSerialCommand();
}

Salvare il file scegliendo File|Salva con nome…
e dandogli il nome egogsm.

Inserire il numero di telefono

All’interno del file sorgente che è stato copiato, cercare la frase:

SCRIVI I TUOI NUMERI DA CHIAMARE QUI

ed inserire nella lista i propri numeri di telefono.

A questi numeri sarà inviato un SMS e vengono chiamati uno dopo l’altro.

Salvare il file scegliendo File|Salva.

Compilazione del sorgente (sketch)

Dare il comando Sketch|Verifica/compila
Controllare che la compilazione vada a buon fine con una frase del tipo:

Lo sketch usa 16240 byte (50%) dello spazio disponibile per i programmi. Il massimo è 32256 byte.

Assemblaggio Arduino e modulo GSM

Montare il modulo GSM sulla scheda di Arduino UNO, come da foto, allineando i pin.

Posizionare i due jumper in modo che sia selezionato D7 e D8 come Rx e Tx della porta seriale.

Impostare l’alimentazione del circuito su Arduino.

Inserire il cavo USB in Arduino UNO ed nel PC.

Caricare lo sketch su Arduino UNO

Andare su Strumenti|Scheda e scegliere Arduino/Genuino UNO.

Cliccare su Strumenti|Porta e selezionare la porta USB (COM o tty) su cui è collegato Arduino UNO. Se non si riesce a capire, provare a scollegare Arduino UNO e vedere nella lista delle porte quale sparisce. Ricollegare e controllare quale porta appare che prima non era nella lista.

Controllare che su Strumenti|Programmatore sia selezionato AVRISP mkII.

Cliccare su Sketch|Carica.

Aspettare che appaia in fondo alla pagina “Caricamento completato”.

Test di funzionamento

Scegliere Strumenti|Monitor seriale.

Selezionare la velocità in basso 19200 baud.

Scegliere A capo (NL).

Accendere il modulo GSM. Premere per qualche secondo il pulsantino di lato. Si devono accendere due led rossi.

Devono cominciare ad apparire dei messaggi del tipo:

iniziamo...>AT
>AT

e una volta acceso il modulo GSM

<<OK

<<

<<RDY

<<

<<+CFUN: 1

Dopo un po’ appare:

inizializzazione completata.

Per provarlo, chiudere il contatto D5 (pin n.6) collegandolo a GND, per entrare in modalità allarme.

D5 e D6
Pin per attivare e segnalare l’allarme

Poi chiudere il contatto D6 (pin n.7) collegandolo a GND e poi aprire il contatto, per provare se invia l’allarme.

Pin GND
Pin GND

Prima viene mandato un SMS ad ogni numero della lista, e poi viene chiamato ogni numero della lista per 1 minuto.

__________________________________

iniziamo...
>AT
<

<<OK

<<
>AT
<

<<OK

<<
>ATE0
<

<<OK

<<
>AT+CNMI=2,1,0,1,0
<

<<OK

<<
>AT+CMGF=1
<

<<OK

<<
>AT+CSCS="UCS2"
<

<<OK

<<
>AT+CSMP=17,167,2,25
<

<<OK

<<
>AT+CSQ
<

<<+CSQ: 26,0

<<

<<OK

<<
inizializzazione completata.
Diversi
10
11
status: Sens tranquillo. In0 L 1
Diversi
11
10
Diversi
1
11
status: Per acceso
Diversi
11
1
status: Per spento
Diversi
1
11
status: Per acceso
Diversi
11
1
status: Per spento
Diversi
1
11
status: Per acceso
Diversi
0
1
status: Sens tranquillo. In0 L 1
Diversi
1
0
Allarme: Sens attivo
status: o4 H
allarme
>AT+CMGS="002B0033003900"
<

<<>
>0061006C006C00610072006D0065
>AT
>AT
>AT
>AT
>AT
>AT
>AT
>AT
>AT
>AT
>AT
>AT
>AT
>AT
<

<<+CMGS: 42

<<

<<OK

<<

<<OK

<<
>AT
<

<<OK

<<
>ATH0
<

<<OK

<<
chiamo +39329800****
>ATD+39329800***;
<

<<OK

<<
>ATH0
>ATH0
chiamo +39329800****
>ATD+39329800****;
<⸮T⸮

<<OK

<<
>AT+CSQ
<

<<+CSQ: 26,0

<<

<<OK

<<

5 comments

  1. Progetto interessante. Si può aggiungere una sirena che suoni per un tempo prestabilito dopo il rilevamento di intrusioni? Se si come posso fare per il software e per l’hardware?

    1. Il progetto ha in sè tutte le potenzialità che richiede. Il sorgente, ma anche il modo in cui è strutturato, permette personalizzazioni. Se riesco a trovare il tempo questi giorni magari ci faccio un articolo.
      Giusto per darle qualche idea, il progetto funziona come una macchina a stati, nel senso che esiste una tabella di transizione che al verificarsi di certe condizioni richiama delle funzioni che possono essere definite con un minimo di personalizzazione.
      Buona giornata.

    1. A che scopo ritardare l’accensione?
      Se intendi una volta acceso, far aspettare altro tempo, prima di iniziare i controlli, si può metere un delay(xxx) prima di resetSw.
      A che scopo ritardare le chiamate? Intendi far partire le chiamate se lo stato di allarme perdura per un certo numero di millisecondi?

Leave a Reply

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *