Subversion Repositories ESP32_P1_Meter

Rev

Rev 4 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 raymond 1
////////////////////////////////  Include libraries  /////////////////////////////////////////
2
#include <Arduino.h>
4 raymond 3
#include <ArduinoOTA.h>
4
#include <EEPROM.h>
5
#include <Ticker.h>
6
#include <FS.h>
7
#include <LittleFS.h>
5 raymond 8
#include <ezButton.h>
9
#include <PubSubClient.h>              // https://github.com/knolleary/pubsubclient/
10
#include <AsyncFsWebServer.h>          //https://github.com/cotestatnt/async-esp-fs-webserver
4 raymond 11
 
5 raymond 12
////////////////////////////////  Include settings  /////////////////////////////////////////
4 raymond 13
#include "settings.h"
14
 
5 raymond 15
////////////////////////////////  Define constants  /////////////////////////////////////////
16
#ifndef LED_BUILTIN
17
#define LED_BUILTIN 2
18
#endif
4 raymond 19
#define FILESYSTEM LittleFS
5 raymond 20
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"          // Timezone definition to get properly time from NTP server
4 raymond 21
#ifndef Default_MQTT_Port
5 raymond 22
  #define Default_MQTT_Port "1883"
4 raymond 23
#endif
24
#define BTN_SAVE  5
5 raymond 25
// added labels for /setup webpage
26
#define USER_LABEL "Username"
27
#define PASSWORD_LABEL "Password"
28
#define EXTERNAL_ANTENNA_LABEL "External (Extra Internal) Antenna"
4 raymond 29
 
30
#define MQTT_ENABLED_LABEL "MQTT Enabled"
31
#define MQTT_CLIENT_LABEL "MQTT Client"
32
#define MQTT_SERVER_LABEL "MQTT Server"
33
#define MQTT_PORT_LABEL "MQTT Server Port"
34
#define MQTT_USER_LABEL "MQTT User"
35
#define MQTT_PASSWORD_LABEL "MQTT Password"
5 raymond 36
#define MQTT_TOPIC_LABEL "MQTT Topic"
4 raymond 37
 
5 raymond 38
#define SHORT_PRESS_TIME_MIN 1000 // 1 second
39
#define SHORT_PRESS_TIME_MAX 2500 // 2.5 seconds
40
#define LONG_PRESS_TIME  10000 // 10 seconds
41
 
42
const uint8_t logo_png[] PROGMEM = {
43
  0x89, 0x50, 0x4E, 0x47, /* ... */
44
};
45
 
46
////////////////////////////////  Create Objects  /////////////////////////////////////////
4 raymond 47
struct tm Time;
5 raymond 48
Ticker ticker;
49
AsyncFsWebServer server(FILESYSTEM, 80, "P1_Meter");
50
ezButton button(9); // create ezButton object that attach to pin GPIO9
4 raymond 51
 
52
 
5 raymond 53
// * Define variables
54
bool captiveRun = false;
55
// Setup Settings
56
String Username = "admin";
57
String Password = "admin";
58
bool External_Antenna = true;
59
// MQTT Settings
60
bool MQTT_Enabled = false;
61
String MQTT_Client = "ESP32_P1_Meter";
62
String MQTT_Server = "";
63
//uint16_t MQTT_Port = Default_MQTT_Port;
64
String MQTT_Port = Default_MQTT_Port;
65
String MQTT_User = "";
66
String MQTT_Password = "";
67
String MQTT_Topic = "P1_Meter";
68
int LEDSpeed = 0;
4 raymond 69
 
5 raymond 70
bool isPressing = false;
71
unsigned long pressedTime  = 0;
72
unsigned long releasedTime = 0;
4 raymond 73
 
74
////////////////////////////////  Filesystem  /////////////////////////////////////////
75
bool startFilesystem() {
76
  if (FILESYSTEM.begin()){
5 raymond 77
    server.printFileList(FILESYSTEM, "/", 2), Serial;
4 raymond 78
    return true;
79
  }
80
  else {
81
    Serial.println("ERROR on mounting filesystem. It will be reformatted!");
82
    FILESYSTEM.format();
83
    ESP.restart();
84
  }
85
  return false;
86
}
87
/*
88
* Getting FS info (total and free bytes) is strictly related to
89
* filesystem library used (LittleFS, FFat, SPIFFS etc etc) and ESP framework
90
*/
91
#ifdef ESP32
92
void getFsInfo(fsInfo_t* fsInfo) {
93
	fsInfo->fsName = "LittleFS";
94
	fsInfo->totalBytes = LittleFS.totalBytes();
95
	fsInfo->usedBytes = LittleFS.usedBytes();
96
}
97
#endif
98
 
5 raymond 99
////////////////////////////////   WebSocket Handler  /////////////////////////////
100
void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
101
  switch (type) {
102
    case WS_EVT_DISCONNECT:
103
      Serial.print("WebSocket client disconnected!\n");
104
      break;
105
    case WS_EVT_CONNECT:  {
106
        IPAddress ip = client->remoteIP();
107
        Serial.printf("WebSocket client %d.%d.%d.%d connected.\n", ip[0], ip[1], ip[2], ip[3]);
108
        client->printf("%s", "{\"Connected\": true}");
109
      }
110
      break;
111
    default:
112
        break;
113
  }
114
}
115
 
116
////////////////////////////////  NTP Time  /////////////////////////////////////
117
void getUpdatedtime(const uint32_t timeout)
118
{
119
  uint32_t start = millis();
120
  Serial.print("Sync time...");
121
  while (millis() - start < timeout  && Time.tm_year <= (1970 - 1900)) {
122
    time_t now = time(nullptr);
123
    Time = *localtime(&now);
124
    delay(5);
125
  }
126
  Serial.println(" done.");
127
}
128
 
4 raymond 129
////////////////////  Load application options from filesystem  ////////////////////
130
bool loadOptions() {
131
  if (FILESYSTEM.exists(server.getConfiFileName())) {
5 raymond 132
    server.getOptionValue(USER_LABEL, Username);
133
    server.getOptionValue(PASSWORD_LABEL, Password);
134
    server.getOptionValue(EXTERNAL_ANTENNA_LABEL, External_Antenna);
135
 
4 raymond 136
    server.getOptionValue(MQTT_ENABLED_LABEL, MQTT_Enabled);
137
    server.getOptionValue(MQTT_CLIENT_LABEL, MQTT_Client);
138
    server.getOptionValue(MQTT_SERVER_LABEL, MQTT_Server);
139
    server.getOptionValue(MQTT_PORT_LABEL, MQTT_Port);
140
    server.getOptionValue(MQTT_USER_LABEL, MQTT_User);
141
    server.getOptionValue(MQTT_PASSWORD_LABEL, MQTT_Password);
5 raymond 142
    server.getOptionValue(MQTT_TOPIC_LABEL, MQTT_Topic);
4 raymond 143
 
144
    Serial.println("\nThis are the current values stored: \n");
145
    Serial.printf("MQTT Enabled: %s\n", MQTT_Enabled ? "true" : "false");
146
    Serial.printf("MQTT Client: %s\n", MQTT_Client.c_str());
147
    Serial.printf("MQTT Server: %s\n", MQTT_Server.c_str());
5 raymond 148
//    Serial.printf("MQTT Server Port: %d\n", MQTT_Port);
149
    Serial.printf("MQTT Server Port: %s\n", MQTT_Port.c_str());
4 raymond 150
    Serial.printf("MQTT User: %s\n", MQTT_User.c_str());
151
    Serial.printf("MQTT password: %s\n", MQTT_Password.c_str());
5 raymond 152
    Serial.printf("MQTT Topic: %s\n", MQTT_Topic.c_str());
4 raymond 153
    return true;
154
  }
155
  else
156
    Serial.println(F("Config file not exist"));
157
  return false;
158
}
159
 
160
bool _was_connected = false;
161
void saveOptions() {
5 raymond 162
   server.saveOptionValue(USER_LABEL, Username);
163
   server.saveOptionValue(PASSWORD_LABEL, Password);
164
   server.saveOptionValue(EXTERNAL_ANTENNA_LABEL, External_Antenna);
165
 
166
   server.saveOptionValue(MQTT_ENABLED_LABEL, MQTT_Enabled);
167
   server.saveOptionValue(MQTT_CLIENT_LABEL, MQTT_Client);
168
   server.saveOptionValue(MQTT_SERVER_LABEL, MQTT_Server);
169
   server.saveOptionValue(MQTT_PORT_LABEL, MQTT_Port);
170
   server.saveOptionValue(MQTT_USER_LABEL, MQTT_User);
171
   server.saveOptionValue(MQTT_PASSWORD_LABEL, MQTT_Password);
172
   server.saveOptionValue(MQTT_TOPIC_LABEL, MQTT_Topic);
4 raymond 173
  Serial.println(F("Application options saved."));
174
}
175
 
176
////////////////////////////  HTTP Request Handlers  ////////////////////////////////////
177
void handleLoadOptions(AsyncWebServerRequest *request) {
178
  request->send(200, "text/plain", "Options loaded");
179
  loadOptions();
180
  Serial.println("Application option loaded after web request");
181
}
182
 
183
 
5 raymond 184
 
185
 
186
// * ==========================================================================================
187
// * = HIERONDER NOG NETJES MAKEN == HIERONDER NOG NETJES MAKEN == HIERONDER NOG NETJES MAKEN =
188
// * ==========================================================================================
189
 
190
//MQTT_Port_String = String(MQTT_Port);
191
//sprintf(MQTT_Port_String, "%u", MQTT_Port);
192
//MQTTRemote _mqtt_remote(MQTT_Client.c_str(), MQTT_Server.c_str(), MQTT_Port, MQTT_User.c_str(), MQTT_Password.c_str(),
193
//                        {.rx_buffer_size = 2048, .tx_buffer_size = 2048, .keep_alive_s = 10});
194
 
195
 
196
////////////////////////////////  SETUP  /////////////////////////////////////////
4 raymond 197
void setup() {
198
  Serial.begin(115200);
5 raymond 199
  button.setDebounceTime(50); // set debounce time to 50 milliseconds
4 raymond 200
  pinMode(BTN_SAVE, INPUT_PULLUP);
5 raymond 201
  pinMode(LED_BUILTIN, OUTPUT);
4 raymond 202
 
5 raymond 203
 
4 raymond 204
  // FILESYSTEM INIT
205
  if (startFilesystem()){
206
    // Load configuration (if not present, default will be created when webserver will start)
207
    if (loadOptions())
208
      Serial.println(F("Application option loaded"));
209
    else
210
      Serial.println(F("Application options NOT loaded!"));
211
  }
212
 
5 raymond 213
  server.setSetupPageTitle("Instellingen P1 Meter");
214
  server.setSetupPageLogo(logo_png, sizeof(logo_png), "image/png", false);
215
  server.closeSetupConfiguration();
216
 
4 raymond 217
  // Try to connect to stored SSID, start AP with captive portal if fails after timeout
218
  IPAddress myIP = server.startWiFi(15000);
219
  if (!myIP) {
220
    Serial.println("\n\nNo WiFi connection, start AP and Captive Portal\n");
221
    server.startCaptivePortal("ESP_AP", "123456789", "/setup");
222
    myIP = WiFi.softAPIP();
223
    captiveRun = true;
5 raymond 224
    LEDSpeed = 250;
225
  } else {
226
    LEDSpeed = 1000;
4 raymond 227
  }
228
 
229
  // Add custom page handlers to webserver
230
  server.on("/reload", HTTP_GET, handleLoadOptions);
231
 
232
  // Configure /setup page and start Web Server
5 raymond 233
  server.addOptionBox("Device Setup");
234
  server.addOption(USER_LABEL, Username);
235
  server.addOption(PASSWORD_LABEL, Password);
236
  server.addOption(EXTERNAL_ANTENNA_LABEL, External_Antenna);
237
  server.addComment(EXTERNAL_ANTENNA_LABEL, "Restart is necessary after changing values.");
238
 
239
  server.addOptionBox("MQTT Setup");
4 raymond 240
  server.addOption(MQTT_ENABLED_LABEL, MQTT_Enabled);
5 raymond 241
  server.addOption(MQTT_CLIENT_LABEL, MQTT_Client);
4 raymond 242
  server.addOption(MQTT_SERVER_LABEL, MQTT_Server);
243
  server.addOption(MQTT_PORT_LABEL, MQTT_Port);
244
  server.addOption(MQTT_USER_LABEL, MQTT_User);
245
  server.addOption(MQTT_PASSWORD_LABEL, MQTT_Password);
5 raymond 246
  server.addOption(MQTT_TOPIC_LABEL, MQTT_Topic);
247
  server.addComment(MQTT_TOPIC_LABEL, "Restart is necessary after changing values.");
4 raymond 248
 
249
  // Enable ACE FS file web editor and add FS info callback function
250
  server.enableFsCodeEditor();
251
  #ifdef ESP32
252
  server.setFsInfoCallback(getFsInfo);
253
  #endif
254
 
255
  // set /setup and /edit page authentication
5 raymond 256
  server.setAuthentication(Username.c_str(), Password.c_str());
4 raymond 257
 
5 raymond 258
   // Start server with custom websocket event handler
259
  server.init(onWsEvent);
4 raymond 260
  Serial.print(F("ESP Web Server started on IP Address: "));
5 raymond 261
  Serial.println(server.getServerIP());
4 raymond 262
 
5 raymond 263
  if (External_Antenna) {
264
    pinMode(3, OUTPUT);    // RF switch power on
265
    digitalWrite(3, LOW);
266
    pinMode(14, OUTPUT);   // select external antenna
267
    digitalWrite(14, HIGH);
268
    Serial.println("External antenna selected.");
269
 } else {
270
    pinMode(14, INPUT);    // select on-board antenna
271
    pinMode(3, INPUT);   // RF switch power off
272
    Serial.println("Internal antenna selected.");
273
 }
274
 long rssi = WiFi.RSSI();
275
 Serial.print("WiFi Strength (RSSI): ");
276
 if ((rssi <= -30) && (rssi > -50)) {
277
   Serial.print("***** (");
278
   Serial.print(rssi);
279
   Serial.print("dBm.)");
280
 } else   if ((rssi <= -50) && (rssi > -60)) {
281
   Serial.print("****. (");
282
   Serial.print(rssi);
283
   Serial.print("dBm.)");
284
 } else   if ((rssi <= -60) && (rssi > -70)) {
285
   Serial.print("***.. (");
286
   Serial.print(rssi);
287
   Serial.print("dBm.)");
288
 } else   if ((rssi <= -70) && (rssi > -80)) {
289
   Serial.print("**... (");
290
   Serial.print(rssi);
291
   Serial.print("dBm.)");
292
 } else   if ((rssi <= -80) && (rssi > -90)) {
293
   Serial.print("*.... (");
294
   Serial.print(rssi);
295
   Serial.print("dBm.)");
296
 } else   if ((rssi <= -90)) {
297
   Serial.print("..... (");
298
   Serial.print(rssi);
299
   Serial.print("dBm.)");
300
 }
301
 
302
 // if (MQTT_Enabled) {
303
 
304
 // }
305
 
306
//  if (MQTT_Enabled) {
307
//    _mqtt_remote.start([](bool connected) {
308
//    if (connected) {
309
//      _mqtt_remote.subscribe(
310
//            _mqtt_remote.publishMessageVerbose(_mqtt_remote.clientId() + "/initial_message", "oh hello!");
311
//          });
312
//    };
4 raymond 313
}
314
 
5 raymond 315
////////////////////////////////  LOOP  /////////////////////////////////////////
4 raymond 316
void loop() {
5 raymond 317
 
318
  // Send ESP system time (epoch) and heap stats to WS client
319
  static uint32_t sendToClientTime;
320
  if (millis() - sendToClientTime > LEDSpeed ) {
321
    sendToClientTime = millis();
322
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
323
 
324
    time_t now = time(nullptr);
325
    using namespace AsyncFSWebServer;
326
    CJSON::Json doc;
327
    doc.setBool("addPoint", true);
328
    doc.setNumber("timestamp", (double)now);
329
#ifdef ESP32
330
    doc.setNumber("totalHeap", (double)heap_caps_get_free_size(0));
331
    doc.setNumber("maxBlock", (double)heap_caps_get_largest_free_block(0));
332
#elif defined(ESP8266)
333
    uint32_t free;
334
    uint32_t max;
335
    ESP.getHeapStats(&free, &max, nullptr);
336
    doc.setNumber("totalHeap", (double)free);
337
    doc.setNumber("maxBlock", (double)max);
338
#endif
339
    String msg = doc.serialize();
340
    server.wsBroadcast(msg.c_str());
341
  }
342
 
4 raymond 343
  if (captiveRun)
344
    server.updateDNS();
345
 
346
  // Savew options also on button click
347
  if (! digitalRead(BTN_SAVE)) {
348
    saveOptions();
349
    delay(1000);
350
  }
5 raymond 351
 
352
  button.loop(); // MUST call the loop() function first
353
 
354
  if (button.isPressed()) {
355
    pressedTime = millis();
356
    isPressing = true;
357
  }
358
 
359
  long pressingDuration = millis() - pressedTime;
360
 
361
  if ((isPressing == true) && (pressingDuration > LONG_PRESS_TIME))
362
      digitalWrite(LED_BUILTIN, LOW);
363
 
364
  if (button.isReleased()) {
365
    releasedTime = millis();
366
    isPressing = false;
367
 
368
    long pressDuration = releasedTime - pressedTime;
369
 
370
    if ((pressDuration > SHORT_PRESS_TIME_MIN) && (pressDuration < SHORT_PRESS_TIME_MAX)) {
371
      ESP.restart();
372
    }
373
 
374
    if (pressDuration > LONG_PRESS_TIME) {
375
      server.clearConfigFile();
376
      ESP.restart();
377
    }
378
  }
4 raymond 379
}