├── .gitattributes ├── .gitignore ├── .vscode ├── arduino.json └── settings.json ├── ArduinoEnergyLogger.ino ├── README.md ├── analog.cpp ├── analog.h ├── app.cpp ├── app.h ├── display.cpp ├── display.h ├── eeprom.cpp ├── eeprom.h ├── html.h ├── network.cpp ├── network.h ├── ntp.cpp ├── ntp.h ├── post.cpp ├── post.h ├── screenshots ├── Screenshot_20210218-212110_Chrome.jpg ├── Screenshot_20210218-212210_Chrome.jpg ├── Screenshot_20210218-212221_Chrome.jpg ├── Screenshot_20210218-212327_Chrome.jpg ├── Screenshot_20210218-212336_Chrome.jpg ├── Screenshot_20210218-212343_Chrome.jpg ├── grafana-1.png └── grafana-2.png ├── snat.cpp ├── snat.h ├── srne.cpp ├── srne.h ├── webserver.cpp └── webserver.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/c_cpp_properties.json 2 | build -------------------------------------------------------------------------------- /.vscode/arduino.json: -------------------------------------------------------------------------------- 1 | { 2 | "board": "esp8266:esp8266:d1_mini_clone", 3 | "port": "COM5", 4 | "sketch": "ArduinoEnergyLogger.ino", 5 | "output": "./build" 6 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "arduino.useArduinoCli": true, 3 | "arduino.logLevel": "info", 4 | "arduino.allowPDEFiletype": false, 5 | "arduino.enableUSBDetection": true, 6 | "arduino.disableTestingOpen": false, 7 | "arduino.skipHeaderProvider": false, 8 | "arduino.additionalUrls": [ 9 | "http://arduino.esp8266.com/stable/package_esp8266com_index.json" 10 | ], 11 | } -------------------------------------------------------------------------------- /ArduinoEnergyLogger.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Author: 3 | - Philip Bordado (kerpz@yahoo.com) 4 | 5 | Hardware: 6 | - Wemos D1 mini (Compatible board) 7 | 8 | Software: 9 | - Arduino 2.2.1 (Stable) 10 | - vscode-arduino (https://github.com/vscode-arduino/vscode-arduino) 11 | - Board 3.1.2 12 | - Adafruit SSD1306 2.5.7 13 | - Adafruit ADS1115 2.4.0 14 | - NTPClient 3.2.1 15 | - ArduinoJson 6.21.3 16 | */ 17 | 18 | #include "eeprom.h" 19 | #include "network.h" 20 | #include "webserver.h" 21 | #include "app.h" 22 | 23 | void setup() 24 | { 25 | delay(10); 26 | 27 | Serial.begin(115200); 28 | 29 | Serial.println(); 30 | Serial.println(APPNAME); 31 | 32 | loadConfig(); 33 | 34 | networkSetup(); 35 | webserverSetup(); 36 | 37 | appSetup(); 38 | 39 | delay(100); 40 | } 41 | 42 | void loop() 43 | { 44 | networkLoop(); 45 | webserverLoop(); 46 | 47 | appLoop(); 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ArduinoEnergyLogger 2 | =========== 3 | 4 | An arduino code that reads Current Transformer (CT sensor) data, SRNE Mppt controller data, and SNAT PSW inverter. 5 | The data collected will be transmit to a HTTP server via POST with a CSV formatted data. 6 | The device used in this project is Wemos D1 mini. 7 | 8 | Please refer to the screenshots below. 9 | 10 | Applications 11 | -------- 12 | * Solar and Energy Datalogging 13 | * Diagnostics 14 | * Consumption Analysis 15 | 16 | 17 | Supports 18 | -------- 19 | * CT Sensor 20 | * SRNE Mppt Controller 21 | * SNAT PSW Inverter 22 | 23 | 24 | Files 25 | ----- 26 | * ArduinoEnergyLogger.ino - main file 27 | * analog.h - support file for ct sensor reading (based on emon) [Edit cpp/h]. 28 | * display.h - support file for displaying data via OLED [Edit cpp/h]. 29 | * post.h - support file for posting data to a HTTP server IoT. 30 | * srne.h - support file for extracting data from a srne mppt controller. 31 | * snat.h - support file for extracting data from a snat psw inverter. 32 | * webserver.h - support file for the device webserver, used for wifi and device configurations/informations [Edit cpp/h]. 33 | * utils.h - helpers. 34 | * hardware - directory of hardware design eagle files 35 | * screeshot - directory of images used for README 36 | 37 | 38 | Wiring for CT sensor, SRNE, and SNAT 39 | -------------------- 40 | CT sensor Wemos D1 mini 41 | divider circuit --------- ADC0 (A0) 42 | (2 x 100k ohms and 10uF) 43 | 44 | SRNE Wemos D1 mini 45 | Rx ---------------------- D7 46 | Tx ---------------------- D8 47 | 48 | SRNE Wemos D1 mini 49 | Rx ---------------------- D5 50 | Tx ---------------------- D6 51 | 52 | 53 | Screenshots (Grafana display) 54 | --------------- 55 | 56 | ![Alt text](https://github.com/kerpz/ArduinoEnergyLogger/blob/main/screenshots/grafana-1.png "Page 1") 57 | ![Alt text](https://github.com/kerpz/ArduinoEnergyLogger/blob/main/screenshots/grafana-2.png "Page 2") 58 | 59 | Screenshots (Device Webserver) 60 | --------------- 61 | 62 | ![Alt text](https://github.com/kerpz/ArduinoEnergyLogger/blob/main/screenshots/Screenshot_20210218-212110_Chrome.jpg "Main Page") 63 | ![Alt text](https://github.com/kerpz/ArduinoEnergyLogger/blob/main/screenshots/Screenshot_20210218-212210_Chrome.jpg "Information 1") 64 | ![Alt text](https://github.com/kerpz/ArduinoEnergyLogger/blob/main/screenshots/Screenshot_20210218-212221_Chrome.jpg "Information 2") 65 | ![Alt text](https://github.com/kerpz/ArduinoEnergyLogger/blob/main/screenshots/Screenshot_20210218-212327_Chrome.jpg "Configuration 1") 66 | ![Alt text](https://github.com/kerpz/ArduinoEnergyLogger/blob/main/screenshots/Screenshot_20210218-212343_Chrome.jpg "Configuration 3") 67 | 68 | 69 | NOTES 70 | ----- 71 | * Still in beta test 72 | 73 | TODO 74 | ----- 75 | * Device mass production 76 | -------------------------------------------------------------------------------- /analog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "eeprom.h" 4 | #include "analog.h" 5 | /* https://www.allaboutcircuits.com/tools/voltage-divider-calculator 6 | * source Voltage = max voltage of the battery 7 | * R2 = 100k (builtin on wemos D1 mini) 8 | * R1 = 220k + additional resistance (100k for 4.2v, 1.22m for 16v) 9 | * target volatge output should be 1v 10 | * 1.0 * (R1 + R2) / R2 11 | */ 12 | 13 | // ADC specs for wemos d1 mini 14 | #define ADC_BITS 10 15 | #define ADC_COUNTS (1 << ADC_BITS) 16 | double offsetI = ADC_COUNTS >> 1; 17 | // #define CT_CALIBRATION 30.0 18 | 19 | int samples = 1480; 20 | int SupplyVoltage = 3200; 21 | 22 | // float ct_voltage = 0.0; 23 | float ct_current = 0.0; 24 | float ct_power = 0.0; 25 | 26 | void analogSetup() 27 | { 28 | } 29 | 30 | void analogLoop() 31 | { 32 | // setup for volt meter reading with 1.2M resistor 33 | // int raw = analogRead(A0); 34 | // a_voltage = raw / 1023.0; 35 | // a_voltage = a_voltage * 15.4; 36 | 37 | // setup for ct sensor reading with 30.0 amps max 38 | double sumI, sqI, filteredI; 39 | for (unsigned int n = 0; n < samples; n++) 40 | { 41 | int sampleI = analogRead(A0); 42 | offsetI = (offsetI + (sampleI - offsetI) / 1024); 43 | filteredI = sampleI - offsetI; 44 | sqI = filteredI * filteredI; 45 | sumI += sqI; 46 | } 47 | double I_RATIO = ct_calibration * ((SupplyVoltage / 1000.0) / (ADC_COUNTS)); 48 | 49 | ct_voltage = ct_voltage; 50 | ct_current = I_RATIO * sqrt(sumI / samples); 51 | 52 | ct_power = (ct_current * ct_voltage * ct_pf); // watt(s) / power apparent 53 | } 54 | -------------------------------------------------------------------------------- /analog.h: -------------------------------------------------------------------------------- 1 | #ifndef ANALOG_H 2 | #define ANALOG_H 3 | 4 | // extern float ct_voltage; 5 | extern float ct_current; 6 | extern float ct_power; 7 | 8 | void analogSetup(); 9 | void analogLoop(); 10 | 11 | #endif -------------------------------------------------------------------------------- /app.cpp: -------------------------------------------------------------------------------- 1 | // wifi 2 | #include 3 | 4 | #include "app.h" 5 | 6 | // https://www.tinkercad.com/things/dJn6LkhyR5E-interface-test 7 | 8 | uint16_t run_time = 0; 9 | 10 | // timing 11 | int timezone = 8; 12 | uint32_t epoch = 0; 13 | uint8_t second = 0; 14 | uint8_t minute = 0; 15 | uint8_t hour = 0; 16 | uint8_t day = 0; 17 | uint8_t month = 0; 18 | uint16_t year = 0; 19 | 20 | float ct_energy; // watt per minute 21 | float pv_energy; // watt per minute 22 | float dc_energy; // watt per minute 23 | 24 | void appSetup() 25 | { 26 | ntpSetup(); 27 | // srne @ D7 D8 28 | // snat @ D5 D6 29 | if (display_enable) 30 | displayLoop(); 31 | // if (dht11_enable) 32 | // dht11Loop(); 33 | 34 | // if (beep_enable) 35 | // beepSetup(); 36 | if (analog_enable) 37 | analogSetup(); 38 | if (display_enable) 39 | displaySetup(); 40 | // if (ads1115_enable) 41 | // ads1115Setup(); 42 | if (srne_enable) 43 | srneSetup(); 44 | if (snat_enable) 45 | snatSetup(); 46 | } 47 | 48 | void appLoop() 49 | { 50 | // static float _prev_device_voltage; 51 | static uint32_t msTick = millis(); 52 | static uint32_t total_ct_power = ct_power; 53 | static uint32_t total_pv_power = pv_power; 54 | static uint32_t total_dc_power = dc_power; 55 | // static uint8_t sTick; 56 | 57 | if (millis() - msTick >= 1000) // 1000ms refresh rate 58 | { 59 | msTick = millis(); 60 | ntpLoop(); 61 | 62 | if (analog_enable) 63 | analogLoop(); 64 | delay(1); 65 | if (srne_enable) 66 | srneLoop(); 67 | delay(1); 68 | if (snat_enable) 69 | snatLoop(); 70 | delay(1); 71 | 72 | if (second >= 59) 73 | { 74 | // Convert to watt-minute 75 | ct_energy = total_ct_power / 60.0; 76 | pv_energy = total_pv_power / 60.0; 77 | dc_energy = total_dc_power / 60.0; 78 | 79 | if (post_enable) 80 | { 81 | String csv = "&csv="; 82 | // ct / consumption 83 | csv += "" + String(ct_voltage, 2); // voltage 84 | csv += ",0.00"; // current 85 | csv += "," + String(ct_energy, 2); // energy W/m 86 | csv += ",dc"; // type 87 | csv += ",0.00"; // temperature 88 | csv += ",0.00"; // charge 89 | 90 | // srne / harvest 91 | csv += "," + String(pv_voltage, 2); // voltage 92 | csv += ",0.00"; // current 93 | csv += "," + String(pv_energy, 2); // energy W/m 94 | csv += ",dc"; // type 95 | csv += ",0.00"; // temperature 96 | csv += ",0.00"; // charge 97 | 98 | // srne / battery 99 | csv += "," + String(battery_voltage, 2); // voltage 100 | csv += ",0.00"; // current 101 | csv += ",0.00"; // energy W/m 102 | csv += ",dc"; // type 103 | csv += "," + String(battery_temperature, 2); // temperature 104 | csv += "," + String(battery_charge, 2); // charge 105 | 106 | // srne / controller 107 | csv += ",0.00"; // voltage 108 | csv += ",0.00"; // current 109 | csv += ",0.00"; // energy W/m 110 | csv += ",dc"; // type 111 | csv += "," + String(mppt_temperature, 2); // temperature 112 | csv += ",0.00"; // charge 113 | 114 | // srne / dc consumption 115 | csv += "," + String(dc_voltage, 2); // voltage 116 | csv += ",0.00"; // current 117 | csv += "," + String(dc_energy, 2); // energy W/m 118 | csv += ",dc"; // type 119 | csv += ",0.00"; // temperature 120 | csv += ",0.00"; // charge 121 | 122 | // snat / input 123 | csv += "," + String(inv_in_voltage, 2); // input voltage 124 | csv += ",0.00"; // input current 125 | csv += ",0.00"; // input energy W/m 126 | csv += ",ac"; // type 127 | csv += ",0.00"; // input temperature 128 | csv += "," + String(inv_in_frequency, 2); // input frequency 129 | 130 | // snat / output 131 | csv += "," + String(inv_out_voltage, 2); // output voltage 132 | csv += ",0.00"; // output current 133 | csv += "," + String(inv_out_power, 2); // output energy W/m 134 | csv += ",ac"; // type 135 | csv += "," + String(inv_temperature, 2); // output temperature 136 | csv += ",0.00"; // output frequency 137 | 138 | csv += "," + String(inv_cell_voltage, 2); // cell voltage 139 | csv += "," + String(inv_in_fault_voltage, 2); // in fault voltage 140 | csv += "," + String(inv_flags); // flags 141 | 142 | postData(csv); 143 | } 144 | 145 | /* 146 | if (minute >= 59) 147 | { 148 | minute = 0; 149 | if (hour >= 23) 150 | { 151 | hour = 0; 152 | } 153 | else 154 | hour++; 155 | } 156 | else 157 | minute++; 158 | */ 159 | 160 | // resets 161 | second = 0; 162 | total_ct_power = ct_power; 163 | total_pv_power = pv_power; 164 | total_dc_power = dc_power; 165 | } 166 | else 167 | { 168 | second++; 169 | // accumulate power every second 170 | total_ct_power += ct_power; 171 | total_pv_power += pv_power; 172 | total_dc_power += dc_power; 173 | } 174 | } 175 | } -------------------------------------------------------------------------------- /app.h: -------------------------------------------------------------------------------- 1 | #ifndef APP_H 2 | #define APP_H 3 | 4 | #include "eeprom.h" 5 | #include "ntp.h" 6 | #include "analog.h" 7 | #include "display.h" 8 | #include "post.h" 9 | 10 | #include "srne.h" 11 | #include "snat.h" 12 | 13 | #define APPNAME "EnergyLogger v1.0" 14 | #define APPCODE "ess" 15 | 16 | extern uint16_t run_time; 17 | 18 | // timing 19 | extern int timezone; 20 | extern uint32_t epoch; 21 | extern uint8_t second; 22 | extern uint8_t minute; 23 | extern uint8_t hour; 24 | extern uint8_t day; 25 | extern uint8_t month; 26 | extern uint16_t year; 27 | 28 | extern float ct_energy; 29 | extern float pv_energy; 30 | extern float dc_energy; 31 | 32 | void appSetup(); 33 | void appLoop(); 34 | 35 | #endif -------------------------------------------------------------------------------- /display.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "display.h" 4 | 5 | #define SCREEN_WIDTH 128 // OLED display width, in pixels 6 | #define SCREEN_HEIGHT 64 // OLED display height, in pixels 7 | // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) 8 | #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) 9 | 10 | Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 11 | 12 | void displaySetup() 13 | { 14 | Serial.print("Starting Display ... "); 15 | display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 16 | Serial.println("Done"); 17 | 18 | display.clearDisplay(); 19 | display.setTextSize(2); // Draw 2X-scale text 20 | display.setTextColor(SSD1306_WHITE); 21 | 22 | display.clearDisplay(); 23 | display.setCursor(0, 0); 24 | display.print(APPNAME); 25 | display.display(); 26 | } 27 | 28 | void displayLoop() 29 | { 30 | static unsigned long msTick = millis(); 31 | if (millis() - msTick >= 500) // 500ms refresh rate 32 | { 33 | msTick = millis(); 34 | 35 | display.clearDisplay(); 36 | display.setCursor(0, 0); 37 | display.println("i2c display"); 38 | // display.println(ct_current, 2); 39 | display.display(); 40 | display.display(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /display.h: -------------------------------------------------------------------------------- 1 | #ifndef DISPLAY_H 2 | #define DISPLAY_H 3 | 4 | #include "app.h" 5 | 6 | void displaySetup(); 7 | void displayLoop(); 8 | 9 | #endif -------------------------------------------------------------------------------- /eeprom.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | // eeprom 3 | #include 4 | 5 | #include "eeprom.h" 6 | 7 | // globals 8 | char ap_ssid[] = "EnergyLogger-AP"; // limit to 32 bytes 9 | char ap_key[] = "12345678"; // limit to 16 bytes 10 | uint8_t sta_enable = 1; 11 | char sta_ssid[] = "KERPZ-AP2"; // limit to 32 bytes 12 | char sta_key[] = "hackmelol"; // limit to 16 bytes 13 | 14 | uint8_t beep_enable = 0; 15 | uint8_t analog_enable = 1; 16 | uint8_t display_enable = 0; 17 | uint8_t ads1115_enable = 0; 18 | 19 | uint8_t post_enable = 0; 20 | char api_url[] = "https://192.168.2.1:8001/cgi-bin/custom-full.cgi?a=iot"; // limit to 256 21 | char api_key[] = "NIJCG7UI28O9CAYD"; // limit to 32 22 | uint16_t http_timeout = 0; 23 | 24 | // emon 25 | uint8_t ct_enable = 1; 26 | float ct_calibration = 30.0; 27 | float ct_pf = 1.0; 28 | float ct_voltage = 235.0; 29 | 30 | uint8_t srne_enable = 1; 31 | uint8_t snat_enable = 0; 32 | 33 | void loadConfig() 34 | { 35 | EEPROM.begin(512); 36 | 37 | char ok[3]; 38 | EEPROM.get(419, ok); 39 | 40 | if (String(ok) == String("OK")) 41 | { 42 | Serial.print("Loading Storage (512b) ... "); 43 | EEPROM.get(0, ap_ssid); // 32 44 | EEPROM.get(32, ap_key); // 16 45 | EEPROM.get(48, sta_enable); // 1 46 | EEPROM.get(49, sta_ssid); // 32 47 | EEPROM.get(81, sta_key); // 16 48 | 49 | EEPROM.get(97, beep_enable); // 1 50 | EEPROM.get(98, analog_enable); // 1 51 | EEPROM.get(99, display_enable); // 1 52 | EEPROM.get(100, ads1115_enable); // 1 53 | 54 | EEPROM.get(101, post_enable); // 1 55 | EEPROM.get(102, api_url); // 256 56 | EEPROM.get(358, api_key); // 32 57 | EEPROM.get(390, http_timeout); // 2 58 | 59 | // Emon part 60 | EEPROM.get(392, ct_enable); // 1 61 | EEPROM.get(393, ct_calibration); // 8 bytes 62 | EEPROM.get(401, ct_voltage); // 8 bytes 63 | EEPROM.get(409, ct_pf); // 8 bytes 64 | 65 | // SRNE part 66 | EEPROM.get(417, srne_enable); // 1 67 | 68 | // SNAT part 69 | EEPROM.get(418, snat_enable); // 1 70 | 71 | Serial.println("Done"); 72 | } 73 | else 74 | { 75 | saveConfig(); 76 | } 77 | 78 | EEPROM.end(); 79 | } 80 | 81 | void saveConfig() 82 | { 83 | EEPROM.begin(512); 84 | 85 | Serial.print("Saving Storage (512b) ... "); 86 | // Wifi part 87 | EEPROM.put(0, ap_ssid); // 32 88 | EEPROM.put(32, ap_key); // 16 89 | EEPROM.put(48, sta_enable); // 1 90 | EEPROM.put(49, sta_ssid); // 32 91 | EEPROM.put(81, sta_key); // 16 92 | 93 | EEPROM.put(97, beep_enable); // 1 94 | EEPROM.put(98, analog_enable); // 1 95 | EEPROM.put(99, display_enable); // 1 96 | EEPROM.put(100, ads1115_enable); // 1 97 | 98 | EEPROM.put(101, post_enable); // 1 99 | EEPROM.put(102, api_url); // 256 100 | EEPROM.put(358, api_key); // 32 101 | EEPROM.put(390, http_timeout); // 2 102 | 103 | // Emon part 104 | EEPROM.put(392, ct_enable); // 1 105 | EEPROM.put(393, ct_calibration); // 8 bytes 106 | EEPROM.put(401, ct_voltage); // 8 bytes 107 | EEPROM.put(409, ct_pf); // 8 bytes 108 | 109 | // SRNE part 110 | EEPROM.put(417, srne_enable); // 1 111 | 112 | // SNAT part 113 | EEPROM.put(418, snat_enable); // 1 114 | 115 | char ok[3] = "OK"; 116 | EEPROM.put(419, ok); // 2 117 | EEPROM.commit(); 118 | Serial.println("Done"); 119 | 120 | EEPROM.end(); 121 | } 122 | -------------------------------------------------------------------------------- /eeprom.h: -------------------------------------------------------------------------------- 1 | #ifndef EEPROM_H 2 | #define EEPROM_H 3 | 4 | extern char ap_ssid[32]; 5 | extern char ap_key[16]; 6 | extern uint8_t sta_enable; 7 | extern char sta_ssid[32]; 8 | extern char sta_key[16]; 9 | 10 | // peripheral devices 11 | extern uint8_t beep_enable; 12 | extern uint8_t analog_enable; 13 | extern uint8_t display_enable; 14 | extern uint8_t ads1115_enable; 15 | 16 | extern uint8_t post_enable; 17 | extern char api_url[256]; 18 | extern char api_key[32]; 19 | extern uint16_t http_timeout; 20 | 21 | // emon 22 | extern uint8_t ct_enable; 23 | extern float ct_calibration; 24 | extern float ct_pf; 25 | extern float ct_voltage; 26 | 27 | extern uint8_t srne_enable; 28 | extern uint8_t snat_enable; 29 | 30 | void loadConfig(); 31 | void saveConfig(); 32 | 33 | #endif -------------------------------------------------------------------------------- /html.h: -------------------------------------------------------------------------------- 1 | #ifndef HTML_H 2 | #define HTML_H 3 | 4 | const char index_html[] PROGMEM = R"rawliteral( 5 | 6 | 7 | 8 | 9 | 10 | ESP8266 11 | 12 | 258 | 259 | 260 | 261 | 277 |
278 |
279 | 563 | 564 | 565 | 566 | )rawliteral"; 567 | 568 | #endif -------------------------------------------------------------------------------- /network.cpp: -------------------------------------------------------------------------------- 1 | // network 2 | #include 3 | #include 4 | #include 5 | 6 | #include "network.h" 7 | 8 | DNSServer dnsServer; 9 | 10 | /* Soft AP network parameters */ 11 | IPAddress apIP(192, 168, 4, 1); 12 | // IPAddress subnet(255, 255, 255, 0); 13 | // IPAddress gateway(192, 168, 4, 1); 14 | 15 | uint16_t wifi_retry = 0; 16 | 17 | boolean connectToSta() 18 | { 19 | static byte l = 30; // wifi connect timeout limit 20 | static byte c = 0; 21 | WiFi.mode(WIFI_AP_STA); 22 | Serial.print("Connecting to " + String(sta_ssid) + " "); 23 | WiFi.begin(sta_ssid, sta_key); 24 | while (c < l) 25 | { 26 | if (WiFi.status() == WL_CONNECTED) 27 | { 28 | Serial.println(" Success"); 29 | 30 | Serial.print("Local IP address: "); 31 | Serial.println(WiFi.localIP()); 32 | break; 33 | } 34 | delay(500); 35 | Serial.print("."); 36 | c++; 37 | } 38 | boolean isConnected = (c < l); 39 | if (!isConnected) 40 | { 41 | Serial.println(" Failed"); 42 | Serial.println("AP mode only!"); 43 | WiFi.mode(WIFI_AP); 44 | } 45 | return isConnected; 46 | } 47 | 48 | void networkSetup() 49 | { 50 | 51 | Serial.println(); 52 | 53 | if (sta_enable) 54 | { 55 | connectToSta(); 56 | } 57 | else 58 | { 59 | Serial.println("AP mode only!"); 60 | WiFi.mode(WIFI_AP); 61 | } 62 | 63 | // Serial.print("Setting soft-AP configuration ... "); 64 | // Serial.println(WiFi.softAPConfig(apIP, gateway, subnet) ? "Ready" : "Failed!"); 65 | 66 | Serial.print("Starting Soft-AP (" + String(ap_ssid) + ") ... "); 67 | Serial.println(WiFi.softAP(ap_ssid, ap_key) ? "Success" : "Failed!"); 68 | 69 | Serial.print("Soft-AP IP address: "); 70 | Serial.println(WiFi.softAPIP()); 71 | 72 | Serial.print("Starting MDNS (" + String(APPCODE) + ".local) ... "); 73 | Serial.println(MDNS.begin(APPCODE) ? "Success." : "Failed!"); 74 | MDNS.addService("http", "tcp", 80); 75 | 76 | WiFi.hostname(APPCODE); 77 | Serial.print("Starting DNS (" + String(APPCODE) + ") ... "); 78 | dnsServer.setTTL(300); 79 | dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure); 80 | dnsServer.start(53, "*", apIP); 81 | Serial.println("DNS started!"); 82 | } 83 | 84 | void networkLoop() 85 | { 86 | static uint32_t msTick = millis(); 87 | // check sta availability 88 | if (sta_enable && WiFi.status() != WL_CONNECTED && millis() - msTick >= 10000) // 10000ms refresh rate 89 | { 90 | msTick = millis(); 91 | // Serial.println("Checking availability: " + String(sta_ssid)); 92 | int n = WiFi.scanNetworks(); 93 | for (int i = 0; i < n; i++) 94 | { 95 | if (WiFi.SSID(i) == sta_ssid) 96 | { 97 | connectToSta(); 98 | wifi_retry = 0; 99 | break; 100 | } 101 | } 102 | if (wifi_retry < 65500) 103 | wifi_retry++; 104 | } 105 | // dns server 106 | dnsServer.processNextRequest(); 107 | MDNS.update(); 108 | } 109 | -------------------------------------------------------------------------------- /network.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORK_H 2 | #define NETWORK_H 3 | 4 | #include "app.h" 5 | 6 | // extern uint16_t wifi_error; 7 | 8 | void networkSetup(); 9 | void networkLoop(); 10 | 11 | #endif -------------------------------------------------------------------------------- /ntp.cpp: -------------------------------------------------------------------------------- 1 | // ntp 2 | #include 3 | #include 4 | 5 | #include "ntp.h" 6 | 7 | WiFiUDP ntpUDP; 8 | NTPClient timeClient(ntpUDP, "pool.ntp.org"); 9 | 10 | void ntpSetup() 11 | { 12 | Serial.print("Starting NTP Client ... "); 13 | timeClient.begin(); 14 | // timeClient.setTimeOffset(28800); // GMT +8 = 8 x 3600 15 | Serial.println("Done"); 16 | } 17 | 18 | void ntpLoop() 19 | { 20 | timeClient.update(); 21 | epoch = timeClient.getEpochTime(); 22 | } 23 | -------------------------------------------------------------------------------- /ntp.h: -------------------------------------------------------------------------------- 1 | #ifndef NTP_H 2 | #define NTP_H 3 | 4 | #include "app.h" 5 | 6 | void ntpSetup(); 7 | void ntpLoop(); 8 | 9 | #endif -------------------------------------------------------------------------------- /post.cpp: -------------------------------------------------------------------------------- 1 | // wifi 2 | #include 3 | // post 4 | #include 5 | #include 6 | 7 | #include "post.h" 8 | // openssl s_client -connect api.thingspeak.com:443 | openssl x509 -fingerprint -noout 9 | // const uint8_t fingerprint[20] = {0x27, 0x18, 0x92, 0xDD, 0xA4, 0x26, 0xC3, 0x07, 0x09, 0xB9, 0x7A, 0xE6, 0xC5, 0x21, 0xB9, 0x5B, 0x48, 0xF7, 0x16, 0xE1}; 10 | uint16_t post_error = 0; 11 | uint16_t wifi_error = 0; 12 | 13 | void postData(const String &data) 14 | { 15 | int ret = 0; 16 | // https 17 | // std::unique_ptrclient(new BearSSL::WiFiClientSecure); 18 | WiFiClientSecure client; 19 | HTTPClient http; 20 | 21 | if (WiFi.status() == WL_CONNECTED) 22 | { 23 | // https insecure 24 | // client.setFingerprint(fingerprint); 25 | client.setInsecure(); 26 | 27 | if (http_timeout > 0) 28 | http.setTimeout(http_timeout); // ms 29 | if (http.begin(client, api_url)) 30 | { 31 | http.addHeader("Content-Type", "application/x-www-form-urlencoded"); 32 | 33 | String postStr = "api_key=" + String(api_key) + data + "\n\n"; 34 | int httpCode = http.POST(postStr); 35 | 36 | if (httpCode == HTTP_CODE_OK) 37 | { 38 | // Serial.printf("[HTTP] POST... code: %d\n", httpCode); 39 | String payload = http.getString(); 40 | // Serial.println("received payload:\n<<"); 41 | // Serial.println(payload); 42 | // Serial.println(">>"); 43 | 44 | if (payload != "1") 45 | { 46 | if (post_error < 65500) 47 | post_error++; 48 | } 49 | // Serial.print("error: "); 50 | // Serial.println(error); 51 | } 52 | else 53 | { 54 | // Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str()); 55 | if (post_error < 65500) 56 | post_error++; 57 | // http_code=httpCode; 58 | } 59 | http.end(); 60 | } 61 | } 62 | else 63 | { 64 | if (wifi_error < 65500) 65 | wifi_error++; 66 | } 67 | } -------------------------------------------------------------------------------- /post.h: -------------------------------------------------------------------------------- 1 | #ifndef POST_H 2 | #define POST_H 3 | 4 | extern uint16_t post_error; 5 | extern uint16_t wifi_error; 6 | 7 | #include "eeprom.h" 8 | 9 | void postData(const String &data); 10 | 11 | #endif -------------------------------------------------------------------------------- /screenshots/Screenshot_20210218-212110_Chrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerpz/ArduinoEnergyLogger/78000e342d19f838a37cc593e1c6464f4fb18188/screenshots/Screenshot_20210218-212110_Chrome.jpg -------------------------------------------------------------------------------- /screenshots/Screenshot_20210218-212210_Chrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerpz/ArduinoEnergyLogger/78000e342d19f838a37cc593e1c6464f4fb18188/screenshots/Screenshot_20210218-212210_Chrome.jpg -------------------------------------------------------------------------------- /screenshots/Screenshot_20210218-212221_Chrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerpz/ArduinoEnergyLogger/78000e342d19f838a37cc593e1c6464f4fb18188/screenshots/Screenshot_20210218-212221_Chrome.jpg -------------------------------------------------------------------------------- /screenshots/Screenshot_20210218-212327_Chrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerpz/ArduinoEnergyLogger/78000e342d19f838a37cc593e1c6464f4fb18188/screenshots/Screenshot_20210218-212327_Chrome.jpg -------------------------------------------------------------------------------- /screenshots/Screenshot_20210218-212336_Chrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerpz/ArduinoEnergyLogger/78000e342d19f838a37cc593e1c6464f4fb18188/screenshots/Screenshot_20210218-212336_Chrome.jpg -------------------------------------------------------------------------------- /screenshots/Screenshot_20210218-212343_Chrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerpz/ArduinoEnergyLogger/78000e342d19f838a37cc593e1c6464f4fb18188/screenshots/Screenshot_20210218-212343_Chrome.jpg -------------------------------------------------------------------------------- /screenshots/grafana-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerpz/ArduinoEnergyLogger/78000e342d19f838a37cc593e1c6464f4fb18188/screenshots/grafana-1.png -------------------------------------------------------------------------------- /screenshots/grafana-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerpz/ArduinoEnergyLogger/78000e342d19f838a37cc593e1c6464f4fb18188/screenshots/grafana-2.png -------------------------------------------------------------------------------- /snat.cpp: -------------------------------------------------------------------------------- 1 | // SNAT Megatec part 2 | 3 | // megatec / snat / rs232 with RTS or DTR set to 5v 4 | #include 5 | SoftwareSerial mtSerial(D5, D6); // RX, TX 6 | 7 | uint16_t megatec_error = 0; 8 | 9 | // SNAT Megatec part 10 | float inv_in_voltage; 11 | float inv_in_fault_voltage; 12 | float inv_out_voltage; 13 | float inv_out_power; // w 14 | float inv_in_frequency; 15 | float inv_temperature; 16 | float inv_cell_voltage; 17 | char inv_flags[9] = ""; 18 | 19 | void snatSetup() 20 | { 21 | // megatec / snat 22 | mtSerial.begin(2400); 23 | } 24 | 25 | void snatLoop() 26 | { 27 | char data[47] = {0}; // buffer 28 | int i = 0; 29 | 30 | uint32_t len = 47; 31 | 32 | mtSerial.write('Q'); 33 | mtSerial.write('1'); 34 | mtSerial.write('\r'); 35 | 36 | unsigned long timeOut = millis() + 225; // timeout @ 225 ms 37 | i = 0; 38 | mtSerial.listen(); 39 | while (i < len && millis() < timeOut) 40 | { 41 | if (mtSerial.available()) 42 | { 43 | data[i] = mtSerial.read(); 44 | if (!(data[i] >= 48 && data[i] <= 57) && data[i] != 13 && data[i] != 40 && data[i] != 32 && data[i] != 46) 45 | { 46 | break; 47 | } 48 | i++; 49 | } 50 | delay(1); // this is required 51 | } 52 | 53 | if (i == len && 54 | data[0] == '(' && 55 | data[6] == ' ' && 56 | data[12] == ' ' && 57 | data[18] == ' ' && 58 | data[22] == ' ' && 59 | data[27] == ' ' && 60 | data[32] == ' ' && 61 | data[37] == ' ' && 62 | data[46] == '\r') 63 | { 64 | // extract data 65 | char *token = 0; 66 | token = strtok(&data[1], " "); // input voltage 67 | inv_in_voltage = atof(token); 68 | token = strtok(NULL, " "); // input fault voltage 69 | inv_in_fault_voltage = atof(token); 70 | token = strtok(NULL, " "); // output voltage 71 | inv_out_voltage = atof(token); 72 | token = strtok(NULL, " "); // output current 73 | inv_out_power = atof(token) * 10.0; 74 | token = strtok(NULL, " "); // input frequency 75 | inv_in_frequency = atof(token); 76 | token = strtok(NULL, " "); // cell voltage 77 | inv_cell_voltage = atof(token); 78 | token = strtok(NULL, " "); // inverter temperature 79 | inv_temperature = atof(token); 80 | token = strtok(NULL, "\r"); // flags 81 | strcpy(inv_flags, token); 82 | 83 | // ct_voltage = inv_in_voltage; 84 | } 85 | else 86 | { 87 | megatec_error++; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /snat.h: -------------------------------------------------------------------------------- 1 | #ifndef SNAT_H 2 | #define SNAT_H 3 | 4 | // #include "analog.h" 5 | #include "app.h" 6 | 7 | extern uint16_t megatec_error; 8 | 9 | extern float inv_in_voltage; 10 | extern float inv_in_fault_voltage; 11 | extern float inv_out_voltage; 12 | extern float inv_out_power; 13 | extern float inv_in_frequency; 14 | extern float inv_temperature; 15 | extern float inv_cell_voltage; 16 | extern char inv_flags[9]; 17 | 18 | void snatSetup(); 19 | void snatLoop(); 20 | 21 | #endif -------------------------------------------------------------------------------- /srne.cpp: -------------------------------------------------------------------------------- 1 | // SRNE Modbus part 2 | 3 | // modbus / srne / rs232 4 | #include 5 | SoftwareSerial mbSerial(D7, D8); // RX, TX 6 | 7 | uint16_t modbus_error = 0; 8 | 9 | float battery_voltage; 10 | float battery_charge; 11 | float mppt_temperature; 12 | float battery_temperature; 13 | 14 | float pv_voltage; 15 | // float pv_current; 16 | float pv_power; 17 | 18 | float dc_voltage; 19 | // float dc_current; 20 | float dc_power; 21 | 22 | /* crc 16 */ 23 | uint16_t crc16(uint8_t *buffer, uint8_t length) 24 | { 25 | uint8_t i, j; 26 | uint16_t crc = 0xFFFF; 27 | uint16_t tmp; 28 | 29 | // Calculate the CRC. 30 | for (i = 0; i < length; i++) 31 | { 32 | crc = crc ^ buffer[i]; 33 | for (j = 0; j < 8; j++) 34 | { 35 | tmp = crc & 0x0001; 36 | crc = crc >> 1; 37 | if (tmp) 38 | { 39 | crc = crc ^ 0xA001; 40 | } 41 | } 42 | } 43 | return crc; 44 | } 45 | 46 | void srneSetup() 47 | { 48 | // modbus srne 49 | mbSerial.begin(9600); 50 | } 51 | 52 | void srneLoop() 53 | { 54 | uint8_t transmit[8] = {0}; // rtu 55 | uint8_t data[25] = {0}; // buffer 56 | int i = 0; 57 | 58 | uint8_t id = 0x01; 59 | uint8_t command = 0x03; 60 | uint16_t start_address = 0x0100; 61 | uint16_t num_registers = 0x000b; 62 | 63 | // build packet for rtu 64 | transmit[0] = id; // slave_id; 65 | transmit[1] = command; // command; 66 | transmit[2] = start_address >> 8; 67 | transmit[3] = start_address & 0xFF; 68 | transmit[4] = num_registers >> 8; 69 | transmit[5] = num_registers & 0xFF; 70 | uint16_t crc = crc16(transmit, 6); 71 | transmit[6] = crc; 72 | transmit[7] = crc >> 8; 73 | 74 | uint32_t len = (num_registers * 2) + 5; 75 | 76 | for (i = 0; i < 8; i++) 77 | mbSerial.write(transmit[i]); 78 | 79 | unsigned long timeOut = millis() + 200; // timeout @ 200 ms 80 | i = 0; 81 | mbSerial.listen(); 82 | while (i < len && millis() < timeOut) 83 | { 84 | if (mbSerial.available()) 85 | { 86 | data[i] = mbSerial.read(); 87 | i++; 88 | } 89 | delay(1); // this is required 90 | } 91 | 92 | if (i == len) 93 | { 94 | // if (crc == crc16(data, 6)) { 95 | // data[0] // id 96 | // data[1] // 97 | // data[2] // 98 | 99 | // extract data 100 | battery_charge = word(data[3], data[4]); 101 | battery_voltage = word(data[5], data[6]) * 0.1; 102 | mppt_temperature = data[9]; 103 | battery_temperature = data[10]; 104 | 105 | dc_voltage = word(data[11], data[12]) * 0.1; 106 | // dc_current = word(data[13], data[14]) * 0.01; 107 | dc_power = word(data[15], data[16]); 108 | 109 | pv_voltage = word(data[17], data[18]) * 0.1; 110 | // pv_current = word(data[19], data[20]) * 0.01; 111 | pv_power = word(data[21], data[22]); // charging power 112 | 113 | // mppt_power = word(data[21], data[22]); 114 | // if (mppt_power > 0) 115 | // mppt_voltage = mppt_power / (word(data[7], data[8]) * 0.01); 116 | // load_switch = word(data[23], data[24]); 117 | } 118 | else 119 | { 120 | modbus_error++; 121 | } 122 | } 123 | 124 | /* 125 | void extractSRNE_daily() 126 | { 127 | uint8_t transmit[8] = {0}; // rtu 128 | uint8_t data[23] = {0}; // buffer 129 | int i = 0; 130 | 131 | uint8_t id = 0x01; 132 | uint8_t command = 0x03; 133 | uint16_t start_address = 0x010b; 134 | uint16_t num_registers = 0x000a; 135 | 136 | // build packet for rtu 137 | transmit[0] = id; // slave_id; 138 | transmit[1] = command; // command; 139 | transmit[2] = start_address >> 8; 140 | transmit[3] = start_address & 0xFF; 141 | transmit[4] = num_registers >> 8; 142 | transmit[5] = num_registers & 0xFF; 143 | uint16_t crc = crc16(transmit, 6); 144 | transmit[6] = crc; 145 | transmit[7] = crc >> 8; 146 | 147 | uint32_t len = (num_registers * 2) + 5; 148 | 149 | for (i = 0; i < 8; i++) 150 | mbSerial.write(transmit[i]); 151 | 152 | unsigned long timeOut = millis() + 200; // timeout @ 200 ms 153 | i = 0; 154 | mbSerial.listen(); 155 | while (i < len && millis() < timeOut) 156 | { 157 | if (mbSerial.available()) 158 | { 159 | data[i] = mbSerial.read(); 160 | i++; 161 | } 162 | delay(1); // this is required 163 | } 164 | 165 | if (i == len) 166 | { 167 | // if (crc == crc16(data, 6)) { 168 | // data[0] // id 169 | // data[1] // 170 | // data[2] // 171 | 172 | // extract data 173 | min_battery_voltage = word(data[3], data[4]); 174 | max_battery_voltage = word(data[5], data[6]); 175 | max_charging_current = word(data[7], data[8]); 176 | max_discharging_current = word(data[9], data[10]); 177 | max_charging_power = word(data[11], data[12]); 178 | max_discharging_power = word(data[13], data[14]); 179 | battery_charging_amphr = word(data[15], data[16]); 180 | battery_discharging_amphr = word(data[17], data[18]); 181 | power_generation = word(data[19], data[20]); 182 | power_consumption = word(data[21], data[22]); 183 | } 184 | else 185 | { 186 | modbus_error++; 187 | } 188 | } 189 | 190 | void extractSRNE_history() 191 | { 192 | uint8_t transmit[8] = {0}; // rtu 193 | uint8_t data[23] = {0}; // buffer 194 | int i = 0; 195 | 196 | uint8_t id = 0x01; 197 | uint8_t command = 0x03; 198 | uint16_t start_address = 0x0115; 199 | uint16_t num_registers = 0x000c; 200 | 201 | // build packet for rtu 202 | transmit[0] = id; // slave_id; 203 | transmit[1] = command; // command; 204 | transmit[2] = start_address >> 8; 205 | transmit[3] = start_address & 0xFF; 206 | transmit[4] = num_registers >> 8; 207 | transmit[5] = num_registers & 0xFF; 208 | uint16_t crc = crc16(transmit, 6); 209 | transmit[6] = crc; 210 | transmit[7] = crc >> 8; 211 | 212 | uint32_t len = (num_registers * 2) + 5; 213 | 214 | for (i = 0; i < 8; i++) 215 | mbSerial.write(transmit[i]); 216 | 217 | unsigned long timeOut = millis() + 200; // timeout @ 200 ms 218 | i = 0; 219 | mbSerial.listen(); 220 | while (i < len && millis() < timeOut) 221 | { 222 | if (mbSerial.available()) 223 | { 224 | data[i] = mbSerial.read(); 225 | i++; 226 | } 227 | delay(1); // this is required 228 | } 229 | 230 | if (i == len) 231 | { 232 | // if (crc == crc16(data, 6)) { 233 | // data[0] // id 234 | // data[1] // 235 | // data[2] // 236 | 237 | // extract data 238 | operating_days = word(data[3], data[4]); 239 | battery_overdischarges = word(data[5], data[6]); 240 | battery_fullcharges = word(data[7], data[8]); 241 | sum_battery_charging_amphr = ((data[9] << 24) | (data[10] << 16) | (data[11] << 8) | data[12]); // long(data[9], data[10], data[11], data[12]); 242 | sum_battery_discharging_amphr = ((data[13] << 24) | (data[14] << 16) | (data[15] << 8) | data[16]); // long(data[13], data[14], data[15], data[16]); 243 | sum_power_generation = ((data[17] << 24) | (data[18] << 16) | (data[19] << 8) | data[20]); // long(data[17], data[18], data[19], data[20]); 244 | sum_power_consumption = ((data[21] << 24) | (data[22] << 16) | (data[23] << 8) | data[24]); // long(data[21], data[22], data[23], data[24]); 245 | load_status = data[25] >> 7; 246 | load_brightness = data[25] & 0x7F; 247 | charging_status = data[26]; 248 | } 249 | else 250 | { 251 | modbus_error++; 252 | } 253 | } 254 | */ -------------------------------------------------------------------------------- /srne.h: -------------------------------------------------------------------------------- 1 | #ifndef SRNE_H 2 | #define SRNE_H 3 | 4 | // #include "analog.h" 5 | #include "app.h" 6 | 7 | extern uint16_t modbus_error; 8 | 9 | // SRNE Modbus part 10 | extern float battery_voltage; 11 | extern float battery_charge; 12 | extern float mppt_temperature; 13 | extern float battery_temperature; 14 | 15 | extern float pv_voltage; 16 | // extern float pv_current; 17 | extern float pv_power; 18 | 19 | extern float dc_voltage; 20 | // extern float dc_current; 21 | extern float dc_power; 22 | 23 | void srneSetup(); 24 | void srneLoop(); 25 | 26 | #endif -------------------------------------------------------------------------------- /webserver.cpp: -------------------------------------------------------------------------------- 1 | // webserver 2 | #include 3 | #include "ArduinoJson.h" 4 | 5 | #include "webserver.h" 6 | 7 | ESP8266WebServer webServer(80); 8 | 9 | int getRSSIasQuality(int RSSI) 10 | { 11 | int quality = 0; 12 | 13 | if (RSSI <= -100) 14 | { 15 | quality = 0; 16 | } 17 | else if (RSSI >= -50) 18 | { 19 | quality = 100; 20 | } 21 | else 22 | { 23 | quality = 2 * (RSSI + 100); 24 | } 25 | return quality; 26 | } 27 | 28 | void webserverSetup() 29 | { 30 | webServer.on("/", HTTP_GET, []() 31 | { webServer.send(200, "text/html", index_html); }); 32 | webServer.on("/system", HTTP_POST, []() 33 | { 34 | byte expand_system = 0; 35 | byte expand_wifiap = 1; 36 | byte expand_wifista = 1; 37 | byte expand_command = 1; 38 | 39 | if (webServer.arg("plain") != "{}") { 40 | DynamicJsonDocument doc(1024); 41 | deserializeJson(doc, webServer.arg("plain").c_str()); 42 | 43 | if (doc["expand_system"]) expand_system = doc["expand_system"]; 44 | if (doc["expand_wifiap"]) expand_wifiap = doc["expand_wifiap"]; 45 | if (doc["expand_wifista"]) expand_wifista = doc["expand_wifista"]; 46 | if (doc["expand_command"]) expand_command = doc["expand_command"]; 47 | 48 | if (doc["reboot"]) ESP.restart(); 49 | } 50 | 51 | String json; 52 | 53 | char datetime[20]; 54 | time_t t_epoch = epoch + (timezone * 3600); // epoch +8GMT 55 | struct tm *now = gmtime(&t_epoch); 56 | strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", now); 57 | 58 | json += "["; 59 | json += "{\"label\":\"System\",\"name\":\"expand_system\",\"value\":"+String(expand_system)+",\"elements\":["; 60 | json += "{\"type\":\"text\",\"label\":\"Chip ID\",\"name\":\"chip_id\",\"value\":\""+String(ESP.getChipId())+"\",\"attrib\":\"disabled\"},"; 61 | json += "{\"type\":\"text\",\"label\":\"Free Heap\",\"name\":\"free_heap\",\"value\":\""+String(ESP.getFreeHeap())+"\",\"attrib\":\"disabled\"},"; 62 | json += "{\"type\":\"text\",\"label\":\"Flash ID\",\"name\":\"flash_id\",\"value\":\""+String(ESP.getFlashChipId())+"\",\"attrib\":\"disabled\"},"; 63 | json += "{\"type\":\"text\",\"label\":\"Flash Size\",\"name\":\"flash_size\",\"value\":\""+String(ESP.getFlashChipSize())+"\",\"attrib\":\"disabled\"},"; 64 | //json += "{\"type\":\"text\",\"label\":\"Flash Real Size\",\"name\":\"flash_real_size\",\"value\":\""+String(ESP.getFlashChipRealSize())+"\",\"attrib\":\"disabled\"}"; 65 | json += "{\"type\":\"text\",\"label\":\"System Date\",\"name\":\"sys_date\",\"value\":\""+String(datetime)+"\",\"attrib\":\"disabled\"}"; 66 | json += "]},"; 67 | json += "{\"label\":\"Wifi AP\",\"name\":\"expand_wifiap\",\"value\":"+String(expand_wifiap)+",\"elements\":["; 68 | json += "{\"type\":\"text\",\"label\":\"AP MAC\",\"name\":\"ap_mac\",\"value\":\""+WiFi.softAPmacAddress()+"\",\"attrib\":\"disabled\"},"; 69 | json += "{\"type\":\"text\",\"label\":\"AP Address\",\"name\":\"ap_address\",\"value\":\""+WiFi.softAPIP().toString()+"\",\"attrib\":\"disabled\"},"; 70 | json += "{\"type\":\"text\",\"label\":\"AP SSID\",\"name\":\"ap_ssid\",\"value\":\""+String(ap_ssid)+"\",\"attrib\":\"disabled\"},"; 71 | json += "{\"type\":\"text\",\"label\":\"Connected Devices\",\"name\":\"connected_devices\",\"value\":\""+String(WiFi.softAPgetStationNum())+"\",\"attrib\":\"disabled\"}"; 72 | json += "]},"; 73 | json += "{\"label\":\"Wifi Station\",\"name\":\"expand_wifista\",\"value\":"+String(expand_wifista)+",\"elements\":["; 74 | json += "{\"type\":\"text\",\"label\":\"MAC\",\"name\":\"mac\",\"value\":\""+WiFi.macAddress()+"\",\"attrib\":\"disabled\"},"; 75 | json += "{\"type\":\"text\",\"label\":\"Address\",\"name\":\"address\",\"value\":\""+WiFi.localIP().toString()+"\",\"attrib\":\"disabled\"},"; 76 | json += "{\"type\":\"text\",\"label\":\"SSID\",\"name\":\"ssid\",\"value\":\""+WiFi.SSID()+"\",\"attrib\":\"disabled\"}"; 77 | json += "]},"; 78 | json += "{\"label\":\"Command\",\"name\":\"expand_command\",\"value\":"+String(expand_command)+",\"elements\":["; 79 | json += "{\"type\":\"button\",\"label\":\"REBOOT\",\"name\":\"reboot\",\"value\":\"reboot\",\"confirm\":\"Are you sure you want to reboot?\"}"; 80 | json += "]}"; 81 | json += "]"; 82 | 83 | webServer.sendHeader("Access-Control-Allow-Origin", "*"); 84 | webServer.send(200, "application/json", json); }); 85 | webServer.on("/scan", HTTP_GET, []() 86 | { 87 | String json = ""; 88 | 89 | json += "["; 90 | int n = WiFi.scanComplete(); 91 | if (n == -2) { 92 | WiFi.scanNetworks(true); 93 | } else if(n) { 94 | for (int i = 0; i < n; ++i) { 95 | if (i) json += ","; 96 | json += "{"; 97 | json += "\"rssi\":" + String(WiFi.RSSI(i)); 98 | json += "\"signal\":" + String(getRSSIasQuality(WiFi.RSSI(i))); 99 | json += ",\"ssid\":\"" + WiFi.SSID(i) + "\""; 100 | json += ",\"bssid\":\"" + WiFi.BSSIDstr(i) + "\""; 101 | json += ",\"channel\":" + String(WiFi.channel(i)); 102 | json += ",\"secure\":" + String(WiFi.encryptionType(i)); 103 | json += ",\"hidden\":" + String(WiFi.isHidden(i) ? "true" : "false"); 104 | json += "}"; 105 | } 106 | WiFi.scanDelete(); 107 | if (WiFi.scanComplete() == -2) { 108 | WiFi.scanNetworks(true); 109 | } 110 | } 111 | json += "]"; 112 | 113 | webServer.sendHeader("Access-Control-Allow-Origin", "*"); 114 | webServer.send(200, "application/json", json); }); 115 | webServer.on("/config", HTTP_POST, []() 116 | { 117 | if (webServer.arg("plain") != "{}") { 118 | DynamicJsonDocument doc(1024); 119 | deserializeJson(doc, webServer.arg("plain").c_str()); 120 | 121 | if (doc["ap_ssid"]) strcpy(ap_ssid, (const char*)doc["ap_ssid"]); 122 | if (doc["ap_key"]) strcpy(ap_key, (const char*)doc["ap_key"]); 123 | 124 | if (doc["sta_enable"]) sta_enable = doc["sta_enable"]; 125 | if (doc["sta_ssid"]) strcpy(sta_ssid, (const char*)doc["sta_ssid"]); 126 | if (doc["sta_key"]) strcpy(sta_key, (const char*)doc["sta_key"]); 127 | 128 | if (doc["beep_enable"]) beep_enable = doc["beep_enable"]; 129 | if (doc["analog_enable"]) analog_enable = doc["analog_enable"]; 130 | if (doc["display_enable"]) display_enable = doc["display_enable"]; 131 | if (doc["ads1115_enable"]) ads1115_enable = doc["ads1115_enable"]; 132 | if (doc["post_enable"]) post_enable = doc["post_enable"]; 133 | if (doc["api_url"]) strcpy(api_url, (const char*)doc["api_url"]); 134 | if (doc["api_key"]) strcpy(api_key, (const char*)doc["api_key"]); 135 | 136 | if (doc["ct_enable"]) ct_enable = doc["ct_enable"]; 137 | if (doc["ct_calibration"]) ct_enable = doc["ct_calibration"]; 138 | if (doc["ct_voltage"]) ct_voltage = doc["ct_voltage"]; 139 | if (doc["ct_pf"]) ct_pf = doc["ct_pf"]; 140 | 141 | if (doc["srne_enable"]) srne_enable = doc["srne_enable"]; 142 | if (doc["snat_enable"]) snat_enable = doc["snat_enable"]; 143 | 144 | saveConfig(); 145 | Serial.println("Save config"); 146 | } 147 | 148 | String json; 149 | String sep; 150 | int n = WiFi.scanNetworks(); 151 | 152 | json += "["; 153 | json += "{\"label\":\"Wifi AP\",\"name\":\"expand_wifiap\",\"value\":1,\"elements\":["; 154 | json += "{\"type\":\"text\",\"label\":\"AP SSID\",\"name\":\"ap_ssid\",\"value\":\"" + String(ap_ssid) + "\"},"; 155 | json += "{\"type\":\"text\",\"label\":\"AP Key\",\"name\":\"ap_key\",\"value\":\"" + String(ap_key) + "\"}"; 156 | json += "]},"; 157 | 158 | //if (sta_enable) { 159 | json += "{\"label\":\"Wifi Sta\",\"name\":\"expand_wifista\",\"value\":1,\"elements\":["; 160 | json += "{\"type\":\"select\",\"label\":\"Wifi Sta\",\"name\":\"sta_enable\",\"value\":\"" + String(sta_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]},"; 161 | json += "{\"type\":\"select\",\"label\":\"Sta SSID\",\"name\":\"ssid\",\"value\":\"" + WiFi.SSID() + "\",\"options\":["; 162 | if (n > 0) { 163 | for (int i = 0; i < n; i++) { 164 | json += sep+"[\""+WiFi.SSID(i)+"\",\""+WiFi.SSID(i)+" "+String(getRSSIasQuality(WiFi.RSSI(i)))+"%"; 165 | if (WiFi.encryptionType(i) != ENC_TYPE_NONE) { 166 | json += " ⚲"; 167 | } 168 | json += "\"]"; 169 | sep = ","; 170 | } 171 | } else { 172 | json += "[\"\",\"\"]"; 173 | } 174 | json += "]},"; 175 | json += "{\"type\":\"text\",\"label\":\"Sta Key\",\"name\":\"sta_key\",\"value\":\"" + String(sta_key) + "\"}"; 176 | json += "]},"; 177 | 178 | json += "{\"label\":\"Components\",\"name\":\"expand_component\",\"value\":1,\"elements\":["; 179 | json += "{\"type\":\"select\",\"label\":\"Beep\",\"name\":\"beep_enable\",\"value\":\"" + String(beep_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]},"; 180 | json += "{\"type\":\"select\",\"label\":\"Analog\",\"name\":\"analog_enable\",\"value\":\"" + String(analog_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]},"; 181 | json += "{\"type\":\"select\",\"label\":\"Display\",\"name\":\"display_enable\",\"value\":\"" + String(display_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]},"; 182 | json += "{\"type\":\"select\",\"label\":\"ADS1115\",\"name\":\"ads1115_enable\",\"value\":\"" + String(ads1115_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]}"; 183 | json += "]},"; 184 | 185 | json += "{\"label\":\"Post\",\"name\":\"expand_post\",\"value\":1,\"elements\":["; 186 | json += "{\"type\":\"select\",\"label\":\"Post Enable\",\"name\":\"post_enable\",\"value\":\"" + String(post_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]},"; 187 | json += "{\"type\":\"text\",\"label\":\"API url\",\"name\":\"api_url\",\"value\":\"" + String(api_url) + "\"},"; 188 | json += "{\"type\":\"text\",\"label\":\"API key\",\"name\":\"api_key\",\"value\":\"" + String(api_key) + "\"}"; 189 | json += "]},"; 190 | 191 | json += "{\"label\":\"Analog\",\"name\":\"expand_analog\",\"value\":1,\"elements\":["; 192 | json += "{\"type\":\"select\",\"label\":\"CT Enable\",\"name\":\"ct_enable\",\"value\":\"" + String(ct_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]},"; 193 | json += "{\"type\":\"text\",\"label\":\"CT Voltage\",\"name\":\"ct_voltage\",\"value\":\"" + String(ct_voltage) + "\"},"; 194 | json += "{\"type\":\"text\",\"label\":\"CT Calibration\",\"name\":\"ct_calibration\",\"value\":\"" + String(ct_calibration) + "\"},"; 195 | json += "{\"type\":\"text\",\"label\":\"CT Pf\",\"name\":\"ct_pf\",\"value\":\"" + String(ct_pf) + "\"}"; 196 | json += "]},"; 197 | 198 | json += "{\"label\":\"SRNE\",\"name\":\"expand_component\",\"value\":1,\"elements\":["; 199 | json += "{\"type\":\"select\",\"label\":\"SRNE Enable\",\"name\":\"srne_enable\",\"value\":\"" + String(srne_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]}"; 200 | json += "]},"; 201 | 202 | json += "{\"label\":\"SNAT\",\"name\":\"expand_component\",\"value\":1,\"elements\":["; 203 | json += "{\"type\":\"select\",\"label\":\"SNAT Enable\",\"name\":\"snat_enable\",\"value\":\"" + String(snat_enable) + "\",\"options\":[[\"0\",\"Disabled\"],[\"1\",\"Enabled\"]]}"; 204 | json += "]},"; 205 | 206 | json += "{\"label\":\"Page\",\"name\":\"expand_page\",\"value\":1,\"elements\":["; 207 | json += "{\"type\":\"button\",\"label\":\"UPDATE\",\"name\":\"update\",\"value\":\"update\"}"; 208 | json += "]}"; 209 | json += "]"; 210 | 211 | webServer.sendHeader("Access-Control-Allow-Origin", "*"); 212 | webServer.send(200, "application/json", json); }); 213 | webServer.on("/app", HTTP_POST, []() 214 | { 215 | byte refresh = 2; 216 | 217 | byte expand_analog = 1; 218 | byte expand_srne = 1; 219 | byte expand_snat = 0; 220 | byte expand_errors = 0; 221 | byte expand_page = 0; 222 | 223 | if (webServer.arg("plain") != "{}") { 224 | DynamicJsonDocument doc(1024); 225 | deserializeJson(doc, webServer.arg("plain").c_str()); 226 | 227 | if (doc["expand_analog"]) expand_analog = doc["expand_analog"]; 228 | if (doc["expand_srne"]) expand_srne = doc["expand_srne"]; 229 | if (doc["expand_snat"]) expand_snat = doc["expand_snat"]; 230 | if (doc["expand_errors"]) expand_errors = doc["expand_errors"]; 231 | if (doc["expand_page"]) expand_page = doc["expand_page"]; 232 | 233 | if (doc["refresh"]) refresh = doc["refresh"]; 234 | } 235 | 236 | String json; 237 | 238 | json += "["; 239 | 240 | if (analog_enable) { 241 | json += "{\"label\":\"Analog Sensor\",\"name\":\"expand_analog\",\"value\":1,\"elements\":["; 242 | json += "{\"type\":\"text\",\"label\":\"CT Voltage\",\"name\":\"ct_voltage\",\"value\":\""+String(ct_voltage)+"\",\"attrib\":\"disabled\"},"; 243 | json += "{\"type\":\"text\",\"label\":\"CT Power\",\"name\":\"ct_power\",\"value\":\""+String(ct_power)+"\",\"attrib\":\"disabled\"},"; 244 | json += "{\"type\":\"text\",\"label\":\"CT Energy W/m\",\"name\":\"ct_energy\",\"value\":\""+String(ct_energy)+"\",\"attrib\":\"disabled\"}"; 245 | json += "]},"; 246 | } 247 | 248 | if (srne_enable) { 249 | json += "{\"label\":\"SRNE Status\",\"name\":\"expand_status\",\"value\":"+String(expand_srne)+",\"elements\":["; 250 | json += "{\"type\":\"text\",\"label\":\"Batt Voltage\",\"name\":\"battery_voltage\",\"value\":\""+String(battery_voltage)+"\",\"attrib\":\"disabled\"},"; 251 | json += "{\"type\":\"text\",\"label\":\"Batt Charge\",\"name\":\"battery_charge\",\"value\":\""+String(battery_charge)+"\",\"attrib\":\"disabled\"},"; 252 | json += "{\"type\":\"text\",\"label\":\"Batt Temperature\",\"name\":\"battery_temperature\",\"value\":\""+String(battery_temperature)+"\",\"attrib\":\"disabled\"},"; 253 | json += "{\"type\":\"text\",\"label\":\"PV Voltage\",\"name\":\"pv_voltage\",\"value\":\""+String(pv_voltage)+"\",\"attrib\":\"disabled\"},"; 254 | json += "{\"type\":\"text\",\"label\":\"PV Power\",\"name\":\"pv_power\",\"value\":\""+String(pv_power)+"\",\"attrib\":\"disabled\"},"; 255 | json += "{\"type\":\"text\",\"label\":\"PV Energy W/m\",\"name\":\"pv_energy\",\"value\":\""+String(pv_energy)+"\",\"attrib\":\"disabled\"},"; 256 | json += "{\"type\":\"text\",\"label\":\"MPPT Temperature\",\"name\":\"mppt_temperature\",\"value\":\""+String(mppt_temperature)+"\",\"attrib\":\"disabled\"},"; 257 | json += "{\"type\":\"text\",\"label\":\"DC Voltage\",\"name\":\"dc_voltage\",\"value\":\""+String(dc_voltage)+"\",\"attrib\":\"disabled\"},"; 258 | json += "{\"type\":\"text\",\"label\":\"DC Power\",\"name\":\"dc_power\",\"value\":\""+String(dc_power)+"\",\"attrib\":\"disabled\"},"; 259 | json += "{\"type\":\"text\",\"label\":\"DC Energy W/m\",\"name\":\"dc_energy\",\"value\":\""+String(dc_energy)+"\",\"attrib\":\"disabled\"}"; 260 | json += "]},"; 261 | } 262 | 263 | if (snat_enable) { 264 | json += "{\"label\":\"SNAT Status\",\"name\":\"expand_snat\",\"value\":"+String(expand_snat)+",\"elements\":["; 265 | json += "{\"type\":\"text\",\"label\":\"Input Voltage\",\"name\":\"inv_in_voltage\",\"value\":\""+String(inv_in_voltage)+"\",\"attrib\":\"disabled\"},"; 266 | json += "{\"type\":\"text\",\"label\":\"Input Fault Voltage\",\"name\":\"inv_in_fault_voltage\",\"value\":\""+String(inv_in_fault_voltage)+"\",\"attrib\":\"disabled\"},"; 267 | json += "{\"type\":\"text\",\"label\":\"Output Voltage\",\"name\":\"inv_out_voltage\",\"value\":\""+String(inv_out_voltage)+"\",\"attrib\":\"disabled\"},"; 268 | json += "{\"type\":\"text\",\"label\":\"Out Power\",\"name\":\"inv_out_power\",\"value\":\""+String(inv_out_power)+"\",\"attrib\":\"disabled\"},"; 269 | json += "{\"type\":\"text\",\"label\":\"Frequency\",\"name\":\"inv_in_voltage\",\"value\":\""+String(inv_in_frequency)+"\",\"attrib\":\"disabled\"},"; 270 | json += "{\"type\":\"text\",\"label\":\"Temperature\",\"name\":\"inv_temperature\",\"value\":\""+String(inv_temperature)+"\",\"attrib\":\"disabled\"},"; 271 | json += "{\"type\":\"text\",\"label\":\"Cell Voltage\",\"name\":\"inv_cell_voltage\",\"value\":\""+String(inv_cell_voltage)+"\",\"attrib\":\"disabled\"}"; 272 | //json += "{\"type\":\"text\",\"label\":\"Input Voltage\",\"name\":\"inv_in_voltage\",\"value\":\""+String(inv_flags)+"\",\"attrib\":\"disabled\"},"; 273 | json += "]},"; 274 | } 275 | 276 | json += "{\"label\":\"Error\",\"name\":\"expand_errors\",\"value\":"+String(expand_errors)+",\"elements\":["; 277 | if (srne_enable) json += "{\"type\":\"text\",\"label\":\"Srne\",\"name\":\"modbus_error\",\"value\":\""+String(modbus_error)+"\",\"attrib\":\"disabled\"},"; 278 | if (snat_enable) json += "{\"type\":\"text\",\"label\":\"Snat\",\"name\":\"megatec_error\",\"value\":\""+String(megatec_error)+"\",\"attrib\":\"disabled\"},"; 279 | json += "{\"type\":\"text\",\"label\":\"Wifi\",\"name\":\"wifi_error\",\"value\":\""+String(wifi_error)+"\",\"attrib\":\"disabled\"},"; 280 | json += "{\"type\":\"text\",\"label\":\"Post\",\"name\":\"post_error\",\"value\":\""+String(post_error)+"\",\"attrib\":\"disabled\"}"; 281 | json += "]},"; 282 | 283 | json += "{\"label\":\"Page\",\"name\":\"expand_page\",\"value\":"+String(expand_page)+",\"elements\":["; 284 | json += "{\"type\":\"refresh\",\"label\":\"Refresh\",\"name\":\"refresh\",\"value\":"+String(refresh)+"}"; 285 | json += "]}"; 286 | 287 | json += "]"; 288 | 289 | webServer.sendHeader("Access-Control-Allow-Origin", "*"); 290 | webServer.send(200, "application/json", json); }); 291 | 292 | webServer.on("/firmware", HTTP_POST, []() 293 | { 294 | String json; 295 | json += "["; 296 | json += "{\"label\":\"Firmware Upgrade\",\"name\":\"firmware_upgrade\",\"value\":\"1\",\"elements\":["; 297 | json += "{\"type\":\"file\",\"label\":\"File\",\"name\":\"file\",\"value\":\"\",\"accept\":\".bin\"},"; 298 | json += "{\"type\":\"button\",\"label\":\"UPLOAD\",\"name\":\"upload\",\"value\":\"upload\"}"; 299 | json += "]}"; 300 | json += "]"; 301 | 302 | webServer.sendHeader("Access-Control-Allow-Origin", "*"); 303 | webServer.send(200, "application/json", json); }); 304 | webServer.on( 305 | "/upload", HTTP_POST, []() 306 | { 307 | String json; 308 | json += "["; 309 | json += "{\"label\":\"Firmware Upgrade\",\"name\":\"firmware_upgrade\",\"value\":\"1\",\"elements\":["; 310 | if (Update.hasError()) 311 | json += "{\"type\":\"alert\",\"value\":\"Upload failed!\"},"; 312 | else 313 | json += "{\"type\":\"alert\",\"value\":\"Upload success!\"},"; 314 | 315 | json += "{\"type\":\"file\",\"label\":\"File\",\"name\":\"file\",\"value\":\"\",\"accept\":\".bin\"},"; 316 | json += "{\"type\":\"button\",\"label\":\"UPDATE\",\"name\":\"update\",\"value\":\"update\"}"; 317 | json += "]}"; 318 | json += "]"; 319 | webServer.sendHeader("Access-Control-Allow-Origin", "*"); 320 | webServer.send(200, "application/json", json); 321 | ESP.restart(); }, 322 | []() 323 | { 324 | HTTPUpload &upload = webServer.upload(); 325 | if (upload.status == UPLOAD_FILE_START) 326 | { 327 | Serial.setDebugOutput(true); 328 | // WiFiUDP::stopAll(); 329 | Serial.printf("Update: %s\n", upload.filename.c_str()); 330 | uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; 331 | if (!Update.begin(maxSketchSpace)) 332 | { // start with max available size 333 | Update.printError(Serial); 334 | } 335 | } 336 | else if (upload.status == UPLOAD_FILE_WRITE) 337 | { 338 | if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) 339 | { 340 | Update.printError(Serial); 341 | } 342 | } 343 | else if (upload.status == UPLOAD_FILE_END) 344 | { 345 | if (Update.end(true)) 346 | { // true to set the size to the current progress 347 | Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); 348 | 349 | String json; 350 | json += "["; 351 | json += "{\"label\":\"Firmware Upgrade\",\"name\":\"firmware_upgrade\",\"value\":\"1\",\"elements\":["; 352 | if (Update.hasError()) 353 | json += "{\"type\":\"alert\",\"value\":\"Upload failed!\"},"; 354 | else 355 | json += "{\"type\":\"alert\",\"value\":\"Upload success!\"},"; 356 | 357 | json += "{\"type\":\"file\",\"label\":\"File\",\"name\":\"file\",\"value\":\"\",\"accept\":\".bin\"},"; 358 | json += "{\"type\":\"button\",\"label\":\"UPDATE\",\"name\":\"update\",\"value\":\"update\"}"; 359 | json += "]}"; 360 | json += "]"; 361 | webServer.sendHeader("Access-Control-Allow-Origin", "*"); 362 | webServer.send(200, "application/json", json); 363 | } 364 | else 365 | { 366 | Update.printError(Serial); 367 | } 368 | Serial.setDebugOutput(false); 369 | } 370 | yield(); 371 | }); 372 | // Send a POST request to /post with a form field message set to 373 | /* 374 | webServer.on("/post", HTTP_POST, []() { 375 | //nothing and dont remove it 376 | }, NULL, [](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { 377 | DynamicJsonDocument doc(1024); 378 | deserializeJson(doc, data); 379 | String json; 380 | 381 | serializeJson(doc, json); 382 | request->send(200, "application/json", json); 383 | }); 384 | */ 385 | webServer.onNotFound([]() 386 | { 387 | String json; 388 | //StaticJsonDocument<20> doc; 389 | //doc["message"] = "Endpoint not found"; 390 | //serializeJson(doc, json); 391 | json += "["; 392 | json += "{\"label\":\"404 Error\",\"name\":\"not_found\",\"value\":\"1\",\"elements\":["; 393 | json += "{\"type\":\"alert\",\"value\":\"Page not found!\"}"; 394 | json += "]}"; 395 | json += "]"; 396 | webServer.sendHeader("Access-Control-Allow-Origin", "*"); 397 | webServer.send(404, "application/json", json); }); 398 | 399 | Serial.print("Starting Webserver ... "); 400 | webServer.begin(); 401 | Serial.println("Done"); 402 | } 403 | 404 | void webserverLoop() 405 | { 406 | webServer.handleClient(); 407 | } 408 | -------------------------------------------------------------------------------- /webserver.h: -------------------------------------------------------------------------------- 1 | #ifndef WEBSERVER_H 2 | #define WEBSERVER_H 3 | 4 | #include "html.h" 5 | #include "analog.h" 6 | #include "post.h" 7 | #include "app.h" 8 | 9 | void webserverSetup(); 10 | void webserverLoop(); 11 | 12 | #endif --------------------------------------------------------------------------------