Browse Source

Merge branch 'dev' into ESP_DIN

rfm69
Pavel Slama 6 years ago
committed by GitHub
parent
commit
0075d386c8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 3634 additions and 3334 deletions
  1. +1
    -1
      README.md
  2. +41
    -0
      code/.github/stale.yml
  3. +1
    -0
      code/espurna/config/arduino.h
  4. +1
    -1
      code/espurna/config/defaults.h
  5. +5
    -1
      code/espurna/config/general.h
  6. +58
    -2
      code/espurna/config/hardware.h
  7. +4
    -0
      code/espurna/config/sensors.h
  8. +1
    -1
      code/espurna/config/version.h
  9. BIN
      code/espurna/data/index.html.gz
  10. +12
    -0
      code/espurna/domoticz.ino
  11. +1
    -1
      code/espurna/influxdb.ino
  12. +1
    -1
      code/espurna/mdns.ino
  13. +29
    -0
      code/espurna/migrate.ino
  14. +1
    -0
      code/espurna/relay.ino
  15. +9
    -3
      code/espurna/sensors/CSE7766Sensor.h
  16. +3246
    -3278
      code/espurna/static/index.html.gz.h
  17. +3
    -1
      code/espurna/uartmqtt.ino
  18. +7
    -3
      code/espurna/utils.ino
  19. +1
    -1
      code/espurna/wifi.ino
  20. +2
    -0
      code/gulpfile.js
  21. +32
    -11
      code/html/custom.js
  22. +5
    -3
      code/html/index.html
  23. +2
    -2
      code/html/vendor/pure-1.0.0.min.css
  24. +2
    -2
      code/html/vendor/pure-grids-responsive-1.0.0.min.css
  25. +28
    -21
      code/ota.py
  26. +115
    -0
      code/package-lock.json
  27. +1
    -0
      code/package.json
  28. +25
    -1
      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.6-brightgreen.svg)](CHANGELOG.md)
[![version](https://img.shields.io/badge/version-1.12.7a-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)


+ 41
- 0
code/.github/stale.yml View File

@ -0,0 +1,41 @@
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 120
# Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 30
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- enhancement
- bug
- staged for release
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed in 30 days if no further activity occurs.
Thank you for your contributions.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
This issue will be auto-closed because there hasn't been any activity for a few months. Feel free to open a new one if you still experience this problem.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
only: issues

+ 1
- 0
code/espurna/config/arduino.h View File

@ -83,6 +83,7 @@
//#define ALLNET_4DUINO_IOT_WLAN_RELAIS //#define ALLNET_4DUINO_IOT_WLAN_RELAIS
//#define TONBUX_MOSQUITO_KILLER //#define TONBUX_MOSQUITO_KILLER
//#define NEO_COOLCAM_POWER_PLUG_WIFI //#define NEO_COOLCAM_POWER_PLUG_WIFI
//#define ESTINK_WIFI_POWER_STRIP
//#define PILOTAK_ESP_DIN_V1 //#define PILOTAK_ESP_DIN_V1
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------


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

@ -399,7 +399,7 @@
// General // General
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Default hostname will be ESPURNA_XXXXXX, where XXXXXX is last 3 octets of chipID
// Default hostname will be ESPURNA-XXXXXX, where XXXXXX is last 3 octets of chipID
#ifndef HOSTNAME #ifndef HOSTNAME
#define HOSTNAME "" #define HOSTNAME ""
#endif #endif


+ 5
- 1
code/espurna/config/general.h View File

@ -511,6 +511,10 @@
#define UART_MQTT_BAUDRATE 115200 // Serial speed #define UART_MQTT_BAUDRATE 115200 // Serial speed
#endif #endif
#ifndef UART_MQTT_TERMINATION
#define UART_MQTT_TERMINATION '\n' // Termination character
#endif
#define UART_MQTT_BUFFER_SIZE 100 // UART buffer size #define UART_MQTT_BUFFER_SIZE 100 // UART buffer size
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -558,9 +562,9 @@
#ifndef MQTT_AUTOCONNECT #ifndef MQTT_AUTOCONNECT
#define MQTT_AUTOCONNECT 1 // If enabled and MDNS_SERVER_SUPPORT=1 will perform an autodiscover and #define MQTT_AUTOCONNECT 1 // If enabled and MDNS_SERVER_SUPPORT=1 will perform an autodiscover and
// autoconnect to the first MQTT broker found if none defined
#endif #endif
// autoconnect to the first MQTT broker found if none defined
#ifndef MQTT_SERVER #ifndef MQTT_SERVER
#define MQTT_SERVER "" // Default MQTT broker address #define MQTT_SERVER "" // Default MQTT broker address
#endif #endif


+ 58
- 2
code/espurna/config/hardware.h View File

@ -395,8 +395,11 @@
#define RELAY1_TYPE RELAY_TYPE_NORMAL #define RELAY1_TYPE RELAY_TYPE_NORMAL
// LEDs // LEDs
#define LED1_PIN 15
#define LED1_PIN_INVERSE 0
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
// Disable UART noise
#define DEBUG_SERIAL_SUPPORT 0
// CSE7766 // CSE7766
#ifndef CSE7766_SUPPORT #ifndef CSE7766_SUPPORT
@ -2178,6 +2181,59 @@
#define LED1_PIN 4 #define LED1_PIN 4
#define LED1_PIN_INVERSE 1 #define LED1_PIN_INVERSE 1
// ------------------------------------------------------------------------------
// Estink Wifi Power Strip
// https://www.amazon.de/Steckdosenleiste-Ladeger%C3%A4t-Sprachsteuerung-SmartphonesTablets-Android/dp/B0796W5FZY
// Fornorm Wi-Fi USB Extension Socket (ZLD-34EU)
// https://www.aliexpress.com/item/Fornorm-WiFi-Extension-Socket-with-Surge-Protector-Smart-Power-Strip-3-Outlets-and-4-USB-Charging/32849743948.html
// -----------------------------------------------------------------------------
#elif defined(ESTINK_WIFI_POWER_STRIP)
// Info
#define MANUFACTURER "ESTINK"
#define DEVICE "WIFI_POWER_STRIP"
// Disable UART noise since this board uses GPIO3
#define DEBUG_SERIAL_SUPPORT 0
// Buttons
#define BUTTON1_PIN 16
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 4
// Relays
#define RELAY1_PIN 14 // USB power
#define RELAY2_PIN 13 // power plug 1
#define RELAY3_PIN 4 // power plug 2
#define RELAY4_PIN 15 // power plug 3
#define RELAY1_TYPE RELAY_TYPE_NORMAL
#define RELAY2_TYPE RELAY_TYPE_NORMAL
#define RELAY3_TYPE RELAY_TYPE_NORMAL
#define RELAY4_TYPE RELAY_TYPE_NORMAL
// LEDs
#define LED1_PIN 0 // power led
#define LED2_PIN 12 // power plug 1
#define LED3_PIN 3 // power plug 2
#define LED4_PIN 5 // power plug 3
#define LED1_PIN_INVERSE 1
#define LED2_PIN_INVERSE 1
#define LED3_PIN_INVERSE 1
#define LED4_PIN_INVERSE 1
#define LED1_MODE LED_MODE_FINDME
#define LED2_MODE LED_MODE_FOLLOW
#define LED3_MODE LED_MODE_FOLLOW
#define LED4_MODE LED_MODE_FOLLOW
#define LED2_RELAY 2
#define LED3_RELAY 3
#define LED4_RELAY 4
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// TEST boards (do not use!!) // TEST boards (do not use!!)
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 4
- 0
code/espurna/config/sensors.h View File

@ -579,6 +579,10 @@
#if SENSOR_SUPPORT #if SENSOR_SUPPORT
#if SENSOR_DEBUG
#include "../config/debug.h"
#endif
#include "../sensors/BaseSensor.h" #include "../sensors/BaseSensor.h"
#if AM2320_SUPPORT #if AM2320_SUPPORT


+ 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.6"
#define APP_VERSION "1.12.7a"
#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


+ 12
- 0
code/espurna/domoticz.ino View File

@ -43,7 +43,13 @@ void _domoticzMqtt(unsigned int type, const char * topic, const char * payload)
String dczTopicOut = getSetting("dczTopicOut", DOMOTICZ_OUT_TOPIC); String dczTopicOut = getSetting("dczTopicOut", DOMOTICZ_OUT_TOPIC);
if (type == MQTT_CONNECT_EVENT) { if (type == MQTT_CONNECT_EVENT) {
// Subscribe to domoticz action topics
mqttSubscribeRaw(dczTopicOut.c_str()); mqttSubscribeRaw(dczTopicOut.c_str());
// Send relays state on connection
domoticzSendRelays();
} }
if (type == MQTT_MESSAGE_EVENT) { if (type == MQTT_MESSAGE_EVENT) {
@ -138,6 +144,12 @@ void domoticzSendRelay(unsigned char relayID) {
domoticzSend(buffer, relayStatus(relayID) ? "1" : "0"); domoticzSend(buffer, relayStatus(relayID) ? "1" : "0");
} }
void domoticzSendRelays() {
for (uint8_t relayID=0; relayID < relayCount(); relayID++) {
domoticzSendRelay(relayID);
}
}
unsigned int domoticzIdx(unsigned char relayID) { unsigned int domoticzIdx(unsigned char relayID) {
char buffer[15]; char buffer[15];
snprintf_P(buffer, sizeof(buffer), PSTR("dczRelayIdx%u"), relayID); snprintf_P(buffer, sizeof(buffer), PSTR("dczRelayIdx%u"), relayID);


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

@ -92,7 +92,7 @@ bool idbSend(const char * topic, const char * payload) {
bool idbSend(const char * topic, unsigned char id, const char * payload) { bool idbSend(const char * topic, unsigned char id, const char * payload) {
char measurement[64]; char measurement[64];
snprintf(measurement, sizeof(measurement), "%s,id=%d", topic, id); snprintf(measurement, sizeof(measurement), "%s,id=%d", topic, id);
return idbSend(topic, payload);
return idbSend(measurement, payload);
} }
bool idbEnabled() { bool idbEnabled() {


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

@ -28,7 +28,7 @@ void _mdnsFindMQTT() {
#endif #endif
void _mdnsServerStart() { void _mdnsServerStart() {
if (MDNS.begin(WiFi.getMode() == WIFI_AP ? APP_NAME : (char *) WiFi.hostname().c_str())) {
if (MDNS.begin((char *) getSetting("hostname").c_str())) {
DEBUG_MSG_P(PSTR("[MDNS] OK\n")); DEBUG_MSG_P(PSTR("[MDNS] OK\n"));
} else { } else {
DEBUG_MSG_P(PSTR("[MDNS] FAIL\n")); DEBUG_MSG_P(PSTR("[MDNS] FAIL\n"));


+ 29
- 0
code/espurna/migrate.ino View File

@ -975,6 +975,35 @@ void migrate() {
setSetting("relayType", 0, RELAY_TYPE_NORMAL); setSetting("relayType", 0, RELAY_TYPE_NORMAL);
setSetting("relayType", 1, RELAY_TYPE_NORMAL); setSetting("relayType", 1, RELAY_TYPE_NORMAL);
#elif defined(ESTINK_WIFI_POWER_STRIP)
setSetting("board", 76);
setSetting("btnGPIO", 0, 16);
setSetting("btnRelay", 0, 3);
setSetting("ledGPIO", 0, 0);
setSetting("ledGPIO", 1, 12);
setSetting("ledGPIO", 2, 3);
setSetting("ledGPIO", 3, 5);
setSetting("ledLogic", 0, 1);
setSetting("ledLogic", 1, 1);
setSetting("ledLogic", 2, 1);
setSetting("ledLogic", 3, 1);
setSetting("ledMode", 0, LED_MODE_FINDME);
setSetting("ledMode", 1, LED_MODE_FOLLOW);
setSetting("ledMode", 2, LED_MODE_FOLLOW);
setSetting("ledMode", 3, LED_MODE_FOLLOW);
setSetting("ledRelay", 1, 1);
setSetting("ledRelay", 2, 2);
setSetting("ledRelay", 3, 3);
setSetting("relayGPIO", 0, 14);
setSetting("relayGPIO", 1, 13);
setSetting("relayGPIO", 2, 4);
setSetting("relayGPIO", 3, 15);
setSetting("relayType", 0, RELAY_TYPE_NORMAL);
setSetting("relayType", 1, RELAY_TYPE_NORMAL);
setSetting("relayType", 2, RELAY_TYPE_NORMAL);
setSetting("relayType", 3, RELAY_TYPE_NORMAL);
#else #else
// Allow users to define new settings without migration config // Allow users to define new settings without migration config


+ 1
- 0
code/espurna/relay.ino View File

@ -220,6 +220,7 @@ void relayPulse(unsigned char id) {
if (pulseStatus == status) { if (pulseStatus == status) {
_relays[id].pulseTicker.detach(); _relays[id].pulseTicker.detach();
} else { } else {
DEBUG_MSG_P(PSTR("[RELAY] Scheduling relay #%d back in %lums (pulse)\n"), id, ms);
_relays[id].pulseTicker.once_ms(ms, relayToggle, id); _relays[id].pulseTicker.once_ms(ms, relayToggle, id);
} }


+ 9
- 3
code/espurna/sensors/CSE7766Sensor.h View File

@ -270,10 +270,16 @@ class CSE7766Sensor : public BaseSensor {
} }
// Calculate energy // Calculate energy
static unsigned long cf_pulses_last = 0;
unsigned long cf_pulses = _data[21] << 8 | _data[22];
unsigned int difference;
static unsigned int cf_pulses_last = 0;
unsigned int cf_pulses = _data[21] << 8 | _data[22];
if (0 == cf_pulses_last) cf_pulses_last = cf_pulses; if (0 == cf_pulses_last) cf_pulses_last = cf_pulses;
_energy += (cf_pulses - cf_pulses_last) * (float) _coefP / 1000000.0;
if (cf_pulses < cf_pulses_last) {
difference = cf_pulses + (0xFFFF - cf_pulses_last) + 1;
} else {
difference = cf_pulses - cf_pulses_last;
}
_energy += difference * (float) _coefP / 1000000.0;
cf_pulses_last = cf_pulses; cf_pulses_last = cf_pulses;
} }


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


+ 3
- 1
code/espurna/uartmqtt.ino View File

@ -32,15 +32,17 @@ void _uartmqttReceiveUART() {
char rc = UART_MQTT_PORT.read(); char rc = UART_MQTT_PORT.read();
if (rc != '\n') {
if (rc != UART_MQTT_TERMINATION) {
_uartmqttBuffer[ndx] = rc; _uartmqttBuffer[ndx] = rc;
if (ndx < UART_MQTT_BUFFER_SIZE - 1) ndx++; if (ndx < UART_MQTT_BUFFER_SIZE - 1) ndx++;
} else { } else {
_uartmqttBuffer[ndx] = '\0'; _uartmqttBuffer[ndx] = '\0';
_uartmqttNewData = true; _uartmqttNewData = true;
ndx = 0; ndx = 0;
} }
} }


+ 7
- 3
code/espurna/utils.ino View File

@ -11,7 +11,7 @@ Ticker _defer_reset;
String getIdentifier() { String getIdentifier() {
char buffer[20]; char buffer[20];
snprintf_P(buffer, sizeof(buffer), PSTR("%s_%06X"), APP_NAME, ESP.getChipId());
snprintf_P(buffer, sizeof(buffer), PSTR("%s-%06X"), APP_NAME, ESP.getChipId());
return String(buffer); return String(buffer);
} }
@ -52,6 +52,10 @@ String getCoreRevision() {
#endif #endif
} }
unsigned long maxSketchSpace() {
return (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
}
// WTF // WTF
// Calling ESP.getFreeHeap() is making the system crash on a specific // Calling ESP.getFreeHeap() is making the system crash on a specific
// AiLight bulb, but anywhere else... // AiLight bulb, but anywhere else...
@ -235,9 +239,9 @@ void info() {
DEBUG_MSG_P(PSTR("[INIT] Flash size (CHIP): %8u bytes\n"), ESP.getFlashChipRealSize()); 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] 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] Firmware size: %8u bytes / %4d sectors\n"), ESP.getSketchSize(), sectors(ESP.getSketchSize()));
DEBUG_MSG_P(PSTR("[INIT] OTA size: %8u bytes / %4d sectors\n"), ESP.getFreeSketchSpace(), sectors(ESP.getFreeSketchSpace()));
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] 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);
DEBUG_MSG_P(PSTR("[INIT] Empty space: %8u bytes / 4 sectors\n"), 4 * SPI_FLASH_SEC_SIZE);
DEBUG_MSG_P(PSTR("\n")); DEBUG_MSG_P(PSTR("\n"));
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------


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

@ -417,7 +417,7 @@ void wifiStatus() {
DEBUG_MSG_P(PSTR("[WIFI] GW %s\n"), WiFi.gatewayIP().toString().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] 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] MASK %s\n"), WiFi.subnetMask().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] HOST %s\n"), WiFi.hostname().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"), 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] bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], bssid[6]
); );


+ 2
- 0
code/gulpfile.js View File

@ -38,6 +38,7 @@ const htmllint = require('gulp-htmllint');
const log = require('fancy-log'); const log = require('fancy-log');
const csslint = require('gulp-csslint'); const csslint = require('gulp-csslint');
const crass = require('gulp-crass'); const crass = require('gulp-crass');
const replace = require('gulp-replace');
const dataFolder = 'espurna/data/'; const dataFolder = 'espurna/data/';
const staticFolder = 'espurna/static/'; const staticFolder = 'espurna/static/';
@ -126,6 +127,7 @@ gulp.task('buildfs_inline', function() {
minifyCSS: true, minifyCSS: true,
minifyJS: true minifyJS: true
})). })).
pipe(replace('pure-', 'p-')).
pipe(gzip()). pipe(gzip()).
pipe(gulp.dest(dataFolder)); pipe(gulp.dest(dataFolder));
}); });


+ 32
- 11
code/html/custom.js View File

@ -102,14 +102,6 @@ function keepTime() {
} }
// http://www.the-art-of-web.com/javascript/validate-password/
function checkPassword(str) {
// at least one lowercase and one uppercase letter or number
// at least five characters (letters, numbers or special characters)
var re = /^(?=.*[A-Z\d])(?=.*[a-z])[\w~!@#$%^&*\(\)<>,.\?;:{}\[\]\\|]{5,}$/;
return re.test(str);
}
function zeroPad(number, positions) { function zeroPad(number, positions) {
var zeros = ""; var zeros = "";
for (var i = 0; i < positions; i++) { for (var i = 0; i < positions; i++) {
@ -147,9 +139,14 @@ function loadTimeZones() {
function validateForm(form) { function validateForm(form) {
// http://www.the-art-of-web.com/javascript/validate-password/
// at least one lowercase and one uppercase letter or number
// at least five characters (letters, numbers or special characters)
var re_password = /^(?=.*[A-Z\d])(?=.*[a-z])[\w~!@#$%^&*\(\)<>,.\?;:{}\[\]\\|]{5,}$/;
// password // password
var adminPass1 = $("input[name='adminPass']", form).first().val(); var adminPass1 = $("input[name='adminPass']", form).first().val();
if (adminPass1.length > 0 && !checkPassword(adminPass1)) {
if (adminPass1.length > 0 && !re_password.test(adminPass1)) {
alert("The password you have entered is not valid, it must have at least 5 characters, 1 lowercase and 1 uppercase or number!"); alert("The password you have entered is not valid, it must have at least 5 characters, 1 lowercase and 1 uppercase or number!");
return false; return false;
} }
@ -160,6 +157,23 @@ function validateForm(form) {
return false; return false;
} }
// RFCs mandate that a hostname's labels may contain only
// the ASCII letters 'a' through 'z' (case-insensitive),
// the digits '0' through '9', and the hyphen.
// Hostname labels cannot begin or end with a hyphen.
// No other symbols, punctuation characters, or blank spaces are permitted.
// Negative lookbehind does not work in Javascript
// var re_hostname = new RegExp('^(?!-)[A-Za-z0-9-]{1,32}(?<!-)$');
var re_hostname = new RegExp('^(?!-)[A-Za-z0-9-]{0,31}[A-Za-z0-9]$');
var hostname = $("input[name='hostname']", form).val();
if (!re_hostname.test(hostname)) {
alert("Hostname cannot be empty and may only contain the ASCII letters ('A' through 'Z' and 'a' through 'z'), the digits '0' through '9', and the hyphen ('-')! They can neither start or end with an hyphen.");
return false;
}
return true; return true;
} }
@ -874,8 +888,9 @@ function initChannels(num) {
}; };
// add templates // add templates
var i = 0;
var template = $("#channelTemplate").children(); var template = $("#channelTemplate").children();
for (var i=0; i<max; i++) {
for (i=0; i<max; i++) {
var channel_id = start + i; var channel_id = start + i;
var line = $(template).clone(); var line = $(template).clone();
@ -887,7 +902,7 @@ function initChannels(num) {
} }
for (var i=0; i<num; i++) {
for (i=0; i<num; i++) {
$("select.islight").append( $("select.islight").append(
$("<option></option>").attr("value",i).text("Channel #" + i)); $("<option></option>").attr("value",i).text("Channel #" + i));
} }
@ -1214,6 +1229,12 @@ function processData(data) {
return; return;
} }
if ("deviceip" === key) {
var a_href = $("span[name='" + key + "']").parent();
a_href.attr("href", "http://" + value);
a_href.next().attr("href", "telnet://" + value);
}
if ("now" === key) { if ("now" === key) {
now = value; now = value;
return; return;


+ 5
- 3
code/html/index.html View File

@ -242,7 +242,7 @@
<div class="pure-u-11-24"><span class="right" name="rssi"></span></div> <div class="pure-u-11-24"><span class="right" name="rssi"></span></div>
<div class="pure-u-1-2">IP</div> <div class="pure-u-1-2">IP</div>
<div class="pure-u-11-24"><span class="right" name="deviceip"></span></div>
<div class="pure-u-11-24"><a href=""><span class="right" name="deviceip"></span></a> (<a href=""><span class="right">telnet</span></a>)</div>
<div class="pure-u-1-2">Free heap</div> <div class="pure-u-1-2">Free heap</div>
<div class="pure-u-11-24"><span class="right" name="heap" post=" bytes"></span></div> <div class="pure-u-11-24"><span class="right" name="heap" post=" bytes"></span></div>
@ -295,7 +295,9 @@
<div class="pure-u-0 pure-u-lg-1-2"></div> <div class="pure-u-0 pure-u-lg-1-2"></div>
<div class="pure-u-0 pure-u-lg-1-4"></div> <div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint"> <div class="pure-u-1 pure-u-lg-3-4 hint">
This name will identify this device in your network (http://&lt;hostname&gt;.local). For this setting to take effect you should restart the wifi interface by clicking the "Reconnect" button.
This name will identify this device in your network (http://&lt;hostname&gt;.local).<br />
Hostname may contain only the ASCII letters 'a' through 'z' (in a case-insensitive manner), the digits '0' through '9', and the hyphen ('-'). They can neither start or end with an hyphen.<br />
For this setting to take effect you should restart the wifi interface by clicking the "Reconnect" button.
</div> </div>
</div> </div>
@ -1349,7 +1351,7 @@
</div> </div>
<div class="pure-g module module-mqtt"> <div class="pure-g module module-mqtt">
<div class="pure-u-1 pure-u-lg-1-4"><label>On MQTT disconnect</label></div> <div class="pure-u-1 pure-u-lg-1-4"><label>On MQTT disconnect</label></div>
<select class="pure-u-1 pure-u-lg-3-4" name="mqttOnDisc">
<select class="pure-u-1 pure-u-lg-3-4" name="relayOnDisc">
<option value="0">Don't change</option> <option value="0">Don't change</option>
<option value="1">Turn the switch OFF</option> <option value="1">Turn the switch OFF</option>
<option value="2">Turn the switch ON</option> <option value="2">Turn the switch ON</option>


+ 2
- 2
code/html/vendor/pure-1.0.0.min.css
File diff suppressed because it is too large
View File


+ 2
- 2
code/html/vendor/pure-grids-responsive-1.0.0.min.css
File diff suppressed because it is too large
View File


+ 28
- 21
code/ota.py View File

@ -13,7 +13,7 @@ import re
import socket import socket
import subprocess import subprocess
import sys import sys
from time import sleep
import time
from zeroconf import ServiceBrowser, ServiceStateChange, Zeroconf from zeroconf import ServiceBrowser, ServiceStateChange, Zeroconf
@ -25,9 +25,11 @@ except NameError:
# ------------------------------------------------------------------------------- # -------------------------------------------------------------------------------
devices = []
description = "ESPurna OTA Manager v0.1"
DISCOVER_TIMEOUT = 2
description = "ESPurna OTA Manager v0.2"
devices = []
discover_last = 0
# ------------------------------------------------------------------------------- # -------------------------------------------------------------------------------
@ -37,23 +39,26 @@ def on_service_state_change(zeroconf, service_type, name, state_change):
""" """
if state_change is ServiceStateChange.Added: if state_change is ServiceStateChange.Added:
discover_last = time.time()
info = zeroconf.get_service_info(service_type, name) info = zeroconf.get_service_info(service_type, name)
if info: if info:
hostname = info.server.split(".")[0] hostname = info.server.split(".")[0]
device = { device = {
'hostname': hostname.upper(), 'hostname': hostname.upper(),
'ip': socket.inet_ntoa(info.address)
'ip': socket.inet_ntoa(info.address),
'mac': '',
'app_name': '',
'app_version': '',
'target_board': '',
'mem_size': '',
'sdk_size': '',
'free_space': '',
} }
device['mac'] = info.properties.get('mac', '')
device['app'] = info.properties.get('app_name', '')
device['version'] = info.properties.get('app_version', '')
device['device'] = info.properties.get('target_board', '')
if 'mem_size' in info.properties:
device['mem_size'] = info.properties.get('mem_size')
if 'sdk_size' in info.properties:
device['sdk_size'] = info.properties.get('sdk_size')
if 'free_space' in info.properties:
device['free_space'] = info.properties.get('free_space')
for key, item in info.properties.items():
device[key.decode('UTF-8')] = item.decode('UTF-8');
devices.append(device) devices.append(device)
@ -84,9 +89,9 @@ def list_devices():
device.get('hostname', ''), device.get('hostname', ''),
device.get('ip', ''), device.get('ip', ''),
device.get('mac', ''), device.get('mac', ''),
device.get('app', ''),
device.get('version', ''),
device.get('device', ''),
device.get('app_name', ''),
device.get('app_version', ''),
device.get('target_board', ''),
device.get('mem_size', ''), device.get('mem_size', ''),
device.get('sdk_size', ''), device.get('sdk_size', ''),
device.get('free_space', ''), device.get('free_space', ''),
@ -121,7 +126,7 @@ def get_board_by_index(index):
if 1 <= index and index <= len(devices): if 1 <= index and index <= len(devices):
device = devices[index - 1] device = devices[index - 1]
board['hostname'] = device.get('hostname') board['hostname'] = device.get('hostname')
board['board'] = device.get('device', '')
board['board'] = device.get('target_board', '')
board['ip'] = device.get('ip', '') board['ip'] = device.get('ip', '')
board['size'] = int(device.get('mem_size', 0) if device.get('mem_size', 0) == device.get('sdk_size', 0) else 0) / 1024 board['size'] = int(device.get('mem_size', 0) if device.get('mem_size', 0) == device.get('sdk_size', 0) else 0) / 1024
return board return board
@ -135,7 +140,7 @@ def get_board_by_hostname(hostname):
if device.get('hostname', '').lower() == hostname: if device.get('hostname', '').lower() == hostname:
board = {} board = {}
board['hostname'] = device.get('hostname') board['hostname'] = device.get('hostname')
board['board'] = device.get('device')
board['board'] = device.get('target_board')
if not board['board']: if not board['board']:
return None return None
board['ip'] = device.get('ip') board['ip'] = device.get('ip')
@ -226,8 +231,10 @@ if __name__ == '__main__':
# Look for sevices # Look for sevices
zeroconf = Zeroconf() zeroconf = Zeroconf()
browser = ServiceBrowser(zeroconf, "_arduino._tcp.local.", handlers=[on_service_state_change]) browser = ServiceBrowser(zeroconf, "_arduino._tcp.local.", handlers=[on_service_state_change])
sleep(5)
zeroconf.close()
discover_last = time.time()
while time.time() < discover_last + DISCOVER_TIMEOUT:
None
#zeroconf.close()
if len(devices) == 0: if len(devices) == 0:
print("Nothing found!\n") print("Nothing found!\n")


+ 115
- 0
code/package-lock.json View File

@ -238,6 +238,12 @@
"integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=",
"dev": true "dev": true
}, },
"binaryextensions": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz",
"integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==",
"dev": true
},
"boolbase": { "boolbase": {
"version": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "version": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
@ -944,6 +950,12 @@
"jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" "jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz"
} }
}, },
"editions": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz",
"integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==",
"dev": true
},
"end-of-stream": { "end-of-stream": {
"version": "0.1.5", "version": "0.1.5",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz",
@ -1708,6 +1720,49 @@
"through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz" "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz"
} }
}, },
"gulp-replace": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz",
"integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==",
"dev": true,
"requires": {
"istextorbinary": "2.2.1",
"readable-stream": "2.3.6",
"replacestream": "4.0.3"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
"core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"isarray": "1.0.0",
"process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"string_decoder": "1.1.1",
"util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
}
}
}
},
"gulp-uglify": { "gulp-uglify": {
"version": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-1.5.4.tgz", "version": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-1.5.4.tgz",
"integrity": "sha1-UkeI2HZm0J+dDCH7IXf5ADmmWMk=", "integrity": "sha1-UkeI2HZm0J+dDCH7IXf5ADmmWMk=",
@ -2227,6 +2282,17 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true "dev": true
}, },
"istextorbinary": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz",
"integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==",
"dev": true,
"requires": {
"binaryextensions": "2.1.1",
"editions": "1.3.4",
"textextensions": "2.2.0"
}
},
"js-yaml": { "js-yaml": {
"version": "3.7.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
@ -3136,6 +3202,49 @@
"integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
"dev": true "dev": true
}, },
"replacestream": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz",
"integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==",
"dev": true,
"requires": {
"escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"readable-stream": "2.3.6"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
"core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"isarray": "1.0.0",
"process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"string_decoder": "1.1.1",
"util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
}
}
}
},
"request": { "request": {
"version": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", "version": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
"integrity": "sha1-ygtl2gLtYpNYh4COb1EDgQNOM1Y=", "integrity": "sha1-ygtl2gLtYpNYh4COb1EDgQNOM1Y=",
@ -3675,6 +3784,12 @@
"upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz"
} }
}, },
"textextensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz",
"integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==",
"dev": true
},
"through": { "through": {
"version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",


+ 1
- 0
code/package.json View File

@ -17,6 +17,7 @@
"gulp-htmllint": "0.0.14", "gulp-htmllint": "0.0.14",
"gulp-htmlmin": "^2.0.0", "gulp-htmlmin": "^2.0.0",
"gulp-inline": "^0.1.1", "gulp-inline": "^0.1.1",
"gulp-replace": "^1.0.0",
"gulp-uglify": "^1.5.3" "gulp-uglify": "^1.5.3"
} }
} }

+ 25
- 1
code/platformio.ini View File

@ -64,7 +64,7 @@ lib_deps =
https://bitbucket.org/xoseperez/fauxmoesp.git#2.4.2 https://bitbucket.org/xoseperez/fauxmoesp.git#2.4.2
https://github.com/xoseperez/hlw8012.git#1.1.0 https://github.com/xoseperez/hlw8012.git#1.1.0
https://github.com/markszabo/IRremoteESP8266#v2.2.0 https://github.com/markszabo/IRremoteESP8266#v2.2.0
https://bitbucket.org/xoseperez/justwifi.git#1.1.9
https://github.com/xoseperez/justwifi.git#1.2.0
https://github.com/madpilot/mDNSResolver#4cfcda1 https://github.com/madpilot/mDNSResolver#4cfcda1
https://github.com/xoseperez/my92xx#3.0.1 https://github.com/xoseperez/my92xx#3.0.1
https://bitbucket.org/xoseperez/nofuss.git#0.2.5 https://bitbucket.org/xoseperez/nofuss.git#0.2.5
@ -2005,6 +2005,30 @@ upload_port = "${env.ESPURNA_IP}"
upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266 upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266
extra_scripts = ${common.extra_scripts} extra_scripts = ${common.extra_scripts}
[env:estink-wifi-power-strip]
platform = ${common.platform}
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DESTINK_WIFI_POWER_STRIP
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:estink-wifi-power-strip-ota]
platform = ${common.platform}
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DESTINK_WIFI_POWER_STRIP
upload_speed = 115200
upload_port = "${env.ESPURNA_IP}"
upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# GENERIC OTA ENVIRONMENTS # GENERIC OTA ENVIRONMENTS
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------


Loading…
Cancel
Save