Aplicativo e ESP32 - Versão Final

 


                                                            Esquema do Projeto



    A versão final do App utilizando a plataforma MIT App Inventor, agora com uma interface mais moderna e funcionalidades mais precisas está pronta. O App inicia com somente os campos de Conectividade visíveis, em uma interface mais limpa.

    Para evitar alguns "bugs" mantivemos o botão de Desconectar desativado enquanto não houver nenhuma conexão realizada.



    Ao clicar em Conectar, temos a lista de dispositivos Bluetooth disponíveis no alcance do smartphone utilizado, com as informações de endereço MAC, Nome do dispositivo BLE e potencia do sinal.


Ao selecionar o dispositivo o App fará a conexão e irá ativar os botões de controle de Iluminação. Os botões estão configurados da seguinte forma:

Lamp_1 ON -> Liga Lâmpada 1 e Aciona o Slide Bar para controle de Intensidade.
Lamp_2 ON -> Liga Lâmpada 2
Lamp_3 ON -> Liga Lâmpada 3
Lamp_4 ON -> Liga Lâmpada 4

Lamp_1 OFF -> Desliga Lâmpada 3 e Desabilita a Slide Bar para controle de Intensidade.
Lamp_2 OFF -> Desliga Lâmpada 2
Lamp_3 OFF -> Desliga Lâmpada 3
Lamp_4 OFF -> Desliga Lâmpada 4

A Slide Bar está configurada somente para uso com a Lampada 1, uma vez que só dispomos de um Dimmer para a montagem do circuito.


    Todos os botões mudam de cor indicando se estão habilitados ou não.
    A Slide Bar é a responsável por fazer a alteração da saída PWM do ESP32, que manda o sinal para o Dimmer e faz a alteração da corrente AC que energiza a lâmpada.
Ao lado do Slide Bar consta uma contagem que mostra os 5 níveis de alteração da intensidade da iluminação.



Para o devido funcionamento do App, é necessário importar uma extensão BluetoothLE, disponibilizada na comunidade do MIT App Inventor que pode ser encontrada no link abaixo:


Abaixo, segue o diagrama de blocos completo contemplando todas as funcionalidades do App.

       


    Para a montagem completa do circuito foram utilizados:

  • 1 ESP 32 - 30 Pinos;
  • 1 Fonte Arduino 5v;
  • 1 Protoboard;
  • Jumpers para conexões;
  • 1 Módulo Relé para Arduino com 4 Relés; 
  • 1 Dispositivo Dimmer MC-8A com entrada PWM para controle digital;
  • 2 bocais para lâmpadas;
  • 2m de cabos 1,5mm² para energização das lâmpadas; 
  • 2 Lâmpadas;
  • 1 Smartphone com suporte BLE; 

Abaixo um breve vídeo com o funcionamento do circuito e App desenvolvido:


 

 Para a programação da eletrônica foi utilizado o Arduino IDE utilizando o código abaixo:

Código ESP32

#include <Arduino.h>

#include <BLEDevice.h>

#include <BLEServer.h>

#include <BLEUtils.h>

#include <BLE2902.h>


BLECharacteristic *characteristicTX; //através desse objeto iremos enviar dados para o client

bool deviceConnected = false; //controle de dispositivo conectado

const int rele1 = 2; 

const int rele2 = 4;

const int rele3 = 5; 

const int rele4 = 18;

int controle = 0;

int aux = 0;

int Busca = 0;


#define SERVICE_UUID           "4FAFC201-1FB5-459E-8FCC-C5C9C331914B" 

// UART service UUID não podedo ser iguais

#define CHARACTERISTIC_UUID_RX "4FAFC202-1FB5-459E-8FCC-C5C9C331914B"

#define CHARACTERISTIC_UUID_TX "4FAFC203-1FB5-459E-8FCC-C5C9C331914B"


#define PINO_DIM    26

#define PINO_ZC     27

#define maxBrightness 800 // brilho maximo em us

#define minBrightness 7500 // brilho minimo em us

#define TRIGGER_TRIAC_INTERVAL 20 // tempo quem que o triac fica acionado

#define IDLE -1

 

#define pino_botao_up 13  // pino quem que o botao de aumentar o brilho esta conectado

#define pino_botao_down 12 // pino que o botao de diminuir o brilho esta conectado


//callback para receber os eventos de conexão de dispositivos

class ServerCallbacks: public BLEServerCallbacks {

    void onConnect(BLEServer* pServer) {

      deviceConnected = true;

    };

  void onDisconnect(BLEServer* pServer) {

      deviceConnected = false;

    }

};


//callback  para envendos das características

class CharacteristicCallbacks: public BLECharacteristicCallbacks {

    void onWrite(BLECharacteristic *characteristic) {

      //retorna ponteiro para o registrador contendo o valor atual da caracteristica

      std::string rxValue = characteristic->getValue(); 

      //verifica se existe dados (tamanho maior que zero)

      if (rxValue.length() > 0) {

        Serial.println("*********");

        Serial.print("Esperando Comando ");// vai printar para mim no serial


        for (int i = 0; i < rxValue.length(); i++) {

          Serial.print(rxValue[i]);

        }


        Serial.println();


        // Do stuff based on the command received

        if (rxValue.find("Liga1") != -1) { 

          Serial.print("Ligar!");// vai printar para mim no serial

          digitalWrite(rele1, LOW);

          aux = 1;

        }

        else if (rxValue.find("Desl1") != -1) {

          Serial.print("Desligar");

          digitalWrite(rele1, HIGH);

          aux = 0;

        }

        else if (rxValue.find("Liga2") != -1) { 

          Serial.print("Ligar!");// vai printar para mim no serial

          digitalWrite(rele2, LOW);

        }

        else if (rxValue.find("Desl2") != -1) {

          Serial.print("Desligar");

          digitalWrite(rele2, HIGH);

        }

        else if (rxValue.find("Liga3") != -1) { 

          Serial.print("Ligar!");// vai printar para mim no serial

          digitalWrite(rele3, LOW);

        }

        else if (rxValue.find("Desl3") != -1) {

          Serial.print("Desligar");

          digitalWrite(rele3, HIGH);

        }

        else if (rxValue.find("Liga4") != -1) { 

          Serial.print("Ligar!");// vai printar para mim no serial

          digitalWrite(rele4, LOW);

        }

        else if (rxValue.find("Desl4") != -1) {

          Serial.print("Desligar");

          digitalWrite(rele4, HIGH);

        }

        else if ((rxValue.find("0") != -1 && aux == 1)){

          controle = 0;


          }

        else if ((rxValue.find("1") != -1) && aux == 1){

           controle = 1;

          

          }

          else if ((rxValue.find("2") != -1 && aux == 1)){

          controle = 2;


          }

        else if ((rxValue.find("3") != -1) && aux == 1){

           controle = 3;

          }

          else if ((rxValue.find("4") != -1 && aux == 1)){

          controle = 4;


          }

        else if ((rxValue.find("5") != -1) && aux == 1){

           controle = 5;

          }

      }

    }

};

 

//variaveis globais

int brilho = 100;

int brilho_convertido = 0;

 

unsigned long ultimo_millis1 = 0; 

unsigned long ultimo_millis2 = 0; 

unsigned long debounce_delay = 100;

 

hw_timer_t * timerToPinHigh;

hw_timer_t * timerToPinLow;

 

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;

 

volatile bool isPinHighEnabled = false;

volatile long currentBrightness = minBrightness;

 

void IRAM_ATTR ISR_turnPinLow(){ // desliga o pino dim

  portENTER_CRITICAL_ISR(&mux); // desativa interrupçoes

    digitalWrite(PINO_DIM, LOW);

    isPinHighEnabled = false;

  portEXIT_CRITICAL_ISR(&mux); // ativa as interrupçoes novamente

}

 

void IRAM_ATTR setTimerPinLow(){ // executa as configuracoes de pwm e aplica os valores da luminosidade ao dimmer no tempo em que ra ficar em low

  timerToPinLow = timerBegin(1, 80, true);

  timerAttachInterrupt(timerToPinLow, &ISR_turnPinLow, true);

  timerAlarmWrite(timerToPinLow, TRIGGER_TRIAC_INTERVAL, false);

  timerAlarmEnable(timerToPinLow);

}

 

void IRAM_ATTR ISR_turnPinHigh(){ // liga o pino dim

  portENTER_CRITICAL_ISR(&mux);  // desativa interrupçoes

    digitalWrite(PINO_DIM, HIGH); 

    setTimerPinLow();

  portEXIT_CRITICAL_ISR(&mux); // ativa as interrupçoes novamente

}

 

void IRAM_ATTR setTimerPinHigh(long brightness){ // executa as configuracoes de pwm e aplica os valores da luminosidade ao dimmer no tempo que ira ficar em high

  isPinHighEnabled = true;

  timerToPinHigh = timerBegin(1, 80, true);

  timerAttachInterrupt(timerToPinHigh, &ISR_turnPinHigh, true);

  timerAlarmWrite(timerToPinHigh, brightness, false);

  timerAlarmEnable(timerToPinHigh);

}

 

void IRAM_ATTR ISR_zeroCross()  {// funçao que é chamada ao dimmer registrar passagem por 0

  if(currentBrightness == IDLE) return;

  portENTER_CRITICAL_ISR(&mux); // desativa interrupçoes

    if(!isPinHighEnabled){

       setTimerPinHigh(currentBrightness); // define o brilho

    }

  portEXIT_CRITICAL_ISR(&mux); // ativa as interrupçoes novamente

}

 

void turnLightOn(){ // liga o dimmer no brilho maximo

  portENTER_CRITICAL(&mux);// desativa interrupçoes

    currentBrightness = maxBrightness;

    digitalWrite(PINO_DIM, HIGH);

  portEXIT_CRITICAL(&mux);// ativa as interrupçoes novamente

}

 

void turnLightOff(){// deliga o dimmer

  portENTER_CRITICAL(&mux); // desativa interrupçoes

    currentBrightness = IDLE;

    digitalWrite(PINO_DIM, LOW);

  portEXIT_CRITICAL(&mux); // ativa as interrupçoes novamente

}

 

void setup() {

  Serial.begin(115200);


  pinMode(rele1, OUTPUT);

  pinMode(rele2, OUTPUT);

  pinMode(rele3, OUTPUT);

  pinMode(rele4, OUTPUT);

  digitalWrite(rele1, HIGH);

  digitalWrite(rele2, HIGH);

  digitalWrite(rele3, HIGH);

  digitalWrite(rele4, HIGH);


  // Create the BLE Device

  BLEDevice::init("BLE_TOPICOS"); // nome do dispositivo bluetooth

  // Create the BLE Server

  BLEServer *server = BLEDevice::createServer(); //cria um BLE server 

  server->setCallbacks(new ServerCallbacks()); //seta o callback do server

  // Create the BLE Service

  BLEService *service = server->createService(SERVICE_UUID);

  // Create a BLE Characteristic para envio de dados

  characteristicTX = service->createCharacteristic(

                      CHARACTERISTIC_UUID_TX,

                      BLECharacteristic::PROPERTY_NOTIFY

                    );

                      

  characteristicTX->addDescriptor(new BLE2902());


  // Create a BLE Characteristic para recebimento de dados

  BLECharacteristic *characteristic = service->createCharacteristic(

                                         CHARACTERISTIC_UUID_RX,

                                         BLECharacteristic::PROPERTY_WRITE

                                       );


  characteristic->setCallbacks(new CharacteristicCallbacks());

  // Start the service

  service->start();

  // Start advertising (descoberta do ESP32)

  server->getAdvertising()->start();

  

  Serial.println("Esperando conexão");

 

  currentBrightness = IDLE;

 

  pinMode(PINO_ZC,  INPUT_PULLUP);

  pinMode(PINO_DIM, OUTPUT);

  digitalWrite(PINO_DIM, LOW);

  attachInterrupt(digitalPinToInterrupt(PINO_ZC), ISR_zeroCross, RISING);

 

  Serial.println("Controlando dimmer com esp32");

 

   pinMode(pino_botao_up, INPUT);

   pinMode(pino_botao_down, INPUT);

}

 

void loop() {

    //se existe algum dispositivo conectado

    if (deviceConnected == false) {

            Serial.print(" Aguardando Nova Conexão: ");

            Serial.println(" ");


            if (Busca == 1){

                Busca = 0;

                ESP.restart();

            }

     }

     delay(1000);

     if (deviceConnected == true) {

            Serial.print(" Aguardando Comando ");

            Serial.println(" ");

            Busca = 1;

     }

  Serial.println(brilho); // mostra a quantidade de brilho atual

      if (controle == 5) { // e o botao estiver precionado

        brilho = 60;

        brilho_convertido = map(brilho, 100, 0, maxBrightness, minBrightness); //converte a luminosidade em microsegundos

         portENTER_CRITICAL(&mux); //desliga as interrupçoes

            currentBrightness = brilho_convertido; // altera o brilho

         portEXIT_CRITICAL(&mux);// liga as interrupçoes

    }

      else if (controle == 4) { // e o botao estiver precionado

        brilho = 48;

        brilho_convertido = map(brilho, 100, 0, maxBrightness, minBrightness); //converte a luminosidade em microsegundos

         portENTER_CRITICAL(&mux); //desliga as interrupçoes

            currentBrightness = brilho_convertido; // altera o brilho

         portEXIT_CRITICAL(&mux);// liga as interrupçoes

    }

    else if (controle == 3) { // e o botao estiver precionado

        brilho = 36;

        brilho_convertido = map(brilho, 100, 0, maxBrightness, minBrightness); //converte a luminosidade em microsegundos

         portENTER_CRITICAL(&mux); //desliga as interrupçoes

            currentBrightness = brilho_convertido; // altera o brilho

         portEXIT_CRITICAL(&mux);// liga as interrupçoes

    }

    else if (controle == 2) { // e o botao estiver precionado

        brilho = 24;

        brilho_convertido = map(brilho, 100, 0, maxBrightness, minBrightness); //converte a luminosidade em microsegundos

         portENTER_CRITICAL(&mux); //desliga as interrupçoes

            currentBrightness = brilho_convertido; // altera o brilho

         portEXIT_CRITICAL(&mux);// liga as interrupçoes

    }

    else if (controle == 1) { // e o botao estiver precionado

        brilho = 12;

        brilho_convertido = map(brilho, 100, 0, maxBrightness, minBrightness); //converte a luminosidade em microsegundos

         portENTER_CRITICAL(&mux); //desliga as interrupçoes

            currentBrightness = brilho_convertido; // altera o brilho

         portEXIT_CRITICAL(&mux);// liga as interrupçoes

    }

    else if (controle == 0) { // e o botao estiver precionado

        brilho = 0;

        brilho_convertido = map(brilho, 100, 0, maxBrightness, minBrightness); //converte a luminosidade em microsegundos

         portENTER_CRITICAL(&mux); //desliga as interrupçoes

            currentBrightness = brilho_convertido; // altera o brilho

         portEXIT_CRITICAL(&mux);// liga as interrupçoes

    }      

}

    Esse projeto de acender e controlar a intensidade da  da luz que passa na lâmpada tem com objetivo aumentar o conhecimento na área de programação em micro controlador, ver como funciona o famoso BLE que vem ganhando destaque em algumas automações no mercado, assim com base nesse projeto pode se aprofundar mais em automação residencial, atingimos o objetivo principal do projeto assim através dele pode surgir novas ideias.

Comentários