Browse Source

Merge branch 'dev' into embedis-get

fastled^2
Xose Pérez 6 years ago
committed by GitHub
parent
commit
b75933f5e6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1790 additions and 1292 deletions
  1. +1
    -1
      README.md
  2. +4
    -4
      code/eagle.flash.1m0m1s.ld
  3. +19
    -0
      code/eagle.flash.1m0m2s.ld
  4. +21
    -0
      code/eagle.flash.4m1m4s.ld
  5. +20
    -0
      code/eagle.flash.4m3m4e.ld
  6. +18
    -0
      code/eagle.flash.512k0m1s.ld
  7. +22
    -13
      code/espurna/button.ino
  8. +25
    -0
      code/espurna/config/defaults.h
  9. +6
    -4
      code/espurna/config/general.h
  10. +7
    -0
      code/espurna/config/prototypes.h
  11. +16
    -0
      code/espurna/config/types.h
  12. +1
    -1
      code/espurna/config/version.h
  13. BIN
      code/espurna/data/index.html.gz
  14. +26
    -26
      code/espurna/debug.ino
  15. +86
    -0
      code/espurna/eeprom.ino
  16. +4
    -1
      code/espurna/espurna.ino
  17. +6
    -2
      code/espurna/homeassistant.ino
  18. +30
    -28
      code/espurna/led.ino
  19. +10
    -10
      code/espurna/mqtt.ino
  20. +11
    -1
      code/espurna/ota.ino
  21. +7
    -6
      code/espurna/relay.ino
  22. +28
    -40
      code/espurna/settings.ino
  23. +604
    -602
      code/espurna/static/index.html.gz.h
  24. +4
    -6
      code/espurna/system.ino
  25. +1
    -1
      code/espurna/telnet.ino
  26. +48
    -11
      code/espurna/utils.ino
  27. +16
    -6
      code/espurna/web.ino
  28. +214
    -52
      code/espurna/wifi.ino
  29. +57
    -13
      code/espurna/ws.ino
  30. +21
    -10
      code/html/custom.js
  31. +457
    -454
      code/platformio.ini

+ 1
- 1
README.md View File

@ -3,7 +3,7 @@
ESPurna ("spark" in Catalan) is a custom firmware for ESP8285/ESP8266 based smart switches, lights and sensors. ESPurna ("spark" in Catalan) is a custom firmware for ESP8285/ESP8266 based smart switches, lights and sensors.
It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries. It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
[![version](https://img.shields.io/badge/version-1.12.7a-brightgreen.svg)](CHANGELOG.md)
[![version](https://img.shields.io/badge/version-1.13.0c-brightgreen.svg)](CHANGELOG.md)
[![branch](https://img.shields.io/badge/branch-dev-orange.svg)](https://github.org/xoseperez/espurna/tree/dev/) [![branch](https://img.shields.io/badge/branch-dev-orange.svg)](https://github.org/xoseperez/espurna/tree/dev/)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=dev)](https://travis-ci.org/xoseperez/espurna) [![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=dev)](https://travis-ci.org/xoseperez/espurna)
[![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/dev.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard) [![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/dev.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard)


code/esp8266.flash.1m0.ld → code/eagle.flash.1m0m1s.ld View File

@ -1,4 +1,4 @@
/* Flash Split for 1M chips, no SPIFFS */
/* Flash Split for 1M chips */
/* sketch 999KB */ /* sketch 999KB */
/* eeprom 20KB */ /* eeprom 20KB */
@ -12,7 +12,7 @@ MEMORY
PROVIDE ( _SPIFFS_start = 0x402FB000 ); PROVIDE ( _SPIFFS_start = 0x402FB000 );
PROVIDE ( _SPIFFS_end = 0x402FB000 ); PROVIDE ( _SPIFFS_end = 0x402FB000 );
PROVIDE ( _SPIFFS_page = 0 );
PROVIDE ( _SPIFFS_block = 0 );
PROVIDE ( _SPIFFS_page = 0x0 );
PROVIDE ( _SPIFFS_block = 0x0 );
INCLUDE "esp8266.flash.common.ld"
INCLUDE "../ld/eagle.app.v6.common.ld"

+ 19
- 0
code/eagle.flash.1m0m2s.ld View File

@ -0,0 +1,19 @@
/* Flash Split for 1M chips, no SPIFFS */
/* sketch 995KB */
/* eeprom 8KB */
/* reserved 16KB */
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40201010, len = 0xf8ff0
}
PROVIDE ( _SPIFFS_start = 0x402FA000 );
PROVIDE ( _SPIFFS_end = 0x402FA000 );
PROVIDE ( _SPIFFS_page = 0 );
PROVIDE ( _SPIFFS_block = 0 );
INCLUDE "../ld/eagle.app.v6.common.ld"

+ 21
- 0
code/eagle.flash.4m1m4s.ld View File

@ -0,0 +1,21 @@
/* Flash Split for 4M chips */
/* sketch 1019KB */
/* empty/ota? 2048KB */
/* spiffs 992KB */
/* eeprom 16KB */
/* reserved 16KB */
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40201010, len = 0xfeff0
}
PROVIDE ( _SPIFFS_start = 0x40500000 );
PROVIDE ( _SPIFFS_end = 0x405F8000 );
PROVIDE ( _SPIFFS_page = 0x100 );
PROVIDE ( _SPIFFS_block = 0x2000 );
INCLUDE "../ld/eagle.app.v6.common.ld"

+ 20
- 0
code/eagle.flash.4m3m4e.ld View File

@ -0,0 +1,20 @@
/* Flash Split for 4M chips */
/* sketch 1019KB */
/* spiffs 3040KB */
/* eeprom 16KB */
/* reserved 16KB */
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40201010, len = 0xfeff0
}
PROVIDE ( _SPIFFS_start = 0x40300000 );
PROVIDE ( _SPIFFS_end = 0x405F8000 );
PROVIDE ( _SPIFFS_page = 0x100 );
PROVIDE ( _SPIFFS_block = 0x2000 );
INCLUDE "../ld/eagle.app.v6.common.ld"

+ 18
- 0
code/eagle.flash.512k0m1s.ld View File

@ -0,0 +1,18 @@
/* Flash Split for 512K chips */
/* sketch 487KB */
/* eeprom 20KB */
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40201010, len = 0x79ff0
}
PROVIDE ( _SPIFFS_start = 0x4027B000 );
PROVIDE ( _SPIFFS_end = 0x4027B000 );
PROVIDE ( _SPIFFS_page = 0x0 );
PROVIDE ( _SPIFFS_block = 0x0 );
INCLUDE "../ld/eagle.app.v6.common.ld"

+ 22
- 13
code/espurna/button.ino View File

@ -60,16 +60,18 @@ unsigned char buttonAction(unsigned char id, unsigned char event) {
if (event == BUTTON_EVENT_DBLCLICK) return (actions >> 8) & 0x0F; if (event == BUTTON_EVENT_DBLCLICK) return (actions >> 8) & 0x0F;
if (event == BUTTON_EVENT_LNGCLICK) return (actions >> 12) & 0x0F; if (event == BUTTON_EVENT_LNGCLICK) return (actions >> 12) & 0x0F;
if (event == BUTTON_EVENT_LNGLNGCLICK) return (actions >> 16) & 0x0F; if (event == BUTTON_EVENT_LNGLNGCLICK) return (actions >> 16) & 0x0F;
if (event == BUTTON_EVENT_TRIPLECLICK) return (actions >> 20) & 0x0F;
return BUTTON_MODE_NONE; return BUTTON_MODE_NONE;
} }
unsigned long buttonStore(unsigned long pressed, unsigned long click, unsigned long dblclick, unsigned long lngclick, unsigned long lnglngclick) {
unsigned long buttonStore(unsigned long pressed, unsigned long click, unsigned long dblclick, unsigned long lngclick, unsigned long lnglngclick, unsigned long tripleclick) {
unsigned int value; unsigned int value;
value = pressed; value = pressed;
value += click << 4; value += click << 4;
value += dblclick << 8; value += dblclick << 8;
value += lngclick << 12; value += lngclick << 12;
value += lnglngclick << 16; value += lnglngclick << 16;
value += tripleclick << 20;
return value; return value;
} }
@ -77,12 +79,13 @@ uint8_t mapEvent(uint8_t event, uint8_t count, uint16_t length) {
if (event == EVENT_PRESSED) return BUTTON_EVENT_PRESSED; if (event == EVENT_PRESSED) return BUTTON_EVENT_PRESSED;
if (event == EVENT_CHANGED) return BUTTON_EVENT_CLICK; if (event == EVENT_CHANGED) return BUTTON_EVENT_CLICK;
if (event == EVENT_RELEASED) { if (event == EVENT_RELEASED) {
if (count == 1) {
if (1 == count) {
if (length > BUTTON_LNGLNGCLICK_DELAY) return BUTTON_EVENT_LNGLNGCLICK; if (length > BUTTON_LNGLNGCLICK_DELAY) return BUTTON_EVENT_LNGLNGCLICK;
if (length > BUTTON_LNGCLICK_DELAY) return BUTTON_EVENT_LNGCLICK; if (length > BUTTON_LNGCLICK_DELAY) return BUTTON_EVENT_LNGCLICK;
return BUTTON_EVENT_CLICK; return BUTTON_EVENT_CLICK;
} }
if (count == 2) return BUTTON_EVENT_DBLCLICK;
if (2 == count) return BUTTON_EVENT_DBLCLICK;
if (3 == count) return BUTTON_EVENT_TRIPLECLICK;
} }
return BUTTON_EVENT_NONE; return BUTTON_EVENT_NONE;
} }
@ -113,7 +116,13 @@ void buttonEvent(unsigned int id, unsigned char event) {
relayStatus(_buttons[id].relayID - 1, false); relayStatus(_buttons[id].relayID - 1, false);
} }
} }
if (action == BUTTON_MODE_AP) createAP();
if (action == BUTTON_MODE_AP) wifiStartAP();
#if defined(JUSTWIFI_ENABLE_WPS)
if (action == BUTTON_MODE_WPS) wifiStartWPS();
#endif // defined(JUSTWIFI_ENABLE_WPS)
#if defined(JUSTWIFI_ENABLE_SMARTCONFIG)
if (action == BUTTON_MODE_SMART_CONFIG) wifiStartSmartConfig();
#endif // defined(JUSTWIFI_ENABLE_SMARTCONFIG)
if (action == BUTTON_MODE_RESET) { if (action == BUTTON_MODE_RESET) {
deferredReset(100, CUSTOM_RESET_HARDWARE); deferredReset(100, CUSTOM_RESET_HARDWARE);
} }
@ -129,7 +138,7 @@ void buttonSetup() {
#ifdef ITEAD_SONOFF_DUAL #ifdef ITEAD_SONOFF_DUAL
unsigned int actions = buttonStore(BUTTON_MODE_NONE, BUTTON_MODE_TOGGLE, BUTTON_MODE_NONE, BUTTON_MODE_NONE, BUTTON_MODE_NONE);
unsigned int actions = buttonStore(BUTTON_MODE_NONE, BUTTON_MODE_TOGGLE, BUTTON_MODE_NONE, BUTTON_MODE_NONE, BUTTON_MODE_NONE, BUTTON_MODE_NONE);
_buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, 1}); _buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, 1});
_buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, 2}); _buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, 2});
_buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, BUTTON3_RELAY}); _buttons.push_back({new DebounceEvent(0, BUTTON_PUSHBUTTON), actions, BUTTON3_RELAY});
@ -140,49 +149,49 @@ void buttonSetup() {
#if BUTTON1_PIN != GPIO_NONE #if BUTTON1_PIN != GPIO_NONE
{ {
unsigned int actions = buttonStore(BUTTON1_PRESS, BUTTON1_CLICK, BUTTON1_DBLCLICK, BUTTON1_LNGCLICK, BUTTON1_LNGLNGCLICK);
unsigned int actions = buttonStore(BUTTON1_PRESS, BUTTON1_CLICK, BUTTON1_DBLCLICK, BUTTON1_LNGCLICK, BUTTON1_LNGLNGCLICK, BUTTON1_TRIPLECLICK);
_buttons.push_back({new DebounceEvent(BUTTON1_PIN, BUTTON1_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON1_RELAY}); _buttons.push_back({new DebounceEvent(BUTTON1_PIN, BUTTON1_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON1_RELAY});
} }
#endif #endif
#if BUTTON2_PIN != GPIO_NONE #if BUTTON2_PIN != GPIO_NONE
{ {
unsigned int actions = buttonStore(BUTTON2_PRESS, BUTTON2_CLICK, BUTTON2_DBLCLICK, BUTTON2_LNGCLICK, BUTTON2_LNGLNGCLICK);
unsigned int actions = buttonStore(BUTTON2_PRESS, BUTTON2_CLICK, BUTTON2_DBLCLICK, BUTTON2_LNGCLICK, BUTTON2_LNGLNGCLICK, BUTTON2_TRIPLECLICK);
_buttons.push_back({new DebounceEvent(BUTTON2_PIN, BUTTON2_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON2_RELAY}); _buttons.push_back({new DebounceEvent(BUTTON2_PIN, BUTTON2_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON2_RELAY});
} }
#endif #endif
#if BUTTON3_PIN != GPIO_NONE #if BUTTON3_PIN != GPIO_NONE
{ {
unsigned int actions = buttonStore(BUTTON3_PRESS, BUTTON3_CLICK, BUTTON3_DBLCLICK, BUTTON3_LNGCLICK, BUTTON3_LNGLNGCLICK);
unsigned int actions = buttonStore(BUTTON3_PRESS, BUTTON3_CLICK, BUTTON3_DBLCLICK, BUTTON3_LNGCLICK, BUTTON3_LNGLNGCLICK, BUTTON3_TRIPLECLICK);
_buttons.push_back({new DebounceEvent(BUTTON3_PIN, BUTTON3_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON3_RELAY}); _buttons.push_back({new DebounceEvent(BUTTON3_PIN, BUTTON3_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON3_RELAY});
} }
#endif #endif
#if BUTTON4_PIN != GPIO_NONE #if BUTTON4_PIN != GPIO_NONE
{ {
unsigned int actions = buttonStore(BUTTON4_PRESS, BUTTON4_CLICK, BUTTON4_DBLCLICK, BUTTON4_LNGCLICK, BUTTON4_LNGLNGCLICK);
unsigned int actions = buttonStore(BUTTON4_PRESS, BUTTON4_CLICK, BUTTON4_DBLCLICK, BUTTON4_LNGCLICK, BUTTON4_LNGLNGCLICK, BUTTON4_TRIPLECLICK);
_buttons.push_back({new DebounceEvent(BUTTON4_PIN, BUTTON4_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON4_RELAY}); _buttons.push_back({new DebounceEvent(BUTTON4_PIN, BUTTON4_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON4_RELAY});
} }
#endif #endif
#if BUTTON5_PIN != GPIO_NONE #if BUTTON5_PIN != GPIO_NONE
{ {
unsigned int actions = buttonStore(BUTTON5_PRESS, BUTTON5_CLICK, BUTTON5_DBLCLICK, BUTTON5_LNGCLICK, BUTTON5_LNGLNGCLICK);
unsigned int actions = buttonStore(BUTTON5_PRESS, BUTTON5_CLICK, BUTTON5_DBLCLICK, BUTTON5_LNGCLICK, BUTTON5_LNGLNGCLICK, BUTTON5_TRIPLECLICK);
_buttons.push_back({new DebounceEvent(BUTTON5_PIN, BUTTON5_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON5_RELAY}); _buttons.push_back({new DebounceEvent(BUTTON5_PIN, BUTTON5_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON5_RELAY});
} }
#endif #endif
#if BUTTON6_PIN != GPIO_NONE #if BUTTON6_PIN != GPIO_NONE
{ {
unsigned int actions = buttonStore(BUTTON6_PRESS, BUTTON6_CLICK, BUTTON6_DBLCLICK, BUTTON6_LNGCLICK, BUTTON6_LNGLNGCLICK);
unsigned int actions = buttonStore(BUTTON6_PRESS, BUTTON6_CLICK, BUTTON6_DBLCLICK, BUTTON6_LNGCLICK, BUTTON6_LNGLNGCLICK, BUTTON6_TRIPLECLICK);
_buttons.push_back({new DebounceEvent(BUTTON6_PIN, BUTTON6_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON6_RELAY}); _buttons.push_back({new DebounceEvent(BUTTON6_PIN, BUTTON6_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON6_RELAY});
} }
#endif #endif
#if BUTTON7_PIN != GPIO_NONE #if BUTTON7_PIN != GPIO_NONE
{ {
unsigned int actions = buttonStore(BUTTON7_PRESS, BUTTON7_CLICK, BUTTON7_DBLCLICK, BUTTON7_LNGCLICK, BUTTON7_LNGLNGCLICK);
unsigned int actions = buttonStore(BUTTON7_PRESS, BUTTON7_CLICK, BUTTON7_DBLCLICK, BUTTON7_LNGCLICK, BUTTON7_LNGLNGCLICK, BUTTON7_TRIPLECLICK);
_buttons.push_back({new DebounceEvent(BUTTON7_PIN, BUTTON7_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON7_RELAY}); _buttons.push_back({new DebounceEvent(BUTTON7_PIN, BUTTON7_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON7_RELAY});
} }
#endif #endif
#if BUTTON8_PIN != GPIO_NONE #if BUTTON8_PIN != GPIO_NONE
{ {
unsigned int actions = buttonStore(BUTTON8_PRESS, BUTTON8_CLICK, BUTTON8_DBLCLICK, BUTTON8_LNGCLICK, BUTTON8_LNGLNGCLICK);
unsigned int actions = buttonStore(BUTTON8_PRESS, BUTTON8_CLICK, BUTTON8_DBLCLICK, BUTTON8_LNGCLICK, BUTTON8_LNGLNGCLICK, BUTTON8_TRIPLECLICK);
_buttons.push_back({new DebounceEvent(BUTTON8_PIN, BUTTON8_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON8_RELAY}); _buttons.push_back({new DebounceEvent(BUTTON8_PIN, BUTTON8_MODE, BUTTON_DEBOUNCE_DELAY, btnDelay), actions, BUTTON8_RELAY});
} }
#endif #endif


+ 25
- 0
code/espurna/config/defaults.h View File

@ -108,6 +108,31 @@
#define BUTTON8_DBLCLICK BUTTON_MODE_NONE #define BUTTON8_DBLCLICK BUTTON_MODE_NONE
#endif #endif
#ifndef BUTTON1_TRIPLECLICK
#define BUTTON1_TRIPLECLICK BUTTON_MODE_SMART_CONFIG
#endif
#ifndef BUTTON2_TRIPLECLICK
#define BUTTON2_TRIPLECLICK BUTTON_MODE_NONE
#endif
#ifndef BUTTON3_TRIPLECLICK
#define BUTTON3_TRIPLECLICK BUTTON_MODE_NONE
#endif
#ifndef BUTTON4_TRIPLECLICK
#define BUTTON4_TRIPLECLICK BUTTON_MODE_NONE
#endif
#ifndef BUTTON5_TRIPLECLICK
#define BUTTON5_TRIPLECLICK BUTTON_MODE_NONE
#endif
#ifndef BUTTON6_TRIPLECLICK
#define BUTTON6_TRIPLECLICK BUTTON_MODE_NONE
#endif
#ifndef BUTTON7_TRIPLECLICK
#define BUTTON7_TRIPLECLICK BUTTON_MODE_NONE
#endif
#ifndef BUTTON8_TRIPLECLICK
#define BUTTON8_TRIPLECLICK BUTTON_MODE_NONE
#endif
#ifndef BUTTON1_LNGCLICK #ifndef BUTTON1_LNGCLICK
#define BUTTON1_LNGCLICK BUTTON_MODE_RESET #define BUTTON1_LNGCLICK BUTTON_MODE_RESET
#endif #endif


+ 6
- 4
code/espurna/config/general.h View File

@ -142,12 +142,17 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#define EEPROM_SIZE 4096 // EEPROM size in bytes #define EEPROM_SIZE 4096 // EEPROM size in bytes
//#define EEPROM_RORATE_SECTORS 2 // Number of sectors to use for EEPROM rotation
// If not defined the firmware will use a number based
// on the number of available sectors
#define EEPROM_RELAY_STATUS 0 // Address for the relay status (1 byte) #define EEPROM_RELAY_STATUS 0 // Address for the relay status (1 byte)
#define EEPROM_ENERGY_COUNT 1 // Address for the energy counter (4 bytes) #define EEPROM_ENERGY_COUNT 1 // Address for the energy counter (4 bytes)
#define EEPROM_CUSTOM_RESET 5 // Address for the reset reason (1 byte) #define EEPROM_CUSTOM_RESET 5 // Address for the reset reason (1 byte)
#define EEPROM_CRASH_COUNTER 6 // Address for the crash counter (1 byte) #define EEPROM_CRASH_COUNTER 6 // Address for the crash counter (1 byte)
#define EEPROM_MESSAGE_ID 7 // Address for the MQTT message id (4 bytes) #define EEPROM_MESSAGE_ID 7 // Address for the MQTT message id (4 bytes)
#define EEPROM_DATA_END 11 // End of custom EEPROM data block
#define EEPROM_ROTATE_DATA 11 // Reserved for the EEPROM_ROTATE library (3 bytes)
#define EEPROM_DATA_END 14 // End of custom EEPROM data block
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// HEARTBEAT // HEARTBEAT
@ -276,9 +281,6 @@
#define WIFI_AP_CAPTIVE 1 // Captive portal enabled when in AP mode #define WIFI_AP_CAPTIVE 1 // Captive portal enabled when in AP mode
#endif #endif
#ifndef WIFI_AP_MODE
#define WIFI_AP_MODE AP_MODE_ALONE
#endif
#ifndef WIFI_SLEEP_MODE #ifndef WIFI_SLEEP_MODE
#define WIFI_SLEEP_MODE WIFI_NONE_SLEEP // WIFI_NONE_SLEEP, WIFI_LIGHT_SLEEP or WIFI_MODEM_SLEEP #define WIFI_SLEEP_MODE WIFI_NONE_SLEEP // WIFI_NONE_SLEEP, WIFI_LIGHT_SLEEP or WIFI_MODEM_SLEEP


+ 7
- 0
code/espurna/config/prototypes.h View File

@ -7,6 +7,12 @@ extern "C" {
#include "user_interface.h" #include "user_interface.h"
} }
// -----------------------------------------------------------------------------
// EEPROM_ROTATE
// -----------------------------------------------------------------------------
#include <EEPROM_Rotate.h>
EEPROM_Rotate EEPROMr;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// WebServer // WebServer
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -67,6 +73,7 @@ void settingsGetJson(JsonObject& data);
bool settingsRestoreJson(JsonObject& data); bool settingsRestoreJson(JsonObject& data);
void settingsRegisterCommand(const String& name, void (*call)(Embedis*)); void settingsRegisterCommand(const String& name, void (*call)(Embedis*));
void settingsInject(void *data, size_t len); void settingsInject(void *data, size_t len);
Stream & settingsSerial();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// I2C // I2C


+ 16
- 0
code/espurna/config/types.h View File

@ -3,6 +3,19 @@
// Do not touch this definitions // Do not touch this definitions
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// WIFI
// -----------------------------------------------------------------------------
#define WIFI_STATE_AP 1
#define WIFI_STATE_STA 2
#define WIFI_STATE_AP_STA 3
#define WIFI_STATE_WPS 4
#define WIFI_STATE_SMARTCONFIG 8
#define WIFI_AP_ALLWAYS 1
#define WIFI_AP_FALLBACK 2
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// BUTTONS // BUTTONS
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -14,6 +27,7 @@
#define BUTTON_EVENT_DBLCLICK 3 #define BUTTON_EVENT_DBLCLICK 3
#define BUTTON_EVENT_LNGCLICK 4 #define BUTTON_EVENT_LNGCLICK 4
#define BUTTON_EVENT_LNGLNGCLICK 5 #define BUTTON_EVENT_LNGLNGCLICK 5
#define BUTTON_EVENT_TRIPLECLICK 6
#define BUTTON_MODE_NONE 0 #define BUTTON_MODE_NONE 0
#define BUTTON_MODE_TOGGLE 1 #define BUTTON_MODE_TOGGLE 1
@ -23,6 +37,8 @@
#define BUTTON_MODE_RESET 5 #define BUTTON_MODE_RESET 5
#define BUTTON_MODE_PULSE 6 #define BUTTON_MODE_PULSE 6
#define BUTTON_MODE_FACTORY 7 #define BUTTON_MODE_FACTORY 7
#define BUTTON_MODE_WPS 8
#define BUTTON_MODE_SMART_CONFIG 9
// Needed for ESP8285 boards under Windows using PlatformIO (?) // Needed for ESP8285 boards under Windows using PlatformIO (?)
#ifndef BUTTON_PUSHBUTTON #ifndef BUTTON_PUSHBUTTON


+ 1
- 1
code/espurna/config/version.h View File

@ -1,5 +1,5 @@
#define APP_NAME "ESPURNA" #define APP_NAME "ESPURNA"
#define APP_VERSION "1.12.7a"
#define APP_VERSION "1.13.0c"
#define APP_REVISION "db84006" #define APP_REVISION "db84006"
#define APP_AUTHOR "xose.perez@gmail.com" #define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat" #define APP_WEBSITE "http://tinkerman.cat"


BIN
code/espurna/data/index.html.gz View File


+ 26
- 26
code/espurna/debug.ino View File

@ -10,7 +10,7 @@ Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <EEPROM.h>
#include <EEPROM_Rotate.h>
extern "C" { extern "C" {
#include "user_interface.h" #include "user_interface.h"
@ -204,31 +204,31 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
// write crash time to EEPROM // write crash time to EEPROM
uint32_t crash_time = millis(); uint32_t crash_time = millis();
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
// write reset info to EEPROM // write reset info to EEPROM
EEPROM.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON, rst_info->reason);
EEPROM.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE, rst_info->exccause);
EEPROMr.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON, rst_info->reason);
EEPROMr.write(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE, rst_info->exccause);
// write epc1, epc2, epc3, excvaddr and depc to EEPROM // write epc1, epc2, epc3, excvaddr and depc to EEPROM
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, rst_info->epc1);
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, rst_info->epc2);
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, rst_info->epc3);
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, rst_info->excvaddr);
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, rst_info->depc);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, rst_info->epc1);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, rst_info->epc2);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, rst_info->epc3);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, rst_info->excvaddr);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, rst_info->depc);
// write stack start and end address to EEPROM // write stack start and end address to EEPROM
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start);
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end);
// write stack trace to EEPROM // write stack trace to EEPROM
int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE; int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE;
for (uint32_t i = stack_start; i < stack_end; i++) { for (uint32_t i = stack_start; i < stack_end; i++) {
byte* byteValue = (byte*) i; byte* byteValue = (byte*) i;
EEPROM.write(current_address++, *byteValue);
EEPROMr.write(current_address++, *byteValue);
} }
EEPROM.commit();
EEPROMr.commit();
} }
@ -237,8 +237,8 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
*/ */
void debugClearCrashInfo() { void debugClearCrashInfo() {
uint32_t crash_time = 0xFFFFFFFF; uint32_t crash_time = 0xFFFFFFFF;
EEPROM.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
EEPROM.commit();
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
EEPROMr.commit();
} }
/** /**
@ -247,28 +247,28 @@ void debugClearCrashInfo() {
void debugDumpCrashInfo() { void debugDumpCrashInfo() {
uint32_t crash_time; uint32_t crash_time;
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time);
if ((crash_time == 0) || (crash_time == 0xFFFFFFFF)) { if ((crash_time == 0) || (crash_time == 0xFFFFFFFF)) {
DEBUG_MSG_P(PSTR("[DEBUG] No crash info\n")); DEBUG_MSG_P(PSTR("[DEBUG] No crash info\n"));
return; return;
} }
DEBUG_MSG_P(PSTR("[DEBUG] Latest crash was at %lu ms after boot\n"), crash_time); DEBUG_MSG_P(PSTR("[DEBUG] Latest crash was at %lu ms after boot\n"), crash_time);
DEBUG_MSG_P(PSTR("[DEBUG] Reason of restart: %u\n"), EEPROM.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON));
DEBUG_MSG_P(PSTR("[DEBUG] Exception cause: %u\n"), EEPROM.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE));
DEBUG_MSG_P(PSTR("[DEBUG] Reason of restart: %u\n"), EEPROMr.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_RESTART_REASON));
DEBUG_MSG_P(PSTR("[DEBUG] Exception cause: %u\n"), EEPROMr.read(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCEPTION_CAUSE));
uint32_t epc1, epc2, epc3, excvaddr, depc; uint32_t epc1, epc2, epc3, excvaddr, depc;
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, epc1);
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, epc2);
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, epc3);
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, excvaddr);
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, depc);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC1, epc1);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC2, epc2);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, epc3);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, excvaddr);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, depc);
DEBUG_MSG_P(PSTR("[DEBUG] epc1=0x%08x epc2=0x%08x epc3=0x%08x\n"), epc1, epc2, epc3); DEBUG_MSG_P(PSTR("[DEBUG] epc1=0x%08x epc2=0x%08x epc3=0x%08x\n"), epc1, epc2, epc3);
DEBUG_MSG_P(PSTR("[DEBUG] excvaddr=0x%08x depc=0x%08x\n"), excvaddr, depc); DEBUG_MSG_P(PSTR("[DEBUG] excvaddr=0x%08x depc=0x%08x\n"), excvaddr, depc);
uint32_t stack_start, stack_end; uint32_t stack_start, stack_end;
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start);
EEPROM.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end);
DEBUG_MSG_P(PSTR("[DEBUG] >>>stack>>>\n[DEBUG] ")); DEBUG_MSG_P(PSTR("[DEBUG] >>>stack>>>\n[DEBUG] "));
int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE; int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE;
int16_t stack_len = stack_end - stack_start; int16_t stack_len = stack_end - stack_start;
@ -276,7 +276,7 @@ void debugDumpCrashInfo() {
for (int16_t i = 0; i < stack_len; i += 0x10) { for (int16_t i = 0; i < stack_len; i += 0x10) {
DEBUG_MSG_P(PSTR("%08x: "), stack_start + i); DEBUG_MSG_P(PSTR("%08x: "), stack_start + i);
for (byte j = 0; j < 4; j++) { for (byte j = 0; j < 4; j++) {
EEPROM.get(current_address, stack_trace);
EEPROMr.get(current_address, stack_trace);
DEBUG_MSG_P(PSTR("%08x "), stack_trace); DEBUG_MSG_P(PSTR("%08x "), stack_trace);
current_address += 4; current_address += 4;
} }


+ 86
- 0
code/espurna/eeprom.ino View File

@ -0,0 +1,86 @@
/*
EEPROM MODULE
*/
#include <EEPROM_Rotate.h>
// -----------------------------------------------------------------------------
bool eepromRotate(bool value) {
// Enable/disable EEPROM rotation only if we are using more sectors than the
// reserved by the memory layout
if (EEPROMr.size() > EEPROMr.reserved()) {
if (value) {
DEBUG_MSG_P(PSTR("[EEPROM] Reenabling EEPROM rotation\n"));
} else {
DEBUG_MSG_P(PSTR("[EEPROM] Disabling EEPROM rotation\n"));
}
EEPROMr.rotate(value);
}
}
String eepromSectors() {
String response;
for (uint32_t i = 0; i < EEPROMr.size(); i++) {
if (i > 0) response = response + String(", ");
response = response + String(EEPROMr.base() - i);
}
return response;
}
#if TERMINAL_SUPPORT
void _eepromInitCommands() {
settingsRegisterCommand(F("EEPROM.DUMP"), [](Embedis* e) {
EEPROMr.dump(settingsSerial());
DEBUG_MSG_P(PSTR("\n+OK\n"));
});
settingsRegisterCommand(F("FLASH.DUMP"), [](Embedis* e) {
if (e->argc < 2) {
DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
return;
}
uint32_t sector = String(e->argv[1]).toInt();
uint32_t max = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE;
if (sector >= max) {
DEBUG_MSG_P(PSTR("-ERROR: Sector out of range\n"));
return;
}
EEPROMr.dump(settingsSerial(), sector);
DEBUG_MSG_P(PSTR("\n+OK\n"));
});
}
#endif
// -----------------------------------------------------------------------------
void eepromSetup() {
#ifdef EEPROM_ROTATE_SECTORS
EEPROMr.size(EEPROM_ROTATE_SECTORS);
#else
// If the memory layout has more than one sector reserved use those,
// otherwise calculate pool size based on memory size.
if (EEPROMr.size() == 1) {
if (EEPROMr.last() > 1000) { // 4Mb boards
EEPROMr.size(4);
} else if (EEPROMr.last() > 250) { // 1Mb boards
EEPROMr.size(2);
}
}
#endif
EEPROMr.offset(EEPROM_ROTATE_DATA);
EEPROMr.begin(EEPROM_SIZE);
#if TERMINAL_SUPPORT
_eepromInitCommands();
#endif
}

+ 4
- 1
code/espurna/espurna.ino View File

@ -47,7 +47,10 @@ void setup() {
debugSetup(); debugSetup();
#endif #endif
// Init EEPROM, Serial, SPIFFS and system check
// Init EEPROM
eepromSetup();
// Init Serial, SPIFFS and system check
systemSetup(); systemSetup();
// Init persistance and terminal features // Init persistance and terminal features


+ 6
- 2
code/espurna/homeassistant.ino View File

@ -255,13 +255,17 @@ void _haInitCommands() {
settingsRegisterCommand(F("HA.SEND"), [](Embedis* e) { settingsRegisterCommand(F("HA.SEND"), [](Embedis* e) {
setSetting("haEnabled", "1"); setSetting("haEnabled", "1");
_haConfigure(); _haConfigure();
wsSend(_haWebSocketOnSend);
#if WEB_SUPPORT
wsSend(_haWebSocketOnSend);
#endif
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
}); });
settingsRegisterCommand(F("HA.CLEAR"), [](Embedis* e) { settingsRegisterCommand(F("HA.CLEAR"), [](Embedis* e) {
setSetting("haEnabled", "0"); setSetting("haEnabled", "0");
_haConfigure(); _haConfigure();
wsSend(_haWebSocketOnSend);
#if WEB_SUPPORT
wsSend(_haWebSocketOnSend);
#endif
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
}); });
} }


+ 30
- 28
code/espurna/led.ino View File

@ -182,16 +182,18 @@ void ledSetup() {
void ledLoop() { void ledLoop() {
uint8_t wifi_state = wifiState();
for (unsigned char i=0; i<_leds.size(); i++) { for (unsigned char i=0; i<_leds.size(); i++) {
if (_ledMode(i) == LED_MODE_WIFI) { if (_ledMode(i) == LED_MODE_WIFI) {
if (wifiConnected()) {
if (WiFi.getMode() == WIFI_AP) {
_ledBlink(i, 900, 100);
} else {
_ledBlink(i, 4900, 100);
}
if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) {
_ledBlink(i, 100, 100);
} else if (wifi_state & WIFI_STATE_STA) {
_ledBlink(i, 4900, 100);
} else if (wifi_state & WIFI_STATE_AP) {
_ledBlink(i, 900, 100);
} else { } else {
_ledBlink(i, 500, 500); _ledBlink(i, 500, 500);
} }
@ -200,19 +202,19 @@ void ledLoop() {
if (_ledMode(i) == LED_MODE_FINDME_WIFI) { if (_ledMode(i) == LED_MODE_FINDME_WIFI) {
if (wifiConnected()) {
if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) {
_ledBlink(i, 100, 100);
} else if (wifi_state & WIFI_STATE_STA) {
if (relayStatus(_leds[i].relay-1)) { if (relayStatus(_leds[i].relay-1)) {
if (WiFi.getMode() == WIFI_AP) {
_ledBlink(i, 900, 100);
} else {
_ledBlink(i, 4900, 100);
}
_ledBlink(i, 4900, 100);
} else { } else {
if (WiFi.getMode() == WIFI_AP) {
_ledBlink(i, 100, 900);
} else {
_ledBlink(i, 100, 4900);
}
_ledBlink(i, 100, 4900);
}
} else if (wifi_state & WIFI_STATE_AP) {
if (relayStatus(_leds[i].relay-1)) {
_ledBlink(i, 900, 100);
} else {
_ledBlink(i, 100, 900);
} }
} else { } else {
_ledBlink(i, 500, 500); _ledBlink(i, 500, 500);
@ -222,19 +224,19 @@ void ledLoop() {
if (_ledMode(i) == LED_MODE_RELAY_WIFI) { if (_ledMode(i) == LED_MODE_RELAY_WIFI) {
if (wifiConnected()) {
if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) {
_ledBlink(i, 100, 100);
} else if (wifi_state & WIFI_STATE_STA) {
if (relayStatus(_leds[i].relay-1)) { if (relayStatus(_leds[i].relay-1)) {
if (WiFi.getMode() == WIFI_AP) {
_ledBlink(i, 100, 900);
} else {
_ledBlink(i, 100, 4900);
}
_ledBlink(i, 100, 4900);
} else { } else {
if (WiFi.getMode() == WIFI_AP) {
_ledBlink(i, 900, 100);
} else {
_ledBlink(i, 4900, 100);
}
_ledBlink(i, 4900, 100);
}
} else if (wifi_state & WIFI_STATE_AP) {
if (relayStatus(_leds[i].relay-1)) {
_ledBlink(i, 100, 900);
} else {
_ledBlink(i, 900, 100);
} }
} else { } else {
_ledBlink(i, 500, 500); _ledBlink(i, 500, 500);


+ 10
- 10
code/espurna/mqtt.ino View File

@ -8,7 +8,7 @@ Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
#if MQTT_SUPPORT #if MQTT_SUPPORT
#include <EEPROM.h>
#include <EEPROM_Rotate.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
@ -265,7 +265,7 @@ unsigned long _mqttNextMessageId() {
if (id == 0) { if (id == 0) {
// read id from EEPROM and shift it // read id from EEPROM and shift it
id = EEPROM.read(EEPROM_MESSAGE_ID);
id = EEPROMr.read(EEPROM_MESSAGE_ID);
if (id == 0xFF) { if (id == 0xFF) {
// There was nothing in EEPROM, // There was nothing in EEPROM,
@ -274,9 +274,9 @@ unsigned long _mqttNextMessageId() {
} else { } else {
id = (id << 8) + EEPROM.read(EEPROM_MESSAGE_ID + 1);
id = (id << 8) + EEPROM.read(EEPROM_MESSAGE_ID + 2);
id = (id << 8) + EEPROM.read(EEPROM_MESSAGE_ID + 3);
id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 1);
id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 2);
id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 3);
// Calculate next block and start from there // Calculate next block and start from there
id = MQTT_MESSAGE_ID_SHIFT * (1 + (id / MQTT_MESSAGE_ID_SHIFT)); id = MQTT_MESSAGE_ID_SHIFT * (1 + (id / MQTT_MESSAGE_ID_SHIFT));
@ -287,11 +287,11 @@ unsigned long _mqttNextMessageId() {
// Save to EEPROM every MQTT_MESSAGE_ID_SHIFT // Save to EEPROM every MQTT_MESSAGE_ID_SHIFT
if (id % MQTT_MESSAGE_ID_SHIFT == 0) { if (id % MQTT_MESSAGE_ID_SHIFT == 0) {
EEPROM.write(EEPROM_MESSAGE_ID + 0, (id >> 24) & 0xFF);
EEPROM.write(EEPROM_MESSAGE_ID + 1, (id >> 16) & 0xFF);
EEPROM.write(EEPROM_MESSAGE_ID + 2, (id >> 8) & 0xFF);
EEPROM.write(EEPROM_MESSAGE_ID + 3, (id >> 0) & 0xFF);
EEPROM.commit();
EEPROMr.write(EEPROM_MESSAGE_ID + 0, (id >> 24) & 0xFF);
EEPROMr.write(EEPROM_MESSAGE_ID + 1, (id >> 16) & 0xFF);
EEPROMr.write(EEPROM_MESSAGE_ID + 2, (id >> 8) & 0xFF);
EEPROMr.write(EEPROM_MESSAGE_ID + 3, (id >> 0) & 0xFF);
EEPROMr.commit();
} }
id++; id++;


+ 11
- 1
code/espurna/ota.ino View File

@ -70,6 +70,7 @@ void _otaFrom(const char * host, unsigned int port, const char * url) {
#ifdef DEBUG_PORT #ifdef DEBUG_PORT
Update.printError(DEBUG_PORT); Update.printError(DEBUG_PORT);
#endif #endif
eepromRotate(true);
} }
DEBUG_MSG_P(PSTR("[OTA] Disconnected\n")); DEBUG_MSG_P(PSTR("[OTA] Disconnected\n"));
@ -133,6 +134,9 @@ void _otaFrom(const char * host, unsigned int port, const char * url) {
} }
#endif #endif
// Disabling EEPROM rotation to prevent writing to EEPROM after the upgrade
eepromRotate(false);
DEBUG_MSG_P(PSTR("[OTA] Downloading %s\n"), _ota_url); DEBUG_MSG_P(PSTR("[OTA] Downloading %s\n"), _ota_url);
char buffer[strlen_P(OTA_REQUEST_TEMPLATE) + strlen(_ota_url) + strlen(_ota_host)]; char buffer[strlen_P(OTA_REQUEST_TEMPLATE) + strlen(_ota_url) + strlen(_ota_host)];
snprintf_P(buffer, sizeof(buffer), OTA_REQUEST_TEMPLATE, _ota_url, _ota_host); snprintf_P(buffer, sizeof(buffer), OTA_REQUEST_TEMPLATE, _ota_url, _ota_host);
@ -140,7 +144,6 @@ void _otaFrom(const char * host, unsigned int port, const char * url) {
}, NULL); }, NULL);
#if ASYNC_TCP_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED
bool connected = _ota_client->connect(host, port, 443 == port); bool connected = _ota_client->connect(host, port, 443 == port);
#else #else
@ -214,10 +217,16 @@ void otaSetup() {
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ArduinoOTA.onStart([]() { ArduinoOTA.onStart([]() {
// Disabling EEPROM rotation to prevent writing to EEPROM after the upgrade
eepromRotate(false);
DEBUG_MSG_P(PSTR("[OTA] Start\n")); DEBUG_MSG_P(PSTR("[OTA] Start\n"));
#if WEB_SUPPORT #if WEB_SUPPORT
wsSend_P(PSTR("{\"message\": 2}")); wsSend_P(PSTR("{\"message\": 2}"));
#endif #endif
}); });
ArduinoOTA.onEnd([]() { ArduinoOTA.onEnd([]() {
@ -242,6 +251,7 @@ void otaSetup() {
else if (error == OTA_RECEIVE_ERROR) DEBUG_MSG_P(PSTR("Receive Failed\n")); else if (error == OTA_RECEIVE_ERROR) DEBUG_MSG_P(PSTR("Receive Failed\n"));
else if (error == OTA_END_ERROR) DEBUG_MSG_P(PSTR("End Failed\n")); else if (error == OTA_END_ERROR) DEBUG_MSG_P(PSTR("End Failed\n"));
#endif #endif
eepromRotate(true);
}); });
ArduinoOTA.begin(); ArduinoOTA.begin();


+ 7
- 6
code/espurna/relay.ino View File

@ -6,7 +6,7 @@ Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/ */
#include <EEPROM.h>
#include <EEPROM_Rotate.h>
#include <Ticker.h> #include <Ticker.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <vector> #include <vector>
@ -369,9 +369,9 @@ void relaySave() {
if (relayStatus(i)) mask += bit; if (relayStatus(i)) mask += bit;
bit += bit; bit += bit;
} }
EEPROM.write(EEPROM_RELAY_STATUS, mask);
EEPROMr.write(EEPROM_RELAY_STATUS, mask);
DEBUG_MSG_P(PSTR("[RELAY] Saving mask: %d\n"), mask); DEBUG_MSG_P(PSTR("[RELAY] Saving mask: %d\n"), mask);
EEPROM.commit();
EEPROMr.commit();
} }
void relayToggle(unsigned char id, bool report, bool group_report) { void relayToggle(unsigned char id, bool report, bool group_report) {
@ -449,7 +449,7 @@ void _relayBoot() {
bool trigger_save = false; bool trigger_save = false;
// Get last statuses from EEPROM // Get last statuses from EEPROM
unsigned char mask = EEPROM.read(EEPROM_RELAY_STATUS);
unsigned char mask = EEPROMr.read(EEPROM_RELAY_STATUS);
DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %d\n"), mask); DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %d\n"), mask);
// Walk the relays // Walk the relays
@ -487,8 +487,8 @@ void _relayBoot() {
// Save if there is any relay in the RELAY_BOOT_TOGGLE mode // Save if there is any relay in the RELAY_BOOT_TOGGLE mode
if (trigger_save) { if (trigger_save) {
EEPROM.write(EEPROM_RELAY_STATUS, mask);
EEPROM.commit();
EEPROMr.write(EEPROM_RELAY_STATUS, mask);
EEPROMr.commit();
} }
_relayRecursive = false; _relayRecursive = false;
@ -811,6 +811,7 @@ void _relayInitCommands() {
settingsRegisterCommand(F("RELAY"), [](Embedis* e) { settingsRegisterCommand(F("RELAY"), [](Embedis* e) {
if (e->argc < 2) { if (e->argc < 2) {
DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n")); DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
return;
} }
int id = String(e->argv[1]).toInt(); int id = String(e->argv[1]).toInt();
if (e->argc > 2) { if (e->argc > 2) {


+ 28
- 40
code/espurna/settings.ino View File

@ -6,7 +6,7 @@ Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/ */
#include <EEPROM.h>
#include <EEPROM_Rotate.h>
#include <vector> #include <vector>
#include "libs/EmbedisWrap.h" #include "libs/EmbedisWrap.h"
#include <Stream.h> #include <Stream.h>
@ -30,7 +30,7 @@ bool _settings_save = false;
unsigned long settingsSize() { unsigned long settingsSize() {
unsigned pos = SPI_FLASH_SEC_SIZE - 1; unsigned pos = SPI_FLASH_SEC_SIZE - 1;
while (size_t len = EEPROM.read(pos)) {
while (size_t len = EEPROMr.read(pos)) {
pos = pos - len - 2; pos = pos - len - 2;
} }
return SPI_FLASH_SEC_SIZE - pos; return SPI_FLASH_SEC_SIZE - pos;
@ -41,9 +41,9 @@ unsigned long settingsSize() {
unsigned int _settingsKeyCount() { unsigned int _settingsKeyCount() {
unsigned count = 0; unsigned count = 0;
unsigned pos = SPI_FLASH_SEC_SIZE - 1; unsigned pos = SPI_FLASH_SEC_SIZE - 1;
while (size_t len = EEPROM.read(pos)) {
while (size_t len = EEPROMr.read(pos)) {
pos = pos - len - 2; pos = pos - len - 2;
len = EEPROM.read(pos);
len = EEPROMr.read(pos);
pos = pos - len - 2; pos = pos - len - 2;
count ++; count ++;
} }
@ -56,17 +56,17 @@ String _settingsKeyName(unsigned int index) {
unsigned count = 0; unsigned count = 0;
unsigned pos = SPI_FLASH_SEC_SIZE - 1; unsigned pos = SPI_FLASH_SEC_SIZE - 1;
while (size_t len = EEPROM.read(pos)) {
while (size_t len = EEPROMr.read(pos)) {
pos = pos - len - 2; pos = pos - len - 2;
if (count == index) { if (count == index) {
s.reserve(len); s.reserve(len);
for (unsigned char i = 0 ; i < len; i++) { for (unsigned char i = 0 ; i < len; i++) {
s += (char) EEPROM.read(pos + i + 1);
s += (char) EEPROMr.read(pos + i + 1);
} }
break; break;
} }
count++; count++;
len = EEPROM.read(pos);
len = EEPROMr.read(pos);
pos = pos - len - 2; pos = pos - len - 2;
} }
@ -156,27 +156,16 @@ void _settingsKeysCommand() {
unsigned long freeEEPROM = SPI_FLASH_SEC_SIZE - settingsSize(); unsigned long freeEEPROM = SPI_FLASH_SEC_SIZE - settingsSize();
DEBUG_MSG_P(PSTR("Number of keys: %d\n"), keys.size()); DEBUG_MSG_P(PSTR("Number of keys: %d\n"), keys.size());
DEBUG_MSG_P(PSTR("Current EEPROM sector: %u\n"), EEPROMr.current());
DEBUG_MSG_P(PSTR("Free EEPROM: %d bytes (%d%%)\n"), freeEEPROM, 100 * freeEEPROM / SPI_FLASH_SEC_SIZE); DEBUG_MSG_P(PSTR("Free EEPROM: %d bytes (%d%%)\n"), freeEEPROM, 100 * freeEEPROM / SPI_FLASH_SEC_SIZE);
} }
void _settingsFactoryResetCommand() { void _settingsFactoryResetCommand() {
for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) { for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) {
EEPROM.write(i, 0xFF);
}
EEPROM.commit();
}
void _settingsDumpCommand(bool ascii) {
for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) {
if (i % 16 == 0) DEBUG_MSG_P(PSTR("\n[%04X] "), i);
byte c = EEPROM.read(i);
if (ascii && 32 <= c && c <= 126) {
DEBUG_MSG_P(PSTR(" %c "), c);
} else {
DEBUG_MSG_P(PSTR("%02X "), c);
}
EEPROMr.write(i, 0xFF);
} }
EEPROMr.commit();
} }
void _settingsInitCommands() { void _settingsInitCommands() {
@ -194,13 +183,6 @@ void _settingsInitCommands() {
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
}); });
settingsRegisterCommand(F("EEPROM.DUMP"), [](Embedis* e) {
bool ascii = false;
if (e->argc == 2) ascii = String(e->argv[1]).toInt() == 1;
_settingsDumpCommand(ascii);
DEBUG_MSG_P(PSTR("\n+OK\n"));
});
settingsRegisterCommand(F("ERASE.CONFIG"), [](Embedis* e) { settingsRegisterCommand(F("ERASE.CONFIG"), [](Embedis* e) {
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
resetReason(CUSTOM_RESET_TERMINAL); resetReason(CUSTOM_RESET_TERMINAL);
@ -257,7 +239,7 @@ void _settingsInitCommands() {
settingsRegisterCommand(F("INFO"), [](Embedis* e) { settingsRegisterCommand(F("INFO"), [](Embedis* e) {
info(); info();
wifiStatus();
wifiDebug();
//StreamString s; //StreamString s;
//WiFi.printDiag(s); //WiFi.printDiag(s);
//DEBUG_MSG(s.c_str()); //DEBUG_MSG(s.c_str());
@ -289,18 +271,20 @@ void _settingsInitCommands() {
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
}); });
settingsRegisterCommand(F("RELOAD"), [](Embedis* e) {
wsReload();
DEBUG_MSG_P(PSTR("+OK\n"));
});
#if WEB_SUPPORT
settingsRegisterCommand(F("RELOAD"), [](Embedis* e) {
wsReload();
DEBUG_MSG_P(PSTR("+OK\n"));
});
#endif
settingsRegisterCommand(F("RESET"), [](Embedis* e) { settingsRegisterCommand(F("RESET"), [](Embedis* e) {
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
deferredReset(100, CUSTOM_RESET_TERMINAL); deferredReset(100, CUSTOM_RESET_TERMINAL);
}); });
settingsRegisterCommand(F("RESET.SAFE"), [](Embedis* e) { settingsRegisterCommand(F("RESET.SAFE"), [](Embedis* e) {
EEPROM.write(EEPROM_CRASH_COUNTER, SYSTEM_CHECK_MAX);
EEPROMr.write(EEPROM_CRASH_COUNTER, SYSTEM_CHECK_MAX);
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
deferredReset(100, CUSTOM_RESET_TERMINAL); deferredReset(100, CUSTOM_RESET_TERMINAL);
}); });
@ -378,6 +362,10 @@ void settingsInject(void *data, size_t len) {
_serial.inject((char *) data, len); _serial.inject((char *) data, len);
} }
Stream & settingsSerial() {
return (Stream &) _serial;
}
size_t settingsMaxSize() { size_t settingsMaxSize() {
size_t size = EEPROM_SIZE; size_t size = EEPROM_SIZE;
if (size > SPI_FLASH_SEC_SIZE) size = SPI_FLASH_SEC_SIZE; if (size > SPI_FLASH_SEC_SIZE) size = SPI_FLASH_SEC_SIZE;
@ -391,7 +379,7 @@ bool settingsRestoreJson(JsonObject& data) {
if (strcmp(app, APP_NAME) != 0) return false; if (strcmp(app, APP_NAME) != 0) return false;
for (unsigned int i = EEPROM_DATA_END; i < SPI_FLASH_SEC_SIZE; i++) { for (unsigned int i = EEPROM_DATA_END; i < SPI_FLASH_SEC_SIZE; i++) {
EEPROM.write(i, 0xFF);
EEPROMr.write(i, 0xFF);
} }
for (auto element : data) { for (auto element : data) {
@ -430,7 +418,7 @@ void settingsRegisterCommand(const String& name, void (*call)(Embedis*)) {
void settingsSetup() { void settingsSetup() {
EEPROM.begin(SPI_FLASH_SEC_SIZE);
EEPROMr.begin(SPI_FLASH_SEC_SIZE);
_serial.callback([](uint8_t ch) { _serial.callback([](uint8_t ch) {
#if TELNET_SUPPORT #if TELNET_SUPPORT
@ -443,8 +431,8 @@ void settingsSetup() {
Embedis::dictionary( F("EEPROM"), Embedis::dictionary( F("EEPROM"),
SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE,
[](size_t pos) -> char { return EEPROM.read(pos); },
[](size_t pos, char value) { EEPROM.write(pos, value); },
[](size_t pos) -> char { return EEPROMr.read(pos); },
[](size_t pos, char value) { EEPROMr.write(pos, value); },
#if SETTINGS_AUTOSAVE #if SETTINGS_AUTOSAVE
[]() { _settings_save = true; } []() { _settings_save = true; }
#else #else
@ -468,7 +456,7 @@ void settingsSetup() {
void settingsLoop() { void settingsLoop() {
if (_settings_save) { if (_settings_save) {
EEPROM.commit();
EEPROMr.commit();
_settings_save = false; _settings_save = false;
} }


+ 604
- 602
code/espurna/static/index.html.gz.h
File diff suppressed because it is too large
View File


+ 4
- 6
code/espurna/system.ino View File

@ -6,7 +6,7 @@ Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
*/ */
#include <EEPROM.h>
#include <EEPROM_Rotate.h>
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -30,7 +30,7 @@ unsigned short int _load_average = 100;
bool _systemStable = true; bool _systemStable = true;
void systemCheck(bool stable) { void systemCheck(bool stable) {
unsigned char value = EEPROM.read(EEPROM_CRASH_COUNTER);
unsigned char value = EEPROMr.read(EEPROM_CRASH_COUNTER);
if (stable) { if (stable) {
value = 0; value = 0;
DEBUG_MSG_P(PSTR("[MAIN] System OK\n")); DEBUG_MSG_P(PSTR("[MAIN] System OK\n"));
@ -41,8 +41,8 @@ void systemCheck(bool stable) {
DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n")); DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n"));
} }
} }
EEPROM.write(EEPROM_CRASH_COUNTER, value);
EEPROM.commit();
EEPROMr.write(EEPROM_CRASH_COUNTER, value);
EEPROMr.commit();
} }
bool systemCheck() { bool systemCheck() {
@ -148,8 +148,6 @@ void _systemSetupSpecificHardware() {
void systemSetup() { void systemSetup() {
EEPROM.begin(EEPROM_SIZE);
#if SPIFFS_SUPPORT #if SPIFFS_SUPPORT
SPIFFS.begin(); SPIFFS.begin();
#endif #endif


+ 1
- 1
code/espurna/telnet.ino View File

@ -138,7 +138,7 @@ void _telnetNewClient(AsyncClient *client) {
// If there is no terminal support automatically dump info and crash data // If there is no terminal support automatically dump info and crash data
#if TERMINAL_SUPPORT == 0 #if TERMINAL_SUPPORT == 0
info(); info();
wifiStatus();
wifiDebug();
debugDumpCrashInfo(); debugDumpCrashInfo();
debugClearCrashInfo(); debugClearCrashInfo();
#endif #endif


+ 48
- 11
code/espurna/utils.ino View File

@ -211,10 +211,42 @@ void heartbeat() {
#endif /// HEARTBEAT_ENABLED #endif /// HEARTBEAT_ENABLED
unsigned int sectors(size_t size) {
// -----------------------------------------------------------------------------
// INFO
// -----------------------------------------------------------------------------
extern "C" uint32_t _SPIFFS_start;
extern "C" uint32_t _SPIFFS_end;
unsigned int info_bytes2sectors(size_t size) {
return (int) (size + SPI_FLASH_SEC_SIZE - 1) / SPI_FLASH_SEC_SIZE; return (int) (size + SPI_FLASH_SEC_SIZE - 1) / SPI_FLASH_SEC_SIZE;
} }
unsigned long info_ota_space() {
return (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
}
unsigned long info_filesystem_space() {
return ((uint32_t)&_SPIFFS_end - (uint32_t)&_SPIFFS_start);
}
unsigned long info_eeprom_space() {
return EEPROMr.reserved() * SPI_FLASH_SEC_SIZE;
}
void _info_print_memory_layout_line(const char * name, unsigned long bytes, bool reset) {
static unsigned long index = 0;
if (reset) index = 0;
if (0 == bytes) return;
unsigned int _sectors = info_bytes2sectors(bytes);
DEBUG_MSG_P(PSTR("[INIT] %-20s: %8lu bytes / %4d sectors (%4d to %4d)\n"), name, bytes, _sectors, index, index + _sectors - 1);
index += _sectors;
}
void _info_print_memory_layout_line(const char * name, unsigned long bytes) {
_info_print_memory_layout_line(name, bytes, false);
}
void info() { void info() {
DEBUG_MSG_P(PSTR("\n\n")); DEBUG_MSG_P(PSTR("\n\n"));
@ -235,13 +267,18 @@ void info() {
DEBUG_MSG_P(PSTR("[INIT] Flash speed: %u Hz\n"), ESP.getFlashChipSpeed()); DEBUG_MSG_P(PSTR("[INIT] Flash speed: %u Hz\n"), ESP.getFlashChipSpeed());
DEBUG_MSG_P(PSTR("[INIT] Flash mode: %s\n"), mode == FM_QIO ? "QIO" : mode == FM_QOUT ? "QOUT" : mode == FM_DIO ? "DIO" : mode == FM_DOUT ? "DOUT" : "UNKNOWN"); DEBUG_MSG_P(PSTR("[INIT] Flash mode: %s\n"), mode == FM_QIO ? "QIO" : mode == FM_QOUT ? "QOUT" : mode == FM_DIO ? "DIO" : mode == FM_DOUT ? "DOUT" : "UNKNOWN");
DEBUG_MSG_P(PSTR("\n")); DEBUG_MSG_P(PSTR("\n"));
DEBUG_MSG_P(PSTR("[INIT] Flash sector size: %8u bytes\n"), SPI_FLASH_SEC_SIZE);
DEBUG_MSG_P(PSTR("[INIT] Flash size (CHIP): %8u bytes\n"), ESP.getFlashChipRealSize());
DEBUG_MSG_P(PSTR("[INIT] Flash size (SDK): %8u bytes / %4d sectors\n"), ESP.getFlashChipSize(), sectors(ESP.getFlashChipSize()));
DEBUG_MSG_P(PSTR("[INIT] Firmware size: %8u bytes / %4d sectors\n"), ESP.getSketchSize(), sectors(ESP.getSketchSize()));
DEBUG_MSG_P(PSTR("[INIT] Max OTA size: %8u bytes / %4d sectors\n"), maxSketchSpace(), sectors(maxSketchSpace()));
DEBUG_MSG_P(PSTR("[INIT] EEPROM size: %8u bytes / %4d sectors\n"), settingsMaxSize(), sectors(settingsMaxSize()));
DEBUG_MSG_P(PSTR("[INIT] Empty space: %8u bytes / 4 sectors\n"), 4 * SPI_FLASH_SEC_SIZE);
_info_print_memory_layout_line("Flash size (CHIP)", ESP.getFlashChipRealSize(), true);
_info_print_memory_layout_line("Flash size (SDK)", ESP.getFlashChipSize(), true);
_info_print_memory_layout_line("Reserved", 1 * SPI_FLASH_SEC_SIZE, true);
_info_print_memory_layout_line("Firmware size", ESP.getSketchSize());
_info_print_memory_layout_line("Max OTA size", info_ota_space());
_info_print_memory_layout_line("SPIFFS size", info_filesystem_space());
_info_print_memory_layout_line("EEPROM size", info_eeprom_space());
_info_print_memory_layout_line("Reserved", 4 * SPI_FLASH_SEC_SIZE);
DEBUG_MSG_P(PSTR("\n"));
DEBUG_MSG_P(PSTR("[INIT] EEPROM sectors: %s\n"), (char *) eepromSectors().c_str());
DEBUG_MSG_P(PSTR("\n")); DEBUG_MSG_P(PSTR("\n"));
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -508,7 +545,7 @@ bool sslFingerPrintChar(const char * fingerprint, char * destination) {
unsigned char resetReason() { unsigned char resetReason() {
static unsigned char status = 255; static unsigned char status = 255;
if (status == 255) { if (status == 255) {
status = EEPROM.read(EEPROM_CUSTOM_RESET);
status = EEPROMr.read(EEPROM_CUSTOM_RESET);
if (status > 0) resetReason(0); if (status > 0) resetReason(0);
if (status > CUSTOM_RESET_MAX) status = 0; if (status > CUSTOM_RESET_MAX) status = 0;
} }
@ -516,8 +553,8 @@ unsigned char resetReason() {
} }
void resetReason(unsigned char reason) { void resetReason(unsigned char reason) {
EEPROM.write(EEPROM_CUSTOM_RESET, reason);
EEPROM.commit();
EEPROMr.write(EEPROM_CUSTOM_RESET, reason);
EEPROMr.commit();
} }
void reset(unsigned char reason) { void reset(unsigned char reason) {


+ 16
- 6
code/espurna/web.ino View File

@ -43,7 +43,7 @@ void _onReset(AsyncWebServerRequest *request) {
void _onGetConfig(AsyncWebServerRequest *request) { void _onGetConfig(AsyncWebServerRequest *request) {
webLog(request); webLog(request);
if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
if (!webAuthenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
AsyncResponseStream *response = request->beginResponseStream("text/json"); AsyncResponseStream *response = request->beginResponseStream("text/json");
@ -64,7 +64,7 @@ void _onGetConfig(AsyncWebServerRequest *request) {
void _onPostConfig(AsyncWebServerRequest *request) { void _onPostConfig(AsyncWebServerRequest *request) {
webLog(request); webLog(request);
if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
if (!webAuthenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
request->send(_webConfigSuccess ? 200 : 400); request->send(_webConfigSuccess ? 200 : 400);
} }
@ -112,7 +112,7 @@ void _onPostConfigData(AsyncWebServerRequest *request, String filename, size_t i
void _onHome(AsyncWebServerRequest *request) { void _onHome(AsyncWebServerRequest *request) {
webLog(request); webLog(request);
if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
if (!webAuthenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
if (request->header("If-Modified-Since").equals(_last_modified)) { if (request->header("If-Modified-Since").equals(_last_modified)) {
@ -212,7 +212,7 @@ int _onCertificate(void * arg, const char *filename, uint8_t **buf) {
void _onUpgrade(AsyncWebServerRequest *request) { void _onUpgrade(AsyncWebServerRequest *request) {
webLog(request); webLog(request);
if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
if (!webAuthenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
char buffer[10]; char buffer[10];
if (!Update.hasError()) { if (!Update.hasError()) {
@ -223,7 +223,9 @@ void _onUpgrade(AsyncWebServerRequest *request) {
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", buffer); AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", buffer);
response->addHeader("Connection", "close"); response->addHeader("Connection", "close");
if (!Update.hasError()) {
if (Update.hasError()) {
eepromRotate(true);
} else {
deferredReset(100, CUSTOM_RESET_UPGRADE); deferredReset(100, CUSTOM_RESET_UPGRADE);
} }
request->send(response); request->send(response);
@ -231,7 +233,12 @@ void _onUpgrade(AsyncWebServerRequest *request) {
} }
void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
if (!index) { if (!index) {
// Disabling EEPROM rotation to prevent writing to EEPROM after the upgrade
eepromRotate(false);
DEBUG_MSG_P(PSTR("[UPGRADE] Start: %s\n"), filename.c_str()); DEBUG_MSG_P(PSTR("[UPGRADE] Start: %s\n"), filename.c_str());
Update.runAsync(true); Update.runAsync(true);
if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) { if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) {
@ -239,7 +246,9 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde
Update.printError(DEBUG_PORT); Update.printError(DEBUG_PORT);
#endif #endif
} }
} }
if (!Update.hasError()) { if (!Update.hasError()) {
if (Update.write(data, len) != len) { if (Update.write(data, len) != len) {
#ifdef DEBUG_PORT #ifdef DEBUG_PORT
@ -247,6 +256,7 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde
#endif #endif
} }
} }
if (final) { if (final) {
if (Update.end(true)){ if (Update.end(true)){
DEBUG_MSG_P(PSTR("[UPGRADE] Success: %u bytes\n"), index + len); DEBUG_MSG_P(PSTR("[UPGRADE] Success: %u bytes\n"), index + len);
@ -262,7 +272,7 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool _authenticate(AsyncWebServerRequest *request) {
bool webAuthenticate(AsyncWebServerRequest *request) {
#if USE_PASSWORD #if USE_PASSWORD
String password = getSetting("adminPass", ADMIN_PASS); String password = getSetting("adminPass", ADMIN_PASS);
char httpPassword[password.length() + 1]; char httpPassword[password.length() + 1];


+ 214
- 52
code/espurna/wifi.ino View File

@ -10,11 +10,26 @@ Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
#include <Ticker.h> #include <Ticker.h>
uint32_t _wifi_scan_client_id = 0; uint32_t _wifi_scan_client_id = 0;
bool _wifi_wps_running = false;
bool _wifi_smartconfig_running = false;
uint8_t _wifi_ap_mode = WIFI_AP_FALLBACK;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// PRIVATE // PRIVATE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void _wifiCheckAP() {
if ((WIFI_AP_FALLBACK == _wifi_ap_mode) &&
(jw.connected()) &&
((WiFi.getMode() & WIFI_AP) > 0) &&
(WiFi.softAPgetStationNum() == 0)
) {
jw.enableAP(false);
}
}
void _wifiConfigure() { void _wifiConfigure() {
jw.setHostname(getSetting("hostname").c_str()); jw.setHostname(getSetting("hostname").c_str());
@ -25,9 +40,11 @@ void _wifiConfigure() {
#endif #endif
jw.setConnectTimeout(WIFI_CONNECT_TIMEOUT); jw.setConnectTimeout(WIFI_CONNECT_TIMEOUT);
wifiReconnectCheck(); wifiReconnectCheck();
jw.setAPMode(WIFI_AP_MODE);
jw.enableAPFallback(true);
jw.cleanNetworks(); jw.cleanNetworks();
_wifi_ap_mode = getSetting("apmode", WIFI_AP_FALLBACK).toInt();
// If system is flagged unstable we do not init wifi networks // If system is flagged unstable we do not init wifi networks
#if SYSTEM_CHECK_ENABLED #if SYSTEM_CHECK_ENABLED
if (!systemCheck()) return; if (!systemCheck()) return;
@ -56,7 +73,7 @@ void _wifiConfigure() {
} }
} }
jw.scanNetworks(getSetting("wifiScan", WIFI_SCAN_NETWORKS).toInt() == 1);
jw.enableScan(getSetting("wifiScan", WIFI_SCAN_NETWORKS).toInt() == 1);
} }
@ -196,6 +213,47 @@ void _wifiInject() {
} }
} }
void _wifiCallback(justwifi_messages_t code, char * parameter) {
if (MESSAGE_WPS_START == code) {
_wifi_wps_running = true;
}
if (MESSAGE_SMARTCONFIG_START == code) {
_wifi_smartconfig_running = true;
}
if (MESSAGE_WPS_ERROR == code || MESSAGE_SMARTCONFIG_ERROR == code) {
_wifi_wps_running = false;
_wifi_smartconfig_running = false;
}
if (MESSAGE_WPS_SUCCESS == code || MESSAGE_SMARTCONFIG_SUCCESS == code) {
String ssid = WiFi.SSID();
String pass = WiFi.psk();
// Look for the same SSID
uint8_t count = 0;
while (count < WIFI_MAX_NETWORKS) {
if (!hasSetting("ssid", count)) break;
if (ssid.equals(getSetting("ssid", count, ""))) break;
count++;
}
// If we have reached the max we overwrite the first one
if (WIFI_MAX_NETWORKS == count) count = 0;
setSetting("ssid", count, ssid);
setSetting("pass", count, pass);
_wifi_wps_running = false;
_wifi_smartconfig_running = false;
}
}
#if WIFI_AP_CAPTIVE #if WIFI_AP_CAPTIVE
#include "DNSServer.h" #include "DNSServer.h"
@ -221,7 +279,9 @@ void _wifiCaptivePortal(justwifi_messages_t code, char * parameter) {
#if DEBUG_SUPPORT #if DEBUG_SUPPORT
void _wifiDebug(justwifi_messages_t code, char * parameter) {
void _wifiDebugCallback(justwifi_messages_t code, char * parameter) {
// -------------------------------------------------------------------------
if (code == MESSAGE_SCANNING) { if (code == MESSAGE_SCANNING) {
DEBUG_MSG_P(PSTR("[WIFI] Scanning\n")); DEBUG_MSG_P(PSTR("[WIFI] Scanning\n"));
@ -243,6 +303,8 @@ void _wifiDebug(justwifi_messages_t code, char * parameter) {
DEBUG_MSG_P(PSTR("[WIFI] %s\n"), parameter); DEBUG_MSG_P(PSTR("[WIFI] %s\n"), parameter);
} }
// -------------------------------------------------------------------------
if (code == MESSAGE_CONNECTING) { if (code == MESSAGE_CONNECTING) {
DEBUG_MSG_P(PSTR("[WIFI] Connecting to %s\n"), parameter); DEBUG_MSG_P(PSTR("[WIFI] Connecting to %s\n"), parameter);
} }
@ -256,25 +318,59 @@ void _wifiDebug(justwifi_messages_t code, char * parameter) {
} }
if (code == MESSAGE_CONNECTED) { if (code == MESSAGE_CONNECTED) {
wifiStatus();
}
if (code == MESSAGE_ACCESSPOINT_CREATED) {
wifiStatus();
wifiDebug(WIFI_STA);
} }
if (code == MESSAGE_DISCONNECTED) { if (code == MESSAGE_DISCONNECTED) {
DEBUG_MSG_P(PSTR("[WIFI] Disconnected\n")); DEBUG_MSG_P(PSTR("[WIFI] Disconnected\n"));
} }
// -------------------------------------------------------------------------
if (code == MESSAGE_ACCESSPOINT_CREATING) { if (code == MESSAGE_ACCESSPOINT_CREATING) {
DEBUG_MSG_P(PSTR("[WIFI] Creating access point\n")); DEBUG_MSG_P(PSTR("[WIFI] Creating access point\n"));
} }
if (code == MESSAGE_ACCESSPOINT_CREATED) {
wifiDebug(WIFI_AP);
}
if (code == MESSAGE_ACCESSPOINT_FAILED) { if (code == MESSAGE_ACCESSPOINT_FAILED) {
DEBUG_MSG_P(PSTR("[WIFI] Could not create access point\n")); DEBUG_MSG_P(PSTR("[WIFI] Could not create access point\n"));
} }
if (code == MESSAGE_ACCESSPOINT_DESTROYED) {
DEBUG_MSG_P(PSTR("[WIFI] Access point destroyed\n"));
}
// -------------------------------------------------------------------------
if (code == MESSAGE_WPS_START) {
DEBUG_MSG_P(PSTR("[WIFI] WPS started\n"));
}
if (code == MESSAGE_WPS_SUCCESS) {
DEBUG_MSG_P(PSTR("[WIFI] WPS succeded!\n"));
}
if (code == MESSAGE_WPS_ERROR) {
DEBUG_MSG_P(PSTR("[WIFI] WPS failed\n"));
}
// ------------------------------------------------------------------------
if (code == MESSAGE_SMARTCONFIG_START) {
DEBUG_MSG_P(PSTR("[WIFI] Smart Config started\n"));
}
if (code == MESSAGE_SMARTCONFIG_SUCCESS) {
DEBUG_MSG_P(PSTR("[WIFI] Smart Config succeded!\n"));
}
if (code == MESSAGE_SMARTCONFIG_ERROR) {
DEBUG_MSG_P(PSTR("[WIFI] Smart Config failed\n"));
}
} }
#endif // DEBUG_SUPPORT #endif // DEBUG_SUPPORT
@ -294,10 +390,24 @@ void _wifiInitCommands() {
}); });
settingsRegisterCommand(F("WIFI.AP"), [](Embedis* e) { settingsRegisterCommand(F("WIFI.AP"), [](Embedis* e) {
createAP();
wifiStartAP();
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
}); });
#if defined(JUSTWIFI_ENABLE_WPS)
settingsRegisterCommand(F("WIFI.WPS"), [](Embedis* e) {
wifiStartWPS();
DEBUG_MSG_P(PSTR("+OK\n"));
});
#endif // defined(JUSTWIFI_ENABLE_WPS)
#if defined(JUSTWIFI_ENABLE_SMARTCONFIG)
settingsRegisterCommand(F("WIFI.SMARTCONFIG"), [](Embedis* e) {
wifiStartSmartConfig();
DEBUG_MSG_P(PSTR("+OK\n"));
});
#endif // defined(JUSTWIFI_ENABLE_SMARTCONFIG)
settingsRegisterCommand(F("WIFI.SCAN"), [](Embedis* e) { settingsRegisterCommand(F("WIFI.SCAN"), [](Embedis* e) {
_wifiScan(); _wifiScan();
DEBUG_MSG_P(PSTR("+OK\n")); DEBUG_MSG_P(PSTR("+OK\n"));
@ -346,6 +456,59 @@ void _wifiWebSocketOnAction(uint32_t client_id, const char * action, JsonObject&
#endif #endif
// -----------------------------------------------------------------------------
// INFO
// -----------------------------------------------------------------------------
void wifiDebug(WiFiMode_t modes) {
bool footer = false;
if (((modes & WIFI_STA) > 0) && ((WiFi.getMode() & WIFI_STA) > 0)) {
uint8_t * bssid = WiFi.BSSID();
DEBUG_MSG_P(PSTR("[WIFI] ------------------------------------- MODE STA\n"));
DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), WiFi.SSID().c_str());
DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.localIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.macAddress().c_str());
DEBUG_MSG_P(PSTR("[WIFI] GW %s\n"), WiFi.gatewayIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] DNS %s\n"), WiFi.dnsIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MASK %s\n"), WiFi.subnetMask().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] HOST http://%s.local\n"), WiFi.hostname().c_str());
DEBUG_MSG_P(PSTR("[WIFI] BSSID %02X:%02X:%02X:%02X:%02X:%02X\n"),
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], bssid[6]
);
DEBUG_MSG_P(PSTR("[WIFI] CH %d\n"), WiFi.channel());
DEBUG_MSG_P(PSTR("[WIFI] RSSI %d\n"), WiFi.RSSI());
footer = true;
}
if (((modes & WIFI_AP) > 0) && ((WiFi.getMode() & WIFI_AP) > 0)) {
DEBUG_MSG_P(PSTR("[WIFI] -------------------------------------- MODE AP\n"));
DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), getSetting("hostname").c_str());
DEBUG_MSG_P(PSTR("[WIFI] PASS %s\n"), getSetting("adminPass", ADMIN_PASS).c_str());
DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.softAPIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.softAPmacAddress().c_str());
footer = true;
}
if (WiFi.getMode() == 0) {
DEBUG_MSG_P(PSTR("[WIFI] ------------------------------------- MODE OFF\n"));
DEBUG_MSG_P(PSTR("[WIFI] No connection\n"));
footer = true;
}
if (footer) {
DEBUG_MSG_P(PSTR("[WIFI] ----------------------------------------------\n"));
}
}
void wifiDebug() {
wifiDebug(WIFI_AP_STA);
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// API // API
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -372,11 +535,30 @@ void wifiDisconnect() {
jw.disconnect(); jw.disconnect();
} }
bool createAP() {
jw.disconnect();
jw.resetReconnectTimeout();
return jw.createAP();
void wifiStartAP(bool only) {
if (only) {
jw.enableSTA(false);
jw.disconnect();
jw.resetReconnectTimeout();
}
jw.enableAP(true);
}
void wifiStartAP() {
wifiStartAP(true);
}
#if defined(JUSTWIFI_ENABLE_WPS)
void wifiStartWPS() {
jw.startWPS();
} }
#endif // defined(JUSTWIFI_ENABLE_WPS)
#if defined(JUSTWIFI_ENABLE_SMARTCONFIG)
void wifiStartSmartConfig() {
jw.startSmartConfig();
}
#endif // defined(JUSTWIFI_ENABLE_SMARTCONFIG)
void wifiReconnectCheck() { void wifiReconnectCheck() {
bool connected = false; bool connected = false;
@ -389,44 +571,13 @@ void wifiReconnectCheck() {
jw.setReconnectTimeout(connected ? 0 : WIFI_RECONNECT_INTERVAL); jw.setReconnectTimeout(connected ? 0 : WIFI_RECONNECT_INTERVAL);
} }
void wifiStatus() {
if (WiFi.getMode() == WIFI_AP_STA) {
DEBUG_MSG_P(PSTR("[WIFI] MODE AP + STA --------------------------------\n"));
} else if (WiFi.getMode() == WIFI_AP) {
DEBUG_MSG_P(PSTR("[WIFI] MODE AP --------------------------------------\n"));
} else if (WiFi.getMode() == WIFI_STA) {
DEBUG_MSG_P(PSTR("[WIFI] MODE STA -------------------------------------\n"));
} else {
DEBUG_MSG_P(PSTR("[WIFI] MODE OFF -------------------------------------\n"));
DEBUG_MSG_P(PSTR("[WIFI] No connection\n"));
}
if ((WiFi.getMode() & WIFI_AP) == WIFI_AP) {
DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), jw.getAPSSID().c_str());
DEBUG_MSG_P(PSTR("[WIFI] PASS %s\n"), getSetting("adminPass", ADMIN_PASS).c_str());
DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.softAPIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.softAPmacAddress().c_str());
}
if ((WiFi.getMode() & WIFI_STA) == WIFI_STA) {
uint8_t * bssid = WiFi.BSSID();
DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), WiFi.SSID().c_str());
DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.localIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.macAddress().c_str());
DEBUG_MSG_P(PSTR("[WIFI] GW %s\n"), WiFi.gatewayIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] DNS %s\n"), WiFi.dnsIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MASK %s\n"), WiFi.subnetMask().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] HOST http://%s.local\n"), WiFi.hostname().c_str());
DEBUG_MSG_P(PSTR("[WIFI] BSSID %02X:%02X:%02X:%02X:%02X:%02X\n"),
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], bssid[6]
);
DEBUG_MSG_P(PSTR("[WIFI] CH %d\n"), WiFi.channel());
DEBUG_MSG_P(PSTR("[WIFI] RSSI %d\n"), WiFi.RSSI());
}
DEBUG_MSG_P(PSTR("[WIFI] ----------------------------------------------\n"));
uint8_t wifiState() {
uint8_t state = 0;
if (jw.connected()) state += WIFI_STATE_STA;
if (jw.connectable()) state += WIFI_STATE_AP;
if (_wifi_wps_running) state += WIFI_STATE_WPS;
if (_wifi_smartconfig_running) state += WIFI_STATE_SMARTCONFIG;
return state;
} }
void wifiRegister(wifi_callback_f callback) { void wifiRegister(wifi_callback_f callback) {
@ -445,11 +596,12 @@ void wifiSetup() {
_wifiConfigure(); _wifiConfigure();
// Message callbacks // Message callbacks
wifiRegister(_wifiCallback);
#if WIFI_AP_CAPTIVE #if WIFI_AP_CAPTIVE
wifiRegister(_wifiCaptivePortal); wifiRegister(_wifiCaptivePortal);
#endif #endif
#if DEBUG_SUPPORT #if DEBUG_SUPPORT
wifiRegister(_wifiDebug);
wifiRegister(_wifiDebugCallback);
#endif #endif
#if WEB_SUPPORT #if WEB_SUPPORT
@ -470,17 +622,27 @@ void wifiSetup() {
void wifiLoop() { void wifiLoop() {
// Main wifi loop
jw.loop(); jw.loop();
// Process captrive portal DNS queries if in AP mode only
#if WIFI_AP_CAPTIVE #if WIFI_AP_CAPTIVE
if ((WiFi.getMode() & WIFI_AP) == WIFI_AP) { if ((WiFi.getMode() & WIFI_AP) == WIFI_AP) {
_wifi_dnsServer.processNextRequest(); _wifi_dnsServer.processNextRequest();
} }
#endif #endif
// Do we have a pending scan?
if (_wifi_scan_client_id > 0) { if (_wifi_scan_client_id > 0) {
_wifiScan(_wifi_scan_client_id); _wifiScan(_wifi_scan_client_id);
_wifi_scan_client_id = 0; _wifi_scan_client_id = 0;
} }
// Check if we should disable AP
static unsigned long last = 0;
if (millis() - last > 60000) {
last = millis();
_wifiCheckAP();
}
} }

+ 57
- 13
code/espurna/ws.ino View File

@ -27,6 +27,57 @@ std::vector<ws_on_receive_callback_f> _ws_on_receive_callbacks;
// Private methods // Private methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
typedef struct {
IPAddress ip;
unsigned long timestamp = 0;
} ws_ticket_t;
ws_ticket_t _ticket[WS_BUFFER_SIZE];
void _onAuth(AsyncWebServerRequest *request) {
webLog(request);
if (!webAuthenticate(request)) return request->requestAuthentication();
IPAddress ip = request->client()->remoteIP();
unsigned long now = millis();
unsigned short index;
for (index = 0; index < WS_BUFFER_SIZE; index++) {
if (_ticket[index].ip == ip) break;
if (_ticket[index].timestamp == 0) break;
if (now - _ticket[index].timestamp > WS_TIMEOUT) break;
}
if (index == WS_BUFFER_SIZE) {
request->send(429);
} else {
_ticket[index].ip = ip;
_ticket[index].timestamp = now;
request->send(200, "text/plain", "OK");
}
}
bool _wsAuth(AsyncWebSocketClient * client) {
IPAddress ip = client->remoteIP();
unsigned long now = millis();
unsigned short index = 0;
for (index = 0; index < WS_BUFFER_SIZE; index++) {
if ((_ticket[index].ip == ip) && (now - _ticket[index].timestamp < WS_TIMEOUT)) break;
}
if (index == WS_BUFFER_SIZE) {
DEBUG_MSG_P(PSTR("[WEBSOCKET] Validation check failed\n"));
wsSend_P(client->id(), PSTR("{\"message\": 10}"));
return false;
}
return true;
}
// -----------------------------------------------------------------------------
#if MQTT_SUPPORT #if MQTT_SUPPORT
void _wsMQTTCallback(unsigned int type, const char * topic, const char * payload) { void _wsMQTTCallback(unsigned int type, const char * topic, const char * payload) {
if (type == MQTT_CONNECT_EVENT) wsSend_P(PSTR("{\"mqttStatus\": true}")); if (type == MQTT_CONNECT_EVENT) wsSend_P(PSTR("{\"mqttStatus\": true}"));
@ -315,6 +366,11 @@ void _wsStart(uint32_t client_id) {
void _wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ void _wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
if (type == WS_EVT_CONNECT) { if (type == WS_EVT_CONNECT) {
#ifndef NOWSAUTH
if (!_wsAuth(client)) return;
#endif
IPAddress ip = client->remoteIP(); IPAddress ip = client->remoteIP();
DEBUG_MSG_P(PSTR("[WEBSOCKET] #%u connected, ip: %d.%d.%d.%d, url: %s\n"), client->id(), ip[0], ip[1], ip[2], ip[3], server->url()); DEBUG_MSG_P(PSTR("[WEBSOCKET] #%u connected, ip: %d.%d.%d.%d, url: %s\n"), client->id(), ip[0], ip[1], ip[2], ip[3], server->url());
_wsStart(client->id()); _wsStart(client->id());
@ -421,17 +477,6 @@ void wsSend_P(uint32_t client_id, PGM_P payload) {
_ws.text(client_id, buffer); _ws.text(client_id, buffer);
} }
void wsConfigure() {
#if USE_PASSWORD
bool auth = getSetting("wsAuth", WS_AUTHENTICATION).toInt() == 1;
if (auth) {
_ws.setAuthentication(WEB_USERNAME, (const char *) getSetting("adminPass", ADMIN_PASS).c_str());
} else {
_ws.setAuthentication("", "");
}
#endif
}
// This method being public makes // This method being public makes
// _ws_on_after_parse_callbacks strange here, // _ws_on_after_parse_callbacks strange here,
// it should belong somewhere else. // it should belong somewhere else.
@ -443,14 +488,13 @@ void wsReload() {
void wsSetup() { void wsSetup() {
_ws.onEvent(_wsEvent); _ws.onEvent(_wsEvent);
wsConfigure();
webServer()->addHandler(&_ws); webServer()->addHandler(&_ws);
webServer()->on("/auth", HTTP_GET, _onAuth);
#if MQTT_SUPPORT #if MQTT_SUPPORT
mqttRegister(_wsMQTTCallback); mqttRegister(_wsMQTTCallback);
#endif #endif
wsOnSendRegister(_wsOnStart); wsOnSendRegister(_wsOnStart);
wsOnReceiveRegister(_wsOnReceive); wsOnReceiveRegister(_wsOnReceive);
wsOnAfterParseRegister(wsConfigure);
espurnaRegisterLoop(_wsLoop); espurnaRegisterLoop(_wsLoop);
} }


+ 21
- 10
code/html/custom.js View File

@ -510,7 +510,7 @@ function onFileUpload(event) {
if (data) { if (data) {
sendAction("restore", data); sendAction("restore", data);
} else { } else {
alert(messages[4]);
window.alert(messages[4]);
} }
}; };
reader.readAsText(inputFile); reader.readAsText(inputFile);
@ -1351,7 +1351,7 @@ function hasChanged() {
function initUrls(root) { function initUrls(root) {
var paths = ["ws", "upgrade", "config"];
var paths = ["ws", "upgrade", "config", "auth"];
urls["root"] = root; urls["root"] = root;
paths.forEach(function(path) { paths.forEach(function(path) {
@ -1363,15 +1363,26 @@ function initUrls(root) {
} }
function connectToURL(url) { function connectToURL(url) {
initUrls(url); initUrls(url);
if (websock) { websock.close(); }
websock = new WebSocket(urls.ws.href);
websock.onmessage = function(evt) {
var data = getJson(evt.data.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t"));
if (data) {
processData(data);
}
};
$.ajax({
'method': 'GET',
'url': urls.auth.href,
'xhrFields': { 'withCredentials': true }
}).done(function(data) {
if (websock) { websock.close(); }
websock = new WebSocket(urls.ws.href);
websock.onmessage = function(evt) {
var data = getJson(evt.data.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t"));
if (data) {
processData(data);
}
};
}).fail(function() {
// Nothing to do, reload page and retry
});
} }
function connect(host) { function connect(host) {


+ 457
- 454
code/platformio.ini
File diff suppressed because it is too large
View File


Loading…
Cancel
Save