Browse Source

Merge branch 'dev'

fastled 1.9.8
Xose Pérez 7 years ago
parent
commit
13ed8dab2e
27 changed files with 4733 additions and 3874 deletions
  1. +20
    -0
      CHANGELOG.md
  2. +1
    -1
      README.md
  3. +2
    -1
      code/build.sh
  4. +8
    -1
      code/espurna/alexa.ino
  5. +2
    -1
      code/espurna/config/arduino.h
  6. +126
    -10
      code/espurna/config/general.h
  7. +46
    -91
      code/espurna/config/hardware.h
  8. +1
    -1
      code/espurna/config/version.h
  9. BIN
      code/espurna/data/index.html.gz
  10. +129
    -21
      code/espurna/dht.ino
  11. +6
    -0
      code/espurna/espurna.ino
  12. +10
    -1
      code/espurna/hardware.ino
  13. +107
    -0
      code/espurna/ir.ino
  14. +94
    -42
      code/espurna/light.ino
  15. +34
    -167
      code/espurna/light_ir.ino
  16. +25
    -22
      code/espurna/power.h
  17. +54
    -34
      code/espurna/power.ino
  18. +1
    -3
      code/espurna/power_emon.ino
  19. +1
    -1
      code/espurna/power_hlw8012.ino
  20. +448
    -0
      code/espurna/pwm.c
  21. +33
    -0
      code/espurna/pwm.h
  22. +3460
    -3444
      code/espurna/static/index.html.gz.h
  23. +7
    -4
      code/espurna/web.ino
  24. +0
    -5
      code/html/custom.css
  25. +12
    -11
      code/html/custom.js
  26. +55
    -5
      code/html/index.html
  27. +51
    -8
      code/platformio.ini

+ 20
- 0
CHANGELOG.md View File

@ -3,6 +3,26 @@
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.9.8] 2017-11-08
### Fixed
- Removed dimmer lights flicker when saving to EEPROM (#191)
- Fixed low brightness in dimmer lights (#157)
- Fixed blank fields in energy (#258, #259)
- Fixed support for Arilux AL-LC06
- Updated fauxmoESP library with support for GetBinaryState actions
### Added
- Support for IR remotes
- Option to select power read and report interval from webUI
- Option to report real-time values in API, configurable via webUI
- Support for ESPurna-H Board v0.8
- Preliminary support for Arilux E28 light bulb (untested)
### Changed
- PWM using ESP8266_new_pwm by Stephan Bruens (https://github.com/StefanBruens/ESP8266_new_pwm)
- Using own DHT implementation (removed dependency on Adafruit libraries)
- Disabled serial debug for Sonoff RFBridge
## [1.9.7] 2017-10-25
### Fixed
- Fix Alexa interface switching on all lights (#256)


+ 1
- 1
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.9.7**, read the [changelog](https://bitbucket.org/xoseperez/espurna/src/master/CHANGELOG.md).
> **Current Release Version is 1.9.8**, 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.


+ 2
- 1
code/build.sh View File

@ -42,9 +42,10 @@ node node_modules/gulp/bin/gulp.js || exit
# Build all the required firmwares
echo "--------------------------------------------------------------"
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
mv .pioenvs/$environment/firmware.bin firmware/espurna-$version-$environment.bin
mv .pioenvs/$environment/firmware.bin firmware/espurna-$version/espurna-$version-$environment.bin
done
echo "--------------------------------------------------------------"

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

@ -30,6 +30,7 @@ void alexaSetup() {
moveSetting("fauxmoEnabled", "alexaEnabled");
alexaConfigure();
unsigned int relays = relayCount();
String hostname = getSetting("hostname");
if (relays == 1) {
@ -39,11 +40,17 @@ void alexaSetup() {
alexa.addDevice((hostname + "_" + i).c_str());
}
}
alexa.onMessage([relays](unsigned char device_id, const char * name, bool state) {
alexa.onSetState([relays](unsigned char device_id, const char * name, bool state) {
_alexa_change = true;
_alexa_device_id = device_id;
_alexa_state = state;
});
alexa.onGetState([relays](unsigned char device_id, const char * name) {
return relayStatus(device_id);
});
}
void alexaLoop() {


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

@ -10,7 +10,7 @@
//#define NODEMCU_LOLIN
//#define WEMOS_D1_MINI_RELAYSHIELD
//#define TINKERMAN_ESPURNA_H06
//#define TINKERMAN_ESPURNA_H07
//#define TINKERMAN_ESPURNA_H08
//#define ITEAD_SONOFF_BASIC
//#define ITEAD_SONOFF_RF
//#define ITEAD_SONOFF_TH
@ -68,6 +68,7 @@
//#define HOMEASSISTANT_SUPPORT 0
//#define I2C_SUPPORT 1
//#define INFLUXDB_SUPPORT 0
//#define IR_SUPPORT 1
//#define MDNS_SUPPORT 0
//#define NOFUSS_SUPPORT 1
//#define NTP_SUPPORT 0


+ 126
- 10
code/espurna/config/general.h View File

@ -311,8 +311,9 @@ PROGMEM const char* const custom_reset_string[] = {
// This will only be enabled if WEB_SUPPORT is 1 (this is the default value)
#define API_ENABLED 0 // Do not enable API by default
#define API_ENABLED 0 // Do not enable API by default
#define API_BUFFER_SIZE 10 // Size of the buffer for HTTP GET API responses
#define API_REAL_TIME_VALUES 0 // Show filtered/median values by default (0 => median, 1 => real time)
// -----------------------------------------------------------------------------
// MDNS
@ -497,9 +498,17 @@ PROGMEM const char* const custom_reset_string[] = {
#endif
#ifndef LIGHT_MAX_PWM
#define LIGHT_MAX_PWM 4095 // Maximum PWM value
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
#define LIGHT_MAX_PWM 256
#endif
#if LIGHT_PROVIDER == LIGHT_PROVIDER_DIMMER
#define LIGHT_MAX_PWM 1000
#endif
#endif // LIGHT_MAX_PWM
#ifndef LIGHT_LIMIT_PWM
#define LIGHT_LIMIT_PWM LIGHT_MAX_PWM // Limit PWM to this value (prevent 100% power)
#endif
@ -509,6 +518,7 @@ PROGMEM const char* const custom_reset_string[] = {
#endif
#define LIGHT_MAX_BRIGHTNESS 255 // Maximun brightness value
#define LIGHT_STEP 32 // Step size
#define LIGHT_USE_COLOR 1 // Use 3 first channels as RGB
#define LIGHT_USE_WHITE 0 // Use white channel whenever RGB have the same value
#define LIGHT_USE_GAMMA 0 // Use gamma correction for color channels
@ -554,9 +564,9 @@ PROGMEM const char* const custom_reset_string[] = {
#endif
#define POWER_VOLTAGE 230 // Default voltage
#define POWER_MIN_READ_INTERVAL 2000 // Minimum read interval
#define POWER_READ_INTERVAL 6000 // Default reading interval (6 seconds)
#define POWER_REPORT_INTERVAL 60000 // Default report interval (1 minute)
#define POWER_REPORT_BUFFER 12 // Default buffer size ()
#define POWER_CURRENT_DECIMALS 2 // Decimals for current values
#define POWER_VOLTAGE_DECIMALS 0 // Decimals for voltage values
#define POWER_POWER_DECIMALS 0 // Decimals for power values
@ -596,9 +606,6 @@ PROGMEM const char* const custom_reset_string[] = {
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
#undef POWER_REPORT_BUFFER
#define POWER_REPORT_BUFFER 60 // Override median buffer size
#ifndef V9261F_PIN
#define V9261F_PIN 2 // TX pin from the V9261F
#endif
@ -619,9 +626,6 @@ PROGMEM const char* const custom_reset_string[] = {
#if POWER_PROVIDER == POWER_PROVIDER_ECH1560
#undef POWER_REPORT_BUFFER
#define POWER_REPORT_BUFFER 60 // Override median buffer size
#ifndef ECH1560_CLK_PIN
#define ECH1560_CLK_PIN 4 // Default CLK pin
#endif
@ -706,10 +710,122 @@ PROGMEM const char* const custom_reset_string[] = {
// Both ALEXA_SUPPORT and alexaEnabled should be 1 for Alexa support to work.
#define ALEXA_ENABLED 1
// -----------------------------------------------------------------------------
// RFBRIDGE
// -----------------------------------------------------------------------------
#define RF_SEND_TIMES 4 // How many times to send the message
#define RF_SEND_DELAY 250 // Interval between sendings in ms
// -----------------------------------------------------------------------------
// IR
// -----------------------------------------------------------------------------
#ifndef IR_SUPPORT
#define IR_SUPPORT 0 // Do not build with IR support by default
#endif
#ifndef IR_PIN
#define IR_PIN 4 // IR LED
#endif
// 24 Buttons Set of the IR Remote
#ifndef IR_BUTTON_SET
#define IR_BUTTON_SET 1 // IR button set to use (see below)
#endif
// IR Button modes
#define IR_BUTTON_MODE_NONE 0
#define IR_BUTTON_MODE_RGB 1
#define IR_BUTTON_MODE_HSV 2
#define IR_BUTTON_MODE_BRIGHTER 3
#define IR_BUTTON_MODE_STATE 4
#define IR_BUTTON_MODE_EFFECT 5
#define LIGHT_EFFECT_SOLID 0
#define LIGHT_EFFECT_FLASH 1
#define LIGHT_EFFECT_STROBE 2
#define LIGHT_EFFECT_FADE 3
#define LIGHT_EFFECT_SMOOTH 4
//Remote Buttons SET 1 (for the original Remote shipped with the controller)
#if IR_BUTTON_SET == 1
#define IR_BUTTON_COUNT 24
const unsigned long IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
{ 0xFF906F, IR_BUTTON_MODE_BRIGHTER, 1 },
{ 0xFFB847, IR_BUTTON_MODE_BRIGHTER, 0 },
{ 0xFFF807, IR_BUTTON_MODE_STATE, 0 },
{ 0xFFB04F, IR_BUTTON_MODE_STATE, 1 },
{ 0xFF9867, IR_BUTTON_MODE_RGB, 0xFF0000 },
{ 0xFFD827, IR_BUTTON_MODE_RGB, 0x00FF00 },
{ 0xFF8877, IR_BUTTON_MODE_RGB, 0x0000FF },
{ 0xFFA857, IR_BUTTON_MODE_RGB, 0xFFFFFF },
{ 0xFFE817, IR_BUTTON_MODE_RGB, 0xD13A01 },
{ 0xFF48B7, IR_BUTTON_MODE_RGB, 0x00E644 },
{ 0xFF6897, IR_BUTTON_MODE_RGB, 0x0040A7 },
{ 0xFFB24D, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FLASH },
{ 0xFF02FD, IR_BUTTON_MODE_RGB, 0xE96F2A },
{ 0xFF32CD, IR_BUTTON_MODE_RGB, 0x00BEBF },
{ 0xFF20DF, IR_BUTTON_MODE_RGB, 0x56406F },
{ 0xFF00FF, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_STROBE },
{ 0xFF50AF, IR_BUTTON_MODE_RGB, 0xEE9819 },
{ 0xFF7887, IR_BUTTON_MODE_RGB, 0x00799A },
{ 0xFF708F, IR_BUTTON_MODE_RGB, 0x944E80 },
{ 0xFF58A7, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FADE },
{ 0xFF38C7, IR_BUTTON_MODE_RGB, 0xFFFF00 },
{ 0xFF28D7, IR_BUTTON_MODE_RGB, 0x0060A1 },
{ 0xFFF00F, IR_BUTTON_MODE_RGB, 0xEF45AD },
{ 0xFF30CF, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_SMOOTH }
};
#endif
//Remote Buttons SET 2 (another identical IR Remote shipped with another controller)
#if IR_BUTTON_SET == 2
#define IR_BUTTON_COUNT 24
const unsigned long IR_BUTTON[IR_BUTTON_COUNT][3] PROGMEM = {
{ 0xFF00FF, IR_BUTTON_MODE_BRIGHTER, 1 },
{ 0xFF807F, IR_BUTTON_MODE_BRIGHTER, 0 },
{ 0xFF40BF, IR_BUTTON_MODE_STATE, 0 },
{ 0xFFC03F, IR_BUTTON_MODE_STATE, 1 },
{ 0xFF20DF, IR_BUTTON_MODE_RGB, 0xFF0000 },
{ 0xFFA05F, IR_BUTTON_MODE_RGB, 0x00FF00 },
{ 0xFF609F, IR_BUTTON_MODE_RGB, 0x0000FF },
{ 0xFFE01F, IR_BUTTON_MODE_RGB, 0xFFFFFF },
{ 0xFF10EF, IR_BUTTON_MODE_RGB, 0xD13A01 },
{ 0xFF906F, IR_BUTTON_MODE_RGB, 0x00E644 },
{ 0xFF50AF, IR_BUTTON_MODE_RGB, 0x0040A7 },
{ 0xFFD02F, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FLASH },
{ 0xFF30CF, IR_BUTTON_MODE_RGB, 0xE96F2A },
{ 0xFFB04F, IR_BUTTON_MODE_RGB, 0x00BEBF },
{ 0xFF708F, IR_BUTTON_MODE_RGB, 0x56406F },
{ 0xFFF00F, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_STROBE },
{ 0xFF08F7, IR_BUTTON_MODE_RGB, 0xEE9819 },
{ 0xFF8877, IR_BUTTON_MODE_RGB, 0x00799A },
{ 0xFF48B7, IR_BUTTON_MODE_RGB, 0x944E80 },
{ 0xFFC837, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_FADE },
{ 0xFF28D7, IR_BUTTON_MODE_RGB, 0xFFFF00 },
{ 0xFFA857, IR_BUTTON_MODE_RGB, 0x0060A1 },
{ 0xFF6897, IR_BUTTON_MODE_RGB, 0xEF45AD },
{ 0xFFE817, IR_BUTTON_MODE_EFFECT, LIGHT_EFFECT_SMOOTH }
};
#endif

+ 46
- 91
code/espurna/config/hardware.h View File

@ -1,4 +1,4 @@
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Configuration HELP
// -----------------------------------------------------------------------------
//
@ -63,7 +63,6 @@
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
// -----------------------------------------------------------------------------
// ESPurna
// -----------------------------------------------------------------------------
@ -110,11 +109,11 @@
#define HLW8012_CF1_PIN 13
#define HLW8012_CF_PIN 14
#elif defined(TINKERMAN_ESPURNA_H07)
#elif defined(TINKERMAN_ESPURNA_H08)
// Info
#define MANUFACTURER "TINKERMAN"
#define DEVICE "ESPURNA_H07"
#define DEVICE "ESPURNA_H08"
// Buttons
#define BUTTON1_PIN 4
@ -143,7 +142,7 @@
// LEDs
#define LED1_PIN 2
#define LED1_PIN_INVERSE 0
#define LED1_PIN_INVERSE 1
// HLW8012
#define POWER_PROVIDER POWER_PROVIDER_HLW8012
@ -466,6 +465,7 @@
#define LED1_PIN_INVERSE 1
// Channels
#define LIGHT_CHANNELS 1
#define LIGHT_CH1_PIN 12
#define LIGHT_CH1_INVERSE 0
@ -479,8 +479,9 @@
#ifndef DUMMY_RELAY_COUNT
#define DUMMY_RELAY_COUNT 6
#endif
#define TERMINAL_SUPPORT 0
#define TRACK_RELAY_STATUS 0
#define TERMINAL_SUPPORT 0
#define DEBUG_SERIAL_SUPPORT 0
#define TRACK_RELAY_STATUS 0
// Buttons
#define BUTTON1_PIN 0
@ -517,9 +518,9 @@
#define LED1_PIN_INVERSE 1
// Channels
#define LIGHT_CHANNELS 2
#define LIGHT_CH1_PIN 12 // Cold white
#define LIGHT_CH2_PIN 14 // Warm white
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
@ -690,16 +691,21 @@
#define LED1_PIN_INVERSE 1
// Channels
#define LIGHT_CHANNELS 4
#define LIGHT_CH1_PIN 14 // RED
#define LIGHT_CH2_PIN 5 // GREEN
#define LIGHT_CH3_PIN 12 // BLUE
#define LIGHT_CH4_PIN 13 // WHITE
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
#define LIGHT_CH3_INVERSE 0
#define LIGHT_CH4_INVERSE 0
// IR
#define IR_SUPPORT 1
#define IR_PIN 4
#define IR_BUTTON_SET 1
#elif defined(MAGICHOME_LED_CONTROLLER_20)
// Info
@ -709,94 +715,27 @@
#define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER
#define DUMMY_RELAY_COUNT 1
//#define LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
// LEDs
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
// Channels
#define LIGHT_CHANNELS 4
#define LIGHT_CH1_PIN 5 // RED
#define LIGHT_CH2_PIN 12 // GREEN
#define LIGHT_CH3_PIN 13 // BLUE
#define LIGHT_CH4_PIN 15 // WHITE
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
#define LIGHT_CH3_INVERSE 0
#define LIGHT_CH4_INVERSE 0
#define LIGHT_IR_PIN 4 // IR LED
#define LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR 0
// 24 Buttons Set of the IR Remote
#ifndef IR_BUTTONS_SET
#define IR_BUTTONS_SET 1
#endif
//Remote Buttons SET 1 (for the original Remote shipped with the controller)
#if IR_BUTTONS_SET == 1
#define IR_BUTTON_0 0xFF906F // Brightness +
#define IR_BUTTON_1 0xFFB847 // Brightness -
#define IR_BUTTON_2 0xFFF807 // OFF
#define IR_BUTTON_3 0xFFB04F // ON
#define IR_BUTTON_4 0xFF9867 // RED
#define IR_BUTTON_5 0xFFD827 // GREEN
#define IR_BUTTON_6 0xFF8877 // BLUE
#define IR_BUTTON_7 0xFFA857 // WHITE
#define IR_BUTTON_8 0xFFE817 // "Red" 1
#define IR_BUTTON_9 0xFF48B7 // "Green" 1
#define IR_BUTTON_10 0xFF6897 // "Blue" 1
#define IR_BUTTON_11 0xFFB24D // FLASH Mode
#define IR_BUTTON_12 0xFF02FD // "Red" 2
#define IR_BUTTON_13 0xFF32CD // "Green" 2
#define IR_BUTTON_14 0xFF20DF // "Blue" 2
#define IR_BUTTON_15 0xFF00FF // STROBE Mode
#define IR_BUTTON_16 0xFF50AF // "Red" 3
#define IR_BUTTON_17 0xFF7887 // "Green" 3
#define IR_BUTTON_18 0xFF708F // "Blue" 3
#define IR_BUTTON_19 0xFF58A7 // FADE Mode
#define IR_BUTTON_20 0xFF38C7 // "Red" 4
#define IR_BUTTON_21 0xFF28D7 // "Green" 4
#define IR_BUTTON_22 0xFFF00F // "Blue" 4
#define IR_BUTTON_23 0xFF30CF // SMOOTH Mode
#endif
//Remote Buttons SET 2 (another identical IR Remote shipped with another controller)
#if IR_BUTTONS_SET == 2
#define IR_BUTTON_0 0xFF00FF // Brightness +
#define IR_BUTTON_1 0xFF807F // Brightness -
#define IR_BUTTON_2 0xFF40BF // OFF
#define IR_BUTTON_3 0xFFC03F // ON
#define IR_BUTTON_4 0xFF20DF // RED
#define IR_BUTTON_5 0xFFA05F // GREEN
#define IR_BUTTON_6 0xFF609F // BLUE
#define IR_BUTTON_7 0xFFE01F // WHITE
#define IR_BUTTON_8 0xFF10EF // "Red" 1
#define IR_BUTTON_9 0xFF906F // "Green" 1
#define IR_BUTTON_10 0xFF50AF // "Blue" 1
#define IR_BUTTON_11 0xFFD02F // FLASH Mode
#define IR_BUTTON_12 0xFF30CF // "Red" 2
#define IR_BUTTON_13 0xFFB04F // "Green" 2
#define IR_BUTTON_14 0xFF708F // "Blue" 2
#define IR_BUTTON_15 0xFFF00F // STROBE Mode
#define IR_BUTTON_16 0xFF08F7 // "Red" 3
#define IR_BUTTON_17 0xFF8877 // "Green" 3
#define IR_BUTTON_18 0xFF48B7 // "Blue" 3
#define IR_BUTTON_19 0xFFC837 // FADE Mode
#define IR_BUTTON_20 0xFF28D7 // "Red" 4
#define IR_BUTTON_21 0xFFA857 // "Green" 4
#define IR_BUTTON_22 0xFF6897 // "Blue" 4
#define IR_BUTTON_23 0xFFE817 // SMOOTH Mode
#endif
// IR
#define IR_SUPPORT 1
#define IR_PIN 4
#define IR_BUTTON_SET 1
// -----------------------------------------------------------------------------
// HUACANXING H801 & H802
@ -816,12 +755,12 @@
#define LED1_PIN_INVERSE 1
// Channels
#define LIGHT_CHANNELS 5
#define LIGHT_CH1_PIN 15 // RED
#define LIGHT_CH2_PIN 13 // GREEN
#define LIGHT_CH3_PIN 12 // BLUE
#define LIGHT_CH4_PIN 14 // WHITE1
#define LIGHT_CH5_PIN 4 // WHITE2
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
#define LIGHT_CH3_INVERSE 0
@ -838,11 +777,11 @@
#define DUMMY_RELAY_COUNT 1
// Channels
#define LIGHT_CHANNELS 4
#define LIGHT_CH1_PIN 12 // RED
#define LIGHT_CH2_PIN 14 // GREEN
#define LIGHT_CH3_PIN 13 // BLUE
#define LIGHT_CH4_PIN 15 // WHITE
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
#define LIGHT_CH3_INVERSE 0
@ -1075,9 +1014,9 @@
#define LED1_PIN_INVERSE 1
// Channels
#define LIGHT_CHANNELS 2
#define LIGHT_CH1_PIN 0
#define LIGHT_CH2_PIN 2
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
@ -1089,24 +1028,40 @@
// Info
#define MANUFACTURER "ARILUX"
#define DEVICE "AL-LC06"
#define DEVICE "AL_LC06"
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
#define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER
#define DUMMY_RELAY_COUNT 1
// Channels
#define LIGHT_CH1_PIN 12 // RED
#define LIGHT_CH2_PIN 14 // GREEN
#define LIGHT_CHANNELS 5
#define LIGHT_CH1_PIN 14 // RED
#define LIGHT_CH2_PIN 12 // GREEN
#define LIGHT_CH3_PIN 13 // BLUE
#define LIGHT_CH4_PIN 15 // WHITE1
#define LIGHT_CH5_PIN 5 // WHITE2
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
#define LIGHT_CH3_INVERSE 0
#define LIGHT_CH4_INVERSE 0
#define LIGHT_CH5_INVERSE 0
#elif defined(ARILUX_E27)
// Info
#define MANUFACTURER "ARILUX"
#define DEVICE "E27"
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
#define LIGHT_PROVIDER LIGHT_PROVIDER_MY9192
#define DUMMY_RELAY_COUNT 1
// Channels
#define MY9291_CHANNELS 4
#define MY9291_DI_PIN 13
#define MY9291_DCKI_PIN 15
#define MY9291_COMMAND MY9291_COMMAND_DEFAULT
// -----------------------------------------------------------------------------
// XENON SM-PW701U
// -----------------------------------------------------------------------------
@ -1145,11 +1100,11 @@
#define DUMMY_RELAY_COUNT 1
// Channels
#define LIGHT_CHANNELS 4
#define LIGHT_CH1_PIN 13 // RED
#define LIGHT_CH2_PIN 12 // GREEN
#define LIGHT_CH3_PIN 14 // BLUE
#define LIGHT_CH4_PIN 2 // WHITE
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
#define LIGHT_CH3_INVERSE 0


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

@ -1,4 +1,4 @@
#define APP_NAME "ESPURNA"
#define APP_VERSION "1.9.7"
#define APP_VERSION "1.9.8"
#define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat"

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


+ 129
- 21
code/espurna/dht.ino View File

@ -8,20 +8,139 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
#if DHT_SUPPORT
#include <DHT.h>
#include <Adafruit_Sensor.h>
DHT dht(DHT_PIN, DHT_TYPE, DHT_TIMING);
double _dhtTemperature = 0;
unsigned int _dhtHumidity = 0;
// -----------------------------------------------------------------------------
// HAL
// https://github.com/gosouth/DHT22/blob/master/main/DHT22.c
// -----------------------------------------------------------------------------
#define DHT_MAX_DATA 5
#define DHT_MAX_ERRORS 5
#define DHT_MIN_INTERVAL 2000
#define DHT_OK 0
#define DHT_CHECKSUM_ERROR -1
#define DHT_TIMEOUT_ERROR -2
#define DHT11 11
#define DHT22 22
#define DHT21 21
#define AM2301 21
unsigned long _getSignalLevel(unsigned char gpio, int usTimeOut, bool state) {
unsigned long uSec = 1;
while (digitalRead(gpio) == state) {
if (++uSec > usTimeOut) return 0;
delayMicroseconds(1);
}
return uSec;
}
int readDHT(unsigned char gpio, unsigned char type) {
static unsigned long last_ok = 0;
if (millis() - last_ok < DHT_MIN_INTERVAL) return DHT_OK;
unsigned long low = 0;
unsigned long high = 0;
static unsigned char errors = 0;
uint8_t dhtData[DHT_MAX_DATA] = {0};
uint8_t byteInx = 0;
uint8_t bitInx = 7;
// Send start signal to DHT sensor
if (++errors > DHT_MAX_ERRORS) {
errors = 0;
digitalWrite(gpio, HIGH);
delay(250);
}
pinMode(gpio, OUTPUT);
digitalWrite(gpio, LOW);
delay(20);
noInterrupts();
digitalWrite(gpio, HIGH);
delayMicroseconds(40);
pinMode(gpio, INPUT_PULLUP);
delayMicroseconds(10);
// DHT will keep the line low for 80 us and then high for 80us
low = _getSignalLevel(gpio, 85, LOW);
if (low==0) return DHT_TIMEOUT_ERROR;
high = _getSignalLevel(gpio, 85, HIGH);
if (high==0) return DHT_TIMEOUT_ERROR;
// No errors, read the 40 data bits
for( int k = 0; k < 40; k++ ) {
// Starts new data transmission with >50us low signal
low = _getSignalLevel(gpio, 56, LOW);
if (low==0) return DHT_TIMEOUT_ERROR;
// Check to see if after >70us rx data is a 0 or a 1
high = _getSignalLevel(gpio, 75, HIGH);
if (high==0) return DHT_TIMEOUT_ERROR;
// add the current read to the output data
// since all dhtData array where set to 0 at the start,
// only look for "1" (>28us us)
if (high > low) dhtData[byteInx] |= (1 << bitInx);
// index to next byte
if (bitInx == 0) {
bitInx = 7;
++byteInx;
} else {
--bitInx;
}
}
interrupts();
// Verify checksum
if (dhtData[4] != ((dhtData[0] + dhtData[1] + dhtData[2] + dhtData[3]) & 0xFF)) {
return DHT_CHECKSUM_ERROR;
}
// Get humidity from Data[0] and Data[1]
if (type == DHT11) {
_dhtHumidity = dhtData[0];
} else {
_dhtHumidity = dhtData[0] * 256 + dhtData[1];
_dhtHumidity /= 10;
}
// Get temp from Data[2] and Data[3]
if (type == DHT11) {
_dhtTemperature = dhtData[2];
} else {
_dhtTemperature = (dhtData[2] & 0x7F) * 256 + dhtData[3];
_dhtTemperature /= 10;
if (dhtData[2] & 0x80) _dhtTemperature *= -1;
}
last_ok = millis();
errors = 0;
return DHT_OK;
}
int readDHT() {
return readDHT(DHT_PIN, DHT_TYPE);
}
// -----------------------------------------------------------------------------
// Values
// -----------------------------------------------------------------------------
double getDHTTemperature(bool celsius) {
return celsius ? _dhtTemperature : _dhtTemperature * 1.8 + 32;
}
double getDHTTemperature() {
return _dhtTemperature;
return getDHTTemperature(true);
}
unsigned int getDHTHumidity() {
@ -30,8 +149,6 @@ unsigned int getDHTHumidity() {
void dhtSetup() {
dht.begin();
#if WEB_SUPPORT
apiRegister(DHT_TEMPERATURE_TOPIC, DHT_TEMPERATURE_TOPIC, [](char * buffer, size_t len) {
dtostrf(_dhtTemperature, 1-len, 1, buffer);
@ -50,21 +167,12 @@ void dhtLoop() {
if ((millis() - last_update > DHT_UPDATE_INTERVAL) || (last_update == 0)) {
last_update = millis();
unsigned char tmpUnits = getSetting("tmpUnits", TMP_UNITS).toInt();
// Read sensor data
double h = dht.readHumidity();
double t = dht.readTemperature(tmpUnits == TMP_FAHRENHEIT);
// Check if readings are valid
if (isnan(h) || isnan(t)) {
DEBUG_MSG_P(PSTR("[DHT] Error reading sensor\n"));
} else {
if (readDHT(DHT_PIN, DHT_TYPE) == DHT_OK) {
_dhtTemperature = t;
_dhtHumidity = h;
unsigned char tmpUnits = getSetting("tmpUnits", TMP_UNITS).toInt();
double t = getDHTTemperature(tmpUnits == TMP_CELSIUS);
unsigned int h = getDHTHumidity();
char temperature[6];
char humidity[6];


+ 6
- 0
code/espurna/espurna.ino View File

@ -294,6 +294,9 @@ void setup() {
#if RF_SUPPORT
rfSetup();
#endif
#if IR_SUPPORT
irSetup();
#endif
#if DOMOTICZ_SUPPORT
domoticzSetup();
#endif
@ -356,5 +359,8 @@ void loop() {
#if RF_SUPPORT
rfLoop();
#endif
#if IR_SUPPORT
irLoop();
#endif
}

+ 10
- 1
code/espurna/hardware.ino View File

@ -461,7 +461,7 @@ void hwUpwardsCompatibility() {
setSetting("board", 38);
#elif defined(TINKERMAN_ESPURNA_H07)
#elif defined(TINKERMAN_ESPURNA_H08)
setSetting("board", 39);
setSetting("ledGPIO", 1, 2);
@ -557,6 +557,15 @@ void hwUpwardsCompatibility() {
setSetting("relays", 1);
setSetting("enGPIO", 15);
#elif defined(ARILUX_E27)
setSetting("board", 46);
setSetting("relayProvider", RELAY_PROVIDER_LIGHT);
setSetting("lightProvider", LIGHT_PROVIDER_MY9192);
setSetting("myDIGPIO", 13);
setSetting("myDCKIGPIO", 15);
setSetting("relays", 1);
#else
#error "UNSUPPORTED HARDWARE!"


+ 107
- 0
code/espurna/ir.ino View File

@ -0,0 +1,107 @@
/*
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
*/
#if IR_SUPPORT
#include <IRremoteESP8266.h>
#include <IRrecv.h>
IRrecv * _ir_recv;
decode_results _ir_results;
// -----------------------------------------------------------------------------
// PRIVATE
// -----------------------------------------------------------------------------
void _irProcessCode(unsigned long code) {
static unsigned long last_code;
boolean found = false;
// Repeat last valid code
DEBUG_MSG_P(PSTR("[IR] Received 0x%06X\n"), code);
if (code == 0xFFFFFFFF) {
DEBUG_MSG_P(PSTR("[IR] Processing 0x%06X\n"), code);
code = last_code;
}
for (unsigned char i = 0; i < IR_BUTTON_COUNT ; i++) {
unsigned long button_code = pgm_read_dword(&IR_BUTTON[i][0]);
if (code == button_code) {
unsigned long button_mode = pgm_read_dword(&IR_BUTTON[i][1]);
unsigned long button_value = pgm_read_dword(&IR_BUTTON[i][2]);
if (button_mode == IR_BUTTON_MODE_STATE) {
relayStatus(0, button_value);
}
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
if (button_mode == IR_BUTTON_MODE_BRIGHTER) {
lightBrightnessStep(button_value ? 1 : -1);
delay(150); //debounce
}
if (button_mode == IR_BUTTON_MODE_RGB) {
lightColor(button_value);
}
/*
#if LIGHT_PROVIDER == LIGHT_PROVIDER_FASTLED
if (button_mode == IR_BUTTON_MODE_EFFECT) {
_buttonAnimMode(button_value);
}
#endif
*/
/*
if (button_mode == IR_BUTTON_MODE_HSV) {
lightColor(button_value);
}
*/
lightUpdate(true, true);
#endif
found = true;
last_code = code;
break;
}
}
if (!found) {
DEBUG_MSG_P(PSTR("[IR] Ignoring code\n"));
}
}
// -----------------------------------------------------------------------------
// PUBLIC API
// -----------------------------------------------------------------------------
void irSetup() {
_ir_recv = new IRrecv(IR_PIN);
_ir_recv->enableIRIn();
}
void irLoop() {
if (_ir_recv->decode(&_ir_results)) {
unsigned long code = _ir_results.value;
_irProcessCode(code);
_ir_recv->resume(); // Receive the next value
}
}
#endif // IR_SUPPORT

+ 94
- 42
code/espurna/light.ino View File

@ -13,6 +13,13 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
#include <ArduinoJson.h>
#include <vector>
#if LIGHT_PROVIDER == LIGHT_PROVIDER_DIMMER
#define PWM_CHANNEL_NUM_MAX LIGHT_CHANNELS
extern "C" {
#include "pwm.h"
}
#endif
Ticker colorTicker;
typedef struct {
unsigned char pin;
@ -29,30 +36,46 @@ unsigned int _brightness = LIGHT_MAX_BRIGHTNESS;
my9291 * _my9291;
#endif
// Gamma Correction lookup table for gamma=2.8 and 12 bit (4095) full scale
// Gamma Correction lookup table (8 bit)
// TODO: move to PROGMEM
const unsigned short gamma_table[LIGHT_MAX_VALUE+1] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 8, 9, 10, 11,
12, 13, 15, 16, 17, 18, 20, 21, 23, 25, 26, 28, 30, 32, 34, 36,
38, 40, 43, 45, 48, 50, 53, 56, 59, 62, 65, 68, 71, 75, 78, 82,
85, 89, 93, 97, 101, 105, 110, 114, 119, 123, 128, 133, 138, 143, 149, 154,
159, 165, 171, 177, 183, 189, 195, 202, 208, 215, 222, 229, 236, 243, 250, 258,
266, 273, 281, 290, 298, 306, 315, 324, 332, 341, 351, 360, 369, 379, 389, 399,
409, 419, 430, 440, 451, 462, 473, 485, 496, 508, 520, 532, 544, 556, 569, 582,
594, 608, 621, 634, 648, 662, 676, 690, 704, 719, 734, 749, 764, 779, 795, 811,
827, 843, 859, 876, 893, 910, 927, 944, 962, 980, 998,1016,1034,1053,1072,1091,
1110,1130,1150,1170,1190,1210,1231,1252,1273,1294,1316,1338,1360,1382,1404,1427,
1450,1473,1497,1520,1544,1568,1593,1617,1642,1667,1693,1718,1744,1770,1797,1823,
1850,1877,1905,1932,1960,1988,2017,2045,2074,2103,2133,2162,2192,2223,2253,2284,
2315,2346,2378,2410,2442,2474,2507,2540,2573,2606,2640,2674,2708,2743,2778,2813,
2849,2884,2920,2957,2993,3030,3067,3105,3143,3181,3219,3258,3297,3336,3376,3416,
3456,3496,3537,3578,3619,3661,3703,3745,3788,3831,3874,3918,3962,4006,4050,4095 };
const unsigned char gamma_table[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,
6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11,
12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19,
19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28,
29, 30, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40,
41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71,
72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 89,
91, 92, 93, 94, 96, 97, 98, 100, 101, 102, 104, 105, 106, 108, 109, 110,
112, 113, 115, 116, 118, 119, 121, 122, 123, 125, 126, 128, 130, 131, 133, 134,
136, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160,
162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189,
191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221,
223, 225, 227, 229, 231, 233, 235, 238, 240, 242, 244, 246, 248, 251, 253, 255
};
// -----------------------------------------------------------------------------
// UTILS
// -----------------------------------------------------------------------------
void _fromLong(unsigned long value, bool brightness) {
if (brightness) {
_channels[0].value = (value >> 24) & 0xFF;
_channels[1].value = (value >> 16) & 0xFF;
_channels[2].value = (value >> 8) & 0xFF;
_brightness = (value & 0xFF) * LIGHT_MAX_BRIGHTNESS / 255;
} else {
_channels[0].value = (value >> 16) & 0xFF;
_channels[1].value = (value >> 8) & 0xFF;
_channels[2].value = (value) & 0xFF;
}
}
void _fromRGB(const char * rgb) {
char * p = (char *) rgb;
@ -67,16 +90,7 @@ void _fromRGB(const char * rgb) {
unsigned long value = strtoul(p, NULL, 16);
// RGBA values are interpreted like RGB + brightness
if (strlen(p) > 7) {
_channels[0].value = (value >> 24) & 0xFF;
_channels[1].value = (value >> 16) & 0xFF;
_channels[2].value = (value >> 8) & 0xFF;
_brightness = (value & 0xFF) * LIGHT_MAX_BRIGHTNESS / 255;
} else {
_channels[0].value = (value >> 16) & 0xFF;
_channels[1].value = (value >> 8) & 0xFF;
_channels[2].value = (value) & 0xFF;
}
_fromLong(value, strlen(p) > 7);
}
@ -197,9 +211,10 @@ void _fromMireds(unsigned long mireds) {
unsigned int _toPWM(unsigned long value, bool bright, bool gamma, bool reverse) {
value = constrain(value, 0, LIGHT_MAX_VALUE);
if (bright) value *= ((float) _brightness / LIGHT_MAX_BRIGHTNESS);
unsigned int pwm = gamma ? gamma_table[value] : map(value, 0, LIGHT_MAX_VALUE, 0, LIGHT_LIMIT_PWM);
if (reverse) pwm = LIGHT_LIMIT_PWM - pwm;
return pwm;
if (gamma) value = gamma_table[value];
if (LIGHT_MAX_VALUE != LIGHT_LIMIT_PWM) value = map(value, 0, LIGHT_MAX_VALUE, 0, LIGHT_LIMIT_PWM);
if (reverse) value = LIGHT_LIMIT_PWM - value;
return value;
}
// Returns a PWM valule for the given channel ID
@ -252,13 +267,11 @@ void _lightProviderUpdate() {
if (_lightState) {
float ratio = (float) LIGHT_MAX_VALUE / LIGHT_MAX_PWM;
unsigned int red = _toPWM(0) * ratio;
unsigned int green = _toPWM(1) * ratio;
unsigned int blue = _toPWM(2) * ratio;
unsigned int white = _toPWM(3) * ratio;
unsigned int warm = _toPWM(4) * ratio;
unsigned int red = _toPWM(0);
unsigned int green = _toPWM(1);
unsigned int blue = _toPWM(2);
unsigned int white = _toPWM(3);
unsigned int warm = _toPWM(4);
_my9291->setColor((my9291_color_t) { red, green, blue, white, warm });
_my9291->setState(true);
@ -274,8 +287,9 @@ void _lightProviderUpdate() {
#if LIGHT_PROVIDER == LIGHT_PROVIDER_DIMMER
for (unsigned int i=0; i < _channels.size(); i++) {
analogWrite(_channels[i].pin, _toPWM(i));
pwm_set_duty(_toPWM(i), i);
}
pwm_start();
#endif
@ -467,6 +481,10 @@ void lightColor(const char * color) {
_fromRGB(color);
}
void lightColor(unsigned long color) {
_fromLong(color, false);
}
String lightColor() {
char rgb[8];
_toRGB(rgb, 8, false);
@ -490,10 +508,14 @@ unsigned int lightBrightness() {
return _brightness;
}
void lightBrightness(unsigned int b) {
void lightBrightness(int b) {
_brightness = constrain(b, 0, LIGHT_MAX_BRIGHTNESS);
}
void lightBrightnessStep(int steps) {
lightBrightness(_brightness + steps * LIGHT_STEP);
}
// -----------------------------------------------------------------------------
// SETUP
// -----------------------------------------------------------------------------
@ -571,6 +593,30 @@ void _lightAPISetup() {
}
#if LIGHT_PROVIDER == LIGHT_PROVIDER_DIMMER
unsigned long getIOMux(unsigned long gpio) {
unsigned long muxes[16] = {
PERIPHS_IO_MUX_GPIO0_U, PERIPHS_IO_MUX_U0TXD_U, PERIPHS_IO_MUX_GPIO2_U, PERIPHS_IO_MUX_U0RXD_U,
PERIPHS_IO_MUX_GPIO4_U, PERIPHS_IO_MUX_GPIO5_U, PERIPHS_IO_MUX_SD_CLK_U, PERIPHS_IO_MUX_SD_DATA0_U,
PERIPHS_IO_MUX_SD_DATA1_U, PERIPHS_IO_MUX_SD_DATA2_U, PERIPHS_IO_MUX_SD_DATA3_U, PERIPHS_IO_MUX_SD_CMD_U,
PERIPHS_IO_MUX_MTDI_U, PERIPHS_IO_MUX_MTCK_U, PERIPHS_IO_MUX_MTMS_U, PERIPHS_IO_MUX_MTDO_U
};
return muxes[gpio];
}
unsigned long getIOFunc(unsigned long gpio) {
unsigned long funcs[16] = {
FUNC_GPIO0, FUNC_GPIO1, FUNC_GPIO2, FUNC_GPIO3,
FUNC_GPIO4, FUNC_GPIO5, FUNC_GPIO6, FUNC_GPIO7,
FUNC_GPIO8, FUNC_GPIO9, FUNC_GPIO10, FUNC_GPIO11,
FUNC_GPIO12, FUNC_GPIO13, FUNC_GPIO14, FUNC_GPIO15
};
return funcs[gpio];
}
#endif
void lightSetup() {
#ifdef LIGHT_ENABLE_PIN
@ -608,11 +654,17 @@ void lightSetup() {
_channels.push_back((channel_t) {LIGHT_CH5_PIN, LIGHT_CH5_INVERSE, 0});
#endif
analogWriteRange(LIGHT_MAX_PWM+1);
analogWriteFreq(LIGHT_PWM_FREQUENCY);
uint32 pwm_duty_init[PWM_CHANNEL_NUM_MAX];
uint32 io_info[PWM_CHANNEL_NUM_MAX][3];
for (unsigned int i=0; i < _channels.size(); i++) {
pwm_duty_init[i] = 0;
io_info[i][0] = getIOMux(_channels[i].pin);
io_info[i][1] = getIOFunc(_channels[i].pin);
io_info[i][2] = _channels[i].pin;
pinMode(_channels[i].pin, OUTPUT);
}
pwm_init(LIGHT_MAX_PWM, pwm_duty_init, PWM_CHANNEL_NUM_MAX, io_info);
pwm_start();
#endif


+ 34
- 167
code/espurna/light_ir.ino View File

@ -1,14 +1,14 @@
/*
LIGHT (EXPERIMENTAL) IR
LIGHT (EXPERIMENTAL)
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) 2017 by François Déchery
------------------------------------------------------------------------------------------
Features :
- ONLY RGB strips are supported (No RGBW or RGBWW)
- IR remote supported (but not mandatory)
- IR remote supported (but not mandatory) -- moved to ir.ino
- HSV (intuitive) WEB controls
- MQTT & API "color_rgb" + "color_hsv" + "brightness" parameters
- Uses the (amazing) Fastled library for fast and natural Color & Brightness
@ -24,8 +24,6 @@ Not currently Implemented :
#ifdef LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <FastLED.h>
// #### Defined ##########################################################################
@ -37,64 +35,9 @@ Not currently Implemented :
#define ANIM3_SPEED 100 // fade speed
#define ANIM4_SPEED 700 // smooth speed
#define ANIM5_SPEED 200 // party speed
#define BUTTONS_COUNT 24
#define LED_DURATION 70 // Status led ON duration
// #### Variables ########################################################################
unsigned long r_but_codes[]={ // IR remote buttons codes
IR_BUTTON_0 , // Brightness +
IR_BUTTON_1 , // Brightness -
IR_BUTTON_2 , // OFF
IR_BUTTON_3 , // ON
IR_BUTTON_4 , // Red
IR_BUTTON_5 , // Green
IR_BUTTON_6 , // Blue
IR_BUTTON_7 , // White
IR_BUTTON_8 , // R1
IR_BUTTON_9 , // G1
IR_BUTTON_10 , // B1
IR_BUTTON_11 , // Flash
IR_BUTTON_12 , // R2
IR_BUTTON_13 , // G2
IR_BUTTON_14 , // B2
IR_BUTTON_15 , // Strobe
IR_BUTTON_16 , // R3
IR_BUTTON_17 , // G3
IR_BUTTON_18 , // B3
IR_BUTTON_19 , // Fade
IR_BUTTON_20 , // R4
IR_BUTTON_21 , // G4
IR_BUTTON_22 , // B4
IR_BUTTON_23 // Smooth
};
unsigned long r_but_colors[]={ // IR remote buttons colors
0, // Brightness +
0, // Brightness -
0, // OFF
0, // ON
0xFF0000, // Red
0x00FF00, // Green
0x0000FF, // Blue
0xFFFFFF, // White
0xD13A01, // R1
0x00E644, // G1
0x0040A7, // B1
0, // Flash
0xE96F2A, // R2
0x00BEBF, // G2
0x56406F, // B2
0, // Strobe
0xEE9819, // R3
0x00799A, // G3
0x944E80, // B3
0, // Fade
0xFFFF00, // R4
0x0060A1, // G4
0xEF45AD, // B4
0 // Smooth
};
// variables declarations ###############################################################
CHSV _cur_color = CHSV(0,255,255);
@ -105,12 +48,8 @@ byte _cur_anim_step = 0;
boolean _cur_anim_dir = true;
unsigned long _cur_anim_speed = 1000;
unsigned long _anim_last_update = millis();
unsigned long _last_ir_button = 0;
unsigned long _last_status_led_time = 0;
IRrecv _ir_recv(LIGHT_IR_PIN); //IRrecv _ir_recv(IR_PIN, IR_LED_PIN); dont work. Why ?
decode_results _ir_results;
// #######################################################################################
// #### PRIVATE ##########################################################################
@ -129,75 +68,6 @@ void _flashStatusLed(){
_last_status_led_time=millis();
}
// ---------------------------------------------------------------------------------------
void _loopProcessIR() {
if (_ir_recv.decode(&_ir_results)) {
//dumpIR(&_ir_results);
//DEBUG_MSG_P(PSTR(".\n"));
unsigned long code = _ir_results.value;
DEBUG_MSG_P(PSTR("[IR] received : 0x%X "), code );
if( code == 0xFFFFFFFF){
code = _last_ir_button;
DEBUG_MSG_P(PSTR("(Repeat : %X) "), code );
}
DEBUG_MSG_P(PSTR("=> ") );
_processIrButtons(code);
_ir_recv.resume(); // Receive the next value
}
}
// ---------------------------------------------------------------------------------------
void _processIrButtons(unsigned long code) {
//DEBUG_MSG_P(PSTR("IR code : %X\n"), code );
boolean done=false;
for (int i = 0; i < BUTTONS_COUNT ; i = i + 1) {
if( code == r_but_codes[i] ){
//DEBUG_MSG_P(PSTR(" : %X -> "), r_but_colors[i] );
_last_ir_button = 0; //no repat else if specified
if(i == 0){
_buttonBrightness(true);
_last_ir_button = code;
delay(150); //debounce
}
else if(i == 1){
_buttonBrightness(false);
_last_ir_button = code;
delay(150); //debounce
}
else if(i == 2){
_buttonPower(false);
}
else if(i == 3){
_buttonPower(true);
}
else if(i == 11){
_buttonAnimMode(1);
}
else if(i == 15){
_buttonAnimMode(2);
}
else if(i == 19){
_buttonAnimMode(3);
}
else if(i == 23){
_buttonAnimMode(4);
}
else{
_buttonColorRVB(r_but_colors[i],0);
}
done=true;
lightUpdate(true, true);
}
}
if(!done){
_last_ir_button = 0;
//DEBUG_PRINTHEX(code);
DEBUG_MSG_P(PSTR("ignored!\n"));
}
}
// ---------------------------------------------------------------------------------------
void _buttonPower(boolean on){
_flashStatusLed();
@ -289,7 +159,7 @@ CHSV _dimHSV(CHSV color, int offset){
offset=offset*10;
int bright=color.v + offset;
if(offset ==0){
return color;
return color;
}
else if(bright < 1){
bright=1; // no off
@ -316,7 +186,7 @@ void _setBrightness(byte val){
if(val==0){
_cur_status=0;
}
_buttonColorHSV(_cur_color,0);
_buttonColorHSV(_cur_color,0);
}
// ---------------------------------------------------------------------------------------
@ -330,7 +200,7 @@ void _setAnimSpeed(unsigned long speed){
void _setLedsRGB(CRGB rgb){
analogWrite(LIGHT_CH1_PIN, rgb.r);
analogWrite(LIGHT_CH2_PIN, rgb.g);
analogWrite(LIGHT_CH3_PIN, rgb.b);
analogWrite(LIGHT_CH3_PIN, rgb.b);
if(_cur_anim_mode == 0){
DEBUG_MSG_P(PSTR("RGB=%3u,%3u,%3u\n"), rgb.r, rgb.g, rgb.b);
}
@ -528,9 +398,9 @@ void _anim5(boolean init){
_cur_anim_color.v= 255;
}
unsigned long now= millis();
if(_cur_anim_step == 1 && now > (_anim_last_update + _cur_anim_speed) ){
if(_cur_anim_step == 1 && now > (_anim_last_update + _cur_anim_speed) ){
DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_cur_anim_color.h = random(0,255);
_cur_anim_color.h = random(0,255);
_setLedsHSV(_cur_anim_color);
_cur_anim_step = 0;
_anim_last_update = now;
@ -794,16 +664,14 @@ void _strToUpper(char * str){
// ################################################################
void lightSetup() {
DEBUG_MSG_P(PSTR("[LIGHT] LIGHT_PROVIDER = %d (With IR)\n"), LIGHT_PROVIDER);
DEBUG_MSG_P(PSTR("[LIGHT] LIGHT_PROVIDER = %d\n"), LIGHT_PROVIDER);
pinMode(LIGHT_CH1_PIN, OUTPUT);
pinMode(LIGHT_CH1_PIN, OUTPUT);
pinMode(LIGHT_CH2_PIN, OUTPUT);
pinMode(LIGHT_CH3_PIN, OUTPUT);
_ir_recv.enableIRIn(); // Start the receiver
//confirmRgb();
_cur_color = _romLoadColor();
_lightColorRestore();
@ -815,7 +683,6 @@ void lightSetup() {
// ---------------------------------------------------------------------------------------
void lightLoop() {
_loopProcessIR();
_loopUpdateAnimation();
_updateStatusLed();
}
@ -849,12 +716,12 @@ void lightUpdate(bool save, bool forward) {
//root["color_hsv"] = lightColor();
//root["brightness"] = _cur_color.v;
// RGB channels
// RGB channels
//JsonArray& channels = root.createNestedArray("channels");
//for (unsigned char id=0; id < lightChannels(); id++) {
// channels.add(lightChannel(id));
//}
// Relay
JsonArray& relay = root.createNestedArray("relayStatus");
relay.add(_cur_status);
@ -927,7 +794,7 @@ unsigned int lightChannel(unsigned char id) {
return current_rvb.b;
}
else{
DEBUG_MSG_P(PSTR(" [ERROR] GET lightChannel : %s\n"), id);
DEBUG_MSG_P(PSTR(" [ERROR] GET lightChannel : %s\n"), id);
return 0;
}
}
@ -935,27 +802,27 @@ unsigned int lightChannel(unsigned char id) {
// ---------------------------------------------------------------------------------------
// Set Channel's Value
void lightChannel(unsigned char id, unsigned int value) {
DEBUG_MSG_P(PSTR("[WEB|API] Set Color Channel "));
DEBUG_MSG_P(PSTR("[WEB|API] Set Color Channel "));
value= constrain(value, 0, 255);
CRGB current_rvb = CHSV(_cur_color);
if(id == 0 ){
DEBUG_MSG_P(PSTR("RED to : %d => "), value);
DEBUG_MSG_P(PSTR("RED to : %d => "), value);
current_rvb.r=value;
_buttonColorRVB(current_rvb,0);
}
else if(id == 1 ){
DEBUG_MSG_P(PSTR("GREEN to : %d => "), value);
DEBUG_MSG_P(PSTR("GREEN to : %d => "), value);
current_rvb.g=value;
_buttonColorRVB(current_rvb,0);
}
else if(id == 2 ){
DEBUG_MSG_P(PSTR("BLUE to : %d => "), value);
DEBUG_MSG_P(PSTR("BLUE to : %d => "), value);
current_rvb.b=value;
_buttonColorRVB(current_rvb,0);
}
else{
DEBUG_MSG_P(PSTR(" [ERROR] SET lightChannel %s To %d \n"), id, value);
DEBUG_MSG_P(PSTR(" [ERROR] SET lightChannel %s To %d \n"), id, value);
}
}
@ -967,12 +834,12 @@ unsigned int lightBrightness() {
// ---------------------------------------------------------------------------------------
// Set Brightness
void lightBrightness(unsigned int b) {
void lightBrightness(int b) {
b=constrain(b, 0, 255);
DEBUG_MSG_P(PSTR("[WEB|API] Set Brightness to : %d\n"), b);
DEBUG_MSG_P(PSTR("[WEB|API] Set Brightness to : %d\n"), b);
_cur_color.v=b;
_setLedsHSV(_cur_color);
//set status
if(b > 0){
_cur_status=1;
@ -1011,34 +878,34 @@ void lightColor(const char * color) {
void _SetLightColorRGB(const char * color) {
//used only from settings
DEBUG_MSG_P(PSTR("[WEB|API] Set (#RGB) Color to : "));
DEBUG_MSG_P(PSTR("[WEB|API] Set (#RGB) Color to : "));
if( _charColorIsValid(color) ){
DEBUG_MSG_P(PSTR("%s \n"), color);
DEBUG_MSG_P(PSTR("%s \n"), color);
_buttonColorRVB(_charToRgb(color), 0);
}
else{
DEBUG_MSG_P(PSTR(" Canceled ('%s' is invalid) !\n"), color);
DEBUG_MSG_P(PSTR(" Canceled ('%s' is invalid) !\n"), color);
}
}
void _SetLightColorHSV(const char * color) {
DEBUG_MSG_P(PSTR("[WEB|API] Set (#HSV) Color to : "));
DEBUG_MSG_P(PSTR("[WEB|API] Set (#HSV) Color to : "));
if( _charColorIsValid(color) ){
DEBUG_MSG_P(PSTR("%s \n"), color);
DEBUG_MSG_P(PSTR("%s \n"), color);
_buttonColorHSV(_charToHsv(color), 0);
}
else{
DEBUG_MSG_P(PSTR(" Canceled ('%s' is invalid) !\n"), color);
DEBUG_MSG_P(PSTR(" Canceled ('%s' is invalid) !\n"), color);
}
}
void setLightColor (const char * h, const char * s, const char * v){
DEBUG_MSG_P(PSTR("[WEB|API] Set Color from (%s,%s,%s) "), h, s, v);
DEBUG_MSG_P(PSTR("[WEB|API] Set Color from (%s,%s,%s) "), h, s, v);
CHSV color;
color.h=strtoul(h, NULL, 10);
color.s=strtoul(s, NULL, 10);
color.v=strtoul(v, NULL, 10);
DEBUG_MSG_P(PSTR("to (%d,%d,%d) "), color.h, color.s, color.v);
DEBUG_MSG_P(PSTR("to (%d,%d,%d) "), color.h, color.s, color.v);
_buttonColorRVB(color, 0);
}
@ -1062,7 +929,7 @@ bool lightState() {
// ---------------------------------------------------------------------------------------
// Set State
void lightState(bool state){
DEBUG_MSG_P(PSTR("[WEB|API] Set Relay to : %u => "), state);
DEBUG_MSG_P(PSTR("[WEB|API] Set Relay to : %u => "), state);
//if(state != _cur_status){
_buttonPower(state);
//}
@ -1074,7 +941,7 @@ String lightAnimMode(){
return String(_cur_anim_mode);
}
void lightAnimMode(const char * val){
DEBUG_MSG_P(PSTR("[WEB|API] Set AnimMode to %s\n"), val);
DEBUG_MSG_P(PSTR("[WEB|API] Set AnimMode to %s\n"), val);
_setAnimMode(strtoul(val, NULL, 10));
}
// ---------------------------------------------------------------------------------------
@ -1082,7 +949,7 @@ String lightAnimSpeed(){
return String(_cur_anim_speed);
}
void lightAnimSpeed(const char * val){
DEBUG_MSG_P(PSTR("[WEB|API] Set AnimSpeed to %s \n"), val);
DEBUG_MSG_P(PSTR("[WEB|API] Set AnimSpeed to %s \n"), val);
_setAnimSpeed(strtoul(val, NULL, 10));
}
@ -1138,7 +1005,7 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl
_setAnimSpeed(atoi(payload));
lightUpdate(true, mqttForward());
}
// Brightness
if (t.equals(MQTT_TOPIC_BRIGHTNESS)) {
_setBrightness (constrain(atoi(payload), 0, LIGHT_MAX_BRIGHTNESS));


+ 25
- 22
code/espurna/power.h View File

@ -8,36 +8,41 @@ class MedianFilter {
public:
MedianFilter(unsigned char size) {
_size = size;
_data = new double[_size+1];
reset();
MedianFilter() {
_data = new std::vector<double>();
}
~MedianFilter() {
if (_data) delete _data;
}
virtual void reset() {
if (_pointer > 1) _data[0] = _data[_pointer-1];
_pointer = 1;
for (unsigned char i=1; i<=_size; i++) _data[i] = 0;
double last = _data->empty() ? 0 : _data->back();
_data->clear();
add(last);
}
virtual void add(double value) {
if (_pointer <= _size) {
_data[_pointer] = value;
++_pointer;
}
_data->push_back(value);
}
virtual double average(bool do_reset = false) {
virtual double median(bool do_reset = false) {
double sum = 0;
if (_pointer > 2) {
if (_data->size() == 1) {
sum = _data->back();
} else if (_data->size() == 2) {
sum = _data->front();
} else if (_data->size() > 2) {
for (unsigned char i = 1; i<_pointer-1; i++) {
for (unsigned char i = 1; i <= _data->size() - 2; i++) {
double previous = _data[i-1];
double current = _data[i];
double next = _data[i+1];
double previous = _data->at(i-1);
double current = _data->at(i);
double next = _data->at(i+1);
if (previous > current) std::swap(previous, current);
if (current > next) std::swap(current, next);
@ -47,7 +52,7 @@ class MedianFilter {
}
sum /= (_pointer - 2);
sum /= (_data->size() - 2);
}
@ -58,13 +63,11 @@ class MedianFilter {
}
virtual unsigned char count() {
return _pointer - 1;
return _data->size();
}
private:
double *_data;
unsigned char _size = 0;
unsigned char _pointer = 0;
std::vector<double> *_data;
};

+ 54
- 34
code/espurna/power.ino View File

@ -17,22 +17,25 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
#include <ArduinoJson.h>
bool _power_enabled = false;
bool _power_ready = false;
bool _power_newdata = false;
bool _power_realtime = API_REAL_TIME_VALUES;
unsigned long _power_read_interval = POWER_READ_INTERVAL;
unsigned long _power_report_interval = POWER_REPORT_INTERVAL;
double _power_current = 0;
double _power_voltage = 0;
double _power_apparent = 0;
double _power_energy = 0;
MedianFilter _filter_current = MedianFilter(POWER_REPORT_BUFFER);
MedianFilter _filter_current = MedianFilter();
#if POWER_HAS_ACTIVE
double _power_active = 0;
double _power_reactive = 0;
double _power_factor = 0;
MedianFilter _filter_voltage = MedianFilter(POWER_REPORT_BUFFER);
MedianFilter _filter_active = MedianFilter(POWER_REPORT_BUFFER);
MedianFilter _filter_apparent = MedianFilter(POWER_REPORT_BUFFER);
MedianFilter _filter_voltage = MedianFilter();
MedianFilter _filter_active = MedianFilter();
MedianFilter _filter_apparent = MedianFilter();
#endif
#if POWER_HAS_ENERGY
@ -48,37 +51,35 @@ MedianFilter _filter_current = MedianFilter(POWER_REPORT_BUFFER);
void _powerAPISetup() {
apiRegister(MQTT_TOPIC_CURRENT, MQTT_TOPIC_CURRENT, [](char * buffer, size_t len) {
if (_power_ready) {
dtostrf(getCurrent(), len-1, POWER_CURRENT_DECIMALS, buffer);
} else {
buffer = NULL;
}
dtostrf(_power_realtime ? _powerCurrent() : getCurrent(), 1-len, POWER_CURRENT_DECIMALS, buffer);
});
apiRegister(MQTT_TOPIC_VOLTAGE, MQTT_TOPIC_VOLTAGE, [](char * buffer, size_t len) {
if (_power_ready) {
snprintf_P(buffer, len, PSTR("%d"), getVoltage());
} else {
buffer = NULL;
}
snprintf_P(buffer, len, PSTR("%d"), (int) (_power_realtime ? _powerVoltage() : getVoltage()));
});
apiRegister(MQTT_TOPIC_POWER_APPARENT, MQTT_TOPIC_POWER_APPARENT, [](char * buffer, size_t len) {
if (_power_ready) {
snprintf_P(buffer, len, PSTR("%d"), getApparentPower());
} else {
buffer = NULL;
}
snprintf_P(buffer, len, PSTR("%d"), (int) (_power_realtime ? _powerApparentPower() : getApparentPower()));
});
#if POWER_HAS_ENERGY
apiRegister(MQTT_TOPIC_ENERGY_TOTAL, MQTT_TOPIC_ENERGY_TOTAL, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%lu"), (int) (_power_realtime ? _powerEnergy() : getPowerEnergy()));
});
#endif
#if POWER_HAS_ACTIVE
apiRegister(MQTT_TOPIC_POWER_ACTIVE, MQTT_TOPIC_POWER_ACTIVE, [](char * buffer, size_t len) {
if (_power_ready) {
snprintf_P(buffer, len, PSTR("%d"), getActivePower());
} else {
buffer = NULL;
}
snprintf_P(buffer, len, PSTR("%d"), (int) (_power_realtime ? _powerActivePower() : getActivePower()));
});
apiRegister(MQTT_TOPIC_POWER_FACTOR, MQTT_TOPIC_POWER_FACTOR, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), (int) (100 * (_power_realtime ? _powerPowerFactor() : getPowerFactor())));
});
#endif
}
@ -171,11 +172,11 @@ void _powerRead() {
void _powerReport() {
// Get the fitered values
_power_current = _filter_current.average(true);
_power_current = _filter_current.median(true);
#if POWER_HAS_ACTIVE
_power_apparent = _filter_apparent.average(true);
_power_voltage = _filter_voltage.average(true);
_power_active = _filter_active.average(true);
_power_apparent = _filter_apparent.median(true);
_power_voltage = _filter_voltage.median(true);
_power_active = _filter_active.median(true);
if (_power_active > _power_apparent) _power_apparent = _power_active;
_power_reactive = (_power_apparent > _power_active) ? sqrt(_power_apparent * _power_apparent - _power_active * _power_active) : 0;
_power_factor = (_power_apparent > 0) ? _power_active / _power_apparent : 1;
@ -189,14 +190,13 @@ void _powerReport() {
double energy_delta = _power_energy - _power_last_energy;
_power_last_energy = _power_energy;
#else
double energy_delta = power * (POWER_REPORT_INTERVAL / 1000.);
double energy_delta = power * (_power_report_interval / 1000.);
_power_energy += energy_delta;
#endif
_power_ready = true;
char buf_current[10];
char buf_energy_delta[10];
char buf_energy_total[10];
char buf_energy_delta[20];
char buf_energy_total[20];
dtostrf(_power_current, 1-sizeof(buf_current), POWER_CURRENT_DECIMALS, buf_current);
dtostrf(energy_delta * POWER_ENERGY_FACTOR, 1-sizeof(buf_energy_delta), POWER_ENERGY_DECIMALS, buf_energy_delta);
dtostrf(_power_energy * POWER_ENERGY_FACTOR, 1-sizeof(buf_energy_total), POWER_ENERGY_DECIMALS, buf_energy_total);
@ -293,6 +293,14 @@ double getPowerFactor() {
// PUBLIC API
// -----------------------------------------------------------------------------
unsigned long powerReadInterval() {
return _power_read_interval;
}
unsigned long powerReportInterval() {
return _power_report_interval;
}
bool powerEnabled() {
return _power_enabled;
}
@ -312,6 +320,17 @@ void powerResetCalibration() {
}
void powerConfigure() {
_power_realtime = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
_power_read_interval = atol(getSetting("pwrReadEvery", POWER_READ_INTERVAL).c_str());
_power_report_interval = atol(getSetting("pwrReportEvery", POWER_REPORT_INTERVAL).c_str());
if (_power_read_interval < POWER_MIN_READ_INTERVAL) {
_power_read_interval = POWER_MIN_READ_INTERVAL;
setSetting("pwrReadEvery", _power_read_interval);
}
if (_power_report_interval < _power_read_interval) {
_power_report_interval = _power_read_interval;
setSetting("pwrReportEvery", _power_report_interval);
}
_powerConfigureProvider();
}
@ -332,6 +351,7 @@ void powerSetup() {
moveSetting("powerRatioP", "pwrRatioP");
_powerSetupProvider();
powerConfigure();
// API
#if WEB_SUPPORT
@ -352,7 +372,7 @@ void powerLoop() {
}
static unsigned long last = 0;
if (millis() - last > POWER_REPORT_INTERVAL) {
if (millis() - last > _power_report_interval) {
last = millis();
_powerReport();
}


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

@ -141,8 +141,6 @@ void _powerSetupProvider() {
brzo_i2c_end_transaction();
#endif
_powerConfigureProvider();
_emon.warmup();
}
@ -152,7 +150,7 @@ void _powerLoopProvider(bool before) {
if (before) {
static unsigned long last = 0;
if (millis() - last > POWER_READ_INTERVAL) {
if (millis() - last > powerReadInterval()) {
last = millis();
_power_newdata = true;
}


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

@ -151,7 +151,7 @@ void _powerLoopProvider(bool before) {
if (before) {
static unsigned long last = 0;
if (millis() - last > POWER_READ_INTERVAL) {
if (millis() - last > powerReadInterval()) {
last = millis();
_power_newdata = true;


+ 448
- 0
code/espurna/pwm.c View File

@ -0,0 +1,448 @@
/*
* Copyright (C) 2016 Stefan Brüns <stefan.bruens@rwth-aachen.de>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Set the following three defines to your needs */
#ifndef SDK_PWM_PERIOD_COMPAT_MODE
#define SDK_PWM_PERIOD_COMPAT_MODE 0
#endif
#ifndef PWM_MAX_CHANNELS
#define PWM_MAX_CHANNELS 8
#endif
#define PWM_DEBUG 0
#define PWM_USE_NMI 1
/* no user servicable parts beyond this point */
#define PWM_MAX_TICKS 0x7fffff
#if SDK_PWM_PERIOD_COMPAT_MODE
#define PWM_PERIOD_TO_TICKS(x) (x * 0.2)
#define PWM_DUTY_TO_TICKS(x) (x * 5)
#define PWM_MAX_DUTY (PWM_MAX_TICKS * 0.2)
#define PWM_MAX_PERIOD (PWM_MAX_TICKS * 5)
#else
#define PWM_PERIOD_TO_TICKS(x) (x)
#define PWM_DUTY_TO_TICKS(x) (x)
#define PWM_MAX_DUTY PWM_MAX_TICKS
#define PWM_MAX_PERIOD PWM_MAX_TICKS
#endif
#include <c_types.h>
#include <pwm.h>
#include <eagle_soc.h>
#include <ets_sys.h>
// from SDK hw_timer.c
#define TIMER1_DIVIDE_BY_16 0x0004
#define TIMER1_ENABLE_TIMER 0x0080
struct pwm_phase {
uint32_t ticks; ///< delay until next phase, in 200ns units
uint16_t on_mask; ///< GPIO mask to switch on
uint16_t off_mask; ///< GPIO mask to switch off
};
/* Three sets of PWM phases, the active one, the one used
* starting with the next cycle, and the one updated
* by pwm_start. After the update pwm_next_set
* is set to the last updated set. pwm_current_set is set to
* pwm_next_set from the interrupt routine during the first
* pwm phase
*/
typedef struct pwm_phase (pwm_phase_array)[PWM_MAX_CHANNELS + 2];
static pwm_phase_array pwm_phases[3];
static struct {
struct pwm_phase* next_set;
struct pwm_phase* current_set;
uint8_t current_phase;
} pwm_state;
static uint32_t pwm_period;
static uint32_t pwm_period_ticks;
static uint32_t pwm_duty[PWM_MAX_CHANNELS];
static uint16_t gpio_mask[PWM_MAX_CHANNELS];
static uint8_t pwm_channels;
// 3-tuples of MUX_REGISTER, MUX_VALUE and GPIO number
typedef uint32_t (pin_info_type)[3];
struct gpio_regs {
uint32_t out; /* 0x60000300 */
uint32_t out_w1ts; /* 0x60000304 */
uint32_t out_w1tc; /* 0x60000308 */
uint32_t enable; /* 0x6000030C */
uint32_t enable_w1ts; /* 0x60000310 */
uint32_t enable_w1tc; /* 0x60000314 */
uint32_t in; /* 0x60000318 */
uint32_t status; /* 0x6000031C */
uint32_t status_w1ts; /* 0x60000320 */
uint32_t status_w1tc; /* 0x60000324 */
};
static struct gpio_regs* gpio = (struct gpio_regs*)(0x60000300);
struct timer_regs {
uint32_t frc1_load; /* 0x60000600 */
uint32_t frc1_count; /* 0x60000604 */
uint32_t frc1_ctrl; /* 0x60000608 */
uint32_t frc1_int; /* 0x6000060C */
uint8_t pad[16];
uint32_t frc2_load; /* 0x60000620 */
uint32_t frc2_count; /* 0x60000624 */
uint32_t frc2_ctrl; /* 0x60000628 */
uint32_t frc2_int; /* 0x6000062C */
uint32_t frc2_alarm; /* 0x60000630 */
};
static struct timer_regs* timer = (struct timer_regs*)(0x60000600);
static void ICACHE_RAM_ATTR
pwm_intr_handler(void)
{
if ((pwm_state.current_set[pwm_state.current_phase].off_mask == 0) &&
(pwm_state.current_set[pwm_state.current_phase].on_mask == 0)) {
pwm_state.current_set = pwm_state.next_set;
pwm_state.current_phase = 0;
}
do {
// force write to GPIO registers on each loop
asm volatile ("" : : : "memory");
gpio->out_w1ts = (uint32_t)(pwm_state.current_set[pwm_state.current_phase].on_mask);
gpio->out_w1tc = (uint32_t)(pwm_state.current_set[pwm_state.current_phase].off_mask);
uint32_t ticks = pwm_state.current_set[pwm_state.current_phase].ticks;
pwm_state.current_phase++;
if (ticks) {
if (ticks >= 16) {
// constant interrupt overhead
ticks -= 9;
timer->frc1_int &= ~FRC1_INT_CLR_MASK;
WRITE_PERI_REG(&timer->frc1_load, ticks);
return;
}
ticks *= 4;
do {
ticks -= 1;
// stop compiler from optimizing delay loop to noop
asm volatile ("" : : : "memory");
} while (ticks > 0);
}
} while (1);
}
/**
* period: initial period (base unit 1us OR 200ns)
* duty: array of initial duty values, may be NULL, may be freed after pwm_init
* pwm_channel_num: number of channels to use
* pin_info_list: array of pin_info
*/
void ICACHE_FLASH_ATTR
pwm_init(uint32_t period, uint32_t *duty, uint32_t pwm_channel_num,
uint32_t (*pin_info_list)[3])
{
int i, j, n;
pwm_channels = pwm_channel_num;
if (pwm_channels > PWM_MAX_CHANNELS)
pwm_channels = PWM_MAX_CHANNELS;
for (i = 0; i < 3; i++) {
for (j = 0; j < (PWM_MAX_CHANNELS + 2); j++) {
pwm_phases[i][j].ticks = 0;
pwm_phases[i][j].on_mask = 0;
pwm_phases[i][j].off_mask = 0;
}
}
pwm_state.current_set = pwm_state.next_set = 0;
pwm_state.current_phase = 0;
uint32_t all = 0;
// PIN info: MUX-Register, Mux-Setting, PIN-Nr
for (n = 0; n < pwm_channels; n++) {
pin_info_type* pin_info = &pin_info_list[n];
PIN_FUNC_SELECT((*pin_info)[0], (*pin_info)[1]);
gpio_mask[n] = 1 << (*pin_info)[2];
all |= 1 << (*pin_info)[2];
if (duty)
pwm_set_duty(duty[n], n);
}
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, all);
GPIO_REG_WRITE(GPIO_ENABLE_W1TS_ADDRESS, all);
pwm_set_period(period);
#if PWM_USE_NMI
ETS_FRC_TIMER1_NMI_INTR_ATTACH(pwm_intr_handler);
#else
ETS_FRC_TIMER1_INTR_ATTACH(pwm_intr_handler, NULL);
#endif
TM1_EDGE_INT_ENABLE();
timer->frc1_int &= ~FRC1_INT_CLR_MASK;
timer->frc1_ctrl = 0;
pwm_start();
}
__attribute__ ((noinline))
static uint8_t ICACHE_FLASH_ATTR
_pwm_phases_prep(struct pwm_phase* pwm)
{
uint8_t n, phases;
uint16_t off_mask = 0;
for (n = 0; n < pwm_channels + 2; n++) {
pwm[n].ticks = 0;
pwm[n].on_mask = 0;
pwm[n].off_mask = 0;
}
phases = 1;
for (n = 0; n < pwm_channels; n++) {
uint32_t ticks = PWM_DUTY_TO_TICKS(pwm_duty[n]);
if (ticks == 0) {
pwm[0].off_mask |= gpio_mask[n];
} else if (ticks >= pwm_period_ticks) {
pwm[0].on_mask |= gpio_mask[n];
} else {
if (ticks < (pwm_period_ticks/2)) {
pwm[phases].ticks = ticks;
pwm[0].on_mask |= gpio_mask[n];
pwm[phases].off_mask = gpio_mask[n];
} else {
pwm[phases].ticks = pwm_period_ticks - ticks;
pwm[phases].on_mask = gpio_mask[n];
pwm[0].off_mask |= gpio_mask[n];
}
phases++;
}
}
pwm[phases].ticks = pwm_period_ticks;
// bubble sort, lowest to hightest duty
n = 2;
while (n < phases) {
if (pwm[n].ticks < pwm[n - 1].ticks) {
struct pwm_phase t = pwm[n];
pwm[n] = pwm[n - 1];
pwm[n - 1] = t;
if (n > 2)
n--;
} else {
n++;
}
}
#if PWM_DEBUG
int t = 0;
for (t = 0; t <= phases; t++) {
ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
}
#endif
// shift left to align right edge;
uint8_t l = 0, r = 1;
while (r <= phases) {
uint32_t diff = pwm[r].ticks - pwm[l].ticks;
if (diff && (diff <= 16)) {
uint16_t mask = pwm[r].on_mask | pwm[r].off_mask;
pwm[l].off_mask ^= pwm[r].off_mask;
pwm[l].on_mask ^= pwm[r].on_mask;
pwm[0].off_mask ^= pwm[r].on_mask;
pwm[0].on_mask ^= pwm[r].off_mask;
pwm[r].ticks = pwm_period_ticks - diff;
pwm[r].on_mask ^= mask;
pwm[r].off_mask ^= mask;
} else {
l = r;
}
r++;
}
#if PWM_DEBUG
for (t = 0; t <= phases; t++) {
ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
}
#endif
// sort again
n = 2;
while (n <= phases) {
if (pwm[n].ticks < pwm[n - 1].ticks) {
struct pwm_phase t = pwm[n];
pwm[n] = pwm[n - 1];
pwm[n - 1] = t;
if (n > 2)
n--;
} else {
n++;
}
}
// merge same duty
l = 0, r = 1;
while (r <= phases) {
if (pwm[r].ticks == pwm[l].ticks) {
pwm[l].off_mask |= pwm[r].off_mask;
pwm[l].on_mask |= pwm[r].on_mask;
pwm[r].on_mask = 0;
pwm[r].off_mask = 0;
} else {
l++;
if (l != r) {
struct pwm_phase t = pwm[l];
pwm[l] = pwm[r];
pwm[r] = t;
}
}
r++;
}
phases = l;
#if PWM_DEBUG
for (t = 0; t <= phases; t++) {
ets_printf("%d @%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
}
#endif
// transform absolute end time to phase durations
for (n = 0; n < phases; n++) {
pwm[n].ticks =
pwm[n + 1].ticks - pwm[n].ticks;
// subtract common overhead
pwm[n].ticks--;
}
pwm[phases].ticks = 0;
// do a cyclic shift if last phase is short
if (pwm[phases - 1].ticks < 16) {
for (n = 0; n < phases - 1; n++) {
struct pwm_phase t = pwm[n];
pwm[n] = pwm[n + 1];
pwm[n + 1] = t;
}
}
#if PWM_DEBUG
for (t = 0; t <= phases; t++) {
ets_printf("%d +%d: %04x %04x\n", t, pwm[t].ticks, pwm[t].on_mask, pwm[t].off_mask);
}
ets_printf("\n");
#endif
return phases;
}
void ICACHE_FLASH_ATTR
pwm_start(void)
{
pwm_phase_array* pwm = &pwm_phases[0];
if ((*pwm == pwm_state.next_set) ||
(*pwm == pwm_state.current_set))
pwm++;
if ((*pwm == pwm_state.next_set) ||
(*pwm == pwm_state.current_set))
pwm++;
uint8_t phases = _pwm_phases_prep(*pwm);
// all with 0% / 100% duty - stop timer
if (phases == 1) {
if (pwm_state.next_set) {
#if PWM_DEBUG
ets_printf("PWM stop\n");
#endif
timer->frc1_ctrl = 0;
ETS_FRC1_INTR_DISABLE();
}
pwm_state.next_set = NULL;
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, (*pwm)[0].on_mask);
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, (*pwm)[0].off_mask);
return;
}
// start if not running
if (!pwm_state.next_set) {
#if PWM_DEBUG
ets_printf("PWM start\n");
#endif
pwm_state.current_set = pwm_state.next_set = *pwm;
pwm_state.current_phase = phases - 1;
ETS_FRC1_INTR_ENABLE();
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, 0);
timer->frc1_ctrl = TIMER1_DIVIDE_BY_16 | TIMER1_ENABLE_TIMER;
return;
}
pwm_state.next_set = *pwm;
}
void ICACHE_FLASH_ATTR
pwm_set_duty(uint32_t duty, uint8_t channel)
{
if (channel > PWM_MAX_CHANNELS)
return;
if (duty > PWM_MAX_DUTY)
duty = PWM_MAX_DUTY;
pwm_duty[channel] = duty;
}
uint32_t ICACHE_FLASH_ATTR
pwm_get_duty(uint8_t channel)
{
if (channel > PWM_MAX_CHANNELS)
return 0;
return pwm_duty[channel];
}
void ICACHE_FLASH_ATTR
pwm_set_period(uint32_t period)
{
pwm_period = period;
if (pwm_period > PWM_MAX_PERIOD)
pwm_period = PWM_MAX_PERIOD;
pwm_period_ticks = PWM_PERIOD_TO_TICKS(period);
}
uint32_t ICACHE_FLASH_ATTR
pwm_get_period(void)
{
return pwm_period;
}
uint32_t ICACHE_FLASH_ATTR
get_pwm_version(void)
{
return 1;
}
void ICACHE_FLASH_ATTR
set_pwm_debug_en(uint8_t print_en)
{
(void) print_en;
}

+ 33
- 0
code/espurna/pwm.h View File

@ -0,0 +1,33 @@
#ifndef __PWM_H__
#define __PWM_H__
/*pwm.h: function and macro definition of PWM API , driver level */
/*user_light.h: user interface for light API, user level*/
/*user_light_adj: API for color changing and lighting effects, user level*/
/*NOTE!! : DO NOT CHANGE THIS FILE*/
/*SUPPORT UP TO 8 PWM CHANNEL*/
//#define PWM_CHANNEL_NUM_MAX 8
struct pwm_param {
uint32 period;
uint32 freq;
uint32 duty[PWM_CHANNEL_NUM_MAX]; //PWM_CHANNEL<=8
};
/* pwm_init should be called only once, for now */
void pwm_init(uint32 period, uint32 *duty,uint32 pwm_channel_num,uint32 (*pin_info_list)[3]);
void pwm_start(void);
void pwm_set_duty(uint32 duty, uint8 channel);
uint32 pwm_get_duty(uint8 channel);
void pwm_set_period(uint32 period);
uint32 pwm_get_period(void);
uint32 get_pwm_version(void);
void set_pwm_debug_en(uint8 print_en);
#endif

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


+ 7
- 4
code/espurna/web.ino View File

@ -215,7 +215,7 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
if (lightHasColor()) {
if (action.equals("color") && root.containsKey("data")) {
lightColor(root["data"]);
lightColor((const char *) root["data"]);
lightUpdate(true, true);
}
@ -479,9 +479,9 @@ void _wsStart(uint32_t client_id) {
root["webMode"] = WEB_MODE_NORMAL;
root["app"] = APP_NAME;
root["version"] = APP_VERSION;
root["build"] = buildTime();
root["app_name"] = APP_NAME;
root["app_version"] = APP_VERSION;
root["app_build"] = buildTime();
root["manufacturer"] = String(MANUFACTURER);
root["chipid"] = chipid;
@ -565,6 +565,7 @@ void _wsStart(uint32_t client_id) {
root["apiEnabled"] = getSetting("apiEnabled", API_ENABLED).toInt() == 1;
root["apiKey"] = getSetting("apiKey");
root["apiRealTime"] = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
root["tmpUnits"] = getSetting("tmpUnits", TMP_UNITS).toInt();
@ -656,6 +657,8 @@ void _wsStart(uint32_t client_id) {
root["pwrVoltage"] = getVoltage();
root["pwrApparent"] = getApparentPower();
root["pwrEnergy"] = getPowerEnergy();
root["pwrReadEvery"] = powerReadInterval();
root["pwrReportEvery"] = powerReportInterval();
#if POWER_HAS_ACTIVE
root["pwrActive"] = getActivePower();
root["pwrReactive"] = getReactivePower();


+ 0
- 5
code/html/custom.css View File

@ -135,7 +135,6 @@ input[name=upgrade] {
margin-top: -50px;
margin-left: -200px;
}
div.state {
border-top: 1px solid #eee;
margin-top: 20px;
@ -150,7 +149,6 @@ div.state {
font-size: 80%;
font-weight: bold;
}
.right {
text-align: right;
}
@ -174,15 +172,12 @@ div.state {
margin: 10px 2px;
padding: 20px;
}
#panel-rfb input {
margin-right: 5px;
}
#panel-rfb label {
padding-top: 5px;
}
#panel-rfb input {
text-align: center;
}

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

@ -1,7 +1,6 @@
var websock;
var password = false;
var maxNetworks;
var useWhite = false;
var messages = [];
var webhost;
@ -10,6 +9,8 @@ var numReset = 0;
var numReconnect = 0;
var numReload = 0;
var useWhite = false;
// -----------------------------------------------------------------------------
// Messages
// -----------------------------------------------------------------------------
@ -280,12 +281,6 @@ function doReconnect(ask) {
}
function doToggle(element, value) {
var relayID = parseInt(element.attr("data"));
websock.send(JSON.stringify({'action': 'relay', 'data': { 'id': relayID, 'status': value ? 1 : 0 }}));
return false;
}
function doBackup() {
document.getElementById('downloader').src = webhost + 'config';
return false;
@ -325,6 +320,12 @@ function doRestore() {
return false;
}
function doToggle(element, value) {
var relayID = parseInt(element.attr("data"));
websock.send(JSON.stringify({'action': 'relay', 'data': { 'id': relayID, 'status': value ? 1 : 0 }}));
return false;
}
// -----------------------------------------------------------------------------
// Visualization
// -----------------------------------------------------------------------------
@ -609,10 +610,10 @@ function rfbSend() {
function processData(data) {
// title
if ("app" in data) {
var title = data.app;
if ("version" in data) {
title = title + " " + data.version;
if ("app_name" in data) {
var title = data.app_name;
if ("app_version" in data) {
title = title + " " + data.app_version;
}
$(".pure-menu-heading").html(title);
if ("hostname" in data) {


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

@ -249,11 +249,14 @@
<div class="pure-u-1 pure-u-sm-1-4">IP</div>
<div class="pure-u-1 pure-u-sm-17-24"><span class="right" name="deviceip"></span></div>
<div class="pure-u-1 pure-u-sm-1-4">ESPurna version</div>
<div class="pure-u-1 pure-u-sm-17-24"><span class="right" name="version"></span></div>
<div class="pure-u-1 pure-u-sm-1-4">Firmware name</div>
<div class="pure-u-1 pure-u-sm-17-24"><span class="right" name="app_name"></span></div>
<div class="pure-u-1 pure-u-sm-1-4">ESPurna build</div>
<div class="pure-u-1 pure-u-sm-17-24"><span class="right" name="build"></span></div>
<div class="pure-u-1 pure-u-sm-1-4">Firmware version</div>
<div class="pure-u-1 pure-u-sm-17-24"><span class="right" name="app_version"></span></div>
<div class="pure-u-1 pure-u-sm-1-4">Firmware build</div>
<div class="pure-u-1 pure-u-sm-17-24"><span class="right" name="app_build"></span></div>
<div class="pure-u-1 pure-u-sm-1-4">Current time</div>
<div class="pure-u-1 pure-u-sm-17-24"><span class="right" name="time"></span></div>
@ -469,6 +472,17 @@
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="apiEnabled" /></div>
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-sm-1-4"><label for="apiRealTime">Real time API</label></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="apiRealTime" /></div>
<div class="pure-u-0 pure-u-md-1-2">&nbsp;</div>
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">
By default, some magnitudes are being preprocessed and filtered to avoid spurious values.<br />
If you want to get real-time values (not preprocessed) in the API turn on this setting.
</div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-md-1-4" for="apiKey">HTTP API Key</label>
<input name="apiKey" class="pure-u-3-4 pure-u-md-1-2" type="text" tabindex="14" />
@ -796,7 +810,7 @@
<div class="header">
<h1>POWER CALIBRATION</h1>
<h2>
Calibrate your power monitor device. Use a pure resistive load and introduce the expected values for active power, current and voltage. Use the nominal values or a multimeter to get the proper numbers. Set any field to 0 to leave the calibration value untouched.
Configure and calibrate your power monitor device. Use a pure resistive load and introduce the expected values for active power, current and voltage. Use the nominal values or a multimeter to get the proper numbers. Set any field to 0 to leave the calibration value untouched.
</h2>
</div>
@ -804,6 +818,42 @@
<fieldset>
<div class="pure-g">
<label class="pure-u-1 pure-u-sm-1-4" for="pwrReadEvery">Read interval</label>
<select class="pure-u-1 pure-u-sm-1-4" name="pwrReadEvery">
<option value=2000>2 seconds</option>
<option value=6000>6 seconds</option>
<option value=10000>10 seconds</option>
<option value=15000>15 seconds</option>
<option value=30000>30 seconds</option>
<option value=60000>60 seconds</option>
</select>
<div class="pure-u-0 pure-u-md-1-2">&nbsp;</div>
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">
Select the interval between readings. These will be filtered and averaged for the report.<br />
The default and recommended value is 6 seconds.
</div>
</div>
<div class="pure-g">
<label class="pure-u-1 pure-u-sm-1-4" for="pwrReportEvery">Report interval</label>
<select class="pure-u-1 pure-u-sm-1-4" name="pwrReportEvery">
<option value=6000>6 seconds</option>
<option value=10000>10 seconds</option>
<option value=30000>30 seconds</option>
<option value=60000>1 minute</option>
<option value=300000>5 minutes</option>
</select>
<div class="pure-u-0 pure-u-md-1-2">&nbsp;</div>
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">
Select the interval between reports via MQTT.<br />
This can't be less than the reading interval above.<br />
The default and recommended value is 1 minute.
</div>
</div>
<div class="pure-g module module-hlw module-emon module-v9261f">
<label class="pure-u-1 pure-u-md-1-4" for="pwrExpectedP">AC RMS Active Power</label>
<input class="pure-u-1 pure-u-md-3-4 pwrExpected" name="pwrExpectedP" type="text" size="8" tabindex="51" placeholder="0" />


+ 51
- 8
code/platformio.ini View File

@ -11,10 +11,8 @@ debug_flags = -DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP
build_flags_512k = ${common.build_flags} -Wl,-Tesp8266.flash.512k0.ld
build_flags_1m = ${common.build_flags} -Wl,-Tesp8266.flash.1m0.ld
#https://github.com/me-no-dev/ESPAsyncTCP#9b0cc37 // 2.3.0 compatible
#https://github.com/me-no-dev/ESPAsyncTCP#3795e16 // 2.4.0-rc2 compatible
#https://github.com/me-no-dev/ESPAsyncTCP#289a681 // 2.4.0-rc2 compatible
lib_deps =
DHT sensor library
Adafruit Unified Sensor
https://github.com/xoseperez/Time
ArduinoJson
https://github.com/me-no-dev/ESPAsyncTCP#9b0cc37
@ -29,7 +27,7 @@ lib_deps =
EspSoftwareSerial
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.2.1
https://bitbucket.org/xoseperez/fauxmoesp.git#2.3.0
https://bitbucket.org/xoseperez/nofuss.git#0.2.5
https://bitbucket.org/xoseperez/emonliteesp.git#0.2.0
https://bitbucket.org/xoseperez/debounceevent.git#2.0.1
@ -128,23 +126,23 @@ upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
[env:tinkerman-espurna-h07]
[env:tinkerman-espurna-h08]
platform = ${common.platform}
framework = arduino
board = esp12e
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H07
build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H08
upload_speed = 460800
monitor_baud = 115200
[env:tinkerman-espurna-h07-ota]
[env:tinkerman-espurna-h08-ota]
platform = ${common.platform}
framework = arduino
board = esp12e
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H07
build_flags = ${common.build_flags} -DTINKERMAN_ESPURNA_H08
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
@ -822,6 +820,29 @@ upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
[env:arilux-e27]
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_E27
monitor_baud = 115200
[env:arilux-e27-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_E27
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
[env:itead-bnsz01]
platform = ${common.platform}
framework = arduino
@ -936,6 +957,28 @@ upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
[env:wemos-ech1560]
platform = ${common.platform}
framework = arduino
board = d1_mini
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DGENERIC_ECH1560
upload_speed = 460800
monitor_baud = 115200
[env:wemos-ech1560-ota]
platform = ${common.platform}
framework = arduino
board = d1_mini
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DGENERIC_ECH1560
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
[env:esp01-ech1560]
platform = ${common.platform}
framework = arduino


Loading…
Cancel
Save