Adicionar vídeo do YouTube em uma página PHP

CAM - Fotos de 30 em 30 min ou quando solicitada.

Descrição da imagem

#include <HTTPClient.h>
#include "esp_camera.h"
#include <WiFi.h>
#include <ArduinoJson.h>
#include "string.h"


unsigned long lastCaptureTime = 0; // Armazena o momento da última captura de foto

// Configuração global da rede wi-fi
const char* ssid = "***********";// MODIFICAR ESTA LINHA......
const char* password = "**********";// MODIFICAR ESTA LINHA......

const int LED_FLASH_PIN = 4; // Defina o pino do LED flash

bool enviarFoto = false; // Variável para controlar o envio da foto

// Configuração global da api
const char* FKhorta = "1"; // MODIFICAR ESTA LINHA......
const char* apikey = "******************************"; // MODIFICAR ESTA LINHA......


int lastStatusChange = -1;  // Valor inicial, pode ser 0 ou 1 dependendo do seu caso

// Protótipos das funções
void initCamera();
int enviar(int inFKsensor, String inValor);
void enviarEmPartes(int inFKsensor, String inValor);
void verifiqueInternetReconecte(int espera);
void conectar();
int getchanges(int FKsensor);
void capturarFoto(int envia, int flash);
int isJPEG(const uint8_t *buffer, size_t length);
String bytesToHexString(const uint8_t *data, size_t length);


// Função para inicializar a câmera
void initCamera() {
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = 5; // D0
  config.pin_d1 = 18; // D1
  config.pin_d2 = 19; // D2
  config.pin_d3 = 21; // D3
  config.pin_d4 = 36; // D4
  config.pin_d5 = 39; // D5
  config.pin_d6 = 34; // D6
  config.pin_d7 = 35; // D7
  config.pin_xclk = 0; // XCLK
  config.pin_pclk = 22; // PCLK
  config.pin_vsync = 25; // VSYNC
  config.pin_href = 23; // HREF
  config.pin_sscb_sda = 26; // SIOD
  config.pin_sscb_scl = 27; // SIOC
  config.pin_pwdn = 32; // PWDN
  config.pin_reset = -1; // Não usado
  
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  
  
  /*
  if(psramFound()){
    config.frame_size = FRAMESIZE_SVGA;//(800x600)
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_VGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }
  */
  
  
  
  config.frame_size = FRAMESIZE_SVGA;
  config.jpeg_quality = 12;


  /*FORÇAR A OBTENÇÃO DA IMAGEM ATUALIZADA
  Opção 1) fb_count = 2 and CAMERA_GRAB_LATEST
  Opção 2) fb_count = 1, CAMERA_GRAB_WHEN_EMPTY and esp_camera_fb_return(esp_camera_fb_get()); 
  */
  config.fb_count = 2;
  config.grab_mode=CAMERA_GRAB_LATEST;
  
  // Inicialização da câmera
  esp_err_t err = esp_camera_init(&config);
  
  sensor_t *s = esp_camera_sensor_get();
  s->set_aec2(s, true); // Ativar a exposição automática
  //s->set_brightness(s, 0); // Define o brilho para 0
  //s->set_contrast(s, 1);   // Define o contraste para 1
  //s->set_saturation(s, 0); // Define a saturação para 0
  
  
  if (err != ESP_OK) {
    Serial.printf("Erro ao inicializar a câmera! (Erro: %d)", err);
    return;
  }
}


/*
* converte em uma string hexadecimal.
*/

String bytesToHexString(const uint8_t *data, size_t length) {
  // Crie uma string para armazenar os dados em hexadecimal
  char *hexString = new char[length * 2 + 1]; // Duas caracteres hexadecimais por byte + 1 para o caractere nulo
  
  // Converta os dados em hexadecimal e armazene na string
  for (size_t i = 0; i < length; i++) {
    sprintf(hexString + i * 2, "%02X", data[i]); // Dois caracteres por byte
  }
  
  // Adicione o caractere nulo para terminar a string
  hexString[length * 2] = '\0';

  // Crie um objeto String a partir da string hexadecimal
  String hexStringObj = String(hexString);

  // Libere a memória alocada para a string
  delete[] hexString;

  return hexStringObj;
}

/*
* verifica os dois primerios e dois útimos FF D8 ... FF D9 para uma validação parcial de JPG.
*/
int isJPEG(const uint8_t *buffer, size_t length) {
    // Verifica se o comprimento do buffer é suficiente para conter um cabeçalho e um rodapé JPEG
    if (length < 4) {
        return 0;
    }

    // Verifica os primeiros dois bytes para o início do cabeçalho JPEG (FF D8)
    if (buffer[0] == 0xFF && buffer[1] == 0xD8) {
        // Verifica os últimos dois bytes para o final do arquivo JPEG (FF D9)
        if (buffer[length - 2] == 0xFF && buffer[length - 1] == 0xD9) {
            return 1;
        }
    }

    return 0;
}


// Conecta-se ao WiFi
void conectar(){

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Tentando se conectar ao WiFi...");
  }
  Serial.println("Conectado ao WiFi com sucesso!");

}

// Se não tiver Internet reestabelecer conexão após 'espera' milisegundos.
void verifiqueInternetReconecte(int espera) {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Sem internet. Tentar conexão em ");
    Serial.print(espera);
    Serial.println(" segundos...");
    delay(espera);
    conectar();
  }
}

void setup() {
  
  Serial.begin(115200);
  pinMode(LED_FLASH_PIN, OUTPUT); // Configura o pino do LED flash como saída
  conectar();
  initCamera();
  // Espera 2 segundos para estabilizar a câmera
  
  delay(2000);
}


/*
*Enviar por partes de 50000
*/
void enviarEmPartes(int inFKsensor, String inValor) {
    const size_t parteTamanho = 50000; // Tamanho de cada parte (50.000 caracteres)
    size_t totalLength = inValor.length();
    String lastID = ""; // Inicializa o lastID como vazio
    int pos = 0;
    for (size_t i = 0; i < totalLength; i += parteTamanho) {
        size_t parteLength = min(parteTamanho, totalLength - i);
        String parte = inValor.substring(i, i + parteLength);

        // Monta o corpo da requisição
        String data_to_send = "apikey=" + String(apikey) +
                              "&FKhorta=" + String(FKhorta) +
                              "&FKsensor=" + String(inFKsensor) +
                              "&c=" + parte;
        
        pos = pos +1;
        Serial.println("Parte"+ String(pos) +" enviada...");

        if (WiFi.status() == WL_CONNECTED) {
            HTTPClient http;
            http.begin("https://horta.gvsoftwares.com.br/api/set_leiturapost/");
            http.addHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");

            // Envia o lastID a partir da segunda parte (não na primeira)
            if (lastID != "" && i > 0) {
                data_to_send += "&id=" + lastID;
            }

            int codigo_resposta = http.POST(data_to_send);

            if (codigo_resposta > 0) {
                Serial.println("Código HTTP -> " + String(codigo_resposta));

                // Captura o lastID apenas na primeira parte
                if (codigo_resposta == 200 && i == 0) { // primeira parte
                    String corpo_resposta = http.getString();
                    Serial.println("O servidor respondeu:");
                    Serial.println(corpo_resposta);

                    // Capacidade inicial definida como suficiente
                    const size_t initialCapacity = 200; // Capacidade inicial fixa
                    DynamicJsonDocument doc(initialCapacity);
                    DeserializationError error = deserializeJson(doc, corpo_resposta);

                    if (!error) {
                        lastID = doc["lastID"].as<String>(); // Atualiza o lastID com a resposta do servidor
                        Serial.println("lastID atualizado: " + lastID);
                    } else {
                        Serial.println("Erro ao desserializar o JSON: ");
                        Serial.println(error.c_str());
                    }
                }
            } else {
                Serial.println("Erro ao enviar POST:");
                Serial.println(codigo_resposta);
            }

            http.end();
        } else {
            Serial.println("Erro na conexão WIFI.");
        }

        delay(500); // Pequeno delay entre envios de partes
    }
}


/*
* Enviar as imagens para a api.
*/
int enviar(int inFKsensor, String inValor) {


  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;

    String data_to_send = "apikey=" + String(apikey) + "&FKhorta=" + String(FKhorta) + "&FKsensor=" + String(inFKsensor) + "&c=" + String(inValor);
    //Serial.println(data_to_send);
    http.begin("https://horta.gvsoftwares.com.br/api/set_leiturapost/");
    http.addHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
    int codigo_resposta = http.POST(data_to_send);

    if (codigo_resposta > 0) {
      Serial.println("Código HTTP -> " + String(codigo_resposta));

      if (codigo_resposta == 200) {
        String corpo_resposta = http.getString();
        Serial.println("O servidor Respondeu:");
        Serial.println(corpo_resposta);
        return 1;
      }
    } else {
      Serial.println("Erro ao enviar POST:");
      Serial.println(codigo_resposta);
      return 0;
    }

    http.end();

  } else {
    Serial.println("Erro na conexão WIFI.");
    return 0;
  }
}

/*
* capturar a foto com flash
*/
void capturarFoto(int envia, int flash) {
  camera_fb_t * fb = NULL;
  if (flash == 1){
    digitalWrite(LED_FLASH_PIN, HIGH);
  }
  delay(500);
  fb = esp_camera_fb_get();
  delay(200);
  digitalWrite(LED_FLASH_PIN, LOW);
  
  if (fb) {
    Serial.println("Tamanho:");
    Serial.println(fb->len); // Exibir o tamanho em decimal
    Serial.println("É uma imagem jpg (0xFF 0xD8 ... 0xFF 0xD9)?");
    Serial.println(isJPEG(fb->buf, fb->len));
    
    String hexData = bytesToHexString(fb->buf, fb->len);
    //Serial.println("hexData:");
    //Serial.println(hexData);

    if (envia==1)
      {
      if (fb->len < 90000){
        //enviar em uma única string.
        enviar(55, hexData);// MODIFICAR ESTA LINHA...... o id 55
      }else{
        //enviar em partes um string maior ou igual à 90000 characteres.
        enviarEmPartes(55,hexData);// MODIFICAR ESTA LINHA...... o id 55 
      }
    }
    esp_camera_fb_return(fb); // Libera a memória da imagem após o uso
    delay(200);
  } else {
    Serial.println("Erro ao capturar a foto");
  }
}

void loop() {
  unsigned long currentTime = millis();
  verifiqueInternetReconecte(2000);

  // Verificar se passou 30 minutos desde a última captura ou se é a primeira captura
  if (currentTime - lastCaptureTime >= 1800000 || lastCaptureTime == 0) {
    capturarFoto(1, 1); // Captura e envia a foto
    lastCaptureTime = currentTime; // Atualiza o tempo da última captura
    Serial.println("Foto capturada e enviada.");
  }

  // Verifica se houve mudança no status do sensor
  int novoStatusChange = getchanges(55);// MODIFICAR ESTA LINHA...... o id 55
  if (novoStatusChange != lastStatusChange && !enviarFoto && novoStatusChange != -1) {
    capturarFoto(1, 1); // Captura e envia a foto
    lastStatusChange = novoStatusChange;
    Serial.println("Mudança de status detectada. Foto capturada e enviada.");
  }

  delay(1000); // Aguarda 1 segundo antes de verificar novamente
}

/*
* Mudanças no status do botão on/off
*/
int getchanges(int FKsensor) {
  // Faça a requisição HTTP
  HTTPClient http;

  // Informe a URL desejada
  String url = "https://horta.gvsoftwares.com.br/api/get_sensoresstatuschange/?FKsensor=" + String(FKsensor);
  http.begin(url);

  // Obtenha e imprima o código de status da resposta
  int httpCode = http.GET();
  Serial.print("Código de Status HTTP: ");
  Serial.println(httpCode);

  // Inicialize a variável de retorno
  int statusChange = -1;  // Defina um valor padrão

  // Se a resposta for bem-sucedida, analise o JSON
  if (httpCode > 0) {
    String payload = http.getString();
    Serial.println("Resposta do servidor: ");
    Serial.println(payload);

    // Tamanho suficiente para armazenar o JSON
    const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 10;
    // Aloque o JSONBuffer
    DynamicJsonDocument doc(capacity);
    // Deserializar a string JSON
    DeserializationError error = deserializeJson(doc, payload);

    // Verificar erros de desserialização
    if (error) {
      Serial.print(F("Erro ao desserializar JSON: "));
      Serial.println(error.c_str());
    } else {
      // Obter o valor da chave "statuschange"
      statusChange = doc[0]["statuschange"];
    }
  }

  http.end();

  return statusChange;  // Retorna o valor, mesmo que seja o padrão -1 em caso de erro
  }