For when you are ready ESP32CAM - FTP code.
#include "sdkconfig.h" // used for log printing
#include "esp_system.h"
#include "freertos/FreeRTOS.h" //freeRTOS items to be used
#include "freertos/task.h"
#include "certs.h"
#include "esp_camera.h"
#include "soc/soc.h" // Disable brownout problems
#include "soc/rtc_cntl_reg.h" // Disable brownout problems
#include "driver/rtc_io.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include "ESP32_FTPClient.h"
#include <PubSubClient.h>
#include <ESP32Time.h>
//
WiFiClient wifiClient; // do the WiFi instantiation thing
PubSubClient MQTTclient( mqtt_server, mqtt_port, wifiClient ); //do the MQTT instantiation thing
ESP32_FTPClient ftp (ftp_server, ftp_user, ftp_pass, 5000, 2);
ESP32Time rtc;
////
//#define evtDoMQTTParse ( 1 << 0 ) // declare an event
//EventGroupHandle_t eg; // variable for the event group handle
////
SemaphoreHandle_t sema_MQTT_KeepAlive;
SemaphoreHandle_t sema_mqttOK;
////
QueueHandle_t xQ_Message; // payload and topic queue of MQTT payload and topic
const int payloadSize = 300;
struct stu_message
{
char payload [payloadSize] = {'\0'};
String topic ;
} x_message;
////
int mqttOK = 0;
bool TimeSet = false;
bool FlashMode = false;
//
void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case SYSTEM_EVENT_STA_CONNECTED:
log_i("Connected to WiFi access point");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
log_i("Disconnected from WiFi access point");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
log_i("WiFi client disconnected");
break;
default: break;
}
} // void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
//
void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
// clear locations
memset( x_message.payload, '\0', payloadSize );
x_message.topic = ""; //clear string buffer
x_message.topic.concat( topic );
int i = 0;
for ( i; i < length; i++)
{
x_message.payload[i] = ((char)payload[i]);
}
x_message.payload[i] = '\0';
xQueueOverwrite( xQ_Message, (void *) &x_message );// send data to queue
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////
void setup()
{
pinMode( GPIO_NUM_4, OUTPUT);
digitalWrite( GPIO_NUM_4, LOW);
//
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
//
//eg = xEventGroupCreate(); // get an event group handle
//
x_message.topic.reserve( payloadSize );
//
xQ_Message = xQueueCreate( 1, sizeof(stu_message) );
//
sema_mqttOK = xSemaphoreCreateBinary();
xSemaphoreGive( sema_mqttOK );
//
xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 7000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fparseMQTT, "fparseMQTT", 9000, NULL, 4, NULL, 1 ); // assign all to core 1, WiFi in use.
xTaskCreatePinnedToCore( fmqttWatchDog, "fmqttWatchDog", 3000, NULL, 2, NULL, 1 );
if ( configInitCamera() )
{
log_i(" start camera task" );
xTaskCreatePinnedToCore( capturePhoto_sendFTP, "capturePhoto_sendFTP", 60000, NULL, 6, NULL, 1 );
} else {
log_i( " camera failed to initilize, rebooting in 5." );
vTaskDelay( 2000 );
ESP.restart();
}
} // void setup()
////
void capturePhoto_sendFTP( void *pvParameters )
{
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 1000 * 5; //delay for mS
//!!!!!Must wait for MQTT connection and proper setup of the sema_MQTT_KeepAlive!!!!
while ( !MQTTclient.connected() )
{
vTaskDelay( 500 );
}
for (;;)
{
log_i( "tick");
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
{
camera_fb_t * fb = NULL; // pointer
fb = esp_camera_fb_get();
if (!fb)
{
log_i( "Camera capture failed" );
esp_camera_fb_return(fb);
} else
{
ftp.OpenConnection(); // try open FTP
if ( ftp.isConnected() )
{
//try send file ftp
ftp.ChangeWorkDir( ftp_path );
ftp.DeleteFile( ftp_file_name );
ftp.InitFile( ftp_file_type ); //"Type I"
ftp.NewFile( ftp_file_name );
ftp.WriteData( (unsigned char *)fb->buf, fb->len );
ftp.CloseFile();
ftp.CloseConnection();
}
esp_camera_fb_return(fb); //return the frame buffer back to the driver for reuse
}
}
xSemaphoreGive( sema_MQTT_KeepAlive );
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
}
vTaskDelete( NULL );
} //void capturePhoto_sendFTP( void *pvParameters )
////
void configureCameraSettings_grpE( int _lenC, int _Hmirror, int _Vflip, int _dcw, int _colorbar )
{
sensor_t * s = esp_camera_sensor_get();
s->set_lenc(s, _lenC); // 0 = disable , 1 = enable
s->set_hmirror(s, _Hmirror); // 0 = disable , 1 = enable
s->set_vflip(s, _Vflip); // 0 = disable , 1 = enable
s->set_dcw(s, _dcw); // 0 = disable , 1 = enable
////s->set_colorbar(s, _colorbar); // 0 = disable , 1 = enable
}
////
void configureCameraSettings_grpD( int _gc, int _agc, int _celing, int _bpc, int _wpc, int _gma )
{
sensor_t * s = esp_camera_sensor_get();
s->set_gain_ctrl(s, _gc); // 0 = disable , 1 = enable
s->set_agc_gain(s, _agc); // 0 to 30
s->set_gainceiling(s, (gainceiling_t)_celing); // 0 to 6
s->set_bpc(s, _bpc); // 0 = disable , 1 = enable
s->set_wpc(s, _wpc); // 0 = disable , 1 = enable
s->set_raw_gma(s, _gma); // 0 = disable , 1 = enable
}
////
void configureCameraSettings_grpC( int _exctl, int _aec2, int _ae, int _aec )
{
sensor_t * s = esp_camera_sensor_get();
s->set_exposure_ctrl(s, _exctl); // 0 = disable , 1 = enable
s->set_aec2(s, _aec2); // 0 = disable , 1 = enable
s->set_ae_level(s, _ae); // -2 to 2
////s->set_aec_value(s, _aec); // 0 to 1200 CAUSES BLACK IMAGE????
}
////
void configureCameraSettings_grpB( int se, int wb, int awb, int wbmode )
{
sensor_t * s = esp_camera_sensor_get();
s->set_special_effect(s, se); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
s->set_whitebal(s, wb); // 0 = disable , 1 = enable
s->set_awb_gain(s, awb); // 0 = disable , 1 = enable
s->set_wb_mode(s, wbmode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
}
////
void configureCameraSettings_grpA(int brightness, int contrast, int saturation )
{
if ( ((brightness > -3) && (brightness < 3)) && ((contrast > -3) && (contrast < 3)) && ((saturation > -3) && (saturation < 3)) )
{
sensor_t * s = esp_camera_sensor_get();
s->set_brightness( s, brightness ); // -2 to 2
s->set_contrast( s, contrast ); // -2 to 2
s->set_saturation( s, saturation ); // -2 to 2
}
} //void configureCameraSettings()
////
void configureCameraSettings()
{
sensor_t * s = esp_camera_sensor_get(); //see certs.h for more info
s->set_brightness(s, -1); // -2 to 2 **************************
s->set_contrast(s, 0); // -2 to 2
s->set_saturation(s, 0); // -2 to 2
s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
s->set_whitebal(s, 1); // 0 = disable , 1 = enable
s->set_awb_gain(s, 1); // 0 = disable , 1 = enable
s->set_wb_mode(s, 0); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
s->set_exposure_ctrl(s, 1); // 0 = disable , 1 = enable
s->set_aec2(s, 0); // 0 = disable , 1 = enable
s->set_ae_level(s, 0); // -2 to 2
s->set_aec_value(s, 300); // 0 to 1200
s->set_gain_ctrl(s, 1); // 0 = disable , 1 = enable
s->set_agc_gain(s, 0); // 0 to 30
s->set_gainceiling(s, (gainceiling_t)0); // 0 to 6
s->set_bpc(s, 0); // 0 = disable , 1 = enable
s->set_wpc(s, 1); // 0 = disable , 1 = enable
s->set_raw_gma(s, 1); // 0 = disable , 1 = enable
s->set_lenc(s, 1); // 0 = disable , 1 = enable
s->set_hmirror(s, 0); // 0 = disable , 1 = enable
s->set_vflip(s, 0); // 0 = disable , 1 = enable
s->set_dcw(s, 1); // 0 = disable , 1 = enable
s->set_colorbar(s, 0); // 0 = disable , 1 = enable
} //void configureCameraSettings()
////
bool configInitCamera()
{
camera_config_t config = {}; // Stores the camera configuration parameters
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = GPIO_NUM_5; //Y2
config.pin_d1 = GPIO_NUM_18; //Y3
config.pin_d2 = GPIO_NUM_19; //Y4
config.pin_d3 = GPIO_NUM_21; //Y5
config.pin_d4 = GPIO_NUM_36; //Y6
config.pin_d5 = GPIO_NUM_39; //Y7
config.pin_d6 = GPIO_NUM_34; //Y8
config.pin_d7 = GPIO_NUM_35; // Y9
config.pin_xclk = GPIO_NUM_0; //XCLK
config.pin_pclk = GPIO_NUM_22; //PCLK
config.pin_vsync = GPIO_NUM_25; //VSSYNC
config.pin_href = GPIO_NUM_23; // HREF
config.pin_sscb_sda = GPIO_NUM_26; //SIOD
config.pin_sscb_scl = GPIO_NUM_27; //SIOC
config.pin_pwdn = GPIO_NUM_32; //PWDN
config.pin_reset = -1; //RESET
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG; //assuming default is has PSRAM
config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10; //0-63 lower number means higher quality
config.fb_count = 2;
// Initialize the Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
log_i("Camera init failed with error %d", err );
return false;
} else {
configureCameraSettings();
return true;
}
} //void configInitCamera()
////
void connectToWiFi()
{
int TryCount = 0;
while ( WiFi.status() != WL_CONNECTED )
{
TryCount++;
WiFi.disconnect();
WiFi.begin( SSID, PASSWORD );
vTaskDelay( 2500 );
if ( TryCount == 10 )
{
ESP.restart();
}
}
WiFi.onEvent( WiFiEvent );
}
////
void MQTTkeepalive( void *pvParameters )
{
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 250; //delay for ms
for (;;)
{
//check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
{
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // !!!!!whiles MQTTlient.loop() is running no other mqtt operations should be in process!!!!!
MQTTclient.loop();
xSemaphoreGive( sema_MQTT_KeepAlive );
}
else {
if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
{
connectToWiFi();
}
connectToMQTT();
}
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
}
vTaskDelete ( NULL );
}
////
void connectToMQTT()
{
byte mac[5]; // create client ID from mac address
WiFi.macAddress(mac); // get mac address
String clientID = String(mac[0]) + String(mac[4]) ; // use mac address to create clientID
while ( !MQTTclient.connected() )
{
MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password );
vTaskDelay( 250 );
}
MQTTclient.setCallback( mqttCallback );
MQTTclient.subscribe( topicOK );
MQTTclient.subscribe( topicGrpA );
MQTTclient.subscribe( topicGrpB );
MQTTclient.subscribe( topicGrpC );
MQTTclient.subscribe( topicGrpD );
MQTTclient.subscribe( topicGrpE );
MQTTclient.subscribe( topicFlash );
} //void connectToMQTT()
//////
void fmqttWatchDog( void * paramater )
{
int UpdateImeTrigger = 86400; //seconds in a day
int UpdateTimeInterval = 85000; // get another reading when = UpdateTimeTrigger
int maxNonMQTTresponse = 3;
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = 60000; //delay for mS
for (;;)
{
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
xSemaphoreTake( sema_mqttOK, portMAX_DELAY ); // update mqttOK
mqttOK++;
xSemaphoreGive( sema_mqttOK );
if ( mqttOK >= maxNonMQTTresponse )
{
log_i( "mqtt watchdog rest" );
vTaskDelay( 200 );
ESP.restart();
}
UpdateTimeInterval++; // trigger new time get
if ( UpdateTimeInterval >= UpdateImeTrigger )
{
TimeSet = false; // sets doneTime to false to get an updated time after a days count of seconds
UpdateTimeInterval = 0;
}
}
vTaskDelete( NULL );
} //void fmqttWatchDog( void * paramater )
////
void fparseMQTT( void *pvParameters )
{
struct stu_message px_message;
for (;;)
{
if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
{
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
mqttOK = 0;
xSemaphoreGive( sema_mqttOK );
if ( !TimeSet)
{
if ( String(px_message.topic) == topicOK )
{
String temp = "";
temp = px_message.payload[0];
temp += px_message.payload[1];
temp += px_message.payload[2];
temp += px_message.payload[3];
int year = temp.toInt();
temp = "";
temp = px_message.payload[5];
temp += px_message.payload[6];
int month = temp.toInt();
temp = "";
temp = px_message.payload[8];
temp += px_message.payload[9];
int day = temp.toInt();
temp = "";
temp = px_message.payload[11];
temp += px_message.payload[12];
int hour = temp.toInt();
temp = "";
temp = px_message.payload[14];
temp += px_message.payload[15];
int min = temp.toInt();
rtc.setTime( 0, min, hour, day, month, year );
log_i( "%s rtc %s ", px_message.payload, rtc.getTime() );
TimeSet = true;
}
}
if ( String(px_message.topic) == topicGrpA )
{
//finding first letter
String sTmp = String( px_message.payload );
int commaIndex = sTmp.indexOf(',');
if ( sTmp.substring(0, commaIndex) == "a" );
{
int commaIndex = sTmp.indexOf(',');
int brt = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int ctrast = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) ); // chop off begining of message
int sat = (sTmp.substring(0, commaIndex)).toInt();
configureCameraSettings_grpA( brt, ctrast, sat );
}
}
if ( String(px_message.topic) == topicGrpB )
{
String sTmp = String( px_message.payload );
int commaIndex = sTmp.indexOf(',');
if ( sTmp.substring(0, commaIndex) == "b" );
{
int commaIndex = sTmp.indexOf(',');
int se = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int wbb = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int wba = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int wbm = (sTmp.substring(0, commaIndex)).toInt();
configureCameraSettings_grpB( se, wbb, wba, wbm );
}
}
if ( String(px_message.topic) == topicGrpC )
{
String sTmp = String( px_message.payload );
int commaIndex = sTmp.indexOf(',');
if ( sTmp.substring(0, commaIndex) == "c" );
{
int commaIndex = sTmp.indexOf(',');
int ex = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int aec2 = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int ae = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int aec = (sTmp.substring(0, commaIndex)).toInt();
configureCameraSettings_grpC( ex, aec2, ae, aec );
}
}
if ( String(px_message.topic) == topicGrpD )
{
String sTmp = String( px_message.payload );
int commaIndex = sTmp.indexOf(',');
if ( sTmp.substring(0, commaIndex) == "d" );
{
int commaIndex = sTmp.indexOf(',');
int gc = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int agc = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int celing = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int bpc = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int wpc = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int gma = (sTmp.substring(0, commaIndex)).toInt();
configureCameraSettings_grpD( gc, agc, celing, bpc, wpc, gma );
}
}
if ( String(px_message.topic) == topicGrpE )
{
String sTmp = String( px_message.payload );
int commaIndex = sTmp.indexOf(',');
if ( sTmp.substring(0, commaIndex) == "e" );
{
int commaIndex = sTmp.indexOf(',');
int lenC = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int Hmirror = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int Vflip = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int dcw = (sTmp.substring(0, commaIndex)).toInt();
sTmp.remove( 0, (commaIndex + 1) );
int colorbar = (sTmp.substring(0, commaIndex)).toInt();
configureCameraSettings_grpE( lenC, Hmirror, Vflip, dcw, colorbar );
}
}
if ( String(px_message.topic) == topicFlash )
{
FlashMode = bool(px_message.payload);
}
} //if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
} //for(;;)
vTaskDelete( NULL );
} // void fparseMQTT( void *pvParameters )
////
void loop() {}