Un temporizzatore con il chip RTC DS1307: il codice

Eccomi di nuovo con il temporizzatore.

Come ho spiegato nel post precedente voglio accendere e/o spegnere un utilizzatore a 220 V utilizzando dei relè.

Ad oggi non ho mai avuto esperienza nell’utilizzo dei relè, quindi lo schema comprenderà l’accensione/spegnimento di un led.

Ecco lo schema visto precedentemente con l’aggiunta del led collegato al PIN 13 digitale di Arduino:

persito

 

Ed ecco il codice:

 

#include <Wire.h>
#include <String.h>
#include "RTClib.h"

#define BUFFER_SIZE 20
#define STATE_OFF  0
#define STATE_ON   1

//Giornate di programmazione
const int numeroProgrammazioni = 4;
String lunedi[numeroProgrammazioni] = {
  "21:35", "20:30","20:35","20:40"};
String martedi[numeroProgrammazioni] = {
  "11:00", "11:35","13:10","13:50"};
String mercoledi[numeroProgrammazioni] = {
  "20:55", "19:58","20:00","20:05"};
String giovedi[numeroProgrammazioni] = {
  "10:00", "10:35","17:10","20:00"};
String venerdi[numeroProgrammazioni] = {
  "10:00", "10:35","14:10","15:00"};
String sabato[numeroProgrammazioni] = {
  "18:15", "18:20","18:22","18:25"};
String domenica[numeroProgrammazioni] = {
  "10:00", "10:35","12:10","15:00"};
//Fine giornate di programmazione

RTC_DS1307 rtc;
int fsm_state;
String START_TIME;
String END_TIME;
int nSize = numeroProgrammazioni / 2;
String giornoTemp[numeroProgrammazioni];

void setup () {
  //Serial.println("Inizio Setup");
  fsm_state = STATE_OFF;
  Serial.begin(57600);
#ifdef AVR
  Wire.begin();
#else
  Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
#endif
  rtc.begin();

  if (! rtc.isrunning()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  pinMode(13,OUTPUT);        //Collegamento al LED
}

void loop () {
    // Ricavo il time attuale
    DateTime now = rtc.now();  

    int giorno = now.dayOfWeek();      //0 = lunedi 1 = martedi 2 = mercoledi ....
    //Serial.println( giorno);
    if (giorno == 1){                  //lunedi
      memcpy(giornoTemp,lunedi, sizeof(lunedi));
    }
    else if (giorno == 2){            //martedi
      memcpy(giornoTemp,martedi, sizeof(martedi));
    }
    else if (giorno == 3){            //mercoledi
      memcpy(giornoTemp,mercoledi, sizeof(mercoledi));
    }
    else if (giorno == 4){            //giovedi
      memcpy(giornoTemp,giovedi, sizeof(giovedi));
    }
    else if (giorno == 5){            //venerdi
      memcpy(giornoTemp,venerdi, sizeof(venerdi));
    }
    else if (giorno == 6){            //sabato
      memcpy(giornoTemp,sabato, sizeof(sabato));
    }
    else if (giorno == 7){            //domenica
      memcpy(giornoTemp,domenica, sizeof(domenica));
    }

    //verifico lo stato che dovrà assumere
    int isON = 0;
    for (int i= 0; i< nSize;i++){
      START_TIME = giornoTemp[i*2];
      END_TIME = giornoTemp[(i*2)+1];
      isON = setStatus(now,START_TIME,END_TIME);
      gestisciCarico(isON);
    } //end for

  delay(3000);
}

int setStatus(DateTime timeOra, String START_TIME, String END_TIME)
{
  //recupero l'ora
  DateTime dSTART_TIME = DateTime(timeOra.year(),timeOra.month(),timeOra.day(),START_TIME.substring(0, 2).toInt(),START_TIME.substring(3, 5).toInt(),0);
  DateTime dEND_TIME = DateTime(timeOra.year(),timeOra.month(),timeOra.day(),END_TIME.substring(0, 2).toInt(),END_TIME.substring(3, 5).toInt(),0);
  long lSTART_TIME = dSTART_TIME.unixtime();
  long lEND_TIME = dEND_TIME.unixtime(); 

  switch(fsm_state) {
  case STATE_OFF:
    if(timeOra.unixtime() > lSTART_TIME && timeOra.unixtime() < lEND_TIME) {
      fsm_state = STATE_ON;
      //Serial.println("caso 1");
    }
    break;
  case STATE_ON:
    if(timeOra.unixtime() > lEND_TIME) {
      fsm_state = STATE_OFF;
      //Serial.println("caso 2");
    }
    break;
  }

  return fsm_state;
}

void gestisciCarico(int isON)
{
  if (isON == 1){
    digitalWrite(13,HIGH);
  }
  else
  {
    digitalWrite(13,LOW);
  }
}

Spiegazione del codice:

dalla riga 12 alla riga 25: settaggio delle ore del giorno in cui accendere il led in questo caso
riga 47: viene settato RTC con l’ora e la data di compilazione del codice
riga 50: imposto il collegamento al led su pin 13
Nel loop:
riga 55: ricavo giorno e ora corrente
riga 57: ricavo il giorno corrente (0 = lunedi, 1 = martedi….), questo mi serve per capire in quale stringa di array andare a verificare se accendere il led,se l’array lunedi, martedi e cosi via
riga 86: utilizzo la funzione setStatus per verificare se accendere o meno il led
riga 84: funzione setStatus: per confrontare le date utilizzo la funzione unixtime() che converte la data in formato unix, quindi come long. Il confronto quindi si limita al confronto fra due long. La funzione restituisce un int 0/1 se necessario attivare o meno il led
riga 87: funzione gestisciCarico: la funzione prende in input il valore precedentemente restituito. A questo punto viene acceso o spendo il led.

 

A questo punto il nostro led si accenderà o spegnerà nelle ore da noi stabilite.

I passaggi successivi, che spiegherò prossimamente sono:

1. aggiunta di una funzione random (opzionale): se la funzione random è attiva, allora all’ora di accensione/spegnimento dei giorni settimanali vengono aggiunti dei minuti casuali.

2. modifica del circuito per ospitare il relè e quindi per accendere o spegnere una lampada

Il sensore ad ultrasuoni HC-SR04 – ARDUINO

Una delle idee iniziali che mi erano venute in mente in fase di realizzazione del mio antifurto era di utilizzare un sensore ad ultrasuoni per la rilevazione della distanza.

Poi sono ripiegato sul modulo PIR.

Ho deciso in ogni caso di rispolverarlo e di leggermi un po’ la documentazione e il datasheet.

La misurazione con questo componente è fatta misurando il tempo impiegato da un segnale sonoro a raggiungere un oggetto e ritornare al sensore.

La misura quindi non è in termini di distanza ma di tempo, in particolare in microsecondi.

Il sensore HC-SR04 dispone di 4 pin: Vcc (+5V), Trigger, Echo, GND.

FullSizeRender

In linea di massima il funzionamento è così:

  1. viene inviato un ping sonoro dal pin Trigger
  2. se viene intercettato un ostacolo l’onda viene riflessa e torna indietro.
  3. il pin Echo riceve il segnale ritornato

Il tempo impiegato ci permette di stabilire la distanza fra il sensore e l’ostacolo.

Come fare?

Per convertire l’unità di tempo in spazio è necessario sapere la velocità del suono nell’aria: ci aiuta wikipedia.

Nell’aria, la velocità del suono è di 331,45 m/s a 0 °C (pari a 1 193,04 km/h) e di 343,8 m/s (pari a 1 237,68 km/h) a 20 °C (e in generale varia secondo la relazione a = 331,45 + 0,62 t con t misurata in °C).

Quindi consideriamo circa 343 m/s, espresso in centrimetri: 0,0343 cm/microsecondi.

Dato che lo spazio = velocità * tempo (s= v*t) ne risulta che s = 0,0343 *t.

Bisogna però considerare che il tempo individuato dal pin Echo è quello di partenza dal pin Trigger, arrivo all’ostacolo e tornare indietro verso il sensore.

Quindi sarà necessario dividere il tempo: s = 0,0343 *t / 2.

La formula che utilizzeremo in definitiva sarà: s = 0,01715 * t

Passiamo ora ai collegamenti con Arduino:

 

Pin Arduino Pin Sensore
POWER 5V VCC
Digital 7 Trig
Digital 8 Echo
GND GND

 

SensoreDistanza2 SensoreDistanza1

DistanceSensor_bb

Passiamo quindi al codice:

 

int trigger_Port = 7;
int echo_Port = 8;

void setup() {
  pinMode( trigger_Port, OUTPUT );
  pinMode( echo_Port, INPUT );
  Serial.begin( 9600 );
  Serial.println( "Sensore distanza ad ultrasuoni: ");

}

void loop() {
  //setto uscita bassa su pin del trigger
  digitalWrite( trigger_Port, LOW );

  //invio impulso di 10 micro secondi  su pin del trigger
  digitalWrite( trigger_Port, HIGH );
  delayMicroseconds( 10 );
  //setto nuovamente uscita bassa su pin del trigger
  digitalWrite( trigger_Port, LOW );
  //leggo la durata sul pin Echo
  long durata = pulseIn( echo_Port, HIGH );
  //calcolo la durata
  long r = 0.034 * durata / 2;

  Serial.print( "durata: " );
  Serial.print( durata );
  Serial.print( " , " );
  Serial.print( "distanza: " );

  //dopo 38ms è fuori dalla portata del sensore
  if( durata > 38000 ) Serial.println( "fuori portata");
  else {
    Serial.print( r );
    Serial.println( "cm" );
  }

  //aspetta 1.0 secondi
  delay( 1000 );
}

E’ possibile anche utilizzare la libreria new_ping.

Una volta scaricata la libreria e copiato il contenuto nella cartella libraries di Arduino è possibile semplificare la scrittura del codice:

 

#include <NewPing.h>

#define trigger_Port 7
#define echo_Port 8
#define max_distance 200

NewPing sonar(trigger_Port, echo_Port, max_distance); 

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

void loop() {
 delay(50);
 unsigned int uS = sonar.ping_cm();
 Serial.print(uS);
 Serial.println("cm");
}

Con questa libreria è possibile inviare anche un ping multiplo e farsi ritornare la media delle letture effettuate, basta utilizzare:

nsigned int uS = sonar.ping_median(numero misurazioni);

#include <NewPing.h>

#define trigger_Port 7
#define echo_Port 8
#define max_distance 200

NewPing sonar(trigger_Port, echo_Port, max_distance); 

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

void loop() {
  delay(50);
  unsigned int durata = sonar.ping_median(5);
  long r = 0.034 * durata / 2;
  Serial.print(r);
  Serial.println("cm");
}

In questo caso ho impostato come numero di misurazioni 5. Quindi ci verrà riportata la media di 5 misurazioni.
Che dire…è decisamente una libreria tanto utile quanto facile da usare!

Un semplice antifurto: il codice completo

Finalmente posso postare il codice completo con le modifiche alla gestione della memoria!

 


#include <String.h>
#include <RCSwitch.h>
#include <Time.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EEPROM.h> 

/* Informazioni Ethernet*/

byte mac[] = {
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
int SERIAL_BAUD        = 9600;
int TRASMIT_PIN       = 9;
int RECEIVE_PIN       = 0;
int NOISE_DIGITAL_PIN =    5;
//Codice wireless webcam
long SEGNALE_ACCENZIONE_WEBCAM = 1394001;
long SEGNALE_SPEGNIMENTO_WEBCAM= 1394004;
int nSensori = 5;

EthernetClient client;
EthernetServer server(8081);
char smtpServer[] = "smtpcorp.com";
RCSwitch mySwitch = RCSwitch();

void setup() {
  Serial.begin(SERIAL_BAUD);
  pinMode(SERIAL_BAUD, INPUT);
  mySwitch.enableReceive(RECEIVE_PIN);  // Receiver on inerrupt 0 => that is pin #2
  mySwitch.enableTransmit(TRASMIT_PIN);  // Using Pin #10
  setupComm();
}

void loop() {
  getClientConnection();
  if (detectNoise()){
   Serial.print("Rumore");
   email("Attenzione, rilevato rumore in casa!");
   accendiCam(SEGNALE_ACCENZIONE_WEBCAM) ;
   }

  if (mySwitch.available()) {
    int value = mySwitch.getReceivedValue();
    //Serial.print(value);
    if (value == 0) {
      Serial.print("Unknown encoding");
      Serial.print("\n");
    }
    else {
      long receivedValue = mySwitch.getReceivedValue();
      int isPresente = isPresenteSensore(receivedValue);
      if (isPresente != -1)
      {
        //Trovato codice
        String messaggioRilevazione = "Attenzione! Sensore " +String(isPresente)+ " rilevato!";
        Serial.println(messaggioRilevazione);
        email(messaggioRilevazione);
        accendiCam(SEGNALE_ACCENZIONE_WEBCAM) ;
        delay(1000);
      }
    }
    //mySwitch.resetAvailable();
  }
}

bool detectNoise ()
{
  bool rit = false;
  if (digitalRead(NOISE_DIGITAL_PIN) == HIGH)
  {
    rit = true;
  }
  return rit;
} 

void accendiCam(long value)
{
  mySwitch.send(value, 24);
  mySwitch.send(value, 24);
  mySwitch.send(value, 24);
  mySwitch.send(value, 24);
  mySwitch.send(value, 24);
} 

void setupComm()
{
  Serial.println("Trying to connect");
  Serial.print("\n");
  if (!Ethernet.begin(mac)){
    Serial.println("Failed to DHCP");
    // no point in carrying on, so do nothing forevermore:
    while(true);
  }

  // print your local IP address:
  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println("fine");
}

// Call to send an email.
bool email(String text)
{
  bool success = false;
  Serial.println("Sending email...");
  Serial.print("\n");
  Serial.println("SMTP server...");
  Serial.print(smtpServer); 

  if (client.connect(smtpServer, 2525)){
    Serial.println("connected");
    delay(100);
    client.println("EHLO arduino");
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    }
    Serial.println("responded");
    Serial.print("\n"); 

    client.println("AUTH LOGIN");
    client.println("XXX");
    client.println("XXXXX");        

    // Put your "from" email address here
    client.println("MAIL FROM:<dumm@gmail.com>"); //Does not seem to matter what email stands here
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    } 

    // Put where you are sending it here
    client.println("RCPT TO:<giuseppe.scola@gmail.com>"); //Must be the reciever ID

    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    } 

    client.println("DATA");
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    }
    //This is the email that is listed in the sender
    client.println("from: giuseppe.scola@gmail.com");
    client.println("to: giuseppe.scola@gmail.com");
    client.println("SUBJECT: ArduAlarm");
    client.println("");
    client.println(text);
    client.println(".");
    client.println("QUIT");
    for(int i=0; i<999; ++i){
      if(i > 998){
        Serial.println("error: No response");
      }
      if(client.read() > 0)
        break;
    }
    success = true;
    client.println();
    Serial.println("end");
    Serial.print("\n");
  }
  else {
    Serial.println("Failed");
    Serial.print("\n");
    client.println("QUIT");
  }
  client.stop();
  return success;
}

void getClientConnection(){
  //Serial.println("nuova richiesta");
  EthernetClient client = server.available();
  if (client) {
    String postString ="";
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if(postString.length()<20){
          Serial.println(c);
          postString +=c;
        }

        if (c == '\n' && currentLineIsBlank) {
          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: text/html"));
          client.println(F("Connection: close"));  // the connection will be closed after completion of the response
          client.println();
          client.println(F("<!DOCTYPE HTML>"));
          client.println(F("<html>"));
          client.println(F("<h1>AllarDuino</h1>"));
          client.print(F("<br>"));
          client.println(F("<a href=\"./?on\">Accendi CAM</a>"));
          client.println(F("<a href=\"./?off\">Spegni CAM</a>"));
          client.print(F("<br>"));
          client.println(F("<h2>Configurazione</h2>"));
          client.print(F("<br>"));
          char linkCompleto[50];
          for (int i=0; i<nSensori; i++)
          {
            strcpy (linkCompleto, "<a href=\"./?save");            //copio la stringa in array char
            sprintf(linkCompleto, "%s%d", linkCompleto, i);        //concateno int a stringa
            strcat(linkCompleto, "\">Salva Sensore ");            //concateno due stringhe
            sprintf(linkCompleto, "%s%d", linkCompleto, i);
            strcat(linkCompleto, "</a><br/>");
            client.println(linkCompleto);
          }
          client.println(F("<a href=\"./?elenco\">dati sensori</a></html>"));
          break;
        }

        if (c == '\n') {
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }  //fine client.connected 

    //Gestione querystring

    if(postString.indexOf("?on") > 0){
      Serial.println("accendi CAM");
      accendiCam(SEGNALE_ACCENZIONE_WEBCAM);
      client.println("<br/>");
      client.println("<p>Cam accesa</p>");
    }
    if(postString.indexOf("?off") > 0){
      accendiCam(SEGNALE_SPEGNIMENTO_WEBCAM);
      client.println("<br/>");
      client.println("<p>Cam spenta</p>");
    }
    if(postString.indexOf("?save") > 0){
      int indexSave = postString.indexOf("?save");
      Serial.println("indexOf");
      Serial.println(indexSave);
      Serial.println("=====");
      //cerco valore del sensore
      String sSensore = postString.substring(indexSave+5 ,indexSave+6);
      Serial.println(sSensore);
      int iSensore = sSensore.toInt();
      long valore = salvaSensore(iSensore);
      client.println("<br/>");
      client.println("<p>Salvataggio sensore effettuato</p>");
      client.println("<br/>");
      client.println("Codice sensore " + sSensore);
      Serial.println("=====");
      client.print(valore);
    }

    if(postString.indexOf("?elenco") > 0){
      for (int i=0; i<nSensori; i++)
      {
        Serial.println("<p>Sensore " + String(i)+" : </p>");
        client.println("<p>Sensore " + String(i)+" : </p>");
        client.print(String(EEPROMReadlong(i*4)));
        Serial.println(EEPROMReadlong(i*4));
      }
    }
    delay(1);
    client.stop();
    Serial.println("client disonnected");
  }
}

long salvaSensore(int iSensore)
{
  int addressTosSave = iSensore*4;
  long valore = 0;
  Serial.println("salvaSensore");
  if (mySwitch.available()) {
    Serial.println("mySwitch.available");
    valore = mySwitch.getReceivedValue();
    Serial.println("valore ");
    Serial.println(valore);
    EEPROMWritelong(addressTosSave,valore);
  }
  delay(1000);
  Serial.println(valore);
  return valore;
} 

void EEPROMWritelong(int address, long value)
{
  byte four = (value & 0xFF);
  byte three = ((value >> 8) & 0xFF);
  byte two = ((value >> 16) & 0xFF);
  byte one = ((value >> 24) & 0xFF);

  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(address, four);
  EEPROM.write(address + 1, three);
  EEPROM.write(address + 2, two);
  EEPROM.write(address + 3, one);
}

long EEPROMReadlong(long address)
{
  //Read the 4 bytes from the eeprom memory.
  long four = EEPROM.read(address);
  long three = EEPROM.read(address + 1);
  long two = EEPROM.read(address + 2);
  long one = EEPROM.read(address + 3);

  //Return the recomposed long by using bitshift.
  return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

//Se trova sensore ritorna il numero del sensore
//Se non lo trova ritorna -1
int isPresenteSensore(long valoreRicevuto)
{

  for(int x = 0; x < nSensori; x ++){
    long valoreRegistrato = EEPROMReadlong(x*4);
    if (valoreRegistrato == valoreRicevuto)
    {
      Serial.println("ritorno");
      return i;
    }
  }

}

Per spiegare le modifiche:

riga 19: definisco quanti sensori voglio gestire, in questo caso 5
riga 51: chiamata ad una nuova funzione (isPresenteSensore). Questa funzione (riga 322) riceve in input il codice ricevuto dal sensore wireless e verifica se presente nella EEPROM. Se presente viene fatto scattare l’allarme, inviando la mail ed accendendo la telecamera.

Le ulteriori modifiche sono state effettuate proprio sulla gestione della memoria: ho eliminato molti Serial.print ed utilizzato la funzione F(), si veda ad esempio dalle righe 193 a 204.

Dal punto di vista del codice mi considero al punto finale: sono abbastanza soddisfatto ma spero di avere vostri spunti ed indicazioni per migliorare ed ottimizzare ulteriormente.

In settimana dovrei aver completato lo schema con Eagle…ci sentiamo prestissimo quindi!!

Giuseppe

Un semplice antifurto: gestiamo al meglio la memoria

Si è da tanto che non mi collego…ma ve lo giuro,  mettere insieme il codice e soprattutto studiarmi quel minimo Eagle per scrivere la libreria finale del progetto non è stato semplice.

Devo ringraziare il forum di Arduino per tutti i preziosi aiuti!

La parte più difficile è stata la gestione della memoria: sono abituato a programmare in Net ed avere a disposizione pochi Kb mi ha fatto sudare.
Ho deciso di leggere la documentazione per capire come sfruttarla un pochino meglio.

LA MEMORIA IN ARDUINO

Il micro controllore presente sulla scheda Arduino UNO, da me utilizzato, è  ATmega328P con le seguenti tipologie di memoria:

  • Flash (program space), è dove lo sketch di arduino  (programma)  viene memorizzato.
  • SRAM (static random access memory) è dove lo sketch  crea e gestisce le variabili quando è in esecuzione.
  • EEPROM (già la conosciamo) è un tipo di memoria non volatile, una memoria in grado di mantenere le informazioni anche quando non viene alimentata.

Per ogni micro controllore si ha a disposizione una diversa quantità di memoria:

ATMega168 ATMega328P ATmega1280 ATmega2560
Flash
(1 Kbyte used
for bootloader)
16 KBytes 32 KBytes 128 KBytes 256 KBytes
SRAM 1024 bytes 2048 bytes 8 KBytes 8 KBytes
EEPROM 512 bytes 1024 bytes 4 KBytes 4 KBytes

Per Arduino UNO quindi:

Flash 32k bytes
SRAM 2k bytes
EEPROM 1k byte

Le stringhe in particolare utilizzano in grosso quantitativo di memoria e nel mio sketch ne faccio grande uso per scrivere sul client web (client.println) e sulla console (Serial.print).

Ad esempio il comando : Serial.println(“Trying to connect”); occupa 18 bytes (1 char = 1 byte più il carattere di fine riga) della SRAM che ne ha a disposizione 2048. Sembra poco….ma ho utilizzato tantissime volte le stringhe nel mio sketch!
Dalla versione 1.0 l’IDE di Arduino permette l’utilizzo della funzione F() che permette di storare le stringhe nella memoria FLASH e non nella SRAM.
Ho quindi deciso di storare proprio nella memoria FLASH tutte le stringhe utilizzate nel costrutto client.println, risolvendo i miei problemi di memoria SRAM (gli int, float e le stringhe non raggruppate con F() naturalmente saranno inizializzare e gestite nella SRAM).

Consiglio comunque una bella lettura di questo  articolo .

Dai che arriva il weekend e finalmente (spero) avrò tempo di pubblicare le modifiche al codice e il file di progetto di Eagle.

Quindi BUON WEEKEND!

Un semplice antifurto: salvare i codici sensori tramite interfaccia web

Non ci posso credere! E’ quasi Natale!! Sono troppo contento…finalmente un po di relax!

Torniamo al nostro arduino…come detto la volta scorsa voglio fare in modo che i codici sensori possano essere memorizzati nelle EEPROM, il tutto da interfaccia web!
Ecco il codice che esegue questa cosa:

#include <String.h>
#include <Time.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EEPROM.h>
#include <RCSwitch.h>

byte mac[] = {
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
int SERIAL_BAUD        = 9600;
EthernetServer server(8081);
RCSwitch mySwitch = RCSwitch();
int RECEIVE_PIN       = 0;
int nSensori = 5;

void setup() {
  Serial.begin(SERIAL_BAUD);
  setupComm();
  mySwitch.enableReceive(RECEIVE_PIN);
}

void loop() {
  getClientConnection();
}

void getClientConnection(){

  EthernetClient client = server.available();
  if (client) {
    String postString ="";
    Serial.println("nuova richiesta");
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if(postString.length()<15){
          postString +=c;
        }

        if (c == 'n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("<h1>Configurazione</h1>");
          client.print("<br>");

          for (int i=0; i<nSensori; i++)
          {
            String linkCompleto = "";
            linkCompleto = "<a href="./?save"+ String(i);
            linkCompleto +="">Salva Sensore " + String(i);
            linkCompleto += "</a><br/>";
            client.println(linkCompleto);
            Serial.println(linkCompleto);
            //client.println("<a href="./?save1">Salva Sensore 1</a>");
          }

          client.println("<br/>");
          client.println("<a href="./?elenco">Visualizza dati sensori</a>");
          client.println("</html>");
          break;
          //}
        }

        if (c == 'n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != 'r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }

      }
    }  //fine client.connected 

    Serial.println("-------------");
    Serial.println(postString);
    Serial.println("-------------");

    if(postString.indexOf("?save") > 0){ 

      int indexSave = postString.indexOf("?save");
      Serial.println("indexOf");
      Serial.println(indexSave);
      //cerco valore del sensore
      String sSensore = postString.substring(indexSave+5 ,indexSave+6);
      Serial.println("Sensore");
      Serial.println(sSensore);
      int iSensore = sSensore.toInt();
      long valore = salvaSensore(iSensore);
      client.println("<br/>");
      client.println("<p>Salvataggio sensore effettuato</p>");
      client.println("<br/>");
      client.println("Codice sensore " + sSensore);
      client.print(valore);
    }   

    if(postString.indexOf("?elenco") > 0){
      for (int i=0; i<nSensori; i++)
      {
        client.println("<p>Sensore " + String(i)+" : </p>");
        client.print(String(EEPROMReadlong(i*4)));
        Serial.println(EEPROMReadlong(i*4));
      }
    }

    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

long salvaSensore(int iSensore)
{
  int addressTosSave = iSensore*4;
  long valore = 0;
  Serial.println("salvaSensore");
  if (mySwitch.available()) {
    Serial.println("mySwitch.available");
    valore = mySwitch.getReceivedValue();
    Serial.println("valore ");
    Serial.print(valore);
    EEPROMWritelong(addressTosSave,valore);
  }
  delay(1000);
  return valore;
} 

void EEPROMWritelong(int address, long value)
{
  //Decomposition from a long to 4 bytes by using bitshift.
  //One = Most significant -> Four = Least significant byte
  byte four = (value & 0xFF);
  byte three = ((value >> 8) & 0xFF);
  byte two = ((value >> 16) & 0xFF);
  byte one = ((value >> 24) & 0xFF);

  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(address, four);
  EEPROM.write(address + 1, three);
  EEPROM.write(address + 2, two);
  EEPROM.write(address + 3, one);
}

void setupComm()
{
  Serial.println("Trying to connect");
  Serial.print("n");
  if (!Ethernet.begin(mac)){
    Serial.println("Failed to DHCP");
    // no point in carrying on, so do nothing forevermore:
    while(true);
  }

  // print your local IP address:
  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println("fine");
}

long EEPROMReadlong(long address)
{
  //Read the 4 bytes from the eeprom memory.
  long four = EEPROM.read(address);
  long three = EEPROM.read(address + 1);
  long two = EEPROM.read(address + 2);
  long one = EEPROM.read(address + 3);

  //Return the recomposed long by using bitshift.
  return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

L’interfaccia risultante su web è la seguente: (evitate commenti 🙂 )

Ricordo che per accedere alla pagina internet è necessario scrivere nel browser l’indirizzo ip che viene stampato nella console di arduino, specificando inoltre la porta 8081.
Nel mio caso, ad esempio: 192.168.1.136:8081

Sono presenti 5 link che permettono di salvare i dati di 5 sensori: premendo il link “Salva sensore 0” ed azionando il sensore (aprendo la porta per esempio) viene memorizzato il dato nella eeprom.

Schermata 2014-12-17 alle 22.31.29

Una volta salvati i dati è possibile visualizzare un elenco riepilogativo di quanto è presente nella EEPROM, cliccando “Visualizza dati sensori”.
Schermata 2014-12-17 alle 22.31.01

Se riesco in serata posto un video dove si vede meglio il funzionamento.
Il codice è relativamente semplice.
Tralasciando la parte di collegamento alla ethernet shield (già spiegata nei precedenti articoli) passiamo a come vengono generati i link e la loro gestione.

riga 14: viene dichiarato nSensori, cioè il numero di sensori che voglio gestire
riga 53-61: viene creato il link in modo dinamico secondo la sintassi html. Il link che viene richiamato sarà del tipo save0, save1, save2..., a seconda del link che si vuole premere.
riga 63-65: creazione del link per elenco dei sensori memorizzati
riga 81-97: gestione del salvataggio del codice sensore.
Nel dettaglio:
riga 81: nella querystring è presente “salva”, quindi è stato richiesto un salvataggio
riga 87: ricavo quale sensore deve essere salvato (sensore0, sensore1, sensore2..)
riga 91: chiamo la funzione salvaSensore: attiva la funzione mySwitch.getReceivedValue() per stabilire il codice del sensore per poi salvarlo nelle EEPROM
riga 92-96: stampa del codice sensore salvato
riga 100-107: viene visualizzalo l’elenco dei sensori salvati; è un semplice ciclo for che va a leggere con la funzione EEPROMReadlong ogni singolo sensore.
A questo punto, nel prossimo articolo, implementeremo quanto visto oggi nel nostro antifurto!

Dai divertente no???? 🙂

Parliamo di cose più serie ora…che dirvi…

BUON NATALE!!!!!!!!!

Un semplice antifurto: memorizzare i codici sensori nella EEPROM

Eccomi di nuovo, raffreddato…buona scusa per non andare in palestra e divertirmi con Arduino.

Come dicevo nel precedente articolo mi piacerebbe rendere più fruibile il codice: in particolare vorrei fare in modo che i codici dei sensori non siano scritti “a mano”  ma rendere possibile  all’utilizzatore di memorizzarli dall’interfaccia web.
Premendo un tasto sull’interfaccia web, il modulo wireless ricevente rimarrà in ascolto in attesa del codice sensore che l’utilizzatore avrà attivato.

Il primo problema è: dove e come memorizzarli?

Ho pensato alla EEPROM presente su Arduino. Questo articolo di Mauro Alfieri spiega perfettamente il suo utilizzo.

I valori che voglio utilizzare sono long (come vedi dalle righe 26,27,28,29 dello sketch del precedente articolo) quindi non mi basta una singola cella della EEPROM (che può contenere solo un byte da 0 a 255).
Il tipo dati long invece è quattro volte un byte:  4 byte.

A titolo riepilogativo:

boolean – Può assumere solamente due valori: vero o falso.

char – Contiene un singolo carattere. L’Arduino lo registra come un numero (ma noi vediamo il testo). Quando i caratteri  sono usati per registrare un numero, possono contenere un valore compreso tra -128 e 127.

byte – Può contenere un numero tra 0 e 255. Come un carattere usa solamente un byte di memoria.

int – Contiene un numero compreso tra -32’768 e 32’767. E’ il tipo di variabile più usata e usa 2 byte di memoria.

unsigned int – Ha la stessa funzione di int, solo che non può contenere numeri negativi, ma numeri tra 0 e 65.535.

long – E’ il doppio delle dimensioni di un int e contiene i numeri da -2’147’483’648 a 2’147’483’647.

unsigned long – Versione senza segno di long va da 0 a 4’294’967”295.

float – Può memorizzare numeri con la virgola. Occupa 4 bytes della RAM.

double – A doppia precisione in virgola mobile con valore massimo di 1’7976931348623157×10^308.

Quindi quello che voglio fare è dividere il mio codice sensore (long) in 4 byte e quindi ognuno di questi quattro byte memorizzarlo in una cella della eeprom.

In questo articolo ho trovato questo splendido pezzo di codice che fa tutto ciò.
Ho semplicemente verificato il funzionamento, nel mio caso:

/*
 Provo a scrivere un long e a leggerlo nella eeprom
 */
 
#include <EEPROM.h>;
// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
 
}
 
// the loop routine runs over and over again forever:
void loop() {
    delay(5000);
     long address=0;
     long sensore1= 3557625;
     long sensore2= 10521177;
     EEPROMWritelong(address, sensore1);
     Serial.println("Scrittura 1 riuscita");
     address+=4;
     EEPROMWritelong(address, sensore2);
     Serial.println("Scrittura 2 riuscita");
 
     /*Serial.println(EEPROMReadlong(0));
     Serial.println(EEPROMReadlong(4));*/
}
 
void EEPROMWritelong(int address, long value)
{
  //Decomposition from a long to 4 bytes by using bitshift.
  //One = Most significant -> Four = Least significant byte
  byte four = (value & 0xFF);
  byte three = ((value >> 8) & 0xFF);
  byte two = ((value >> 16) & 0xFF);
  byte one = ((value >> 24) & 0xFF);
 
  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(address, four);
  EEPROM.write(address + 1, three);
  EEPROM.write(address + 2, two);
  EEPROM.write(address + 3, one);
}
 
long EEPROMReadlong(long address)
{
  //Read the 4 bytes from the eeprom memory.
  long four = EEPROM.read(address);
  long three = EEPROM.read(address + 1);
  long two = EEPROM.read(address + 2);
  long one = EEPROM.read(address + 3);
 
  //Return the recomposed long by using bitshift.
  return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

riga 5: includo la libreria EEPROM
riga 19-22: salvo, tramite la funzione EEPROMWritelong il valore del primo e secondo sensore. Il primo sensore lo salvo nell’ indirizzo 0, mentre il secondo nell’indirizzo 4, giustamente 4 byte successivi al primo sensore.

A questo punto ho spento Arduino per poi ricollegarlo. Vediamo che variabili ho letto.
Il ciclo loop per la lettura l’ho modificato in questo modo:

void loop() {
  /*delay(5000);
   long address=0;
   long sensore1= 3557625;
   long sensore2= 10521177;
   EEPROMWritelong(address, sensore1);
   Serial.println("Scrittura 1 riuscita");
   address+=4;
   EEPROMWritelong(address, sensore2);
   Serial.println("Scrittura 2 riuscita");*/
 
  Serial.println("Sensore 1");
  Serial.println(EEPROMReadlong(0));
  Serial.println("Sensore 2");
  Serial.println(EEPROMReadlong(4));
  delay(10000000);
}

I valori letti sono stati:

Schermata 2014-12-03 alle 22.25.17

Ma porc! Funziona!

Naturalmente gli indirizzi della eeprom letti sono 0 e il 4, sempre per il solito discorso dei 4 byte per i long.

Ok, a questo punto so come memorizzare i valori nelle eeprom, nel prossimo post cercherò di costruire l’interfaccia web per la memorizzazione.

Alla prossima! Spero senza raffreddore e senza esondazione Seveso!

Un semplice antifurto: cerchiamo di mettere tutto insieme

Eccomi di nuovo…costretto a casa dalla piena del Seveso ne approfitto per aggiornare il blog.

Nei precedenti post abbiamo:

  • letto i dati dai sensori di movimento
  • letto i dati dal sensore di rumore
  • collegato la ethernet shield ed inviata una mail

A questo punto possiamo mettere insieme i vari pezzi.

Inoltre avendo a casa  una telecamera D-Link DCS-930L ho deciso di inserirla in questo progetto.

Per non tenere accesa la telecamera tutto il giorno vorrei fare in modo che si accenda solo nel momento in cui viene individuato un movimento.
Non solo: poterla accenderla da remoto nel caso in cui ho voglia di verificare cosa succede in casa.
Per non complicarmi la vita ho deciso di comprare una ciabatta wireless (sempre a 433 Mhz) tipo queste. Collegata la webcam alla ciabatta posso comandarla tramite arduino, basta solo scoprire il codice di trasmissione come fatto precedentemente con i sensori di movimento!
Utilizzando il telecomando in dotazione alla prese quindi ho determinato:

Codice accensione ciabatta Codice spegnimento ciabatta
1394001 1394004

Ho quindi tutti i codici sensori che necessito, posso aggiungere il modulo di trasmissione ad Arduino.

Il risultato finale è questo:

IMG_4507IMG_4506IMG_4505

I collegamenti, rispetto a quanto fatto nelle precedenti “puntate”, li ho dovuti modificare in quanto ho scoperto che i pin 10, 11, 12 e 13 vengono utilizzati in modo esclusivo dall’ethernet shield.

Quindi riepilogando i collegamenti sono:

Sensore Rumore

Vcc 5 V
GND GND
SNG Pin 5 (digitale)

Sensore ricevente 433 Mhz

Pin Ricevitore Pin Arduino
Vcc 5 V
GND GND
DATA Pin 2 (digitale)

Sensore trasmittente 433 Mhz

 

Pin Ricevitore Pin Arduino
Vcc 5 V
GND GND
DATA Pin 9 (digitale)

 

Il codice per verificare se il tutto funziona quindi :

 

/*
 Ricezione dai sensori porte
 Trasmissione verso telecamera
 rivelazione rumore

 http://code.google.com/p/rc-switch/

 Need help? http://forum.ardumote.com
 */

#include <String.h>
#include <RCSwitch.h>
#include <Time.h>
#include <SPI.h>
#include <Ethernet.h>

/* Informazioni Ethernet*/

byte mac[] = {
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
int SERIAL_BAUD        = 9600;
int TRASMIT_PIN       = 9;
int RECEIVE_PIN       = 0;
int NOISE_DIGITAL_PIN =    5;
//Sensori
long PORTA_INGRESSO_SENSORE  = 3557625;
long PORTA_CUCINA_SENSORE = 10521177;
long SEGNALE_ACCENZIONE_WEBCAM = 1394001;
long SEGNALE_SPEGNIMENTO_WEBCAM= 1394004;

EthernetClient client;
EthernetServer server(8081);
char smtpServer[] = "smtpcorp.com";
RCSwitch mySwitch = RCSwitch();

void setup() {
  Serial.begin(SERIAL_BAUD);
  pinMode(SERIAL_BAUD, INPUT);
  mySwitch.enableReceive(RECEIVE_PIN);
  mySwitch.enableTransmit(TRASMIT_PIN);
  setupComm();
}

void loop() {

  getClientConnection();
  if (detectNoise()){
    Serial.print("Rumore");
    email("Attenzione, rilevato rumore in casa!");
    accendiCam(SEGNALE_ACCENZIONE_WEBCAM) ;
  }

  if (mySwitch.available()) {

    int value = mySwitch.getReceivedValue();

    Serial.print(value);
    if (value == 0) {
      Serial.print("Unknown encoding");
      Serial.print("\n");
    }
    else {
      long receivedValue = mySwitch.getReceivedValue();
      if (receivedValue == PORTA_INGRESSO_SENSORE) {
        Serial.print("Attenzione! Porta ingresso aperta!");
        Serial.print("\n");
        email("Attenzione, porta ingresso aperta!");
        accendiCam(SEGNALE_ACCENZIONE_WEBCAM) ;
        delay(1000);
      }
      else if(receivedValue == PORTA_CUCINA_SENSORE) {
        Serial.print("Attenzione! Porta cucina aperta!");
        Serial.print("\n");
        email("Attenzione, porta cucina aperta!");
        accendiCam(SEGNALE_ACCENZIONE_WEBCAM) ;
        delay(1000);
      }  

      Serial.print("Received ");
      Serial.print( receivedValue);
      Serial.print(" / ");
      Serial.print( mySwitch.getReceivedBitlength() );
      Serial.print("bit ");
      Serial.print("Protocol: ");
      Serial.println( mySwitch.getReceivedProtocol() );
    }

    mySwitch.resetAvailable();
  }

}

bool detectNoise ()
{
  bool rit = false;
  if (digitalRead(NOISE_DIGITAL_PIN) == HIGH)
  {
    rit = true;
  }
  return rit;
} 

void accendiCam(long value)
{
  mySwitch.send(value, 24);
  mySwitch.send(value, 24);
  mySwitch.send(value, 24);
  mySwitch.send(value, 24);
  mySwitch.send(value, 24);
} 

void setupComm()
{
  Serial.println("Trying to connect");
  Serial.print("\n");
  if (!Ethernet.begin(mac)){
    Serial.println("Failed to DHCP");
    while(true);
  }

  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println("fine");
}

// Call to send an email.
bool email(char* text)
{
  bool success = false;
  Serial.println("Sending email...");
  Serial.print("\n");
  Serial.println("SMTP server...");
  Serial.print(smtpServer); 

  if (client.connect(smtpServer, 2525)){
    Serial.println("connected");
    delay(100);
    client.println("EHLO arduino");
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    }
    Serial.println("responded");
    Serial.print("\n");
    client.println("AUTH LOGIN");
    client.println("xxxxxxx");           //vedi precedente post per la spiegazione
    client.println("yyyyyy");   //vedi precedenti post per la spiegazione     

    client.println("MAIL FROM:<dumm@gmail.com>");
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    } 

    client.println("RCPT TO:<giuseppe.scola@gmail.com>"); 

    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    } 

    client.println("DATA");
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    }

    client.println("from: giuseppe.scola@gmail.com");
    client.println("to: giuseppe.scola@gmail.com");
    client.println("SUBJECT: ArduAlarm");
    client.println("");
    client.println(text);
    client.println(".");
    client.println("QUIT");
    for(int i=0; i<999; ++i){
      if(i > 998){
        Serial.println("error: No response");
      }
      if(client.read() > 0)
        break;
    }
    success = true;
    client.println();
    Serial.println("end");
    Serial.print("\n");
  }
  else {
    Serial.println("Failed");
    Serial.print("\n");
    client.println("QUIT");
  }
  client.stop();
  return success;
}

void getClientConnection(){

  EthernetClient client = server.available();
  if (client) {
    String postString ="";
    Serial.println("nuova richiesta");
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        //postString.concat(c);
        if(postString.length()<10){
          postString +=c;
        }
        // Serial.write(c);
        if (c == '\n' && currentLineIsBlank) {
          //if(readString.indexOf("id=1") > 0){
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          //client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          //client.println("<h1>Settaggi</h1><br>");
          client.println("<h1>AllarDuino</h1>");
          client.print("<br>");
          client.println("<a href=\"./?on\">Accendi CAM</a>");
          client.println("<a href=\"./?off\">Spegni CAM</a>");
          client.println("</html>");
          break;
          //}
        }

        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }

      }
    }  //fine client.connected 

    Serial.println("-------------");
    Serial.println(postString);
    Serial.println("-------------");

    if(postString.indexOf("?on") > 0){
      Serial.println("accendi CAM");
      accendiCam(SEGNALE_ACCENZIONE_WEBCAM);
      client.println("<br/>");
      client.println("<p>Cam accesa</p>");

    }
    if(postString.indexOf("?off") > 0){
      accendiCam(SEGNALE_SPEGNIMENTO_WEBCAM);
      client.println("<br/>");
      client.println("<p>Cam spenta</p>");
    } 

    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

Domani o dopo spero di riuscire a commentare un po il codice, soprattutto la parte in cui viene generato l’html.

Un semplice antifurto: collegamento ethernet shield

Ciao di nuovo, mi è arrivata finalmente a casa l’ethernet shield ed è ora di studiarla un po!
Quello che voglio capire è come inviare una mail al mio indirizzo di posta.

Il collegamento ad Arduino UNO è semplicissimo, un’immagine vale più di 1000 parole!

FZ05SN7H05NT26I.MEDIUM(da instructables.com)

Quindi colleghiamo la presa RJ45 al nostro router e il cavo USB di alimentazione alla presa di alimentazione di Arduino UNO (vedi figura).

FDP0VOXH05NHCWO.MEDIUM(da instructables.com)

Le informazioni fondamentali per procedere sono:

  1. impostazione ip della ethernet shield
  2. impostazione mac address della ethernet shield
  3. impostazioni del server SMTP per invio della mail

Il mio router è in DHCP, quindi assegna automaticamente gli indirizzi ip.
Non ci sono problemi per il  MAC Address in quanto si può assegnare un numero in modo arbitrario.

A questo punto ho scoperto ci possono essere due strade per l’invio delle email:

1. Il servizio Temboo mette a disposizione una libreria per l’invio mail tramite gmail (qui le istruzioni)
2. il servizio SMTP2GO che permette di inviare fino a 10 email tramite il proprio SMTP gratuito (registrazione qui).

Ho optato per la seconda strada (servizio SMTP2GO)…soprattutto perche ho scoperto Temboo quando ormai avevo finito di sviluppare con SMTP2GO! Zero voglia di provare Temboo!!!!!
Anzi, se qualcuno ha effettuato delle prove sarei felice di sentire una loro opinione. Thanks

Lato codice ho utlizzato quanto scritto da Nicolaj Joergensen:

#include <SPI.h>;
#include <Ethernet.h>;
 
// Arduino network information
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
EthernetClient client;
char smtpServer[] = "smtpcorp.com";
 
void setup()
{
  Serial.begin(9600);  // per debug
  setupComm();
}
 
void loop()
{
  email("ciao");
  delay(1000);
}
 
// Inizializzazione connessione ethernet shield
void setupComm()
{
  Serial.println("Trying to connect");
  if (!Ethernet.begin(mac)){
    Serial.println("Failed to DHCP");
    // verifica della connessione
    while(true);
  }
  delay(10000);
 
  // individuazione dell'indirizzo IP:
  Serial.print("IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();
}
 
// Invio effettivo della mail
bool email(char* text)
{
  bool success = false;
  Serial.println("Sending email...");
 
  if (client.connect(smtpServer, 2525)){            //2525 è la porta del SMTP Server
    Serial.println("connected");
    delay(100);
    client.println("EHLO arduino");
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    }
    Serial.println("responded");
 
    client.println("AUTH LOGIN");                     //vedi "http://base64-encoder-online.waraxe.us/"
    client.println("xxxxxxxxxx");           //Username in base 64
    client.println("yyyyyyyyyy");        //Password in base 64
 
    // Put your "from" email address here
    client.println("MAIL FROM:<dumm@gmail.com>"); //Sembra non importi molto quanto scritto qui...
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
      break;
    } 
 
    // Indirizzo di destinazione
    client.println("RCPT TO:<mail@mail.com>"); 
 
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
      break;
    } 
 
    client.println("DATA");
    for(int i=0; i<999; ++i){
      if(client.read() > 0)
        break;
    }
    //Sender
    client.println("from: mail@mail.com"); //Sender address visualizzato nella mail
    client.println("to: mail@mail.com");  //Receiver address visualizzato dalla mail
    client.println("SUBJECT: From your arduino");
    client.println("");
    client.println(text);
    client.println(".");
    client.println("QUIT");
    for(int i=0; i<999; ++i){
      if(i > 998){Serial.println("error: No response");}
      if(client.read() > 0)
        break;
    }
    success = true;
    client.println();
    Serial.println("end");
  } else {
    Serial.println("Failed");
    client.println("QUIT"); //Disconnessione
  }
  client.stop();
  return success;
}

Spiegazione del codice:

riga  5: impostazione del MAC Address: potete scrivere quello il numero che preferite!
riga  7: indirizzo del server SMTP
riga 17:chiamata alla funzione effettiva di invio email. Verrà inviata una mail con testo ciao
riga 25: inizializzazione della scheda ethernet
riga 34-35: visualizzazione dell’indirizzo IP assegnato in DHCP da mio router. Utile se vogliamo fare in modo che la scheda ethernet possa essere utilizzata come webserver e quindi richiamata da un browser.
riga 42: vengono inviati al server SMTP i comandi per l’invio della mail.
riga 58:  username del servizio SMTP2GO in base 64.
riga 59: password del servizio SMTP2GO in base 64.
E’ comodo utilizzare questo servizio per trasformare in base 64: http://base64-encoder-online.waraxe.us/
Per esempio la username CICCIO diventa Q0lDQ0lP

Caricato il programma ed uploadato su Arduino UNO ho ricevuto la mia prima mail!
Ho messo un delay alla riga 18, quindi ogni 10 secondi viene inviata una mail! Prestate attenzione con le prove perchè SMTP2GO mette a disposizione (nella versione free) solo l’invio di 10 mail giornaliere

Ho finito con la sperimentazione della ethernet shield per oggi…ho ottenuto quello che volevo.

Lo step successivo è di inviare una mail personalizzata nel momento in cui un sensore dell’antifurto riceve un segnale: la mail dovrà indicarmi quale sensore ha fatto scattare l’allarme (sensore porta, finestra, rumore) con relativa ora.

Ci vediamo alla prossima! (spero presto…)

Ps. Nel frattempo mi è arrivato arduino nano… 🙂 🙂

Un semplice antifurto: il modulo sensore rumore,

Il modulo FC04 è veramente semplice.
Ha solo tre pin: Vcc, GND e SNG, quindi i collegamenti che ho stabilito sono questi:

Pin Ricevitore Pin Arduino
Vcc 5 V
GND GND
SNG Pin 2 (digitale)

Il sensore ha una soglia di rumore impostabile tramite una vite: se viene individuato un rumore che supera la soglia, viene inviato un segnale HIGH sul pin selezionato (2 nel nostro caso)

Quindi lo sketch può essere questo:

 

int SERIAL_BAUD        = 9600;
int SENSOR_DIGITAL_PIN =    2;
int SOUND_DELAY        =   50; /* Un piccolo ritardo per non intercettare rumori duplicati o echi */
 
void setup() {
    Serial.begin(SERIAL_BAUD);
    pinMode(SERIAL_BAUD, INPUT);
}                                                                               
 
void loop() {
    if (digitalRead(SENSOR_DIGITAL_PIN) == LOW) {
        Serial.print("Rumore!");
 
        delay(SOUND_DELAY);
    }
}

A questo punto posso unire insieme i due programmi (sensori movimento e rumore) per inviarmi una mail in caso di sospetta intrusione!

Nel prossimo articolo lavorerò sulla internet shield, come fatto in questi post prima cercherò di capirne il funzionamento svincolato dal resto dei programmi per poi integrare il tutto successivamente.

A presto!

Un semplice antifurto: leggere i dati dai sensori

Per leggere i dati dai sensori ho trovato veramente utile la libreria rc-switch.

Il primo obiettivo è stato di capire cosa succede nel momento in cui attivo il sensore porta o il sensore PIR.
Ho quindi collegato come nella figura sottostante il ricevitore ad Arduino:

Pin Ricevitore Pin Arduino
Vcc 5 V
GND GND
DATA Pin 2 (digitale)

Nel mio caso utilizzo la breadboard (millefori) presente nello starterkit. 

riceventeMiajpg

A questo punto ho scaricato la libreria rc switch e l’ho copiata nella cartella libraries di Arduino.
La struttura a cartella sarà:

libraries\RCswitch

con all’interno i seguenti files:

  • keywords.txt
  • RCSwitch.cpp
  • RCSwitch.h
  • la cartella example

Possiamo aprire l’arduino ide e copiare il seguente codice:

#include <RCSwitch.h>;

RCSwitch mySwitch = RCSwitch();

void setup() {
   Serial.begin(9600);
   mySwitch.enableReceive(0); // Receiver on inerrupt 0 =&gt; that is pin #2
}

void loop() {
   if (mySwitch.available()) {

      int value = mySwitch.getReceivedValue();

      if (value == 0) {
         Serial.print("Unknown encoding");
     } else {
         Serial.print("Received ");
         Serial.print( mySwitch.getReceivedValue() );
         Serial.print(" / ");
         Serial.print( mySwitch.getReceivedBitlength() );
         Serial.print("bit ");
         Serial.print("Protocol: ");
         Serial.println( mySwitch.getReceivedProtocol() );
      }

      mySwitch.resetAvailable();
   }
}

Caricato il programma ed aperta la console del monitor seriale sui 9600 baud ho ricevuto le seguenti indicazioni:

  1. sensore porta 1: Received 1398111 / 24bit Protocol: 1
  2. sensore porta 2: Received 1394004 / 24bit Protocol: 1
  3. sensore PIR      :Received 1392102 / 24bit Protocol: 1

A questo punto posso utilizzare questi valori per intercettare l’apertura di una porta o il movimento in casa per mandarmi una mail o un sms.
Ho optato per la l’invio di una mail: qui entra in gioco  l’ethernet shield.

Alla prossima puntata