Cuando se detecta moviento antes de hacer la foto se cierra un relé al cual se podría conectar una lámpara de modo que haya luz cuando se haga la foto.
// He tenido que reducir al mínimo las cadenas de texto utilizadas pues estoy en el límite de la memoria del Arduino UNO
// Para que desde el navegador nos podamos descargar un fichero que ya esta en la tarjeta simplemente
// pondremos la ip del sitio seguido de /nombrearchivo Por ejemplo: http://192.168.1.177/IMAGE10.JPG
// Si Unicamente ponemos la ip sin nada detras nos mostrara la lista de los ficheros que contiene la tarjeta
// http://192.168.1.177/1 Activaría la detección de movimiento
// http://192.168.1.177/2 Desactivaría la detección de movimiento
// http://192.168.1.177/3 Activaría el envío de tweets
// http://192.168.1.177/4 Desactivaría el envío de tweets
//
// Version V2: Le pongo activar o desactivar Motion añadiendo en la URL motion_off o motion_on
// Version V3: He quitado muchos if, quito upload file, activar o desactivar motio y lo reduzco todo al mínimo para poder
// mandar el tweet y que quepa en la memoria
// Version V4: Pruebo a almacenar cosas en SRAM en vez de en Flash. Pongo activar o desactivar envio de tweet poniendo
// en la URL tweet_on o tweet_off. Cuando se envia un tweet se pone a off automaticamene. Cada vez que se manda un comando
// se muestra la pagina index con el estado de los switches y la lista de ficheros.
// Version V5: He conectado el rele que permanecerá un intervalo de tiempo encendido desde que se enciende y así poder conectar
// una luz para que la cámara pueda sacar una foto nítida
// IMPORTANTE: He intentado poner todo el proyecto sobre Arduino Mega 2560 para terminar con los problemas de memoria
// pero no ha sido posible porque la versión 10 de
// la librería NewSoftSerial no funciona sobre Mega. He probado con la beta 11 de
// http://arduiniana.org/2011/01/newsoftserial-11-beta pero no he conseguido que funcione
// TODO: crear una cuenta de twitter especifica y habilitarla para envio de sms
// TODO: abrir puertos del PC para ver el Arduino
// TODO: posibilidad de borrar las fotografías.
// TODO: añadir opción para que pueda dispararse de manera remota una foto aunque no se haya detectado movimiento
// TODO: poner la cámara sobre unos servos de modo que puediera moverse su orientación de manera remota
//
// Cuando graba 99 fotos la nueva siempre se graba como 99, una y otra vez. Decido dejarlo así.
//
// Sobre Tiny Web Server http://www.webweavertech.com/ovidiu/weblog/archives/000484.html
// Para el envío de tweets, como es muy costoso en términos de memoria se utiliza una aplicación externa http://arduino-tweet.appspot.com
// Ethernet shield http://www.adafruit.com/products/201
Ejemplo de la pantalla con el índice de todas las fotos:
Código fuente CamaraTinyWebServerV5:
// -*- c++ -*-
// Author: Antonio García Figueras
// Date: Noviembre 2011
// Programa para controlar una microcámara que al detectar moviento active un relé, al que se puede conectar una bombilla,
// tome una foto y la guarde en la tarjeta de memoria SD que se colocaría en el ethernet shield. Seguidamente se enviaría un tweet.
// Foto con los circuitos necesarios en
// http://xp-dev.com/svn/arduino_antonio/trunk/C%C3%A1mara/Foto%20conexi%C3%B3n%20c%C3%A1mara%20a%20shiel%20ethernet%20y%20relay.jpg
// Este ethernet shield permitirá
// que el servidor web (Tiny web server) que he usado permita visualizar la lista de fotografías que se hayan ido almacenando en la tarjeta
// de memoria y que el usuario desde internet pueda visualizar cualquiera de ellas. También puede activar o desactiva la
// función de detectar movimiento de la cámara y el envío o no de tweets.
// He tenido que reducir al mínimo las cadenas de texto utilizadas pues estoy en el límite de la memoria del Arduino UNO
// Para que desde el navegador nos podamos descargar un fichero que ya esta en la tarjeta simplemente
// pondremos la ip del sitio seguido de /nombrearchivo Por ejemplo: http://192.168.1.177/IMAGE10.JPG
// Si Unicamente ponemos la ip sin nada detras nos mostrara la lista de los ficheros que contiene la tarjeta
// http://192.168.1.177/1 Activaría la detección de movimiento
// http://192.168.1.177/2 Desactivaría la detección de movimiento
// http://192.168.1.177/3 Activaría el envío de tweets
// http://192.168.1.177/4 Desactivaría el envío de tweets
//
// Version V2: Le pongo activar o desactivar Motion añadiendo en la URL motion_off o motion_on
// Version V3: He quitado muchos if, quito upload file, activar o desactivar motio y lo reduzco todo al mínimo para poder
// mandar el tweet y que quepa en la memoria
// Version V4: Pruebo a almacenar cosas en SRAM en vez de en Flash. Pongo activar o desactivar envio de tweet poniendo
// en la URL tweet_on o tweet_off. Cuando se envia un tweet se pone a off automaticamene. Cada vez que se manda un comando
// se muestra la pagina index con el estado de los switches y la lista de ficheros.
// Version V5: He conectado el rele que permanecerá un intervalo de tiempo encendido desde que se enciende y así poder conectar
// una luz para que la cámara pueda sacar una foto nítida
// IMPORTANTE: He intentado poner todo el proyecto sobre Arduino Mega 2560 para terminar con los problemas de memoria
// pero no ha sido posible porque la versión 10 de
// la librería NewSoftSerial no funciona sobre Mega. He probado con la beta 11 de
// http://arduiniana.org/2011/01/newsoftserial-11-beta pero no he conseguido que funcione
// TODO: crear una cuenta de twitter especifica y habilitarla para envio de sms
// TODO: abrir puertos del PC para ver el Arduino
// TODO: posibilidad de borrar las fotografías.
// TODO: añadir opción para que pueda dispararse de manera remota una foto aunque no se haya detectado movimiento
// TODO: poner la cámara sobre unos servos de modo que puediera moverse su orientación de manera remota
//
// Cuando graba 99 fotos la nueva siempre se graba como 99, una y otra vez. Decido dejarlo así.
//
// Sobre Tiny Web Server http://www.webweavertech.com/ovidiu/weblog/archives/000484.html
// Para el envío de tweets, como es muy costoso en términos de memoria se utiliza una aplicación externa http://arduino-tweet.appspot.com
// Ethernet shield http://www.adafruit.com/products/201
// Para el Tiny Web Server
#include <SPI.h>
#include <Ethernet.h>
#include <Flash.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <TinyWebServer.h>
// Para la camara
#include <VC0706.h>
#include <NewSoftSerial.h>
// Para Tweeter
#include <EthernetDNS.h>
#include <Twitter.h>
boolean file_handler(TinyWebServer& web_server);
boolean index_handler(TinyWebServer& web_server);
boolean tweetOn=false;
boolean isRelayOn=false;
long previousMillis = 0;
//Intervalo en milisegundos que permanecerá el relé encendido
long interval = 10000;
// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
#define chipSelect 4
// This is the camera pin connection. Connect the camera TX
// to pin 2, camera RX to pin 3
NewSoftSerial cameraconnection = NewSoftSerial(2, 3);
// pass the serial connection to the camera object
VC0706 cam = VC0706(&cameraconnection);
TinyWebServer::PathHandler handlers[] = {
// Work around Arduino's IDE preprocessor bug in handling /* inside
// strings.
//
// `put_handler' is defined in TinyWebServer
{"/1", TinyWebServer::GET, &motionOn_handler },
{"/2", TinyWebServer::GET, &motionOff_handler },
{"/3", TinyWebServer::GET, &tweetOn_handler },
{"/4", TinyWebServer::GET, &tweetOff_handler },
{"/", TinyWebServer::GET, &index_handler },
// {"/upload/" "*", TinyWebServer::PUT, &TinyWebPutHandler::put_handler },
{"/" "*", TinyWebServer::GET, &file_handler },
{NULL},
};
const char* headers[] = {
// "Content-Length",
// NULL
};
TinyWebServer web = TinyWebServer(handlers, headers);
//boolean has_filesystem = true;
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// Don't forget to modify the IP to an available one on your home network
byte ip[] = { 192, 168, 1, 177 };
// Your Token to Tweet (get it from http://arduino-tweet.appspot.com/)
Twitter twitter("353548191-qy3gHOQDgwxiKVW8bsRihE4rRTllZIkC4CFEdGDD");
void send_file_name(TinyWebServer& web_server, const char* filename) {
if (!filename) {
web_server.send_error_code(404);
// web_server << F("Could not parse URL");
} else {
TinyWebServer::MimeType mime_type
= TinyWebServer::get_mime_type_from_filename(filename);
web_server.send_error_code(200);
web_server.send_content_type(mime_type);
web_server.end_headers();
if (file.open(&root, filename, O_READ)) {
// Serial << F("Read file "); Serial.println(filename);
web_server.send_file(file);
file.close();
} else {
// web_server << F("Could not find file: ") << filename << "\n";
}
}
}
boolean file_handler(TinyWebServer& web_server) {
char* filename = TinyWebServer::get_file_from_path(web_server.get_path());
send_file_name(web_server, filename);
free(filename);
return true;
}
boolean tweetOn_handler(TinyWebServer& web_server){
tweetOn=true;
generaIndex(web_server);
return true;
}
boolean tweetOff_handler(TinyWebServer& web_server){
tweetOn=false;
generaIndex(web_server);
return true;
}
boolean motionOff_handler(TinyWebServer& web_server) {
// Serial.println("Recibida peticion de motion OFF");
cam.setMotionDetect(false);
generaIndex(web_server);
return true;
}
//
boolean motionOn_handler(TinyWebServer& web_server) {
// Serial.println("Recibida peticion de motion ON");
cam.setMotionDetect(true);
generaIndex(web_server);
return true;
}
boolean index_handler(TinyWebServer& web_server) {
// send_file_name(web_server, "INDEX.HTM");
// web_server.send_error_code(200);
// web_server.end_headers();
//// web_server << F("<html><body><h1>Hola. La tarjeta contiene los siguientes ficheros:</h1></body></html>\n");
// web_server << "<html><body>motion:";
// if (cam.getMotionDetect())
// web_server << "ON";
// else
// web_server << "OFF";
//
// web_server << "<br>tweet:";
// if (tweetOn)
// web_server << "ON";
// else
// web_server << "OFF";
//
// ListFiles(web_server, LS_SIZE);
// web_server << "</body></html>\n";
generaIndex(web_server);
return true;
}
void generaIndex(TinyWebServer& web_server){
web_server.send_error_code(200);
web_server.end_headers();
// web_server << F("<html><body><h1>Hola. La tarjeta contiene los siguientes ficheros:</h1></body></html>\n");
web_server << "<html><body>mot:";
if (cam.getMotionDetect())
web_server << "ON";
else
web_server << "OFF";
web_server << "<br>tw:";
if (tweetOn)
web_server << "ON";
else
web_server << "OFF";
ListFiles(web_server, LS_SIZE);
web_server << "</body></html>";
}
void ListFiles(TinyWebServer& web_server, uint8_t flags) {
// This code is just copied from SdFile.cpp in the SDFat library
// and tweaked to print to the client output in html!
dir_t p;
root.rewind();
web_server << "<ul>";
while (root.readDir(p) > 0) {
// done if past last used entry
if (p.name[0] == DIR_NAME_FREE) break;
// skip deleted entry and entries for . and ..
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;
// only list subdirectories and files
if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
// print any indent spaces
web_server << "<li><a href=\"";
for (uint8_t i = 0; i < 11; i++) {
if (p.name[i] == ' ') continue;
if (i == 8) {
web_server << ".";
}
web_server << p.name[i];
}
web_server << "\">";
// print file name with possible blank fill
for (uint8_t i = 0; i < 11; i++) {
if (p.name[i] == ' ') continue;
if (i == 8) {
web_server << ".";
}
web_server << p.name[i];
}
web_server << "</a>";
if (DIR_IS_SUBDIR(&p)) {
web_server << "/";
}
// print modify date/time if requested
if (flags & LS_DATE) {
root.printFatDate(p.lastWriteDate);
web_server << " ";
root.printFatTime(p.lastWriteTime);
}
// print size if requested
if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
web_server << " ";
web_server << p.fileSize;
}
web_server << "</li>";
}
web_server << "</ul>";
}
//void file_uploader_handler(TinyWebServer& web_server,
// TinyWebPutHandler::PutAction action,
// char* buffer, int size) {
// static uint32_t start_time;
// static uint32_t total_size;
//
// switch (action) {
// case TinyWebPutHandler::START:
// start_time = millis();
// total_size = 0;
// if (!file.isOpen()) {
// // File is not opened, create it. First obtain the desired name
// // from the request path.
// char* fname = web_server.get_file_from_path(web_server.get_path());
// if (fname) {
//// Serial << F("Creating ") << fname << "\n";
// file.open(&root, fname, O_CREAT | O_WRITE | O_TRUNC);
// free(fname);
// }
// }
// break;
//
// case TinyWebPutHandler::WRITE:
// if (file.isOpen()) {
// file.write(buffer, size);
// total_size += size;
// }
// break;
//
// case TinyWebPutHandler::END:
// file.sync();
//// Serial << F("Wrote ") << file.fileSize() << F(" bytes in ")
//// << millis() - start_time << F(" millis (received ")
//// << total_size << F(" bytes)\n");
// file.close();
// }
//}
void inicializaCamara(){
// Serial.println("VC0706 Camera test");
// Try to locate the camera
cam.begin();
// if (cam.begin()) {
//// Serial.println("Camera Found:");
// } else {
//// Serial.println("No camera found?");
// return;
// }
// Print out the camera version information (Realmente no es optional)
char *reply = cam.getVersion();
// if (reply == 0) {
//// Serial.print("Failed to get version");
// } else {
//// Serial.println("-----------------");
//// Serial.print(reply);
//// Serial.println("-----------------");
// }
// Set the picture size - you can choose one of 640x480, 320x240 or 160x120
// Remember that bigger pictures take longer to transmit!
// cam.setImageSize(VC0706_640x480); // biggest
// cam.setImageSize(VC0706_320x240); // medium
cam.setImageSize(VC0706_160x120); // small
// You can read the size back from the camera (optional, but maybe useful?)
// uint8_t imgsize = cam.getImageSize();
// Serial.print("Image size: ");
// if (imgsize == VC0706_640x480) Serial.println("640x480");
// if (imgsize == VC0706_320x240) Serial.println("320x240");
// if (imgsize == VC0706_160x120) Serial.println("160x120");
// Motion detection system can alert you when the camera 'sees' motion!
cam.setMotionDetect(true); // turn it on
//cam.setMotionDetect(false); // turn it off (default)
// You can also verify whether motion detection is active!
// Serial.print("Motion detection is ");
// if (cam.getMotionDetect())
//// Serial.println("ON");
// else
// Serial.println("OFF");
}
void tomaFoto(){
// Serial.println("Motion!");
cam.setMotionDetect(false);
cam.takePicture();
// if (! cam.takePicture())
//// Serial.println("Failed to snap!");
// else
// Serial.println("Picture taken!");
char filename[13];
strcpy(filename, "IMAGE00.JPG");
for (int i = 0; i < 100; i++) {
filename[5] = '0' + i/10;
filename[6] = '0' + i%10;
// create if does not exist, do not open existing, write, sync after write
if (! root.exists(filename)) {
break;
}
}
SdFile imgFile;
imgFile.open(&root, filename, O_CREAT | O_WRITE | O_TRUNC);
uint16_t jpglen = cam.frameLength();
// Serial.print(jpglen, DEC);
// Serial.println(" byte image");
//
// Serial.print("Writing image to "); Serial.print(filename);
while (jpglen != 0) {
// read 64 bytes at a time;
// cambio a 32 bytes el buffer para que funciones
uint8_t *buffer;
uint8_t bytesToRead = min(32, jpglen);
buffer = cam.readPicture(bytesToRead);
imgFile.write(buffer, bytesToRead);
//Serial.print("Read "); Serial.print(bytesToRead, DEC); Serial.println(" bytes");
jpglen -= bytesToRead;
}
imgFile.close();
// Serial.println("...Done!");
cam.resumeVideo();
cam.setMotionDetect(true);
}
void enviaTweet(){
if (twitter.post("B")){
twitter.wait();
}
}
void relayOn(){
digitalWrite(6, HIGH);
isRelayOn=true;
previousMillis = millis();
}
void relayOff(){
digitalWrite(6, LOW);
isRelayOn=false;
}
void setup() {
// Serial.begin(9600);
// Serial << F("Free RAM: ") << FreeRam() << "\n";
// initialize the SD card
// Serial << F("Setting up SD card...\n");
pinMode(10, OUTPUT); // set the SS pin as an output (necessary!)
digitalWrite(10, HIGH); // but turn off the W5100 chip!
card.init(SPI_FULL_SPEED, 4);
// if (!card.init(SPI_FULL_SPEED, 4)) {
//// Serial << F("card failed\n");
// has_filesystem = false;
// }
// initialize a FAT volume
volume.init(&card);
// if (!volume.init(&card)) {
//// Serial << F("vol.init failed!\n");
// has_filesystem = false;
// }
root.openRoot(&volume);
// if (!root.openRoot(&volume)) {
//// Serial << F("openRoot failed");
// has_filesystem = false;
// }
// if (has_filesystem) {
// // Assign our function to `upload_handler_fn'.
// TinyWebPutHandler::put_handler_fn = file_uploader_handler;
// }
// Serial << F("Setting up the Ethernet card...\n");
Ethernet.begin(mac, ip);
// Start the web server.
// Serial << F("Web server starting...\n");
web.begin();
// Serial << F("Ready to accept HTTP requests.\n");
inicializaCamara();
pinMode(6, OUTPUT);
}
void loop() {
// if (has_filesystem) {
web.process();
// }
if (cam.motionDetected()) {
tomaFoto();
relayOn();
if (tweetOn){
enviaTweet();
// En cuanto envio un tweet desactivo el envío
tweetOn=false;
}
}
if(isRelayOn && (millis()-previousMillis > interval)) {
//Apagamos el relay si ya se ha sobrepasado encedido el intervalo estipulado
relayOff();
}
}
No hay comentarios:
Publicar un comentario