Browse Source

Merged xoseperez/espurna into master

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

+ 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)


+ 21
- 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
@ -106,6 +110,18 @@ It uses the Arduino Core for ESP8266 framework and a number of 3rd party librari
* Extra long click (>10 seconds) to go back to factory settings (only main button)
* Specific definitions for touch button devices (ESPurna Switch, Sonoff Touch & T1)
## Contribute
There are several ways to contribute to ESpurna development. You can contribute to the repository by doing:
* Pull requests (fixes, enhancements, new features... are very welcome)
* Documentation (I reckon I'm bad at it)
* Testing (filing issues or help resolving them, they take a lot of time and sometimes I don't have the required hardware to test them all)
And of course you can always buy me a beer, coffee, tea,... via the donation button below.
[![Donate to ESPurna Project](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=xose%2eperez%40gmail%2ecom&lc=US&no_note=0&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest)
## Documentation
For more information please refer to the [ESPurna Wiki](https://bitbucket.org/xoseperez/espurna/wiki/Home).
@ -139,11 +155,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/build.sh View File

@ -45,7 +45,7 @@ echo "Building firmware images..."
mkdir -p firmware/espurna-$version
for environment in $environments; do
echo "* espurna-$version-$environment.bin"
platformio run -s -e $environment || exit
platformio run --silent --environment $environment || exit
mv .pioenvs/$environment/firmware.bin firmware/espurna-$version/espurna-$version-$environment.bin
done
echo "--------------------------------------------------------------"

+ 0
- 51
code/core_version.py View File

@ -1,51 +0,0 @@
#!/bin/python
import json
import commands
import subprocess
import os
import sys
def core_version(env):
# Get the core folder
fwdir = env["FRAMEWORK_ARDUINOESP8266_DIR"]
# Get the core version
with open(fwdir + '/package.json') as data_file:
data = json.load(data_file)
core_version = data["version"].upper().replace(".", "_").replace("-", "_")
print "CORE VERSION: %s" % core_version
# Get git version
pr = subprocess.Popen(
"git --git-dir .git rev-parse --short=8 HEAD 2>/dev/null || echo ffffffff",
cwd = fwdir,
shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE )
(out, error) = pr.communicate()
git_version = str(out).replace('\n', "")
print "GIT VERSION: %s" % git_version
#env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_RELEASE=" + core_version)
#env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_RELEASE_" + core_version)
#env["BUILD_FLAGS"][0] += str(" -DARDUINO_ESP8266_GIT_VER=" + git_version)
with open('espurna/config/core_version.h', 'w') as the_file:
the_file.write('#define ARDUINO_ESP8266_RELEASE "%s"\n' % core_version)
the_file.write('#define ARDUINO_ESP8266_RELEASE_%s\n' % core_version)
the_file.write('#define ARDUINO_ESP8266_GIT_VER "%s"\n' % git_version)
#env.Append(
# CFLAGS = [
# str("-DARDUINO_ESP8266_RELEASE=" + core_version),
# str("-DARDUINO_ESP8266_RELEASE_" + core_version),
# str("-DARDUINO_ESP8266_GIT_VER=" + git_version)
# ]
#)
#print " -DARDUINO_ESP8266_RELEASE=" + core_version +
# " -DARDUINO_ESP8266_RELEASE_" + core_version +
# " -DARDUINO_ESP8266_GIT_VER=" + git_version
Import('env')
core_version(env)

+ 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>
*/


+ 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
//--------------------------------------------------------------------------------


+ 71
- 5
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
@ -208,7 +234,7 @@ PROGMEM const char* const custom_reset_string[] = {
#define RELAY_BOOT_OFF 0
#define RELAY_BOOT_ON 1
#define RELAY_BOOT_SAME 2
#define RELAY_BOOT_TOOGLE 3
#define RELAY_BOOT_TOGGLE 3
#define RELAY_TYPE_NORMAL 0
#define RELAY_TYPE_INVERSE 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:
@ -588,6 +614,11 @@ PROGMEM const char* const custom_reset_string[] = {
#define HOMEASSISTANT_SUPPORT MQTT_SUPPORT // Build with home assistant support (if MQTT, 1.64Kb)
#endif
#if HOMEASSISTANT_SUPPORT
#undef MQTT_SUPPORT
#define MQTT_SUPPORT 1 // If Home Assistant enabled enable MQTT
#endif
#define HOMEASSISTANT_ENABLED 0 // Integration not enabled by default
#define HOMEASSISTANT_PREFIX "homeassistant" // Default MQTT prefix
@ -606,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
- 1
code/espurna/config/hardware.h View File

@ -64,6 +64,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
// -----------------------------------------------------------------------------
@ -444,6 +454,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
@ -728,7 +769,6 @@
// LEDs
#define LED1_PIN 13
#define LED1_PIN_INVERSE 0
#define LED_WIFI 0
// -----------------------------------------------------------------------------
@ -1183,6 +1223,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


+ 14
- 9
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
// -----------------------------------------------------------------------------
@ -512,12 +517,12 @@ PROGMEM const char magnitude_reactive_power_topic[] = "reactive";
PROGMEM const char magnitude_power_factor_topic[] = "factor";
PROGMEM const char magnitude_energy_topic[] = "energy";
PROGMEM const char magnitude_energy_delta_topic[] = "energy_delta";
PROGMEM const char magnitude_pm1dot0_topic[] = "pm1dot0";
PROGMEM const char magnitude_pm2dot5_topic[] = "pm2dot5";
PROGMEM const char magnitude_pm10_topic[] = "pm10";
PROGMEM const char magnitude_analog_topic[] = "analog";
PROGMEM const char magnitude_digital_topic[] = "digital";
PROGMEM const char magnitude_events_topic[] = "events";
PROGMEM const char magnitude_pm1dot0_topic[] = "pm1dot0";
PROGMEM const char magnitude_pm2dot5_topic[] = "pm2dot5";
PROGMEM const char magnitude_pm10_topic[] = "pm10";
PROGMEM const char magnitude_co2_topic[] = "co2";
PROGMEM const char magnitude_lux_topic[] = "lux";
@ -526,8 +531,8 @@ PROGMEM const char* const magnitude_topics[] = {
magnitude_pressure_topic, magnitude_current_topic, magnitude_voltage_topic,
magnitude_active_power_topic, magnitude_apparent_power_topic, magnitude_reactive_power_topic,
magnitude_power_factor_topic, magnitude_energy_topic, magnitude_energy_delta_topic,
magnitude_pm1dot0_topic, magnitude_pm2dot5_topic, magnitude_pm10_topic,
magnitude_analog_topic, magnitude_digital_topic, magnitude_events_topic,
magnitude_pm1dot0_topic, magnitude_pm2dot5_topic, magnitude_pm10_topic,
magnitude_co2_topic, magnitude_lux_topic
};
@ -549,8 +554,8 @@ PROGMEM const char* const magnitude_units[] = {
magnitude_hectopascals, magnitude_amperes, magnitude_volts,
magnitude_watts, magnitude_watts, magnitude_watts,
magnitude_percentage, magnitude_joules, magnitude_joules,
magnitude_ugm3, magnitude_ugm3, magnitude_ugm3,
magnitude_empty, magnitude_empty, magnitude_empty,
magnitude_ugm3, magnitude_ugm3, magnitude_ugm3,
magnitude_ppm, magnitude_lux
};


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

@ -1,5 +1,5 @@
#define APP_NAME "ESPURNA"
#define APP_VERSION "1.11.3"
#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
- 3
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
@ -427,6 +433,9 @@ void loop() {
#if SENSOR_SUPPORT
sensorLoop();
#endif
#if THINGSPEAK_SUPPORT
tspkLoop();
#endif
// Power saving delay
delay(_loopDelay);


+ 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>
*/


+ 47
- 3
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>
*/
@ -309,6 +309,17 @@ void _toLong(char * color, size_t len) {
_toLong(color, len, false);
}
void _toCSV(char * buffer, size_t len, bool applyBrightness) {
char num[10];
float b = applyBrightness ? (float) _light_brightness / LIGHT_MAX_BRIGHTNESS : 1;
for (unsigned char i=0; i<_light_channel.size(); i++) {
itoa(_light_channel[i].value * b, num, 10);
if (i>0) strncat(buffer, ",", len--);
strncat(buffer, num, len);
len = len - strlen(num);
}
}
// Thanks to Sacha Telgenhof for sharing this code in his AiLight library
// https://github.com/stelgenhof/AiLight
void _fromKelvin(unsigned long kelvin) {
@ -451,6 +462,7 @@ void _lightColorRestore() {
#if MQTT_SUPPORT
void _lightMQTTCallback(unsigned int type, const char * topic, const char * payload) {
String mqtt_group_color = getSetting("mqttGroupColor");
if (type == MQTT_CONNECT_EVENT) {
@ -463,6 +475,10 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl
mqttSubscribe(MQTT_TOPIC_COLOR_HSV);
}
// Group color
if (mqtt_group_color.length() > 0) mqttSubscribeRaw(mqtt_group_color.c_str());
// Channels
char buffer[strlen(MQTT_TOPIC_CHANNEL) + 3];
snprintf_P(buffer, sizeof(buffer), PSTR("%s/+"), MQTT_TOPIC_CHANNEL);
mqttSubscribe(buffer);
@ -471,6 +487,13 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl
if (type == MQTT_MESSAGE_EVENT) {
// Group color
if ((mqtt_group_color.length() > 0) & (mqtt_group_color.equals(topic))) {
lightColor(payload, true);
lightUpdate(true, mqttForward(), false);
return;
}
// Match topic
String t = mqttSubtopic((char *) topic);
@ -478,28 +501,33 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl
if (t.equals(MQTT_TOPIC_MIRED)) {
_fromMireds(atol(payload));
lightUpdate(true, mqttForward());
return;
}
// Color temperature in kelvins
if (t.equals(MQTT_TOPIC_KELVIN)) {
_fromKelvin(atol(payload));
lightUpdate(true, mqttForward());
return;
}
// Color
if (t.equals(MQTT_TOPIC_COLOR) || t.equals(MQTT_TOPIC_COLOR_RGB)) { // DEPRECATE MQTT_TOPIC_COLOR
lightColor(payload, true);
lightUpdate(true, mqttForward());
return;
}
if (t.equals(MQTT_TOPIC_COLOR_HSV)) {
lightColor(payload, false);
lightUpdate(true, mqttForward());
return;
}
// Brightness
if (t.equals(MQTT_TOPIC_BRIGHTNESS)) {
_light_brightness = constrain(atoi(payload), 0, LIGHT_MAX_BRIGHTNESS);
lightUpdate(true, mqttForward());
return;
}
// Channel
@ -511,6 +539,7 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl
}
lightChannel(channelID, atoi(payload));
lightUpdate(true, mqttForward());
return;
}
}
@ -519,7 +548,7 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl
void lightMQTT() {
char buffer[12];
char buffer[20];
if (_light_has_color) {
@ -548,6 +577,15 @@ void lightMQTT() {
}
void lightMQTTGroup() {
String mqtt_group_color = getSetting("mqttGroupColor");
if (mqtt_group_color.length()>0) {
char buffer[20];
_toCSV(buffer, sizeof(buffer), true);
mqttSendRaw(mqtt_group_color.c_str(), buffer);
}
}
#endif
// -----------------------------------------------------------------------------
@ -566,7 +604,7 @@ unsigned char lightWhiteChannels() {
return _light_channel.size() % 3;
}
void lightUpdate(bool save, bool forward) {
void lightUpdate(bool save, bool forward, bool group_forward) {
// Configure color transition
_light_steps_left = _light_use_transitions ? LIGHT_TRANSITION_STEPS : 1;
@ -575,6 +613,7 @@ void lightUpdate(bool save, bool forward) {
// Report color & brightness to MQTT broker
#if MQTT_SUPPORT
if (forward) lightMQTT();
if (group_forward) lightMQTTGroup();
#endif
// Report color to WS clients (using current brightness setting)
@ -589,6 +628,10 @@ void lightUpdate(bool save, bool forward) {
};
void lightUpdate(bool save, bool forward) {
lightUpdate(save, forward, true);
}
#if LIGHT_SAVE_ENABLED == 0
void lightSave() {
_lightColorSave();
@ -667,6 +710,7 @@ void lightBrightnessStep(int steps) {
void _lightWebSocketOnSend(JsonObject& root) {
root["colorVisible"] = 1;
root["mqttGroupColor"] = getSetting("mqttGroupColor");
root["useColor"] = _light_has_color;
root["useWhite"] = _light_use_white;
root["useGamma"] = _light_use_gamma;


+ 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


+ 29
- 53
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>
*/
@ -45,6 +45,7 @@ bool _mqtt_forward;
char *_mqtt_user = 0;
char *_mqtt_pass = 0;
char *_mqtt_will;
char *_mqtt_clientid;
#if MQTT_SKIP_RETAINED
unsigned long _mqtt_connected_at = 0;
#endif
@ -209,6 +210,8 @@ void mqttRegister(mqtt_callback_f callback) {
// Callbacks
// -----------------------------------------------------------------------------
#if WEB_SUPPORT
void _mqttWebSocketOnSend(JsonObject& root) {
root["mqttVisible"] = 1;
root["mqttStatus"] = mqttConnected();
@ -216,6 +219,7 @@ void _mqttWebSocketOnSend(JsonObject& root) {
root["mqttServer"] = getSetting("mqttServer", MQTT_SERVER);
root["mqttPort"] = getSetting("mqttPort", MQTT_PORT);
root["mqttUser"] = getSetting("mqttUser");
root["mqttClientID"] = getSetting("mqttClientID");
root["mqttPassword"] = getSetting("mqttPassword");
root["mqttKeep"] = _mqtt_keepalive;
root["mqttRetain"] = _mqtt_retain;
@ -229,6 +233,12 @@ void _mqttWebSocketOnSend(JsonObject& root) {
root["mqttUseJson"] = getSetting("mqttUseJson", MQTT_USE_JSON).toInt() == 1;
}
void _mqttConfigure() {
if (getSetting("mqttClientID").length() == 0) delSetting("mqttClientID");
}
#endif
void _mqttCallback(unsigned int type, const char * topic, const char * payload) {
if (type == MQTT_CONNECT_EVENT) {
@ -309,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);
@ -385,17 +354,21 @@ void mqttConnect() {
if (_mqtt_user) free(_mqtt_user);
if (_mqtt_pass) free(_mqtt_pass);
if (_mqtt_will) free(_mqtt_will);
if (_mqtt_clientid) free(_mqtt_clientid);
_mqtt_user = strdup(getSetting("mqttUser", MQTT_USER).c_str());
_mqtt_pass = strdup(getSetting("mqttPassword", MQTT_PASS).c_str());
_mqtt_will = strdup((_mqtt_topic + MQTT_TOPIC_STATUS).c_str());
_mqtt_clientid = strdup(getSetting("mqttClientID", getIdentifier()).c_str());
DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%d\n"), host, port);
#if MQTT_USE_ASYNC
_mqtt.setServer(host, port);
_mqtt.setKeepAlive(_mqtt_keepalive).setCleanSession(false);
_mqtt.setClientId(_mqtt_clientid);
_mqtt.setKeepAlive(_mqtt_keepalive);
_mqtt.setCleanSession(false);
_mqtt.setWill(_mqtt_will, _mqtt_qos, _mqtt_retain, "0");
if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) {
DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user);
@ -409,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"));
@ -418,9 +391,10 @@ void mqttConnect() {
#endif // ASYNC_TCP_SSL_ENABLED
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid);
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0);
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
_mqtt.connect();
@ -435,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 {
@ -469,14 +443,15 @@ void mqttConnect() {
if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) {
DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user);
response = _mqtt.connect(getIdentifier().c_str(), _mqtt_user, _mqtt_pass, _mqtt_will, _mqtt_qos, _mqtt_retain, "0");
response = _mqtt.connect(_mqtt_clientid, _mqtt_user, _mqtt_pass, _mqtt_will, _mqtt_qos, _mqtt_retain, "0");
} else {
response = _mqtt.connect(getIdentifier().c_str(), _mqtt_will, _mqtt_qos, _mqtt_retain, "0");
response = _mqtt.connect(_mqtt_clientid, _mqtt_will, _mqtt_qos, _mqtt_retain, "0");
}
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid);
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0);
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
}
@ -533,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
@ -576,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);
});
@ -589,6 +564,7 @@ void mqttSetup() {
#if WEB_SUPPORT
wsOnSendRegister(_mqttWebSocketOnSend);
wsOnAfterParseRegister(_mqttConfigure);
#endif
}


+ 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
}
// -----------------------------------------------------------------------------


+ 8
- 3
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>
*/
@ -345,7 +345,7 @@ void _relayBoot() {
case RELAY_BOOT_SAME:
status = ((mask & bit) == bit);
break;
case RELAY_BOOT_TOOGLE:
case RELAY_BOOT_TOGGLE:
status = ((mask & bit) != bit);
mask ^= bit;
trigger_save = true;
@ -364,7 +364,7 @@ void _relayBoot() {
bit <<= 1;
}
// Save if there is any relay in the RELAY_BOOT_TOOGLE mode
// Save if there is any relay in the RELAY_BOOT_TOGGLE mode
if (trigger_save) {
EEPROM.write(EEPROM_RELAY_STATUS, mask);
EEPROM.commit();
@ -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>
*/


+ 6
- 3
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>
*/
@ -252,11 +252,14 @@ void _rfbReceive() {
//DEBUG_MSG_P(PSTR("[RFBRIDGE] Received 0x%02X\n"), c);
if (receiving) {
if (c == RF_CODE_STOP) {
if (c == RF_CODE_STOP && (_uartpos == 1 || _uartpos == 10)) {
_rfbDecode();
receiving = false;
} else {
} else if (_uartpos < 10) {
_uartbuf[_uartpos++] = c;
} else {
// wrong message, should have received a RF_CODE_STOP
receiving = false;
}
} else if (c == RF_CODE_START) {
_uartpos = 0;


+ 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; };


+ 16
- 2
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;
@ -137,7 +147,11 @@ class DHTSensor : public BaseSensor {
pinMode(_gpio, OUTPUT);
noInterrupts();
digitalWrite(_gpio, LOW);
delayMicroseconds(_type == DHT_CHIP_DHT11 ? 20000 : 500);
if (_type == DHT_CHIP_DHT11) {
delay(20);
} else {
delayMicroseconds(500);
}
digitalWrite(_gpio, HIGH);
delayMicroseconds(40);
pinMode(_gpio, INPUT_PULLUP);


+ 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


+ 3090
- 3074
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() {


+ 46
- 0
code/extra_scripts.py View File

@ -0,0 +1,46 @@
#!/usr/bin/env python
import time
Import("env")
# ------------------------------------------------------------------------------
# Utils
# ------------------------------------------------------------------------------
class Color:
BLACK = '\x1b[1;30m'
RED = '\x1b[1;31m'
GREEN = '\x1b[1;32m'
YELLOW = '\x1b[1;33m'
BLUE = '\x1b[1;34m'
MAGENTA = '\x1b[1;35m'
CYAN = '\x1b[1;36m'
WHITE = '\x1b[1;37m'
LIGHT_GREY = '\x1b[0;30m'
LIGHT_RED = '\x1b[0;31m'
LIGHT_GREEN = '\x1b[0;32m'
LIGHT_YELLOW = '\x1b[0;33m'
LIGHT_BLUE = '\x1b[0;34m'
LIGHT_MAGENTA = '\x1b[0;35m'
LIGHT_CYAN = '\x1b[0;36m'
LIGHT_WHITE = '\x1b[0;37m'
def clr(color, text):
return color + str(text) + '\x1b[0m'
# ------------------------------------------------------------------------------
# Callbacks
# ------------------------------------------------------------------------------
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)
# ------------------------------------------------------------------------------
# Hooks
# ------------------------------------------------------------------------------
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", check_size)

+ 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

@ -102,7 +102,8 @@ var is_group = [
"ssid", "pass", "gw", "mask", "ip", "dns",
"relayBoot", "relayPulse", "relayTime",
"mqttGroup", "mqttGroupInv",
"dczRelayIdx",
"dczRelayIdx", "dczMagnitude",
"tspkRelay", "tspkMagnitude",
"ledMode",
"adminPass"
];
@ -394,36 +395,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);
}
}
@ -683,6 +684,8 @@ function rfbSend() {
function processData(data) {
console.log(data);
// title
if ("app_name" in data) {
var title = data.app_name;
@ -842,14 +845,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;
}


+ 89
- 13
code/html/index.html View File

@ -116,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>
@ -133,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/>
@ -399,6 +403,13 @@
<div class="pure-u-1 pure-u-lg-3-4 hint">If enabled color changes will be smoothed.</div>
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-4"><label>MQTT group</label></div>
<div class="pure-u-1 pure-u-lg-3-4"><input name="mqttGroupColor" class="pure-u-1" tabindex="13" action="reconnect" /></div>
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">Sync color between different lights.</div>
</div>
</fieldset>
</div>
</div>
@ -564,9 +575,19 @@
<input class="pure-u-1 pure-u-lg-1-4" name="mqttPassword" type="password" size="20" tabindex="24" placeholder="Leave blank if no pass" autocomplete="false" />
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">MQTT Client ID</label>
<input class="pure-u-1 pure-u-lg-1-4" name="mqttClientID" type="text" size="20" tabindex="25" />
<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-1 pure-u-lg-3-4 hint">
If left empty the firmware will generate a client ID based on the serial number of the chip.
</div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">MQTT QoS</label>
<select class="pure-u-1 pure-u-lg-1-4" name="mqttQoS">
<select class="pure-u-1 pure-u-lg-1-4" name="mqttQoS" tabindex="26">
<option value="0">0: At most once</option>
<option value="1">1: At least once</option>
<option value="2">2: Exactly once</option>
@ -575,22 +596,22 @@
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">MQTT Retain</label>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="mqttRetain" tabindex="25" /></div>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="mqttRetain" tabindex="27" /></div>
</div>
<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="25" />
<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">
<label class="pure-u-1 pure-u-lg-1-4">Use secure connection (SSL)</label>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="mqttUseSSL" tabindex="26" /></div>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="mqttUseSSL" tabindex="29" /></div>
</div>
<div class="pure-g module module-mqttssl">
<label class="pure-u-1 pure-u-lg-1-4">SSL Fingerprint</label>
<input class="pure-u-1 pure-u-lg-3-4" name="mqttFP" type="text" size="59" tabindex="26" />
<input class="pure-u-1 pure-u-lg-3-4" name="mqttFP" type="text" size="59" tabindex="30" />
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">
This is the fingerprint for the SSL certificate of the server.<br />
@ -602,7 +623,7 @@
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4">MQTT Root Topic</label>
<input class="pure-u-1 pure-u-lg-3-4" name="mqttTopic" type="text" size="20" tabindex="27" />
<input class="pure-u-1 pure-u-lg-3-4" name="mqttTopic" type="text" size="20" tabindex="31" />
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">
This is the root topic for this device. A trailing slash will be added if not preset. The {identifier} placeholder will be replaced by the device hostname.<br />
@ -618,7 +639,7 @@
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-4"><label>Use JSON payload</label></div>
<div class="pure-u-1 pure-u-lg-3-4"><input type="checkbox" name="mqttUseJson" tabindex="26" /></div>
<div class="pure-u-1 pure-u-lg-3-4"><input type="checkbox" name="mqttUseJson" tabindex="32" /></div>
<div class="pure-u-1 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">
All messages (except the device status) will be included in a JSON payload along with the timestamp and hostname
@ -721,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>
@ -983,7 +1044,7 @@
<option value="0">Always OFF</option>
<option value="1">Always ON</option>
<option value="2">Same as before</option>
<option value="3">Toogle before</option>
<option value="3">Toggle before</option>
</select>
</div>
<div class="pure-g">
@ -1011,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>
@ -1026,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>


+ 52
- 29
code/memanalyzer.py View File

@ -19,6 +19,7 @@ import shlex
import commands
import subprocess
import sys
import os
import re
import argparse
@ -39,6 +40,12 @@ description = "ESPurna Memory Analyzer v0.1"
#-------------------------------------------------------------------------------
def file_size(file):
try:
return os.stat(file).st_size
except:
return 0
def analyse_memory(elf_file):
command = "%s -t '%s' " % (objdump_binary, elf_file)
@ -107,7 +114,7 @@ try:
# Parse command line options
parser = argparse.ArgumentParser(description=description)
parser.add_argument("modules", nargs='*', help="Modules to test")
parser.add_argument("modules", nargs='*', help="Modules to test (use ALL to test them all)")
parser.add_argument("-c", "--core", help="use core as base configuration instead of default", default=0, action='count')
parser.add_argument("-l", "--list", help="list available modules", default=0, action='count')
args = parser.parse_args()
@ -133,10 +140,12 @@ try:
sys.exit(0)
# Which modules to test?
test_modules = []
if len(args.modules) > 0:
test_modules = args.modules
else:
test_modules = available_modules.keys()
if "ALL" in args.modules:
test_modules = available_modules.keys()
else:
test_modules = args.modules
# Check test modules exist
for module in test_modules:
@ -153,20 +162,26 @@ try:
modules = available_modules
# Show init message
print "Analyzing module(s) %s on top of %s configuration\n" % (", ".join(test_modules), "CORE" if args.core > 0 else "DEFAULT")
output_format="{:<20}|{:<11}|{:<11}|{:<11}|{:<11}|{:<11}"
if len(test_modules) > 0:
print "Analyzing module(s) %s on top of %s configuration\n" % (", ".join(test_modules), "CORE" if args.core > 0 else "DEFAULT")
else:
print "Analyzing %s configuration\n" % ("CORE" if args.core > 0 else "DEFAULT")
output_format="{:<20}|{:<11}|{:<11}|{:<11}|{:<11}|{:<11}|{:<12}"
print(output_format.format(
"Module",
"Cache IRAM",
"Init RAM",
"R.O. RAM",
"Uninit RAM",
"Flash ROM"
"Flash ROM",
"Binary size"
))
# Build the core without modules to get base memory usage
run(env, modules)
base = analyse_memory(".pioenvs/"+env+"/firmware.elf")
base = analyse_memory(".pioenvs/%s/firmware.elf" % env)
base['size'] = file_size(".pioenvs/%s/firmware.bin" % env)
print(output_format.format(
"CORE" if args.core == 1 else "DEFAULT",
base['text'],
@ -174,6 +189,7 @@ try:
base['rodata'],
base['bss'],
base['irom0_text'],
base['size'],
))
# Test each module
@ -182,7 +198,8 @@ try:
modules[module] = 1
run(env, modules)
results[module]=analyse_memory(".pioenvs/"+env+"/firmware.elf")
results[module]=analyse_memory(".pioenvs/%s/firmware.elf" % env)
results[module]['size'] = file_size(".pioenvs/%s/firmware.bin" % env)
modules[module] = 0
print(output_format.format(
@ -192,33 +209,39 @@ try:
results[module]['rodata'] - base['rodata'],
results[module]['bss'] - base['bss'],
results[module]['irom0_text'] - base['irom0_text'],
results[module]['size'] - base['size'],
))
# Test all modules
for module in test_modules:
modules[module] = 1
run(env, modules)
total = analyse_memory(".pioenvs/"+env+"/firmware.elf")
if len(test_modules) > 0:
for module in test_modules:
modules[module] = 1
run(env, modules)
total = analyse_memory(".pioenvs/%s/firmware.elf" % env)
total['size'] = file_size(".pioenvs/%s/firmware.bin" % env)
if len(test_modules) > 1:
print(output_format.format(
"ALL MODULES",
total['text'] - base['text'],
total['data'] - base['data'],
total['rodata'] - base['rodata'],
total['bss'] - base['bss'],
total['irom0_text'] - base['irom0_text'],
total['size'] - base['size'],
))
if len(test_modules) > 1:
print(output_format.format(
"ALL MODULES",
total['text'] - base['text'],
total['data'] - base['data'],
total['rodata'] - base['rodata'],
total['bss'] - base['bss'],
total['irom0_text'] - base['irom0_text'],
"TOTAL",
total['text'],
total['data'],
total['rodata'],
total['bss'],
total['irom0_text'],
total['size'],
))
print(output_format.format(
"TOTAL",
total['text'],
total['data'],
total['rodata'],
total['bss'],
total['irom0_text'],
))
except:
raise


+ 221
- 0
code/ota.py View File

@ -0,0 +1,221 @@
#!/usr/bin/env python
#-------------------------------------------------------------------------------
# ESPurna OTA manager
# xose.perez@gmail.com
#
# Requires PlatformIO Core
#-------------------------------------------------------------------------------
import sys
import re
import logging
import socket
import argparse
import subprocess
from time import sleep
from zeroconf import ServiceBrowser, ServiceStateChange, Zeroconf
#-------------------------------------------------------------------------------
devices = []
description = "ESPurna OTA Manager v0.1"
#-------------------------------------------------------------------------------
def on_service_state_change(zeroconf, service_type, name, state_change):
'''
Callback that adds discovered devices to "devices" list
'''
if state_change is ServiceStateChange.Added:
info = zeroconf.get_service_info(service_type, name)
if info:
hostname = info.server.split(".")[0]
device = {
'hostname': hostname.upper(),
'ip': socket.inet_ntoa(info.address)
}
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')
devices.append(device)
def list():
'''
Shows the list of discovered devices
'''
output_format="{:>3} {:<25}{:<25}{:<15}{:<15}{:<30}{:<10}{:<10}{:<10}"
print(output_format.format(
"#",
"HOSTNAME",
"IP",
"APP",
"VERSION",
"DEVICE",
"MEM_SIZE",
"SDK_SIZE",
"FREE_SPACE"
))
print "-" * 146
index = 0
for device in devices:
index = index + 1
print(output_format.format(
index,
device.get('hostname', ''),
device.get('ip', ''),
device.get('app', ''),
device.get('version', ''),
device.get('device', ''),
device.get('mem_size', ''),
device.get('sdk_size', ''),
device.get('free_space', ''),
))
print
def get_boards():
'''
Grabs board types fro hardware.h file
'''
boards = []
for line in open("espurna/config/hardware.h"):
m = re.search(r'defined\((\w*)\)', line)
if m:
boards.append(m.group(1))
return sorted(boards)
def flash():
'''
Grabs info from the user about what device to flash
'''
# Choose the board
try:
index = int(input("Choose the board you want to flash (empty if none of these): "))
except:
index = 0
if index < 0 or len(devices) < index:
print "Board number must be between 1 and %s\n" % str(len(devices))
return None
board = {'board': '', 'ip': '', 'size': 0 , 'auth': '', 'flags': ''}
if index > 0:
device = devices[index-1]
board['board'] = device.get('device', '')
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
# Choose board type if none before
if len(board['board']) == 0:
print
count = 1
boards = get_boards()
for name in boards:
print "%3d\t%s" % (count, name)
count = count + 1
print
try:
index = int(input("Choose the board type you want to flash: "))
except:
index = 0
if index < 1 or len(boards) < index:
print "Board number must be between 1 and %s\n" % str(len(boards))
return None
board['board'] = boards[index-1]
# Choose board size of none before
if board['size'] == 0:
try:
board['size'] = int(input("Board memory size (1 for 1M, 4 for 4M): "))
except:
print "Wrong memory size"
return None
# Choose IP of none before
if len(board['ip']) == 0:
try:
board['ip'] = raw_input("IP of the device to flash (empty for 192.168.4.1): ") or "192.168.4.1"
except:
print "Wrong IP"
return None
board['auth'] = raw_input("Authorization key of the device to flash: ")
board['flags'] = raw_input("Extra flags for the build: ")
return board
def run(device, env):
command = "export ESPURNA_IP=\"%s\"; export ESPURNA_BOARD=\"%s\"; export ESPURNA_AUTH=\"%s\"; export ESPURNA_FLAGS=\"%s\"; platformio run --silent --environment %s -t upload"
command = command % (device['ip'], device['board'], device['auth'], device['flags'], env)
subprocess.check_call(command, shell=True)
#-------------------------------------------------------------------------------
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()
print
print description
print
# Enable logging if verbose
#logging.basicConfig(level=logging.DEBUG)
#logging.getLogger('zeroconf').setLevel(logging.DEBUG)
# Look for sevices
zeroconf = Zeroconf()
browser = ServiceBrowser(zeroconf, "_arduino._tcp.local.", handlers=[on_service_state_change])
sleep(1)
zeroconf.close()
# Sort list
field = args.sort.lower()
if field not in devices[0]:
print "Unknown field '%s'\n" % field
sys.exit(1)
devices = sorted(devices, key=lambda device: device.get(field, ''))
# List devices
list()
# Flash device
if args.flash > 0:
device = flash()
if device:
# Flash core version?
if args.core > 0:
device['flags'] = "-DESPURNA_CORE " + device['flags']
env = "esp8266-%sm-ota" % device['size']
# Summary
print
print "ESPURNA_IP = %s" % device['ip']
print "ESPURNA_BOARD = %s" % device['board']
print "ESPURNA_AUTH = %s" % device['auth']
print "ESPURNA_FLAGS = %s" % device['flags']
print "ESPURNA_ENV = %s" % env
response = raw_input("\nAre these values right [y/N]: ")
print
if response == "y":
run(device, env)

+ 0
- 225
code/ota_flash.sh View File

@ -1,225 +0,0 @@
#!/bin/bash
ip=
board=
size=
auth=
flags=
export boards=()
ips=""
exists() {
command -v "$1" >/dev/null 2>&1
}
echo_pad() {
string=$1
pad=$2
printf '%s' "$string"
printf '%*s' $(( $pad - ${#string} ))
}
useAvahi() {
echo_pad "#" 4
echo_pad "HOSTNAME" 25
echo_pad "IP" 25
echo_pad "APP" 15
echo_pad "VERSION" 15
echo_pad "DEVICE" 30
echo_pad "MEM_SIZE" 10
echo_pad "SDK_SIZE" 10
echo
printf -v line '%*s\n' 134
echo ${line// /-}
counter=0
ip_file="/tmp/espurna.flash.ips"
board_file="/tmp/espurna.flash.boards"
count_file="/tmp/espurna.flash.count"
size_file="/tmp/espurna.flash.size"
echo -n "" > $ip_file
echo -n "" > $board_file
echo -n "" > $size_file
echo -n "$counter" > $count_file
avahi-browse -t -r -p "_arduino._tcp" 2>/dev/null | grep ^= | sort -t ';' -k 3 | while read line; do
(( counter++ ))
echo "$counter" > $count_file
hostname=`echo $line | cut -d ';' -f4`
ip=`echo $line | cut -d ';' -f8`
txt=`echo $line | cut -d ';' -f10`
app_name=`echo $txt | sed -n "s/.*app_name=\([^\"]*\).*/\1/p"`
app_version=`echo $txt | sed -n "s/.*app_version=\([^\"]*\).*/\1/p"`
board=`echo $txt | sed -n "s/.*target_board=\([^\"]*\).*/\1/p"`
mem_size=`echo $txt | sed -n "s/.*mem_size=\([^\"]*\).*/\1/p"`
sdk_size=`echo $txt | sed -n "s/.*sdk_size=\([^\"]*\).*/\1/p"`
echo_pad "$counter" 4
echo_pad "$hostname" 25
echo_pad "http://$ip" 25
echo_pad "$app_name" 15
echo_pad "$app_version" 15
echo_pad "$board" 30
echo_pad "$mem_size" 10
echo_pad "$sdk_size" 10
echo
echo -n "$ip;" >> $ip_file
echo -n "$board;" >> $board_file
if [ "$mem_size" == "$sdk_size" ]; then
mem_size=`echo $mem_size | head -c 1`
echo -n "$mem_size;" >> $size_file
else
echo -n ";" >> $size_file
fi
done
echo
read -p "Choose the board you want to flash (empty if none of these): " num
# None of these
if [ "$num" == "" ]; then
return
fi
# Check boundaries
counter=`cat $count_file`
if [ $num -lt 1 ] || [ $num -gt $counter ]; then
echo "Board number must be between 1 and $counter"
exit 1
fi
# Fill the fields
ip=`cat $ip_file | cut -d ';' -f$num`
board=`cat $board_file | cut -d ';' -f$num`
size=`cat $size_file | cut -d ';' -f$num`
}
getBoard() {
boards=(`cat espurna/config/hardware.h | grep "defined" | sed "s/.*(\(.*\)).*/\1/" | sort`)
echo_pad "#" 4
echo_pad "DEVICE" 30
echo
printf -v line '%*s\n' 34
echo ${line// /-}
counter=0
for board in "${boards[@]}"; do
(( counter++ ))
echo_pad "$counter" 4
echo_pad "$board" 30
echo
done
echo
read -p "Choose the board you want to flash (empty if none of these): " num
# None of these
if [ "$num" == "" ]; then
return
fi
# Check boundaries
counter=${#boards[*]}
if [ $num -lt 1 ] || [ $num -gt $counter ]; then
echo "Board code must be between 1 and $counter"
exit 1
fi
# Fill the fields
(( num -- ))
board=${boards[$num]}
}
# ------------------------------------------------------------------------------
# Welcome
echo
echo "--------------------------------------------------------------"
echo "ESPURNA FIRMWARE OTA FLASHER"
# Get current version
version=`cat espurna/config/version.h | grep APP_VERSION | awk '{print $3}' | sed 's/"//g'`
echo "Building for version $version"
echo "--------------------------------------------------------------"
echo
if exists avahi-browse; then
useAvahi
fi
if [ "$board" == "" ]; then
getBoard
fi
if [ "$board" == "" ]; then
read -p "Board type of the device to flash: " -e -i "NODEMCU_LOLIN" board
fi
if [ "$board" == "" ]; then
echo "You must define the board type"
exit 2
fi
if [ "$size" == "" ]; then
read -p "Board memory size (1 for 1M, 4 for 4M): " -e size
fi
if [ "$size" == "" ]; then
echo "You must define the board memory size"
exit 2
fi
if [ "$ip" == "" ]; then
read -p "IP of the device to flash: " -e -i 192.168.4.1 ip
fi
if [ "$ip" == "" ]; then
echo "You must define the IP of the device"
exit 2
fi
if [ "$auth" == "" ]; then
read -p "Authorization key of the device to flash: " auth
fi
if [ "$flags" == "" ]; then
read -p "Extra flags for the build: " -e -i "" flags
fi
env="esp8266-${size}m-ota"
echo
echo "ESPURNA_IP = $ip"
echo "ESPURNA_BOARD = $board"
echo "ESPURNA_AUTH = $auth"
echo "ESPURNA_FLAGS = $flags"
echo "ESPURNA_ENV = $env"
echo
echo -n "Are these values corrent [y/N]: "
read response
if [ "$response" != "y" ]; then
exit
fi
export ESPURNA_IP=$ip
export ESPURNA_BOARD=$board
export ESPURNA_AUTH=$auth
export ESPURNA_FLAGS=$flags
pio run -e $env -t upload

+ 0
- 74
code/ota_list.sh View File

@ -1,74 +0,0 @@
#!/bin/bash
exists() {
command -v "$1" >/dev/null 2>&1
}
echo_pad() {
string=$1
pad=$2
printf '%s' "$string"
printf '%*s' $(( $pad - ${#string} ))
}
useAvahi() {
echo_pad "#" 4
echo_pad "HOSTNAME" 25
echo_pad "IP" 25
echo_pad "APP" 15
echo_pad "VERSION" 15
echo_pad "DEVICE" 30
echo_pad "MEM_SIZE" 10
echo_pad "SDK_SIZE" 10
echo
printf -v line '%*s\n' 134
echo ${line// /-}
counter=0
avahi-browse -t -r -p "_arduino._tcp" 2>/dev/null | grep ^= | sort -t ';' -k 3 | while read line; do
(( counter++ ))
hostname=`echo $line | cut -d ';' -f4`
ip=`echo $line | cut -d ';' -f8`
txt=`echo $line | cut -d ';' -f10`
app_name=`echo $txt | sed -n "s/.*app_name=\([^\"]*\).*/\1/p"`
app_version=`echo $txt | sed -n "s/.*app_version=\([^\"]*\).*/\1/p"`
board=`echo $txt | sed -n "s/.*target_board=\([^\"]*\).*/\1/p"`
mem_size=`echo $txt | sed -n "s/.*mem_size=\([^\"]*\).*/\1/p"`
sdk_size=`echo $txt | sed -n "s/.*sdk_size=\([^\"]*\).*/\1/p"`
echo_pad "$counter" 4
echo_pad "$hostname" 25
echo_pad "http://$ip" 25
echo_pad "$app_name" 15
echo_pad "$app_version" 15
echo_pad "$board" 30
echo_pad "$mem_size" 10
echo_pad "$sdk_size" 10
echo
done
echo
}
# ------------------------------------------------------------------------------
# Welcome
echo
echo "--------------------------------------------------------------"
echo "OTA-UPDATABLE DEVICES"
echo "--------------------------------------------------------------"
echo
if exists avahi-browse; then
useAvahi
else
echo "Avahi not installed"
exit 1
fi

+ 147
- 5
code/platformio.ini View File

@ -4,8 +4,8 @@ src_dir = espurna
data_dir = espurna/data
[common]
platform = espressif8266
#platform = https://github.com/platformio/platform-espressif8266.git#feature/stage
#platform = espressif8266
platform = https://github.com/platformio/platform-espressif8266.git#v1.5.0
build_flags = -g -DMQTT_MAX_PACKET_SIZE=400 ${env.ESPURNA_FLAGS}
debug_flags = -DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM
build_flags_512k = ${common.build_flags} -Wl,-Tesp8266.flash.512k0.ld
@ -26,15 +26,27 @@ 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
https://github.com/xoseperez/RemoteSwitch-arduino-library.git
https://github.com/markszabo/IRremoteESP8266#v2.2.0
lib_ignore =
#extra_scripts = post:core_version.py
extra_scripts =
extra_scripts = extra_scripts.py
# ------------------------------------------------------------------------------
[env:espurna-core]
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_1m} -DITEAD_SONOFF_BASIC -DESPURNA_CORE
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------
@ -58,6 +70,7 @@ lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=Serial -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1
upload_speed = 460800
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:wemos-d1mini-relayshield-ota]
platform = ${common.platform}
@ -69,6 +82,7 @@ build_flags = ${common.build_flags} -DWEMOS_D1_MINI_RELAYSHIELD -DDEBUG_FAUXMO=S
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
extra_scripts = ${common.extra_scripts}
[env:nodemcu-lolin]
platform = ${common.platform}
@ -79,6 +93,7 @@ lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH
upload_speed = 460800
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:nodemcu-lolin-ssl]
platform = espressif8266_stage
@ -89,6 +104,7 @@ lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1
upload_speed = 460800
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:nodemcu-lolin-ota]
platform = ${common.platform}
@ -101,6 +117,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------
@ -112,6 +129,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H06
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:tinkerman-espurna-h06-ota]
platform = ${common.platform}
@ -124,6 +142,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:tinkerman-espurna-h08]
platform = ${common.platform}
@ -133,6 +152,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H08
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:tinkerman-espurna-h08-ota]
platform = ${common.platform}
@ -145,6 +165,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------
@ -157,6 +178,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_BASIC
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-basic-ota]
platform = ${common.platform}
@ -170,6 +192,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-basic-dht]
platform = ${common.platform}
@ -180,6 +203,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_BASIC -DDHT_SUPPORT=1
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-basic-dht-ota]
platform = ${common.platform}
@ -193,6 +217,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-basic-dallas]
platform = ${common.platform}
@ -203,6 +228,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_BASIC -DDALLAS_SUPPORT=1
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-rf]
platform = ${common.platform}
@ -213,6 +239,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_RF
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-rf-ota]
platform = ${common.platform}
@ -226,6 +253,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-th]
platform = ${common.platform}
@ -236,6 +264,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_TH
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-th-ota]
platform = ${common.platform}
@ -249,6 +278,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-pow]
platform = ${common.platform}
@ -259,6 +289,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_POW
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-pow-ota]
platform = ${common.platform}
@ -272,6 +303,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-dual]
platform = ${common.platform}
@ -281,6 +313,7 @@ board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_DUAL
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-dual-ota]
platform = ${common.platform}
@ -293,6 +326,7 @@ build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_DUAL
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-dual-r2]
platform = ${common.platform}
@ -302,6 +336,7 @@ board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_DUAL_R2
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-dual-ota-r2]
platform = ${common.platform}
@ -314,6 +349,7 @@ build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_DUAL_R2
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-4ch]
platform = ${common.platform}
@ -324,6 +360,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_4CH
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-4ch-ota]
platform = ${common.platform}
@ -337,6 +374,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-4ch-pro]
platform = ${common.platform}
@ -347,6 +385,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_4CH_PRO
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-4ch-pro-ota]
platform = ${common.platform}
@ -360,6 +399,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-touch]
platform = ${common.platform}
@ -370,6 +410,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_TOUCH
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-touch-ota]
platform = ${common.platform}
@ -383,6 +424,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-b1]
platform = ${common.platform}
@ -393,6 +435,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_B1
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-b1-ota]
platform = ${common.platform}
@ -406,6 +449,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-t1-1ch]
platform = ${common.platform}
@ -416,6 +460,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_1CH
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-t1-1ch-ota]
platform = ${common.platform}
@ -429,6 +474,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-t1-2ch]
platform = ${common.platform}
@ -439,6 +485,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_2CH
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-t1-2ch-ota]
platform = ${common.platform}
@ -452,6 +499,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-t1-3ch]
platform = ${common.platform}
@ -462,6 +510,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_T1_3CH
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-t1-3ch-ota]
platform = ${common.platform}
@ -475,6 +524,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-led]
platform = ${common.platform}
@ -485,6 +535,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_LED
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-led-ota]
platform = ${common.platform}
@ -498,6 +549,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-rfbridge]
platform = ${common.platform}
@ -508,6 +560,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SONOFF_RFBRIDGE
monitor_baud = 19200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-rfbridge-ota]
platform = ${common.platform}
@ -521,6 +574,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=Algernon1 --port 8266
monitor_baud = 19200
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------
@ -533,6 +587,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_SLAMPHER
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-slampher-ota]
platform = ${common.platform}
@ -546,6 +601,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-s20]
platform = ${common.platform}
@ -556,6 +612,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_S20
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-s20-ota]
platform = ${common.platform}
@ -569,6 +626,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-1ch-inching]
platform = ${common.platform}
@ -579,6 +637,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_1CH_INCHING
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-1ch-inching-ota]
platform = ${common.platform}
@ -592,6 +651,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-motor]
platform = ${common.platform}
@ -602,6 +662,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_MOTOR
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-motor-ota]
platform = ${common.platform}
@ -615,6 +676,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------
@ -626,6 +688,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DELECTRODRAGON_WIFI_IOT -DDHT_SUPPORT=1
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:electrodragon-wifi-iot-ota]
platform = ${common.platform}
@ -638,6 +701,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:workchoice-ecoplug]
platform = ${common.platform}
@ -648,6 +712,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DWORKCHOICE_ECOPLUG
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:workchoice-ecoplug-ota]
platform = ${common.platform}
@ -661,6 +726,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:jangoe-wifi-relay]
platform = ${common.platform}
@ -670,6 +736,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DJANGOE_WIFI_RELAY_NC
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:jangoe-wifi-relay-ota]
platform = ${common.platform}
@ -682,6 +749,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:openenergymonitor-mqtt-relay]
platform = ${common.platform}
@ -691,6 +759,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DOPENENERGYMONITOR_MQTT_RELAY -DDALLAS_SUPPORT=1
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:openenergymonitor-mqtt-relay-ota]
platform = ${common.platform}
@ -703,6 +772,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:jorgegarcia-wifi-relays]
platform = ${common.platform}
@ -712,6 +782,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DJORGEGARCIA_WIFI_RELAYS
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:jorgegarcia-wifi-relays-ota]
platform = ${common.platform}
@ -724,6 +795,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:aithinker-ai-light]
platform = ${common.platform}
@ -734,6 +806,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DAITHINKER_AI_LIGHT
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:aithinker-ai-light-ota]
platform = ${common.platform}
@ -747,6 +820,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:magichome-led-controller]
platform = ${common.platform}
@ -757,6 +831,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:magichome-led-controller-ota]
platform = ${common.platform}
@ -770,6 +845,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:magichome-led-controller-20]
platform = ${common.platform}
@ -780,6 +856,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER_20
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:magichome-led-controller-20-ota]
platform = ${common.platform}
@ -792,6 +869,7 @@ build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER_20
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:huacanxing-h801]
platform = ${common.platform}
@ -802,6 +880,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DHUACANXING_H801
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:huacanxing-h801-ota]
platform = ${common.platform}
@ -815,6 +894,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:huacanxing-h802]
platform = ${common.platform}
@ -825,6 +905,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DHUACANXING_H802
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:huacanxing-h802-ota]
platform = ${common.platform}
@ -838,6 +919,7 @@ 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-lc01]
platform = ${common.platform}
@ -848,6 +930,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC01
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:arilux-al-lc01-ota]
platform = ${common.platform}
@ -861,6 +944,32 @@ 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-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}
@ -871,6 +980,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC06
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:arilux-al-lc06-ota]
platform = ${common.platform}
@ -884,6 +994,7 @@ 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-lc11]
platform = ${common.platform}
@ -894,6 +1005,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_AL_LC11
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:arilux-al-lc11-ota]
platform = ${common.platform}
@ -907,6 +1019,7 @@ 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-e27]
platform = ${common.platform}
@ -917,6 +1030,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = -g -Wl,-Tesp8266.flash.1m0.ld -DARILUX_E27
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:arilux-e27-ota]
platform = ${common.platform}
@ -930,6 +1044,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-bnsz01]
platform = ${common.platform}
@ -940,6 +1055,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DITEAD_BNSZ01
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-bnsz01-ota]
platform = ${common.platform}
@ -953,6 +1069,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:wion-50055]
platform = ${common.platform}
@ -963,6 +1080,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DWION_50055
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:wion-50055-ota]
platform = ${common.platform}
@ -976,6 +1094,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:exs-wifi-relay-v31]
platform = ${common.platform}
@ -986,6 +1105,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DEXS_WIFI_RELAY_V31
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:exs-wifi-relay-v31-ota]
platform = ${common.platform}
@ -999,6 +1119,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:wemos-v9261f]
platform = ${common.platform}
@ -1009,6 +1130,7 @@ lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DGENERIC_V9261F
upload_speed = 460800
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:wemos-v9261f-ota]
platform = ${common.platform}
@ -1021,6 +1143,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:esp01-v9261f]
platform = ${common.platform}
@ -1031,6 +1154,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DGENERIC_V9261F
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:esp01-v9261f-ota]
platform = ${common.platform}
@ -1044,6 +1168,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:wemos-ech1560]
platform = ${common.platform}
@ -1054,6 +1179,7 @@ lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DGENERIC_ECH1560
upload_speed = 460800
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:wemos-ech1560-ota]
platform = ${common.platform}
@ -1066,6 +1192,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:esp01-ech1560]
platform = ${common.platform}
@ -1076,6 +1203,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DGENERIC_ECH1560
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:esp01-ech1560-ota]
platform = ${common.platform}
@ -1089,6 +1217,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:mancavemade-esplive]
platform = ${common.platform}
@ -1099,6 +1228,7 @@ lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DMANCAVEMADE_ESPLIVE
upload_speed = 460800
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:mancavemade-esplive-ota]
platform = ${common.platform}
@ -1111,6 +1241,7 @@ upload_speed = 460800
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:intermittech-quinled]
platform = ${common.platform}
@ -1121,6 +1252,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DINTERMITTECH_QUINLED
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:intermittech-quinled-ota]
platform = ${common.platform}
@ -1134,6 +1266,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:xenon-sm-pw702u]
platform = ${common.platform}
@ -1144,6 +1277,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DXENON_SM_PW702U
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:xenon-sm-pw702u-ota]
platform = ${common.platform}
@ -1157,6 +1291,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:authometion-lyt8266]
platform = ${common.platform}
@ -1167,6 +1302,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DAUTHOMETION_LYT8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:authometion-lyt8266-ota]
platform = ${common.platform}
@ -1180,6 +1316,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:yjzk-switch-2ch]
platform = ${common.platform}
@ -1190,6 +1327,7 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DYJZK_SWITCH_2CH
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:yjzk-switch-2ch-ota]
platform = ${common.platform}
@ -1203,6 +1341,7 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:generic-8ch]
platform = ${common.platform}
@ -1213,6 +1352,7 @@ lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DGENERIC_8CH
upload_speed = 460800
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------
# GENERIC OTA ENVIRONMENTS
@ -1229,6 +1369,7 @@ build_flags = ${common.build_flags_1m} -D${env.ESPURNA_BOARD}
upload_speed = 115200
upload_port = "${env.ESPURNA_IP}"
upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266
extra_scripts = ${common.extra_scripts}
[env:esp8266-4m-ota]
platform = ${common.platform}
@ -1241,3 +1382,4 @@ build_flags = ${common.build_flags} -D${env.ESPURNA_BOARD}
upload_speed = 115200
upload_port = "${env.ESPURNA_IP}"
upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266
extra_scripts = ${common.extra_scripts}

+ 7
- 0
code/requirements.txt View File

@ -0,0 +1,7 @@
enum-compat==0.0.2
enum34==1.1.6
netifaces==0.10.6
ordereddict==1.1
six==1.11.0
sortedcontainers==1.5.9
zeroconf==0.19.1

Loading…
Cancel
Save