Merge branch 'master' into travis_all_features
This commit is contained in:
commit
3b96eef2ad
45
CHANGELOG.md
45
CHANGELOG.md
@ -1,6 +1,49 @@
|
||||
## WLED changelog
|
||||
|
||||
### Development versions after 0.9.1 release
|
||||
### Development versions after 0.10.0 release
|
||||
|
||||
#### Build 2005100
|
||||
|
||||
- Update to Espalexa v2.4.6 (+1.6kB free heap memory)
|
||||
- Added `m5atom` PlatformIO environment
|
||||
|
||||
#### Build 2005090
|
||||
|
||||
- Default to ESP8266 Arduino core v2.7.1 in PlatformIO
|
||||
- Fixed Preset Slot 16 always indicating as empty (#891)
|
||||
- Disabled Alexa emulation by default (causes bootloop for some users)
|
||||
- Added BWLT11 and SHOJO_PCB defines to NpbWrapper
|
||||
- Merged pull request #898 adding Solid Glitter effect
|
||||
|
||||
### WLED version 0.10.0
|
||||
|
||||
#### Build 2005030
|
||||
|
||||
- DMX Single RGW and Single DRGB modes now support an additional white channel
|
||||
- Improved palettes derived from set colors and changed their names
|
||||
|
||||
### Development versions between 0.9.1 and 0.10.0 release
|
||||
|
||||
#### Build 2005020
|
||||
|
||||
- Added ACST and ACST/ACDT timezones
|
||||
|
||||
#### Build 2005010
|
||||
|
||||
- Added module info page to web UI
|
||||
- Added realtime override functionality to web UI
|
||||
- Added individial segment power and brightness to web UI
|
||||
- Added feature to one-click select single segment only by tapping segment name
|
||||
- Removed palette jumping to default if color is changed
|
||||
|
||||
#### Build 2004300
|
||||
|
||||
- Added realtime override option and `lor` JSON property
|
||||
- Added `lm` (live mode) and `lip` (live IP) properties to info in JSON API
|
||||
- Added reset commands to APIs
|
||||
- Added `json/si`, returning state and info, but no FX or Palette lists
|
||||
- Added rollover detection to millis(). Can track uptimes longer than 49 days
|
||||
- Attempted to fix Wifi issues with Unifi brand APs
|
||||
|
||||
#### Build 2004230
|
||||
|
||||
|
@ -16,7 +16,7 @@ extra_configs =
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Release binaries follow
|
||||
default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom32_LEDPIN_16
|
||||
; default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom32_LEDPIN_16
|
||||
|
||||
# Single binaries (uncomment your board)
|
||||
; default_envs = nodemcuv2
|
||||
@ -34,6 +34,8 @@ default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_W
|
||||
; default_envs = esp8285_4CH_H801
|
||||
; default_envs = esp8285_5CH_H801
|
||||
; default_envs = d1_mini_5CH_Shojo_PCB
|
||||
; default_envs = wemos_shield_esp32
|
||||
; default_envs = m5atom
|
||||
|
||||
[common]
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -50,6 +52,7 @@ default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_W
|
||||
# arduino core 2.6.1 = platformIO 2.3.0
|
||||
# arduino core 2.6.2 = platformIO 2.3.1
|
||||
# arduino core 2.6.3 = platformIO 2.3.2
|
||||
# arduino core 2.7.0 = platformIO 2.5.0
|
||||
# ------------------------------------------------------------------------------
|
||||
arduino_core_2_3_0 = espressif8266@1.5.0
|
||||
arduino_core_2_4_0 = espressif8266@1.6.0
|
||||
@ -61,13 +64,14 @@ arduino_core_2_5_2 = espressif8266@2.2.3
|
||||
arduino_core_2_6_1 = espressif8266@2.3.0
|
||||
arduino_core_2_6_2 = espressif8266@2.3.1
|
||||
arduino_core_2_6_3 = espressif8266@2.3.3
|
||||
arduino_core_2_7_1 = espressif8266@2.5.1
|
||||
|
||||
# Development platforms
|
||||
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
|
||||
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
|
||||
|
||||
platform = ${common.arduino_core_2_4_2}
|
||||
platform_latest = ${common.arduino_core_2_6_3}
|
||||
# Platform to use for ESP8266
|
||||
platform_latest = ${common.arduino_core_2_7_1}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: DEBUG
|
||||
@ -161,8 +165,7 @@ lib_deps =
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
#U8g2@~2.27.2
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
DallasTemperature@~3.8.0
|
||||
OneWire@~2.3.5
|
||||
#OneWire@~2.3.5
|
||||
#For BME280 sensor uncomment following
|
||||
#BME280@~3.0.0
|
||||
lib_ignore =
|
||||
@ -183,13 +186,13 @@ board = esp01
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_512k}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK
|
||||
-D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
|
||||
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
|
||||
|
||||
[env:esp01_1m_ota]
|
||||
board = esp01_1m
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
|
||||
|
||||
[env:esp01_1m_full]
|
||||
board = esp01_1m
|
||||
@ -206,6 +209,7 @@ build_flags = ${common.build_flags_esp8266}
|
||||
[env:d1_mini]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
upload_speed = 921500
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
@ -251,7 +255,7 @@ build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# DEVELOPMENT BOARDS
|
||||
@ -309,6 +313,25 @@ lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:wemos_shield_esp32]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.11.2
|
||||
upload_port = /dev/cu.SLAB_USBtoUART
|
||||
monitor_port = /dev/cu.SLAB_USBtoUART
|
||||
upload_speed = 460800
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19 -D BTNPIN=17
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:m5atom]
|
||||
board = esp32dev
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
platform = espressif32@1.11.2
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# travis test board configurations
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -1,24 +1,49 @@
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
#include <DallasTemperature.h> //Dallastemperature sensor
|
||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
||||
#include <OneWire.h> // Dallas temperature sensor
|
||||
|
||||
//Dallas sensor quick reading. Credit to - Author: Peter Scargill, August 17th, 2013
|
||||
int16_t Dallas(int x, byte start)
|
||||
{
|
||||
OneWire DallasSensor(x);
|
||||
byte i;
|
||||
byte data[2];
|
||||
int16_t result;
|
||||
do
|
||||
{
|
||||
DallasSensor.reset();
|
||||
DallasSensor.write(0xCC);
|
||||
DallasSensor.write(0xBE);
|
||||
for ( i = 0; i < 2; i++) data[i] = DallasSensor.read();
|
||||
result=(data[1]<<8)|data[0];
|
||||
result>>=4; if (data[1]&128) result|=61440;
|
||||
if (data[0]&8) ++result;
|
||||
DallasSensor.reset();
|
||||
DallasSensor.write(0xCC);
|
||||
DallasSensor.write(0x44,1);
|
||||
if (start) delay(1000);
|
||||
} while (start--);
|
||||
return result;
|
||||
}
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
OneWire oneWire(23);
|
||||
#else //ESP8266 boards
|
||||
uint8_t SDA_PIN = 21;
|
||||
uint8_t DALLAS_PIN =23;
|
||||
#else
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
uint8_t DALLAS_PIN =13;
|
||||
// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||
OneWire oneWire(13);
|
||||
#endif
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
//ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21
|
||||
#define U8X8_PIN_SCL SCL_PIN
|
||||
#define U8X8_PIN_SDA SDA_PIN
|
||||
//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8
|
||||
// Dallas sensor
|
||||
DallasTemperature sensor(&oneWire);
|
||||
|
||||
// Dallas sensor reading timer
|
||||
long temptimer = millis();
|
||||
long lastMeasure = 0;
|
||||
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
|
||||
@ -36,7 +61,9 @@ U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_
|
||||
//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8
|
||||
// gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup() {
|
||||
sensor.begin(); //Start Dallas temperature sensor
|
||||
//Serial.begin(115200);
|
||||
|
||||
Dallas (DALLAS_PIN,1);
|
||||
u8x8.begin();
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setFlipMode(1);
|
||||
@ -77,18 +104,17 @@ void userLoop() {
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr)
|
||||
{
|
||||
sensor.requestTemperatures();
|
||||
// Serial.println(Dallas(DALLAS_PIN,0));
|
||||
//Gets prefered temperature scale based on selection in definitions section
|
||||
#ifdef Celsius
|
||||
float board_temperature = sensor.getTempCByIndex(0);
|
||||
#else
|
||||
float board_temperature = sensor.getTempFByIndex(0);
|
||||
#endif
|
||||
#ifdef Celsius
|
||||
int16_t board_temperature = Dallas(DALLAS_PIN,0);
|
||||
#else
|
||||
int16_t board_temperature = (Dallas(DALLAS_PIN,0)* 1.8 + 32);
|
||||
#endif
|
||||
//Create character string populated with user defined device topic from the UI, and the read temperature. Then publish to MQTT server.
|
||||
char subuf[38];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/temperature");
|
||||
mqtt->publish(subuf, 0, true, String(board_temperature).c_str());
|
||||
String t = String(mqttDeviceTopic);
|
||||
t += "/temperature";
|
||||
mqtt->publish(t.c_str(), 0, true, String(board_temperature).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,10 +156,10 @@ void userLoop() {
|
||||
lastRedraw = millis();
|
||||
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
knownSsid = WiFi.SSID();
|
||||
#else
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
|
@ -3322,3 +3322,15 @@ CRGB WS2812FX::pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart
|
||||
uint8_t sindex8 = scale16(sindex16, 240);
|
||||
return ColorFromPalette(p, sindex8, bri, LINEARBLEND);
|
||||
}
|
||||
|
||||
//Solid colour background with glitter
|
||||
uint16_t WS2812FX::mode_solid_glitter()
|
||||
{
|
||||
fill(SEGCOLOR(0));
|
||||
|
||||
if (SEGMENT.intensity > random8())
|
||||
{
|
||||
setPixelColor(random16(SEGLEN), ULTRAWHITE);
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
16
wled00/FX.h
16
wled00/FX.h
@ -98,7 +98,7 @@
|
||||
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
||||
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
|
||||
|
||||
#define MODE_COUNT 103
|
||||
#define MODE_COUNT 104
|
||||
|
||||
#define FX_MODE_STATIC 0
|
||||
#define FX_MODE_BLINK 1
|
||||
@ -203,6 +203,7 @@
|
||||
#define FX_MODE_HEARTBEAT 100
|
||||
#define FX_MODE_PACIFICA 101
|
||||
#define FX_MODE_CANDLE_MULTI 102
|
||||
#define FX_MODE_SOLID_GLITTER 103
|
||||
|
||||
class WS2812FX {
|
||||
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
||||
@ -219,7 +220,7 @@ class WS2812FX {
|
||||
uint8_t intensity;
|
||||
uint8_t palette;
|
||||
uint8_t mode;
|
||||
uint8_t options; //bit pattern: msb first: transitional tbd tbd tbd tbd paused reverse selected
|
||||
uint8_t options; //bit pattern: msb first: transitional needspixelstate tbd tbd (paused) on reverse selected
|
||||
uint8_t grouping, spacing;
|
||||
uint8_t opacity;
|
||||
uint32_t colors[NUM_COLORS];
|
||||
@ -394,6 +395,7 @@ class WS2812FX {
|
||||
_mode[FX_MODE_HEARTBEAT] = &WS2812FX::mode_heartbeat;
|
||||
_mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica;
|
||||
_mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi;
|
||||
_mode[FX_MODE_SOLID_GLITTER] = &WS2812FX::mode_solid_glitter;
|
||||
|
||||
_brightness = DEFAULT_BRIGHTNESS;
|
||||
currentPalette = CRGBPalette16(CRGB::Black);
|
||||
@ -562,7 +564,7 @@ class WS2812FX {
|
||||
mode_twinklecat(void),
|
||||
mode_halloween_eyes(void),
|
||||
mode_static_pattern(void),
|
||||
mode_tri_static_pattern(void),
|
||||
mode_tri_static_pattern(void),
|
||||
mode_spots(void),
|
||||
mode_spots_fade(void),
|
||||
mode_glitter(void),
|
||||
@ -580,8 +582,8 @@ class WS2812FX {
|
||||
mode_ripple_rainbow(void),
|
||||
mode_heartbeat(void),
|
||||
mode_pacifica(void),
|
||||
mode_candle_multi(void);
|
||||
|
||||
mode_candle_multi(void),
|
||||
mode_solid_glitter(void);
|
||||
|
||||
private:
|
||||
NeoPixelWrapper *bus;
|
||||
@ -667,12 +669,12 @@ const char JSON_mode_names[] PROGMEM = R"=====([
|
||||
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
|
||||
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
|
||||
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
|
||||
"Heartbeat","Pacifica","Candle Multi"
|
||||
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter"
|
||||
])=====";
|
||||
|
||||
|
||||
const char JSON_palette_names[] PROGMEM = R"=====([
|
||||
"Default","Random Cycle","Primary Color","Based on Primary","Set Colors","Based on Set","Party","Cloud","Lava","Ocean",
|
||||
"Default","* Random Cycle","* Color 1","* Colors 1&2","* Color Gradient","* Colors Only","Party","Cloud","Lava","Ocean",
|
||||
"Forest","Rainbow","Rainbow Bands","Sunset","Rivendell","Breeze","Red & Blue","Yellowout","Analogous","Splash",
|
||||
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
|
||||
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
|
||||
|
@ -72,6 +72,7 @@ void WS2812FX::service() {
|
||||
now = nowUp + timebase;
|
||||
if (nowUp - _lastShow < MIN_SHOW_DELAY) return;
|
||||
bool doShow = false;
|
||||
|
||||
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
_segment_index = i;
|
||||
@ -743,25 +744,25 @@ void WS2812FX::handle_palette(void)
|
||||
case 2: {//primary color only
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
targetPalette = CRGBPalette16(prim); break;}
|
||||
case 3: {//based on primary
|
||||
//considering performance implications
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CHSV prim_hsv = rgb2hsv_approximate(prim);
|
||||
targetPalette = CRGBPalette16(
|
||||
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v), //color itself
|
||||
CHSV(prim_hsv.h, MAX(prim_hsv.s - 50,0), prim_hsv.v), //less saturated
|
||||
CHSV(prim_hsv.h, prim_hsv.s, MAX(prim_hsv.v - 50,0)), //darker
|
||||
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v)); //color itself
|
||||
break;}
|
||||
case 4: {//primary + secondary
|
||||
case 3: {//primary + secondary
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
targetPalette = CRGBPalette16(sec,prim); break;}
|
||||
case 5: {//based on primary + secondary
|
||||
targetPalette = CRGBPalette16(prim,prim,sec,sec); break;}
|
||||
case 4: {//primary + secondary + tertiary
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
CRGB ter = col_to_crgb(SEGCOLOR(2));
|
||||
targetPalette = CRGBPalette16(ter,sec,prim); break;}
|
||||
case 5: {//primary + secondary (+tert if not off), more distinct
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
if (SEGCOLOR(2)) {
|
||||
CRGB ter = col_to_crgb(SEGCOLOR(2));
|
||||
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,ter,ter,ter,ter,ter,prim);
|
||||
} else {
|
||||
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,sec,sec,sec);
|
||||
}
|
||||
break;}
|
||||
case 6: //Party colors
|
||||
targetPalette = PartyColors_p; break;
|
||||
case 7: //Cloud colors
|
||||
|
@ -14,6 +14,8 @@
|
||||
//#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13)
|
||||
//#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well
|
||||
//#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white
|
||||
//#define WLED_USE_BWLT11
|
||||
//#define WLED_USE_SHOJO_PCB
|
||||
|
||||
#ifndef BTNPIN
|
||||
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
|
||||
@ -62,7 +64,7 @@
|
||||
#define GPIN 4 //G pin for analog LED strip
|
||||
#define BPIN 14 //B pin for analog LED strip
|
||||
#define WPIN 5 //W pin for analog LED strip
|
||||
#elif defined(SHOJO_PCB)
|
||||
#elif defined(WLED_USE_SHOJO_PCB)
|
||||
//PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/)
|
||||
#define RPIN 14 //R pin for analog LED strip
|
||||
#define GPIN 4 //G pin for analog LED strip
|
||||
|
@ -45,6 +45,11 @@
|
||||
#define REALTIME_MODE_ADALIGHT 5
|
||||
#define REALTIME_MODE_ARTNET 6
|
||||
|
||||
//realtime override modes
|
||||
#define REALTIME_OVERRIDE_NONE 0
|
||||
#define REALTIME_OVERRIDE_ONCE 1
|
||||
#define REALTIME_OVERRIDE_ALWAYS 2
|
||||
|
||||
//E1.31 DMX modes
|
||||
#define DMX_MODE_DISABLED 0 //not used
|
||||
#define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels)
|
||||
@ -81,6 +86,8 @@
|
||||
#define SEG_OPTION_SELECTED 0
|
||||
#define SEG_OPTION_REVERSED 1
|
||||
#define SEG_OPTION_ON 2
|
||||
#define SEG_OPTION_PAUSED 3 //unused
|
||||
#define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor
|
||||
#define SEG_OPTION_TRANSITIONAL 7
|
||||
|
||||
//EEPROM size
|
||||
|
File diff suppressed because one or more lines are too long
@ -88,12 +88,12 @@
|
||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
|
||||
<h3>About</h3>
|
||||
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.9.0<br><br>
|
||||
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.10.0<br><br>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||
A huge thank you to everyone who helped me create WLED!<br><br>
|
||||
(c) 2016-2019 Christian Schwinne <br>
|
||||
<i>Licensed under the MIT license</i><br><br>
|
||||
Server message: <span class="msg"> Response error! </span><hr>
|
||||
Server message: <span class="sip"> Response error! </span><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
|
||||
</form>
|
||||
</body>
|
||||
|
@ -46,6 +46,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
|
||||
|
||||
// update status info
|
||||
realtimeIP = clientIP;
|
||||
byte wChannel = 0;
|
||||
|
||||
switch (DMXMode) {
|
||||
case DMX_MODE_DISABLED:
|
||||
@ -56,21 +57,25 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 3) return;
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
wChannel = (dmxChannels-DMXAddress+1 > 3) ? e131_data[DMXAddress+3] : 0;
|
||||
for (uint16_t i = 0; i < ledCount; i++)
|
||||
setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], 0);
|
||||
setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], wChannel);
|
||||
break;
|
||||
|
||||
case DMX_MODE_SINGLE_DRGB:
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 4) return;
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
wChannel = (dmxChannels-DMXAddress+1 > 4) ? e131_data[DMXAddress+4] : 0;
|
||||
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
|
||||
DMXOldDimmer = e131_data[DMXAddress+0];
|
||||
bri = e131_data[DMXAddress+0];
|
||||
strip.setBrightness(bri);
|
||||
}
|
||||
for (uint16_t i = 0; i < ledCount; i++)
|
||||
setRealtimePixel(i, e131_data[DMXAddress+1], e131_data[DMXAddress+2], e131_data[DMXAddress+3], 0);
|
||||
setRealtimePixel(i, e131_data[DMXAddress+1], e131_data[DMXAddress+2], e131_data[DMXAddress+3], wChannel);
|
||||
break;
|
||||
|
||||
case DMX_MODE_EFFECT:
|
||||
@ -103,6 +108,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
|
||||
|
||||
case DMX_MODE_MULTIPLE_RGB:
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
if (previousUniverses == 0) {
|
||||
// first universe of this fixture
|
||||
possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress + 1) / 3;
|
||||
@ -125,6 +131,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
|
||||
|
||||
case DMX_MODE_MULTIPLE_DRGB:
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
if (previousUniverses == 0) {
|
||||
// first universe of this fixture
|
||||
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
|
||||
|
@ -50,7 +50,7 @@ const char PAGE_dmxmap[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
const char PAGE_update[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta content='width=device-width' name='viewport'><title>WLED Update</title><script>function B(){window.history.back()}</script>
|
||||
<style>.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}</style></head>
|
||||
<body><h2>WLED Software Update</h2>Installed version: 0.9.1<br>Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br><form method='POST' action='/update' enctype='multipart/form-data'><input type='file' class="bt" name='update' required><br><input type='submit' class="bt" value='Update!'></form><button type="button" class="bt" onclick="B()">Back</button></body></html>)=====";
|
||||
<body><h2>WLED Software Update</h2>Installed version: 0.10.0<br>Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br><form method='POST' action='/update' enctype='multipart/form-data'><input type='file' class="bt" name='update' required><br><input type='submit' class="bt" value='Update!'></form><button type="button" class="bt" onclick="B()">Back</button></body></html>)=====";
|
||||
|
||||
|
||||
//new user welcome page
|
||||
|
@ -344,7 +344,7 @@ Hue Bridge IP:<br>
|
||||
<input name=H3 type=number min=0 max=255><br>
|
||||
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
|
||||
(when first connecting)<br>
|
||||
Hue status: <span class=hms> Disabled in this build </span><hr>
|
||||
Hue status: <span class=sip> Disabled in this build </span><hr>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button>
|
||||
</form>
|
||||
</body></html>)=====";
|
||||
@ -384,6 +384,8 @@ Time zone:
|
||||
<option value="13">North Korea</option>
|
||||
<option value="14">IST (India)</option>
|
||||
<option value="15">CA-Saskatchewan</option>
|
||||
<option value="16">ACST</option>
|
||||
<option value="17">ACST/ACDT</option>
|
||||
</select><br>
|
||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||
Current local time is <span class="times">unknown</span>.
|
||||
@ -470,12 +472,12 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
|
||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
|
||||
<h3>About</h3>
|
||||
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.9.1<br><br>
|
||||
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.10.0<br><br>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||
A huge thank you to everyone who helped me create WLED!<br><br>
|
||||
(c) 2016-2020 Christian Schwinne <br>
|
||||
<i>Licensed under the MIT license</i><br><br>
|
||||
Server message: <span class="msg"> Response error! </span><hr>
|
||||
Server message: <span class="sip"> Response error! </span><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
|
||||
</form>
|
||||
</body>
|
||||
|
3176
wled00/html_ui.h
3176
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -129,6 +129,10 @@ bool deserializeState(JsonObject root)
|
||||
|
||||
int timein = root["time"] | -1;
|
||||
if (timein != -1) setTime(timein);
|
||||
doReboot = root["rb"] | doReboot;
|
||||
|
||||
realtimeOverride = root["lor"] | realtimeOverride;
|
||||
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
|
||||
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
strip.mainSegment = root["mainseg"] | prevMain;
|
||||
@ -249,6 +253,8 @@ void serializeState(JsonObject root)
|
||||
udpn["send"] = notifyDirect;
|
||||
udpn["recv"] = receiveNotifications;
|
||||
|
||||
root["lor"] = realtimeOverride;
|
||||
|
||||
root["mainseg"] = strip.getMainSegmentId();
|
||||
|
||||
JsonArray seg = root.createNestedArray("seg");
|
||||
@ -287,6 +293,7 @@ void serializeInfo(JsonObject root)
|
||||
{
|
||||
root["ver"] = versionString;
|
||||
root["vid"] = VERSION;
|
||||
//root["cn"] = WLED_CODENAME;
|
||||
|
||||
JsonObject leds = root.createNestedObject("leds");
|
||||
leds["count"] = ledCount;
|
||||
@ -305,6 +312,24 @@ void serializeInfo(JsonObject root)
|
||||
root["name"] = serverDescription;
|
||||
root["udpport"] = udpPort;
|
||||
root["live"] = (bool)realtimeMode;
|
||||
|
||||
switch (realtimeMode) {
|
||||
case REALTIME_MODE_INACTIVE: root["lm"] = ""; break;
|
||||
case REALTIME_MODE_GENERIC: root["lm"] = ""; break;
|
||||
case REALTIME_MODE_UDP: root["lm"] = "UDP"; break;
|
||||
case REALTIME_MODE_HYPERION: root["lm"] = "Hyperion"; break;
|
||||
case REALTIME_MODE_E131: root["lm"] = "E1.31"; break;
|
||||
case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight");
|
||||
case REALTIME_MODE_ARTNET: root["lm"] = "Art-Net"; break;
|
||||
}
|
||||
|
||||
if (realtimeIP[0] == 0)
|
||||
{
|
||||
root["lip"] = "";
|
||||
} else {
|
||||
root["lip"] = realtimeIP.toString();
|
||||
}
|
||||
|
||||
root["fxcount"] = strip.getModeCount();
|
||||
root["palcount"] = strip.getPaletteCount();
|
||||
|
||||
@ -339,7 +364,7 @@ void serializeInfo(JsonObject root)
|
||||
#endif
|
||||
|
||||
root["freeheap"] = ESP.getFreeHeap();
|
||||
root["uptime"] = millis()/1000;
|
||||
root["uptime"] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
byte os = 0;
|
||||
#ifdef WLED_DEBUG
|
||||
@ -369,7 +394,7 @@ void serializeInfo(JsonObject root)
|
||||
root["opt"] = os;
|
||||
|
||||
root["brand"] = "WLED";
|
||||
root["product"] = "DIY light";
|
||||
root["product"] = "FOSS";
|
||||
root["mac"] = escapedMac;
|
||||
}
|
||||
|
||||
@ -379,6 +404,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
const String& url = request->url();
|
||||
if (url.indexOf("state") > 0) subJson = 1;
|
||||
else if (url.indexOf("info") > 0) subJson = 2;
|
||||
else if (url.indexOf("si") > 0) subJson = 3;
|
||||
else if (url.indexOf("live") > 0) {
|
||||
serveLiveLeds(request);
|
||||
return;
|
||||
@ -410,8 +436,11 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
serializeState(state);
|
||||
JsonObject info = doc.createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
doc["effects"] = serialized((const __FlashStringHelper*)JSON_mode_names);
|
||||
doc["palettes"] = serialized((const __FlashStringHelper*)JSON_palette_names);
|
||||
if (subJson != 3)
|
||||
{
|
||||
doc["effects"] = serialized((const __FlashStringHelper*)JSON_mode_names);
|
||||
doc["palettes"] = serialized((const __FlashStringHelper*)JSON_palette_names);
|
||||
}
|
||||
}
|
||||
|
||||
response->setLength();
|
||||
|
@ -60,8 +60,13 @@ Timezone tzNK(NKST, NKST);
|
||||
TimeChangeRule IST = {Last, Sun, Mar, 1, 330}; // India Standard Time = UTC + 5.5 hours
|
||||
Timezone tzIndia(IST, IST);
|
||||
|
||||
TimeChangeRule ACST = {First, Sun, Apr, 3, 570}; //Australian Central Standard = UTC + 9.5 hours
|
||||
TimeChangeRule ACDT = {First, Sun, Oct, 2, 630}; //Australian Central Daylight = UTC + 10.5 hours
|
||||
Timezone tzAUNorthern(ACST, ACST);
|
||||
Timezone tzAUSouthern(ACDT, ACST);
|
||||
|
||||
// Pick your timezone from here.
|
||||
Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ, &tzNK, &tzIndia, &tzCASaskatchewan};
|
||||
Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ, &tzNK, &tzIndia, &tzCASaskatchewan, &tzAUNorthern, &tzAUSouthern};
|
||||
|
||||
void handleNetworkTime()
|
||||
{
|
||||
|
@ -659,6 +659,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
if (countdownTime - now() > 0) countdownOverTriggered = false;
|
||||
}
|
||||
|
||||
pos = req.indexOf("RB");
|
||||
if (pos > 0) doReboot = true;
|
||||
|
||||
//cronixie
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
//mode, 1 countdown
|
||||
|
@ -1,318 +0,0 @@
|
||||
/*
|
||||
esp8266_waveform - General purpose waveform generation and control,
|
||||
supporting outputs on all pins in parallel.
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
||||
mode and is always loaded with the time until the next edge of any live
|
||||
waveforms.
|
||||
|
||||
Up to one waveform generator per pin supported.
|
||||
|
||||
Each waveform generator is synchronized to the ESP cycle counter, not the
|
||||
timer. This allows for removing interrupt jitter and delay as the counter
|
||||
always increments once per 80MHz clock. Changes to a waveform are
|
||||
contiguous and only take effect on the next waveform transition,
|
||||
allowing for smooth transitions.
|
||||
|
||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||
|
||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
||||
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <Arduino.h>
|
||||
#include "ets_sys.h"
|
||||
#include "core_esp8266_waveform.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Maximum delay between IRQs
|
||||
#define MAXIRQUS (10000)
|
||||
|
||||
// Set/clear GPIO 0-15 by bitmask
|
||||
#define SetGPIO(a) do { GPOS = a; } while (0)
|
||||
#define ClearGPIO(a) do { GPOC = a; } while (0)
|
||||
|
||||
// Waveform generator can create tones, PWM, and servos
|
||||
typedef struct {
|
||||
uint32_t nextServiceCycle; // ESP cycle timer when a transition required
|
||||
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
|
||||
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
|
||||
uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform
|
||||
} Waveform;
|
||||
|
||||
static Waveform waveform[17]; // State of all possible pins
|
||||
static volatile uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
|
||||
static volatile uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
|
||||
|
||||
// Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine
|
||||
static volatile uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin
|
||||
static volatile uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation
|
||||
|
||||
static uint32_t (*timer1CB)() = NULL;
|
||||
|
||||
|
||||
// Non-speed critical bits
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCount() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
// Interrupt on/off control
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt();
|
||||
static bool timerRunning = false;
|
||||
|
||||
static void initTimer() {
|
||||
timer1_disable();
|
||||
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
|
||||
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
|
||||
timerRunning = true;
|
||||
}
|
||||
|
||||
static void ICACHE_RAM_ATTR deinitTimer() {
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
||||
timer1_disable();
|
||||
timer1_isr_init();
|
||||
timerRunning = false;
|
||||
}
|
||||
|
||||
// Set a callback. Pass in NULL to stop it
|
||||
void setTimer1Callback(uint32_t (*fn)()) {
|
||||
timer1CB = fn;
|
||||
if (!timerRunning && fn) {
|
||||
initTimer();
|
||||
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
|
||||
} else if (timerRunning && !fn && !waveformEnabled) {
|
||||
deinitTimer();
|
||||
}
|
||||
}
|
||||
|
||||
// Start up a waveform on a pin, or change the current one. Will change to the new
|
||||
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
|
||||
// first, then it will immediately begin.
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
|
||||
if ((pin > 16) || isFlashInterfacePin(pin)) {
|
||||
return false;
|
||||
}
|
||||
Waveform *wave = &waveform[pin];
|
||||
// Adjust to shave off some of the IRQ time, approximately
|
||||
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
|
||||
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
|
||||
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
|
||||
if (runTimeUS && !wave->expiryCycle) {
|
||||
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
|
||||
}
|
||||
|
||||
uint32_t mask = 1<<pin;
|
||||
if (!(waveformEnabled & mask)) {
|
||||
// Actually set the pin high or low in the IRQ service to guarantee times
|
||||
wave->nextServiceCycle = GetCycleCount() + microsecondsToClockCycles(1);
|
||||
waveformToEnable |= mask;
|
||||
if (!timerRunning) {
|
||||
initTimer();
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
} else {
|
||||
// Ensure timely service....
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
}
|
||||
while (waveformToEnable) {
|
||||
delay(0); // Wait for waveform to update
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Speed critical bits
|
||||
#pragma GCC optimize ("O2")
|
||||
// Normally would not want two copies like this, but due to different
|
||||
// optimization levels the inline attribute gets lost if we try the
|
||||
// other version.
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCountIRQ() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b) {
|
||||
if (a < b) {
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Stops a waveform on a pin
|
||||
int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
|
||||
// Can't possibly need to stop anything if there is no timer active
|
||||
if (!timerRunning) {
|
||||
return false;
|
||||
}
|
||||
// If user sends in a pin >16 but <32, this will always point to a 0 bit
|
||||
// If they send >=32, then the shift will result in 0 and it will also return false
|
||||
uint32_t mask = 1<<pin;
|
||||
if (!(waveformEnabled & mask)) {
|
||||
return false; // It's not running, nothing to do here
|
||||
}
|
||||
waveformToDisable |= mask;
|
||||
// Ensure timely service....
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
while (waveformToDisable) {
|
||||
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
||||
}
|
||||
if (!waveformEnabled && !timer1CB) {
|
||||
deinitTimer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// The SDK and hardware take some time to actually get to our NMI code, so
|
||||
// decrement the next IRQ's timer value by a bit so we can actually catch the
|
||||
// real CPU cycle counter we want for the waveforms.
|
||||
#if F_CPU == 80000000
|
||||
#define DELTAIRQ (microsecondsToClockCycles(3))
|
||||
#else
|
||||
#define DELTAIRQ (microsecondsToClockCycles(2))
|
||||
#endif
|
||||
|
||||
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt() {
|
||||
// Optimize the NMI inner loop by keeping track of the min and max GPIO that we
|
||||
// are generating. In the common case (1 PWM) these may be the same pin and
|
||||
// we can avoid looking at the other pins.
|
||||
static int startPin = 0;
|
||||
static int endPin = 0;
|
||||
|
||||
uint32_t nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||
uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14);
|
||||
|
||||
if (waveformToEnable || waveformToDisable) {
|
||||
// Handle enable/disable requests from main app.
|
||||
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
|
||||
waveformState &= ~waveformToEnable; // And clear the state of any just started
|
||||
waveformToEnable = 0;
|
||||
waveformToDisable = 0;
|
||||
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
|
||||
startPin = __builtin_ffs(waveformEnabled) - 1;
|
||||
// Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one)
|
||||
endPin = 32 - __builtin_clz(waveformEnabled);
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
if (waveformEnabled) {
|
||||
do {
|
||||
nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||
for (int i = startPin; i <= endPin; i++) {
|
||||
uint32_t mask = 1<<i;
|
||||
|
||||
// If it's not on, ignore!
|
||||
if (!(waveformEnabled & mask)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Waveform *wave = &waveform[i];
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
|
||||
// Disable any waveforms that are done
|
||||
if (wave->expiryCycle) {
|
||||
int32_t expiryToGo = wave->expiryCycle - now;
|
||||
if (expiryToGo < 0) {
|
||||
// Done, remove!
|
||||
waveformEnabled &= ~mask;
|
||||
if (i == 16) {
|
||||
GP16O &= ~1;
|
||||
} else {
|
||||
ClearGPIO(mask);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for toggles
|
||||
int32_t cyclesToGo = wave->nextServiceCycle - now;
|
||||
if (cyclesToGo < 0) {
|
||||
// See #7057
|
||||
// The following is a no-op unless we have overshot by an entire waveform cycle.
|
||||
// As modulus is an expensive operation, this code is removed for now:
|
||||
// cyclesToGo = -((-cyclesToGo) % (wave->nextTimeHighCycles + wave->nextTimeLowCycles));
|
||||
//
|
||||
// Alternative version with lower CPU impact:
|
||||
// while (-cyclesToGo > wave->nextTimeHighCycles + wave->nextTimeLowCycles) { cyclesToGo += wave->nextTimeHighCycles + wave->nextTimeLowCycles)};
|
||||
waveformState ^= mask;
|
||||
if (waveformState & mask) {
|
||||
if (i == 16) {
|
||||
GP16O |= 1; // GPIO16 write slow as it's RMW
|
||||
} else {
|
||||
SetGPIO(mask);
|
||||
}
|
||||
wave->nextServiceCycle = now + wave->nextTimeHighCycles + cyclesToGo;
|
||||
nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeHighCycles + cyclesToGo, 1));
|
||||
} else {
|
||||
if (i == 16) {
|
||||
GP16O &= ~1; // GPIO16 write slow as it's RMW
|
||||
} else {
|
||||
ClearGPIO(mask);
|
||||
}
|
||||
wave->nextServiceCycle = now + wave->nextTimeLowCycles + cyclesToGo;
|
||||
nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeLowCycles + cyclesToGo, 1));
|
||||
}
|
||||
} else {
|
||||
uint32_t deltaCycles = wave->nextServiceCycle - now;
|
||||
nextEventCycles = min_u32(nextEventCycles, deltaCycles);
|
||||
}
|
||||
}
|
||||
|
||||
// Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
int32_t cycleDeltaNextEvent = timeoutCycle - (now + nextEventCycles);
|
||||
int32_t cyclesLeftTimeout = timeoutCycle - now;
|
||||
done = (cycleDeltaNextEvent < 0) || (cyclesLeftTimeout < 0);
|
||||
} while (!done);
|
||||
} // if (waveformEnabled)
|
||||
|
||||
if (timer1CB) {
|
||||
nextEventCycles = min_u32(nextEventCycles, timer1CB());
|
||||
}
|
||||
|
||||
if (nextEventCycles < microsecondsToClockCycles(10)) {
|
||||
nextEventCycles = microsecondsToClockCycles(10);
|
||||
}
|
||||
nextEventCycles -= DELTAIRQ;
|
||||
|
||||
// Do it here instead of global function to save time and because we know it's edge-IRQ
|
||||
#if F_CPU == 160000000
|
||||
T1L = nextEventCycles >> 1; // Already know we're in range by MAXIRQUS
|
||||
#else
|
||||
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
|
||||
#endif
|
||||
TEIE |= TEIE1; // Edge int enable
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
esp8266_waveform - General purpose waveform generation and control,
|
||||
supporting outputs on all pins in parallel.
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
||||
mode and is always loaded with the time until the next edge of any live
|
||||
waveforms.
|
||||
|
||||
Up to one waveform generator per pin supported.
|
||||
|
||||
Each waveform generator is synchronized to the ESP cycle counter, not the
|
||||
timer. This allows for removing interrupt jitter and delay as the counter
|
||||
always increments once per 80MHz clock. Changes to a waveform are
|
||||
contiguous and only take effect on the next waveform transition,
|
||||
allowing for smooth transitions.
|
||||
|
||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||
|
||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
||||
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifndef __ESP8266_WAVEFORM_H
|
||||
#define __ESP8266_WAVEFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Start or change a waveform of the specified high and low times on specific pin.
|
||||
// If runtimeUS > 0 then automatically stop it after that many usecs.
|
||||
// Returns true or false on success or failure.
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS);
|
||||
// Stop a waveform, if any, on the specified pin.
|
||||
// Returns true or false on success or failure.
|
||||
int stopWaveform(uint8_t pin);
|
||||
|
||||
// Add a callback function to be called on *EVERY* timer1 trigger. The
|
||||
// callback returns the number of microseconds until the next desired call.
|
||||
// However, since it is called every timer1 interrupt, it may be called
|
||||
// again before this period. It should therefore use the ESP Cycle Counter
|
||||
// to determine whether or not to perform an operation.
|
||||
// Pass in NULL to disable the callback and, if no other waveforms being
|
||||
// generated, stop the timer as well.
|
||||
// Make sure the CB function has the ICACHE_RAM_ATTR decorator.
|
||||
void setTimer1Callback(uint32_t (*fn)());
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
/*
|
||||
* @title Espalexa library
|
||||
* @version 2.4.5
|
||||
* @version 2.4.6
|
||||
* @author Christian Schwinne
|
||||
* @license MIT
|
||||
* @contributors d-999
|
||||
@ -49,7 +49,7 @@
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
#ifdef ESPALEXA_DEBUG
|
||||
#pragma message "Espalexa 2.4.5 debug mode"
|
||||
#pragma message "Espalexa 2.4.6 debug mode"
|
||||
#define EA_DEBUG(x) Serial.print (x)
|
||||
#define EA_DEBUGLN(x) Serial.println (x)
|
||||
#else
|
||||
@ -81,35 +81,29 @@ private:
|
||||
WiFiUDP espalexaUdp;
|
||||
IPAddress ipMulti;
|
||||
bool udpConnected = false;
|
||||
char packetBuffer[255]; //buffer to hold incoming udp packet
|
||||
String escapedMac=""; //lowercase mac address
|
||||
|
||||
//private member functions
|
||||
String boolString(bool st)
|
||||
{
|
||||
return(st)?"true":"false";
|
||||
}
|
||||
|
||||
String modeString(EspalexaColorMode m)
|
||||
const char* modeString(EspalexaColorMode m)
|
||||
{
|
||||
if (m == EspalexaColorMode::xy) return "xy";
|
||||
if (m == EspalexaColorMode::hs) return "hs";
|
||||
return "ct";
|
||||
}
|
||||
|
||||
String typeString(EspalexaDeviceType t)
|
||||
const char* typeString(EspalexaDeviceType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case EspalexaDeviceType::dimmable: return "Dimmable light";
|
||||
case EspalexaDeviceType::whitespectrum: return "Color temperature light";
|
||||
case EspalexaDeviceType::color: return "Color light";
|
||||
case EspalexaDeviceType::extendedcolor: return "Extended color light";
|
||||
case EspalexaDeviceType::dimmable: return PSTR("Dimmable light");
|
||||
case EspalexaDeviceType::whitespectrum: return PSTR("Color temperature light");
|
||||
case EspalexaDeviceType::color: return PSTR("Color light");
|
||||
case EspalexaDeviceType::extendedcolor: return PSTR("Extended color light");
|
||||
}
|
||||
return "Light";
|
||||
return "";
|
||||
}
|
||||
|
||||
String modelidString(EspalexaDeviceType t)
|
||||
const char* modelidString(EspalexaDeviceType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
@ -118,7 +112,7 @@ private:
|
||||
case EspalexaDeviceType::color: return "LST001";
|
||||
case EspalexaDeviceType::extendedcolor: return "LCT015";
|
||||
}
|
||||
return "Plug";
|
||||
return "";
|
||||
}
|
||||
|
||||
//Workaround functions courtesy of Sonoff-Tasmota
|
||||
@ -135,38 +129,38 @@ private:
|
||||
}
|
||||
|
||||
//device JSON string: color+temperature device emulates LCT015, dimmable device LWB010, (TODO: on/off Plug 01, color temperature device LWT010, color device LST001)
|
||||
String deviceJsonString(uint8_t deviceId)
|
||||
void deviceJsonString(uint8_t deviceId, char* buf)
|
||||
{
|
||||
deviceId--;
|
||||
if (deviceId >= currentDeviceCount) return "{}"; //error
|
||||
if (deviceId >= currentDeviceCount) {strcpy(buf,"{}"); return;} //error
|
||||
EspalexaDevice* dev = devices[deviceId];
|
||||
|
||||
String json = "{\"state\":{\"on\":";
|
||||
json += boolString(dev->getValue());
|
||||
if (dev->getType() != EspalexaDeviceType::onoff) //bri support
|
||||
{
|
||||
json += ",\"bri\":" + String(dev->getLastValue()-1);
|
||||
if (static_cast<uint8_t>(dev->getType()) > 2) //color support
|
||||
{
|
||||
json += ",\"hue\":" + String(dev->getHue()) + ",\"sat\":" + String(dev->getSat());
|
||||
json += ",\"effect\":\"none\",\"xy\":[" + String(dev->getX()) + "," + String(dev->getY()) + "]";
|
||||
}
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1 && dev->getType() != EspalexaDeviceType::color) //white spectrum support
|
||||
{
|
||||
json += ",\"ct\":" + String(dev->getCt());
|
||||
}
|
||||
}
|
||||
json += ",\"alert\":\"none";
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1) json += "\",\"colormode\":\"" + modeString(dev->getColorMode());
|
||||
json += "\",\"mode\":\"homeautomation\",\"reachable\":true},";
|
||||
json += "\"type\":\"" + typeString(dev->getType());
|
||||
json += "\",\"name\":\"" + dev->getName();
|
||||
json += "\",\"modelid\":\"" + modelidString(dev->getType());
|
||||
json += "\",\"manufacturername\":\"Philips\",\"productname\":\"E" + String(static_cast<uint8_t>(dev->getType()));
|
||||
json += "\",\"uniqueid\":\"" + String(encodeLightId(deviceId+1));
|
||||
json += "\",\"swversion\":\"espalexa-2.4.5\"}";
|
||||
|
||||
return json;
|
||||
//char buf_bri[12] = "";
|
||||
//brightness support, add "bri" to JSON
|
||||
//if (dev->getType() != EspalexaDeviceType::onoff)
|
||||
// sprintf(buf_bri,",\"bri\":%u", dev->getLastValue()-1);
|
||||
|
||||
char buf_col[80] = "";
|
||||
//color support
|
||||
if (static_cast<uint8_t>(dev->getType()) > 2)
|
||||
sprintf_P(buf_col,PSTR(",\"hue\":%u,\"sat\":%u,\"effect\":\"none\",\"xy\":[%f,%f]")
|
||||
,dev->getHue(), dev->getSat(), dev->getX(), dev->getY());
|
||||
|
||||
char buf_ct[16] = "";
|
||||
//white spectrum support
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1 && dev->getType() != EspalexaDeviceType::color)
|
||||
sprintf(buf_ct, ",\"ct\":%u", dev->getCt());
|
||||
|
||||
char buf_cm[20] = "";
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1)
|
||||
sprintf(buf_cm,PSTR("\",\"colormode\":\"%s"), modeString(dev->getColorMode()));
|
||||
|
||||
sprintf_P(buf, PSTR("{\"state\":{\"on\":%s,\"bri\":%u%s%s,\"alert\":\"none%s\",\"mode\":\"homeautomation\",\"reachable\":true},"
|
||||
"\"type\":\"%s\",\"name\":\"%s\",\"modelid\":\"%s\",\"manufacturername\":\"Philips\",\"productname\":\"E%u"
|
||||
"\",\"uniqueid\":\"%u\",\"swversion\":\"espalexa-2.4.6\"}")
|
||||
|
||||
, (dev->getValue())?"true":"false", dev->getLastValue()-1, buf_col, buf_ct, buf_cm, typeString(dev->getType()),
|
||||
dev->getName().c_str(), modelidString(dev->getType()), static_cast<uint8_t>(dev->getType()), encodeLightId(deviceId+1));
|
||||
}
|
||||
|
||||
//Espalexa status page /espalexa
|
||||
@ -181,14 +175,14 @@ private:
|
||||
res += "Value of device " + String(i+1) + " (" + dev->getName() + "): " + String(dev->getValue()) + " (" + typeString(dev->getType());
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1) //color support
|
||||
{
|
||||
res += ", colormode=" + modeString(dev->getColorMode()) + ", r=" + String(dev->getR()) + ", g=" + String(dev->getG()) + ", b=" + String(dev->getB());
|
||||
res += ", colormode=" + String(modeString(dev->getColorMode())) + ", r=" + String(dev->getR()) + ", g=" + String(dev->getG()) + ", b=" + String(dev->getB());
|
||||
res +=", ct=" + String(dev->getCt()) + ", hue=" + String(dev->getHue()) + ", sat=" + String(dev->getSat()) + ", x=" + String(dev->getX()) + ", y=" + String(dev->getY());
|
||||
}
|
||||
res += ")\r\n";
|
||||
}
|
||||
res += "\r\nFree Heap: " + (String)ESP.getFreeHeap();
|
||||
res += "\r\nUptime: " + (String)millis();
|
||||
res += "\r\n\r\nEspalexa library v2.4.5 by Christian Schwinne 2020";
|
||||
res += "\r\n\r\nEspalexa library v2.4.6 by Christian Schwinne 2020";
|
||||
server->send(200, "text/plain", res);
|
||||
}
|
||||
#endif
|
||||
@ -206,7 +200,7 @@ private:
|
||||
EA_DEBUGLN("Body: " + body);
|
||||
if(!handleAlexaApiCall(server))
|
||||
#endif
|
||||
server->send(404, "text/plain", "Not Found (espalexa-internal)");
|
||||
server->send(404, "text/plain", "Not Found (espalexa)");
|
||||
}
|
||||
|
||||
//send description.xml device property page
|
||||
@ -216,30 +210,31 @@ private:
|
||||
IPAddress localIP = WiFi.localIP();
|
||||
char s[16];
|
||||
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
|
||||
String setup_xml = "<?xml version=\"1.0\" ?>"
|
||||
char buf[1024];
|
||||
|
||||
sprintf_P(buf,PSTR("<?xml version=\"1.0\" ?>"
|
||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
|
||||
"<specVersion><major>1</major><minor>0</minor></specVersion>"
|
||||
"<URLBase>http://"+ String(s) +":80/</URLBase>"
|
||||
"<URLBase>http://%s:80/</URLBase>"
|
||||
"<device>"
|
||||
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
|
||||
"<friendlyName>Espalexa ("+ String(s) +")</friendlyName>"
|
||||
"<friendlyName>Espalexa (%s)</friendlyName>"
|
||||
"<manufacturer>Royal Philips Electronics</manufacturer>"
|
||||
"<manufacturerURL>http://www.philips.com</manufacturerURL>"
|
||||
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
|
||||
"<modelName>Philips hue bridge 2012</modelName>"
|
||||
"<modelNumber>929000226503</modelNumber>"
|
||||
"<modelURL>http://www.meethue.com</modelURL>"
|
||||
"<serialNumber>"+ escapedMac +"</serialNumber>"
|
||||
"<UDN>uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"</UDN>"
|
||||
"<serialNumber>%s</serialNumber>"
|
||||
"<UDN>uuid:2f402f80-da50-11e1-9b23-%s</UDN>"
|
||||
"<presentationURL>index.html</presentationURL>"
|
||||
"</device>"
|
||||
"</root>";
|
||||
"</root>"),s,s,escapedMac.c_str(),escapedMac.c_str());
|
||||
|
||||
server->send(200, "text/xml", setup_xml.c_str());
|
||||
server->send(200, "text/xml", buf);
|
||||
|
||||
EA_DEBUG("Sending :");
|
||||
EA_DEBUGLN(setup_xml);
|
||||
EA_DEBUG("Send setup.xml");
|
||||
//EA_DEBUGLN(setup_xml);
|
||||
}
|
||||
|
||||
//init the server
|
||||
@ -290,22 +285,23 @@ private:
|
||||
char s[16];
|
||||
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
|
||||
String response =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
char buf[1024];
|
||||
|
||||
sprintf_P(buf,PSTR("HTTP/1.1 200 OK\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL
|
||||
"LOCATION: http://"+ String(s) +":80/description.xml\r\n"
|
||||
"LOCATION: http://%s:80/description.xml\r\n"
|
||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber
|
||||
"hue-bridgeid: "+ escapedMac +"\r\n"
|
||||
"hue-bridgeid: %s\r\n"
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType
|
||||
"USN: uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"::ssdp:all\r\n" // _uuid::_deviceType
|
||||
"\r\n";
|
||||
"USN: uuid:2f402f80-da50-11e1-9b23-%s::ssdp:all\r\n" // _uuid::_deviceType
|
||||
"\r\n"),s,escapedMac.c_str(),escapedMac.c_str());
|
||||
|
||||
espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort());
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
espalexaUdp.write((uint8_t*)response.c_str(), response.length());
|
||||
espalexaUdp.write((uint8_t*)buf, strlen(buf));
|
||||
#else
|
||||
espalexaUdp.write(response.c_str());
|
||||
espalexaUdp.write(buf);
|
||||
#endif
|
||||
espalexaUdp.endPacket();
|
||||
}
|
||||
@ -362,7 +358,8 @@ public:
|
||||
if (!packetSize) return; //no new udp packet
|
||||
|
||||
EA_DEBUGLN("Got UDP!");
|
||||
int len = espalexaUdp.read(packetBuffer, 254);
|
||||
char packetBuffer[255]; //buffer to hold incoming udp packet
|
||||
uint16_t len = espalexaUdp.read(packetBuffer, 254);
|
||||
if (len > 0) {
|
||||
packetBuffer[len] = 0;
|
||||
}
|
||||
@ -370,10 +367,9 @@ public:
|
||||
if (!discoverable) return; //do not reply to M-SEARCH if not discoverable
|
||||
|
||||
String request = packetBuffer;
|
||||
if(request.indexOf("M-SEA") >= 0) { //M-SEARCH
|
||||
if(request.indexOf("M-SEARCH") >= 0) {
|
||||
EA_DEBUGLN(request);
|
||||
//match upnp:rootdevice, device:basic:1, ssdp:all and ssdp:discover
|
||||
if(request.indexOf("np:rootd") > 0 || request.indexOf("asic:1") > 0 || request.indexOf("dp:all") > 0 || request.indexOf("dp:dis") > 0) {
|
||||
if(request.indexOf("upnp:rootdevice") > 0 || request.indexOf("asic:1") > 0 || request.indexOf("ssdp:all") > 0) {
|
||||
EA_DEBUGLN("Responding search req...");
|
||||
respondToSearch();
|
||||
}
|
||||
@ -448,13 +444,13 @@ public:
|
||||
{
|
||||
EA_DEBUGLN("devType");
|
||||
body = "";
|
||||
server->send(200, "application/json", "[{\"success\":{\"username\":\"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]");
|
||||
server->send(200, "application/json", F("[{\"success\":{\"username\":\"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (req.indexOf("state") > 0) //client wants to control light
|
||||
{
|
||||
server->send(200, "application/json", "[{\"success\":{\"/lights/1/state/\": true}}]");
|
||||
server->send(200, "application/json", F("[{\"success\":{\"/lights/1/state/\": true}}]"));
|
||||
|
||||
uint32_t devId = req.substring(req.indexOf("lights")+7).toInt();
|
||||
EA_DEBUG("ls"); EA_DEBUGLN(devId);
|
||||
@ -531,7 +527,9 @@ public:
|
||||
for (int i = 0; i<currentDeviceCount; i++)
|
||||
{
|
||||
jsonTemp += "\"" + String(encodeLightId(i+1)) + "\":";
|
||||
jsonTemp += deviceJsonString(i+1);
|
||||
char buf[512];
|
||||
deviceJsonString(i+1, buf);
|
||||
jsonTemp += buf;
|
||||
if (i < currentDeviceCount-1) jsonTemp += ",";
|
||||
}
|
||||
jsonTemp += "}";
|
||||
@ -544,7 +542,9 @@ public:
|
||||
{
|
||||
server->send(200, "application/json", "{}");
|
||||
} else {
|
||||
server->send(200, "application/json", deviceJsonString(devId));
|
||||
char buf[512];
|
||||
deviceJsonString(devId, buf);
|
||||
server->send(200, "application/json", buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ EspalexaDevice::EspalexaDevice(String deviceName, DeviceCallbackFunction gnCallb
|
||||
_callbackDev = gnCallback;
|
||||
_type = t;
|
||||
if (t == EspalexaDeviceType::onoff) _type = EspalexaDeviceType::dimmable; //on/off is broken, so make dimmable device instead
|
||||
if (t == EspalexaDeviceType::whitespectrum) _mode = EspalexaColorMode::ct;
|
||||
_val = initialValue;
|
||||
_val_last = _val;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#ifndef EspalexaDevice_h
|
||||
#define EspalexaDevice_h
|
||||
#include <functional>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <functional>
|
||||
|
||||
|
@ -74,16 +74,18 @@ void notify(byte callMode, bool followUp)
|
||||
|
||||
void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
{
|
||||
if (!realtimeMode){
|
||||
if (!realtimeMode && !realtimeOverride){
|
||||
for (uint16_t i = 0; i < ledCount; i++)
|
||||
{
|
||||
strip.setPixelColor(i,0,0,0,0);
|
||||
}
|
||||
realtimeMode = md;
|
||||
}
|
||||
|
||||
realtimeTimeout = millis() + timeoutMs;
|
||||
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
|
||||
if (arlsForceMaxBri) strip.setBrightness(255);
|
||||
realtimeMode = md;
|
||||
|
||||
if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness(255);
|
||||
}
|
||||
|
||||
|
||||
@ -103,8 +105,10 @@ void handleNotifications()
|
||||
//unlock strip when realtime UDP times out
|
||||
if (realtimeMode && millis() > realtimeTimeout)
|
||||
{
|
||||
if (realtimeOverride == REALTIME_OVERRIDE_ONCE) realtimeOverride = REALTIME_OVERRIDE_NONE;
|
||||
strip.setBrightness(bri);
|
||||
realtimeMode = REALTIME_MODE_INACTIVE;
|
||||
realtimeIP[0] = 0;
|
||||
}
|
||||
|
||||
//receive UDP notifications
|
||||
@ -122,6 +126,7 @@ void handleNotifications()
|
||||
uint8_t lbuf[packetSize];
|
||||
rgbUdp.read(lbuf, packetSize);
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
|
||||
if (realtimeOverride) return;
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 0; i < packetSize -2; i += 3)
|
||||
{
|
||||
@ -202,50 +207,52 @@ void handleNotifications()
|
||||
{
|
||||
realtimeIP = notifierUdp.remoteIP();
|
||||
DEBUG_PRINTLN(notifierUdp.remoteIP());
|
||||
if (packetSize > 1) {
|
||||
if (udpIn[1] == 0)
|
||||
{
|
||||
realtimeTimeout = 0;
|
||||
return;
|
||||
} else {
|
||||
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
|
||||
}
|
||||
if (udpIn[0] == 1) //warls
|
||||
{
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
|
||||
}
|
||||
} else if (udpIn[0] == 2) //drgb
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -2; i += 3)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
if (packetSize < 2) return;
|
||||
|
||||
id++; if (id >= ledCount) break;
|
||||
}
|
||||
} else if (udpIn[0] == 3) //drgbw
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||
|
||||
id++; if (id >= ledCount) break;
|
||||
}
|
||||
} else if (udpIn[0] == 4) //dnrgb
|
||||
{
|
||||
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||
for (uint16_t i = 4; i < packetSize -2; i += 3)
|
||||
{
|
||||
if (id >= ledCount) break;
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
id++;
|
||||
}
|
||||
}
|
||||
strip.show();
|
||||
if (udpIn[1] == 0)
|
||||
{
|
||||
realtimeTimeout = 0;
|
||||
return;
|
||||
} else {
|
||||
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
|
||||
}
|
||||
if (realtimeOverride) return;
|
||||
|
||||
if (udpIn[0] == 1) //warls
|
||||
{
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
|
||||
}
|
||||
} else if (udpIn[0] == 2) //drgb
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -2; i += 3)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
|
||||
id++; if (id >= ledCount) break;
|
||||
}
|
||||
} else if (udpIn[0] == 3) //drgbw
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||
|
||||
id++; if (id >= ledCount) break;
|
||||
}
|
||||
} else if (udpIn[0] == 4) //dnrgb
|
||||
{
|
||||
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||
for (uint16_t i = 4; i < packetSize -2; i += 3)
|
||||
{
|
||||
if (id >= ledCount) break;
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
id++;
|
||||
}
|
||||
}
|
||||
strip.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ void WLED::loop()
|
||||
if (doReboot)
|
||||
reset();
|
||||
|
||||
if (!realtimeMode) // block stuff if WARLS/Adalight is enabled
|
||||
if (!realtimeMode || realtimeOverride) // block stuff if WARLS/Adalight is enabled
|
||||
{
|
||||
if (apActive)
|
||||
dnsServer.processNextRequest();
|
||||
@ -89,8 +89,10 @@ void WLED::loop()
|
||||
#ifdef ESP8266
|
||||
MDNS.update();
|
||||
#endif
|
||||
if (millis() - lastMqttReconnectAttempt > 30000)
|
||||
if (millis() - lastMqttReconnectAttempt > 30000) {
|
||||
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
|
||||
initMqtt();
|
||||
}
|
||||
|
||||
// DEBUG serial logging
|
||||
#ifdef WLED_DEBUG
|
||||
@ -284,7 +286,7 @@ void WLED::initAP(bool resetAP)
|
||||
|
||||
void WLED::initConnection()
|
||||
{
|
||||
WiFi.disconnect(); // close old connections
|
||||
WiFi.disconnect(true); // close old connections
|
||||
#ifdef ESP8266
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
#endif
|
||||
@ -308,6 +310,7 @@ void WLED::initConnection()
|
||||
} else {
|
||||
DEBUG_PRINTLN("Access point disabled.");
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.mode(WIFI_STA);
|
||||
}
|
||||
}
|
||||
showWelcomePage = false;
|
||||
|
@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.9.1n
|
||||
@version 0.10.0
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2004230
|
||||
#define VERSION 2005100
|
||||
|
||||
// ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS).
|
||||
|
||||
@ -109,10 +109,10 @@
|
||||
#include <IRutils.h>
|
||||
#endif
|
||||
|
||||
// remove flicker because PWM signal of RGB channels can become out of phase
|
||||
#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266)
|
||||
#include "src/dependencies/arduino/core_esp8266_waveform.h"
|
||||
#endif
|
||||
// remove flicker because PWM signal of RGB channels can become out of phase (part of core as of Arduino core v2.7.0)
|
||||
//#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266)
|
||||
// #include "src/dependencies/arduino/core_esp8266_waveform.h"
|
||||
//#endif
|
||||
|
||||
// enable additional debug output
|
||||
#ifdef WLED_DEBUG
|
||||
@ -148,7 +148,8 @@
|
||||
#endif
|
||||
|
||||
// Global Variable definitions
|
||||
WLED_GLOBAL char versionString[] _INIT("0.9.1n");
|
||||
WLED_GLOBAL char versionString[] _INIT("0.10.0");
|
||||
#define WLED_CODENAME "Namigai"
|
||||
|
||||
// AP and OTA default passwords (for maximum security change them!)
|
||||
WLED_GLOBAL char apPass[65] _INIT(DEFAULT_AP_PASS);
|
||||
@ -215,7 +216,7 @@ WLED_GLOBAL bool notifyMacro _INIT(false); // send notifi
|
||||
WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes
|
||||
WLED_GLOBAL bool notifyTwice _INIT(false); // notifications use UDP: enable if devices don't sync reliably
|
||||
|
||||
WLED_GLOBAL bool alexaEnabled _INIT(true); // enable device discovery by Amazon Echo
|
||||
WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo
|
||||
WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand
|
||||
|
||||
WLED_GLOBAL char blynkApiKey[36] _INIT(""); // Auth token for Blynk server. If empty, no connection will be made
|
||||
@ -414,6 +415,7 @@ WLED_GLOBAL bool saveCurrPresetCycConf _INIT(false);
|
||||
|
||||
// realtime
|
||||
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
|
||||
WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE);
|
||||
WLED_GLOBAL IPAddress realtimeIP _INIT((0, 0, 0, 0));
|
||||
WLED_GLOBAL unsigned long realtimeTimeout _INIT(0);
|
||||
|
||||
@ -447,6 +449,7 @@ WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(999000000L);
|
||||
WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L);
|
||||
WLED_GLOBAL IPAddress ntpServerIP;
|
||||
WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390);
|
||||
WLED_GLOBAL uint16_t rolloverMillis _INIT(0);
|
||||
|
||||
// Temp buffer
|
||||
WLED_GLOBAL char* obuf;
|
||||
|
@ -594,7 +594,7 @@ void savedToPresets()
|
||||
savedPresets &= ~(0x01 << (index-1));
|
||||
}
|
||||
}
|
||||
if (EEPROM.read(700) == 2) {
|
||||
if (EEPROM.read(700) == 2 || EEPROM.read(700) == 3) {
|
||||
savedPresets |= 0x01 << 15;
|
||||
} else
|
||||
{
|
||||
|
@ -67,13 +67,13 @@ void handleSerial()
|
||||
break;
|
||||
case AdaState::Data_Blue:
|
||||
byte blue = next;
|
||||
setRealtimePixel(pixel++, red, green, blue, 0);
|
||||
if (!realtimeOverride) setRealtimePixel(pixel++, red, green, blue, 0);
|
||||
if (--count > 0) state = AdaState::Data_Red;
|
||||
else {
|
||||
if (!realtimeMode && bri == 0) strip.setBrightness(briLast);
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_ADALIGHT);
|
||||
|
||||
strip.show();
|
||||
if (!realtimeOverride) strip.show();
|
||||
state = AdaState::Header_A;
|
||||
}
|
||||
break;
|
||||
|
@ -382,7 +382,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
default: sprintf(hueErrorString,"Bridge Error %i",hueError);
|
||||
}
|
||||
|
||||
sappends('m',"(\"hms\")[0]",hueErrorString);
|
||||
sappends('m',"(\"sip\")[0]",hueErrorString);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -445,12 +445,12 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',"NO",otaLock);
|
||||
sappend('c',"OW",wifiLock);
|
||||
sappend('c',"AO",aOtaEnabled);
|
||||
sappends('m',"(\"msg\")[0]","WLED ");
|
||||
sappends('m',"(\"sip\")[0]","WLED ");
|
||||
olen -= 2; //delete ";
|
||||
oappend(versionString);
|
||||
oappend(" (build ");
|
||||
oappendi(VERSION);
|
||||
oappend(") OK\";");
|
||||
oappend(")\";");
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
|
Loading…
Reference in New Issue
Block a user