Go Down

Topic: Telecontrollo GSM caldaia Baxi (Read 2403 times) previous topic - next topic

ghennet

Buonasera a tutti, vorrei realizzare un controllo caldaia remoto tramite Arduino e modulo GSM, l'intenzione è quella di comandare una caldaia Baxi.
Il problema principale è relativo alla comunicazione caldaia/telecontrollo in quanto le informazioni viaggiano su un BUS e non con un semplice azionamento NC o NO.

Disturbando in Baxi ... pertanto se si desidera attivare la caldaia solamente tramite la chiusura del contatto pulito in Morsettiera M1 Morsetti 1-2 è necessario escludere ... direi che comunque è possibile pilotare l'accensione della caldaia semplicemente chiudendo il contatto sui due Morsetti.

La mia idea è:
- Arduino Mega (per future ampliamenti dell'impianto [sensori PIR])
- SeeedStudio GPRS (per il controllo remoto tramite GSM)
- Relay Shield  (http://www.robot-italy.com/it/itead-2-channels-5v-relay-module-1.html)


Avete qualche consiglio o suggerimento ??

(lo scopo è quello di azionare la caldaia prima del nostro arrivo, è una casa di campagna e viene usata poco proprio per questo problema)

grazie 1000

PaoloP

Quello di robot italy che hai indicato non è una shield, che si innesta sull'Arduino, ma un modulo da connettere con cavetteria a parte.
Se dovessi optare per uno shield vero e proprio controlla che sia compatibile col lo shield GSM, ovvero che non usino gli stessi pin per funzioni specifiche.

ghennet

Grazie Paolo, alla fine ho cambiato idea e ho ordinato direttamente la Shield GSM ufficiale Arduino. Costa da più, ma per evitare problemi di compatibilità e scarsa documentazione ho proferito optare per questa.

Ho già realizzato su BreadBoard un piccolo prototipo con un termistore per leggere la temperatura, dei pulsanti collegati tramite partitore di tensione per alzare, abbassare la temperatura preferita e per comandare abilitare l'abilitazione del controllo della scheda.

Per quanto riguarda il rele, ho pensato ad un BC537 con una resistenza da 1K, e come rele dovrei avere in casa un 5v con corrente da 120mA e 1n4004 in parallelo alla bobina.

Considerando che non conosco cosa transita sui morsetti da chiudere, conviene usare questo o una shield optoisolata ??
Ho il sospesso che 1K sia pochino, non sarebbe meglio 2K ??

Ot: una resistenza tra emettitore e GND servirebbe a ??

ghennet

ci siamo quasi, qui una prima bozza del codice ...

ho solo un problema che non riesco a capire, il codice qui sotto funziona... aggiungo una variabile di qualsiasi genere, il codice non funziona più, possibile che vada fuori memoria Arduino ??

Avete qualche suggerimento ???

Code: [Select]

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <math.h>
#include <GSM.h>

// Variabili Dichiarazione
// Display
Adafruit_PCD8544 display = Adafruit_PCD8544(8, 6, 5, 4, 9);
// Temperatura Desiderata
float     SetPoint = 20.5;
float     TempAmb;
boolean   Manuale = false;
int       Btn;
boolean   Caldaia = false;


int RELEPin = 12; 
// PIN Number for the SIM
#define PINNUMBER ""

// initialize the library instances
GSM     gsmAccess;
GSM_SMS sms;
// GSMScanner scannerNetworks;
// Array to hold the number a SMS is retreived from
char   senderNumber[14]; 
char   sms_ok1[14] = {"+39393XXYYXXX"};


// Funzione traduzione Temp Locale
double Thermister(int RawADC) {
double Temp;
Temp = log(((10240000/RawADC) - 10000));
Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
Temp = Temp - 273.15;            // Convert Kelvin to Celcius
// Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
return Temp;
}


void DisegnaLCD(){
  display.clearDisplay();
  display.setTextSize(1);
  // Scrivo la temperatura rilevata dal sensore
  display.setCursor(0,0);
  display.print("TempAmb:");
  display.setCursor(54,0);
  display.print(TempAmb);
 
  // Scrivo la temperatura impostata da pulsanti
  display.setCursor(0,10);
  display.print("TempOtt:");
  display.setCursor(54,10);
  display.print(SetPoint);
 
  // Scrivo lo stato del Termostato Interno
  display.setCursor(0,20);
  display.print("Manuale:");
  display.setCursor(65,20);
  if (Manuale) {
    display.print("ON");
  } else {
    display.print("OFF");
  }
 
  //Scrivo lo stato della Caldaia
  display.setCursor(0,30);
  display.print("Caldaia:");
  display.setCursor(65,30);
  if (Caldaia) {
    display.print("ON");
  } else {
    display.print("OFF");
  }
 
   // Scrivo lo stato del GSM
  // display.setCursor(0,40);
  // display.print("GSM: " + Operatore + "  " + Signal + " [0-31]");
 
  // Mando tutto al display
  display.display();
}

void AccendiCaldaia() {
   // Devo eccitare il rele
  digitalWrite(RELEPin, LOW);
  // Mostro a schermo lo stato caldaia
  Caldaia = 1;
}

void SpegniCaldaia() {
  // Spengo il rele
  digitalWrite(RELEPin, HIGH);
  Caldaia = 0; 
}




void setup() {
  pinMode(RELEPin, OUTPUT);
  //Spengo la caldaia
  digitalWrite(RELEPin, HIGH);
 
  display.begin();
  display.setContrast(60);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.setCursor(0,0);
  display.print("TERMOSTATO GSM");
  display.setCursor(10,30);
  display.print("GSM  On ...");
  display.display();
 
  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  Serial.println("SMS Messages Receiver");
   
  // connection state
  boolean notConnected = true;
 
  // scannerNetworks.begin();
 
  // Start GSM connection
  while(notConnected)
  {
    if(gsmAccess.begin(PINNUMBER)==GSM_READY)
      notConnected = false;
    else
    {
      Serial.println("Not connected");
      delay(1000);
    }
  }
 
  // Operatore = scannerNetworks.getCurrentCarrier();
 
  Serial.println("GSM initialized");
  Serial.println("Waiting for messages");
}

void loop() {
  // Varibili
  char c;
  char TextMsg[200];
  // variabili per il controllo del mittente
  boolean equal_1, equal_2;
  byte i;
  String messaggio;
  char cmd[5];

 
  TempAmb = Thermister(analogRead(0));
 
  // Controllo L'INPUT dei pulsanti
  Btn = analogRead(1);
  if (Btn < 1000) {
    // Cambio stato Controllo Manuale
    if ( (Btn >650) && (Btn <700) ) {
      Manuale = !Manuale;
    }
    // ---
    if (Btn < 20 ) {
       SetPoint -= 0.5;
    }
    // +++
    if ( (Btn >500) && (Btn <520) ) {
      SetPoint += 0.5;
    }
  }
 
  // Controllo se devo accendere la caldaia manualmente
  if (Manuale) {
    if (TempAmb < SetPoint) {
      AccendiCaldaia();
    } else {
      SpegniCaldaia();
    }
  } else {
    SpegniCaldaia();
  }
 
  DisegnaLCD();
 
  // Verifico il segnale e l'operatore
  // Signal = scannerNetworks.getSignalStrength();
 
  // If there are any SMSs available() 
  if (sms.available())  {
    Serial.println("INIZIO analisi SMS");
   
   
    // Get remote number
    Serial.println("Message received from:");

    // Get remote number
    sms.remoteNumber(senderNumber, 14);
    Serial.println(senderNumber);
   
    equal_1 = true;
    i = 0;
    while ( (equal_1) && (i<13) )  {
      if (senderNumber[i] != sms_ok1[i]) equal_1=false;
      i++;
    }
    Serial.print("Equal_1: ");
    Serial.println(equal_1);
   
    if ( (equal_1) ) {
      Serial.println("entro qui");
      // An example of message disposal   
      // Any messages starting with # should be discarded
      if(sms.peek()=='#') {
        sms.flush();
      }
     
      messaggio = "";
      // Read message bytes and print them
      while(c=sms.read()) {
        messaggio += c;
      } 
      Serial.println(messaggio.substring(0, 10));
     
     
      if (messaggio.substring(0, 10) == "Caldaia ON") {
        Serial.println("Accendo");
        SpegniCaldaia();
        messaggio=messaggio.substring(11);
        messaggio.toCharArray(cmd,5);
        SetPoint = atof(cmd);
        Manuale = true;
        AccendiCaldaia();
        messaggio = "Caldaia ACCESA";
      }
     
      if (messaggio.substring(0, 11) == "Caldaia OFF") {
        Serial.println("Spengo");
        Manuale = false;
        SpegniCaldaia();   
       
        // sms_ritorno = "Ho appena spento la caldaia.";
      }
      // Delete message from modem memory
      sms.flush();
     
      delay(1000);
      // Mando sms conferma operazione
      // InviaSMS(messaggio);
    } else {
      Serial.println("Messaggio scartato");
      // Delete message from modem memory
      sms.flush();
    }
  }
  delay(500);
}



ghennet

Secondo voi potrei risolvere dichiarando qualche variabile PROGMEM magari le stringhe in modo da liberare la SRAM ??

Cavolata ?

ghennet

Si cavolata... (mi rispondo da solo)

PROGMEM è in sola lettura, quindi la posso usare per delle costanti ... Uff

gpb01

Inserisci un piccolo test della memoria libera e fatti stampare il valore ... guarda QUI

Guglielmo
Search is Your friend ... or I am Your enemy !

ghennet

Gentilissimo Guglielmo, link messo nei preferiti....

Ho un FreeRam di 140....

Questa è la riga dove si inchioda o meglio, che non esegue:
Code: [Select]
Serial.println(messaggio.substring(0, 10));

ghennet

Ho ottimizzato un pochino il codice e ora ottengo questi valori di RAM:
RAM: 301
RAM: 209

prima dell'analisi del messaggio e il secondo dopo essere entrato nell'analisi dell'sms.

ORA FUNZIONA

Questo il codice:
Code: [Select]
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <math.h>
#include <GSM.h>

// Variabili Dichiarazione
// Display
Adafruit_PCD8544 display = Adafruit_PCD8544(8, 6, 5, 4, 9);
// Temperatura Desiderata
float     SetPoint = 20.5;
boolean   Manuale = false;
int       Btn;
boolean   Caldaia = false;



int RELEPin = 12; 
// PIN Number for the SIM
#define PINNUMBER ""

// initialize the library instances
GSM     gsmAccess;
GSM_SMS sms;
// GSMScanner scannerNetworks;
// Array to hold the number a SMS is retreived from
char   senderNumber[14]; 
char   sms_ok1[14] = {"+393"};


// Funzione traduzione Temp Locale
double Thermister(int RawADC) {
double Temp;
Temp = log(((10240000/RawADC) - 10000));
Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
Temp = Temp - 273.15;            // Convert Kelvin to Celcius
// Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
return Temp;
}

// RAM libera
int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void InviaSMS(byte Type) {
  char msg_sms[20] = "Comando ricevuto"; 
 
  delay(500);
  sms.beginSMS(senderNumber);
  sms.print(msg_sms);
  sms.endSMS();
  delay(500);
}


void DisegnaLCD(float TempAmb){
  display.clearDisplay();
  display.setTextSize(1);
  // Scrivo la temperatura rilevata dal sensore
  display.setCursor(0,0);
  display.print("TempAmb:");
  display.setCursor(54,0);
  display.print(TempAmb);
 
  // Scrivo la temperatura impostata da pulsanti
  display.setCursor(0,10);
  display.print("TempOtt:");
  display.setCursor(54,10);
  display.print(SetPoint);
 
  // Scrivo lo stato del Termostato Interno
  display.setCursor(0,20);
  display.print("Manuale:");
  display.setCursor(65,20);
  if (Manuale) {
    display.print("ON");
  } else {
    display.print("OFF");
  }
 
  //Scrivo lo stato della Caldaia
  display.setCursor(0,30);
  display.print("Caldaia:");
  display.setCursor(65,30);
  if (Caldaia) {
    display.print("ON");
  } else {
    display.print("OFF");
  }
 
   // Scrivo lo stato del GSM
  // display.setCursor(0,40);
  // display.print("GSM: " + Operatore + "  " + Signal + " [0-31]");
 
  // Mando tutto al display
  display.display();
}

void AccendiCaldaia() {
   // Devo eccitare il rele
  digitalWrite(RELEPin, LOW);
  // Mostro a schermo lo stato caldaia
  Caldaia = 1;
}

void SpegniCaldaia() {
  // Spengo il rele
  digitalWrite(RELEPin, HIGH);
  Caldaia = 0; 
}




void setup() {
  pinMode(RELEPin, OUTPUT);
  //Spengo la caldaia
  digitalWrite(RELEPin, HIGH);
 
  display.begin();
  display.setContrast(60);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.setCursor(0,0);
  display.print("TERMOSTATO GSM");
  display.setCursor(10,30);
  display.print("GSM  On ...");
  display.display();
 
  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  Serial.println("SMS Messages Receiver");
   
  // connection state
  boolean notConnected = true;
 
  // scannerNetworks.begin();
 
  // Start GSM connection
  while(notConnected)
  {
    if(gsmAccess.begin(PINNUMBER)==GSM_READY)
      notConnected = false;
    else
    {
      Serial.println("Not connected");
      delay(1000);
    }
  }
 
  // Operatore = scannerNetworks.getCurrentCarrier();
 
  Serial.println("GSM initialized");
  Serial.println("Waiting for messages");
  Serial.print("RAM: ");
  Serial.println(freeRam());
}

void loop() {
  // Varibili
  char c;
  // variabili per il controllo del mittente
  boolean   equal_1, equal_2;
  byte      i;
  // String messaggio;
  char      cmd[5];
  float     TempAmb;
  char      msg[60] = "";
  boolean   accendo, spengo;
  char      accendo_cmd[11] = {"Caldaia ON"};
  char      spengo_cmd[12] = {"Caldaia OFF"};
 
 
  // Controllo L'INPUT dei pulsanti
  Btn = analogRead(1);
  if (Btn < 1000) {
    // Cambio stato Controllo Manuale
    if ( (Btn >650) && (Btn <700) ) {
      Manuale = !Manuale;
    }
    // ---
    if (Btn < 20 ) {
       SetPoint -= 0.5;
    }
    // +++
    if ( (Btn >500) && (Btn <520) ) {
      SetPoint += 0.5;
    }
  }
 
  TempAmb = Thermister(analogRead(0));
  // Controllo se devo accendere la caldaia manualmente
  if (Manuale) {
    if (TempAmb < SetPoint) {
      AccendiCaldaia();
    } else {
      SpegniCaldaia();
    }
  } else {
    SpegniCaldaia();
  }
 
  DisegnaLCD(TempAmb);
 
  // Verifico il segnale e l'operatore
  // Signal = scannerNetworks.getSignalStrength();
 
  // If there are any SMSs available() 
  if (sms.available())  {
    Serial.print("RAM: ");
    Serial.println(freeRam());

    // Get remote number
    sms.remoteNumber(senderNumber, 14);
   
    equal_1 = true;
    i = 0;
    while ( (equal_1) && (i<13) )  {
      if (senderNumber[i] != sms_ok1[i]) equal_1=false;
      i++;
    }
    Serial.print("Equal_1: ");
    Serial.println(equal_1);
   
    if ( (equal_1) ) {
      // An example of message disposal   
      // Any messages starting with # should be discarded
      if(sms.peek()=='#') {
        sms.flush();
      }
     
      Serial.print("RAM: ");
      Serial.println(freeRam());
      // Read message bytes and print them
      i = 0;
      while(c=sms.read()) {
        msg[i] = c;
        i++;
      } 
     
      i = 0;
      accendo = true;
      while ( (accendo) && (i<10) )  {
        if (msg[i] != accendo_cmd[i]) accendo=false;
        i++;
      }
     
      if (accendo) {
        SpegniCaldaia();
        for (i=0; i<=4; i++) {
          cmd[i] = msg[i+10];
        }
        SetPoint = atof(cmd);
        Manuale = true;
        AccendiCaldaia();
        InviaSMS(1);
      }
     
     
      i = 0;
      spengo = true;
      while ( (spengo) && (i<12) )  {
        if (msg[i] != spengo_cmd[i]) spengo=false;
        i++;
      }
   
      if (spengo) {
        Serial.println("Spengo");
        Manuale = false;
        SpegniCaldaia();
        InviaSMS(2);   
      }
      // Delete message from modem memory
      sms.flush();
      Serial.print("RAM: ");
      Serial.println(freeRam());
    } else {
      Serial.println("Messaggio scartato");
      // Delete message from modem memory
      sms.flush();
    }
  }
  delay(500);
}



Vorrei solo migliorare questa parte...
Code: [Select]
void InviaSMS(byte Type) {
  char msg_sms[20] = "Comando ricevuto"; 
 
  delay(500);
  sms.beginSMS(senderNumber);
  sms.print(msg_sms);
  sms.endSMS();
  delay(500);
}


dentro a Type gli passo il tipo di operazione (1 > accendo, 2 > spengo), ottengo i messaggi di ritorno...
Vorrei modificare questa stringa in
"Accendo caldaia a xx gradi", oppure spengo caldaia...

Suggerimenti ?? (scappo al lavoro)

gpb01


.....
Suggerimenti ?? (scappo al lavoro)


Si, un paio ...

Primo, invece della forma :
Code: [Select]
Serial.println("testo_fisso");
usa la forma
Code: [Select]
Serial.println(F("testo_fisso"));
risparmierai parecchia memoria.

Secondo, evita come la peste le variabili di tipo String e le operazioni su di esse ... :D
... impara ad usare gli array di caratteri e le funzioni ad essi collegate ... risparmierai memoria ed avrai molti meno problemi. ;)

Guglielmo

Search is Your friend ... or I am Your enemy !

ghennet

Grazie GP ..

Le serial le uso solo x debug, in faase di compilazione finale le elimino tutte...

Per quanto riguarda le strong le ho rimosse tutte pensando fossero loro il problema e in effetti è proprio cosi, ora devo capire come lavorare con gli array di chat

Una cosa banale del tipo
Strong + variabile + stringa
Come la faccio ??

Thanks a lot

gpb01

#11
Oct 23, 2013, 05:24 pm Last Edit: Oct 23, 2013, 05:27 pm by gpb01 Reason: 1
Allora, le variabili numeriche devi convertire in array di caratteri (ovvero in stringhe) e, per farlo, puoi usare le funzioni che sono definite in stdlib.h (un reference lo hai QUI), mentre per copiare, concatenare, e fare altre oprazioni su gli array di caratteri, puoi usare le funzioni che sono definite in string.h (un reference lo hai QUI).

Basta solo farci un po' la mano ;)

Guglielmo

Edit : ricorda che gli array di caratteri (stringhe) aggiungono alla fine un carattere dal valore 0x00 per indicare la fine della stringa. Quindi, quando calcoli le dimensioni dei tuoi array considera sempre UN carattere di più per il terminatore di stringa.
Search is Your friend ... or I am Your enemy !

ghennet

Grandissimo consiglio, molto utile...

Ci sono... ultimo intoppo è in questa riga... non mi converte i due float
Code: [Select]
sprintf(msg_sms,  "TempAtt: %2.2f - ACCENSIONE caldaia a: %2.2f gradi", TempAmb, SetPoint);

mi ritorno un ? come risultato della conversione

gpb01

... mmm ... posta l'ultima versione del codice e controlliamo meglio.

Una altra nota che rilevo dal vecchio codice postato ...
... tu usi sia variabili float che double e numeri con un discreto numero di decimali, peccato che, se leggi il reference ...

Floats have only 6-7 decimal digits of precision. That means the total number of digits, not the number to the right of the decimal point. Unlike other platforms, where you can get more precision by using a double (e.g. up to 15 digits), on the Arduino, double is the same size as float.

... ti accorgi che : a) float e double, su Arduino UNO / Arduino Mega, sono la stessa cosa !  b) il numero TOTALE di cifre è tra 6 e 7, tra decimali e intere !!!

Ti rendi conto che :
Code: [Select]
Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
... è abbastanza un NON senso visto che quello 0.0000000876741 verrà probabilmente arrotondato a 0 con le ovvie conseguenze, visto che lo usi in una moltiplicazione !!!

Quindi occhio ... magari verifica il tuo codice e ottimizza ancora, poi mettilo qui nell'ultima versione ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

ghennet

hiihi verissimo, ma quella funziona l'ho presa pari pari da un sito per la traduzione di un termistore da 10K e l'ho presa per buona...
l'ho preso da qui:
http://playground.arduino.cc/ComponentLib/Thermistor2

I miei Float sono banalmente a 2 decimali...

ora funziona tutto, molto bene e anche molto stabile, ho solo un problema nel mostrare i caratteri nell'sms di ritorno ...
il problema è in questa conversione che non funziona.

Code: [Select]
switch (Type) {
    case 1:
      sprintf(msg_sms,  "TempAtt: %2.2f - ACCENSIONE caldaia a: %2.2f gradi", TempAmb, SetPoint);
      break;
    case 2:
      sprintf(msg_sms,  "TempAtt: %2.2f - SPEGNIMENTO caldaia", TempAmb);
      break;
  }


Grazie della dedizione ;)

Go Up