Quantcast
Channel: AUTOMALABS
Viewing all 63 articles
Browse latest View live

Códigos do controle remoto do receptor de satélite GVT/VIVO

$
0
0

Até onde sei todos os aparelhos da GVT usam o mesmo controle remoto e a VIVO ao comprar a GVT só mudou o nome.

Protocolo RC6 de 36 bits

O quinto byte alterna (é um protocolo Philips) entre “A” (00001010) e “2” (00000010)

Power			0x8070A60C
MUTE			0x8070260D
1			0x8070A601
2			0x80702602
3			0x8070A603
4			0x80702604
5			0x8070A605
6			0x80702606
7			0x8070A607
8			0x80702608
9			0x8070A609
0			0x80702600
Source			0x8070A68B
@			0x807026FB
Menu			0x8070A654
Sair			0x80702683
UP			0x8070A658
DOWN			0x80702659
LEFT			0x8070A65A
RIGHT			0x8070265B
OK			0x8070A65C
Voltar			0x807026A9
Guia			0x8070A6CC
Opcoes(laranja)		0x807026A3
Info			0x8070A60F
GVT			0x807026A2
VOL+			0x8070A610
VOL-			0x80702611
CH+			0x8070A61E
CH-			0x8070261F
RED			0x8070A66D
GREEN			0x8070266E
YELLOW			0x8070A66F
BLUE			0x80702670
REW			0x8070A62B
Stop			0x8070A631
Play/Pause		0x8070262C
FFW			0x8070A628
?1			0x807026F0
?2			0x8070A6A4
REC			0x80702637
?4			0x8070A6A5
Controle_remoto_GVT_DSC02639_640_automalabs.com.br

Códigos do controle remoto do receptor ISDB-T Aquário DTV-6000

$
0
0

Este controle não apenas é parecido com o do receptor ISDB-T comercializado pela Infokit. Os códigos são os mesmos.

Protocolo NEC de 32bits

Power            0xFF9A65
MUTE            0xFF9867
EPG            0xFFB24D
Info            0xFF708F
TTX            0xFFB04F
Audio            0xFF8A75
PVR            0xFF48B7
Subtitle        0xFF8877
Menu            0xFFA25D
Exit            0xFFA05F
UP/CH+            0xFF609F
DOWN/CH-        0xFF6897
LEFT/VOL-        0xFF5AA5
RIGHT/VOL+        0xFFD827
ENTER/OK        0xFF58A7
Favoritos        0xFFAA55
TV/Radio        0xFFA857
Recall            0xFFC837
GOTO            0xFFE817
1            0xFF4AB5
2            0xFF0AF5
3            0xFF08F7
4            0xFF6A95
5            0xFF2AD5
6            0xFF28D7
7            0xFF728D
8            0xFF32CD
9            0xFF30CF
0            0xFFF00F
REW            0xFF52AD
FWD            0xFF12ED
Prev            0xFF10EF
Next            0xFFD02F
Play            0xFF629D
Pause            0xFF22DD
Stop            0xFF20DF
Repeat            0xFFE01F
RED            0xFF42BD
GREEN            0xFF02FD
YELLOW            0xFF00FF
BLUE            0xFFC03F

 

 

Códigos do controle remoto lennox RC-109

$
0
0

Este remoto é usado em uma TV Lenoxx cujo modelo ainda não sei.

Protocolo NEC 32 bits

Power			FF50AF
MUTE			FF9867
1			FF807F
2			FF40BF
3			FFC03F
4			FF20DF
5			FFA05F
6			FF609F
7			FFE01F
8			FF10EF
9			FF906F
-/--			FFA25D
0			FF00FF
PREVIOUS		FF02FD
SOURCE			FF6897
MENU			FFF807
UP			FFD02F
DOWN			FF708F
LEFT			FF8877
RIGHT			FF08F7
ENTER			FFB04F
SLEEP			FF58A7
EXIT			FFD827
CH+			FFA857
CH-			FF18E7
VOL+			FF827D
VOL-			FF42BD
DISPLAY			FF38C7
P.MODE			FF22DD
S.MODE			FF30CF

 

 

Códigos do controle remoto do receptor de satélite OI TV HD

$
0
0

Protocolo RC6 de 36 bits

 
left      0x8072245A 
right     0x8072245B 
up        0x80722458 
down      0x8072A459 
ok        0x8072A45C 
vol+      0x8072A410 
vol-      0x8072A411 
ch+       0x8072A41E 
ch-       0x8072241F 
mute      0x8072A40D 
return    0x8072A4A9 
info      0x8072240F 
VDD       0x807224F0 
APP       0x807224FD 
DVR       0x807224F1 
1         0x80722401
2         0x8072A402
3         0x80722403
4         0x8072A404
5         0x80722405
6         0x8072A406
7         0x80722407
8         0x80722408
9         0x8072A409
0         0x80722400
Legenda   0x8072A44B 
Audio     0x8072A4A1 
Menu      0x80722454 
Guia      0x8072A4CC 
POWER     0x8072240C 
Oi TV     0x8072A49F 
Sair      0x8072A483 
Rew       0x8072A42B 
STOP      0x80722431 
PLAY      0x8072242C 
FWD       0x80722428 
BACK      0x8072A44D 
REC       0x8072A437 
Pause     0x80722430 
JUMP      0x8072A44C 
RED       0x8072246D 
Green     0x8072A46E 
Yellow    0x8072246F 
Blue      0x80722470
 Controle_Remoto_OI_small_automalabs.com.br

 

Códigos do controle remoto do receptor de satélite OI TV SD

$
0
0

Este controle remoto não tem a palavra “HD”. Os códigos do receptor HD são estes.

Protocolo RC6 de 36 bits

left      0x8072265A 
right     0x8072265B 
up        0x80722658 
down      0x80722659 
ok        0x8072265C 
vol+      0x80722610 
vol-      0x80722611 
ch+       0x8072261E 
ch-       0x8072261F 
mute      0x8072260D 
return    0x807226A9 
info      0x8072260F 
1         0x80722601
2         0x80722602
3         0x80722603
4         0x80722604
5         0x80722605
6         0x80722606
7         0x80722607
8         0x80722608
9         0x80722609
0         0x80722600
Legenda   0x8072264B 
Audio     0x807226A1 
Menu      0x80722654 
Guia      0x807226CC 
POWER     0x8072260C 
Oi TV     0x8072269F 
Sair      0x80722683 
Rew       0x8072262B 
STOP      0x80722631 
PLAY      0x8072262C 
FWD       0x80722628 
REC       0x80722637 
Pause     0x80722630

 

Códigos do controle remoto do receptor de satélite ASAMÉRICA

$
0
0

Nota: Eu não anotei o modelo do receptor onde esse controle funcionava. Não sei se funciona com todos ASAMÉRICA.

Protocolo NEC de 32 bits

FE7887		POWER
FE5AA5		V-MODE
FE3AC5		MUTE
FEF00F		SAT
FED02F		TV/AV
FE728D		ZOOM
FE629D		SLEEP
FE58A7		1
FEF807		2
FE1AE5		3
FE6897		4
FED827		5
FE2AD5		6
FE48B7		7
FEE817		8
FE0AF5		9
FEC837		0
FE708F		TV/RADIO
FE38C7		<-PR
FEE01F		FAV
FE9A65		PAUSE
FE32CD		PAGE+
FE18E7		PAGE-
FEC03F		PR+
FE7A85		PR-
FE40BF		VOL-
FE02FD		VOL+
FEFA05		OK/LIST
FEFA05		MENU
FE22DD		EXIT
FE609F		INFO
FE50AF		EPG
FE926D		FIND/RED
FE8A75		V-FORMAT/GREEN
FEA25D		TXT/YELLOW
FEB24D		LR/BLUE
FEBA45		RECORD
FEDA25		PLAY
FED22D		STOP
FEF20D		SHIFT
FECA35		REW
FEE21D		FF
FE20DF		SLOWREW
FE08F7		SLOWFF

 

Códigos do controle remoto do DVR ControlBR iDVR CBR-ST16H

$
0
0

controle_remoto_DVR_ControlBR_iDVR_CBR-ST16H_DSC02640_640_automalabs.com.br

Protocolo NEC de 32 bits

MULT			0xFF21DE
Search			0xFF11EE
1			0xFFE11E
2			0xFF619E
3			0xFFA15E
4			0xFFD12E
5			0xFF51AE
6			0xFF916E
7			0xFFF10E
8			0xFF718E
9			0xFFB14E
0			0xFF49B6
ESC			0xFF6996
-/--			0xFF29D6
UP			0xFFA956
DOWN			0xFF59A6
LEFT			0xFFD926
RIGHT			0xFF9966
Menu			0xFF7986
ADD			0xFFE916
FN			0xFF8976
SlowRew			0xFF19E6
SlowFW			0xFF41BE
FWD			0xFF39C6
Prev			0xFF09F6
Next			0xFFC13E
Play/Pause		0xFF31CE
REC			0xFFC936

 

Como testar o envio de notificações para o Pushbullet

$
0
0

Neste texto eu vou usar o complemento Postman do Google Chrome para enviar notificações para dispositivos com o Pushbullet configurado para a minha conta. Enviar notificações para outras pessoas será abordado em outra oportunidade.

Você vai precisar do Access Token que é obtido na sua conta em Settings -> Account -> Create Access Token

Digamos que seu AccessToken seja

o.XtZT2TyDFKITdygNvFQivViC9r4ojyMV

Com o Postman:

Selecione “POST” e coloque o endereço “https://api.pushbullet.com/v2/pushes”

Chrome_Postman_Pushbullet_detalhe1_automalabs.com.br

Em Headers, acrescente um key de nome Authorization com o conteúdo

Bearer o.XtZT2TyDFKITdygNvFQivViC9r4ojyMV

Chrome_Postman_Pushbullet_detalhe2_automalabs.com.br

Em Body, selecione “raw” e na caixa de seleção à direita escolha JSON

Cole na caixa diretamente abaixo o texto a seguir:

{“type”: “note”, “title”: “Enviado pelo Postman”, “body”: “Sucesso!”}

Chrome_Postman_Pushbullet_detalhe3_automalabs.com.br

Você verá que em Headers foi acrescentado um key de nome “Content-Type” e valor “application/json”

Chrome_Postman_Pushbullet_detalhe4_automalabs.com.br

Clique em SEND. Você deverá receber uma resposta do tipo:

{
"active": true,
"iden":fRghtfgSWgssjAl8kzYqE8",
"created": 1494288758.0494468,
"modified": 1494288758.0577545,
"type": "note",
"dismissed": false,
"direction": "self",
"sender_iden": "fRghtfgSW",
"sender_email": "xxxxxxxxxxxxx@gmail.com",
"sender_email_normalized": "xxxxxxxxxxxxxx@gmail.com",
"sender_name": "Jefferson Ryan",
"receiver_iden": "fRghtfgSW",
"receiver_email": "xxxxxxxxxxxxx@gmail.com",
"receiver_email_normalized": "xxxxxxxxxxxxxx@gmail.com",
"title": "Enviado pelo Postman",
"body": "Sucesso!"
}

E seus dispositivos conectados à mesma conta deverão receber a notificação

Se a resposta for do tipo “Invalid Token” como esta:

{
"error": {
"code": "invalid_access_token",
"type": "invalid_request",
"message": "Access token is missing or invalid.",
"cat": "(=^???^)y="
},
"error_code": "invalid_access_token"
}

e você tiver certeza de que o Token está certo, experimente limpá-lo de caracteres estranhos (invisíveis).
Para isso você pode colar o Access Token no notepad e salvar como ANSI. Se for esse mesmo problema você verá uma mensagem sobre a conversão. Confirme e o Token já deverá estar limpo.

Porém essa “limpeza” às vezes dá mais trabalho. Eu notei que a versão anterior do Postman, quando ainda se chamava “Postman REST client” não tem esse problema.


Cuidado ao usar o ESP8266 no modo AP_STA

$
0
0

Certas operações podem falhar silenciosamente nesse modo porque duas redes são criadas: a do AP e a do STA.

Por exemplo, se o ESP8266 estiver conectado a um roteador WiFi na sua rede (modo STA) e estiver com o modo AP habilitado, se o ESP8266 enviar um broadcast UDP para 255.255.255.255 esse broadcast não vai ser transmitido para a sua rede e sim para a rede criada pelo AP.

Mas se você mandar um broadcast para o endereço de broadcast da sua sub-rede, funciona, porque aí a biblioteca UDP sabe para onde mandar.

Por exemplo, se sua rede for da faixa 10.0.0.x:

resultado=udp.beginPacket(IPAddress(255, 255, 255, 255), 2391); //Não funciona

resultado=udp.beginPacket(IPAddress(10, 0, 0, 255), 2391); //Funciona mesmo com o AP habilitado

Claro, há situações em que mandar um broadcast para a sub-rede não é o bastante, pois você pode estar procurando o ESP8266 em outra sub-rede e não vai receber a mensagem. No momento eu não conheço outro jeito que não seja desligar o AP para enviar o broadcast.

Como converter comandos no formato Pronto Hex para o formato da irLib

$
0
0

No momento eu vou apenas mostrar como se faz para comandos NEC.

No RemoteCentral você vai encontrar muitos códigos de controle remoto infravermelho, mas num formato difícil de armazenar na limitada memória do Arduino: O Pronto Hex. Esse formato tem a vantagem de descrever completamente como é o sinal transmitido, mas é muito inconveniente.  Vou tomar por base os comandos de TV Samsung.

Por exemplo, vamos decodificar o comando discreto para selecionar a porta HDMI4:

Device Code: 7.7 Function: 197HDMI 4 (SIDE)
0000 006D 0000 0022 00AC 00AB 0015 0041 0015 0041 0015 0041 0015 0016 0015 0016 0015 0016 0015 0016 0015 0016 0015 0041 0015 0041 0015 0041 0015 0016 0015 0016 0015 0016 0015 0016 0015 0016 0015 0041 0015 0016 0015 0041 0015 0016 0015 0016 0015 0016 0015 0041 0015 0041 0015 0016 0015 0041 0015 0016 0015 0041 0015 0041 0015 0041 0015 0016 0015 0016 0015 0689

Os primeiros seis valores podem ser ignorados, porque são parte do protocolo NEC.

0000 006D 0000 0022 00AC 00AB

O código mesmo só começa a partir do sétimo valor e devem ser organizados em grupos de dois. Cada grupo que tenha dois números iguais ou próximos é um “0”. Cada uma cujo segundo valor seja cerca do dobro do primeiro é um “1”

0015 0041 = 1
0015 0041 = 1
0015 0041 = 1
0015 0016 = 0
0015 0016 = 0
0015 0016 = 0
0015 0016 = 0
0015 0016 = 0
0015 0041 = 1
0015 0041 = 1
0015 0041 = 1
0015 0016 = 0
0015 0016 = 0
0015 0016 = 0
0015 0016 = 0
0015 0016 = 0
0015 0041 = 1
0015 0016 = 0
0015 0041 = 1
0015 0016 = 0
0015 0016 = 0
0015 0016 = 0
0015 0041 = 1
0015 0041 = 1
0015 0016 = 0
0015 0041 = 1
0015 0016 = 0
0015 0041 = 1
0015 0041 = 1
0015 0041 = 1
0015 0016 = 0
0015 0016 = 0
0015 0689

Os dois últimos grupos são ignorados porque são a finalização do protocolo.

O código é 11100000111000001010001101011100 ou E0E0A35C

Veja a minha lista de comandos discretos para TVs Samsung.

Códigos discretos de controle remoto para TVs Samsung

$
0
0

Códigos ou comandos “discretos” são comandos cujo resultado não depende do atual estado do aparelho. Por exemplo, quando você manda um comando “Power” para uma TV, esse comando pode ser “Power On” ou “Power Off”, dependendo do estado atual da TV. Se a TV já estiver ligada e você mandar um comando Power querendo ligá-la, vai desligar.

Então para ter certeza de que você vai ligar quando quer ligar, precisa do código discreto de PowerON da TV. Códigos discretos são essenciais  para uma automação sem falhas.

Convertendo os códigos no formato Pronto Hex publicados no RemoteCentral usando a informação que dei no post anterior, chegamos a essa lista:

"E0E019E6" : "PowerOFF",
"E0E09966" : "PowerON",
"E0E09768" : "HDMI1",
"E0E07D82" : "HDMI2",
"E0E043BC" : "HDMI3",
"E0E0A35C" : "HDMI4",
"E0E09669" : "PC",
"E0E021DE" : "AV1",
"E0E0D728" : "AV2",
"E0E0619E" : "Component1",
"E0E011EE" : "Component",
"E0E0D827" : "_TV",
"E0E0DE21" : "_Cable",
"E0E07E81" : "_DVD",
"E0E0FE01" : "_STB",
"E0E05EA1" : "_VCR",
"E0E027D8" : "Aspect_16:9",
"E0E0C738" : "Aspect_4:3",
"E0E047B8" : "Aspect_Panorama",
"E0E0CA35" : "Aspect_Zoom1",
"E0E08778" : "Aspect_Zoom2",
"E0E0BD42" : "P._Mode_Dynamic",
"E0E07B84" : "P._Mode_Movie1",
"E0E0BB44" : "P._Mode_Movie2",
"E0E0FB04" : "P._Mode_Standard",
"E0E0D42B" : "Sound_Mode",
"E0E0D12E" : "Toggle Active Input",

 

Não há garantia de que todos os códigos funcionem no seu modelo Samsung e eu só testei até agora PowerOn e PowerOff.

Como obter dispositivo e função de um código de controle remoto NEC

$
0
0

Eu me deparei com esse problema ao chegar a essa página do RemoteCentral que lista os comandos como sendo compostos de dispositivo, sub-dispostitivo e função.

Depois eu me deparei com esta outra que faz o mesmo.

Por exemplo, o código para Power é descrito como:
Protocol NECx2, device 7, subdevice 7, OBC 2

Mas de onde vem isso? Eu sempre decodifiquei esse código como sendo E0E040BF. Como um número tão complexo esconde apenas os números 7, 7 e 2?

Eu encontrei a resposta ao analisar o funcionamento do programa SamsungBlinkie para Arduino

O código hexadecimal é dividido em três partes (as duas primeiras em conjunto formam o chamado “endereço”):

E0 -> dispositivo 7
E0 -> sub-dispositivo 7
40BF -> função 2

Vendo esses números em binário a coisa começa a fazer sentido.

E0 = 11100000. Note que se você espelhar esse número, vira 00000111, que é 7. Já sabemos então de onde vem o dispositivo e o sub-dispositivo.

A função é codificada de forma ainda mais confusa, mas se você olhar em binário rapidamente entende.

40 = 01000000 
BF = 10111111

O primeiro byte corresponde a um 2 binário espelhado e o segundo byte é uma inversão bit a bit do primeiro e funciona como um “checksum” para que o dispositivo tenha certeza de que leu corretamente.

Note que a Samsung usa um código NEC estendido. Nos códigos NEC tradicionais ou a segunda parte do endereço também é um checksum da primeira ou não existe segunda parte no endereço.

Use o browser para debugar seu projeto que usa HTTP

$
0
0

Na maioria das vezes você não precisa instalar um proxy ou nada mais complicado para ver como está se comportando seu projeto. No Chrome, por exemplo, tecle F12 para abrir as ferramentas de desenvolvedor e clique na aba “network” (rede). Daí “visite” o seu projeto. A cada clique que você der o Chrome vai mostrar que arquivos (CSS, imagens, javascript, etc) foram requisitados, que tamanho tinham, quanto tempo levou, quais não chegaram, a ordem das operações, etc.

Como usar I2C no ESP8266 e especificamente no ESP-01

$
0
0

Usando a IDE Arduino com Board ESP8266 é realmente muito simples. Não é preciso usar uma biblioteca I2C específica como é o caso de rede e seus programas já existentes devem funcionar exceto por um detalhe: você precisa especificar na inicialização da biblioteca Wire os pinos que você está usando para I2C no ESP8266.

Wire.begin(SDApin, SCLpin);

No ESP-01 você provavelmente vai ter que usar GPIO0 e GPIO2, por isso a inicialização fica assim:

Wire.begin(0, 2);

Em todos os casos você deve colocar resistores de pullup de 4k7 nos GPIO que você escolheu para I2C.

ESP8266: Como fazer um atualizador para DDNS Cloudflare

$
0
0

Eu não sou programador. Tudo o que garanto é que nas condições certas o programa funciona.

Correções e aperfeiçoamentos são bem-vindos.

Você precisa de:

Preencha os dados da sua rede sem fio e da sua conta Cloudflare e faça o upload. Se tudo estiver certo o procedimento do programa será o seguinte:

Ao inicializar:

  • Verifica o IP registrado para o host na sua conta Cloudflare;
  • Verifica com checkip.dyndns.org qual o seu IP externo atual;
  • Se forem diferentes atualiza a sua conta Cloudflare;
  • Guarda o IP para não precisar mais consultar a conta;

A cada 10 minutos

  • Verifica com checkip.dyndns.org qual o seu IP externo atual;
  • Compara com o ip armazenado e atualiza sua conta se forem diferentes;

Em caso de erro o programa reduz o intervalo entre checagens para 2 minutos. Retorna a 10 minutos após o primeiro sucesso.

 

A melhorar:

  • As rotinas de parse ainda são uma gambiarra;
  • Não testei se minhas checagens de erro realmente funcionam;
  • Com mais alguns GETs e parses JSON é possível obter o zone_id e o host_id a partir do host_name. Isso simplifica a vida de quem não sabe obter essas informações.

/*
 * Cloudflare DDNS Updater for ESP8266
 * Jefferson Ryan - automalabs.com.br 
 * Testado com IDE v1.8.1 e ESP8266 Core v2.3.0
 */

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <Ticker.h>

Ticker tick;

// Você precisa preencher estes valores ========================================================
//sua rede sem fio
const char* ssid = "";
const char* password = "";

//cloudflare
const String zone_id = "";
const String host_id = ""; 
const String host_name = "";
const String login_email = "";
const String api_key = "";  
//================================================================================================



const char* cloudflare_host = "api.cloudflare.com";
//const String user_agent="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0";
const String user_agent="ESP8266_DDNS_Updater";  //A Cloudflare exige um user_agent. É educado não mentir se não for indispensável. 
const int httpsPort = 443;

char ipservice[] = "checkip.dyndns.com";

//Obtido através de debug. É diferente do exibido pelo browser
//Precisará ser atualizado manualmente quando o certificado expirar
const char* cloudflare_host_fingerprint = "6F 1F FB 38 B9 49 03 1E 84 AF DC 48 C8 81 84 45 1A 19 6F 70";


  WiFiClientSecure secureClient;
  WiFiClient UnsecureClient;
  DynamicJsonBuffer jsonBuffer;

  String ipExterno;
  String ipRegistrado;
  String ipAnterior;
  boolean refresh=false;
  const int maxIntervaloChecagens=10;
  const int minIntervaloChecagens=2;
  int minutos=0;
  int intervaloChecagens=maxIntervaloChecagens;

void oneMinute() {

  //oneMinute é uma callback. Executar algo complexo ("blocking") pode levar a resets do ESP8266
  minutos++;
  if (intervaloChecagens-minutos<1){ 
    minutos=0;
    refresh=true;
  }
  else{

    int MinutosRestantes=intervaloChecagens-minutos;
    Serial.print(MinutosRestantes);
    Serial.println(" minutos para proxima checagem");
    
  }

  
}  

boolean GETMyIP(){
  boolean result=true;
  Serial.print("Conectando a ");
  Serial.println(ipservice);
  if (!UnsecureClient.connect(ipservice, 80)) {
    Serial.println("Falha na conexao.");
    result=false;
    return result;
  }

 
  String url = "/";
  UnsecureClient.print("GET " + url + " HTTP/1.1\n");
  UnsecureClient.print("Host: " + (String)ipservice+"\n");
  UnsecureClient.print("Connection: close\n");
  UnsecureClient.print("User-Agent: "+user_agent+"\n");
  UnsecureClient.print("\r\n\r\n");

  Serial.print("Esperando resposta.");

 int limiteEspera=500;
 int count=0;
 //TODO: Seria melhor usar um FOR aqui?
 while (UnsecureClient.available() < 1) {  //espero por uma resposta
    count++;
    Serial.print(".");
    delay(100);
    if (count>limiteEspera){
      Serial.println("Desisti de esperar.");
      Serial.println("Fechando Conexao.");
      UnsecureClient.stop(); 
      return false;     
      break;
    }
  } 
  
  Serial.println(""); //Separo dos "."

  String line;  
  while(UnsecureClient.available()) //processo a resposta
  {
    line = UnsecureClient.readStringUntil('\n');
    // Serial.println(line);
    if (line.substring(0,5)=="<html"){
      ipExterno= line.substring(line.indexOf(":")+2);
      ipExterno= ipExterno.substring(0,ipExterno.indexOf("<"));
      Serial.print("ipExterno: ");
      Serial.println(ipExterno);
    }
  }
  Serial.println("");
  Serial.println("Fechando conexao.");
  UnsecureClient.stop();
  return result; 
}



boolean conectarCloudflare(){
  Serial.print("Conectando a ");
  Serial.println(cloudflare_host);
  if (!secureClient.connect(cloudflare_host, httpsPort)) {
    Serial.println("A conexao falhou");
    return false;
  }

  if (secureClient.verify(cloudflare_host_fingerprint, cloudflare_host)) {
    Serial.println("O certificado confere.");
    return true;    
  } else {
    Serial.println("O certificado nao confere. Cancelando.");
    secureClient.stop();
    return false;
  }
}  



boolean SEND(String action){
  boolean result=false;
  if (!conectarCloudflare()){return result;};
  
  String url = "/client/v4/zones/"+zone_id+"/dns_records/"+host_id;
  Serial.print("Acessando URL: ");
  Serial.println(url);
  secureClient.print(action +" " + url + " HTTP/1.1\n");
  secureClient.print("Host: " + (String)cloudflare_host+":443\n");  //TODO: colocar a porta em uma constante
  secureClient.print("Connection: close\n");
  secureClient.print("User-Agent: "+user_agent+"\n");
  secureClient.print("X-Auth-Email: "+login_email+"\n");
  secureClient.print("Content-Type: application/json\n");  
  secureClient.print("X-Auth-Key: "+api_key+"\n");  

  if (action=="PUT"){
      //String original: {"type":"A","name":"r7.automalabs.com.br","content":"127.0.0.1","ttl":120,"proxied":false}
      String postData = "{\"type\":\"A\",\"name\":\""+host_name+"\",\"content\":\""+ipExterno+"\",\"ttl\":120,\"proxied\":false}";   
      secureClient.print("Content-Length: ");
      secureClient.print(postData.length());
      secureClient.print("\r\n\r\n");
      secureClient.print(postData);
  }
  else
  {
      secureClient.print("\r\n\r\n");
  }
  Serial.print(action);
  Serial.print(" enviado. ");

  Serial.print("Esperando resposta.");

 int limiteEspera=500;
 int count=0;
 //TODO: Seria melhor usar um FOR aqui?
 while (secureClient.available() < 1) {  //espero por uma resposta
    count++;
    Serial.print(".");
    delay(100);
    if (count>limiteEspera){
      Serial.println("Desisti de esperar.");
      Serial.println("Fechando Conexao.");
      secureClient.stop(); 
      return false;     
      break;
    }
  } 
  
  Serial.println(""); //Separo dos "."

  String line;  
  while(secureClient.available()) //processo a resposta
  {
    line = secureClient.readStringUntil('\n');
    if (line.substring(2,8)=="result"){
      Serial.println(line);
      String ip= ParseJSON(line.substring(10));  //TODO: fazer processar toda a string
      if (ip!=""){ 
       ipRegistrado=ip;
       result=true;
      }
      else{
       result=false;
        
      }
      
    }
   // Serial.println(line); //Util apenas para debug;

  }
  Serial.println("");
  Serial.println("Fechando conexao.");
  Serial.println("");
  secureClient.stop(); 
  return result;
}


String ParseJSON(String json){

  JsonObject& root = jsonBuffer.parseObject(json);

  if (!root.success()) {
    Serial.println("parseObject() falhou");
    return "";
  }

  //TODO: fazer o parse de "success" também
  String nome = root["name"];
  String ip = root["content"];
  
  
  Serial.println(nome);
  Serial.println(ip);
  return ip;
}

void setup() {
  tick.attach(60, oneMinute); //Executa oneMinute a cada 60 segundos
  Serial.begin(115200);
  //Serial.setDebugOutput(true);
  Serial.println();
  Serial.print("Conectando ao AP: ");
  Serial.println(ssid);
  Serial.print("Com a senha: ");
  Serial.println(password);  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi conectado.");
  Serial.print("Endereco IP do ESP8266: ");
  Serial.println(WiFi.localIP());

  if (SEND("GET")){
  compararEatualizar(ipRegistrado);
  }

}


void loop() {

  if (refresh) {
  refresh=false;  
  compararEatualizar(ipAnterior);
  }
  
}

void compararEatualizar(String ip) {

  if (GETMyIP()){ 
  if (ipExterno==ip){
    Serial.println("Os IPs sao iguais.");
    intervaloChecagens=maxIntervaloChecagens; 
  }
    else
    {   Serial.print("IP: ");
        Serial.println(ip);
        Serial.print("IP externo: ");
        Serial.println(ipExterno);  
        Serial.println("Os IPs sao diferentes. Iniciando arualizacao.");        
    if (SEND("PUT")){
      if (ipExterno!=ipRegistrado){
        Serial.println("Erro ao atualizar o IP.");
        Serial.print("IP na cloudflare: ");
        Serial.println(ipRegistrado);
        Serial.print("IP externo: ");
        Serial.println(ipExterno);
        intervaloChecagens=minIntervaloChecagens; //PUT falhou
      }
      else{
         ipAnterior=ipExterno;
         intervaloChecagens=maxIntervaloChecagens; 
      }
    }
  } 
   }
   else
   {
   intervaloChecagens=minIntervaloChecagens;  //GetMyIP falhou
   }
  Serial.print(intervaloChecagens);
  Serial.println(" minutos para proxima checagem");
  
}

O programa não prossegue se o fingerprint do certificado for diferente do esperado. Infelizmente isso significa que quando o certificado da Clouflare for atualizado o programa deixará de funcionar até que um novo fingerprint seja inserido. Você pode remover esse requerimento mas fica sujeito a roubo de suas credenciais num ataque MITM. Uma sugestão seria armazenar o fingerprint em um arquivo no SPIFFS e fazer o programa ao não conseguir mais validar o certificado mandar uma mensagem para você e passar a procurar por uma atualização de fingerprint no seu domínio, em arquivo criptografado por você.

Infelizmente não parece haver meio do ESP8266 verificar a validade de certificados em tempo real. A checagem de fingerprints foi o melhor que a impressionante equipe por trás do desenvolvimento conseguiu fazer.

Ferramentas online úteis ao debugar esse projeto:

  • Teste da ArduinoJSON – Você pode testar algumas idéias sem ter que fazer upload para um arduino
  • dostring.com – Não sabe qual o tamanho do JSON em bytes? String Length diz.
  • JSON Parser Online – Não consegue visualizar a árvore mentalmente? Permite colapsar estruturas;

ESP8266: Como enviar e-mail por um servidor SMTP

$
0
0

Este código é um aperfeiçoamento do código apresentado aqui.

Testado com IDE 1.8.1 e ESP8266 Core v2.3.0

Melhorias:

  • Não é preciso pré-codificar usuário e senha em base64. Eu inclui as rotinas para isso;
  • Removi o uso de flash strings, que aparentemente era a causa da rotina demorar absurdamente em certos pontos;
  • Usei constantes no lugar de strings “hardcoded”;

/*
 * Este sketch não usa conexão criptografada. Suas credenciais poderão ser interceptadas
 * Use uma conta de email descartável
 *
 *  
 */
// Você precisa mudar estas constantes ==========================
#include <ESP8266WiFi.h>
const char* SSID = "-------------";
const char* PASS = "-------------";
char smtp_server[] = "exemplo.com.br";
const int smtp_port = 587;
const String mail_username="user@exemplo.com.br";
const String mail_password="minhasenha";
const String mail_from="ESP8266 <user@servidor_remetente>";
const String mail_to="Jefferson <user@servidor_destino>";
const String mail_subject="Enviado pelo ESP8266";
const String mail_line1="Esta é a linha 1\n";
const String mail_line2="Esta é a linha 2";
const String mail_line3="Esta é a linha 3";
//============================================================

const char* _b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

WiFiClient client;

void a3_to_a4(unsigned char * a4, unsigned char * a3) {
  a4[0] = (a3[0] & 0xfc) >> 2;
  a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
  a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
  a4[3] = (a3[2] & 0x3f);
}

int base64_encode(char *output, const char *input, int inputLen) {
  int i = 0, j = 0;
  int encLen = 0;
  unsigned char a3[3];
  unsigned char a4[4];
  while(inputLen--) {
    a3[i++] = *(input++);
    if(i == 3) {
      a3_to_a4(a4, a3);
      for(i = 0; i < 4; i++) {
        output[encLen++] = _b64_alphabet[a4[i]];
      }
      i = 0;
    }
  }
  if(i) {
    for(j = i; j < 3; j++) {
      a3[j] = '\0';
    }
    a3_to_a4(a4, a3);
    for(j = 0; j < i + 1; j++) {
      output[encLen++] = _b64_alphabet[a4[j]];
    }
    while((i++ < 3)) {
      output[encLen++] = '=';
    }
  }
  output[encLen] = '\0';
  return encLen;
}

void setup()
{
  Serial.begin(115200);
  delay(10);
  Serial.println("");
  Serial.println("");
  Serial.print("Connecting To ");
  Serial.println(SSID);
  WiFi.begin(SSID, PASS);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  byte ret = sendEmail();
}

void loop()
{
}

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  if (client.connect(smtp_server, smtp_port) == 1) {
    Serial.println("connected");
  } else {
    Serial.println("connection failed");
    return 0;
  }
  if (!eRcv()) return 0;

    char* buf = (char*)malloc(100);

  Serial.println("Sending EHLO");
  client.print("EHLO ");
  client.println(smtp_server); 
  if (!eRcv()) return 0;
  Serial.println("Sending auth login");
  client.println("auth login");
  if (!eRcv()) return 0;
  Serial.println("Sending User");
  base64_encode(buf, mail_username.c_str(), mail_username.length());
  client.println(buf);  
  if (!eRcv()) return 0;
  
  Serial.println("Sending Password");
  base64_encode(buf, mail_password.c_str(), mail_password.length());
  client.println(buf);   
  if (!eRcv()) return 0;
  
  Serial.println("Sending From");
  // change to your email address (sender)
  client.print("MAIL From: ");
  client.println(mail_from);
  if (!eRcv()) return 0;
  // change to recipient address
  Serial.println("Sending To");
  client.print("RCPT To: ");
  client.println(mail_to);
  if (!eRcv()) return 0;
  Serial.println("Sending DATA");
  client.println("DATA");
  if (!eRcv()) return 0;
  Serial.println("Sending email");
  // change to recipient address
  client.print("To: ");
  client.println(mail_to);
  // change to your address
  client.print("From: "); 
  client.println(mail_from); //Este é o "nome para exibição"
  client.print("Subject: ");
  client.print(mail_subject);
  client.println("\r\n");    
  client.println(mail_line1);
  client.println(mail_line2);
  client.println(mail_line3);
  client.println("."); //O email tem que terminar assim
  if (!eRcv()) return 0;
  Serial.println("Sending QUIT");
  client.println("QUIT");
  if (!eRcv()) return 0;
  client.stop();
  Serial.println("disconnected");
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;

  while (!client.available()) {
    delay(1);
    loopCount++;
    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      Serial.println("\r\nTimeout");
      return 0;
    }
  }

  respCode = client.peek();
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }

  if (respCode >= '4')
  {
    //  efail();
    return 0;
  }
  return 1;
}

Versão melhorada

Eu criei esta versão porque preferia uma rotina de envio mais “limpa” e o log na porta serial feito de forma a representar com mais fidelidade a comunicação com o servidor.

/*
 * Este sketch não usa conexão criptografada. Suas credenciais poderão ser interceptadas
 * Use uma conta de email descartável
 *
 *  
 */
#include <ESP8266WiFi.h>
const char* SSID = "";
const char* PASS = "";
char smtp_server[] = "";
const int smtp_port = 587;
const String mail_username="";
const String mail_password="";
const String mail_from="";
const String mail_to="";
const String mail_subject="Enviado pelo ESP8266";
const String mail_line1="Esta é a linha 1\n";
const String mail_line2="Esta é a linha 2";
const String mail_line3="Esta é a linha 3";


bool construindoLinha=false;
const char* _b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

WiFiClient client;

void a3_to_a4(unsigned char * a4, unsigned char * a3) {
  a4[0] = (a3[0] & 0xfc) >> 2;
  a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
  a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
  a4[3] = (a3[2] & 0x3f);
}

int base64_encode(char *output, const char *input, int inputLen) {
  int i = 0, j = 0;
  int encLen = 0;
  unsigned char a3[3];
  unsigned char a4[4];
  while(inputLen--) {
    a3[i++] = *(input++);
    if(i == 3) {
      a3_to_a4(a4, a3);
      for(i = 0; i < 4; i++) {
        output[encLen++] = _b64_alphabet[a4[i]];
      }
      i = 0;
    }
  }
  if(i) {
    for(j = i; j < 3; j++) {
      a3[j] = '\0';
    }
    a3_to_a4(a4, a3);
    for(j = 0; j < i + 1; j++) {
      output[encLen++] = _b64_alphabet[a4[j]];
    }
    while((i++ < 3)) {
      output[encLen++] = '=';
    }
  }
  output[encLen] = '\0';
  return encLen;
}

void setup()
{
  Serial.begin(115200);
  delay(10);
  Serial.println("");
  Serial.println("");
  Serial.print("Connecting To ");
  Serial.println(SSID);
  WiFi.begin(SSID, PASS);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  byte ret = sendEmail();
}

void loop()
{
}

void SEND(String message)
{
if (!construindoLinha){Serial.print("EU: ");};  //Imprimo apenas no início de cada linha
Serial.print (message);
client.print (message);
construindoLinha=true;
  
}

void SENDln(String message)
{
if (!construindoLinha){Serial.print("EU: ");};  //Imprimo apenas no início de cada linha
Serial.println (message);
client.println (message);
construindoLinha=false;  
}

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  if (client.connect(smtp_server, smtp_port) == 1) {
    Serial.println("Conectado.");
  } else {
    Serial.println("Falha na conexao.");
    return 0;
  }
  if (!eRcv()) return 0;

  char* buf = (char*)malloc(100);

  SEND("EHLO ");
  SENDln(smtp_server); 
  if (!eRcv()) return 0;

  SENDln("auth login");
  if (!eRcv()) return 0;

  base64_encode(buf, mail_username.c_str(), mail_username.length());
  client.println(buf);  
  Serial.println(buf);
  if (!eRcv()) return 0;
  
  base64_encode(buf, mail_password.c_str(), mail_password.length());
  client.println(buf);   
  Serial.println(buf);
  if (!eRcv()) return 0;
  
  SEND("MAIL From: ");
  SENDln(mail_from);
  if (!eRcv()) return 0;
  
  SEND("RCPT To: ");
  SENDln(mail_to);
  if (!eRcv()) return 0;
  
  SENDln("DATA");
  if (!eRcv()) return 0;
  
  SEND("To: ");
  SENDln(mail_to);
  SEND("From: "); 
  SENDln(mail_from); //Este é o "nome para exibição"
  SEND("Subject: ");
  SENDln(mail_subject);
  SENDln(mail_line1);
  SENDln(mail_line2);
  SENDln(mail_line3);
  SENDln("."); //O email tem que terminar assim
  if (!eRcv()) return 0;

  SENDln("QUIT");
 
  if (!eRcv()) return 0;
  client.stop();
  Serial.println("Desconectado.");
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;

  while (!client.available()) {
    delay(1);
    loopCount++;
    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      Serial.println("\r\nTimeout");
      return 0;
    }
  }

  respCode = client.peek();
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }

  if (respCode >= '4')
  {
    //  efail();
    return 0;
  }
  return 1;
}

 

ESP8266: Como enviar um e-mail a cada x minutos em caso de alarme.

$
0
0

Este exemplo é uma aplicação desse.

Está configurado para mandar dois e-mails diferentes para um mesmo destinatário. Um quando a condição for ativada (repetindo a cada x minutos) e outro quando for desativada.

 

/*
 * Este sketch não usa conexão criptografada. Suas credenciais poderão ser interceptadas
 * Use uma conta de email descartável. E não use para nada que seja sigiloso.
 * Jefferson Ryan - automalabs.com.br - julho 2017
 *  
 */

 
#include <Ticker.h>
#include <ESP8266WiFi.h>

// itens a preencher ================================================
// Configure o resto em AlarmeON() e AlarmeOFF() 
const char* SSID = "";
const char* PASS = "";
char smtp_server[] = "exemplo.com.br";
const int smtp_port = 587; //pode ser 25, 587, 465, etc.
const String mail_username="usuario@exemplo.com.br";
const String mail_password="senha";
const String mail_from="ESP8266 <remetente@servidor_remetente>";
const String mail_to="Jefferson <destinatario@servidor_destinatario>";
String mail_subject=""; //Preencha em AlarmeON() e AlarmeOFF()
String mail_line1=""; //Preencha em AlarmeON() e AlarmeOFF()
String mail_line2=""; //Preencha em AlarmeON() e AlarmeOFF()
String mail_line3=""; //Preencha em AlarmeON() e AlarmeOFF()

const int sensorPin = 0; //0=GPIO zero
const int intervalo=15; //em minutos
//=====================================================================


bool alarmando = false;
bool refresh=false;
bool construindoLinha=false;
const char* _b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

WiFiClient client;
Ticker tick;


void a3_to_a4(unsigned char * a4, unsigned char * a3) {
  a4[0] = (a3[0] & 0xfc) >> 2;
  a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
  a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
  a4[3] = (a3[2] & 0x3f);
}

int base64_encode(char *output, const char *input, int inputLen) {
  int i = 0, j = 0;
  int encLen = 0;
  unsigned char a3[3];
  unsigned char a4[4];
  while(inputLen--) {
    a3[i++] = *(input++);
    if(i == 3) {
      a3_to_a4(a4, a3);
      for(i = 0; i < 4; i++) {
        output[encLen++] = _b64_alphabet[a4[i]];
      }
      i = 0;
    }
  }
  if(i) {
    for(j = i; j < 3; j++) {
      a3[j] = '\0';
    }
    a3_to_a4(a4, a3);
    for(j = 0; j < i + 1; j++) {
      output[encLen++] = _b64_alphabet[a4[j]];
    }
    while((i++ < 3)) {
      output[encLen++] = '=';
    }
  }
  output[encLen] = '\0';
  return encLen;
}

void setup()
{
  pinMode(sensorPin, INPUT);  

  Serial.begin(115200);
  delay(10);
  Serial.println("");
  Serial.println("");
  Serial.print("Conectando a: ");
  Serial.println(SSID);
  Serial.print("Com a senha: ");
  Serial.println(PASS);  
  WiFi.begin(SSID, PASS);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Conectado.");
  Serial.print("Endereco IP: ");
  Serial.println(WiFi.localIP());

 Serial.print("A cada ");
 Serial.print(intervalo);
 Serial.print(" segundos sera enviado um email se GPIO ");
 Serial.print(sensorPin);
 Serial.println(" estiver em nível baixo.");
}

void fimContagem()
{
  //fimContagem é uma callback do Ticker e a documentação recomenda não fazer nada
  //"blocking" aqui. Na dúvida é melhor só levantar uma flag e processar no loop
  refresh=true;
}


void loop()
{

 if (refresh) { //Ocorre apenas a cada x segundos
   if (digitalRead(sensorPin)==LOW){
    alarmeON(); 

   }
   refresh=false;
 }

    if ((digitalRead(sensorPin)==HIGH)&&(alarmando)){ //Executa uma única vez e imediatamente ao mudar de estado 
    alarmeOFF(); 

   }

    if ((digitalRead(sensorPin)==LOW)&&(!alarmando)){ //Executa uma única vez e imediatamente ao mudar de estado 
    alarmeON(); 

   }   

}


void alarmeOFF()
{
  Serial.println("\r\nDesligando.\r\n");
  tick.detach();//paro a contagem de tempo
     alarmando=false; 
     mail_subject="Alarme OFF!";
     mail_line1="Esta é a linha 1\n";
     mail_line2="Esta é a linha 2";
     mail_line3="Esta é a linha 3";   
     byte ret = sendEmail(); 
  
} 


void alarmeON()
{
    Serial.println("\r\nLigando.\r\n");
    tick.attach(intervalo*60, fimContagem); //A partir deste momnento, executa "fimContagem" a cada intervalo    
     alarmando=true; 
     mail_subject="Alarme ON!";
     mail_line1="Esta é a linha 1\n";
     mail_line2="Esta é a linha 2";
     mail_line3="Esta é a linha 3";   
     byte ret = sendEmail(); 
  
} 
  

void SEND(String message)
{
  if (!construindoLinha){Serial.print("EU: ");};  //Imprimo apenas no início de cada linha
  Serial.print (message);
  client.print (message);
  construindoLinha=true;
  
}

void SENDln(String message)
{
  if (!construindoLinha){Serial.print("EU: ");};  //Imprimo apenas no início de cada linha
  Serial.println (message);
  client.println (message);
  construindoLinha=false;  
}

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  Serial.print("Conectando a ");
  Serial.println(smtp_server);
  if (client.connect(smtp_server, smtp_port) == 1) {
    Serial.println("Conectado.");
  } else {
    Serial.println("Falha na conexao.");
    return 0;
  }
  if (!eRcv()) return 0;

  char* buf = (char*)malloc(100);

  SEND("EHLO ");
  SENDln(smtp_server); 
  if (!eRcv()) return 0;

  SENDln("auth login");
  if (!eRcv()) return 0;

  base64_encode(buf, mail_username.c_str(), mail_username.length());
  client.println(buf);  
  Serial.println(buf);
  if (!eRcv()) return 0;
  
  base64_encode(buf, mail_password.c_str(), mail_password.length());
  client.println(buf);   
  Serial.println(buf);
  if (!eRcv()) return 0;
  
  SEND("MAIL From: ");
  SENDln(mail_from);
  if (!eRcv()) return 0;
  
  SEND("RCPT To: ");
  SENDln(mail_to);
  if (!eRcv()) return 0;
  
  SENDln("DATA");
  if (!eRcv()) return 0;
  
  SEND("To: ");
  SENDln(mail_to);
  SEND("From: "); 
  SENDln(mail_from); //Este é o "nome para exibição"
  SEND("Subject: ");
  SENDln(mail_subject);
  SENDln(mail_line1);
  SENDln(mail_line2);
  SENDln(mail_line3);
  SENDln("."); //O email tem que terminar assim
  if (!eRcv()) return 0;

  SENDln("QUIT");
 
  if (!eRcv()) return 0;
  client.stop();
  Serial.println("Desconectado.");
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;

  while (!client.available()) {
    delay(1);
    loopCount++;
    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      Serial.println("\r\nTimeout");
      return 0;
    }
  }

  respCode = client.peek();
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }

  if (respCode >= '4')
  {
    //  efail();
    return 0;
  }
  return 1;
}

 

ESP8266: Como enviar notificações usando o serviço Pushbullet

$
0
0

O Pushbullet é um serviço muito útil que permite enviar notificações instantâneas com o texto que você quiser para smartphones, tablets, browsers, etc. Antes de usar este exemplo certifique-se de que o serviço Pushbullet funciona para você usando o que está explicado neste outro post.

Este exemplo foi baseado neste aqui que por sua vez é baseado no exemplo HTTPSRequest.ino da biblioteca. Eu incluí algumas modificações que gosto de fazer.

Não tem checagens de erro, mas por sem bem simples fica também simples de entender.

Note que por usar HTTPS requer muita RAM. Eu incluí uma função para mostrar o impacto disso.

 

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>

// ============= Você precisa preencher com seus dados ===================================
const char* ssid = "";
const char* password = "";

const char* PushBulletAPIKEY = ""; //A sua chave de API. Veja na sua conta Pushbullet.
const String message_title = "Enviado do ESP8266";
const String message_body = "Funciona!";

// ========================================================================================

const char* host = "api.pushbullet.com";
const int httpsPort = 443;
//Tenha em mente que este fingerprint muda toda vez que a Pusnbullet renovar seu certificado
const char* fingerprint = "E7 06 F1 30 B1 5F 25 72 00 4D 99 F0 ED 90 4D F9 60 D3 FB 75"; 

void printFreeRAM(){
  Serial.print("RAM livre: ");
  Serial.print(ESP.getFreeHeap());
  Serial.print(" bytes.");
  
}


void setup() {
  Serial.begin(115200);
  //Serial.setDebugOutput(true);  
  printFreeRAM();
  WiFi.mode(WIFI_STA); //Apenas para me certificar de que o AP não seja ativado por uma configuração anterior gravada na flash  
  Serial.println();
  Serial.print("Conectando a: ");
  Serial.println(ssid);
  Serial.print("Com a senha: ");
  Serial.println(password);  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi conetado.");
  Serial.println("Endereco IP do modulo: ");
  Serial.println(WiFi.localIP());

  // Use WiFiClientSecure class to create TLS connection
  WiFiClientSecure client;
  Serial.print("Conectando a: ");
  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
    Serial.println("Falha na conexao.");
    return;
  }

  if (client.verify(fingerprint, host)) {
    Serial.println("O certificado confere.");
  } else {
    Serial.println("O certificado não confere.");
  }

 printFreeRAM(); //A RAM livre cai uns 20KB neste ponto.

   Serial.println("Enviando POST.");
  
  String url = "/v2/pushes";
  String messagebody = "{\"type\": \"note\", \"title\": \""+message_title+"\", \"body\": \""+message_body+"\"}\r\n";
  Serial.print("requesting URL: ");
  Serial.println(url);

  client.print(String("POST ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Authorization: Bearer " + PushBulletAPIKEY + "\r\n" +
               "Content-Type: application/json\r\n" +
               "Content-Length: " +
               String(messagebody.length()) + "\r\n\r\n");
  client.print(messagebody);


  Serial.println("Esperando resposta.");

  while (client.available() == 0);

  while (client.available()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
  }
}

void loop() {
}

 

 

 

 

ESP8266: GPIO no módulo ESP-01

$
0
0

esp8266_esp01_automalabs

ESP-01_pinout_automalabs

O problema: o ESP-01 tem apenas dois GPIO disponíveis: GPIO0 e GPIO2 e ambos são usados no processo de boot do chip.

Por que é tão limitado ?

O meu melhor palpite é que ele não foi mesmo feito para isso. Quando o ESP-01 surgiu não existia essa facilidade que temos hoje para programá-lo diretamente. O fabricante do módulo, AI Thinker, criou um firmware que respondia a comandos AT e esse módulo foi criado para basicamente dar Wi-Fi a um projeto usando outro microcontrolador, como um Arduino. O módulo não precisava de GPIO para isso e o microcontrolador podia se comunicar por TX e RX e controlar seu status e até resetá-lo através dos pinos RST e CH_PD.

Para usar como saídas

Qualquer que seja o caso é recomendável que você tenha resistores de pull-up em ambos e assim o sinal ativo seja “LOW”.

Você pode usar ambos GPIO0 e GPIO2 como saídas, mas eu só recomendo no momento para LEDs e para i2C. GPIO2 especificamente é o TX da “hardware UART” na inicialização e por isso “pisca”. Acionar um relê com ele pode não ser uma boa ideia. GPIO0 parece ser seguro para relês mas ainda não estou certo disso.

Eu costumo usar assim e até agora não notei nenhum problema. Alguns recomendam colocar um pull-up de 4k7 ou 3k3 em paralelo com cada conjunto, mas ainda não vi real necessidade para isso:

ESP-01_output_leds

 

Para usar como entrada

Se qualquer um dos dois pinos estiver em nível baixo o ESP8266 poderá não inicializar. Você pode contornar o problema usando um dos GPIO como saída para ativar o uso do outro como entrada conforme mostra o último exemplo desta página, que é muito confuso por isso refiz assim:

ESP-01_GPIO

Durante o boot não importa se a chave S1 está aberta ou fechada, os resistores manterão GPIO0 e GPIO2 em nível alto. Quando rodar o programa você coloca GPIO2 como saída e em nível baixo, assim:

pinMode(2, OUTPUT);
digitalWrite(2, LOW);

Agora GPIO0 pode ser HIGH ou LOW dependendo da posição da chave. E assim você ganha uma entrada.

Mas o modo mais simples e “seguro” de ter uma entrada no ESP-01 é usar o pino RX da serial. Ele pode ser “liberado” no sketch com uma linha assim:

Serial.begin(115200,SERIAL_8N1,SERIAL_TX_ONLY);

É claro que você não vai poder transmitir nada para esse sketch, mas vai poder receber normalmente pela serial.

Outro modo, mais complicado, de expandir a capacidade de I/O do ESP-01 é usando i2C. Basta um chip como o PCF8574 para transformar GPIO0 e GPIO2 em até oito entradas/saídas perfeitamente usáveis.

 

ESP-01_PCF8574_I2C

 

 

ESP8266: Os LEDs do módulo ESP-01

$
0
0

ESP-01_leds

O LED vermelho é ligado diretamente à alimentação e o LED azul é ligado ao TX da serial. Se você não usar a serial no seu projeto pode controlar esse LED usando GPIO1, conforme o código abaixo:

/* Blink the blue LED on the ESP-01 module
 Based on Blink without Delay. This example code is in the public domain
 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

const int ledPin =  1;  // The blue LED on the ESP-01 module is connected to GPIO1 
                        // (which is also the TXD pin; so we cannot user Serial at the same time

int ledState = LOW;     

unsigned long previousMillis = 0;
const long interval = 1000;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;   
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    digitalWrite(ledPin, ledState);
  }
}

 

Viewing all 63 articles
Browse latest View live