V1.0.0 Release Candidate
Implémentation OTA Web serveur sur le système de fichier SPIFFS Interface Utilisateur pour la Configuration
This commit is contained in:
parent
0f73e251b0
commit
c11caa31a1
|
@ -7,6 +7,10 @@ Desktop.ini
|
||||||
|
|
||||||
# Recycle Bin used on file shares
|
# Recycle Bin used on file shares
|
||||||
$RECYCLE.BIN/
|
$RECYCLE.BIN/
|
||||||
|
node_modules/
|
||||||
|
bootstrap-3.3.5-dist/
|
||||||
|
font-awesome-4.5.0/
|
||||||
|
webdev/
|
||||||
|
|
||||||
# Windows Installer files
|
# Windows Installer files
|
||||||
*.cab
|
*.cab
|
||||||
|
|
|
@ -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 <Arduino.h>
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESP8266WebServer.h>
|
|
||||||
#include <ESP8266mDNS.h>
|
|
||||||
#include <WiFiUDP.h>
|
|
||||||
#include <EEPROM.h>
|
|
||||||
#include <Ticker.h>
|
|
||||||
//#include <WebSocketsServer.h>
|
|
||||||
//#include <Hash.h>
|
|
||||||
#include <NeoPixelBus.h>
|
|
||||||
#include <LibTeleinfo.h>
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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("<html><head>"
|
|
||||||
"<meta name='viewport' content='width=device-width, initial-scale=1'>"
|
|
||||||
"<meta charset='UTF-8'>"
|
|
||||||
"<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css'>"
|
|
||||||
"<link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.8.1/bootstrap-table.min.css'>"
|
|
||||||
// Our custom style
|
|
||||||
"<style type='text/css'>"
|
|
||||||
".nav-tabs {margin-top:4px;}"
|
|
||||||
".fixed-table-body {height:auto;}"
|
|
||||||
".progress {position:relative;}"
|
|
||||||
".progress span {position:absolute;display:block;width:100%;color:black;}"
|
|
||||||
"</style>"
|
|
||||||
"<script src='http://code.jquery.com/jquery-2.1.3.min.js'></script>"
|
|
||||||
"<script src='http://cdn.rawgit.com/Foliotek/AjaxQ/master/ajaxq.js'></script>"
|
|
||||||
"<title>Wifinfo</title>"
|
|
||||||
"</head><body>");
|
|
||||||
|
|
||||||
response += F("<div class='container'>"
|
|
||||||
// Onglets
|
|
||||||
"<ul class='nav nav-tabs' id='myTab'>"
|
|
||||||
"<li class='active'>"
|
|
||||||
"<a href='#tab_tinfo' data-toggle='tab'>"
|
|
||||||
"Téléinformation <span class='badge' id='scharge'></span>"
|
|
||||||
"</a>"
|
|
||||||
"</li>"
|
|
||||||
"<li><a href='#tab_sys' data-toggle='tab'>Système</a></li>"
|
|
||||||
"<li><a href='#tab_cfg' data-toggle='tab'>Configuration</a></li>"
|
|
||||||
"</ul>");
|
|
||||||
|
|
||||||
// Contenu des onglets
|
|
||||||
response += F("<div class='tab-content'>");
|
|
||||||
|
|
||||||
// tab teleinfo
|
|
||||||
response += F( "<div class='tab-pane fade in active' id='tab_tinfo'>"
|
|
||||||
"<h4>Données de Téléinformation</h4>"
|
|
||||||
"<div><span style='float:left;width:18ex;text-align:center;'>Charge courante : </span>"
|
|
||||||
"<div class='progress'>"
|
|
||||||
"<div class='progress-bar progress-bar-success' style='width:0' id='pbar'>"
|
|
||||||
"<span class=show id='pcharge'>Attente des données</span>"
|
|
||||||
"</div></div></div>"
|
|
||||||
"<div id='toolbar'>"
|
|
||||||
"</div>"
|
|
||||||
"<table data-toggle='table' "
|
|
||||||
"data-toolbar='#toolbar'"
|
|
||||||
"data-url='/tinfojsontbl' "
|
|
||||||
"class='table table-striped' "
|
|
||||||
"data-show-refresh='true' "
|
|
||||||
"data-show-toggle='true' "
|
|
||||||
"data-show-columns='true' "
|
|
||||||
"data-search='true' "
|
|
||||||
"data-row-style='rowStyle' "
|
|
||||||
"id='tblinfo' "
|
|
||||||
"data-select-item-name='toolbar1'>"
|
|
||||||
"<thead>"
|
|
||||||
"<tr>"
|
|
||||||
"<th data-field='na' data-align='left' data-sortable='true' data-formatter='labelFormatter'>Etiquette</th>"
|
|
||||||
"<th data-field='va' data-align='left' data-sortable='true' data-formatter='valueFormatter'>Valeur</th>"
|
|
||||||
"<th data-field='ck' data-align='center'>Checksum</th>"
|
|
||||||
"<th data-field='fl' data-align='center' data-visible='false'>Flags</th>"
|
|
||||||
"</tr>"
|
|
||||||
"</thead>"
|
|
||||||
"</table>"
|
|
||||||
"</div>"); // tab pane
|
|
||||||
// tab Systeme
|
|
||||||
response += F( "<div class='tab-pane fade' id='tab_sys'>"
|
|
||||||
"<h4>Données du système</h4>"
|
|
||||||
"<table data-toggle='table' "
|
|
||||||
"data-url='/sysjsontbl' "
|
|
||||||
"class='table table-striped' "
|
|
||||||
"data-show-refresh='true' "
|
|
||||||
"data-show-toggle='true' "
|
|
||||||
"data-search='true' "
|
|
||||||
"id='tblsys' "
|
|
||||||
"data-select-item-name='toolbar2'>"
|
|
||||||
"<thead>"
|
|
||||||
"<tr>"
|
|
||||||
"<th data-field='na' data-align='left'>Donnée</th>"
|
|
||||||
"<th data-field='va' data-align='left'>Valeur</th>"
|
|
||||||
"</tr>"
|
|
||||||
"</thead>"
|
|
||||||
"</table>"
|
|
||||||
"</div>"); // tab pane
|
|
||||||
|
|
||||||
// tab Configuration
|
|
||||||
response += F( "<div class='tab-pane fade' id='tab_cfg'>"
|
|
||||||
"<h4>Configuration du module WifInfo</h4>"
|
|
||||||
"<p>Cette partie reste à faire, des volontaires motivés ?</p>"
|
|
||||||
"</div>"); // tab pane
|
|
||||||
|
|
||||||
response += F("</div>"); // tab content
|
|
||||||
|
|
||||||
/*
|
|
||||||
response += F("<script>$( document ).ready(function() {"));
|
|
||||||
response += F("$.getq('queue','/"));
|
|
||||||
response += F("Uptime"));
|
|
||||||
response += F("', function(data) { $('#"));
|
|
||||||
response += F("Uptime"));
|
|
||||||
response += F("').html(data."));
|
|
||||||
response += F("Uptime"));
|
|
||||||
response += F("); });"));
|
|
||||||
response += F("});</script>"));
|
|
||||||
*/
|
|
||||||
|
|
||||||
response += F("</div>\r\n"); // Container
|
|
||||||
response += F("<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js'></script>\r\n");
|
|
||||||
response += F("<script src='//cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.8.1/bootstrap-table.min.js'></script>\r\n");
|
|
||||||
response += F("<script src='//cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.8.1/locale/bootstrap-table-fr-FR.min.js'></script>\r\n");
|
|
||||||
|
|
||||||
response += F("<script>" "\r\n"
|
|
||||||
"var counters={};"
|
|
||||||
"var isousc, iinst;"
|
|
||||||
"function rowStyle(row, index){" "\r\n"
|
|
||||||
"var classes=['active','success','info','warning','danger'];" "\r\n"
|
|
||||||
"var flags=parseInt(row.fl,10);" "\r\n"
|
|
||||||
"if (flags&0x80){return{classes:classes[4]};}""\r\n"
|
|
||||||
"if (flags&0x02){return{classes:classes[3]};}""\r\n"
|
|
||||||
"if (flags&0x08){return{classes:classes[1]};}""\r\n"
|
|
||||||
"return {};""\r\n"
|
|
||||||
"}""\r\n"
|
|
||||||
"function labelFormatter(value, row){" "\r\n"
|
|
||||||
"var flags=parseInt(row.fl,10);" "\r\n"
|
|
||||||
"if (typeof counters[value]==='undefined') counters[value]=1;" "\r\n"
|
|
||||||
"if (flags&0x88) counters[value]++;" "\r\n"
|
|
||||||
"return value + ' <span class=\"badge\">'+counters[value]+'</span>';" "\r\n"
|
|
||||||
"}" "\r\n"
|
|
||||||
"function valueFormatter(value, row){" "\r\n"
|
|
||||||
"if (row.na==\"ISOUSC\")" "\r\n"
|
|
||||||
"isousc=parseInt(value);" "\r\n"
|
|
||||||
"else if (row.na==\"IINST\"){" "\r\n"
|
|
||||||
"var pb, pe, cl;" "\r\n"
|
|
||||||
"iinst=parseInt(value);" "\r\n"
|
|
||||||
"pe=parseInt(iinst*100/isousc);" "\r\n"
|
|
||||||
"if (isNaN(pe)) pe=0;" "\r\n"
|
|
||||||
"cl='success';" "\r\n"
|
|
||||||
"if (pe>70) cl ='info';" "\r\n"
|
|
||||||
"if (pe>80) cl ='warning';" "\r\n"
|
|
||||||
"if (pe>90) cl ='danger';" "\r\n"
|
|
||||||
"cl = 'progress-bar-' + cl;" "\r\n"
|
|
||||||
"if (pe>0) $('#scharge').text(pe+'%');" "\r\n"
|
|
||||||
"if (typeof isousc!='undefined')" "\r\n"
|
|
||||||
" $('#pcharge').text(iinst+'A / '+isousc+'A');" "\r\n"
|
|
||||||
"$('#pbar').attr('class','progress-bar '+cl);" "\r\n"
|
|
||||||
"$('#pbar').css('width', pe+'%');"" \r\n"
|
|
||||||
"}" "\r\n"
|
|
||||||
"return value;" "\r\n"
|
|
||||||
"}" "\r\n"
|
|
||||||
"</script>" "\r\n");
|
|
||||||
|
|
||||||
response += F("<script>" "\r\n"
|
|
||||||
"var myTimer;" "\r\n"
|
|
||||||
"function myRefresh(){" "\r\n"
|
|
||||||
"var id=$('.nav-tabs .active > a').attr('href');" "\r\n"
|
|
||||||
"if (id=='#tab_tinfo') id='#tblinfo';" "\r\n"
|
|
||||||
"if (id=='#tab_sys') id='#tblsys';" "\r\n"
|
|
||||||
#ifdef DEBUG
|
|
||||||
"console.log('Refreshing : '+id);" "\r\n"
|
|
||||||
#endif
|
|
||||||
"clearInterval(myTimer);" "\r\n"
|
|
||||||
"$('#tblinfo').bootstrapTable('refresh',{silent: true});" "\r\n"
|
|
||||||
"if (id=='#tblsys')" "\r\n"
|
|
||||||
"$(id).bootstrapTable('refresh',{silent: true});" "\r\n"
|
|
||||||
"}""\r\n"
|
|
||||||
|
|
||||||
"$(function () {" "\r\n"
|
|
||||||
"$('#tblinfo').on('load-success.bs.table', function (e, data) {" "\r\n"
|
|
||||||
#ifdef DEBUG
|
|
||||||
"console.log('Event: load-success.bs.table');" "\r\n"
|
|
||||||
#endif
|
|
||||||
"myTimer=setInterval(function(){myRefresh()},1000);" "\r\n"
|
|
||||||
"})" "\r\n"
|
|
||||||
".on('load-error.bs.table', function (e, status) {" "\r\n"
|
|
||||||
#ifdef DEBUG
|
|
||||||
"console.log('Event: load-error.bs.table');" "\r\n"
|
|
||||||
#endif
|
|
||||||
"myTimer=setInterval(function(){myRefresh()},5000);" "\r\n"
|
|
||||||
"})" "\r\n"
|
|
||||||
"});" "\r\n"
|
|
||||||
"</script>");
|
|
||||||
|
|
||||||
response += F("</body></html>\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();
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <ESP8266WebServer.h>
|
#include <ESP8266WebServer.h>
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
#include <ESP8266mDNS.h>
|
#include <ESP8266mDNS.h>
|
||||||
#include <WiFiUDP.h>
|
#include <WiFiUDP.h>
|
||||||
#include <EEPROM.h>
|
#include <EEPROM.h>
|
||||||
|
@ -34,23 +35,33 @@
|
||||||
//#include <Hash.h>
|
//#include <Hash.h>
|
||||||
#include <NeoPixelBus.h>
|
#include <NeoPixelBus.h>
|
||||||
#include <LibTeleinfo.h>
|
#include <LibTeleinfo.h>
|
||||||
|
#include <fs.h>
|
||||||
|
|
||||||
#include "route.h"
|
extern "C" {
|
||||||
|
#include "user_interface.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "webserver.h"
|
||||||
|
#include "webclient.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
#define DEBUG
|
#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
|
// I prefix debug macro to be sure to use specific for THIS library
|
||||||
// debugging, this should not interfere with main sketch or other
|
// debugging, this should not interfere with main sketch or other
|
||||||
// libraries
|
// libraries
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define Debug(x) Serial1.print(x)
|
#define Debug(x) DEBUG_SERIAL.print(x)
|
||||||
#define Debugln(x) Serial1.println(x)
|
#define Debugln(x) DEBUG_SERIAL.println(x)
|
||||||
#define DebugF(x) Serial1.print(F(x))
|
#define DebugF(x) DEBUG_SERIAL.print(F(x))
|
||||||
#define DebuglnF(x) Serial1.println(F(x))
|
#define DebuglnF(x) DEBUG_SERIAL.println(F(x))
|
||||||
#define Debugf(...) Serial1.printf(__VA_ARGS__)
|
#define Debugf(...) DEBUG_SERIAL.printf(__VA_ARGS__)
|
||||||
#define Debugflush Serial1.flush
|
#define Debugflush DEBUG_SERIAL.flush
|
||||||
#else
|
#else
|
||||||
#define Debug(x) {}
|
#define Debug(x) {}
|
||||||
#define Debugln(x) {}
|
#define Debugln(x) {}
|
||||||
|
@ -92,13 +103,6 @@
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
String sys_uptime;
|
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;
|
} _sysinfo;
|
||||||
|
|
||||||
// Exported variables/object instancied in main sketch
|
// Exported variables/object instancied in main sketch
|
||||||
|
@ -110,7 +114,15 @@ extern NeoPixelBus rgb_led ;
|
||||||
extern uint8_t rgb_brightness;
|
extern uint8_t rgb_brightness;
|
||||||
extern unsigned long seconds;
|
extern unsigned long seconds;
|
||||||
extern _sysinfo sysinfo;
|
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
|
#endif
|
||||||
|
|
|
@ -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 <Arduino.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
#include <ArduinoOTA.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#include <Ticker.h>
|
||||||
|
//#include <WebSocketsServer.h>
|
||||||
|
//#include <Hash.h>
|
||||||
|
#include <NeoPixelBus.h>
|
||||||
|
#include <LibTeleinfo.h>
|
||||||
|
#include <fs.h>
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
|
@ -58,11 +58,10 @@ void eepromDump(uint8_t bytesPerRow)
|
||||||
Debugln();
|
Debugln();
|
||||||
|
|
||||||
// loop thru EEP address
|
// loop thru EEP address
|
||||||
for (i = 0; i <= sizeof(_Config); i++) {
|
for (i = 0; i < sizeof(_Config); i++) {
|
||||||
// First byte of the row ?
|
// First byte of the row ?
|
||||||
if (j==0) {
|
if (j==0) {
|
||||||
// Display Address
|
// Display Address
|
||||||
Debug(buf);
|
|
||||||
Debugf("%04X : ", i);
|
Debugf("%04X : ", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,18 +80,18 @@ void eepromDump(uint8_t bytesPerRow)
|
||||||
/* ======================================================================
|
/* ======================================================================
|
||||||
Function: readConfig
|
Function: readConfig
|
||||||
Purpose : fill config structure with data located into eeprom
|
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
|
Output : true if config found and crc ok, false otherwise
|
||||||
Comments: -
|
Comments: -
|
||||||
====================================================================== */
|
====================================================================== */
|
||||||
bool readConfig (void)
|
bool readConfig (bool clear_on_error)
|
||||||
{
|
{
|
||||||
uint16_t crc = ~0;
|
uint16_t crc = ~0;
|
||||||
uint8_t * pconfig = (uint8_t *) &config ;
|
uint8_t * pconfig = (uint8_t *) &config ;
|
||||||
uint8_t data ;
|
uint8_t data ;
|
||||||
|
|
||||||
// For whole size of config structure
|
// 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
|
// read data
|
||||||
data = EEPROM.read(i);
|
data = EEPROM.read(i);
|
||||||
|
|
||||||
|
@ -105,8 +104,9 @@ bool readConfig (void)
|
||||||
|
|
||||||
// CRC Error ?
|
// CRC Error ?
|
||||||
if (crc != 0) {
|
if (crc != 0) {
|
||||||
// Clear config
|
// Clear config if wanted
|
||||||
memset(&config, 0, sizeof( _Config ));
|
if (clear_on_error)
|
||||||
|
memset(&config, 0, sizeof( _Config ));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +125,8 @@ bool saveConfig (void)
|
||||||
uint8_t * pconfig ;
|
uint8_t * pconfig ;
|
||||||
bool ret_code;
|
bool ret_code;
|
||||||
|
|
||||||
|
//eepromDump(32);
|
||||||
|
|
||||||
// Init pointer
|
// Init pointer
|
||||||
pconfig = (uint8_t *) &config ;
|
pconfig = (uint8_t *) &config ;
|
||||||
|
|
||||||
|
@ -132,28 +134,32 @@ bool saveConfig (void)
|
||||||
config.crc = ~0;
|
config.crc = ~0;
|
||||||
|
|
||||||
// For whole size of config structure, pre-calculate CRC
|
// 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++);
|
config.crc = crc16Update(config.crc, *pconfig++);
|
||||||
|
|
||||||
// Re init pointer
|
// Re init pointer
|
||||||
pconfig = (uint8_t *) &config ;
|
pconfig = (uint8_t *) &config ;
|
||||||
|
|
||||||
// For whole size of config structure, write to EEP
|
// For whole size of config structure, write to EEP
|
||||||
for (byte i = 0; i < sizeof(_Config); ++i)
|
for (uint16_t i = 0; i < sizeof(_Config); ++i)
|
||||||
EEPROM.write(i, *pconfig++);
|
EEPROM.write(i, *pconfig++);
|
||||||
|
|
||||||
// Physically save
|
// Physically save
|
||||||
EEPROM.commit();
|
EEPROM.commit();
|
||||||
|
|
||||||
// Read Again to see if saved ok
|
// Read Again to see if saved ok, but do
|
||||||
ret_code = readConfig();
|
// 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)
|
if (ret_code)
|
||||||
Debugln(F("OK!"));
|
Debugln(F("OK!"));
|
||||||
else
|
else
|
||||||
Debugln(F("Error!"));
|
Debugln(F("Error!"));
|
||||||
|
|
||||||
|
//eepromDump(32);
|
||||||
|
|
||||||
// return result
|
// return result
|
||||||
return (ret_code);
|
return (ret_code);
|
||||||
|
@ -168,6 +174,32 @@ Comments: -
|
||||||
====================================================================== */
|
====================================================================== */
|
||||||
void showConfig()
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -20,11 +20,11 @@
|
||||||
//
|
//
|
||||||
// **********************************************************************************
|
// **********************************************************************************
|
||||||
|
|
||||||
#ifndef ROUTE_H
|
#ifndef WEBSERVER_H
|
||||||
#define ROUTE_H
|
#define WEBSERVER_H
|
||||||
|
|
||||||
// Include main project include file
|
// Include main project include file
|
||||||
#include "ESP8266_WifInfo.h"
|
#include "Wifinfo.h"
|
||||||
|
|
||||||
// Web response max size
|
// Web response max size
|
||||||
#define RESPONSE_BUFFER_SIZE 4096
|
#define RESPONSE_BUFFER_SIZE 4096
|
||||||
|
@ -38,10 +38,18 @@ extern uint16_t response_idx;
|
||||||
// ===================================================
|
// ===================================================
|
||||||
void handleTest(void);
|
void handleTest(void);
|
||||||
void handleRoot(void);
|
void handleRoot(void);
|
||||||
|
void handleFormConfig(void) ;
|
||||||
void handleNotFound(void);
|
void handleNotFound(void);
|
||||||
void tinfoJSONTable(void);
|
void tinfoJSONTable(void);
|
||||||
|
void getSysJSONData(String & r);
|
||||||
void sysJSONTable(void);
|
void sysJSONTable(void);
|
||||||
|
void getConfJSONData(String & r);
|
||||||
|
void confJSONTable(void);
|
||||||
|
void getSpiffsJSONData(String & r);
|
||||||
|
void spiffsJSONTable(void);
|
||||||
void sendJSON(void);
|
void sendJSON(void);
|
||||||
|
void wifiScanJSON(void);
|
||||||
|
void handleFactoryReset(void);
|
||||||
|
void handleReset(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue