/* * Sensor de Temperatura que registra el valor en Internet llamando a la * aplicación con la URL * http://php-domos.rhcloud.com/insert.php?sensor=1236&valor=xx */ #include "DHT.h" #include "SPI.h" #include "Ethernet.h" #include <EEPROM.h> #include <avr/wdt.h> /* ============================================================================================= CONFIGURACION PARTICULAR ============================================================================================= */ //#define DEBUG_ON #ifdef DEBUG_ON #define debug(x) Serial.println(x) #else #define debug(x) #endif const long PERIODO_ACTUADOR = 10L * 60L * 1000L; // Cada cuanto pregunta por el estado del actuador. const long PERIODO_TEMPERATURA = 20L * 60L * 1000L; // Cada cuanto informa sobre la temperatura. const long PERIODO_HUMEDAD = 2L * 60L * 60L * 1000L; // Cada cuanto informa sobre la humedad const long PERIODO_RESET = 4L * 60L * 60L * 1000L; // Hace un reset cada 4 horas #define SW_TEMPERATURA 1 // Indica si queremos leer temperatura y enviarla al servidor #define USAR_RELE // Indica si queremos que el actuador funcione con un Relé #define USAR_IR // Indica si queremos usar códigos IR para const int PIN_DISPOSITIVO = 8; const int PIN_ERROR = 7; const int PIN_EN_EJECUCION = 6; //const int PIN_RESET = 5; const int ID_SENSOR_TEMPERATURA=nnnn; // Temperatura interior de Lamuño const int ID_SENSOR_HUMEDAD=nnnn; // Sensor de la humedad interior de Lamuño const int ID_ACTUADOR=nnnn; #define PIN_TERMOMETRO 2 // EL PIN DEL SENSOR DE TEMPERATURA const int REINTENTOS = 4; //const long CODIGO_IR_OFF = 0x807FC837; // El código para encender el aparato a controlar //const long CODIGO_IR_ON = 0x807F58A7; // El código para apagar el aparato a controlar const long CODIGO_IR_ON = 0x807F48B7; // El código para encender VERDADERO const long CODIGO_IR_OFF = CODIGO_IR_ON; #define PIN_IR 3 int ledEnEjecucion=0; // Simplemente el indicador que parpadeará si se está ejecuando el bucle. const int ESTADO_ON = 1; const int ESTADO_OFF = 0; const int ESTADO_INDETERMINADO = -1; int estadoDispositivo = ESTADO_OFF; /* ============================================================================================= */ #ifdef USAR_IR #include <IRremote.h> IRsend irsend; // Parece ser que no se puede definir el PIN sino que es siempre el 5. #endif long milisActuador= -PERIODO_ACTUADOR; long milisTemperatura= -PERIODO_TEMPERATURA; long milisReset=0; long milisHumedad= -PERIODO_HUMEDAD; char server[]= "xxxxx.rhcloud.com"; char query[]="GET /xxxxx.php?sensor=%d&valor=%d HTTP/1.1"; char actuador[]="GET /xxxxxx.php?id=%d HTTP/1.1"; char actuador_off[]="GET /xxx.php?actuador=%d&estado=OFF HTTP/1.1"; char host[]="Host: xxxxxx.rhcloud.com"; #define DHTTYPE DHT11 DHT dht(PIN_TERMOMETRO, DHTTYPE); byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192,168,0,2); EthernetClient cliente; void setup() { wdt_disable(); delay(50); // Segun dice la documentación http://www.freetronics.com.au/pages/usb-power-and-reset#.VN_itPmG_gc int isReset=checkReset(); // Hay que hacer esto lo antes posible para limpiar la EEPROM rapidamente. // HACK Para poder hacer reset //digitalWrite(PIN_RESET, HIGH); //pinMode(PIN_RESET, OUTPUT); pinMode(PIN_DISPOSITIVO, OUTPUT); pinMode(PIN_ERROR,OUTPUT); pinMode(PIN_EN_EJECUCION, OUTPUT); Serial.begin(9600); debug("Setup"); // Parpareamos un segundo el PIN de error para mostrar que funciona. esperar(2000, 50, PIN_ERROR); // Espera a ver si se inicializa el modem... esperar(2000, 50, PIN_DISPOSITIVO); esperar(2000, 50, PIN_EN_EJECUCION); if(SW_TEMPERATURA) { dht.begin(); } // De momento el wdt no funciona. Aunque haga reset la placa Ethernet no acaba funcionando hata que haga reset // fisicamente en la placa. // Además, 8 segundos es poco tiempo para esperar ya que el método connect podría tardar más incluso. // wdt_enable(WDTO_8S); debug("Inicializando Ethernet."); //if(Ethernet.begin(mac)==0) { // mostrarError("Error obteniendo la IP. La ponemos fija"); Ethernet.begin(mac, ip); //} debug(Ethernet.localIP()); wdt_reset(); esperar(5000, 100); if(isReset) { estadoDispositivo=EEPROM.read(1); digitalWrite(PIN_DISPOSITIVO, estadoDispositivo); } else { int estadoRecibido=ESTADO_INDETERMINADO; for(int vez=0; vez<3 && estadoRecibido==ESTADO_INDETERMINADO; vez++) { estadoRecibido=consultarActuador(cliente,0); if(estadoRecibido==ESTADO_INDETERMINADO) { esperar(5000, 2000, PIN_ERROR); } } if(estadoRecibido==ESTADO_INDETERMINADO) { mostrarError("Imposible conocer el estado"); for(;;); // NO puedo continuar si no conozco el estado. } estadoDispositivo=estadoRecibido; } wdt_reset(); } // Devuelve cierto si el Setup se está ejecutando tras un Reset. int checkReset() { int result=EEPROM.read(2); EEPROM.write(2, 0); // Limpiamos return result==1? 1:0; // Hacemos asi para garantixar 1 o cero. } // Marcamos para que se sepa al arrancar que viene de un reset. void setReset() { EEPROM.write(2, 1); } void reset() { EEPROM.write(1, (byte)estadoDispositivo); // Guardamos el estado del dispositivo para cargarlo en el siguiente setup; setReset(); wdt_enable(WDTO_8S); // Fuerzo un reset con el WatchDog a base de esperar unos segundos. esperar(20000, 100, PIN_ERROR); digitalWrite(PIN_ERROR, HIGH); // Marcamos que hay reset por si no funcionara. // digitalWrite(PIN_RESET, LOW); // Sistema de reset con cable al RESET (NO lo uso); for(;;); // Tras el Reset no puede haber nada. } void esperar(long total, long parpadeo, int pin) { int valor=0; for(long i=0; i<total; i+=parpadeo) { wdt_reset(); delay(parpadeo); digitalWrite(pin, valor); valor=valor?0:1; } digitalWrite(pin, 0); } void esperar(long total, long parpadeo) { esperar(total, parpadeo, PIN_EN_EJECUCION); } void mostrarError(char *Mensaje) { debug(Mensaje); digitalWrite(PIN_ERROR, 1); } void limpiarError() { digitalWrite(PIN_ERROR, 0); } void enviarConsulta(EthernetClient &cliente, char *consulta) { cliente.println(consulta); cliente.println(host); cliente.println("Connection: close\r"); cliente.println(); } void enviarTemperatura(EthernetClient &cliente) { if(!SW_TEMPERATURA) { return; } wdt_reset(); digitalWrite(PIN_EN_EJECUCION, 1); debug("Conectado para enviar temperatura"); int t = (int)dht.readTemperature(); if(t<=0) { esperar(5000, 300, PIN_ERROR); digitalWrite(PIN_ERROR, 1); return; } if(conectar(cliente)!=1) { mostrarError("Error conectando a temperatura"); return; } enviarQuery(ID_SENSOR_TEMPERATURA, t); milisTemperatura=millis(); wdt_reset(); } void enviarHumedad(EthernetClient &cliente) { if(!SW_TEMPERATURA) { return; } wdt_reset(); digitalWrite(PIN_EN_EJECUCION, 1); debug("Conectado para enviar humedad"); int h = (int)dht.readHumidity(); if(h<=0) { esperar(5000, 300, PIN_ERROR); digitalWrite(PIN_ERROR, 1); return; } if(conectar(cliente)!=1) { mostrarError("Error conectando a humedad"); return; } enviarQuery(ID_SENSOR_HUMEDAD, h); milisHumedad=millis(); wdt_reset(); } void enviarQuery(int idSensor, int t) { char aux[256]; sprintf(aux, query, idSensor, t); enviarConsulta(cliente,aux); esperar(3000,50); cliente.stop(); cliente.flush(); esperar(2000,100); digitalWrite(PIN_EN_EJECUCION, 0); } int conectar(EthernetClient &cliente) { int ret; for(int i=0; i<REINTENTOS; i++) { wdt_reset(); ret=cliente.connect(server, 80); if(ret==1) { return ret; } } return ret; } void ponerActuadorOff(EthernetClient &cliente) { debug("Poniendo el actuador en OFF"); int ret=conectar(cliente); if(ret != 1) { char aux[256]; sprintf(aux, "Error %d connect", ret); mostrarError(aux); return; } char aux[256]; sprintf(aux, actuador_off, ID_ACTUADOR); enviarConsulta(cliente, aux); esperar(2000,100); cliente.stop(); // Me da lo mismo lo que responda... cliente.flush(); esperar(2000,100); } int consultarActuador(EthernetClient &cliente, int actuar) { debug("Consultar actuador"); int ret=conectar(cliente); if(ret != 1) { char aux[256]; sprintf(aux, "Error %d connect", ret); mostrarError(aux); return ESTADO_INDETERMINADO; } char aux[256]; //debug("Conectado para leer actuador"); sprintf(aux, actuador, ID_ACTUADOR); enviarConsulta(cliente, aux); esperar(100,50); // Esperamos un poco a ver si hay respuesta. int estadoRecibido=leerRespuesta(cliente); cliente.stop(); cliente.flush(); if(actuar) { if(estadoRecibido==ESTADO_ON) { encenderDispositivo(); } else if(estadoRecibido==ESTADO_OFF) { apagarDispositivo(); } else { mostrarError("Estado recibido indeterminado"); } } else { if(estadoRecibido==ESTADO_INDETERMINADO) { mostrarError("Estado recibido indeterminado"); } } return estadoRecibido; } void apagarDispositivo() { #ifdef USAR_RELE digitalWrite(PIN_DISPOSITIVO, 0); #endif #ifdef USAR_IR if(estadoDispositivo==ESTADO_ON) { irsend.sendNEC(CODIGO_IR_OFF, 32); estadoDispositivo=ESTADO_OFF; } #endif } void encenderDispositivo() { #ifdef USAR_RELE digitalWrite(PIN_DISPOSITIVO, 1); #endif #ifdef USAR_IR if(estadoDispositivo==ESTADO_OFF) { irsend.sendNEC(CODIGO_IR_ON, 32); estadoDispositivo=ESTADO_ON; } #endif } void leerLinea(EthernetClient &client, char aux[], int max) { int i=0; while(client.available() && i<max) { char c=client.read(); if(c=='\n') { break; } else { aux[i++]=c; } } aux[i]=0; } int leerRespuesta(EthernetClient &cliente) { int retorno=ESTADO_INDETERMINADO; int intentos=0; // Esperando a datos disponibles, un maximo de 5 segundos for(intentos=0; intentos<500 && cliente.connected(); intentos++) { if(cliente.available()) { break; } delay(50); } // Leemos los datos disponibles... for(intentos=0; intentos<100 && cliente.connected(); intentos++) { if(cliente.available()) { char linea[256]; leerLinea(cliente, linea,100); if(!strcmp(linea,"ON")) { retorno=ESTADO_ON; break; } if(!strcmp(linea,"OFF")) { retorno=ESTADO_OFF; break; } } delay(50); } return retorno; } void procesarActuador(EthernetClient &cliente) { int estadoRecibido=consultarActuador(cliente, 1); if(estadoRecibido!=ESTADO_INDETERMINADO) { limpiarError(); } } void loop() { wdt_reset(); long time=millis(); if(time > PERIODO_RESET) { // Antes de hacer reset hay que ver si el actuador quiere que encienda o apague. procesarActuador(cliente); reset(); } if(time > milisTemperatura + PERIODO_TEMPERATURA) { enviarTemperatura(cliente); milisTemperatura=time; } if(time > milisHumedad + PERIODO_HUMEDAD) { enviarHumedad(cliente); milisHumedad=time; } if(time > milisActuador + PERIODO_ACTUADOR) { procesarActuador(cliente); milisActuador=time; } delay(1000); ledEnEjecucion = ledEnEjecucion? 0:1; digitalWrite(PIN_EN_EJECUCION, ledEnEjecucion); }
domingo, 15 de marzo de 2015
Domos - El código fuente definitivo
Bueno,... , tras un mes utilizando ya el sistema domótico de encendido de la estufa, el código fuente ya está bastante estabilizado.
Suscribirse a:
Enviar comentarios (Atom)
No hay comentarios:
Publicar un comentario