diff --git a/.gitignore b/.gitignore index 96374c4..25f47fd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,10 @@ Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ +node_modules/ +bootstrap-3.3.5-dist/ +font-awesome-4.5.0/ +webdev/ # Windows Installer files *.cab diff --git a/examples/ESP8266_WifInfo/ESP8266_WifInfo.ino b/examples/ESP8266_WifInfo/ESP8266_WifInfo.ino deleted file mode 100644 index 5dbc353..0000000 --- a/examples/ESP8266_WifInfo/ESP8266_WifInfo.ino +++ /dev/null @@ -1,585 +0,0 @@ -// ********************************************************************************** -// ESP8266 Teleinfo WEB Server -// ********************************************************************************** -// Creative Commons Attrib Share-Alike License -// You are free to use/extend this library but please abide with the CC-BY-SA license: -// Attribution-NonCommercial-ShareAlike 4.0 International License -// http://creativecommons.org/licenses/by-nc-sa/4.0/ -// -// For any explanation about teleinfo ou use , see my blog -// http://hallard.me/category/tinfo -// -// This program works with the Wifinfo board -// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo -// -// Written by Charles-Henri Hallard (http://hallard.me) -// -// History : V1.00 2015-06-14 - First release -// -// All text above must be included in any redistribution. -// -// ********************************************************************************** -// Include Arduino header -#include -#include -#include -#include -#include -#include -#include -//#include -//#include -#include -#include - -// Global project file -#include "ESP8266_WifInfo.h" - -//WiFiManager wifi(0); -ESP8266WebServer server(80); -// Udp listener and telnet server -WiFiUDP OTA; -// Teleinfo -TInfo tinfo; -// RGB Loed -NeoPixelBus rgb_led = NeoPixelBus(1, RGB_LED_PIN, NEO_RGB | NEO_KHZ800); - -// define whole brigtness level for RGBLED -uint8_t rgb_brightness = 127; -// LED Blink timers -Ticker rgb_ticker; -Ticker blu_ticker; -Ticker red_ticker; -Ticker Every_1_Sec; - -volatile boolean task_1_sec = false; -unsigned long seconds = 0; - -// sysinfo data -_sysinfo sysinfo; - -/* ====================================================================== -Function: UpdateSysinfo -Purpose : update sysinfo variables -Input : true if first call - true if needed to print on serial debug -Output : - -Comments: - -====================================================================== */ -void UpdateSysinfo(boolean first_call, boolean show_debug) -{ - char buff[64]; - int32_t adc; - int sec = seconds; - int min = sec / 60; - int hr = min / 60; - - sprintf( buff, "%02d:%02d:%02d", hr, min % 60, sec % 60); - sysinfo.sys_uptime = buff; - - sprintf( buff, "%d KB", ESP.getFreeHeap()/1024 ); - sysinfo.sys_free_ram = buff; - - adc = ( (1000 * analogRead(A0)) / 1024); - sprintf( buff, "%d mV", adc); - sysinfo.sys_analog = buff; - - // Values not subject to change during running sketch - if (first_call) { - sprintf( buff, "%d KB", ESP.getFlashChipRealSize()/1024 ); - sysinfo.sys_flash_real_size = buff; - sprintf( buff, "%d KB", ESP.getSketchSize()/1024 ); - sysinfo.sys_firmware_size = buff; - sprintf( buff, "%d KB", ESP.getFreeSketchSpace()/1024 ); - sysinfo.sys_firmware_free = buff; - sprintf( buff, "%d MHZ", ESP.getFlashChipSpeed()/1000 ); - sysinfo.sys_flash_speed = buff; - } - - if (show_debug) { - Debug(F("Firmware : ")); Debugln(__DATE__ " " __TIME__); - Debug(F("Flash real id: ")); Serial1.printf("0x%08X\r\n", ESP.getFlashChipId()); - Debug(F("Flash RSize : ")); Debugln(sysinfo.sys_flash_real_size); - Debug(F("CPU Speed : ")); Debugln(sysinfo.sys_flash_speed); - Debug(F("Sketch size : ")); Debugln(sysinfo.sys_firmware_size); - Debug(F("Free size : ")); Debugln(sysinfo.sys_firmware_free); - Debug(F("Free RAM : ")); Debugln(sysinfo.sys_free_ram); - Debug(F("OTA port : ")); Debugln(config.ota_port); - Debug(F("Analog Read : ")); Debugln(sysinfo.sys_analog); - Debug(F("Saved Config : ")); Debugln(sysinfo.sys_eep_config); - } -} - -/* ====================================================================== -Function: Task_1_Sec -Purpose : update our second ticker -Input : - -Output : - -Comments: - -====================================================================== */ -void Task_1_Sec() -{ - task_1_sec = true; - seconds++; -} - -/* ====================================================================== -Function: LedOff -Purpose : callback called after led blink delay -Input : led (defined in term of PIN) -Output : - -Comments: - -====================================================================== */ -void LedOff(int led) -{ - #ifdef BLU_LED_PIN - if (led==BLU_LED_PIN) - LedBluOFF(); - #endif - if (led==RED_LED_PIN) - LedRedOFF(); - if (led==RGB_LED_PIN) - LedRGBOFF(); -} - -/* ====================================================================== -Function: ADPSCallback -Purpose : called by library when we detected a ADPS on any phased -Input : phase number - 0 for ADPS (monophase) - 1 for ADIR1 triphase - 2 for ADIR2 triphase - 3 for ADIR3 triphase -Output : - -Comments: should have been initialised in the main sketch with a - tinfo.attachADPSCallback(ADPSCallback()) -====================================================================== */ -void ADPSCallback(uint8_t phase) -{ - // Monophasé - if (phase == 0 ) { - Debugln(F("ADPS")); - } else { - Debug(F("ADPS Phase ")); - Debugln('0' + phase); - } -} - -/* ====================================================================== -Function: DataCallback -Purpose : callback when we detected new or modified data received -Input : linked list pointer on the concerned data - value current state being TINFO_VALUE_ADDED/TINFO_VALUE_UPDATED -Output : - -Comments: - -====================================================================== */ -void DataCallback(ValueList * me, uint8_t flags) -{ - - // This is for simulating ADPS during my tests - // =========================================== - /* - static uint8_t test = 0; - // Each new/updated values - if (++test >= 20) { - test=0; - uint8_t anotherflag = TINFO_FLAGS_NONE; - ValueList * anotherme = tinfo.addCustomValue("ADPS", "46", &anotherflag); - - // Do our job (mainly debug) - DataCallback(anotherme, anotherflag); - } - Debugf("%02d:",test); - */ - // =========================================== - - - // Do whatever you want there - Debug(me->name); - Debug('='); - Debug(me->value); - - if ( flags & TINFO_FLAGS_NOTHING ) Debug(F(" Nothing")); - if ( flags & TINFO_FLAGS_ADDED ) Debug(F(" Added")); - if ( flags & TINFO_FLAGS_UPDATED ) Debug(F(" Updated")); - if ( flags & TINFO_FLAGS_EXIST ) Debug(F(" Exist")); - if ( flags & TINFO_FLAGS_ALERT ) Debug(F(" Alert")); - - Debugln(); -} - -/* ====================================================================== -Function: NewFrame -Purpose : callback when we received a complete teleinfo frame -Input : linked list pointer on the concerned data -Output : - -Comments: - -====================================================================== */ -void NewFrame(ValueList * me) -{ - char buff[32]; - - // Light the RGB LED - LedRGBON(COLOR_GREEN); - - sprintf( buff, "New Frame (%ld Bytes free)", ESP.getFreeHeap() ); - Debugln(buff); - - // led off after delay - rgb_ticker.once_ms( (uint32_t) BLINK_LED_MS, LedOff, (int) RGB_LED_PIN); -} - -/* ====================================================================== -Function: NewFrame -Purpose : callback when we received a complete teleinfo frame -Input : linked list pointer on the concerned data -Output : - -Comments: it's called only if one data in the frame is different than - the previous frame -====================================================================== */ -void UpdatedFrame(ValueList * me) -{ - char buff[32]; - - // Light the RGB LED (purple) - LedRGBON(COLOR_MAGENTA); - - sprintf( buff, "Updated Frame (%ld Bytes free)", ESP.getFreeHeap() ); - Debugln(buff); - - // led off after delay - rgb_ticker.once_ms(BLINK_LED_MS, LedOff, RGB_LED_PIN); -} - -/* ====================================================================== -Function: CheckOTAUpdate -Purpose : Check if we need to update the firmware over the Air -Input : - -Output : - -Comments: If upgraded, no return, perform update and reboot ESP -====================================================================== */ -void CheckOTAUpdate(void) -{ - bool spiffs = false; - - //OTA detection - if (OTA.parsePacket()) { - IPAddress remote = OTA.remoteIP(); - int cmd = OTA.parseInt(); - int port = OTA.parseInt(); - int size = OTA.parseInt(); - - LedRGBON(COLOR_MAGENTA); - - DebugF("OTA received command "); - Debugln(cmd); - if (cmd == U_SPIFFS) { - spiffs = true; - DebugF("Get SPIFFS image"); - } - - - DebugF("Update Start: ip:"); - Debug(remote); - Debugf(", port:%d, size:%dKB\n", port, size/1024); - uint32_t startTime = millis(); - - WiFiUDP::stopAll(); - - if(!Update.begin(size, cmd)) { - DebugF("Update Begin Error"); - return; - } - - WiFiClient ota_client; - - if (ota_client.connect(remote, port)) { - - uint32_t written; - while(!Update.isFinished()) { - written = Update.write(ota_client); - if(written > 0) - { - LedRGBOFF(); - ota_client.print(written, DEC); - LedRGBON(COLOR_MAGENTA); - } - } - LedRGBOFF(); - Serial.setDebugOutput(false); - - if(Update.end()) { - ota_client.println("OK"); - Debugf("Update Success: %u\nRebooting...\n", millis() - startTime); - ESP.restart(); - } else { - Update.printError(ota_client); - Update.printError(Serial); - } - } else { - Debugf("Connect Failed: %u\n", millis() - startTime); - } - - // Be sure to re enable it - OTA.begin(DEFAULT_OTA_PORT); - } -} - -/* ====================================================================== -Function: WifiSoftAP -Purpose : Change Wifi mode to Soft AP -Input : - -Output : state of the wifi status -Comments: - -====================================================================== */ -int WifiSoftAP() -{ -} - -/* ====================================================================== -Function: WifiHandleConn -Purpose : Handle Wifi connection / reconnection and OTA updates -Input : setup true if we're called 1st Time from setup -Output : state of the wifi status -Comments: - -====================================================================== */ -int WifiHandleConn(boolean setup = false) -{ - int ret ; - - if (setup) - { - // Check WiFi connection mode, at startup - // try to connect to AP - if (WiFi.getMode()!=WIFI_STA) { - WiFi.mode(WIFI_STA); - delay(10); - } - - // Get Wifi Status - ret = WiFi.status(); - - // Try to get 1st connexion - if ( ret != WL_CONNECTED ) { - - // Orange we're not connected anymore - LedRGBON(COLOR_ORANGE); - - DebugF("Connecting to: "); - Debug(DEFAULT_WIFI_SSID); - Debug(F("...")); - - WiFi.begin(DEFAULT_WIFI_SSID, DEFAULT_WIFI_PASS); - - ret = WiFi.waitForConnectResult(); - if ( ret != WL_CONNECTED) { - LedRGBON(COLOR_RED); - DebuglnF("Connection failed!"); - } else { - LedRGBON(COLOR_GREEN); - DebuglnF("Connected"); - DebugF("IP address : "); Debugln(WiFi.localIP()); - DebugF("MAC address : "); Debugln(WiFi.macAddress()); - - // just in case your sketch sucks, keep update OTA Available - // Trust me, when coding and testing it happens, this could save - // the need to connect FTDI to reflash - // Usefull just after 1st connexion when called from setup() before - // launching potentially bugging main() - for (uint8_t i=0; i<= 10; i++) { - LedRGBON(COLOR_MAGENTA); - delay(100); - LedRGBOFF(); - delay(200); - CheckOTAUpdate(); - } - } - } - - // We did not succeded to connect ? - if ( ret != WL_CONNECTED ) { - uint8_t mac[WL_MAC_ADDR_LENGTH]; - char ssid[32]; - - // start Soft AP - DebuglnF("Starting Soft AP mode"); - WiFi.mode(WIFI_AP); - - // Add the last two bytes of the MAC address to AP name - WiFi.softAPmacAddress(mac); - sprintf_P(ssid, PSTR("%s_%02X%02X"), DEFAULT_WIFI_AP_SSID, mac[4], mac[5] ); - - DebugF("SSID : "); Debugln(ssid); - //WiFi.softAP(ssid, DEFAULT_WIFI_AP_PSK); - //DebuglnF("PSK : " DEFAULT_WIFI_AP_PSK); - // No password - WiFi.softAP(ssid); - DebugF("IP : "); - Debugln(WiFi.softAPIP()); - } - - // Advertise US for Arduino IDE - // not very usefull on Windows (IDE does not always sees us) - MDNS.begin(DEFAULT_HOSTNAME); - MDNS.addService("arduino", "tcp", DEFAULT_OTA_PORT); - - // Setup OTA feature - OTA.begin(DEFAULT_OTA_PORT); - } - - // Handle OTA - CheckOTAUpdate(); - - return ret; -} - -/* ====================================================================== -Function: setup -Purpose : Setup I/O and other one time startup stuff -Input : - -Output : - -Comments: - -====================================================================== */ -void setup() -{ - boolean reset_config = true; - - // Set WiFi to station mode and disconnect from an AP if it was previously connected - //WiFi.mode(WIFI_STA); - //WiFi.disconnect(); - //delay(100); - - // Init the RGB Led, and set it off - rgb_led.Begin(); - LedRGBOFF(); - - // Init the serial 1 - // Teleinfo is connected to RXD2 (GPIO13) to - // avoid conflict when flashing, this is why - // we swap RXD1/RXD1 to RXD2/TXD2 - // Note that TXD2 is not used teleinfo is receive only - Serial.begin(1200, SERIAL_7E1); - Serial.swap(); - - // Our Debug Serial TXD0 - // note this serial can only transmit, just - // enough for debugging purpose - Serial1.begin(115200); - - Debugln(F("==============")); - Debugln(F("Wifinfo V1.0.1")); - Debugln(); - Debugflush(); - - // Clear our global flags - config.config = 0; - - // Our configuration is stored into EEPROM - EEPROM.begin(sizeof(_Config)); - - // Read Configuration from EEP - if (readConfig()) { - // in case of saved default config it's not good - if (config.ssid[0]!='*' && config.pass[0]!='*' ) { - sysinfo.sys_eep_config = PSTR("Good CRC, config OK"); - reset_config = false; - } else { - sysinfo.sys_eep_config = PSTR("Good CRC, not set!"); - } - } - - if (reset_config ) { - // Error, enable default configuration - strcpy_P(config.ssid, PSTR(DEFAULT_WIFI_SSID)); - strcpy_P(config.pass, PSTR(DEFAULT_WIFI_PASS)); - strcpy_P(config.host, PSTR(DEFAULT_HOSTNAME)); - config.ota_port = DEFAULT_OTA_PORT ; - - // Indicate the error in global flags - config.config |= CFG_BAD_CRC; - sysinfo.sys_eep_config = PSTR("Reset to default"); - - // save back - saveConfig(); - } - - Debugln(sysinfo.sys_eep_config); - - // Init teleinfo - tinfo.init(); - - // Attach the callback we need - // set all as an example - tinfo.attachADPS(ADPSCallback); - tinfo.attachData(DataCallback); - tinfo.attachNewFrame(NewFrame); - tinfo.attachUpdatedFrame(UpdatedFrame); - - // We'll drive our onboard LED - // old TXD1, not used anymore, has been swapped - pinMode(RED_LED_PIN, OUTPUT); - LedRedOFF(); - - // start Wifi connect or soft AP - WifiHandleConn(true); - - // Update sysinfor variable and print them - UpdateSysinfo(true, true); - - server.on("/", handleRoot); - server.on("/json", sendJSON); - server.on("/tinfojsontbl", tinfoJSONTable); - server.on("/sysjsontbl", sysJSONTable); - server.onNotFound(handleNotFound); - server.begin(); - - Debugln(F("HTTP server started")); - - //webSocket.begin(); - //webSocket.onEvent(webSocketEvent); - - // Light off the RGB LED - LedRGBOFF(); - - // control watchdog - //ESP.wdtEnable(); - //ESP.wdtDisable() - //ESP.wdtFeed(); - - // Update sysinfo every second - Every_1_Sec.attach(1, Task_1_Sec); -} - -/* ====================================================================== -Function: loop -Purpose : infinite loop main code -Input : - -Output : - -Comments: - -====================================================================== */ -void loop() -{ - char c; - - // Do all related network stuff - server.handleClient(); - - //webSocket.loop(); - - // 1 second task job ? - if (task_1_sec) { - UpdateSysinfo(false, false); - task_1_sec = false; - } - - // Handle teleinfo serial - if ( Serial.available() ) { - // Read Serial and process to tinfo - c = Serial.read(); - //Serial1.print(c); - tinfo.process(c); - } - - delay(10); -} - diff --git a/examples/ESP8266_WifInfo/config.h b/examples/ESP8266_WifInfo/config.h deleted file mode 100644 index 067dd03..0000000 --- a/examples/ESP8266_WifInfo/config.h +++ /dev/null @@ -1,75 +0,0 @@ -// ********************************************************************************** -// ESP8266 Teleinfo WEB Server configuration Include file -// ********************************************************************************** -// Creative Commons Attrib Share-Alike License -// You are free to use/extend this library but please abide with the CC-BY-SA license: -// Attribution-NonCommercial-ShareAlike 4.0 International License -// http://creativecommons.org/licenses/by-nc-sa/4.0/ -// -// For any explanation about teleinfo ou use , see my blog -// http://hallard.me/category/tinfo -// -// This program works with the Wifinfo board -// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo -// -// Written by Charles-Henri Hallard (http://hallard.me) -// -// History : V1.00 2015-06-14 - First release -// -// All text above must be included in any redistribution. -// -// ********************************************************************************** -#ifndef __CONFIG_H__ -#define __CONFIG_H__ - -// Include main project include file -#include "ESP8266_WifInfo.h" - -#define CFG_MAX_SSID_SIZE 32 -#define CFG_MAX_PASS_SIZE 32 -#define CFG_MAX_HOSTNAME 16 - -// Mettez ici vos identifiant de connexion à -// votre réseau WIFI -#define DEFAULT_WIFI_SSID "************" -#define DEFAULT_WIFI_PASS "************" -#define DEFAULT_HOSTNAME "WifInfo-esp01" - -// En mode acces point -#define DEFAULT_WIFI_AP_SSID "WifInfo" -#define DEFAULT_WIFI_AP_PSK "WifInfoPSK" - -// Port pour l'OTA -#define DEFAULT_OTA_PORT 8266 - -// Bit definition for different configuration modes -#define CFG_LCD 0x0001 // Enable display -#define CFG_DEBUG 0x0002 // Enable serial debug -#define CFG_BAD_CRC 0x8000 // Bad CRC when reading configuration - -// Config saved into eeprom -// 128 bytes total including CRC -typedef struct -{ - char ssid[CFG_MAX_SSID_SIZE]; /* SSID */ - char pass[CFG_MAX_PASS_SIZE]; /* Password */ - char host[CFG_MAX_HOSTNAME]; /* Password */ - uint32_t config; /* Bit field register */ - uint16_t ota_port; /* OTA port */ - uint8_t filler[40]; /* in case adding data in config avoiding loosing current conf by bad crc*/ - uint16_t crc; -} _Config; - - -// Exported variables/object instancied in main sketch -// =================================================== -extern _Config config; - -// Declared exported function from route.cpp -// =================================================== -bool readConfig (void); -bool saveConfig (void); - - -#endif - diff --git a/examples/ESP8266_WifInfo/route.cpp b/examples/ESP8266_WifInfo/route.cpp deleted file mode 100644 index 97a4059..0000000 --- a/examples/ESP8266_WifInfo/route.cpp +++ /dev/null @@ -1,562 +0,0 @@ -// ********************************************************************************** -// ESP8266 Teleinfo WEB Server, route web function -// ********************************************************************************** -// Creative Commons Attrib Share-Alike License -// You are free to use/extend this library but please abide with the CC-BY-SA license: -// Attribution-NonCommercial-ShareAlike 4.0 International License -// http://creativecommons.org/licenses/by-nc-sa/4.0/ -// -// For any explanation about teleinfo ou use, see my blog -// http://hallard.me/category/tinfo -// -// This program works with the Wifinfo board -// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo -// -// Written by Charles-Henri Hallard (http://hallard.me) -// -// History : V1.00 2015-06-14 - First release -// -// All text above must be included in any redistribution. -// -// ********************************************************************************** - -// Include Arduino header -#include "route.h" - -/* ====================================================================== -Function: handleRoot -Purpose : handle main page /, display information -Input : - -Output : - -Comments: - -====================================================================== */ -void handleRoot(void) -{ - String response=""; - - // Just to debug where we are - Debug(F("Serving / page...")); - - LedBluON(); - - // start HTML Code - response += F("" - "" - "" - "" - "" - // Our custom style - "" - "" - "" - "Wifinfo" - ""); - - response += F("
" - // Onglets - ""); - - // Contenu des onglets - response += F("
"); - - // tab teleinfo - response += F( "
" - "

Données de Téléinformation

" - "
Charge courante : " - "
" - "
" - "Attente des données" - "
" - "
" - "
" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "
EtiquetteValeurChecksumFlags
" - "
"); // tab pane - // tab Systeme - response += F( "
" - "

Données du système

" - "" - "" - "" - "" - "" - "" - "" - "
DonnéeValeur
" - "
"); // tab pane - - // tab Configuration - response += F( "
" - "

Configuration du module WifInfo

" - "

Cette partie reste à faire, des volontaires motivés ?

" - "
"); // tab pane - - response += F("
"); // tab content - -/* - response += F("")); -*/ - - response += F("
\r\n"); // Container - response += F("\r\n"); - response += F("\r\n"); - response += F("\r\n"); - - response += F("" "\r\n"); - - response += F(""); - - response += F("\r\n"); - - // Just to debug buffer free size - Debug(F("sending ")); - Debug(response.length()); - Debug(F(" bytes...")); - - // Send response to client - server.send ( 200, "text/html", response ); - - Debug(F("OK!")); - - LedBluOFF(); -} - -/* ====================================================================== -Function: formatNumberJSON -Purpose : check if data value is full number and send correct JSON format -Input : String where to add response - char * value to check -Output : - -Comments: 00150 => 150 - ADCO => "ADCO" - 1 => 1 -====================================================================== */ -void formatNumberJSON( String &response, char * value) -{ - // we have at least something ? - if (value && strlen(value)) - { - boolean isNumber = true; - uint8_t c; - char * p = value; - - // just to be sure - if (strlen(p)<=16) { - // check if value is number - while (*p && isNumber) { - if ( *p < '0' || *p > '9' ) - isNumber = false; - p++; - } - - // this will add "" on not number values - if (!isNumber) { - response += '\"' ; - response += value ; - response += F("\":") ; - } else { - // this will remove leading zero on numbers - p = value; - while (*p=='0' && *(p+1) ) - p++; - response += p ; - } - } else { - Debugln(F("formatNumberJSON error!")); - } - } -} - - -/* ====================================================================== -Function: tinfoJSONTable -Purpose : dump all teleinfo values in JSON table format for browser -Input : linked list pointer on the concerned data - true to dump all values, false for only modified ones -Output : - -Comments: - -====================================================================== */ -void tinfoJSONTable(void) -{ - ValueList * me = tinfo.getList(); - String response = ""; - - // Just to debug where we are - Debug(F("Serving /tinfoJSONTable page...\r\n")); - - // Got at least one ? - if (me) { - uint8_t index=0; - - boolean first_item = true; - // Json start - response += F("[\r\n"); - - // Loop thru the node - while (me->next) { - - // we're there - ESP.wdtFeed(); - - // go to next node - me = me->next; - - // First item do not add , separator - if (first_item) - first_item = false; - else - response += F(",\r\n"); - - Debug(F("(")) ; - Debug(++index) ; - Debug(F(") ")) ; - - if (me->name) Debug(me->name) ; - else Debug(F("NULL")) ; - - Debug(F("=")) ; - - if (me->value) Debug(me->value) ; - else Debug(F("NULL")) ; - - Debug(F(" '")) ; - Debug(me->checksum) ; - Debug(F("' ")); - - // Flags management - if ( me->flags) { - Debug(F("Flags:0x")); - Debugf("%02X => ", me->flags); - if ( me->flags & TINFO_FLAGS_EXIST) - Debug(F("Exist ")) ; - if ( me->flags & TINFO_FLAGS_UPDATED) - Debug(F("Updated ")) ; - if ( me->flags & TINFO_FLAGS_ADDED) - Debug(F("New ")) ; - } - - Debugln() ; - - response += F("{\"na\":\""); - response += me->name ; - response += F("\", \"va\":\"") ; - response += me->value; - response += F("\", \"ck\":\"") ; - if (me->checksum == '"' || me->checksum == '\\' || me->checksum == '/') - response += '\\'; - response += (char) me->checksum; - response += F("\", \"fl\":"); - response += me->flags ; - response += '}' ; - - } - // Json end - response += F("\r\n]"); - - } else { - Debugln(F("sending 404...")); - server.send ( 404, "text/plain", "No data" ); - } - Debug(F("sending...")); - server.send ( 200, "text/json", response ); - Debugln(F("OK!")); -} - -/* ====================================================================== -Function: sysJSONTable -Purpose : dump all sysinfo values in JSON table format for browser -Input : linked list pointer on the concerned data - true to dump all values, false for only modified ones -Output : - -Comments: - -====================================================================== */ -void sysJSONTable() -{ - String response = ""; - - // Just to debug where we are - Debug(F("Serving /sysJSONTable page...")); - - // Json start - response += F("[\r\n"); - - response += "{\"na\":\"Uptime\",\"va\":\""; - response += sysinfo.sys_uptime; - response += "\"},\r\n"; - - response += "{\"na\":\"Compile le\",\"va\":\"" __DATE__ " " __TIME__ "\"},\r\n"; - response += "{\"na\":\"Free Ram\",\"va\":\""; - response += sysinfo.sys_free_ram; - response += "\"},\r\n"; - - response += "{\"na\":\"Flash Real Size\",\"va\":\""; - response += sysinfo.sys_flash_real_size ; - response += "\"},\r\n"; - - response += "{\"na\":\"Firmware Size\",\"va\":\""; - response += sysinfo.sys_firmware_size; - response += "\"},\r\n"; - - response += "{\"na\":\"Free Size\",\"va\":\""; - response += sysinfo.sys_firmware_free; - response += "\"},\r\n"; - - response += "{\"na\":\"Wifi SSID\",\"va\":\""; - response += config.ssid; - response += "\"},\r\n"; - - response += "{\"na\":\"OTA Network Port\",\"va\":"; - response += config.ota_port ; - response += "},\r\n"; - - response += "{\"na\":\"Wifi RSSI\",\"va\":\""; - response += WiFi.RSSI() ; - response += " dB\"}\r\n"; - - response += "{\"na\":\"Analog\",\"va\":\""; - response += sysinfo.sys_analog; - response += " dB\"}\r\n"; - - // Json end - response += F("]\r\n"); - - Debug(F("sending...")); - server.send ( 200, "text/json", response ); - Debugln(F("Ok!")); -} - -/* ====================================================================== -Function: sendJSON -Purpose : dump all values in JSON -Input : linked list pointer on the concerned data - true to dump all values, false for only modified ones -Output : - -Comments: - -====================================================================== */ -void sendJSON(void) -{ - ValueList * me = tinfo.getList(); - String response = ""; - - // Got at least one ? - if (me) { - // Json start - response += F("{\"_UPTIME\":"); - response += seconds; - - // Loop thru the node - while (me->next) { - - // we're there - ESP.wdtFeed(); - - // go to next node - me = me->next; - - response += F(",\"") ; - response += me->name ; - response += F("\":") ; - formatNumberJSON(response, me->value); - } - // Json end - response += F("}\r\n") ; - - } else { - server.send ( 404, "text/plain", "No data" ); - } - server.send ( 200, "text/json", response ); -} - -/* ====================================================================== -Function: handleNotFound -Purpose : default WEB routing when URI is not found -Input : linked list pointer on the concerned data - true to dump all values, false for only modified ones -Output : - -Comments: We search is we have a name that match to this URI, if one we - return it's pair name/value in json -====================================================================== */ -void handleNotFound(void) -{ - String response = ""; - - // We check for an known label - ValueList * me = tinfo.getList(); - const char * uri; - boolean found = false; - - // Led on - LedBluON(); - - // convert uri to char * for compare - uri = server.uri().c_str(); - - Debugf("handleNotFound(%s)\r\n", uri); - - // Got at least one and consistent URI ? - if (me && uri && *uri=='/' && *++uri ) { - - // Loop thru the linked list of values - while (me->next && !found) { - - // we're there - ESP.wdtFeed(); - - // go to next node - me = me->next; - - //Debugf("compare to '%s' ", me->name); - // Do we have this one ? - if (stricmp (me->name, uri) == 0 ) - { - // no need to continue - found = true; - - // Add to respone - response += F("{\"") ; - response += me->name ; - response += F("\":") ; - formatNumberJSON(response, me->value); - response += F("}\r\n"); - } - } - } - - // Got it, send json - if (found) { - server.send ( 200, "text/json", response ); - } else { - // send error message in plain text - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; - message += ( server.method() == HTTP_GET ) ? "GET" : "POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; - - for ( uint8_t i = 0; i < server.args(); i++ ) { - message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n"; - } - - server.send ( 404, "text/plain", message ); - } - - // Led off - LedBluOFF(); -} - diff --git a/examples/ESP8266_WifInfo/ESP8266_WifInfo.h b/examples/Wifinfo/Wifinfo.h similarity index 80% rename from examples/ESP8266_WifInfo/ESP8266_WifInfo.h rename to examples/Wifinfo/Wifinfo.h index b64df11..3836de5 100644 --- a/examples/ESP8266_WifInfo/ESP8266_WifInfo.h +++ b/examples/Wifinfo/Wifinfo.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,23 +35,33 @@ //#include #include #include +#include -#include "route.h" +extern "C" { +#include "user_interface.h" +} + +#include "webserver.h" +#include "webclient.h" #include "config.h" #define DEBUG +#define DEBUG_SERIAL Serial1 +#define DEBUG_SERIAL1 + +#define WIFINFO_VERSION "1.0.0" // I prefix debug macro to be sure to use specific for THIS library // debugging, this should not interfere with main sketch or other // libraries #ifdef DEBUG -#define Debug(x) Serial1.print(x) -#define Debugln(x) Serial1.println(x) -#define DebugF(x) Serial1.print(F(x)) -#define DebuglnF(x) Serial1.println(F(x)) -#define Debugf(...) Serial1.printf(__VA_ARGS__) -#define Debugflush Serial1.flush +#define Debug(x) DEBUG_SERIAL.print(x) +#define Debugln(x) DEBUG_SERIAL.println(x) +#define DebugF(x) DEBUG_SERIAL.print(F(x)) +#define DebuglnF(x) DEBUG_SERIAL.println(F(x)) +#define Debugf(...) DEBUG_SERIAL.printf(__VA_ARGS__) +#define Debugflush DEBUG_SERIAL.flush #else #define Debug(x) {} #define Debugln(x) {} @@ -92,13 +103,6 @@ typedef struct { String sys_uptime; - String sys_free_ram; - String sys_flash_real_size; - String sys_flash_speed; - String sys_firmware_size; - String sys_firmware_free; - String sys_analog; - String sys_eep_config; } _sysinfo; // Exported variables/object instancied in main sketch @@ -110,7 +114,15 @@ extern NeoPixelBus rgb_led ; extern uint8_t rgb_brightness; extern unsigned long seconds; extern _sysinfo sysinfo; +extern Ticker Tick_emoncms; +extern Ticker Tick_jeedom; +// Exported function located in main sketch +// =================================================== +void ResetConfig(void); +void Task_emoncms(); +void Task_jeedom(); + #endif diff --git a/examples/Wifinfo/Wifinfo.ino b/examples/Wifinfo/Wifinfo.ino new file mode 100644 index 0000000..b368ebf --- /dev/null +++ b/examples/Wifinfo/Wifinfo.ino @@ -0,0 +1,766 @@ +// ********************************************************************************** +// ESP8266 Teleinfo WEB Server +// ********************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this library but please abide with the CC-BY-SA license: +// Attribution-NonCommercial-ShareAlike 4.0 International License +// http://creativecommons.org/licenses/by-nc-sa/4.0/ +// +// For any explanation about teleinfo ou use , see my blog +// http://hallard.me/category/tinfo +// +// This program works with the Wifinfo board +// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2015-06-14 - First release +// +// All text above must be included in any redistribution. +// +// ********************************************************************************** +// Include Arduino header +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include +#include + +// Global project file +#include "Wifinfo.h" + +//WiFiManager wifi(0); +ESP8266WebServer server(80); + +bool ota_blink; + +// Teleinfo +TInfo tinfo; + +// RGB Loed +NeoPixelBus rgb_led = NeoPixelBus(1, RGB_LED_PIN, NEO_RGB | NEO_KHZ800); + +// define whole brigtness level for RGBLED +uint8_t rgb_brightness = 127; +// LED Blink timers +Ticker rgb_ticker; +Ticker blu_ticker; +Ticker red_ticker; +Ticker Every_1_Sec; +Ticker Tick_emoncms; +Ticker Tick_jeedom; + +volatile boolean task_1_sec = false; +volatile boolean task_emoncms = false; +volatile boolean task_jeedom = false; +unsigned long seconds = 0; + +// sysinfo data +_sysinfo sysinfo; + +/* ====================================================================== +Function: UpdateSysinfo +Purpose : update sysinfo variables +Input : true if first call + true if needed to print on serial debug +Output : - +Comments: - +====================================================================== */ +void UpdateSysinfo(boolean first_call, boolean show_debug) +{ + char buff[64]; + int32_t adc; + int sec = seconds; + int min = sec / 60; + int hr = min / 60; + + sprintf_P( buff, PSTR("%02d:%02d:%02d"), hr, min % 60, sec % 60); + sysinfo.sys_uptime = buff; +} + +/* ====================================================================== +Function: Task_1_Sec +Purpose : update our second ticker +Input : - +Output : - +Comments: - +====================================================================== */ +void Task_1_Sec() +{ + task_1_sec = true; + seconds++; +} + +/* ====================================================================== +Function: Task_emoncms +Purpose : callback of emoncms ticker +Input : +Output : - +Comments: Like an Interrupt, need to be short, we set flag for main loop +====================================================================== */ +void Task_emoncms() +{ + task_emoncms = true; +} + +/* ====================================================================== +Function: Task_jeedom +Purpose : callback of jeedom ticker +Input : +Output : - +Comments: Like an Interrupt, need to be short, we set flag for main loop +====================================================================== */ +void Task_jeedom() +{ + task_jeedom = true; +} + +/* ====================================================================== +Function: LedOff +Purpose : callback called after led blink delay +Input : led (defined in term of PIN) +Output : - +Comments: - +====================================================================== */ +void LedOff(int led) +{ + #ifdef BLU_LED_PIN + if (led==BLU_LED_PIN) + LedBluOFF(); + #endif + if (led==RED_LED_PIN) + LedRedOFF(); + if (led==RGB_LED_PIN) + LedRGBOFF(); +} + +/* ====================================================================== +Function: ADPSCallback +Purpose : called by library when we detected a ADPS on any phased +Input : phase number + 0 for ADPS (monophase) + 1 for ADIR1 triphase + 2 for ADIR2 triphase + 3 for ADIR3 triphase +Output : - +Comments: should have been initialised in the main sketch with a + tinfo.attachADPSCallback(ADPSCallback()) +====================================================================== */ +void ADPSCallback(uint8_t phase) +{ + // Monophasé + if (phase == 0 ) { + Debugln(F("ADPS")); + } else { + Debug(F("ADPS Phase ")); + Debugln('0' + phase); + } +} + +/* ====================================================================== +Function: DataCallback +Purpose : callback when we detected new or modified data received +Input : linked list pointer on the concerned data + value current state being TINFO_VALUE_ADDED/TINFO_VALUE_UPDATED +Output : - +Comments: - +====================================================================== */ +void DataCallback(ValueList * me, uint8_t flags) +{ + + // This is for simulating ADPS during my tests + // =========================================== + /* + static uint8_t test = 0; + // Each new/updated values + if (++test >= 20) { + test=0; + uint8_t anotherflag = TINFO_FLAGS_NONE; + ValueList * anotherme = tinfo.addCustomValue("ADPS", "46", &anotherflag); + + // Do our job (mainly debug) + DataCallback(anotherme, anotherflag); + } + Debugf("%02d:",test); + */ + // =========================================== + +/* + // Do whatever you want there + Debug(me->name); + Debug('='); + Debug(me->value); + + if ( flags & TINFO_FLAGS_NOTHING ) Debug(F(" Nothing")); + if ( flags & TINFO_FLAGS_ADDED ) Debug(F(" Added")); + if ( flags & TINFO_FLAGS_UPDATED ) Debug(F(" Updated")); + if ( flags & TINFO_FLAGS_EXIST ) Debug(F(" Exist")); + if ( flags & TINFO_FLAGS_ALERT ) Debug(F(" Alert")); + + Debugln(); +*/ +} + +/* ====================================================================== +Function: NewFrame +Purpose : callback when we received a complete teleinfo frame +Input : linked list pointer on the concerned data +Output : - +Comments: - +====================================================================== */ +void NewFrame(ValueList * me) +{ + char buff[32]; + + // Light the RGB LED + if ( config.config & CFG_RGB_LED) { + LedRGBON(COLOR_GREEN); + + // led off after delay + rgb_ticker.once_ms( (uint32_t) BLINK_LED_MS, LedOff, (int) RGB_LED_PIN); + } + + sprintf_P( buff, PSTR("New Frame (%ld Bytes free)"), ESP.getFreeHeap() ); + Debugln(buff); +} + +/* ====================================================================== +Function: NewFrame +Purpose : callback when we received a complete teleinfo frame +Input : linked list pointer on the concerned data +Output : - +Comments: it's called only if one data in the frame is different than + the previous frame +====================================================================== */ +void UpdatedFrame(ValueList * me) +{ + char buff[32]; + + // Light the RGB LED (purple) + if ( config.config & CFG_RGB_LED) { + LedRGBON(COLOR_MAGENTA); + + // led off after delay + rgb_ticker.once_ms(BLINK_LED_MS, LedOff, RGB_LED_PIN); + } + + sprintf_P( buff, PSTR("Updated Frame (%ld Bytes free)"), ESP.getFreeHeap() ); + Debugln(buff); + +/* + // Got at least one ? + if (me) { + WiFiUDP myudp; + IPAddress ip = WiFi.localIP(); + + // start UDP server + myudp.begin(1201); + ip[3] = 255; + + // transmit broadcast package + myudp.beginPacket(ip, 1201); + + // start of frame + myudp.write(TINFO_STX); + + // Loop thru the node + while (me->next) { + me = me->next; + // prepare line and write it + sprintf_P( buff, PSTR("%s %s %c\n"),me->name, me->value, me->checksum ); + myudp.write( buff); + } + + // End of frame + myudp.write(TINFO_ETX); + myudp.endPacket(); + myudp.flush(); + + } +*/ +} + + +/* ====================================================================== +Function: ResetConfig +Purpose : Set configuration to default values +Input : - +Output : - +Comments: - +====================================================================== */ +void ResetConfig(void) +{ + // enable default configuration + memset(&config, 0, sizeof(_Config)); + + // Set default Hostname + sprintf_P(config.host, PSTR("WifInfo_%06X"), ESP.getChipId()); + strcpy_P(config.ota_auth, PSTR(DEFAULT_OTA_AUTH)); + config.ota_port = DEFAULT_OTA_PORT ; + + // Add other init default config here + + // Emoncms + strcpy_P(config.emoncms.host, CFG_EMON_DEFAULT_HOST); + config.emoncms.port = CFG_EMON_DEFAULT_PORT; + strcpy_P(config.emoncms.url, CFG_EMON_DEFAULT_URL); + config.emoncms.apikey[0] = '\0'; + config.emoncms.node = 0; + config.emoncms.freq = 0; + + // Jeedom + strcpy_P(config.jeedom.host, CFG_JDOM_DEFAULT_HOST); + config.jeedom.port = CFG_JDOM_DEFAULT_PORT; + strcpy_P(config.jeedom.url, CFG_JDOM_DEFAULT_URL); + strcpy_P(config.jeedom.adco, CFG_JDOM_DEFAULT_ADCO); + config.jeedom.apikey[0] = '\0'; + config.jeedom.freq = 0; + + + config.config |= CFG_RGB_LED; + + // save back + saveConfig(); +} + +/* ====================================================================== +Function: WifiHandleConn +Purpose : Handle Wifi connection / reconnection and OTA updates +Input : setup true if we're called 1st Time from setup +Output : state of the wifi status +Comments: - +====================================================================== */ +int WifiHandleConn(boolean setup = false) +{ + int ret = WiFi.status(); + + if (setup) { + + DebuglnF("========== SDK Saved parameters Start"); + WiFi.printDiag(DEBUG_SERIAL); + DebuglnF("========== SDK Saved parameters End"); + Debugflush(); + + // no correct SSID + if (!*config.ssid) { + DebugF("no Wifi SSID in config, trying to get SDK ones..."); + + // Let's see of SDK one is okay + if ( WiFi.SSID() == "" ) { + DebuglnF("Not found may be blank chip!"); + } else { + *config.psk = '\0'; + + // Copy SDK SSID + strcpy(config.ssid, WiFi.SSID().c_str()); + + // Copy SDK password if any + if (WiFi.psk() != "") + strcpy(config.psk, WiFi.psk().c_str()); + + DebuglnF("found one!"); + + // save back new config + saveConfig(); + } + } + + // correct SSID + if (*config.ssid) { + uint8_t timeout ; + + DebugF("Connecting to: "); + Debug(config.ssid); + Debugflush(); + + // Do wa have a PSK ? + if (*config.psk) { + // protected network + Debug(F(" with key '")); + Debug(config.psk); + Debug(F("'...")); + Debugflush(); + WiFi.begin(config.ssid, config.psk); + } else { + // Open network + Debug(F("unsecure AP")); + Debugflush(); + WiFi.begin(config.ssid); + } + + timeout = 25; // 25 * 200 ms = 5 sec time out + // 200 ms loop + while ( ((ret = WiFi.status()) != WL_CONNECTED) && timeout ) + { + // Orange LED + LedRGBON(COLOR_ORANGE); + delay(50); + LedRGBOFF(); + delay(150); + --timeout; + } + } + + + // connected ? disable AP, client mode only + if (ret == WL_CONNECTED) + { + DebuglnF("connected!"); + WiFi.mode(WIFI_STA); + + DebugF("IP address : "); Debugln(WiFi.localIP()); + DebugF("MAC address : "); Debugln(WiFi.macAddress()); + + // not connected ? start AP + } else { + char ap_ssid[32]; + DebuglnF("Error!"); + Debugflush(); + + // SSID = hostname + strcpy(ap_ssid, config.host ); + DebugF("Switching to AP "); + Debugln(ap_ssid); + Debugflush(); + + // protected network + if (*config.ap_psk) { + DebugF(" with key '"); + Debug(config.ap_psk); + DebuglnF("'"); + WiFi.softAP(ap_ssid, config.ap_psk); + // Open network + } else { + DebuglnF(" with no password"); + WiFi.softAP(ap_ssid); + } + WiFi.mode(WIFI_AP_STA); + + DebugF("IP address : "); Debugln(WiFi.softAPIP()); + DebugF("MAC address : "); Debugln(WiFi.softAPmacAddress()); + } + + // Set OTA parameters + ArduinoOTA.setPort(config.ota_port); + ArduinoOTA.setHostname(config.host); + ArduinoOTA.setPassword(config.ota_auth); + ArduinoOTA.begin(); + + // just in case your sketch sucks, keep update OTA Available + // Trust me, when coding and testing it happens, this could save + // the need to connect FTDI to reflash + // Usefull just after 1st connexion when called from setup() before + // launching potentially buggy main() + for (uint8_t i=0; i<= 10; i++) { + LedRGBON(COLOR_MAGENTA); + delay(100); + LedRGBOFF(); + delay(200); + ArduinoOTA.handle(); + } + + } // if setup + + return WiFi.status(); +} + +/* ====================================================================== +Function: setup +Purpose : Setup I/O and other one time startup stuff +Input : - +Output : - +Comments: - +====================================================================== */ +void setup() +{ + char buff[32]; + boolean reset_config = true; + + // Set CPU speed to 160MHz + system_update_cpu_freq(160); + + //WiFi.disconnect(false); + + // Set WiFi to station mode and disconnect from an AP if it was previously connected + //WiFi.mode(WIFI_AP_STA); + //WiFi.disconnect(); + //delay(1000); + + // Init the RGB Led, and set it off + rgb_led.Begin(); + LedRGBOFF(); + + // Init the serial 1, Our Debug Serial TXD0 + // note this serial can only transmit, just + // enough for debugging purpose + DEBUG_SERIAL.begin(115200); + Debugln(F("\r\n\r\n==============")); + Debug(F("WifInfo V")); + Debugln(F(WIFINFO_VERSION)); + Debugln(); + Debugflush(); + + // Clear our global flags + config.config = 0; + + // Our configuration is stored into EEPROM + //EEPROM.begin(sizeof(_Config)); + EEPROM.begin(1024); + + DebugF("Config size="); Debug(sizeof(_Config)); + DebugF(" (emoncms="); Debug(sizeof(_emoncms)); + DebugF(" jeedom="); Debug(sizeof(_jeedom)); + Debugln(')'); + Debugflush(); + + // Check File system init + if (!SPIFFS.begin()) + { + // Serious problem + DebuglnF("SPIFFS Mount failed"); + } else { + + DebuglnF("SPIFFS Mount succesfull"); + + Dir dir = SPIFFS.openDir("/"); + while (dir.next()) { + String fileName = dir.fileName(); + size_t fileSize = dir.fileSize(); + Debugf("FS File: %s, size: %d\n", fileName.c_str(), fileSize); + } + DebuglnF(""); + } + + // Read Configuration from EEP + if (readConfig()) { + DebuglnF("Good CRC, not set!"); + } else { + // Reset Configuration + ResetConfig(); + + // save back + saveConfig(); + + // Indicate the error in global flags + config.config |= CFG_BAD_CRC; + + DebuglnF("Reset to default"); + } + + // We'll drive our onboard LED + // old TXD1, not used anymore, has been swapped + pinMode(RED_LED_PIN, OUTPUT); + LedRedOFF(); + + // start Wifi connect or soft AP + WifiHandleConn(true); + + // OTA callbacks + ArduinoOTA.onStart([]() { + LedRGBON(COLOR_MAGENTA); + DebuglnF("Update Started"); + ota_blink = true; + }); + + ArduinoOTA.onEnd([]() { + LedRGBOFF(); + DebuglnF("Update finished restarting"); + }); + + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + if (ota_blink) { + LedRGBON(COLOR_MAGENTA); + } else { + LedRGBOFF(); + } + ota_blink = !ota_blink; + //Serial.printf("Progress: %u%%\n", (progress / (total / 100))); + }); + + ArduinoOTA.onError([](ota_error_t error) { + LedRGBON(COLOR_RED); + Debugf("Update Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) DebuglnF("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) DebuglnF("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) DebuglnF("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) DebuglnF("Receive Failed"); + else if (error == OTA_END_ERROR) DebuglnF("End Failed"); + ESP.restart(); + }); + + // Update sysinfo variable and print them + UpdateSysinfo(true, true); + + server.on("/", handleRoot); + server.on("/config_form.json", handleFormConfig); + server.on("/json", sendJSON); + server.on("/tinfo.json", tinfoJSONTable); + server.on("/system.json", sysJSONTable); + server.on("/config.json", confJSONTable); + server.on("/spiffs.json", spiffsJSONTable); + server.on("/wifiscan.json", wifiScanJSON); + server.on("/factory_reset", handleFactoryReset); + server.on("/reset", handleReset); + + // handler for the hearbeat + server.on("/hb.htm", HTTP_GET, [&](){ + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(200, "text/html", R"(OK)"); + }); + + // handler for the /update form POST (once file upload finishes) + server.on("/update", HTTP_POST, + // handler once file upload finishes + [&]() { + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); + ESP.restart(); + }, + // handler for upload, get's the sketch bytes, + // and writes them through the Update object + [&]() { + HTTPUpload& upload = server.upload(); + + if(upload.status == UPLOAD_FILE_START) { + uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; + WiFiUDP::stopAll(); + Debugf("Update: %s\n", upload.filename.c_str()); + LedRGBON(COLOR_MAGENTA); + ota_blink = true; + + //start with max available size + if(!Update.begin(maxSketchSpace)) + Update.printError(Serial1); + + } else if(upload.status == UPLOAD_FILE_WRITE) { + if (ota_blink) { + LedRGBON(COLOR_MAGENTA); + } else { + LedRGBOFF(); + } + ota_blink = !ota_blink; + Debug("."); + if(Update.write(upload.buf, upload.currentSize) != upload.currentSize) + Update.printError(Serial1); + + } else if(upload.status == UPLOAD_FILE_END) { + //true to set the size to the current progress + if(Update.end(true)) + Debugf("Update Success: %u\nRebooting...\n", upload.totalSize); + else + Update.printError(Serial1); + + LedRGBOFF(); + + } else if(upload.status == UPLOAD_FILE_ABORTED) { + Update.end(); + LedRGBOFF(); + DebuglnF("Update was aborted"); + } + delay(0); + } + ); + + // All other not known + server.onNotFound(handleNotFound); + + // serves all SPIFFS Web file with 24hr max-age control + // to avoid multiple requests to ESP + server.serveStatic("/font", SPIFFS, "/font","max-age=86400"); + server.serveStatic("/js", SPIFFS, "/js" ,"max-age=86400"); + server.serveStatic("/css", SPIFFS, "/css" ,"max-age=86400"); + server.begin(); + + // Display configuration + showConfig(); + + Debugln(F("HTTP server started")); + + // Teleinfo is connected to RXD2 (GPIO13) to + // avoid conflict when flashing, this is why + // we swap RXD1/RXD1 to RXD2/TXD2 + // Note that TXD2 is not used teleinfo is receive only + #ifdef DEBUG_SERIAL1 + Serial.begin(1200, SERIAL_7E1); + Serial.swap(); + #endif + + // Init teleinfo + tinfo.init(); + + // Attach the callback we need + // set all as an example + tinfo.attachADPS(ADPSCallback); + tinfo.attachData(DataCallback); + tinfo.attachNewFrame(NewFrame); + tinfo.attachUpdatedFrame(UpdatedFrame); + + //webSocket.begin(); + //webSocket.onEvent(webSocketEvent); + + // Light off the RGB LED + LedRGBOFF(); + + // Update sysinfo every second + Every_1_Sec.attach(1, Task_1_Sec); + + // Emoncms Update if needed + if (config.emoncms.freq) + Tick_emoncms.attach(config.emoncms.freq, Task_emoncms); + + // Jeedom Update if needed + if (config.jeedom.freq) + Tick_jeedom.attach(config.jeedom.freq, Task_jeedom); +} + +/* ====================================================================== +Function: loop +Purpose : infinite loop main code +Input : - +Output : - +Comments: - +====================================================================== */ +void loop() +{ + char c; + + // Do all related network stuff + server.handleClient(); + ArduinoOTA.handle(); + + //webSocket.loop(); + + // Only once task per loop, let system do it own task + if (task_1_sec) { + UpdateSysinfo(false, false); + task_1_sec = false; + } else if (task_emoncms) { + emoncmsPost(); + task_emoncms=false; + } else if (task_jeedom) { + jeedomPost(); + task_jeedom=false; + } + + // Handle teleinfo serial + if ( Serial.available() ) { + // Read Serial and process to tinfo + c = Serial.read(); + //Serial1.print(c); + tinfo.process(c); + } + + //delay(10); +} + diff --git a/examples/ESP8266_WifInfo/config.cpp b/examples/Wifinfo/config.cpp similarity index 65% rename from examples/ESP8266_WifInfo/config.cpp rename to examples/Wifinfo/config.cpp index aec3c09..c8f1fa3 100644 --- a/examples/ESP8266_WifInfo/config.cpp +++ b/examples/Wifinfo/config.cpp @@ -58,11 +58,10 @@ void eepromDump(uint8_t bytesPerRow) Debugln(); // loop thru EEP address - for (i = 0; i <= sizeof(_Config); i++) { + for (i = 0; i < sizeof(_Config); i++) { // First byte of the row ? if (j==0) { // Display Address - Debug(buf); Debugf("%04X : ", i); } @@ -81,18 +80,18 @@ void eepromDump(uint8_t bytesPerRow) /* ====================================================================== Function: readConfig Purpose : fill config structure with data located into eeprom -Input : - +Input : true if we need to clear actual struc in case of error Output : true if config found and crc ok, false otherwise Comments: - ====================================================================== */ -bool readConfig (void) +bool readConfig (bool clear_on_error) { uint16_t crc = ~0; uint8_t * pconfig = (uint8_t *) &config ; uint8_t data ; // For whole size of config structure - for (uint8_t i = 0; i < sizeof(_Config); ++i) { + for (uint16_t i = 0; i < sizeof(_Config); ++i) { // read data data = EEPROM.read(i); @@ -105,8 +104,9 @@ bool readConfig (void) // CRC Error ? if (crc != 0) { - // Clear config - memset(&config, 0, sizeof( _Config )); + // Clear config if wanted + if (clear_on_error) + memset(&config, 0, sizeof( _Config )); return false; } @@ -125,6 +125,8 @@ bool saveConfig (void) uint8_t * pconfig ; bool ret_code; + //eepromDump(32); + // Init pointer pconfig = (uint8_t *) &config ; @@ -132,28 +134,32 @@ bool saveConfig (void) config.crc = ~0; // For whole size of config structure, pre-calculate CRC - for (uint8_t i = 0; i < sizeof (_Config) - 2; ++i) + for (uint16_t i = 0; i < sizeof (_Config) - 2; ++i) config.crc = crc16Update(config.crc, *pconfig++); // Re init pointer pconfig = (uint8_t *) &config ; - // For whole size of config structure, write to EEP - for (byte i = 0; i < sizeof(_Config); ++i) - EEPROM.write(i, *pconfig++); + // For whole size of config structure, write to EEP + for (uint16_t i = 0; i < sizeof(_Config); ++i) + EEPROM.write(i, *pconfig++); // Physically save EEPROM.commit(); - // Read Again to see if saved ok - ret_code = readConfig(); + // Read Again to see if saved ok, but do + // not clear if error this avoid clearing + // default config and breaks OTA + ret_code = readConfig(false); - Debug(F("Write config")); + Debug(F("Write config ")); if (ret_code) Debugln(F("OK!")); else Debugln(F("Error!")); + + //eepromDump(32); // return result return (ret_code); @@ -168,6 +174,32 @@ Comments: - ====================================================================== */ void showConfig() { - + DebuglnF("===== Wifi"); + DebugF("ssid :"); Debugln(config.ssid); + DebugF("psk :"); Debugln(config.psk); + DebugF("host :"); Debugln(config.host); + DebugF("ap_psk :"); Debugln(config.ap_psk); + DebugF("OTA auth :"); Debugln(config.ota_auth); + DebugF("OTA port :"); Debugln(config.ota_port); + DebugF("Config :"); + if (config.config & CFG_RGB_LED) DebugF(" RGB"); + if (config.config & CFG_DEBUG) DebugF(" DEBUG"); + if (config.config & CFG_LCD) DebugF(" LCD"); + + DebuglnF("\r\n===== Emoncms"); + DebugF("host :"); Debugln(config.emoncms.host); + DebugF("port :"); Debugln(config.emoncms.port); + DebugF("url :"); Debugln(config.emoncms.url); + DebugF("key :"); Debugln(config.emoncms.apikey); + DebugF("node :"); Debugln(config.emoncms.node); + DebugF("freq :"); Debugln(config.emoncms.freq); + + DebuglnF("\r\n===== Jeedom"); + DebugF("host :"); Debugln(config.jeedom.host); + DebugF("port :"); Debugln(config.jeedom.port); + DebugF("url :"); Debugln(config.jeedom.url); + DebugF("key :"); Debugln(config.jeedom.apikey); + DebugF("compteur :"); Debugln(config.jeedom.adco); + DebugF("freq :"); Debugln(config.jeedom.freq); } diff --git a/examples/Wifinfo/config.h b/examples/Wifinfo/config.h new file mode 100644 index 0000000..6f9b833 --- /dev/null +++ b/examples/Wifinfo/config.h @@ -0,0 +1,148 @@ +// ********************************************************************************** +// ESP8266 Teleinfo WEB Server configuration Include file +// ********************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this library but please abide with the CC-BY-SA license: +// Attribution-NonCommercial-ShareAlike 4.0 International License +// http://creativecommons.org/licenses/by-nc-sa/4.0/ +// +// For any explanation about teleinfo ou use , see my blog +// http://hallard.me/category/tinfo +// +// This program works with the Wifinfo board +// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2015-06-14 - First release +// +// All text above must be included in any redistribution. +// +// ********************************************************************************** +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +// Include main project include file +#include "Wifinfo.h" + +#define CFG_SSID_SIZE 32 +#define CFG_PSK_SIZE 64 +#define CFG_HOSTNAME_SIZE 16 + +#define CFG_EMON_HOST_SIZE 32 +#define CFG_EMON_APIKEY_SIZE 32 +#define CFG_EMON_URL_SIZE 32 +#define CFG_EMON_DEFAULT_PORT 80 +#define CFG_EMON_DEFAULT_HOST "emoncms.org" +#define CFG_EMON_DEFAULT_URL "/input/post.json" + +#define CFG_JDOM_HOST_SIZE 32 +#define CFG_JDOM_APIKEY_SIZE 32 +#define CFG_JDOM_URL_SIZE 64 +#define CFG_JDOM_ADCO_SIZE 12 +#define CFG_JDOM_DEFAULT_PORT 80 +#define CFG_JDOM_DEFAULT_HOST "jeedom.local" +#define CFG_JDOM_DEFAULT_URL "/jeedom/plugins/teleinfo/core/php/jeeTeleinfo.php" +#define CFG_JDOM_DEFAULT_ADCO "0000111122223333" + + +// Port pour l'OTA +#define DEFAULT_OTA_PORT 8266 +#define DEFAULT_OTA_AUTH "OTA_WifInfo" +//#define DEFAULT_OTA_AUTH "" + +// Bit definition for different configuration modes +#define CFG_LCD 0x0001 // Enable display +#define CFG_DEBUG 0x0002 // Enable serial debug +#define CFG_RGB_LED 0x0004 // Enable RGB LED +#define CFG_BAD_CRC 0x8000 // Bad CRC when reading configuration + +// Web Interface Configuration Form field names +#define CFG_FORM_SSID FPSTR("ssid") +#define CFG_FORM_PSK FPSTR("psk") +#define CFG_FORM_HOST FPSTR("host") +#define CFG_FORM_AP_PSK FPSTR("ap_psk") +#define CFG_FORM_OTA_AUTH FPSTR("ota_auth") +#define CFG_FORM_OTA_PORT FPSTR("ota_port") + +#define CFG_FORM_EMON_HOST FPSTR("emon_host") +#define CFG_FORM_EMON_PORT FPSTR("emon_port") +#define CFG_FORM_EMON_URL FPSTR("emon_url") +#define CFG_FORM_EMON_KEY FPSTR("emon_apikey") +#define CFG_FORM_EMON_NODE FPSTR("emon_node") +#define CFG_FORM_EMON_FREQ FPSTR("emon_freq") + +#define CFG_FORM_JDOM_HOST FPSTR("jdom_host") +#define CFG_FORM_JDOM_PORT FPSTR("jdom_port") +#define CFG_FORM_JDOM_URL FPSTR("jdom_url") +#define CFG_FORM_JDOM_KEY FPSTR("jdom_apikey") +#define CFG_FORM_JDOM_ADCO FPSTR("jdom_adco") +#define CFG_FORM_JDOM_FREQ FPSTR("jdom_freq") + +#define CFG_FORM_IP FPSTR("wifi_ip"); +#define CFG_FORM_GW FPSTR("wifi_gw"); +#define CFG_FORM_MSK FPSTR("wifi_msk"); + +#pragma pack(push) // push current alignment to stack +#pragma pack(1) // set alignment to 1 byte boundary + +// Config for emoncms +// 128 Bytes +typedef struct +{ + char host[CFG_EMON_HOST_SIZE+1]; // FQDN + char apikey[CFG_EMON_APIKEY_SIZE+1]; // Secret + char url[CFG_EMON_URL_SIZE+1]; // Post URL + uint8_t port; // Protocol port (HTTP/HTTPS) + uint8_t node; // optional node + uint32_t freq; // refresh rate + uint8_t filler[23]; // in case adding data in config avoiding loosing current conf by bad crc*/ +} _emoncms; + +// Config for jeedom +// 160 Bytes +typedef struct +{ + char host[CFG_JDOM_HOST_SIZE+1]; // FQDN + char apikey[CFG_JDOM_APIKEY_SIZE+1]; // Secret + char url[CFG_JDOM_URL_SIZE+1]; // Post URL + char adco[CFG_JDOM_ADCO_SIZE+1]; // Identifiant compteur + uint8_t port; // Protocol port (HTTP/HTTPS) + uint32_t freq; // refresh rate + uint8_t filler[11]; // in case adding data in config avoiding loosing current conf by bad crc*/ +} _jeedom; + +// Config saved into eeprom +// 1024 bytes total including CRC +typedef struct +{ + char ssid[CFG_SSID_SIZE+1]; // SSID + char psk[CFG_PSK_SIZE+1]; // Pre shared key + char host[CFG_HOSTNAME_SIZE+1]; // Hostname + char ap_psk[CFG_PSK_SIZE+1]; // Access Point Pre shared key + char ota_auth[CFG_PSK_SIZE+1]; // OTA Authentication password + uint32_t config; // Bit field register + uint16_t ota_port; // OTA port + uint8_t filler[131]; // in case adding data in config avoiding loosing current conf by bad crc + _emoncms emoncms; // Emoncms configuration + _jeedom jeedom; // jeedom configuration + uint8_t filler1[352]; // Another filler in case we need more + uint16_t crc; +} _Config; + + +// Exported variables/object instancied in main sketch +// =================================================== +extern _Config config; + +#pragma pack(pop) + +// Declared exported function from route.cpp +// =================================================== +bool readConfig(bool clear_on_error=true); +bool saveConfig(void); +void showConfig(void); + + +#endif + diff --git a/examples/Wifinfo/data/css/wifinfo.css.gz b/examples/Wifinfo/data/css/wifinfo.css.gz new file mode 100644 index 0000000..67b07b8 Binary files /dev/null and b/examples/Wifinfo/data/css/wifinfo.css.gz differ diff --git a/examples/Wifinfo/data/favicon.ico b/examples/Wifinfo/data/favicon.ico new file mode 100644 index 0000000..20da666 Binary files /dev/null and b/examples/Wifinfo/data/favicon.ico differ diff --git a/examples/Wifinfo/data/fonts/glyphicons.woff b/examples/Wifinfo/data/fonts/glyphicons.woff new file mode 100644 index 0000000..9e61285 Binary files /dev/null and b/examples/Wifinfo/data/fonts/glyphicons.woff differ diff --git a/examples/Wifinfo/data/fonts/glyphicons.woff2 b/examples/Wifinfo/data/fonts/glyphicons.woff2 new file mode 100644 index 0000000..64539b5 Binary files /dev/null and b/examples/Wifinfo/data/fonts/glyphicons.woff2 differ diff --git a/examples/Wifinfo/data/index.htm.gz b/examples/Wifinfo/data/index.htm.gz new file mode 100644 index 0000000..a42c9d7 Binary files /dev/null and b/examples/Wifinfo/data/index.htm.gz differ diff --git a/examples/Wifinfo/data/js/wifinfo.js.gz b/examples/Wifinfo/data/js/wifinfo.js.gz new file mode 100644 index 0000000..b975dcf Binary files /dev/null and b/examples/Wifinfo/data/js/wifinfo.js.gz differ diff --git a/examples/Wifinfo/webclient.cpp b/examples/Wifinfo/webclient.cpp new file mode 100644 index 0000000..10ec024 --- /dev/null +++ b/examples/Wifinfo/webclient.cpp @@ -0,0 +1,241 @@ +// ********************************************************************************** +// ESP8266 Teleinfo WEB Client, web server function +// ********************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this library but please abide with the CC-BY-SA license: +// Attribution-NonCommercial-ShareAlike 4.0 International License +// http://creativecommons.org/licenses/by-nc-sa/4.0/ +// +// For any explanation about teleinfo ou use, see my blog +// http://hallard.me/category/tinfo +// +// This program works with the Wifinfo board +// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2015-12-04 - First release +// +// All text above must be included in any redistribution. +// +// ********************************************************************************** + +#include "webclient.h" + +/* ====================================================================== +Function: httpPost +Purpose : Do a http post +Input : hostname + port + url +Output : true if received 200 OK +Comments: - +====================================================================== */ +boolean httpPost(char * host, uint16_t port, char * url) +{ + HTTPClient http; + bool ret = false; + + unsigned long start = millis(); + + // configure traged server and url + http.begin(host, port, url, port==443 ? true : false); + //http.begin("http://emoncms.org/input/post.json?node=20&apikey=2f13e4608d411d20354485f72747de7b&json={PAPP:100}"); + //http.begin("emoncms.org", 80, "/input/post.json?node=20&apikey=2f13e4608d411d20354485f72747de7b&json={}"); //HTTP + + Debugf("http%s://%s:%d%s => ", port==443?"s":"", host, port, url); + + // start connection and send HTTP header + int httpCode = http.GET(); + if(httpCode) { + // HTTP header has been send and Server response header has been handled + Debug(httpCode); + Debug(" "); + // file found at server + if(httpCode == 200) { + String payload = http.getString(); + Debug(payload); + ret = true; + } + } else { + DebugF("failed!"); + } + Debugf(" in %d ms\r\n",millis()-start); + return ret; +} + +/* ====================================================================== +Function: emoncmsPost +Purpose : Do a http post to emoncms +Input : +Output : true if post returned 200 OK +Comments: - +====================================================================== */ +boolean emoncmsPost(void) +{ + boolean ret = false; + + // Some basic checking + if (*config.emoncms.host) { + ValueList * me = tinfo.getList(); + // Got at least one ? + if (me && me->next) { + String url ; + boolean first_item; + + url = *config.emoncms.url ? config.emoncms.url : "/"; + url += "?"; + if (config.emoncms.node>0) { + url+= F("node="); + url+= String(config.emoncms.node); + url+= "&"; + } + + url += F("apikey=") ; + url += config.emoncms.apikey; + url += F("&json={") ; + + first_item = true; + + // Loop thru the node + while (me->next) { + // go to next node + me = me->next; + // First item do not add , separator + if (first_item) + first_item = false; + else + url += ","; + + url += me->name ; + url += ":" ; + + // EMONCMS ne sais traiter que des valeurs numériques, donc ici il faut faire une + // table de mappage, tout à fait arbitraire, mais c"est celle-ci dont je me sers + // depuis mes débuts avec la téléinfo + if (!strcmp(me->name, "OPTARIF")) { + // L'option tarifaire choisie (Groupe "OPTARIF") est codée sur 4 caractères alphanumériques + /* J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous + je mets le 4eme char à 0, trop de possibilités + BASE => Option Base. + HC.. => Option Heures Creuses. + EJP. => Option EJP. + BBRx => Option Tempo + */ + char * p = me->value; + + if (*p=='B'&&*(p+1)=='A'&&*(p+2)=='S') url += "1"; + else if (*p=='H'&&*(p+1)=='C'&&*(p+2)=='.') url += "2"; + else if (*p=='E'&&*(p+1)=='J'&&*(p+2)=='P') url += "3"; + else if (*p=='B'&&*(p+1)=='B'&&*(p+2)=='R') url += "4"; + else url +="0"; + } else if (!strcmp(me->name, "HHPHC")) { + // L'horaire heures pleines/heures creuses (Groupe "HHPHC") est codé par un caractère A à Y + // J'ai choisi de prendre son code ASCII + int code = *me->value; + url += String(code); + } else if (!strcmp(me->name, "PTEC")) { + // La période tarifaire en cours (Groupe "PTEC"), est codée sur 4 caractères + /* J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous + TH.. => Toutes les Heures. + HC.. => Heures Creuses. + HP.. => Heures Pleines. + HN.. => Heures Normales. + PM.. => Heures de Pointe Mobile. + HCJB => Heures Creuses Jours Bleus. + HCJW => Heures Creuses Jours Blancs (White). + HCJR => Heures Creuses Jours Rouges. + HPJB => Heures Pleines Jours Bleus. + HPJW => Heures Pleines Jours Blancs (White). + HPJR => Heures Pleines Jours Rouges. + */ + if (!strcmp(me->value, "TH..")) url += "1"; + else if (!strcmp(me->value, "HC..")) url += "2"; + else if (!strcmp(me->value, "HP..")) url += "3"; + else if (!strcmp(me->value, "HN..")) url += "4"; + else if (!strcmp(me->value, "PM..")) url += "5"; + else if (!strcmp(me->value, "HCJB")) url += "6"; + else if (!strcmp(me->value, "HCJW")) url += "7"; + else if (!strcmp(me->value, "HCJR")) url += "8"; + else if (!strcmp(me->value, "HPJB")) url += "9"; + else if (!strcmp(me->value, "HPJW")) url += "10"; + else if (!strcmp(me->value, "HPJR")) url += "11"; + else url +="0"; + } else { + url += me->value; + } + } // While me + + // Json end + url += "}"; + + ret = httpPost( config.emoncms.host, config.emoncms.port, (char *) url.c_str()) ; + } // if me + } // if host + return ret; +} + +/* ====================================================================== +Function: jeedomPost +Purpose : Do a http post to jeedom server +Input : +Output : true if post returned 200 OK +Comments: - +====================================================================== */ +boolean jeedomPost(void) +{ + boolean ret = false; + + // Some basic checking + if (*config.jeedom.host) { + ValueList * me = tinfo.getList(); + // Got at least one ? + if (me && me->next) { + String url ; + boolean skip_item; + + url = *config.jeedom.url ? config.jeedom.url : "/"; + url += "?"; + + // Config identifiant forcée ? + if (*config.jeedom.adco) { + url+= F("ADCO="); + url+= config.jeedom.adco; + url+= "&"; + } + + url += F("api=") ; + url += config.jeedom.apikey; + url += F("&") ; + + // Loop thru the node + while (me->next) { + // go to next node + me = me->next; + skip_item = false; + + // Si ADCO déjà renseigné, on le remet pas + if (!strcmp(me->name, "ADCO")) { + if (*config.jeedom.adco) + skip_item = true; + } + + // Si Item virtuel, on le met pas + if (*me->name =='_') + skip_item = true; + + // On doit ajouter l'item ? + if (!skip_item) { + url += me->name ; + url += "=" ; + url += me->value; + url += "&" ; + } + } // While me + + ret = httpPost( config.jeedom.host, config.jeedom.port, (char *) url.c_str()) ; + } // if me + } // if host + return ret; +} + diff --git a/examples/Wifinfo/webclient.h b/examples/Wifinfo/webclient.h new file mode 100644 index 0000000..7a42e0b --- /dev/null +++ b/examples/Wifinfo/webclient.h @@ -0,0 +1,38 @@ +// ********************************************************************************** +// ESP8266 Teleinfo WEB Client routing Include file +// ********************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this library but please abide with the CC-BY-SA license: +// Attribution-NonCommercial-ShareAlike 4.0 International License +// http://creativecommons.org/licenses/by-nc-sa/4.0/ +// +// For any explanation about teleinfo ou use , see my blog +// http://hallard.me/category/tinfo +// +// This program works with the Wifinfo board +// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2015-12-04 - First release +// +// All text above must be included in any redistribution. +// +// ********************************************************************************** + +#ifndef WEBCLIENT_H +#define WEBCLIENT_H + +// Include main project include file +#include "Wifinfo.h" + +// Exported variables/object instancied in main sketch +// =================================================== + +// declared exported function from route.cpp +// =================================================== +boolean httpPost(char * host, uint16_t port, char * url); +boolean emoncmsPost(void); +boolean jeedomPost(void); + +#endif diff --git a/examples/Wifinfo/webserver.cpp b/examples/Wifinfo/webserver.cpp new file mode 100644 index 0000000..984a09c --- /dev/null +++ b/examples/Wifinfo/webserver.cpp @@ -0,0 +1,812 @@ +// ********************************************************************************** +// ESP8266 Teleinfo WEB Server, route web function +// ********************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this library but please abide with the CC-BY-SA license: +// Attribution-NonCommercial-ShareAlike 4.0 International License +// http://creativecommons.org/licenses/by-nc-sa/4.0/ +// +// For any explanation about teleinfo ou use, see my blog +// http://hallard.me/category/tinfo +// +// This program works with the Wifinfo board +// see schematic here https://github.com/hallard/teleinfo/tree/master/Wifinfo +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2015-06-14 - First release +// +// All text above must be included in any redistribution. +// +// ********************************************************************************** + +// Include Arduino header +#include "webserver.h" + +// Optimize string space in flash, avoid duplication +const char FP_JSON_START[] PROGMEM = "{\r\n"; +const char FP_JSON_END[] PROGMEM = "\r\n}\r\n"; +const char FP_QCQ[] PROGMEM = "\":\""; +const char FP_QCNL[] PROGMEM = "\",\r\n\""; +const char FP_RESTART[] PROGMEM = "OK, Redémarrage en cours\r\n"; +const char FP_NL[] PROGMEM = "\r\n"; + +/* ====================================================================== +Function: formatSize +Purpose : format a asize to human readable format +Input : size +Output : formated string +Comments: - +====================================================================== */ +String formatSize(size_t bytes) +{ + if (bytes < 1024){ + return String(bytes) + F(" Byte"); + } else if(bytes < (1024 * 1024)){ + return String(bytes/1024.0) + F(" KB"); + } else if(bytes < (1024 * 1024 * 1024)){ + return String(bytes/1024.0/1024.0) + F(" MB"); + } else { + return String(bytes/1024.0/1024.0/1024.0) + F(" GB"); + } +} + +/* ====================================================================== +Function: getContentType +Purpose : return correct mime content type depending on file extension +Input : - +Output : Mime content type +Comments: - +====================================================================== */ +String getContentType(String filename) { + if(filename.endsWith(".htm")) return F("text/html"); + else if(filename.endsWith(".html")) return F("text/html"); + else if(filename.endsWith(".css")) return F("text/css"); + else if(filename.endsWith(".json")) return F("text/json"); + else if(filename.endsWith(".js")) return F("application/javascript"); + else if(filename.endsWith(".png")) return F("image/png"); + else if(filename.endsWith(".gif")) return F("image/gif"); + else if(filename.endsWith(".jpg")) return F("image/jpeg"); + else if(filename.endsWith(".ico")) return F("image/x-icon"); + else if(filename.endsWith(".xml")) return F("text/xml"); + else if(filename.endsWith(".pdf")) return F("application/x-pdf"); + else if(filename.endsWith(".zip")) return F("application/x-zip"); + else if(filename.endsWith(".gz")) return F("application/x-gzip"); + else if(filename.endsWith(".otf")) return F("application/x-font-opentype"); + else if(filename.endsWith(".eot")) return F("application/vnd.ms-fontobject"); + else if(filename.endsWith(".svg")) return F("image/svg+xml"); + else if(filename.endsWith(".woff")) return F("application/x-font-woff"); + else if(filename.endsWith(".woff2")) return F("application/x-font-woff2"); + else if(filename.endsWith(".ttf")) return F("application/x-font-ttf"); + return "text/plain"; +} + +/* ====================================================================== +Function: handleFileRead +Purpose : return content of a file stored on SPIFFS file system +Input : file path +Output : true if file found and sent +Comments: - +====================================================================== */ +bool handleFileRead(String path) { + if ( path.endsWith("/") ) + path += "index.htm"; + + String contentType = getContentType(path); + String pathWithGz = path + ".gz"; + + DebugF("handleFileRead "); + Debug(path); + + if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { + if( SPIFFS.exists(pathWithGz) ){ + path += ".gz"; + DebugF(".gz"); + } + + DebuglnF(" found on FS"); + + File file = SPIFFS.open(path, "r"); + size_t sent = server.streamFile(file, contentType); + file.close(); + return true; + } + + Debugln(""); + + server.send(404, "text/plain", "File Not Found"); + return false; +} + +/* ====================================================================== +Function: handleFormConfig +Purpose : handle main configuration page +Input : - +Output : - +Comments: - +====================================================================== */ +void handleFormConfig(void) +{ + String response=""; + int ret ; + + LedBluON(); + + // We validated config ? + if (server.hasArg("save")) + { + int itemp; + DebuglnF("===== Posted configuration"); + + // WifInfo + strncpy(config.ssid , server.arg("ssid").c_str(), CFG_SSID_SIZE ); + strncpy(config.psk , server.arg("psk").c_str(), CFG_PSK_SIZE ); + strncpy(config.host , server.arg("host").c_str(), CFG_HOSTNAME_SIZE ); + strncpy(config.ap_psk , server.arg("ap_psk").c_str(), CFG_PSK_SIZE ); + strncpy(config.ota_auth,server.arg("ota_auth").c_str(), CFG_PSK_SIZE ); + itemp = server.arg("ota_port").toInt(); + config.ota_port = (itemp>=0 && itemp<=65535) ? itemp : DEFAULT_OTA_PORT ; + + // Emoncms + strncpy(config.emoncms.host, server.arg("emon_host").c_str(), CFG_EMON_HOST_SIZE ); + strncpy(config.emoncms.url, server.arg("emon_url").c_str(), CFG_EMON_URL_SIZE ); + strncpy(config.emoncms.apikey, server.arg("emon_apikey").c_str(),CFG_EMON_APIKEY_SIZE ); + itemp = server.arg("emon_node").toInt(); + config.emoncms.node = (itemp>=0 && itemp<=255) ? itemp : 0 ; + itemp = server.arg("emon_port").toInt(); + config.emoncms.port = (itemp>=0 && itemp<=65535) ? itemp : CFG_EMON_DEFAULT_PORT ; + itemp = server.arg("emon_freq").toInt(); + if (itemp>0 && itemp<=86400){ + // Emoncms Update if needed + Tick_emoncms.detach(); + Tick_emoncms.attach(itemp, Task_emoncms); + } else { + itemp = 0 ; + } + config.emoncms.freq = itemp; + + // jeedom + strncpy(config.jeedom.host, server.arg("jdom_host").c_str(), CFG_JDOM_HOST_SIZE ); + strncpy(config.jeedom.url, server.arg("jdom_url").c_str(), CFG_JDOM_URL_SIZE ); + strncpy(config.jeedom.apikey, server.arg("jdom_apikey").c_str(),CFG_JDOM_APIKEY_SIZE ); + strncpy(config.jeedom.adco, server.arg("jdom_adco").c_str(),CFG_JDOM_ADCO_SIZE ); + itemp = server.arg("jdom_port").toInt(); + config.jeedom.port = (itemp>=0 && itemp<=65535) ? itemp : CFG_JDOM_DEFAULT_PORT ; + itemp = server.arg("jdom_freq").toInt(); + if (itemp>0 && itemp<=86400){ + // Emoncms Update if needed + Tick_jeedom.detach(); + Tick_jeedom.attach(itemp, Task_jeedom); + } else { + itemp = 0 ; + } + config.jeedom.freq = itemp; + + if ( saveConfig() ) { + ret = 200; + response = PSTR("OK"); + } else { + ret = 412; + response = PSTR("Unable to save configuration"); + } + + showConfig(); + } + else + { + ret = 400; + response = PSTR("Missing Form Field"); + } + + DebugF("Sending response "); + Debug(ret); + Debug(":"); + Debugln(response); + server.send ( ret, "text/plain", response); + LedBluOFF(); +} + +/* ====================================================================== +Function: handleRoot +Purpose : handle main page / +Input : - +Output : - +Comments: - +====================================================================== */ +void handleRoot(void) +{ + LedBluON(); + handleFileRead("/"); + LedBluOFF(); +} + +/* ====================================================================== +Function: formatNumberJSON +Purpose : check if data value is full number and send correct JSON format +Input : String where to add response + char * value to check +Output : - +Comments: 00150 => 150 + ADCO => "ADCO" + 1 => 1 +====================================================================== */ +void formatNumberJSON( String &response, char * value) +{ + // we have at least something ? + if (value && strlen(value)) + { + boolean isNumber = true; + uint8_t c; + char * p = value; + + // just to be sure + if (strlen(p)<=16) { + // check if value is number + while (*p && isNumber) { + if ( *p < '0' || *p > '9' ) + isNumber = false; + p++; + } + + // this will add "" on not number values + if (!isNumber) { + response += '\"' ; + response += value ; + response += F("\"") ; + } else { + // this will remove leading zero on numbers + p = value; + while (*p=='0' && *(p+1) ) + p++; + response += p ; + } + } else { + Debugln(F("formatNumberJSON error!")); + } + } +} + + +/* ====================================================================== +Function: tinfoJSONTable +Purpose : dump all teleinfo values in JSON table format for browser +Input : linked list pointer on the concerned data + true to dump all values, false for only modified ones +Output : - +Comments: - +====================================================================== */ +void tinfoJSONTable(void) +{ + ValueList * me = tinfo.getList(); + String response = ""; + + // Just to debug where we are + Debug(F("Serving /tinfo page...\r\n")); + + // Got at least one ? + if (me) { + uint8_t index=0; + + boolean first_item = true; + // Json start + response += F("[\r\n"); + + // Loop thru the node + while (me->next) { + + // we're there + ESP.wdtFeed(); + + // go to next node + me = me->next; + + // First item do not add , separator + if (first_item) + first_item = false; + else + response += F(",\r\n"); + +/* + Debug(F("(")) ; + Debug(++index) ; + Debug(F(") ")) ; + + if (me->name) Debug(me->name) ; + else Debug(F("NULL")) ; + + Debug(F("=")) ; + + if (me->value) Debug(me->value) ; + else Debug(F("NULL")) ; + + Debug(F(" '")) ; + Debug(me->checksum) ; + Debug(F("' ")); + + // Flags management + if ( me->flags) { + Debug(F("Flags:0x")); + Debugf("%02X => ", me->flags); + if ( me->flags & TINFO_FLAGS_EXIST) + Debug(F("Exist ")) ; + if ( me->flags & TINFO_FLAGS_UPDATED) + Debug(F("Updated ")) ; + if ( me->flags & TINFO_FLAGS_ADDED) + Debug(F("New ")) ; + } + + Debugln() ; +*/ + response += F("{\"na\":\""); + response += me->name ; + response += F("\", \"va\":\"") ; + response += me->value; + response += F("\", \"ck\":\"") ; + if (me->checksum == '"' || me->checksum == '\\' || me->checksum == '/') + response += '\\'; + response += (char) me->checksum; + response += F("\", \"fl\":"); + response += me->flags ; + response += '}' ; + + } + // Json end + response += F("\r\n]"); + + } else { + Debugln(F("sending 404...")); + server.send ( 404, "text/plain", "No data" ); + } + Debug(F("sending...")); + server.send ( 200, "text/json", response ); + Debugln(F("OK!")); +} + + + + + +/* ====================================================================== +Function: getSysJSONData +Purpose : Return JSON string containing system data +Input : Response String +Output : - +Comments: - +====================================================================== */ +void getSysJSONData(String & response) +{ + response = ""; + char buffer[32]; + int32_t adc = ( 1000 * analogRead(A0) / 1024 ); + + // Json start + response += F("[\r\n"); + + response += "{\"na\":\"Uptime\",\"va\":\""; + response += sysinfo.sys_uptime; + response += "\"},\r\n"; + + response += "{\"na\":\"WifInfo Version\",\"va\":\"" WIFINFO_VERSION "\"},\r\n"; + + response += "{\"na\":\"Compile le\",\"va\":\"" __DATE__ " " __TIME__ "\"},\r\n"; + + response += "{\"na\":\"SDK Version\",\"va\":\""; + response += system_get_sdk_version() ; + response += "\"},\r\n"; + + response += "{\"na\":\"Chip ID\",\"va\":\""; + sprintf_P(buffer, "0x%0X",system_get_chip_id() ); + response += buffer ; + response += "\"},\r\n"; + + response += "{\"na\":\"Boot Version\",\"va\":\""; + sprintf_P(buffer, "0x%0X",system_get_boot_version() ); + response += buffer ; + response += "\"},\r\n"; + + response += "{\"na\":\"Flash Real Size\",\"va\":\""; + response += formatSize(ESP.getFlashChipRealSize()) ; + response += "\"},\r\n"; + + response += "{\"na\":\"Firmware Size\",\"va\":\""; + response += formatSize(ESP.getSketchSize()) ; + response += "\"},\r\n"; + + response += "{\"na\":\"Free Size\",\"va\":\""; + response += formatSize(ESP.getFreeSketchSpace()) ; + response += "\"},\r\n"; + + response += "{\"na\":\"Analog\",\"va\":\""; + adc = ( (1000 * analogRead(A0)) / 1024); + sprintf_P( buffer, PSTR("%d mV"), adc); + response += buffer ; + response += "\"},\r\n"; + + FSInfo info; + SPIFFS.info(info); + + response += "{\"na\":\"SPIFFS Total\",\"va\":\""; + response += formatSize(info.totalBytes) ; + response += "\"},\r\n"; + + response += "{\"na\":\"SPIFFS Used\",\"va\":\""; + response += formatSize(info.usedBytes) ; + response += "\"},\r\n"; + + response += "{\"na\":\"SPIFFS Occupation\",\"va\":\""; + sprintf_P(buffer, "%d%%",100*info.usedBytes/info.totalBytes); + response += buffer ; + response += "\"},\r\n"; + + // Free mem should be last one + response += "{\"na\":\"Free Ram\",\"va\":\""; + response += formatSize(system_get_free_heap_size()) ; + response += "\"}\r\n"; // Last don't have comma at end + + // Json end + response += F("]\r\n"); +} + +/* ====================================================================== +Function: sysJSONTable +Purpose : dump all sysinfo values in JSON table format for browser +Input : - +Output : - +Comments: - +====================================================================== */ +void sysJSONTable() +{ + String response = ""; + + getSysJSONData(response); + + // Just to debug where we are + Debug(F("Serving /system page...")); + server.send ( 200, "text/json", response ); + Debugln(F("Ok!")); +} + + + +/* ====================================================================== +Function: getConfigJSONData +Purpose : Return JSON string containing configuration data +Input : Response String +Output : - +Comments: - +====================================================================== */ +void getConfJSONData(String & r) +{ + // Json start + r = FPSTR(FP_JSON_START); + + r+="\""; + r+=CFG_FORM_SSID; r+=FPSTR(FP_QCQ); r+=config.ssid; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_PSK; r+=FPSTR(FP_QCQ); r+=config.psk; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_HOST; r+=FPSTR(FP_QCQ); r+=config.host; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_AP_PSK; r+=FPSTR(FP_QCQ); r+=config.ap_psk; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_EMON_HOST; r+=FPSTR(FP_QCQ); r+=config.emoncms.host; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_EMON_PORT; r+=FPSTR(FP_QCQ); r+=config.emoncms.port; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_EMON_URL; r+=FPSTR(FP_QCQ); r+=config.emoncms.url; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_EMON_KEY; r+=FPSTR(FP_QCQ); r+=config.emoncms.apikey; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_EMON_NODE; r+=FPSTR(FP_QCQ); r+=config.emoncms.node; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_EMON_FREQ; r+=FPSTR(FP_QCQ); r+=config.emoncms.freq; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_OTA_AUTH; r+=FPSTR(FP_QCQ); r+=config.ota_auth; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_OTA_PORT; r+=FPSTR(FP_QCQ); r+=config.ota_port; r+= FPSTR(FP_QCNL); + + r+=CFG_FORM_JDOM_HOST; r+=FPSTR(FP_QCQ); r+=config.jeedom.host; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_JDOM_PORT; r+=FPSTR(FP_QCQ); r+=config.jeedom.port; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_JDOM_URL; r+=FPSTR(FP_QCQ); r+=config.jeedom.url; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_JDOM_KEY; r+=FPSTR(FP_QCQ); r+=config.jeedom.apikey; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_JDOM_ADCO; r+=FPSTR(FP_QCQ); r+=config.jeedom.adco; r+= FPSTR(FP_QCNL); + r+=CFG_FORM_JDOM_FREQ; r+=FPSTR(FP_QCQ); r+=config.jeedom.freq; + + r+= F("\""); + // Json end + r += FPSTR(FP_JSON_END); + +} + +/* ====================================================================== +Function: confJSONTable +Purpose : dump all config values in JSON table format for browser +Input : - +Output : - +Comments: - +====================================================================== */ +void confJSONTable() +{ + String response = ""; + getConfJSONData(response); + // Just to debug where we are + Debug(F("Serving /config page...")); + server.send ( 200, "text/json", response ); + Debugln(F("Ok!")); +} + +/* ====================================================================== +Function: getSpiffsJSONData +Purpose : Return JSON string containing list of SPIFFS files +Input : Response String +Output : - +Comments: - +====================================================================== */ +void getSpiffsJSONData(String & response) +{ + char buffer[32]; + bool first_item = true; + + // Json start + response = FPSTR(FP_JSON_START); + + // Files Array + response += F("\"files\":[\r\n"); + + // Loop trough all files + Dir dir = SPIFFS.openDir("/"); + while (dir.next()) { + String fileName = dir.fileName(); + size_t fileSize = dir.fileSize(); + if (first_item) + first_item=false; + else + response += ","; + + response += F("{\"na\":\""); + response += fileName.c_str(); + response += F("\",\"va\":\""); + response += fileSize; + response += F("\"}\r\n"); + } + response += F("],\r\n"); + + + // SPIFFS File system array + response += F("\"spiffs\":[\r\n{"); + + // Get SPIFFS File system informations + FSInfo info; + SPIFFS.info(info); + response += F("\"Total\":"); + response += info.totalBytes ; + response += F(", \"Used\":"); + response += info.usedBytes ; + response += F(", \"ram\":"); + response += system_get_free_heap_size() ; + response += F("}\r\n]"); + + // Json end + response += FPSTR(FP_JSON_END); +} + +/* ====================================================================== +Function: spiffsJSONTable +Purpose : dump all spiffs system in JSON table format for browser +Input : - +Output : - +Comments: - +====================================================================== */ +void spiffsJSONTable() +{ + String response = ""; + getSpiffsJSONData(response); + server.send ( 200, "text/json", response ); +} + +/* ====================================================================== +Function: sendJSON +Purpose : dump all values in JSON +Input : linked list pointer on the concerned data + true to dump all values, false for only modified ones +Output : - +Comments: - +====================================================================== */ +void sendJSON(void) +{ + ValueList * me = tinfo.getList(); + String response = ""; + + // Got at least one ? + if (me) { + // Json start + response += FPSTR(FP_JSON_START); + response += F("\"_UPTIME\":"); + response += seconds; + + // Loop thru the node + while (me->next) { + // go to next node + me = me->next; + response += F(",\"") ; + response += me->name ; + response += F("\":") ; + formatNumberJSON(response, me->value); + } + // Json end + response += FPSTR(FP_JSON_END) ; + + } else { + server.send ( 404, "text/plain", "No data" ); + } + server.send ( 200, "text/json", response ); +} + + +/* ====================================================================== +Function: wifiScanJSON +Purpose : scan Wifi Access Point and return JSON code +Input : - +Output : - +Comments: - +====================================================================== */ +void wifiScanJSON(void) +{ + String response = ""; + bool first = true; + + // Just to debug where we are + Debug(F("Serving /wifiscan page...")); + + int n = WiFi.scanNetworks(); + + // Json start + response += F("[\r\n"); + + for (uint8_t i = 0; i < n; ++i) + { + int8_t rssi = WiFi.RSSI(i); + + uint8_t percent; + + // dBm to Quality + if(rssi<=-100) percent = 0; + else if (rssi>=-50) percent = 100; + else percent = 2 * (rssi + 100); + + if (first) + first = false; + else + response += F(","); + + response += F("{\"ssid\":\""); + response += WiFi.SSID(i); + response += F("\",\"rssi\":") ; + response += rssi; + response += FPSTR(FP_JSON_END); + } + + // Json end + response += FPSTR("]\r\n"); + + Debug(F("sending...")); + server.send ( 200, "text/json", response ); + Debugln(F("Ok!")); +} + + +/* ====================================================================== +Function: handleFactoryReset +Purpose : reset the module to factory settingd +Input : - +Output : - +Comments: - +====================================================================== */ +void handleFactoryReset(void) +{ + // Just to debug where we are + Debug(F("Serving /factory_reset page...")); + ResetConfig(); + ESP.eraseConfig(); + Debug(F("sending...")); + server.send ( 200, "text/plain", FPSTR(FP_RESTART) ); + Debugln(F("Ok!")); + delay(1000); + ESP.restart(); + while (true) + delay(1); +} + +/* ====================================================================== +Function: handleReset +Purpose : reset the module +Input : - +Output : - +Comments: - +====================================================================== */ +void handleReset(void) +{ + // Just to debug where we are + Debug(F("Serving /reset page...")); + Debug(F("sending...")); + server.send ( 200, "text/plain", FPSTR(FP_RESTART) ); + Debugln(F("Ok!")); + delay(1000); + ESP.restart(); + while (true) + delay(1); + +} + + +/* ====================================================================== +Function: handleNotFound +Purpose : default WEB routing when URI is not found +Input : - +Output : - +Comments: - +====================================================================== */ +void handleNotFound(void) +{ + String response = ""; + boolean found = false; + + // Led on + LedBluON(); + + // try to return SPIFFS file + found = handleFileRead(server.uri()); + + // Try Teleinfo ETIQUETTE + if (!found) { + // We check for an known label + ValueList * me = tinfo.getList(); + const char * uri; + // convert uri to char * for compare + uri = server.uri().c_str(); + + Debugf("handleNotFound(%s)\r\n", uri); + + // Got at least one and consistent URI ? + if (me && uri && *uri=='/' && *++uri ) { + + // Loop thru the linked list of values + while (me->next && !found) { + + // go to next node + me = me->next; + + //Debugf("compare to '%s' ", me->name); + // Do we have this one ? + if (stricmp (me->name, uri) == 0 ) + { + // no need to continue + found = true; + + // Add to respone + response += F("{\"") ; + response += me->name ; + response += F("\":") ; + formatNumberJSON(response, me->value); + response += F("}\r\n"); + } + } + } + + // Got it, send json + if (found) + server.send ( 200, "text/json", response ); + } + + // All trys failed + if (!found) { + // send error message in plain text + String message = F("File Not Found\n\n"); + message += F("URI: "); + message += server.uri(); + message += F("\nMethod: "); + message += ( server.method() == HTTP_GET ) ? "GET" : "POST"; + message += F("\nArguments: "); + message += server.args(); + message += FPSTR(FP_NL); + + for ( uint8_t i = 0; i < server.args(); i++ ) { + message += " " + server.argName ( i ) + ": " + server.arg ( i ) + FPSTR(FP_NL); + } + + server.send ( 404, "text/plain", message ); + } + + // Led off + LedBluOFF(); +} + diff --git a/examples/ESP8266_WifInfo/route.h b/examples/Wifinfo/webserver.h similarity index 81% rename from examples/ESP8266_WifInfo/route.h rename to examples/Wifinfo/webserver.h index 015ca66..81326b7 100644 --- a/examples/ESP8266_WifInfo/route.h +++ b/examples/Wifinfo/webserver.h @@ -20,11 +20,11 @@ // // ********************************************************************************** -#ifndef ROUTE_H -#define ROUTE_H +#ifndef WEBSERVER_H +#define WEBSERVER_H // Include main project include file -#include "ESP8266_WifInfo.h" +#include "Wifinfo.h" // Web response max size #define RESPONSE_BUFFER_SIZE 4096 @@ -38,10 +38,18 @@ extern uint16_t response_idx; // =================================================== void handleTest(void); void handleRoot(void); +void handleFormConfig(void) ; void handleNotFound(void); void tinfoJSONTable(void); +void getSysJSONData(String & r); void sysJSONTable(void); +void getConfJSONData(String & r); +void confJSONTable(void); +void getSpiffsJSONData(String & r); +void spiffsJSONTable(void); void sendJSON(void); - +void wifiScanJSON(void); +void handleFactoryReset(void); +void handleReset(void); #endif