Newer
Older

Zoe Michaela Dietmar Pfister
committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*
Snippet content:
Takes pictures with ESP32-CAM, saves images to MicroSD Card.
Measures air temperature and relative humidity from SHT85.
We use the ESP-CAM for the SHT85 readout because of the
limited wire length that can be used for I2C sensors - the
camera sits at the top of the mast next to the SHT85 sensor.
ESP-CAM code partially copied from
https://dronebotworkshop.com/esp32-cam-microsd/
NOTE: To flash the ESP-CAM, pin IO0 has to be connected to GND!
TODO: because of this limitation, it would be nice to implement
over-the-air updates for the camera at one point.
*/
// Include Required Libraries
// I2C: SHT85, RTC
#include "ESPNow.hpp"
#include "NoDataAvailableException.hpp"
#include "RTClib.h" // adafruit/RTClib @^2.1.1
#include "Sht85.hpp"
#include "ram_caching.hpp"
#include <Arduino.h>
#include <Wire.h>
// Camera libraries
#include "driver/rtc_io.h"
#include "esp_camera.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/soc.h"
// MicroSD Libraries
#include "FS.h"
#include "SD_MMC.h"
// Pin definitions for 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
// Pin definitions for I2C (SHT85, RTC)
// This is different from the pins on the ESP32-C3-DevKit boards!

Zoe Michaela Dietmar Pfister
committed
// LED control
#define LEDpin 4

marieschroeder
committed
// Deep Sleep Settings
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 10 /* Time ESP32 will go to sleep (in seconds) */
// Counting files on sd card for saving in the name of each image
int fileCountOnSD = 0; // for counting files

Zoe Michaela Dietmar Pfister
committed
// string for saving the time
char time_string[20];
// number of images to take: the last one is saved
// this is done because the first few images have a green tint otherwise
int img_number = 3;
RTC_DS3231 rtc; // I2C address: 0x68
camera_config_t camera_config; // camera configuration parameters
void camera_configESPCamera()
{
// Configure Camera parameters
camera_config.ledc_channel = LEDC_CHANNEL_0;
camera_config.ledc_timer = LEDC_TIMER_0;
camera_config.pin_d0 = Y2_GPIO_NUM;
camera_config.pin_d1 = Y3_GPIO_NUM;
camera_config.pin_d2 = Y4_GPIO_NUM;
camera_config.pin_d3 = Y5_GPIO_NUM;
camera_config.pin_d4 = Y6_GPIO_NUM;
camera_config.pin_d5 = Y7_GPIO_NUM;
camera_config.pin_d6 = Y8_GPIO_NUM;
camera_config.pin_d7 = Y9_GPIO_NUM;
camera_config.pin_xclk = XCLK_GPIO_NUM;
camera_config.pin_pclk = PCLK_GPIO_NUM;
camera_config.pin_vsync = VSYNC_GPIO_NUM;
camera_config.pin_href = HREF_GPIO_NUM;
camera_config.pin_sccb_sda = SIOD_GPIO_NUM;
camera_config.pin_sccb_scl = SIOC_GPIO_NUM;

Zoe Michaela Dietmar Pfister
committed
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
camera_config.pin_pwdn = PWDN_GPIO_NUM;
camera_config.pin_reset = RESET_GPIO_NUM;
camera_config.xclk_freq_hz = 20000000;
camera_config.pixel_format = PIXFORMAT_JPEG; // Choices are YUV422, GRAYSCALE, RGB565, JPEG
// Select lower framesize if the camera doesn't support PSRAM
if (psramFound()) {
camera_config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
camera_config.jpeg_quality = 10; // 10-63 lower number means higher quality
camera_config.fb_count = 2;
} else {
camera_config.frame_size = FRAMESIZE_SVGA;
camera_config.jpeg_quality = 12;
camera_config.fb_count = 1;
}
// Initialize the Camera
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// Camera quality adjustments
sensor_t *s = esp_camera_sensor_get();
// TODO: this is copied from an online tutorial, it's possible that we don't need this at all!
// BRIGHTNESS (-2 to 2)
s->set_brightness(s, 0);
// CONTRAST (-2 to 2)
s->set_contrast(s, 0);
// SATURATION (-2 to 2)
s->set_saturation(s, 0);
// SPECIAL EFFECTS (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 -
// Sepia)
s->set_special_effect(s, 0);
// WHITE BALANCE (0 = Disable , 1 = Enable)
s->set_whitebal(s, 1);
// AWB GAIN (0 = Disable , 1 = Enable)
s->set_awb_gain(s, 1);
// WB MODES (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
s->set_wb_mode(s, 0);
// EXPOSURE CONTROLS (0 = Disable , 1 = Enable)
s->set_exposure_ctrl(s, 1);
// AEC2 (0 = Disable , 1 = Enable)
s->set_aec2(s, 0);
// AE LEVELS (-2 to 2)
s->set_ae_level(s, 0);
// AEC VALUES (0 to 1200)
s->set_aec_value(s, 300);
// GAIN CONTROLS (0 = Disable , 1 = Enable)
s->set_gain_ctrl(s, 1);
// AGC GAIN (0 to 30)
s->set_agc_gain(s, 0);
// GAIN CEILING (0 to 6)
s->set_gainceiling(s, (gainceiling_t)0);
// BPC (0 = Disable , 1 = Enable)
s->set_bpc(s, 0);
// WPC (0 = Disable , 1 = Enable)
s->set_wpc(s, 1);
// RAW GMA (0 = Disable , 1 = Enable)
s->set_raw_gma(s, 1);
// LENC (0 = Disable , 1 = Enable)
s->set_lenc(s, 1);
// HORIZ MIRROR (0 = Disable , 1 = Enable)
s->set_hmirror(s, 0);
// VERT FLIP (0 = Disable , 1 = Enable)
s->set_vflip(s, 0);
// DCW (0 = Disable , 1 = Enable)
s->set_dcw(s, 1);
// COLOR BAR PATTERN (0 = Disable , 1 = Enable)
s->set_colorbar(s, 0);
}
//SHTSensor sht(SHTSensor::SHT85); // I2C address: 0x44

Zoe Michaela Dietmar Pfister
committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
void initMicroSDCard()
{
// Start the MicroSD card
Serial.println("Mounting MicroSD Card");
if (!SD_MMC.begin("/sdcard", true)) { // the arguments disable the LED when using the SD card - leave them there!
Serial.println("MicroSD Card Mount Failed");
return;
}
uint8_t cardType = SD_MMC.cardType();
if (cardType == CARD_NONE) {
Serial.println("No MicroSD Card found");
return;
}
}
void takeNewPhoto(String path)
{
// Take picture with the camera and save it
// Take multiple pictures with a short break in between
// necessary for the camera to auto-adjust settings
camera_fb_t *fb;
for (int i = 1; i <= img_number; i++) {
// Setup frame buffer
fb = esp_camera_fb_get();
// digitalWrite(LEDpin, LOW); // disable flash LED if needed
if (!fb) {
Serial.println("Camera capture failed");
return;
} else {
Serial.println("Camera capture successful");
}
// TODO check if this delay is necessary once the SD-card todo below
// is resolved. It's possible that it can be at least shortened.
if (i == img_number) {
delay(2000);
}
esp_camera_fb_return(fb);
// Without this delay the image is corrupt
// TODO this delay can possibly also be optimized.
delay(1500);
/* TODO:
The SD card throws the following error when the capture fails:
E (877528) sdmmc_cmd: sdmmc_write_sectors_dma: sdmmc_send_cmd returned 0x109
E (877528) diskio_sdmmc: sdmmc_write_blocks failed (265)
This happens infrequently, say every 10th image or so.
If this happens, one more new image should be taken and saved
*/
}
// Save picture to microSD card
fs::FS &fs = SD_MMC;
File file = fs.open(path.c_str(), FILE_WRITE);
if (!file) {
Serial.println("Failed to open file in write mode");
} else {
file.write(fb->buf, fb->len); // payload (image), payload length
Serial.printf("Saved file to path: %s\n", path.c_str());
}
// Close the file
file.close();
// Return the frame buffer back to the driver for reuse
esp_camera_fb_return(fb);
}

marieschroeder
committed
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// Count files on SD card to give a meaningful count
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
fileCountOnSD += 1;
//Serial.print(" FILE: ");
//Serial.print(file.name());
//Serial.print(" SIZE: ");
//Serial.println(file.size());
file = root.openNextFile();
}
Serial.println("File Count on SD: ");
Serial.println(fileCountOnSD);

Zoe Michaela Dietmar Pfister
committed
}

marieschroeder
committed
void readRTC()
{
// This is used for a picture timestamp (name of the image)
if (! rtc.begin()) {
Serial.println("Couldnt find RTC!");
} else {
Serial.println("Setting the time");
}
DateTime now = rtc.now();
sprintf(time_string, "%04d-%02d-%02dT%02d-%02d-%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(),
now.second());
Serial.println(time_string);
}

Zoe Michaela Dietmar Pfister
committed
Sht85 sht85Sensor;
void setup()

marieschroeder
committed
{ // control of the LED pin

Zoe Michaela Dietmar Pfister
committed
pinMode(LEDpin, OUTPUT);
// Disable brownout detector
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
// Start Serial
Serial.begin(115200);

marieschroeder
committed
Serial.println("Wake Up!");
delay(1000);

Zoe Michaela Dietmar Pfister
committed
// Initialize the camera
Serial.print("Initializing the camera module...");
camera_configESPCamera();
Serial.println("Camera OK!");
espnow_setup();
sht85Sensor.setup();

marieschroeder
committed
// before in loop

Zoe Michaela Dietmar Pfister
committed
// initiate I2C, read SHT+RTC, end I2C

marieschroeder
committed

Zoe Michaela Dietmar Pfister
committed
readRTC();

marieschroeder
committed

Zoe Michaela Dietmar Pfister
committed
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
try {
// out_data_drs26 data= dr26.readData();
// Serial.printf("data circumfrence");
// Serial.printf(String( data.circumferenceIncrement).c_str());
// auto messages = drs26.buildMessages();
auto messages = sht85Sensor.buildMessages();
// auto scdMessages = scd30.buildmessages();
for (const Message &message : messages) {
if (message.send() != ESP_OK) {
RtcMemory::store(message.getMessageAsMinifiedJsonString());
}
delay(5000);
if (!was_msg_received()) {
RtcMemory::store(message.getMessageAsMinifiedJsonString());
}
}
} catch (const NoDataAvailableException &e) {
std::cerr << e.what() << '\n';
}
// Initialize the MicroSD
Serial.print("Initializing the MicroSD card module... ");
initMicroSDCard();

marieschroeder
committed
// Count files on SD card
listDir(SD_MMC, "/", 0);

Zoe Michaela Dietmar Pfister
committed
// Path where new image will be saved in MicroSD card

marieschroeder
committed
String path = "/Picture_" + String(fileCountOnSD) + ".jpg";

Zoe Michaela Dietmar Pfister
committed
Serial.printf("Picture file name: %s\n", path.c_str());
// Take and save a picture
takeNewPhoto(path);
// Unmount SD card to free the pins for I2C use
SD_MMC.end();
// Delay for specified period
delay(1000);

marieschroeder
committed
// Deep sleep
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for " + String(TIME_TO_SLEEP) + " Seconds");
Serial.println("Going to sleep now");
delay(1000);
Serial.flush();
gpio_hold_en((gpio_num_t)LEDpin);
esp_deep_sleep_start();
}
void loop()
{