Subversion Repositories ESP8266_P1_Meter

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 raymond 1
 
2
#include <FS.h>
3
#include <SD_MMC.h>
4
#include <AsyncFsWebServer.h>   // https://github.com/cotestatnt/async-esp-fs-webserver/
5
#include "esp_camera.h"
6
#include "soc/soc.h"          // Brownout error fix
7
#include "soc/rtc_cntl_reg.h" // Brownout error fix
8
 
9
#if ESP_ARDUINO_VERSION_MAJOR >= 3
10
  #include "soc/soc_caps.h"
11
#endif
12
 
13
#define FILESYSTEM SD_MMC
14
AsyncFsWebServer server(FILESYSTEM, 80);
15
 
16
// Local include files
17
#include "camera_pins.h"
18
 
19
uint16_t grabInterval = 0;  // Grab a picture every x seconds
20
uint32_t lastGrabTime = 0;
21
 
22
// Timezone definition to get properly time from NTP server
23
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"
24
 
25
// Struct for saving time datas (needed for time-naming the image files)
26
struct tm tInfo;
27
 
28
// Functions prototype
29
void listDir(const char *, uint8_t);
30
void setLamp(int);
31
 
32
// Grab a picture from CAM and store on SD or in flash
33
void getPicture(AsyncWebServerRequest *);
34
const char* getFolder = "/img";
35
 
36
///////////////////////////////////  SETUP  ///////////////////////////////////////
37
void setup() {
38
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // disable brownout detect
39
 
40
  // Flash LED setup
41
  pinMode(LAMP_PIN, OUTPUT);                      // set the lamp pin as output
42
#if ESP_ARDUINO_VERSION_MAJOR >= 3
43
  ledcAttach(LAMP_PIN, 1000, 8);
44
#else
45
  ledcSetup(lampChannel, pwmfreq, pwmresolution); // configure LED PWM channel
46
  ledcAttachPin(LAMP_PIN, lampChannel);
47
#endif
48
  setLamp(0);                                     // set default value
49
 
50
  Serial.begin(115200);
51
  Serial.println();
52
 
53
  // Try to connect to WiFi (will start AP if not connected after timeout)
54
  if (!server.startWiFi(10000)) {
55
    Serial.println("\nWiFi not connected! Starting AP mode...");
56
    server.startCaptivePortal("ESP32CAM_AP", "123456789", "/setup");
57
  }
58
 
59
  // Sync time with NTP
60
  configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
61
 
62
  /*
63
   Init onboard SD filesystem (format if necessary)
64
   SD_MMC.begin(const char * mountpoint, bool mode1bit, bool format_if_mount_failed, int sdmmc_frequency, uint8_t maxOpenFiles)
65
   To avoid led glowing, set mode1bit = true (SD HS_DATA1 is tied to GPIO4, the same of on-board flash led)
66
  */
67
  if (!SD_MMC.begin("/sdcard", true, true, SDMMC_FREQ_HIGHSPEED, 5)) {
68
    Serial.println("\nSD Mount Failed.\n");
69
  }
70
 
71
  if (!SD_MMC.exists(getFolder)) {
72
    if(SD_MMC.mkdir(getFolder))
73
      Serial.println("Dir created");
74
    else
75
      Serial.println("mkdir failed");
76
  }
77
  listDir(getFolder, 1);
78
 
79
  // Enable ACE FS file web editor and add FS info callback function
80
  server.enableFsCodeEditor();
81
 
82
  // Add custom handlers to webserver
83
  server.on("/getPicture", getPicture);
84
  server.on("/setInterval", setInterval);
85
 
86
  // Start server with built-in websocket event handler
87
  server.init();
88
  Serial.print(F("\nESP Web Server started on IP Address: "));
89
  Serial.println(server.getServerIP());
90
  Serial.println(F(
91
    "This is \"remoteOTA.ino\" example.\n"
92
    "Open /setup page to configure optional parameters.\n"
93
    "Open /edit page to view, edit or upload example or your custom webserver source files."
94
  ));
95
 
96
  // Init the camera module (according the camera_config_t defined)
97
  init_camera();
98
}
99
 
100
///////////////////////////////////  LOOP  ///////////////////////////////////////
101
void loop() {
102
  if (grabInterval) {
103
    if (millis() - lastGrabTime > grabInterval *1000) {
104
      lastGrabTime = millis();
105
      getPicture(nullptr);
106
    }
107
  }
108
}
109
 
110
//////////////////////////////////  FUNCTIONS//////////////////////////////////////
111
void setInterval(AsyncWebServerRequest *request) {
112
  if (request->hasArg("val")) {
113
    grabInterval = request->arg("val").toInt();
114
    Serial.printf("Set grab interval every %d seconds\n", grabInterval);
115
  }
116
  request->send(200, "text/plain", "OK");
117
}
118
 
119
// Lamp Control
120
void setLamp(int newVal) {
121
  if (newVal != -1) {
122
    // Apply a logarithmic function to the scale.
123
    int brightness = round((pow(2, (1 + (newVal * 0.02))) - 2) / 6 * pwmMax);
124
    ledcWrite(lampChannel, brightness);
125
    Serial.print("Lamp: ");
126
    Serial.print(newVal);
127
    Serial.print("%, pwm = ");
128
    Serial.println(brightness);
129
  }
130
}
131
 
132
// Send a picture taken from CAM to a Telegram chat
133
void getPicture(AsyncWebServerRequest *request) {
134
 
135
  // Take Picture with Camera;
136
  Serial.println("Camera capture requested");
137
 
138
  // Take Picture with Camera and store in ram buffer fb
139
  setLamp(100);
140
  delay(100);
141
  camera_fb_t *fb = esp_camera_fb_get();
142
  setLamp(0);
143
 
144
  if (!fb) {
145
    Serial.println("Camera capture failed");
146
    if (request != nullptr)
147
      request->send(500, "text/plain", "ERROR. Image grab failed");
148
    return;
149
  }
150
 
151
  // Keep files on SD memory, filename is time based (YYYYMMDD_HHMMSS.jpg)
152
  // Embedded filesystem is too small to keep all images, overwrite the same file
153
  char filename[20];
154
  time_t now = time(nullptr);
155
  tInfo = *localtime(&now);
156
  strftime(filename, sizeof(filename), "%Y%m%d_%H%M%S.jpg", &tInfo);
157
 
158
  char filePath[30];
159
  strcpy(filePath, getFolder);
160
  strcat(filePath, "/");
161
  strcat(filePath, filename);
162
  File file = SD_MMC.open(filePath, "w");
163
  if (!file) {
164
    Serial.println("Failed to open file in writing mode");
165
    if(request != nullptr)
166
      request->send(500, "text/plain", "ERROR. Image grab failed");
167
    return;
168
  }
169
  // size_t _jpg_buf_len = 0;
170
  // uint8_t *_jpg_buf = NULL;
171
  // bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
172
  file.write(fb->buf, fb->len);
173
  file.close();
174
  Serial.printf("Saved file to path: %s - %zu bytes\n", filePath, fb->len);
175
 
176
  // Clear buffer
177
  esp_camera_fb_return(fb);
178
  if (request != nullptr)
179
    request->send(200, "text/plain", filename);
180
}
181
 
182
// List all files saved in the selected filesystem
183
void listDir(const char *dirname, uint8_t levels) {
184
  uint32_t freeBytes = SD_MMC.totalBytes() - SD_MMC.usedBytes();
185
  Serial.print("\nTotal space: ");
186
  Serial.println(SD_MMC.totalBytes());
187
  Serial.print("Free space: ");
188
  Serial.println(freeBytes);
189
 
190
  Serial.printf("Listing directory: %s\r\n", dirname);
191
  File root = SD_MMC.open(dirname);
192
  if (!root) {
193
    Serial.println("- failed to open directory\n");
194
    return;
195
  }
196
  if (!root.isDirectory()) {
197
    Serial.println(" - not a directory\n");
198
    return;
199
  }
200
  File file = root.openNextFile();
201
  while (file) {
202
    if (file.isDirectory()) {
203
      if (levels)
204
        listDir(file.name(), levels - 1);
205
    }
206
    else {
207
      Serial.printf("|__ FILE: %s (%d bytes)\n",file.name(), file.size());
208
    }
209
    file = root.openNextFile();
210
  }
211
}