Created
August 5, 2013 10:43
-
-
Save rat/6155004 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Arduino Gateway SMS | |
* Version 1.0 Jul, 2013 | |
* Copyright 2013 Renato Tavares | |
* | |
* Modified by Renato Tavares <dr.renatotavares@gmail.com> to support ethernet shield and GPRS Shield. | |
* | |
* Complete Web Server to sending SMS with Arduino. | |
*/ | |
// Incluindo bibliotecas necessárias | |
#include <SD.h> | |
#include <SPI.h> | |
#include <Ethernet.h> | |
#include <SoftwareSerial.h> | |
//Arduino Mega | |
//#define rxPin 50 | |
//#define txPin 51 | |
// Define as variáveis para simular o multitasking | |
unsigned long UpdateCycle = 30000; | |
unsigned long UpdateLastMillis = 0; | |
// Ponteiro para o meu arquivo no SD Card | |
File myFile; | |
// Define os dados da rede necessarios para o Ethernet Shield | |
byte mac[] = { | |
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; | |
byte ip[] = { | |
192,168,1,177}; | |
// Ethernet Server escutando na porta 80 | |
EthernetServer server(80); | |
// Inicia a biblioteca SoftwareSerial | |
// Jumpers no RX 3 e DX 2 | |
SoftwareSerial mySerial(2, 3); | |
//SoftwareSerial mySerial(rxPin, txPin); | |
/** | |
* Função de configuração do Arduino. | |
* | |
* Função obrigatória do Arduino que realiza a iniciação das | |
* variáveis e configurações que serão usadas no decorrer do código. | |
* | |
*/ | |
void setup() | |
{ | |
Serial.begin(19200); | |
mySerial.begin(19200); | |
Ethernet.begin(mac, ip); | |
pinMode(10, OUTPUT); | |
if (!SD.begin(4)) { | |
Serial.println("initialization failed!"); | |
return; | |
} | |
Serial.println("SD iniciado"); | |
} | |
/** | |
* Loop principal do programa. | |
* | |
* Função obrigatória do Arduino, responsável pelo loop infinito | |
* que realiza o processamento dos dados. | |
* | |
*/ | |
void loop() | |
{ | |
if(cycleCheck(&UpdateLastMillis, UpdateCycle)) { | |
Serial.println("Processando..."); | |
get_sms_data(); | |
Serial.println("Processado!!!!"); | |
UpdateNoIP(); | |
} | |
client_request(); | |
} | |
/** | |
* Salva o pedido do cliente no SD Card. | |
* | |
* Toda vez que um pedido para envio de SMS chega ao Arduino | |
* ele primeiro é salvo no SD card e só posteriormente enviado | |
* de fato. Isso é útil para responder rapidamente vários pedidos | |
* e enviar as mensagens quando o Arduino está folgado. | |
* | |
*/ | |
void save_sms_data(char data[]) | |
{ | |
myFile = SD.open("sms.txt", FILE_WRITE); | |
if (myFile) { | |
myFile.print(data); | |
myFile.print("\n"); | |
myFile.close(); | |
Serial.println("Gravado com sucesso"); | |
} | |
else { | |
Serial.println("error opening for save sms.txt"); | |
return; | |
} | |
} | |
/** | |
* Recupera o texto vindo do cartão SD e envia o SMS. | |
* | |
* Todas as mensagens são salvas no SD Carda antes de | |
* serem enviadas, isso garante (ou deveria) velocidade | |
* pois se um ou mais clientes solicitarem o envio do SMS | |
* o Arduino demora responder e a requisição fala. Já escrever | |
* no SD Carda é rápido, basta posteriomente eu ler os dados gravados | |
* e enviar os SMS's quando o Arduino não estiver atendendo um cliente. | |
* | |
* @TODO Criar algoritimo que impede receber novos pedidos enquando envia os SMS's. | |
* @TODO Criar um resposta HTTP para sucesso e outra para falha. (Se possível ;.;) | |
* @TODO Confirmar se o Arduino garante que o arquivo só possa ser escrito por um processo. | |
* | |
*/ | |
void get_sms_data() | |
{ | |
if(SD.exists("sms.txt")){ | |
myFile = SD.open("sms.txt"); | |
char mensagem[161]; | |
char numero[15]; | |
byte pointer = 0; | |
byte foundPipe = 0; | |
if (myFile) { | |
while (myFile.available()) { | |
char c = myFile.read(); | |
if(c != '|' && foundPipe == 0){ | |
mensagem[pointer] = c; | |
pointer++; | |
mensagem[pointer] = '\0'; | |
} | |
else if(c == '|' && foundPipe == 0){ | |
foundPipe = 1; | |
pointer = 0; | |
} | |
else if(foundPipe == 1 && c != '|' && c != '\n'){ | |
numero[pointer] = c; | |
pointer++; | |
numero[pointer] = '\0'; | |
} | |
else if(foundPipe == 1 && c == '\n'){ | |
pointer = 0; | |
foundPipe = 0; | |
send_sms(mensagem, numero); | |
} | |
} | |
myFile.close(); | |
SD.remove("sms.txt"); | |
} | |
else{ | |
// Erro ao abrir o arquivo | |
Serial.println("Erro ao abrir o arquivo"); | |
return; | |
} | |
} | |
else{ | |
// Arquivo não existe | |
Serial.println("Arquino nao existe"); | |
return; | |
} | |
} | |
/** | |
* Função para realizar o envio de SMS. | |
* | |
* A GPRS Shield utilizar AT commands para funcionar, a documentação | |
* da shield e os comendos podem ser encontrados na página do | |
* fornecedor: http://www.elecfreaks.com/wiki/index.php?title=EFCom_GPRS/GSM_Shield | |
* | |
* Realizei backup da documentação no Google Drive | |
*/ | |
void send_sms(char msg[], char phone[]) | |
{ | |
mySerial.print("\r\n"); | |
delay(1100); | |
mySerial.print("AT+CMGF=1\r\n"); | |
delay(1100); | |
mySerial.print("AT+CMGS=\""); | |
mySerial.print(phone); | |
mySerial.print("\"\r\n"); | |
delay(1100); | |
mySerial.print(msg); | |
mySerial.print("\r\n"); | |
delay(1100); | |
mySerial.write(26); | |
delay(1100); | |
} | |
/** | |
* Função para monitorar o pedido vindo do cliente. | |
* | |
* Recebe a requisição vinda do cliente sempre no formato: | |
* | |
* mensagem|telefone | |
* | |
* Caso não obedeça esse padrão, a mensagem não será enviada ao cliente. | |
*/ | |
void client_request() | |
{ | |
EthernetClient client = server.available(); | |
if (client) { | |
char mensagem[175]; | |
byte pointer = 0; | |
while (client.connected()) { | |
if (client.available()) { | |
char c = client.read(); | |
mensagem[pointer] = c; | |
pointer++; | |
mensagem[pointer] = '\0'; | |
} | |
} | |
//desconecta o cliente | |
client.stop(); | |
//recebeu a msg do PHP grava no SD | |
Serial.println(mensagem); | |
save_sms_data(mensagem); | |
} | |
} | |
/** | |
* Função para simular o multitasking. | |
* | |
* Função que verifica a diferença entre o tempo atual | |
* e o tempo do último ciclo, se essa diferença for maior | |
* ou igual a constante de ciclo, realiza a tarefa desejada. | |
* | |
* Outras informações em http://arduino.cc/forum/index.php/topic,5686.msg44073.html | |
* | |
*/ | |
boolean cycleCheck(unsigned long *UpdateLastMillis, unsigned long UpdateCycle) { | |
unsigned long currentMillis = millis(); | |
if(currentMillis - *UpdateLastMillis >= UpdateCycle) { | |
*UpdateLastMillis = currentMillis; | |
return true; | |
} | |
else{ | |
return false; | |
} | |
} | |
void UpdateNoIP(){ | |
EthernetClient client; | |
if(client.connect("dynupdate.no-ip.com", 80)){ | |
Serial.println("Conectando com No-IP"); | |
client.println("GET /nic/update?hostname=freesms2.hopto.org HTTP/1.0"); | |
client.println("Host: dynupdate.no-ip.com"); | |
client.println("Authorization: Basic Senha em Base64"); | |
client.println("User-Agent: Arduino Client/1.0 dr.renatotavares@gmail.com"); | |
client.println(); | |
while(client.connected()){ | |
// stay in this loop until the server closes the connection | |
while(client.available()){ | |
// The server will not close the connection until it has sent the last packet | |
// and this buffer is empty | |
char read_char = client.read(); | |
Serial.write(read_char); | |
} | |
} | |
// close your end after the server closes its end | |
client.stop(); | |
Serial.println("Conexão com No-IP fechada"); | |
} | |
else{ | |
Serial.println("Falha na Conexão"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment