Zum Hauptinhalt springen

Ein kleines anderes Hobby

Nachdem in meinem Bekanntenkreis ein paar Leute fragten, ob ich mich mit Microcontrollern auskennen würde, war die Antwort:
"Nein."
Aber jetzt habe ich mich etwas damit beschäftigt und freue mich bekanntzugeben, die Microcontroller ESP32 und ESP8266 von Espressif in C++ programmieren zu können.
(Wenn das mit denen geht, dann sicherlich auch mit anderen Chips/Modulen anderer Hersteller.)

Weiter unten mein erstes Projekt:


ESP32CAM mit Foto-Upload  auf einen FTP-Server.
Darf kopiert, verändert und in jeglicher Weise benutzt werden.


#include 
#include 
#include "esp_camera.h"
#include "time.h"

#define DEBUG
#define DEBUG_FTP true // true
#define DEBUG_CAM false

// PIR-Cam ist das Modul mit PIR und OLED, M5Cam ist die kleine M5Stack-Cam, diese mit ESP32 Devkit ohne PSRAM compilieren.

//#define PIR_CAM                           // für Modul mit PIR

//#define M5_CAM                            // für M5Stack-Cam

#define LED_CAM                             // für AI-Thinker Modul mit LEDC_CHANNEL_0


#define BUTTON  34                        // L aktiv 

#define PIR_OUT 33                        // H aktiv


//WLAN

const char* ssid = "SSID";

const char* password = "Passwort";


// FTP

#define FTP_ANZAHL 4

String ftp_comm[] = {"USER AAAAA","PASS BBBBB","SYST","Type I"};

String ftp_ret[] = {"331","230","215","200"};

IPAddress ftpserver( 192, 168, 178, 52 );

uint16_t ftpport = 21;


String ftp_pfad = "/Your Path";


//NTP

const char* ntpServer = "pool.ntp.org";

const long  gmtOffset_sec = 3600;

const int   daylightOffset_sec = 3600;


// DeepSleep Timer

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */

#define TIME_TO_SLEEP  120        /* Time ESP32 will go to sleep (in seconds) */


RTC_DATA_ATTR int bootCount = 0;


void print_wakeup_reason(void);


#define WAKE_TIMER   1

#define WAKE_PIR     2


uint16_t wake_reason = 0;                   // Grund für das Aufwecken

  

WiFiClient ftpclient;

WiFiClient dclient;


String uploadFTP(String filename);

String ftpReceive(void);

bool ftpCommand(uint8_t index);


// Kamera

#if defined (PIR_CAM)


#define PWDN_GPIO_NUM 26

#define RESET_GPIO_NUM -1

#define XCLK_GPIO_NUM 32

#define SIOD_GPIO_NUM 13

#define SIOC_GPIO_NUM 12


#define Y9_GPIO_NUM 39

#define Y8_GPIO_NUM 36

#define Y7_GPIO_NUM 23

#define Y6_GPIO_NUM 18

#define Y5_GPIO_NUM 15

#define Y4_GPIO_NUM 4

#define Y3_GPIO_NUM 14

#define Y2_GPIO_NUM 5

#define VSYNC_GPIO_NUM 27

#define HREF_GPIO_NUM 25

#define PCLK_GPIO_NUM 19


#define XCLK_FREQUENZ  20000000

#define RESOLUTION  FRAMESIZE_SXGA

#define BILDNAME "PIR_CAM_"


#elif defined(LED_CAM)


#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 XCLK_FREQUENZ  20000000

#define RESOLUTION  FRAMESIZE_UXGA

#define BILDNAME "LED_CAM_"


#elif defined(M5_CAM)


#define PWDN_GPIO_NUM     -1

#define RESET_GPIO_NUM    15

#define XCLK_GPIO_NUM     27

#define SIOD_GPIO_NUM     25

#define SIOC_GPIO_NUM     23


#define Y9_GPIO_NUM       19

#define Y8_GPIO_NUM       36

#define Y7_GPIO_NUM       18

#define Y6_GPIO_NUM       39

#define Y5_GPIO_NUM        5

#define Y4_GPIO_NUM       34

#define Y3_GPIO_NUM       35

#define Y2_GPIO_NUM       17

#define VSYNC_GPIO_NUM    22

#define HREF_GPIO_NUM     26

#define PCLK_GPIO_NUM     21



#define XCLK_FREQUENZ  20000000

#define RESOLUTION  FRAMESIZE_UXGA

#define BILDNAME "M5_CAM_"


#else

  

#error "Camera Modell nicht ausgewählt"


#endif


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 20MHz or 10MHz for OV2640 double FPS (Experimental)

    .xclk_freq_hz = XCLK_FREQUENZ,

    .ledc_timer = LEDC_TIMER_0,

    .ledc_channel = LEDC_CHANNEL_0,


    .pixel_format = PIXFORMAT_JPEG,//YUV422,GRAYSCALE,RGB565,JPEG

    //.frame_size = RESOLUTION,   //QQVGA-QXGA Do not use sizes above QVGA when not JPEG

    .frame_size = FRAMESIZE_UXGA,

    .jpeg_quality = 10, //0-63 lower number means higher quality

    .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG

};


esp_err_t camera_init(void);

esp_err_t camera_capture(void);

void setSensordaten(void);

void grabPicture(String filename);


//#########################################################


void setup(void)

{

  Serial.begin(115200);


//Increment boot number and print it every reboot

  ++bootCount;

  Serial.println("Boot number: " + String(bootCount));


//Print the wakeup reason for ESP32

  print_wakeup_reason();


  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");


  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  Serial.print("Wifi connect");


  // Wait for connection

  while (WiFi.status() != WL_CONNECTED)

  {

    delay(500);

    Serial.print(".");

  }

  Serial.println("");

  Serial.print("Connected to ");

  Serial.println(ssid);

  Serial.print("IP address: ");

  Serial.println(WiFi.localIP());

  

  esp_err_t err = esp_camera_init(&camera_config);

  if (err == ESP_OK)

  {

    Serial.println("Cam Init ok");

  }

  else  

  {

    Serial.println("Cam Init FAIL");

  }

  setSensordaten();

  

  sensor_t *s = esp_camera_sensor_get();

#ifndef PIR_CAM

  s->set_vflip(s, 1);

  s->set_hmirror(s, 1);

#endif  

}


//----------------------------------------------------------


void loop(void)

{

  String filename = "Bild.jpg";

  Serial.println(filename);

   configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

  uploadFTP(filename);  


  Serial.println("Going to sleep now");

  delay(100);

  Serial.flush(); 


  WiFi.disconnect();

  WiFi.mode(WIFI_OFF);

  btStop();  


#if defined (PIR_CAM)

  esp_sleep_enable_ext0_wakeup((gpio_num_t )BUTTON, LOW);  

  esp_sleep_enable_ext0_wakeup((gpio_num_t )PIR_OUT, HIGH); 


  pinMode(PWDN_GPIO_NUM,PULLUP);                      // Kamera aus

  digitalWrite(PWDN_GPIO_NUM, HIGH);

#endif


  esp_deep_sleep_start();

  

  Serial.println("This will never be printed");

}


//#########################################################

//-------------------- Sleep Tools ------------------------

//#########################################################



void print_wakeup_reason()

{

  esp_sleep_wakeup_cause_t wakeup_reason;


  wakeup_reason = esp_sleep_get_wakeup_cause();


  switch(wakeup_reason)

  {

    case ESP_SLEEP_WAKEUP_EXT0:

      Serial.println("Wakeup caused by external signal using RTC_IO");

      wake_reason = WAKE_PIR;

      break;


    case ESP_SLEEP_WAKEUP_EXT1:

      Serial.println("Wakeup caused by external signal using RTC_CNTL");

      break;


    case ESP_SLEEP_WAKEUP_TIMER:

      Serial.println("Wakeup caused by timer");

      wake_reason = WAKE_TIMER;

      break;


    case ESP_SLEEP_WAKEUP_TOUCHPAD:

      Serial.println("Wakeup caused by touchpad");

      break;

 

    case ESP_SLEEP_WAKEUP_ULP:

      Serial.println("Wakeup caused by ULP program");

      break;


    default:

      Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason);

      break;

  }

}


//#########################################################

//--------------------- CAM Tools -------------------------

//#########################################################


void setSensordaten()

{

  size_t res = 0;

  sensor_t * s = esp_camera_sensor_get();

 

  //res = s->set_framesize(s, (framesize_t)val);        // Framesize      FRAMESIZE_(QQVGA, HQVGA, QVGQ, CIF, VGA, SVGA, XGA, SXGA, UXGA)

       

  res = s->set_quality(s, 10);                          // JPEG Quality   (10...63)  10

  res = s->set_contrast(s, 0);                          // Kontrast       (-2...+2)   0

  res = s->set_brightness(s, 0);                        // Helligkeit     (-2...+2)   0

  res = s->set_saturation(s, 0);                        // Farbsättigung  (-2...+2)   0 

  res = s->set_gainceiling(s, (gainceiling_t) GAINCEILING_2X);      // Verstärkung    GAINCEILING_(2x, 4x, 8x, 16x, 32x, 64x, 128x)   2x

  res = s->set_colorbar(s, 0);                          // Farbbalken     (off/on)   off 

  res = s->set_whitebal(s, 1);                          // Weißbalance    (off/on)    on

  res = s->set_gain_ctrl(s, 1);                         // AGC            (off/on)    on

  res = s->set_exposure_ctrl(s, 1);                     // AEC            (off/on)    on               

//  res = s->set_hmirror(s, val);                         // H-Mirror       (off/on) 

//  res = s->set_vflip(s, val);                           // V-Flip         (off/on) 

//  res = s->set_awb_gain(s, val);                        // Verstärkung AWB

//  res = s->set_agc_gain(s, val);                        // Verstärkung AGC

//  res = s->set_aec_value(s, val);                       // Wert AEC       (0...1200)  

//  res = s->set_aec2(s, val);                            // Wert AEC2

  res = s->set_dcw(s, 1);                             // Downsize       (off/on)    on  

  res = s->set_bpc(s, 0);                             //                (off/on)   off

  res = s->set_wpc(s, 1);                             //                (off/on)    on

  res = s->set_raw_gma(s, 1);                         // RAW-Gamma      (off/on)    on

  res = s->set_lenc(s, 1);                            // Linsenkorr.    (off/on)    on 

//  res = s->set_special_effect(s, val);                  // Special Effekt 

//  res = s->set_wb_mode(s, val);                         // WB Mode         (Auto/Sunny/..) 

  res = s->set_ae_level(s, 0);                        // AE Level        (-2...+2)    0

}


//#########################################################

//--------------------- FTP Tools -------------------------

//#########################################################


String uploadFTP(String filename)

  for (uint8_t i = 0; i < 3; i++)

  {

    camera_fb_t * fb = esp_camera_fb_get();

    esp_camera_fb_return(fb);  

    delay(10);   

  }

  camera_fb_t * fb = esp_camera_fb_get();

   configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

   struct tm timeinfo;

  if(!getLocalTime(&timeinfo)){

    Serial.println("Failed to obtain time");

  }

  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

  char timeHour[3];

  strftime(timeHour,3, "%H", &timeinfo);

  char timeMin[3];

  strftime(timeMin,3, "%M", &timeinfo);

  char timeS[3];

  strftime(timeS,3, "%S", &timeinfo);

  char timeY[5];

  strftime(timeY,5, "%Y", &timeinfo);

  char timeT[3];

  strftime(timeT,3, "%d", &timeinfo);

  char timeM[10];

  strftime(timeM,10, "%B", &timeinfo);



  String Monat = timeM;

  String Tag = timeT;

  String Jahr = timeY;

  String ZeitH = timeHour;

  String ZeitM = timeMin;

  String ZeitS = timeS;


  String returnText = "";

  String meldung = "";

  bool flag_ftp_ok = true;


  String bildnummer = "00000" + String(bootCount, DEC);

  bildnummer = bildnummer.substring(bildnummer.length() - 5);

  String dateiname = String(wake_reason, DEC) + "_" + Tag + "_" + Monat + "_" + Jahr + "_" + ZeitH + ZeitM + ZeitS + ".jpg";

  

  if (ftpclient.connect(ftpserver, ftpport)) // 21 = FTP server

  { 

    Serial.println(F("Command connected"));

  }

  else

  {

    Serial.println(F("Command connection failed while log-in"));

    return "FTP Error";

  }


  returnText = ftpReceive();

  meldung = returnText.substring(0,3); // erste 3 Zeichen

  if (DEBUG_FTP) Serial.println("Return: " + meldung);

  if (meldung == "220")

  {

    for (uint8_t i = 0; i < FTP_ANZAHL; i++)

    {

      if (!ftpCommand(i))

      {

        flag_ftp_ok = false;

        break;

      }  

    }  


    if (flag_ftp_ok)    // alles klar, PASV senden

    {

      uint8_t werte[6];

      uint8_t pos = 0;

      uint8_t start = 0;

      uint8_t komma = 0;

      uint16_t dport = 0;

      

      if (DEBUG_FTP) Serial.println("PASV senden");

      ftpclient.println("PASV");

      String returnText = ftpReceive();

      Serial.println(returnText);

      String meldung = returnText.substring(0,3); // erste 3 Zeichen

      if (DEBUG_FTP) Serial.println("Return: " + meldung); 

       if (meldung == "421")

       {Serial.println("Scheisse");

       }

      if (meldung == "227")

      {

        Serial.println("227 empfangen.");

        start = returnText.indexOf("(");

        for (uint8_t i = 0; i < 5; i++)

        {

          komma = returnText.indexOf(",", start + 1);

          werte[pos] = returnText.substring(start + 1, komma).toInt();

          if (DEBUG_FTP) Serial.println(werte[pos], DEC);

          pos++; 

          start = komma;

        }       

        werte[pos] = returnText.substring(start + 1).toInt();

        if (DEBUG_FTP) Serial.println(werte[pos], DEC);

        dport = (werte[4] << 8) | werte[5];

        if (DEBUG_FTP) Serial.println("Datenport: " + String(dport, DEC));

        if (dclient.connect(ftpserver, dport))

        {

          Serial.println(F("Data connected"));

        }

        else

        {

          Serial.println(F("Data connection failed"));

          ftpclient.stop();

          return "Error";

        }

        if (DEBUG_FTP) Serial.println("CWD " + ftp_pfad);

        ftpclient.println("CWD " + ftp_pfad);

        String returnText = ftpReceive();

        String meldung = returnText.substring(0,3); // erste 3 Zeichen

        if (DEBUG_FTP) Serial.println("Return: " + meldung); 

      

        if (meldung == "250")

        {

          Serial.println(dateiname);

          if (DEBUG_FTP) Serial.println("STOR " + dateiname);

          ftpclient.println("STOR " + dateiname);

          String returnText = ftpReceive();

          String meldung = returnText.substring(0,3); // erste 3 Zeichen

          if (DEBUG_FTP) Serial.println("Return: " + meldung); 

          if (meldung == "150")

          {

            Serial.print(F("Writing..."));

            dclient.write((const uint8_t *)fb->buf, fb->len);

            Serial.println(F("OK"));

          }          

        }        

        dclient.stop();

        Serial.println(F("Data disconnected"));

      }  

    }


  }

 

  ftpclient.println(F("QUIT"));


  ftpclient.stop();

  Serial.println(F("Command disconnected"));


  esp_camera_fb_return(fb);  


  return "OK";


//----------------------------------------------------------


String ftpReceive()  

{                       // gibt nur die letzte Zeile zurück

  Serial.println("FTP-Receive");

  char thisByte;

  uint8_t count = 0;

  String outText[20];

  String retText = "";

  

  while (!ftpclient.available()) delay(100);  // auf Daten warten


  while (ftpclient.available())

  {

    thisByte = ftpclient.read();

#ifdef DEBUG_FTP

    if (DEBUG_FTP) Serial.write(thisByte);

#endif

    if (thisByte == 13)          // return

    {

      count++;      // nächste Zeile

    }

    else if (thisByte != 10)          // newline

    {

      outText[count] += thisByte;

    }

  }  

  for (uint8_t i = 20; i > 0; i--)

  {

    if (outText[i - 1] > "")

    {

      retText = outText[i - 1];

      break;

    }  

  }  

  return retText;


//----------------------------------------------------------


bool ftpCommand(uint8_t index)

{

  if (DEBUG_FTP) Serial.println(ftp_comm[index]);

  ftpclient.println(ftp_comm[index]);

  String returnText = ftpReceive();

  String meldung = returnText.substring(0,3); // erste 3 Zeichen

  if (DEBUG_FTP) Serial.println("Return: " + meldung);


  if (meldung == ftp_ret[index])

  {

    return true;

  }

  else  

  {

    return false;

  }

}