cotestatnt / AsyncTelegram2

Powerful, flexible and secure Arduino Telegram BOT library. Hardware independent, it can be used with any MCU capable of handling an SSL connection.
MIT License
85 stars 25 forks source link

My project doesnt work anymore when I compile and upload it using the updated library #88

Closed FBMinis closed 2 years ago

FBMinis commented 2 years ago

One year ago I put together the following project:

https://github.com/FBMinis/DS3231-Alarm-ESP32-Cam-Telegram-Bot

After updating your library to 2.1.5 the program compiles and uploads but I never receive the photo on Telegram.

It worked on: Windows 10; Arduino portable 1.8.13; ESP32 2.0.0; AsyncTelegram2 2.0.4

Currently not working on: Win10; Arduino portable 1.8.19; ESP32 2.0.4; AsyncTelegram2 2.1.5

The example "ESP32-CAM" included in your library works fine.

My interpretation is that something changed since 2.0.4 regarding the way the photo info is sent to the server. I read your documentation but have not been able to identify what might be causing this situation.

I would appreciated some suggestions from you on how to solve this. Thank you!

cotestatnt commented 2 years ago

Hi @FBMinis, first of all thank you for the feedback which is always very useful for finding insidious bugs like this.

The way the photo is sent to the server should not be changed a lot... in the last releases I've only added the possibility to include caption with pictures.

I did my tests by sending images directly from the flash, but unfortunately not using an ESP32-CAM board. As soon as I can I try to verify your sketch to see if I can identify the problem with the new version of the library.

FBMinis commented 2 years ago

Thank you for your quick reply.

Here is a simple version of the sketch that works with version 2.0.0 but with 2.1.5 I dont receive the photo.

#include <WiFi.h>
#include <AsyncTelegram2.h>
#include "esp_camera.h"
#include "soc/soc.h"           // Brownout error fix
#include "soc/rtc_cntl_reg.h"  // Brownout error fix

#define USE_SSLCLIENT false
#if USE_SSLCLIENT
#include <SSLClient.h>
#include "tg_certificate.h"
WiFiClient base_client;
SSLClient client(base_client, TAs, (size_t)TAs_NUM, A0);
#else
#include <WiFiClientSecure.h>
WiFiClientSecure client;
#endif

const char* ssid = "XYZ";  // SSID WiFi network
const char* pass = "XYZ";  // Password  WiFi network
const char* token = "XYZ";

// Check the userid with the help of bot @JsonDumpBot or @getidsbot (work also with groups)
// https://t.me/JsonDumpBot  or  https://t.me/getidsbot
int64_t userid = XYZ;

#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  30        /* Time ESP32 will go to sleep (in seconds) */

// Timezone definition to get properly time from NTP server
#define MYTZ "WET0WEST,M3.5.0/1,M10.5.0"

AsyncTelegram2 myBot(client);

#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27

#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22

#define LAMP_PIN 4

static camera_config_t camera_config = {
  .pin_pwdn = PWDN_GPIO_NUM,
  .pin_reset = RESET_GPIO_NUM,
  .pin_xclk = XCLK_GPIO_NUM,
  .pin_sscb_sda = SIOD_GPIO_NUM,
  .pin_sscb_scl = SIOC_GPIO_NUM,
  .pin_d7 = Y9_GPIO_NUM,
  .pin_d6 = Y8_GPIO_NUM,
  .pin_d5 = Y7_GPIO_NUM,
  .pin_d4 = Y6_GPIO_NUM,
  .pin_d3 = Y5_GPIO_NUM,
  .pin_d2 = Y4_GPIO_NUM,
  .pin_d1 = Y3_GPIO_NUM,
  .pin_d0 = Y2_GPIO_NUM,
  .pin_vsync = VSYNC_GPIO_NUM,
  .pin_href = HREF_GPIO_NUM,
  .pin_pclk = PCLK_GPIO_NUM,
  .xclk_freq_hz = 20000000,        //XCLK 20MHz or 10MHz
  .ledc_timer = LEDC_TIMER_0,
  .ledc_channel = LEDC_CHANNEL_0,
  .pixel_format = PIXFORMAT_JPEG,  //YUV422,GRAYSCALE,RGB565,JPEG
  .frame_size = FRAMESIZE_XGA,    //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
  .jpeg_quality = 10,              //0-63 lower number means higher quality
  .fb_count = 2                    //if more than one, i2s runs in continuous mode. Use only with JPEG
};

int lampChannel = 7;           // a free PWM channel (some channels used by camera)
const int pwmfreq = 50000;     // 50K pwm frequency
const int pwmresolution = 9;   // duty cycle bit range
const int pwmMax = pow(2, pwmresolution) - 1;

// Lamp Control
void setLamp(int newVal) {
  if (newVal != -1) {
    // Apply a logarithmic function to the scale.
    int brightness = round((pow(2, (1 + (newVal * 0.02))) - 2) / 6 * pwmMax);
    ledcWrite(lampChannel, brightness);
    Serial.print("Lamp: ");
    Serial.print(newVal);
    Serial.print("%, pwm = ");
    Serial.println(brightness);
  }
}

static esp_err_t init_camera() {
  //initialize the camera
  Serial.print("Camera init... ");
  esp_err_t err = esp_camera_init(&camera_config);

  if (err != ESP_OK) {
    delay(100);  // need a delay here or the next serial o/p gets missed
    Serial.printf("\n\nCRITICAL FAILURE: Camera sensor failed to initialise.\n\n");
    Serial.printf("A full (hard, power off/on) reboot will probably be needed to recover from this.\n");
    return err;
  } else {
    Serial.println("succeeded");

    // Get a reference to the sensor
    sensor_t* s = esp_camera_sensor_get();

    // Dump camera module, warn for unsupported modules.
    switch (s->id.PID) {
      case OV9650_PID: Serial.println("WARNING: OV9650 camera module is not properly supported, will fallback to OV2640 operation"); break;
      case OV7725_PID: Serial.println("WARNING: OV7725 camera module is not properly supported, will fallback to OV2640 operation"); break;
      case OV2640_PID: Serial.println("OV2640 camera module detected"); break;
      case OV3660_PID: Serial.println("OV3660 camera module detected"); break;
      default: Serial.println("WARNING: Camera module is unknown and not properly supported, will fallback to OV2640 operation");
    }

    // Adjust sensor settings
    s->set_whitebal(s, 1);       // 0 = disable , 1 = enable
    s->set_awb_gain(s, 1);       // 0 = disable , 1 = enable
    s->set_wb_mode(s, 2);        // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
    //    s->set_hmirror(s, 0);        // 0 = disable , 1 = enable
    //    s->set_vflip(s, 0);          // 0 = disable , 1 = enable

  }
  return ESP_OK;
}

size_t sendPicture(TBMessage& msg) {
  // Take Picture with Camera;
  Serial.println("Camera capture requested");

  // Take picture with Camera and send to Telegram
  //  setLamp(100);
  camera_fb_t* fb = esp_camera_fb_get();
  //  setLamp(0);
  if (!fb) {
    Serial.println("Camera capture failed");
    return 0;
  }
  size_t len = fb->len;
  if (!myBot.sendPhoto(msg, fb->buf, fb->len)) {
    len = 0;
    myBot.sendMessage(msg, "Error! Picture not sent.");
  }

  // Clear buffer
  esp_camera_fb_return(fb);
  return len;
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);       // disable brownout detector
  pinMode(LAMP_PIN, OUTPUT);                       // set the lamp pin as output
  ledcSetup(lampChannel, pwmfreq, pwmresolution);  // configure LED PWM channel
  setLamp(0);                                      // set default value
  ledcAttachPin(LAMP_PIN, lampChannel);            // attach the GPIO pin to the channel

  Serial.begin(115200);
  Serial.println();

  // Init the camera module (accordind the camera_config_t defined)
  init_camera();

  // Start WiFi connection
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println(WiFi.localIP());

  // Sync time with NTP
  configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
#if USE_CLIENTSSL == false
  client.setCACert(telegram_cert);
#endif

  // Set the Telegram bot properies
  myBot.setUpdateTime(1000);
  myBot.setTelegramToken(token);

  // Check if all things are ok
  Serial.print("\nTest Telegram connection... ");
  myBot.begin() ? Serial.println("OK") : Serial.println("NOK");

  // Send a welcome message to user when ready
  //  char welcome_msg[64];
  //  snprintf(welcome_msg, 64, "BOT @%s online.\nTry with /takePhoto command.", myBot.getBotName());
  //  myBot.sendTo(userid, welcome_msg);

  // Init the camera module (accordind the camera_config_t defined)
  //  init_camera();

  //Take and send photo
  TBMessage msg;
  msg.sender.id = userid;

  Serial.println("\nSending Photo from CAM");
  if (sendPicture(msg))
    Serial.println("Picture sent successfull");
  else
    myBot.sendMessage(msg, "Error, picture not sent.");

  // Go to sleep
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
  Serial.print("Going to sleep now: "); Serial.println(millis());
  Serial.flush();
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop() {
  //  // A variable to store telegram message data
  //  TBMessage msg;
  //  // if there is an incoming message...
  //  if (myBot.getNewMessage(msg)) {
  //    Serial.print("New message from chat_id: ");
  //    Serial.println(msg.sender.id);
  //    MessageType msgType = msg.messageType;
  //
  //    if (msgType == MessageText) {
  //      // Received a text message
  //      if (msg.text.equalsIgnoreCase("/takePhoto")) {
  //        Serial.println("\nSending Photo from CAM");
  //        if (sendPicture(msg))
  //          Serial.println("Picture sent successfull");
  //        else
  //          myBot.sendMessage(msg, "Error, picture not sent.");
  //      }
  //      else {
  //        Serial.print("\nText message received: ");
  //        Serial.println(msg.text);
  //        String replyStr = "Message received:\n";
  //        replyStr += msg.text;
  //        replyStr += "\nTry with /takePhoto";
  //        myBot.sendMessage(msg, replyStr);
  //      }
  //    }
  //  }
}
cotestatnt commented 2 years ago

Hi @FBMinis

The problem related to your code should be due to this line msg.sender.id = userid; Unfortunately this data structure can lead to some confusion as at some point I decided to treat the sending of messages to a specific user or group in the same way.

In fact the only difference is the ID which in the case of groups is in negative int64. If you modify the sendPicture () function in this way it should also work with the latest version of the library.

size_t sendPicture(int64_t user) {
  // Take Picture with Camera;
  Serial.println("Camera capture requested");

  // Take picture with Camera and send to Telegram
  //  setLamp(100);
  camera_fb_t* fb = esp_camera_fb_get();
  //  setLamp(0);
  if (!fb) {
    Serial.println("Camera capture failed");
    return 0;
  }
  size_t len = fb->len;
  if (!myBot.sendPhoto(user, fb->buf, fb->len)) {
    len = 0;    
  }

  // Clear buffer
  esp_camera_fb_return(fb);
  return len;
}

and off course you have to call the function using userid

 Serial.println("\nSending Photo from CAM");
  if (sendPicture(userid))
    Serial.println("Picture sent successfull");
  else
    myBot.sendTo(userid, "Error, picture not sent.");
FBMinis commented 2 years ago

I made the changes you suggested and it's working again, thank you!