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;
}
}