Subversion Repositories ESP8266_P1_Meter

Rev

Details | Last modification | View Log | RSS feed

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