Browse Source

Merge remote-tracking branch 'remotes/upstream/dev' into dev

# Conflicts:
#	code/espurna/config/version.h
#	code/espurna/data/index.html.gz
#	code/espurna/espurna.ino
#	code/espurna/static/index.html.gz.h
#	code/extra_scripts.py
#	code/html/index.html
#	code/ota.py
#	code/platformio.ini
i18n
Stefano Cotterli 6 years ago
parent
commit
2d5e14b3a3
74 changed files with 3558 additions and 2803 deletions
  1. +2
    -0
      .gitignore
  2. +25
    -0
      CHANGELOG.md
  3. +9
    -5
      README.md
  4. +1
    -1
      code/espurna/alexa.ino
  5. +1
    -1
      code/espurna/api.ino
  6. +16
    -9
      code/espurna/ascheduler.ino
  7. +2
    -2
      code/espurna/button.ino
  8. +4
    -1
      code/espurna/config/arduino.h
  9. +65
    -4
      code/espurna/config/general.h
  10. +61
    -0
      code/espurna/config/hardware.h
  11. +9
    -4
      code/espurna/config/sensors.h
  12. +1
    -1
      code/espurna/config/version.h
  13. BIN
      code/espurna/data/index.html.gz
  14. +7
    -7
      code/espurna/debug.ino
  15. +2
    -2
      code/espurna/domoticz.ino
  16. +12
    -4
      code/espurna/espurna.ino
  17. +1
    -1
      code/espurna/filters/BaseFilter.h
  18. +1
    -1
      code/espurna/filters/MaxFilter.h
  19. +1
    -1
      code/espurna/filters/MedianFilter.h
  20. +1
    -1
      code/espurna/filters/MovingAverageFilter.h
  21. +1
    -1
      code/espurna/gpio.ino
  22. +1
    -1
      code/espurna/homeassitant.ino
  23. +1
    -1
      code/espurna/i2c.ino
  24. +2
    -2
      code/espurna/influxdb.ino
  25. +2
    -2
      code/espurna/ir.ino
  26. +1
    -1
      code/espurna/led.ino
  27. +1
    -1
      code/espurna/light.ino
  28. +1
    -1
      code/espurna/llmnr.ino
  29. +7
    -2
      code/espurna/mdns.ino
  30. +16
    -1
      code/espurna/migrate.ino
  31. +7
    -48
      code/espurna/mqtt.ino
  32. +1
    -1
      code/espurna/netbios.ino
  33. +1
    -1
      code/espurna/nofuss.ino
  34. +1
    -1
      code/espurna/ntp.ino
  35. +4
    -2
      code/espurna/ota.ino
  36. +6
    -1
      code/espurna/relay.ino
  37. +1
    -1
      code/espurna/rf.ino
  38. +1
    -1
      code/espurna/rfbridge.ino
  39. +47
    -1
      code/espurna/sensor.ino
  40. +11
    -1
      code/espurna/sensors/AnalogSensor.h
  41. +1
    -1
      code/espurna/sensors/BH1750Sensor.h
  42. +2
    -2
      code/espurna/sensors/BMX280Sensor.h
  43. +7
    -4
      code/espurna/sensors/BaseSensor.h
  44. +11
    -1
      code/espurna/sensors/DHTSensor.h
  45. +14
    -1
      code/espurna/sensors/DallasSensor.h
  46. +11
    -1
      code/espurna/sensors/DigitalSensor.h
  47. +13
    -1
      code/espurna/sensors/ECH1560Sensor.h
  48. +1
    -1
      code/espurna/sensors/EmonADC121Sensor.h
  49. +9
    -1
      code/espurna/sensors/EmonADS1X15Sensor.h
  50. +6
    -1
      code/espurna/sensors/EmonAnalogSensor.h
  51. +1
    -1
      code/espurna/sensors/EmonSensor.h
  52. +11
    -1
      code/espurna/sensors/EventSensor.h
  53. +13
    -1
      code/espurna/sensors/HLW8012Sensor.h
  54. +13
    -1
      code/espurna/sensors/I2CSensor.h
  55. +13
    -1
      code/espurna/sensors/MHZ19Sensor.h
  56. +7
    -0
      code/espurna/sensors/PMSX003Sensor.h
  57. +1
    -1
      code/espurna/sensors/SHT3XI2CSensor.h
  58. +6
    -1
      code/espurna/sensors/SI7021Sensor.h
  59. +11
    -1
      code/espurna/sensors/V9261FSensor.h
  60. +19
    -1
      code/espurna/settings.ino
  61. +1
    -1
      code/espurna/ssdp.ino
  62. +2565
    -2570
      code/espurna/static/index.html.gz.h
  63. +1
    -1
      code/espurna/telnet.ino
  64. +265
    -0
      code/espurna/thinkspeak.ino
  65. +56
    -1
      code/espurna/utils.ino
  66. +9
    -5
      code/espurna/web.ino
  67. +6
    -2
      code/espurna/wifi.ino
  68. +5
    -3
      code/espurna/ws.ino
  69. +5
    -3
      code/extra_scripts.py
  70. +1
    -1
      code/gulpfile.js
  71. +34
    -15
      code/html/custom.js
  72. +65
    -57
      code/html/index.html
  73. +15
    -4
      code/ota.py
  74. +26
    -1
      code/platformio.ini

+ 2
- 0
.gitignore View File

@ -12,3 +12,5 @@ credentials.h
node_modules
code/utils
custom.h
.python
.env

+ 25
- 0
CHANGELOG.md View File

@ -3,6 +3,31 @@
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.11.4] 2018-01-09
### Fixed
- Fix bug in RF Bridge when RF code contains the stop byte. Check overflow (#357)
- Fixed typos in code and wiki (Thanks to Ryan Jarvis)
- Fix bug in magnitude topic and units (#355)
### Added
- Small core build to allow two-step flashing method for big binaries
- Thingspeak support (#371, disabled by default)
- Color synchronization between lights using MQTT (#362)
- Support for Arilux AL-LC02 (#347)
- Support for Tarpuna Shield for Wemos D1
- Build option to disable password checking (#373)
- Option to report sensor address via MQTT (#377, I2C address, GPIO, Dallas address,...)
- Added binary size to memanalyzer script
- Option to specify custom client ID for MQTT connection (#368)
- Cross-platform ESPurna OTA Manager implemented in python (untested)
- Terminal command to get or set digital GPIO
### Changed
- Using 2.3.0 for prebuilt binaries
- Fix delay in DHT sensor
- Allow MQTT keep alive value of up to 3600s
- Changed Sonoff 4CH Pro definitions to support built-in interlock mode (#333)
## [1.11.3] 2018-01-02
### Fixed
- Fix uninitialized PWM channels bug (#356)


+ 9
- 5
README.md View File

@ -4,7 +4,7 @@ ESPurna ("spark" in Catalan) is a custom firmware for ESP8266 based smart switch
It was originally developed with the **[IteadStudio Sonoff](https://www.itead.cc/sonoff-wifi-wireless-switch.html)** in mind but now it supports a growing number of ESP8266-based boards.
It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
> **Current Release Version is 1.11.3**, read the [changelog](https://bitbucket.org/xoseperez/espurna/src/master/CHANGELOG.md).
> **Current Release Version is 1.11.4**, read the [changelog](https://bitbucket.org/xoseperez/espurna/src/master/CHANGELOG.md).
> **NOTICE**: Default flash layout changed in 1.8.3, as an unpredicted consequence devices will not be able to persist/retrieve configuration if flashed with 1.8.3 via **OTA** from **PlatformIO**. Please check issue #187.
@ -37,6 +37,7 @@ It uses the Arduino Core for ESP8266 framework and a number of 3rd party librari
* Enable/disable pulse mode
* Change LED notification mode
* Remote reset the board
* Fully configurable in webUI (broker, user, password, QoS, keep alive time, retain flag, client ID)
* **Alexa** integration using the [FauxmoESP Library](https://bitbucket.org/xoseperez/fauxmoesp)
* [**Google Assistant**](http://tinkerman.cat/using-google-assistant-control-your-esp8266-devices/) integration using IFTTT and Webhooks (Google Home, Allo)
* [**Domoticz**](https://domoticz.com/) integration via MQTT
@ -45,13 +46,14 @@ It uses the Arduino Core for ESP8266 framework and a number of 3rd party librari
* Support for lights (color, brightness, on/off state)
* Supports MQTT auto-discover feature (both switches and lights)
* [**InfluxDB**](https://www.influxdata.com/) integration via HTTP API
* [**Thingspeak**](https://thingspeak.com/) integration via HTTP API (HTTPS available for custom builds)
* Support for different **sensors**
* Environment
* **DHT11 / DHT22 / DHT21 / AM2301 / Itead's SI7021** (supports celsius & fahrenheit reporting)
* **DHT11 / DHT22 / DHT21 / AM2301 / Itead's SI7021**
* **BMP280** and **BME280** temperature, humidity (BME280) and pressure sensor by Bosch
* **SI7021** temperature and humidity sensor
* **SHT3X** temperature and humidity sensor over I2C (Wemos shield)
* **Dallas OneWire sensors** like the DS18B20 (supports celsius & fahrenheit reporting)
* **Dallas OneWire sensors** like the DS18B20
* **MHZ19** CO2 sensor
* **PMSX003** dust sensor
* **BH1750** luminosity sensor
@ -62,6 +64,7 @@ It uses the Arduino Core for ESP8266 framework and a number of 3rd party librari
* **V9261F** power monitor chip
* Raw analog and digital sensors
* Simple pulse counter
* All temperature sensors support Fahrenheit and Celsius
* Support for LED lights
* MY92XX-based light bulbs and PWM LED strips (dimmers) up to 5 channels (RGB, cold white and warm white, for instance)
* RGB and HSV color codes supported
@ -69,6 +72,7 @@ It uses the Arduino Core for ESP8266 framework and a number of 3rd party librari
* Temperature color supported (in mired and kelvin) via MQTT / REST API
* Flicker-free PWM management
* Soft color transitions
* Color synchronization between light using MQTT
* Fast asynchronous **HTTP Server**
* Configurable port
* Basic authentication
@ -139,11 +143,11 @@ Here is the list of supported hardware. For more information please refer to the
|![EXS Wifi Relay v3.1](images/devices/exs-wifi-relay-v31.jpg)|||
|**EXS Wifi Relay v3.1**|||
**Other supported boards:** Itead Sonoff LED, Itead Sonoff Dual R2, Huacanxing H802, WiOn 50055, ManCaveMade ESP-Live, InterMitTech QuinLED 2.6, Arilux AL-LC01, Arilux AL-LC06, Arilux AL-LC11, Arilux E27 light bulb, Xenon SM-PW702U, Authometion LYT8266, YJZK 2-gang switch.
**Other supported boards:** Itead Sonoff LED, Itead Sonoff Dual R2, Huacanxing H802, WiOn 50055, ManCaveMade ESP-Live, InterMitTech QuinLED 2.6, Arilux AL-LC01, Arilux AL-LC02, Arilux AL-LC06, Arilux AL-LC11, Arilux E27 light bulb, Xenon SM-PW702U, Authometion LYT8266, YJZK 2-gang switch.
## License
Copyright (C) 2016-2017 by Xose Pérez (@xoseperez)
Copyright (C) 2016-2018 by Xose Pérez (@xoseperez)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by


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

@ -2,7 +2,7 @@
ALEXA MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -2,7 +2,7 @@
API MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


+ 16
- 9
code/espurna/ascheduler.ino View File

@ -50,7 +50,9 @@ void schLoop(){
if ((millis() - last_update > ((SCH_UPDATE_SEC + 60 - sec)*1000)) || (last_update == 0)) {
last_update = millis();
if (!ntpConnected()){
DEBUG_MSG_P(PSTR("[SCH] no NTP\n"));
time_t t = now();
sec = second(t);
DEBUG_MSG_P(PSTR("[SCH] no NTP, time now=%02d:%02d:%02d\n"),hour(t),minute(t),second(t));
}
else {
// compare at next minute and SCH_UPDATE_SEC seconds
@ -96,13 +98,18 @@ bool isThisWday(String weekdays){
}
int diffTime(int schhour, int schminute){
if (!ntpConnected())
return 9999; //NTP time not set
String value = NTP.getTimeDateString();
int hour = value.substring(0, 2).toInt();
int minute = value.substring(3, 5).toInt();
//DEBUG_MSG_P(PSTR("[SCH] ntp time: %02d:%02d\n"), hour, minute);
//DEBUG_MSG_P(PSTR("[SCH] cmp time: %02d:%02d\n"), schhour, schminute);
return (hour - schhour) * 60 + minute - schminute;
if (!ntpConnected()){
time_t t = now();
DEBUG_MSG_P(PSTR("[SCH] no NTP time = %02d:%02d:%02d\n"),hour(t),minute(t),second(t));
return (hour(t) - schhour) * 60 + minute(t) - schminute;
}
else {
String value = NTP.getTimeDateString();
int hour = value.substring(0, 2).toInt();
int minute = value.substring(3, 5).toInt();
//DEBUG_MSG_P(PSTR("[SCH] ntp time: %02d:%02d\n"), hour, minute);
//DEBUG_MSG_P(PSTR("[SCH] cmp time: %02d:%02d\n"), schhour, schminute);
return (hour - schhour) * 60 + minute - schminute;
}
}
#endif

+ 2
- 2
code/espurna/button.ino View File

@ -2,7 +2,7 @@
BUTTON MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -80,7 +80,7 @@ uint8_t mapEvent(uint8_t event, uint8_t count, uint16_t length) {
void buttonEvent(unsigned int id, unsigned char event) {
DEBUG_MSG_P(PSTR("[BUTTON] Pressed #%d, event: %d\n"), id, event);
DEBUG_MSG_P(PSTR("[BUTTON] Button #%d event %d\n"), id, event);
if (event == 0) return;
#if MQTT_SUPPORT


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

@ -57,6 +57,8 @@
//#define GENERIC_8CH
//#define ARILUX_AL_LC01
//#define ARILUX_AL_LC11
//#define ARILUX_AL_LC02
//#define WEMOS_D1_TARPUNA_SHIELD
//--------------------------------------------------------------------------------
// Features (values below are non-default values)
@ -69,7 +71,7 @@
//#define DOMOTICZ_SUPPORT 0
//#define HOMEASSISTANT_SUPPORT 0
//#define I2C_SUPPORT 1
//#define INFLUXDB_SUPPORT 0
//#define INFLUXDB_SUPPORT 1
//#define IR_SUPPORT 1
//#define LLMNR_SUPPORT 1 // Only with Arduino Core 2.4.0
//#define MDNS_SUPPORT 0
@ -82,6 +84,7 @@
//#define SSDP_SUPPORT 1
//#define TELNET_SUPPORT 0
//#define TERMINAL_SUPPORT 0
//#define THINGSPEAK_SUPPORT 0
//#define WEB_SUPPORT 0
//--------------------------------------------------------------------------------


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

@ -7,13 +7,29 @@
// GENERAL
//------------------------------------------------------------------------------
#define DEVICE_NAME MANUFACTURER "_" DEVICE // Concatenate both to get a unique device name
#define ADMIN_PASS "fibonacci" // Default password (WEB, OTA, WIFI)
#define DEVICE_NAME MANUFACTURER "_" DEVICE // Concatenate both to get a unique device name
#define USE_PASSWORD 1 // Insecurity caution! Disabling this will disable password querying completely.
#define LOOP_DELAY_TIME 10 // Delay for this millis in the main loop [0-250]
#define ARRAYINIT(type, name, ...) \
type name[] = {__VA_ARGS__};
//------------------------------------------------------------------------------
// ESPURNA CORE
//------------------------------------------------------------------------------
#ifdef ESPURNA_CORE
#define ALEXA_SUPPORT 0
#define DOMOTICZ_SUPPORT 0
#define HOMEASSISTANT_SUPPORT 0
#define MQTT_SUPPORT 0
#define NTP_SUPPORT 0
#define WEB_SUPPORT 0
#define SENSOR_SUPPORT 0
#define I2C_SUPPORT 0
#endif
//------------------------------------------------------------------------------
// TELNET
//------------------------------------------------------------------------------
@ -74,7 +90,6 @@
//------------------------------------------------------------------------------
// General debug options and macros
#define DEBUG_FORMAT_MAX_LENGTH 80
#define DEBUG_SUPPORT DEBUG_SERIAL_SUPPORT || DEBUG_UDP_SUPPORT || DEBUG_TELNET_SUPPORT
#if DEBUG_SUPPORT
@ -179,10 +194,21 @@ PROGMEM const char* const custom_reset_string[] = {
// BUTTON
//------------------------------------------------------------------------------
#ifndef BUTTON_DEBOUNCE_DELAY
#define BUTTON_DEBOUNCE_DELAY 50 // Debounce delay (ms)
#endif
#ifndef BUTTON_DBLCLICK_DELAY
#define BUTTON_DBLCLICK_DELAY 500 // Time in ms to wait for a second (or third...) click
#endif
#ifndef BUTTON_LNGCLICK_DELAY
#define BUTTON_LNGCLICK_DELAY 1000 // Time in ms holding the button down to get a long click
#endif
#ifndef BUTTON_LNGLNGCLICK_DELAY
#define BUTTON_LNGLNGCLICK_DELAY 10000 // Time in ms holding the button down to get a long-long click
#endif
#define BUTTON_EVENT_NONE 0
#define BUTTON_EVENT_PRESSED 1
@ -305,7 +331,7 @@ PROGMEM const char* const custom_reset_string[] = {
#endif
// This is not working at the moment!!
// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core staging version.
// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0
#define WEB_SSL_ENABLED 0 // Use HTTPS web interface
#define WEB_MODE_NORMAL 0
@ -404,7 +430,7 @@ PROGMEM const char* const custom_reset_string[] = {
// MQTT OVER SSL
// Using MQTT over SSL works pretty well but generates problems with the web interface.
// It could be a good idea to use it in conjuntion with WEB_SUPPORT=0.
// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core staging version.
// Requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0.
//
// You can use it with MQTT_USE_ASYNC=1 (AsyncMqttClient library)
// but you might experience hiccups on the web interface, so my recommendation is:
@ -611,6 +637,41 @@ PROGMEM const char* const custom_reset_string[] = {
#define INFLUXDB_USERNAME "" // Default username
#define INFLUXDB_PASSWORD "" // Default password
// -----------------------------------------------------------------------------
// THINGSPEAK
// -----------------------------------------------------------------------------
#ifndef THINGSPEAK_SUPPORT
#define THINGSPEAK_SUPPORT 1 // Enable Thingspeak support by default (2.56Kb)
#endif
#define THINGSPEAK_ENABLED 0 // Thingspeak disabled by default
#define THINGSPEAK_APIKEY "" // Default API KEY
#define THINGSPEAK_USE_ASYNC 1 // Use AsyncClient instead of WiFiClientSecure
// THINGSPEAK OVER SSL
// Using THINGSPEAK over SSL works well but generates problems with the web interface,
// so you should compile it with WEB_SUPPORT to 0.
// When THINGSPEAK_USE_ASYNC is 1, requires ASYNC_TCP_SSL_ENABLED to 1 and ESP8266 Arduino Core 2.4.0.
#define THINGSPEAK_USE_SSL 0 // Use secure connection
#define THINGSPEAK_FINGERPRINT "78 60 18 44 81 35 BF DF 77 84 D4 0A 22 0D 9B 4E 6C DC 57 2C"
#define THINGSPEAK_HOST "api.thingspeak.com"
#if THINGSPEAK_USE_SSL
#define THINGSPEAK_PORT 443
#else
#define THINGSPEAK_PORT 80
#endif
#define THINGSPEAK_URL "/update"
#define THINGSPEAK_MIN_INTERVAL 15000 // Minimum interval between POSTs (in millis)
#ifndef ASYNC_TCP_SSL_ENABLED
#if THINGSPEAK_USE_SSL && THINGSPEAK_USE_ASYNC
#undef THINGSPEAK_SUPPORT // Thingspeak in ASYNC mode requires ASYNC_TCP_SSL_ENABLED
#endif
#endif
// -----------------------------------------------------------------------------
// NTP
// -----------------------------------------------------------------------------


+ 61
- 0
code/espurna/config/hardware.h View File

@ -72,6 +72,16 @@
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
#elif defined(WEMOS_D1_TARPUNA_SHIELD)
// Info
#define MANUFACTURER "WEMOS"
#define DEVICE "D1_TARPUNA_SHIELD"
// Relays
#define RELAY1_PIN 12
#define RELAY1_TYPE RELAY_TYPE_NORMAL
// -----------------------------------------------------------------------------
// ESPurna
// -----------------------------------------------------------------------------
@ -452,6 +462,37 @@
#define BUTTON3_RELAY 3
#define BUTTON4_RELAY 4
// Sonoff 4CH Pro uses a secondary STM32 microcontroller to handle
// buttons and relays, but it also forwards button presses to the ESP8285.
// This allows ESPurna to handle button presses -almost- the same way
// as with other devices except:
// * Double click seems to break/disable the button on the STM32 side
// * With S6 switch to 1 (self-locking and inching modes) everything's OK
// * With S6 switch to 0 (interlock mode) if there is a relay ON
// and you click on another relay button, the STM32 sends a "press"
// event for the button of the first relay (to turn it OFF) but it
// does not send a "release" event. It's like it's holding the
// button down since you can see it is still LOW.
// Whatever reason the result is that it may actually perform a
// long click or long-long click.
// The configuration below make the button toggle the relay on press events
// and disables any possibly harmful combination with S6 set to 0.
// If you are sure you will only use S6 to 1 you can comment the
// BUTTON1_LNGCLICK and BUTTON1_LNGLNGCLICK options below to recover the
// AP mode and factory reset functionalities.
#define BUTTON1_PRESS BUTTON_MODE_TOGGLE
#define BUTTON1_CLICK BUTTON_MODE_NONE
#define BUTTON1_DBLCLICK BUTTON_MODE_NONE
#define BUTTON1_LNGCLICK BUTTON_MODE_NONE
#define BUTTON1_LNGLNGCLICK BUTTON_MODE_NONE
#define BUTTON2_PRESS BUTTON_MODE_TOGGLE
#define BUTTON2_CLICK BUTTON_MODE_NONE
#define BUTTON3_PRESS BUTTON_MODE_TOGGLE
#define BUTTON3_CLICK BUTTON_MODE_NONE
#define BUTTON4_PRESS BUTTON_MODE_TOGGLE
#define BUTTON4_CLICK BUTTON_MODE_NONE
// Relays
#define RELAY1_PIN 12
#define RELAY2_PIN 5
@ -1190,6 +1231,26 @@
#define LIGHT_CH4_INVERSE 0
#elif defined(ARILUX_AL_LC02)
// Info
#define MANUFACTURER "ARILUX"
#define DEVICE "AL_LC02"
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
#define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER
#define DUMMY_RELAY_COUNT 1
// Light
#define LIGHT_CHANNELS 4
#define LIGHT_CH1_PIN 12 // RED
#define LIGHT_CH2_PIN 5 // GREEN
#define LIGHT_CH3_PIN 13 // BLUE
#define LIGHT_CH4_PIN 15 // WHITE1
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
#define LIGHT_CH3_INVERSE 0
#define LIGHT_CH4_INVERSE 0
#elif defined(ARILUX_AL_LC06)
// Info


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

@ -36,6 +36,9 @@
#define HUMIDITY_DRY 2
#define HUMIDITY_WET 3
#define SENSOR_PUBLISH_ADDRESSES 0 // Publish sensor addresses
#define SENSOR_ADDRESS_TOPIC "address" // Topic to publish sensor addresses
//--------------------------------------------------------------------------------
// Sensor ID
// These should remain over time, do not modify them, only add new ones at the end
@ -161,8 +164,8 @@
#define DALLAS_PIN 14
#endif
#define DALLAS_RESOLUTION 9 // Not used atm
#define DALLAS_READ_INTERVAL 2000 // Force sensor read & cache every 2 seconds
#define DALLAS_RESOLUTION 9 // Not used atm
#define DALLAS_READ_INTERVAL 2000 // Force sensor read & cache every 2 seconds
//------------------------------------------------------------------------------
// DHTXX temperature/humidity sensor
@ -438,15 +441,17 @@
// Sensor helpers configuration
// =============================================================================
#ifndef SENSOR_SUPPORT
#if ANALOG_SUPPORT || BH1750_SUPPORT || BMX280_SUPPORT || DALLAS_SUPPORT \
|| DHT_SUPPORT || DIGITAL_SUPPORT || ECH1560_SUPPORT \
|| EMON_ADC121_SUPPORT || EMON_ADS1X15_SUPPORT \
|| EMON_ANALOG_SUPPORT || EVENTS_SUPPORT || HLW8012_SUPPORT \
|| MHZ19_SUPPORT || PMSX003_SUPPORT || SHT3X_I2C_SUPPORT \
|| SI7021_SUPPORT || V9261F_SUPPORT
#define SENSOR_SUPPORT 1
#else
#define SENSOR_SUPPORT 0
#endif
#endif
// -----------------------------------------------------------------------------


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

@ -1,5 +1,5 @@
#define APP_NAME "ESPURNA"
#define APP_VERSION "1.11.4a"
#define APP_VERSION "1.11.4"
#define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat"
#define CFG_VERSION 3

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


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

@ -2,7 +2,7 @@
DEBUG MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -55,17 +55,17 @@ void debugSend(const char * format, ...) {
}
void debugSend_P(PGM_P format, ...) {
void debugSend_P(PGM_P format_P, ...) {
char f[DEBUG_FORMAT_MAX_LENGTH+1];
memcpy_P(f, format, DEBUG_FORMAT_MAX_LENGTH);
char format[strlen_P(format_P)+1];
memcpy_P(format, format_P, sizeof(format));
va_list args;
va_start(args, format);
va_start(args, format_P);
char test[1];
int len = ets_vsnprintf(test, 1, f, args) + 1;
int len = ets_vsnprintf(test, 1, format, args) + 1;
char * buffer = new char[len];
ets_vsnprintf(buffer, len, f, args);
ets_vsnprintf(buffer, len, format, args);
va_end(args);
#if DEBUG_SERIAL_SUPPORT


+ 2
- 2
code/espurna/domoticz.ino View File

@ -2,7 +2,7 @@
DOMOTICZ MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -97,7 +97,7 @@ void _domoticzWebSocketOnSend(JsonObject& root) {
root["dczTopicIn"] = getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC);
root["dczTopicOut"] = getSetting("dczTopicOut", DOMOTICZ_OUT_TOPIC);
JsonArray& relays = root.createNestedArray("dczRelayIdx");
JsonArray& relays = root.createNestedArray("dczRelays");
for (byte i=0; i<relayCount(); i++) {
relays.add(domoticzIdx(i));
}


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

@ -2,7 +2,7 @@
ESPurna
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -128,8 +128,7 @@ void welcome() {
// -------------------------------------------------------------------------
DEBUG_MSG_P(PSTR("[INIT] MANUFACTURER: %s\n"), MANUFACTURER);
DEBUG_MSG_P(PSTR("[INIT] DEVICE: %s\n"), DEVICE);
DEBUG_MSG_P(PSTR("[INIT] BOARD: %s\n"), getBoardName().c_str());
DEBUG_MSG_P(PSTR("[INIT] SUPPORT:"));
#if ALEXA_SUPPORT
@ -189,6 +188,9 @@ void welcome() {
#if TERMINAL_SUPPORT
DEBUG_MSG_P(PSTR(" TERMINAL"));
#endif
#if THINGSPEAK_SUPPORT
DEBUG_MSG_P(PSTR(" THINGSPEAK"));
#endif
#if WEB_SUPPORT
DEBUG_MSG_P(PSTR(" WEB"));
#endif
@ -286,6 +288,7 @@ void setup() {
if (getSetting("hostname").length() == 0) {
setSetting("hostname", getIdentifier());
}
setBoardName();
// Cache loop delay value to speed things (recommended max 250ms)
_loopDelay = atol(getSetting("loopDelay", LOOP_DELAY_TIME).c_str());
@ -357,6 +360,9 @@ void setup() {
#if INFLUXDB_SUPPORT
idbSetup();
#endif
#if THINGSPEAK_SUPPORT
tspkSetup();
#endif
#if RF_SUPPORT
rfSetup();
#endif
@ -430,7 +436,9 @@ void loop() {
#if SENSOR_SUPPORT
sensorLoop();
#endif
#if SCHEDULER_SUPPORT
#if THINGSPEAK_SUPPORT
tspkLoop();
#endif #if SCHEDULER_SUPPORT
schLoop();
#endif


+ 1
- 1
code/espurna/filters/BaseFilter.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Base Filter (other filters inherit from this)
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT


+ 1
- 1
code/espurna/filters/MaxFilter.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Max Filter
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT


+ 1
- 1
code/espurna/filters/MedianFilter.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Median Filter
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT


+ 1
- 1
code/espurna/filters/MovingAverageFilter.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Moving Average Filter
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT


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

@ -2,7 +2,7 @@
GPIO MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -2,7 +2,7 @@
HOME ASSISTANT MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -2,7 +2,7 @@
I2C MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -1,8 +1,8 @@
/*
I2C MODULE
INFLUXDB MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


+ 2
- 2
code/espurna/ir.ino View File

@ -2,8 +2,8 @@
IR MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017 by François Déchery
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by François Déchery
*/


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

@ -2,7 +2,7 @@
LED MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -2,7 +2,7 @@
LIGHT MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -2,7 +2,7 @@
LLMNR MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


+ 7
- 2
code/espurna/mdns.ino View File

@ -2,7 +2,7 @@
MDNS MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -45,7 +45,7 @@ void mdnsSetup() {
// Public ESPurna related txt for OTA discovery
MDNS.addServiceTxt("arduino", "tcp", "app_name", APP_NAME);
MDNS.addServiceTxt("arduino", "tcp", "app_version", APP_VERSION);
MDNS.addServiceTxt("arduino", "tcp", "target_board", DEVICE_NAME);
MDNS.addServiceTxt("arduino", "tcp", "target_board", getBoardName());
{
char buffer[6];
itoa(ESP.getFlashChipRealSize() / 1024, buffer, 10);
@ -56,6 +56,11 @@ void mdnsSetup() {
itoa(ESP.getFlashChipSize() / 1024, buffer, 10);
MDNS.addServiceTxt("arduino", "tcp", "sdk_size", (const char *) buffer);
}
{
char buffer[6];
itoa(ESP.getFreeSketchSpace(), buffer, 10);
MDNS.addServiceTxt("arduino", "tcp", "free_space", (const char *) buffer);
}
_mdns_wifi_onSTA = WiFi.onStationModeGotIP([](WiFiEventStationModeGotIP ipInfo) {
_mdnsStart();


+ 16
- 1
code/espurna/migrate.ino View File

@ -2,7 +2,7 @@
MIGRATE MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -683,6 +683,21 @@ void migrate() {
setSetting("chLogic", 4, 0);
setSetting("relays", 1);
#elif defined(ARILUX_AL_LC02)
setSetting("board", 52);
setSetting("relayProvider", RELAY_PROVIDER_LIGHT);
setSetting("lightProvider", LIGHT_PROVIDER_DIMMER);
setSetting("chGPIO", 0, 12);
setSetting("chGPIO", 1, 5);
setSetting("chGPIO", 2, 13);
setSetting("chGPIO", 3, 15);
setSetting("chLogic", 0, 0);
setSetting("chLogic", 1, 0);
setSetting("chLogic", 2, 0);
setSetting("chLogic", 3, 0);
setSetting("relays", 1);
#else
// Allow users to define new settings without migration config


+ 7
- 48
code/espurna/mqtt.ino View File

@ -2,7 +2,7 @@
MQTT MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -319,47 +319,6 @@ void _mqttOnMessage(char* topic, char* payload, unsigned int len) {
}
#if MQTT_USE_ASYNC
bool mqttFormatFP(const char * fingerprint, unsigned char * bytearray) {
// check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59)
if (strlen(fingerprint) != 59) return false;
DEBUG_MSG_P(PSTR("[MQTT] Fingerprint %s\n"), fingerprint);
// walk the fingerprint
for (unsigned int i=0; i<20; i++) {
bytearray[i] = strtol(fingerprint + 3*i, NULL, 16);
}
return true;
}
#else
bool mqttFormatFP(const char * fingerprint, char * destination) {
// check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59)
if (strlen(fingerprint) != 59) return false;
DEBUG_MSG_P(PSTR("[MQTT] Fingerprint %s\n"), fingerprint);
// copy it
strncpy(destination, fingerprint, 59);
// walk the fingerprint replacing ':' for ' '
for (unsigned char i = 0; i<59; i++) {
if (destination[i] == ':') destination[i] = ' ';
}
return true;
}
#endif
void mqttEnabled(bool status) {
_mqtt_enabled = status;
setSetting("mqttEnabled", status ? 1 : 0);
@ -423,7 +382,7 @@ void mqttConnect() {
if (secure) {
DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n"));
unsigned char fp[20] = {0};
if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
if (sslFingerPrintArray(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
_mqtt.addServerFingerprint(fp);
} else {
DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n"));
@ -450,7 +409,7 @@ void mqttConnect() {
DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n"));
if (_mqtt_client_secure.connect(host, port)) {
char fp[60] = {0};
if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
if (sslFingerPrintChar(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
if (_mqtt_client_secure.verify(fp, host)) {
_mqtt.setClient(_mqtt_client_secure);
} else {
@ -549,8 +508,10 @@ void mqttSetBrokerIfNone(IPAddress ip, unsigned int port) {
void mqttSetup() {
DEBUG_MSG_P(PSTR("[MQTT] MQTT_USE_ASYNC = %d\n"), MQTT_USE_ASYNC);
DEBUG_MSG_P(PSTR("[MQTT] MQTT_AUTOCONNECT = %d\n"), MQTT_AUTOCONNECT);
DEBUG_MSG_P(PSTR("[MQTT] Async %s, Autoconnect %s\n"),
MQTT_USE_ASYNC ? "ENABLED" : "DISABLED",
MQTT_AUTOCONNECT ? "ENABLED" : "DISABLED"
);
#if MQTT_USE_ASYNC
@ -592,8 +553,6 @@ void mqttSetup() {
#else // not MQTT_USE_ASYNC
DEBUG_MSG_P(PSTR("[MQTT] Using SYNC MQTT library\n"));
_mqtt.setCallback([](char* topic, byte* payload, unsigned int length) {
_mqttOnMessage(topic, (char *) payload, length);
});


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

@ -2,7 +2,7 @@
NETBIOS MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -2,7 +2,7 @@
NOFUSS MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -2,7 +2,7 @@
NTP MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


+ 4
- 2
code/espurna/ota.ino View File

@ -2,7 +2,7 @@
OTA MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -15,7 +15,9 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
void _otaConfigure() {
ArduinoOTA.setPort(OTA_PORT);
ArduinoOTA.setHostname(getSetting("hostname").c_str());
ArduinoOTA.setPassword(getSetting("adminPass", ADMIN_PASS).c_str());
#if USE_PASSWORD
ArduinoOTA.setPassword(getSetting("adminPass", ADMIN_PASS).c_str());
#endif
}
// -----------------------------------------------------------------------------


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

@ -2,7 +2,7 @@
RELAY MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -747,6 +747,11 @@ void relayLoop(void) {
relayInfluxDB(id);
#endif
#if THINGSPEAK_SUPPORT
tspkEnqueueRelay(id, status);
tspkFlush();
#endif
// Flag relay-based LEDs to update status
ledUpdate(true);


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

@ -2,7 +2,7 @@
RF MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


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

@ -2,7 +2,7 @@
ITEAD RF BRIDGE MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/


+ 47
- 1
code/espurna/sensor.ino View File

@ -2,7 +2,7 @@
SENSOR MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -203,6 +203,19 @@ void _sensorPost() {
void _sensorInit() {
/*
This is temporal, in the future sensors will be initialized based on
soft configuration (data stored in EEPROM config) so you will be able
to define and configure new sensors on the fly
At the time being, only enabled sensors (those with *_SUPPORT to 1) are being
loaded and initialized here. If you want to add new sensors of the same type
just duplicate the block and change the arguments for the set* methods.
Check the DHT block below for an example
*/
#if ANALOG_SUPPORT
{
AnalogSensor * sensor = new AnalogSensor();
@ -244,6 +257,19 @@ void _sensorInit() {
}
#endif
/*
// Example on how to add a second DHT sensor
// DHT2_PIN and DHT2_TYPE should be defined in sensors.h file
#if DHT_SUPPORT
{
DHTSensor * sensor = new DHTSensor();
sensor->setGPIO(DHT2_PIN);
sensor->setType(DHT2_TYPE);
_sensors.push_back(sensor);
}
#endif
*/
#if DIGITAL_SUPPORT
{
DigitalSensor * sensor = new DigitalSensor();
@ -634,11 +660,23 @@ void sensorLoop() {
dtostrf(filtered, 1-sizeof(buffer), decimals, buffer);
#if MQTT_SUPPORT
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
mqttSend(_magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
} else {
mqttSend(_magnitudeTopic(magnitude.type).c_str(), buffer);
}
#if SENSOR_PUBLISH_ADDRESSES
char topic[32];
snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, _magnitudeTopic(magnitude.type).c_str());
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
mqttSend(topic, magnitude.global, magnitude.sensor->address(magnitude.local).c_str());
} else {
mqttSend(topic, magnitude.sensor->address(magnitude.local).c_str());
}
#endif // SENSOR_PUBLISH_ADDRESSES
#endif // MQTT_SUPPORT
#if INFLUXDB_SUPPORT
@ -649,6 +687,10 @@ void sensorLoop() {
}
#endif // INFLUXDB_SUPPORT
#if THINGSPEAK_SUPPORT
tspkEnqueueMeasurement(i, buffer);
#endif
#if DOMOTICZ_SUPPORT
{
char key[15];
@ -685,6 +727,10 @@ void sensorLoop() {
wsSend(_sensorWebSocketSendData);
#endif
#if THINGSPEAK_SUPPORT
if (report_count == 0) tspkFlush();
#endif
}
}


+ 11
- 1
code/espurna/sensors/AnalogSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Analog Sensor (maps to an analogRead)
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && ANALOG_SUPPORT
@ -37,6 +37,16 @@ class AnalogSensor : public BaseSensor {
return String("ANALOG @ GPIO0");
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String("0");
}
// Type for slot # index
unsigned char type(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 1
- 1
code/espurna/sensors/BH1750Sensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// BH1750 Liminosity sensor over I2C
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && BH1750_SUPPORT


+ 2
- 2
code/espurna/sensors/BMX280Sensor.h View File

@ -1,7 +1,7 @@
// -----------------------------------------------------------------------------
// BME280/BMP280 Sensor over I2C
// Uses SparkFun BME280 library
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && BMX280_SUPPORT
@ -150,7 +150,7 @@ class BMX280Sensor : public I2CSensor {
void getConfig(JsonObject& root) {
root["sensor_id"] = _sensor_id;
root["address"] = getAddress();
root["address"] = _address;
};
void setConfig(JsonObject& root) {


+ 7
- 4
code/espurna/sensors/BaseSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Abstract sensor class (other sensor classes extend this class)
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT
@ -46,6 +46,12 @@ class BaseSensor {
// Descriptive name of the sensor
virtual String description() {}
// Address of the sensor (it could be the GPIO or I2C address)
virtual String address(unsigned char index) {}
// Descriptive name of the slot # index
virtual String slot(unsigned char index) {};
// Type for slot # index
virtual unsigned char type(unsigned char index) {}
@ -61,9 +67,6 @@ class BaseSensor {
// Load the configuration manifest
static void manifest(JsonArray& root) {};
// Descriptive name of the slot # index
String slot(unsigned char index) { return description(); }
// Sensor ID
unsigned char getID() { return _sensor_id; };


+ 11
- 1
code/espurna/sensors/DHTSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// DHTXX Sensor
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && DHT_SUPPORT
@ -90,6 +90,16 @@ class DHTSensor : public BaseSensor {
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String(_gpio);
}
// Type for slot # index
unsigned char type(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 14
- 1
code/espurna/sensors/DallasSensor.h View File

@ -1,7 +1,7 @@
// -----------------------------------------------------------------------------
// Dallas OneWire Sensor
// Uses OneWire library
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && DALLAS_SUPPORT
@ -170,6 +170,19 @@ class DallasSensor : public BaseSensor {
return String(buffer);
}
// Address of the device
String address(unsigned char index) {
char buffer[20] = {0};
if (index < _count) {
uint8_t * address = _devices[index].address;
snprintf(buffer, sizeof(buffer), "%02X%02X%02X%02X%02X%02X%02X%02X",
address[0], address[1], address[2], address[3],
address[4], address[5], address[6], address[7]
);
}
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 11
- 1
code/espurna/sensors/DigitalSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Digital Sensor (maps to a digitalRead)
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && DIGITAL_SUPPORT
@ -67,6 +67,16 @@ class DigitalSensor : public BaseSensor {
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String(_gpio);
}
// Type for slot # index
unsigned char type(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 13
- 1
code/espurna/sensors/ECH1560Sensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// ECH1560 based power monitor
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && ECH1560_SUPPORT
@ -82,6 +82,18 @@ class ECH1560Sensor : public BaseSensor {
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
char buffer[6];
snprintf(buffer, sizeof(buffer), "%i:%i", _clk, _miso);
return String(buffer);
}
// Type for slot # index
unsigned char type(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 1
- 1
code/espurna/sensors/EmonADC121Sensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// ADS121-based Energy Monitor Sensor over I2C
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && EMON_ADC121_SUPPORT


+ 9
- 1
code/espurna/sensors/EmonADS1X15Sensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// ADS1X15-based Energy Monitor Sensor over I2C
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && EMON_ADS1X15_SUPPORT
@ -203,6 +203,14 @@ class EmonADS1X15Sensor : public EmonSensor {
return String(buffer);
}
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
char buffer[10];
unsigned char channel = getChannel(index % _ports);
snprintf(buffer, sizeof(buffer), "0x%02X:%i", _address, channel);
return String(buffer);
}
// Type for slot # index
unsigned char type(unsigned char index) {
if (index < _count) {


+ 6
- 1
code/espurna/sensors/EmonAnalogSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Energy Monitor Sensor using builtin ADC
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && EMON_ANALOG_SUPPORT
@ -59,6 +59,11 @@ class EmonAnalogSensor : public EmonSensor {
return String("EMON @ ANALOG @ GPIO0");
}
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String("0");
}
// Type for slot # index
unsigned char type(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 1
- 1
code/espurna/sensors/EmonSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Abstract Energy Monitor Sensor (other EMON sensors extend this class)
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT


+ 11
- 1
code/espurna/sensors/EventSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Event Counter Sensor
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && EVENTS_SUPPORT
@ -81,6 +81,16 @@ class EventSensor : public BaseSensor {
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String(_gpio);
}
// Type for slot # index
unsigned char type(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 13
- 1
code/espurna/sensors/HLW8012Sensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Event Counter Sensor
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && HLW8012_SUPPORT
@ -162,6 +162,18 @@ class HLW8012Sensor : public BaseSensor {
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
char buffer[10];
snprintf(buffer, sizeof(buffer), "%i:%i:%i", _sel, _cf, _cf1);
return String(buffer);
}
// Type for slot # index
unsigned char type(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 13
- 1
code/espurna/sensors/I2CSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// Abstract I2C sensor class (other sensor classes extend this class)
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && ( I2C_SUPPORT || EMON_ANALOG_SUPPORT )
@ -23,6 +23,18 @@ class I2CSensor : public BaseSensor {
return _address;
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
char buffer[5];
snprintf(buffer, sizeof(buffer), "0x%02X", _address);
return String(buffer);
}
protected:
// Specific for I2C sensors


+ 13
- 1
code/espurna/sensors/MHZ19Sensor.h View File

@ -3,7 +3,7 @@
// Based on: https://github.com/nara256/mhz19_uart
// http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf
// Uses SoftwareSerial library
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && MHZ19_SUPPORT
@ -89,6 +89,18 @@ class MHZ19Sensor : public BaseSensor {
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
char buffer[6];
snprintf(buffer, sizeof(buffer), "%i:%i", _pin_rx, _pin_tx);
return String(buffer);
}
// Type for slot # index
unsigned char type(unsigned char index) {
_error = SENSOR_ERROR_OK;


+ 7
- 0
code/espurna/sensors/PMSX003Sensor.h View File

@ -97,6 +97,13 @@ class PMSX003Sensor : public BaseSensor {
return String();
}
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
char buffer[6];
snprintf(buffer, sizeof(buffer), "%i:%i", _pin_rx, _pin_tx);
return String(buffer);
}
// Type for slot # index
unsigned char type(unsigned char index) {
if (index < _count) {


+ 1
- 1
code/espurna/sensors/SHT3XI2CSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// SHT3X Sensor over I2C (Wemos)
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && SHT3X_I2C_SUPPORT


+ 6
- 1
code/espurna/sensors/SI7021Sensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// SI7021 / HTU21D Sensor over I2C
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && SI7021_SUPPORT
@ -85,6 +85,11 @@ class SI7021Sensor : public I2CSensor {
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Type for slot # index
unsigned char type(unsigned char index) {
if (index < _count) {


+ 11
- 1
code/espurna/sensors/V9261FSensor.h View File

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------------
// V9261F based power monitor
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && V9261F_SUPPORT
@ -77,6 +77,16 @@ class V9261FSensor : public BaseSensor {
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String(_pin_rx);
}
// Loop-like method, call it in your main loop
void tick() {
_read();


+ 19
- 1
code/espurna/settings.ino View File

@ -2,7 +2,7 @@
SETTINGS MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -250,6 +250,24 @@ void settingsSetup() {
DEBUG_MSG_P(PSTR("+OK\n"));
});
Embedis::command( F("GPIO"), [](Embedis* e) {
if (e->argc < 2) {
DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
return;
}
int pin = String(e->argv[1]).toInt();
//if (!gpioValid(pin)) {
// DEBUG_MSG_P(PSTR("-ERROR: Invalid GPIO\n"));
// return;
//}
if (e->argc > 2) {
bool state = String(e->argv[2]).toInt() == 1;
digitalWrite(pin, state);
}
DEBUG_MSG_P(PSTR("GPIO %d is %s\n"), pin, digitalRead(pin) == HIGH ? "HIGH" : "LOW");
DEBUG_MSG_P(PSTR("+OK\n"));
});
Embedis::command( F("HEAP"), [](Embedis* e) {
DEBUG_MSG_P(PSTR("Free HEAP: %d bytes\n"), getFreeHeap());
DEBUG_MSG_P(PSTR("+OK\n"));


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

@ -2,7 +2,7 @@
SSDP MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
Uses SSDP library by PawelDino (https://github.com/PawelDino)
https://github.com/esp8266/Arduino/issues/2283#issuecomment-299635604


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


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

@ -2,7 +2,7 @@
TELNET MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
Parts of the code have been borrowed from Thomas Sarlandie's NetServer
(https://github.com/sarfata/kbox-firmware/tree/master/src/esp)


+ 265
- 0
code/espurna/thinkspeak.ino View File

@ -0,0 +1,265 @@
/*
THINGSPEAK MODULE
Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if THINGSPEAK_SUPPORT
#if THINGSPEAK_USE_ASYNC
#include <ESPAsyncTCP.h>
AsyncClient * _tspk_client;
#else
#include <ESP8266WiFi.h>
#endif
const char THINGSPEAK_REQUEST_TEMPLATE[] PROGMEM =
"POST %s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: ESPurna\r\n"
"Connection: close\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %d\r\n\r\n"
"%s\r\n";
bool _tspk_enabled = false;
char * _tspk_queue[8] = {NULL};
bool _tspk_flush = false;
unsigned long _tspk_last_flush = 0;
// -----------------------------------------------------------------------------
void _tspkWebSocketOnSend(JsonObject& root) {
unsigned char visible = 0;
root["tspkEnabled"] = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1;
root["tspkKey"] = getSetting("tspkKey");
JsonArray& relays = root.createNestedArray("tspkRelays");
for (byte i=0; i<relayCount(); i++) {
relays.add(getSetting("tspkRelay", i, 0).toInt());
}
if (relayCount() > 0) visible = 1;
#if SENSOR_SUPPORT
JsonArray& list = root.createNestedArray("tspkMagnitudes");
for (byte i=0; i<magnitudeCount(); i++) {
JsonObject& element = list.createNestedObject();
element["name"] = magnitudeName(i);
element["type"] = magnitudeType(i);
element["index"] = magnitudeIndex(i);
element["idx"] = getSetting("tspkMagnitude", i, 0).toInt();
}
if (magnitudeCount() > 0) visible = 1;
#endif
root["tspkVisible"] = visible;
}
void _tspkConfigure() {
_tspk_enabled = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1;
if (_tspk_enabled && (getSetting("tspkKey").length() == 0)) {
_tspk_enabled = false;
setSetting("tspkEnabled", 0);
}
}
#if THINGSPEAK_USE_ASYNC
void _tspkPost(String data) {
if (_tspk_client == NULL) {
_tspk_client = new AsyncClient();
}
_tspk_client->onDisconnect([](void *s, AsyncClient *c) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Disconnected\n"));
_tspk_client->free();
delete _tspk_client;
_tspk_client = NULL;
}, 0);
_tspk_client->onTimeout([](void *s, AsyncClient *c, uint32_t time) {
_tspk_client->close(true);
}, 0);
_tspk_client->onData([](void * arg, AsyncClient * c, void * response, size_t len) {
char * b = (char *) response;
b[len] = 0;
char * p = strstr((char *)response, "\r\n\r\n");
unsigned int code = (p != NULL) ? atoi(&p[4]) : 0;
DEBUG_MSG_P(PSTR("[THINGSPEAK] Response value: %d\n"), code);
_tspk_client->close(true);
}, NULL);
_tspk_client->onConnect([data](void * arg, AsyncClient * client) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Connected to %s:%d\n"), THINGSPEAK_HOST, THINGSPEAK_PORT);
#if THINGSPEAK_USE_SSL
uint8_t fp[20] = {0};
sslFingerPrintArray(THINGSPEAK_FINGERPRINT, fp);
SSL * ssl = _tspk_client->getSSL();
if (ssl_match_fingerprint(ssl, fp) != SSL_OK) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Warning: certificate doesn't match\n"));
}
#endif
DEBUG_MSG_P(PSTR("[THINGSPEAK] POST %s\n"), data.c_str());
char buffer[strlen_P(THINGSPEAK_REQUEST_TEMPLATE) + strlen(THINGSPEAK_URL) + strlen(THINGSPEAK_HOST) + data.length()];
snprintf_P(buffer, sizeof(buffer),
THINGSPEAK_REQUEST_TEMPLATE,
THINGSPEAK_URL,
THINGSPEAK_HOST,
data.length(),
data.c_str()
);
client->write(buffer);
}, NULL);
#if ASYNC_TCP_SSL_ENABLED
bool connected = _tspk_client->connect(THINGSPEAK_HOST, THINGSPEAK_PORT, THINGSPEAK_USE_SSL);
#else
bool connected = _tspk_client->connect(THINGSPEAK_HOST, THINGSPEAK_PORT);
#endif
if (!connected) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Connection failed\n"));
_tspk_client->close(true);
}
}
#else // THINGSPEAK_USE_ASYNC
void _tspkPost(String data) {
#if THINGSPEAK_USE_SSL
WiFiClientSecure _tspk_client;
#else
WiFiClient _tspk_client;
#endif
if (_tspk_client.connect(THINGSPEAK_HOST, THINGSPEAK_PORT)) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Connected to %s:%d\n"), THINGSPEAK_HOST, THINGSPEAK_PORT);
if (!_tspk_client.verify(THINGSPEAK_FINGERPRINT, THINGSPEAK_HOST)) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Warning: certificate doesn't match\n"));
}
DEBUG_MSG_P(PSTR("[THINGSPEAK] POST %s\n"), data.c_str());
char buffer[strlen_P(THINGSPEAK_REQUEST_TEMPLATE) + strlen(THINGSPEAK_URL) + strlen(THINGSPEAK_HOST) + data.length()];
snprintf_P(buffer, sizeof(buffer),
THINGSPEAK_REQUEST_TEMPLATE,
THINGSPEAK_URL,
THINGSPEAK_HOST,
data.length(),
data.c_str()
);
_tspk_client.print(buffer);
nice_delay(100);
String response = _tspk_client.readString();
int pos = response.indexOf("\r\n\r\n");
unsigned int code = (pos > 0) ? response.substring(pos + 4).toInt() : 0;
DEBUG_MSG_P(PSTR("[THINGSPEAK] Response value: %d\n"), code);
_tspk_client.stop();
return;
}
DEBUG_MSG_P(PSTR("[THINGSPEAK] Connection failed\n"));
}
#endif // THINGSPEAK_USE_ASYNC
bool _tspkEnqueue(unsigned char index, char * payload) {
DEBUG_MSG_P(PSTR("[THINGSPEAK] Enqueuing field #%d with value %s\n"), index, payload);
--index;
if (_tspk_queue[index] != NULL) free(_tspk_queue[index]);
_tspk_queue[index] = strdup(payload);
}
void _tspkFlush() {
String data;
// Walk the fields
for (unsigned char id=0; id<8; id++) {
if (_tspk_queue[id] != NULL) {
if (data.length() > 0) data = data + String("&");
data = data + String("field") + String(id+1) + String("=") + String(_tspk_queue[id]);
free(_tspk_queue[id]);
_tspk_queue[id] = NULL;
}
}
// POST data if any
if (data.length() > 0) {
data = data + String("&api_key=") + getSetting("tspkKey");
_tspkPost(data);
_tspk_last_flush = millis();
}
}
// -----------------------------------------------------------------------------
bool tspkEnqueueRelay(unsigned char index, unsigned char status) {
if (!_tspk_enabled) return true;
unsigned char id = getSetting("tspkRelay", index, 0).toInt();
if (id > 0) {
char payload[3];
itoa(status ? 1 : 0, payload, 10);
_tspkEnqueue(id, payload);
}
}
bool tspkEnqueueMeasurement(unsigned char index, char * payload) {
if (!_tspk_enabled) return true;
unsigned char id = getSetting("tspkMagnitude", index, 0).toInt();
if (id > 0) {
_tspkEnqueue(id, payload);
}
}
void tspkFlush() {
_tspk_flush = true;
}
bool tspkEnabled() {
return _tspk_enabled;
}
void tspkSetup() {
_tspkConfigure();
#if WEB_SUPPORT
wsOnSendRegister(_tspkWebSocketOnSend);
wsOnAfterParseRegister(_tspkConfigure);
#endif
DEBUG_MSG_P(PSTR("[THINGSPEAK] Async %s, SSL %s\n"),
THINGSPEAK_USE_ASYNC ? "ENABLED" : "DISABLED",
THINGSPEAK_USE_SSL ? "ENABLED" : "DISABLED"
);
}
void tspkLoop() {
if (!_tspk_enabled) return;
if (!wifiConnected() || (WiFi.getMode() != WIFI_STA)) return;
if (_tspk_flush && (millis() - _tspk_last_flush > THINGSPEAK_MIN_INTERVAL)) {
_tspkFlush();
_tspk_flush = false;
}
}
#endif

+ 56
- 1
code/espurna/utils.ino View File

@ -2,7 +2,7 @@
UTILS MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -15,6 +15,16 @@ String getIdentifier() {
return String(buffer);
}
void setBoardName() {
#ifndef ESPURNA_CORE
setSetting("boardName", DEVICE_NAME);
#endif
}
String getBoardName() {
return getSetting("boardName", DEVICE_NAME);
}
String getCoreVersion() {
String version = ESP.getCoreVersion();
#ifdef ARDUINO_ESP8266_RELEASE
@ -191,6 +201,51 @@ void heartbeat() {
}
// -----------------------------------------------------------------------------
// SSL
// -----------------------------------------------------------------------------
#if ASYNC_TCP_SSL_ENABLED
bool sslCheckFingerPrint(const char * fingerprint) {
return (strlen(fingerprint) == 59);
}
bool sslFingerPrintArray(const char * fingerprint, unsigned char * bytearray) {
// check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59)
if (!sslCheckFingerPrint(fingerprint)) return false;
// walk the fingerprint
for (unsigned int i=0; i<20; i++) {
bytearray[i] = strtol(fingerprint + 3*i, NULL, 16);
}
return true;
}
bool sslFingerPrintChar(const char * fingerprint, char * destination) {
// check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59)
if (!sslCheckFingerPrint(fingerprint)) return false;
// copy it
strncpy(destination, fingerprint, 59);
// walk the fingerprint replacing ':' for ' '
for (unsigned char i = 0; i<59; i++) {
if (destination[i] == ':') destination[i] = ' ';
}
return true;
}
#endif
// -----------------------------------------------------------------------------
// Reset
// -----------------------------------------------------------------------------
unsigned char resetReason() {


+ 9
- 5
code/espurna/web.ino View File

@ -2,7 +2,7 @@
WEBSERVER MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -267,10 +267,14 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde
// -----------------------------------------------------------------------------
bool _authenticate(AsyncWebServerRequest *request) {
String password = getSetting("adminPass", ADMIN_PASS);
char httpPassword[password.length() + 1];
password.toCharArray(httpPassword, password.length() + 1);
return request->authenticate(WEB_USERNAME, httpPassword);
#if USE_PASSWORD
String password = getSetting("adminPass", ADMIN_PASS);
char httpPassword[password.length() + 1];
password.toCharArray(httpPassword, password.length() + 1);
return request->authenticate(WEB_USERNAME, httpPassword);
#else
return true;
#endif
}
// -----------------------------------------------------------------------------


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

@ -2,7 +2,7 @@
WIFI MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -73,7 +73,11 @@ void wifiReconnectCheck() {
void wifiConfigure() {
jw.setHostname(getSetting("hostname").c_str());
jw.setSoftAP(getSetting("hostname").c_str(), getSetting("adminPass", ADMIN_PASS).c_str());
#if USE_PASSWORD
jw.setSoftAP(getSetting("hostname").c_str(), getSetting("adminPass", ADMIN_PASS).c_str());
#else
jw.setSoftAP(getSetting("hostname").c_str());
#endif
jw.setConnectTimeout(WIFI_CONNECT_TIMEOUT);
wifiReconnectCheck();
jw.setAPMode(WIFI_AP_MODE);


+ 5
- 3
code/espurna/ws.ino View File

@ -2,7 +2,7 @@
WEBSOCKET MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
@ -205,7 +205,7 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
void _wsOnStart(JsonObject& root) {
#if WEB_FORCE_PASS_CHANGE
#if USE_PASSWORD && WEB_FORCE_PASS_CHANGE
String adminPass = getSetting("adminPass", ADMIN_PASS);
bool changePassword = adminPass.equals(ADMIN_PASS);
#else
@ -350,7 +350,9 @@ void wsSend_P(uint32_t client_id, PGM_P payload) {
}
void wsConfigure() {
_ws.setAuthentication(WEB_USERNAME, (const char *) getSetting("adminPass", ADMIN_PASS).c_str());
#if USE_PASSWORD
_ws.setAuthentication(WEB_USERNAME, (const char *) getSetting("adminPass", ADMIN_PASS).c_str());
#endif
}
void wsSetup() {


+ 5
- 3
code/extra_scripts.py View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
import time
Import("env")
# ------------------------------------------------------------------------------
@ -31,11 +32,12 @@ def clr(color, text):
# ------------------------------------------------------------------------------
def check_size(source, target, env):
time.sleep(1)
size = target[0].get_size()
print clr(Color.LIGHT_BLUE, "Binary size: %s bytes" % size)
if size > 512000:
print clr(Color.LIGHT_RED, "File too large for OTA!")
Exit(1)
#if size > 512000:
# print clr(Color.LIGHT_RED, "File too large for OTA!")
# Exit(1)
# ------------------------------------------------------------------------------
# Hooks


+ 1
- 1
code/gulpfile.js View File

@ -2,7 +2,7 @@
ESP8266 file system builder
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by


+ 34
- 15
code/html/custom.js View File

@ -104,7 +104,8 @@ var is_group = [
"sch_switch","sch_operation","sch_hour","sch_minute","sch_weekdays",
"relayBoot", "relayPulse", "relayTime",
"mqttGroup", "mqttGroupInv",
"dczRelayIdx",
"dczRelayIdx", "dczMagnitude",
"tspkRelay", "tspkMagnitude",
"ledMode",
"adminPass"
];
@ -396,36 +397,36 @@ function toggleMenu() {
}
// -----------------------------------------------------------------------------
// Domoticz
// Relays & magnitudes mapping
// -----------------------------------------------------------------------------
function createRelayIdxs(data) {
function createRelayList(data, container, template) {
var current = $("#domoticzRelays > div").length;
var current = $("#" + container + " > div").length;
if (current > 0) return;
var template = $("#relayIdxTemplate .pure-g")[0];
var template = $("#" + template + " .pure-g")[0];
for (var i=0; i<data.length; i++) {
var line = $(template).clone();
$("label", line).html("Switch #" + i);
$("input", line).attr("name", "dczRelayIdx" + i).attr("tabindex", 40 + i).val(data[i]);
line.appendTo("#domoticzRelays");
$("input", line).attr("tabindex", 40 + i).val(data[i]);
line.appendTo("#" + container);
}
}
function createMagnitudeIdxs(data) {
function createMagnitudeList(data, container, template) {
var current = $("#domoticzMagnitudes > div").length;
var current = $("#" + container + " > div").length;
if (current > 0) return;
var template = $("#magnitudeIdxTemplate .pure-g")[0];
var template = $("#" + template + " .pure-g")[0];
for (var i=0; i<data.length; i++) {
var line = $(template).clone();
$("label", line).html(magnitudeType(data[i].type) + " #" + parseInt(data[i].index));
$("div.hint", line).html(data[i].name);
$("input", line).attr("name", "dczMagnitude" + i).attr("tabindex", 40 + i).val(data[i].idx);
line.appendTo("#domoticzMagnitudes");
$("input", line).attr("tabindex", 40 + i).val(data[i].idx);
line.appendTo("#" + container);
}
}
@ -718,6 +719,8 @@ function rfbSend() {
function processData(data) {
console.log(data);
// title
if ("app_name" in data) {
var title = data.app_name;
@ -902,14 +905,30 @@ function processData(data) {
// ---------------------------------------------------------------------
// Domoticz - Relays
if (key == "dczRelayIdx") {
createRelayIdxs(data[key]);
if (key == "dczRelays") {
createRelayList(data[key], "dczRelays", "dczRelayTemplate");
return;
}
// Domoticz - Magnitudes
if (key == "dczMagnitudes") {
createMagnitudeIdxs(data[key]);
createMagnitudeList(data[key], "dczMagnitudes", "dczMagnitudeTemplate");
return;
}
// ---------------------------------------------------------------------
// Thingspeak
// ---------------------------------------------------------------------
// Thingspeak - Relays
if (key == "tspkRelays") {
createRelayList(data[key], "tspkRelays", "tspkRelayTemplate");
return;
}
// Thingspeak - Magnitudes
if (key == "tspkMagnitudes") {
createMagnitudeList(data[key], "tspkMagnitudes", "tspkMagnitudeTemplate");
return;
}


+ 65
- 57
code/html/index.html View File

@ -100,10 +100,6 @@
<a href="#" class="pure-menu-link" data="panel-relay">SWITCHES</a>
</li>
<li class="pure-menu-item module module-relay">
<a href="#" class="pure-menu-link" data="panel-schedule">SCHEDULE</a>
</li>
<li class="pure-menu-item module module-color">
<a href="#" class="pure-menu-link" data="panel-color">LIGHTS</a>
</li>
@ -120,6 +116,10 @@
<a href="#" class="pure-menu-link" data="panel-idb">INFLUXDB</a>
</li>
<li class="pure-menu-item module module-tspk">
<a href="#" class="pure-menu-link" data="panel-thingspeak">THINGSPEAK</a>
</li>
<li class="pure-menu-item module module-rfb">
<a href="#" class="pure-menu-link" data="panel-rfb">RFBRIDGE</a>
</li>
@ -137,7 +137,7 @@
</div>
<div class="footer">
&copy; 2016-2017<br />
&copy; 2016-2018<br />
Xose Pérez<br/>
<a href="http://tinkerman.cat" target="_blank">http://tinkerman.cat</a><br/>
<a href="https://bitbucket.org/xoseperez/espurna" target="_blank">ESPurna @ Bitbucket</a><br/>
@ -539,22 +539,6 @@
</div>
</div>
<div class="panel" id="panel-schedule">
<div class="header">
<h1>SCHEDULE</h1>
<h2>
Define actions based on the current time.
</h2>
</div>
<div class="page">
<fieldset>
<div id="schedules">
</div>
<button type="button" class="pure-button button-add-schedule">Add schedule</button>
</fieldset>
</div>
</div>
<div class="panel" id="panel-mqtt">
<div class="header">
@ -617,7 +601,7 @@
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">MQTT Keep Alive</label>
<input class="pure-u-1 pure-u-lg-1-4" type="number" name="mqttKeep" min="10" max="60" tabindex="28" />
<input class="pure-u-1 pure-u-lg-1-4" type="number" name="mqttKeep" min="10" max="3600" tabindex="28" />
</div>
<div class="pure-g module module-mqttssl">
@ -758,9 +742,49 @@
<div class="pure-u-1 hint">Set IDX to 0 to disable notifications from that component.</div>
</div>
<div id="domoticzRelays"></div>
<div id="dczRelays"></div>
<div id="dczMagnitudes"></div>
</fieldset>
</div>
</div>
<div class="panel" id="panel-thingspeak">
<div class="header">
<h1>THINGSPEAK</h1>
<h2>
Send your sensors data to Thinkgspeak.
</h2>
</div>
<div class="page">
<fieldset>
<legend>General</legend>
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-4"><label>Enable Thingspeak</label></div>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="tspkEnabled" tabindex="30" /></div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Thingspeak API Key</label>
<input class="pure-u-1 pure-u-lg-3-4" name="tspkKey" type="text" tabindex="31" />
</div>
<div id="domoticzMagnitudes"></div>
<legend>Sensors &amp; actuators</legend>
<div class="pure-g">
<div class="pure-u-1 hint">Enter the field number to send each data to, 0 disable notifications from that component.</div>
</div>
<div id="tspkRelays"></div>
<div id="tspkMagnitudes"></div>
</fieldset>
</div>
@ -1005,37 +1029,6 @@
</div>
<div id="scheduleTemplate" class="template">
<div class="pure-g">
<label class="pure-u-sm-4-24 pure-u-1-3" for="sch_switch">Turn&nbsp;Switch&nbsp;No</label>
<div class="pure-u-sm-3-24 pure-u-1-3">
<input name="sch_switch" type="number" min="0" max="10" step="1" value="0" tabindex="0" />
</div>
<div class="pure-u-sm-3-24 pure-u-1-3">
<select name="sch_operation" tabindex="0">
<option value="0">OFF</option>
<option value="1">ON</option>
</select>
</div>
<label class="pure-u-sm-5-24 pure-u-1-3">at&nbsp;Time&nbsp;HH&nbsp;MM</label>
<div class="pure-u-sm-3-24 pure-u-1-3">
<input name="sch_hour" type="number" min="0" max="23" step="1" tabindex="0" value="0" />
</div>
<div class="pure-u-sm-3-24 pure-u-1-3">
<input name="sch_minute" type="number" min="0" max="59" step="1" tabindex="0" value="0" />
</div>
<div class="pure-u break"></div>
<label class="pure-u-sm-1-4 pure-u-1">on&nbsp;Weekdays:</label>
<div class="pure-u-sm-3-4 pure-u-1">
<div class="pure-u-1 weekDays-selector">
<input type="inbox" name="sch_weekdays" value="1,2,3,4,5,6,7" class="weekday" tabindex="0" />
</div>
<div class="pure-u-1 hint">1 = Sunday, 2 = Monday, ...</div>
</div>
<div class="pure-u-md-1-6 pure-u-1-4"><button type="button" class="pure-button button-del-schedule pure-u-5-6 pure-u-md-5-6">Del</button></div>
</div>
</div>
<div id="relayTemplate" class="template">
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-4"><label>Switch #<span class="id"></span></label></div>
@ -1079,14 +1072,14 @@
</div>
</div>
<div id="relayIdxTemplate" class="template">
<div id="dczRelayTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Switch</label>
<div class="pure-u-1 pure-u-lg-1-4"><input class="pure-u-23-24 dczRelayIdx" name="dczRelayIdx" type="number" min="0" tabindex="0" data="0" /></div>
</div>
</div>
<div id="magnitudeIdxTemplate" class="template">
<div id="dczMagnitudeTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Magnitude</label>
<div class="pure-u-1 pure-u-lg-1-4"><input class="pure-u-23-24 center" name="dczMagnitude" type="number" min="0" tabindex="0" data="0" /></div>
@ -1094,6 +1087,21 @@
</div>
</div>
<div id="tspkRelayTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Switch</label>
<div class="pure-u-1 pure-u-lg-1-4"><input class="pure-u-23-24" name="tspkRelay" type="number" min="0" max="8" tabindex="0" data="0" /></div>
</div>
</div>
<div id="tspkMagnitudeTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Magnitude</label>
<div class="pure-u-1 pure-u-lg-1-4"><input class="pure-u-23-24 center" name="tspkMagnitude" type="number" min="0" max="8" tabindex="0" data="0" /></div>
<div class="pure-u-1 pure-u-lg-1-2 hint center"></div>
</div>
</div>
<div id="colorRGBTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">Color</label>


+ 15
- 4
code/ota.py View File

@ -38,15 +38,19 @@ def on_service_state_change(zeroconf, service_type, name, state_change):
device['app'] = info.properties.get('app_name', '')
device['version'] = info.properties.get('app_version', '')
device['device'] = info.properties.get('target_board', '')
device['mem_size'] = info.properties.get('mem_size', '')
device['sdk_size'] = info.properties.get('sdk_size', '')
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')
devices.append(device)
def list():
'''
Shows the list of discovered devices
'''
output_format="{:>3} {:<25}{:<25}{:<15}{:<15}{:<30}{:<10}{:<10}"
output_format="{:>3} {:<25}{:<25}{:<15}{:<15}{:<30}{:<10}{:<10}{:<10}"
print(output_format.format(
"#",
"HOSTNAME",
@ -56,8 +60,9 @@ def list():
"DEVICE",
"MEM_SIZE",
"SDK_SIZE",
"FREE_SPACE"
))
print "-" * 135
print "-" * 146
index = 0
for device in devices:
@ -71,6 +76,7 @@ def list():
device.get('device', ''),
device.get('mem_size', ''),
device.get('sdk_size', ''),
device.get('free_space', ''),
))
print
@ -161,6 +167,7 @@ if __name__ == '__main__':
# Parse command line options
parser = argparse.ArgumentParser(description=description)
#parser.add_argument("-v", "--verbose", help="show verbose output", default=0, action='count')
parser.add_argument("-c", "--core", help="flash ESPurna core", default=0, action='count')
parser.add_argument("-f", "--flash", help="flash device", default=0, action='count')
parser.add_argument("-s", "--sort", help="sort devices list by field", default='hostname')
args = parser.parse_args()
@ -194,6 +201,10 @@ if __name__ == '__main__':
device = flash()
if device:
# Flash core version?
if args.core > 0:
device['flags'] = "-DESPURNA_CORE " + device['flags']
env = "esp8266-%sm-ota" % device['size']
# Summary


+ 26
- 1
code/platformio.ini View File

@ -26,7 +26,7 @@ lib_deps =
PMS Library
https://bitbucket.org/xoseperez/justwifi.git#1.1.4
https://bitbucket.org/xoseperez/hlw8012.git#1.1.0
https://bitbucket.org/xoseperez/fauxmoesp.git#2.3.0
https://bitbucket.org/xoseperez/fauxmoesp.git#2.4.0
https://bitbucket.org/xoseperez/nofuss.git#0.2.5
https://bitbucket.org/xoseperez/debounceevent.git#2.0.1
https://github.com/xoseperez/my92xx#3.0.0
@ -933,6 +933,31 @@ upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:arilux-al-lc02]
platform = ${common.platform}
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC02
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:arilux-al-lc02-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 = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC02
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:arilux-al-lc06]
platform = ${common.platform}
framework = arduino


Loading…
Cancel
Save