#include <Wire.h>
#include <WiFi.h>
#include "esp_camera.h"
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <time.h>
#include "sntp.h"
#define ON 2
#define UP 12
#define DOWN 13
#define I2C_SDA 15
#define I2C_SCL 14
TwoWire I2Cbus = TwoWire(0);
const char* ssid = "It's me";
const char* password = "asder2001";
String time_curr="00:00 AM";
const char* ntpServer1 = "pool.ntp.org";
const char* ntpServer2 = "time.nist.gov";
const long gmtOffset_sec = 16200;
const int daylightOffset_sec = 3600;
int lastTime=0;
const char* time_zone = "CET-1CEST,M3.5.0,M10.5.0/3"; // TimeZone rule for Europe/Rome including daylight adjustment rules (optional)
String CHAT_ID = "1265427106";
String BOTtoken = "6176846745:AAHKysQFnpcCHlAv84oNtreNDVlDd46wlac"; // your Bot Token (Get from Botfather)
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
#define MPU_ADDR 0x68
#define CAMERA_MODEL_AI_THINKER
#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
WiFiClientSecure clientTCP;
UniversalTelegramBot bot(BOTtoken, clientTCP);
int botRequestDelay = 1000;
unsigned long lastTimeBotRan;
void configInitCamera(){
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
//init with high specs to pre-allocate larger buffers
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 4; //0-63 lower number means higher quality
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 10; //0-63 lower number means higher quality
config.fb_count = 1;
}
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
delay(1000);
ESP.restart();
}
// Drop down frame size for higher initial frame rate
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_CIF); // UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
}
float jerk=0;
int m_index=0;
String messageText="null";
void handleNewMessages(int numNewMessages) {
Serial.print("Handle New Messages: ");
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
if (chat_id != CHAT_ID){
bot.sendMessage(chat_id, "Unauthorized user", "");
continue;
}
// Print the received message
String text = bot.messages[i].text;
Serial.println(text);
String from_name = bot.messages[i].from_name;
if (text == "/start") {
String welcome = "Welcome , " + from_name + "\n";
welcome += "Use the following commands to interact with the ESP32-CAM \n";
welcome += "/photo : takes a new photo\n";
welcome += "/send : send msg \n";
bot.sendMessage(CHAT_ID, welcome, "");
}
if (text == "/send") {
Serial.println("Change flash LED state");
bot.sendMessage(CHAT_ID, time_curr, "");
}
if (text == "/photo") {
Serial.println("New photo request");
bot.sendMessage(CHAT_ID, "trying boss", "");
sendTelegramPhoto();
}else{
messageText=text;
}
}
}
int charArrayToInt(const char* arr) {
int result = 0;
for (int i = 0; i < 2; i++) {
result = result * 10 + (arr[i] - '0');
}
return result;
}
String minute;
int hourInt;
int minuteInt;
int sec;
int temperature=15;
void printLocalTime()
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time");
return;
}
hourInt = timeinfo.tm_hour;
minuteInt = timeinfo.tm_min;
sec = timeinfo.tm_sec;
if(minuteInt<10){
minute=String("0")+String(minuteInt);
}else
{
minute=String(minuteInt);
}
if(hourInt>12){
hourInt=hourInt-12;
time_curr=minute+" PM";
}
else if(hourInt==0){
hourInt=12;
time_curr=minute+" AM";
}else if(hourInt<10){
time_curr=minute+" AM";
}
else{
time_curr=minute+" AM";
}
Serial.print(hourInt);
Serial.print(":");
Serial.println(time_curr);
}
String sendTelegramPhoto() {
Serial.println("trying to send Photo");
const char* myDomain = "api.telegram.org";
String getAll = "";
String getBody = "";
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
bot.sendMessage(CHAT_ID, "failed", "");
delay(1000);
ESP.restart();
return "Camera capture failed";
}
Serial.println("Connect to " + String(myDomain));
if (clientTCP.connect(myDomain, 443)) {
Serial.println("Connection successful");
String head = "--Vwatch\r\nContent-Disposition: form-data; name=\"chat_id\"; \r\n\r\n" + CHAT_ID + "\r\n--Vwatch\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--Vwatch--\r\n";
uint16_t imageLen = fb->len;
uint16_t extraLen = head.length() + tail.length();
uint16_t totalLen = imageLen + extraLen;
clientTCP.println("POST /bot"+BOTtoken+"/sendPhoto HTTP/1.1");
clientTCP.println("Host: " + String(myDomain));
clientTCP.println("Content-Length: " + String(totalLen));
clientTCP.println("Content-Type: multipart/form-data; boundary=Vwatch");
clientTCP.println();
clientTCP.print(head);
uint8_t *fbBuf = fb->buf;
size_t fbLen = fb->len;
for (size_t n=0;n<fbLen;n=n+1024) {
if (n+1024<fbLen) {
clientTCP.write(fbBuf, 1024);
fbBuf += 1024;
}
else if (fbLen%1024>0) {
size_t remainder = fbLen%1024;
clientTCP.write(fbBuf, remainder);
}
}
clientTCP.print(tail);
esp_camera_fb_return(fb);
int waitTime = 10000; // timeout 10 seconds
long startTimer = millis();
boolean state = false;
while ((startTimer + waitTime) > millis()){
Serial.print(".");
delay(100);
while (clientTCP.available()) {
char c = clientTCP.read();
if (state==true) getBody += String(c);
if (c == '\n') {
if (getAll.length()==0) state=true;
getAll = "";
}
else if (c != '\r')
getAll += String(c);
startTimer = millis();
}
if (getBody.length()>0) break;
}
clientTCP.stop();
Serial.println(getBody);
}
else {
getBody="Connected to api.telegram.org failed.";
Serial.println("Connected to api.telegram.org failed.");
}
return getBody;
}
void timeavailable(struct timeval *t)
{
Serial.println("Got time adjustment from NTP!");
printLocalTime();
}
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &I2Cbus, OLED_RESET);
Adafruit_MPU6050 mpu;
sensors_event_t a, g, temp;
bool mpuState=false;
String gyroText="not available";
void showMessage(int n){
String result;
for (int i = n*100; i < (n+1)*100; i++) {
if(i<messageText.length()){
result += messageText[i];
}
}
display.clearDisplay();
display.setCursor(4,4);
display.setTextSize(1);
display.print(result);
display.display();
}
void configGyro(){
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
Serial.print("Accelerometer range set to: ");
switch (mpu.getAccelerometerRange()) {
case MPU6050_RANGE_2_G:
Serial.println("+-2G");
break;
case MPU6050_RANGE_4_G:
Serial.println("+-4G");
break;
case MPU6050_RANGE_8_G:
Serial.println("+-8G");
break;
case MPU6050_RANGE_16_G:
Serial.println("+-16G");
break;
}
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
Serial.print("Gyro range set to: ");
switch (mpu.getGyroRange()) {
case MPU6050_RANGE_250_DEG:
Serial.println("+- 250 deg/s");
break;
case MPU6050_RANGE_500_DEG:
Serial.println("+- 500 deg/s");
break;
case MPU6050_RANGE_1000_DEG:
Serial.println("+- 1000 deg/s");
break;
case MPU6050_RANGE_2000_DEG:
Serial.println("+- 2000 deg/s");
break;
}
mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);
Serial.print("Filter bandwidth set to: ");
switch (mpu.getFilterBandwidth()) {
case MPU6050_BAND_260_HZ:
Serial.println("260 Hz");
break;
case MPU6050_BAND_184_HZ:
Serial.println("184 Hz");
break;
case MPU6050_BAND_94_HZ:
Serial.println("94 Hz");
break;
case MPU6050_BAND_44_HZ:
Serial.println("44 Hz");
break;
case MPU6050_BAND_21_HZ:
Serial.println("21 Hz");
break;
case MPU6050_BAND_10_HZ:
Serial.println("10 Hz");
break;
case MPU6050_BAND_5_HZ:
Serial.println("5 Hz");
break;
}
}
bool time_show=true;
bool message_show=false;
void showTime(){
printLocalTime();
display.clearDisplay();
display.setCursor(5,20);
display.setTextSize(2);
display.print(hourInt);
display.print(":");
display.print(time_curr);
if(mpuState){
display.setCursor(30,50);
display.setTextSize(1);
display.print(temperature);
display.print(" deg C");
}
display.display();
delay(500);
}
int r=3;
void newMessage(){
if(r==7){
r=3;
}
r++;
display.clearDisplay();
display.drawCircle(100, 40, r, WHITE);
//Display the image
display.display();
delay(500);
}
void setup(){
sntp_set_time_sync_notification_cb( timeavailable );
sntp_servermode_dhcp(1);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
configInitCamera();
WiFi.mode(WIFI_STA);
clientTCP.setCACert(TELEGRAM_CERTIFICATE_ROOT);
Serial.begin(115200);
I2Cbus.begin(I2C_SDA, I2C_SCL, 100000);
UniversalTelegramBot bot(BOTtoken, clientTCP);
//WiFi.begin("Wokwi-GUEST", "", 6);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
}
if (!mpu.begin(MPU_ADDR,&I2Cbus,101)) {
Serial.println("Failed to find MPU6050 chip");
mpuState=false;
}else{
Serial.println("gyro working");
configGyro();
mpuState=true;
}
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
{
Serial.printf("SSD1306 OLED display failed to initalize.\nCheck that display SDA is connected to pin %d and SCL connected to pin %d\n", I2C_SDA, I2C_SCL);
while (true);
}
display.clearDisplay();
Serial.println("showing display");
display.setCursor(5, 5);
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
lastTime=millis();
if(mpuState){
mpu.getEvent(&a, &g, &temp);
temperature=temp.temperature;
}
}
void loop(){
if (millis() > lastTimeBotRan + botRequestDelay) {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
Serial.println(numNewMessages);
while (numNewMessages) {
Serial.println("got response");
handleNewMessages(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
lastTimeBotRan = millis();
}
/* Get new sensor events with the readings */
if(mpuState){
mpu.getEvent(&a, &g, &temp);
jerk=a.acceleration.x*a.acceleration.x+a.acceleration.y*a.acceleration.y+(a.acceleration.z-1)*(a.acceleration.z-1);
temperature=temp.temperature;
}
if(touchRead(ON) < 50){
if(!message_show && !time_show){
time_show=true;
}else if(time_show && touchRead(UP)<50){
time_show=false;
message_show=true;
m_index=0;
}
if(message_show){
time_show=false;
message_show=false;
}
}
if(jerk>1){
time_show=false;
message_show=false;
}
if(message_show){
if(touchRead(UP)<50){
showMessage(m_index);
}else if(touchRead(DOWN)<50){
m_index+=1;
showMessage(m_index);
}
}else{
if(touchRead(UP)<50){
bot.sendMessage(CHAT_ID, "YES", "");
}else if(touchRead(DOWN)<50){
bot.sendMessage(CHAT_ID, "NO", "");
}
if(touchRead(UP)<50 && touchRead(DOWN)<50){
sendTelegramPhoto();
}
}
display.clearDisplay();
display.print(" ");
display.display();
if(Serial.available()){
lastTime=millis();
}
}